From: Jean-Philippe Bruyère Date: Sat, 3 Aug 2019 17:49:15 +0000 (+0200) Subject: sample directory X-Git-Tag: v0.9.5-beta~137^2~23 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=e6030fa04a8de3fdae1dc19d081bf5feb3d3d73c;p=jp%2Fcrow.git sample directory --- diff --git a/Crow.NetStd.sln b/Crow.NetStd.sln deleted file mode 100644 index a62e1600..00000000 --- a/Crow.NetStd.sln +++ /dev/null @@ -1,38 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 -MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crow.NetStd", "Crow\Crow.NetStd.csproj", "{75BDE4C7-4BAF-4A03-B697-5D1370775E20}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.NetStd", "Tests\Tests.NetStd.csproj", "{28BAF8B8-6A6E-40D5-8E9C-E7C1165C59DD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowIDE.NetStd", "CrowIDE\CrowIDE.NetStd.csproj", "{A01B3151-BC81-437C-B526-CC8DBB808638}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {75BDE4C7-4BAF-4A03-B697-5D1370775E20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75BDE4C7-4BAF-4A03-B697-5D1370775E20}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75BDE4C7-4BAF-4A03-B697-5D1370775E20}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75BDE4C7-4BAF-4A03-B697-5D1370775E20}.Release|Any CPU.Build.0 = Release|Any CPU - {28BAF8B8-6A6E-40D5-8E9C-E7C1165C59DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {28BAF8B8-6A6E-40D5-8E9C-E7C1165C59DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {28BAF8B8-6A6E-40D5-8E9C-E7C1165C59DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {28BAF8B8-6A6E-40D5-8E9C-E7C1165C59DD}.Release|Any CPU.Build.0 = Release|Any CPU - {A01B3151-BC81-437C-B526-CC8DBB808638}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A01B3151-BC81-437C-B526-CC8DBB808638}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A01B3151-BC81-437C-B526-CC8DBB808638}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A01B3151-BC81-437C-B526-CC8DBB808638}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/Crow.sln b/Crow.sln index 68347c39..dcb8a1ec 100644 --- a/Crow.sln +++ b/Crow.sln @@ -1,11 +1,13 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crow", "Crow\Crow.csproj", "{C2980F9B-4798-4C05-99E2-E174810F7C7B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{74289092-9F70-4941-AFCB-DFD7BE2140B6}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowIDE", "CrowIDE\CrowIDE.csproj", "{B6D911CD-1D09-42FC-B300-9187190F2AE1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld", "Samples\HelloWorld\HelloWorld.csproj", "{F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShowCase", "Samples\ShowCase\ShowCase.csproj", "{56329D48-D382-4850-93DE-59C453894E8A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,18 +15,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {74289092-9F70-4941-AFCB-DFD7BE2140B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {74289092-9F70-4941-AFCB-DFD7BE2140B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {74289092-9F70-4941-AFCB-DFD7BE2140B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {74289092-9F70-4941-AFCB-DFD7BE2140B6}.Release|Any CPU.Build.0 = Release|Any CPU - {B6D911CD-1D09-42FC-B300-9187190F2AE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B6D911CD-1D09-42FC-B300-9187190F2AE1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B6D911CD-1D09-42FC-B300-9187190F2AE1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B6D911CD-1D09-42FC-B300-9187190F2AE1}.Release|Any CPU.Build.0 = Release|Any CPU {C2980F9B-4798-4C05-99E2-E174810F7C7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C2980F9B-4798-4C05-99E2-E174810F7C7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C2980F9B-4798-4C05-99E2-E174810F7C7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C2980F9B-4798-4C05-99E2-E174810F7C7B}.Release|Any CPU.Build.0 = Release|Any CPU + {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A}.Release|Any CPU.Build.0 = Release|Any CPU + {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56329D48-D382-4850-93DE-59C453894E8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56329D48-D382-4850-93DE-59C453894E8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56329D48-D382-4850-93DE-59C453894E8A}.Release|Any CPU.Build.0 = Release|Any CPU + {56329D48-D382-4850-93DE-59C453894E8A}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 @@ -65,4 +67,9 @@ Global description = @C.R.O.W. c# Rapid Open Widgets\n\nCrow is a pure c# widget toolkit with XML definition of interface, bindings, styling...\n version = 0.8.0 EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} + {56329D48-D382-4850-93DE-59C453894E8A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} + {348A1983-0794-445A-975C-CBBF68EAC810} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} + EndGlobalSection EndGlobal diff --git a/Crow/Crow.NetStd.csproj b/Crow/Crow.NetStd.csproj deleted file mode 100644 index 0421fa3d..00000000 --- a/Crow/Crow.NetStd.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - Crow - C.R.O.W. is a widget toolkit and rendering engine entirely developed in C# with templates, styles, compositing, and bindings. - - - netcoreapp2.0 - - $(SolutionDir)build/$(Configuration) - $(SolutionDir)build/obj/$(Configuration) - - DESIGN_MODE - - true - false - false - true - Crow - 0.8.0.1-beta - - JP Bruyère - C# Rapid Open Widget Toolkit - https://opensource.org/licenses/MIT - https://jpbruyere.github.io/Crow/images/crow.png - https://github.com/jpbruyere/Crow/wiki - Crow Widget Interface GUI C# .Net Mono - Copyright 2013-2018 - - JP Bruyère - - - - - TRACE;DESIGN_MODE;DEBUG - - - - - - - Crow.%(Filename).template - - - - - - - - - - - - - - - - - diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index dce02f07..61afef56 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -1,192 +1,69 @@ - - + + - Debug - AnyCPU - {C2980F9B-4798-4C05-99E2-E174810F7C7B} - Library - Properties - Crow + net471;netstandard2.0 Crow - 512 - True - False - False - 4 - False - false - OnBuildSuccess - C# Rapid Open Widget - 4194304 - $(SolutionDir)build\$(Configuration) - $(SolutionDir)build\obj\$(Configuration) - crow.key + + 0.8.1 + C.R.O.W. is a widget toolkit and rendering engine entirely developed in C# with templates, styles, compositing, and bindings. + + true + false + false + + Jean-Philippe Bruyère + C# Rapid Open Widget Toolkit + MIT + Crow + GUI Widget toolkit Interface C# .Net Mono + $(AssemblyVersion)-beta + True + false + https://github.com/jpbruyere/Crow/wiki + https://opensource.org/licenses/MIT + https://jpbruyere.github.io/Crow/images/crow.png + Copyright 2013-2019 + Turn on vulkan layer through vkvg + https://github.com/jpbruyere/Crow + + $(SolutionDir)build\$(Configuration)\ + DESIGN_MODE 0.8.0 - 8.0.30703 - 2.0 - v4.6.1 - + + - true full + TRACE;DEBUG;DESIGN_MODE;_DEBUG_CLIP_RECTANGLE;NETFRAMEWORK;NET471 true - false - $(SolutionDir)build\Debug - TRACE0;DEBUG;DEBUG_BINDING_FUNC_CALLS0;DEBUG_DRAGNDROP0;DEBUG_LOG0;XLIB_BACKEND0;DESIGN_MODE;DEBUG_UPDATE0;DEBUG_FOCUS0;DEBUG_DISPOSE0;MEASURE_TIME;DEBUG_LOAD0;DEBUG_BINDING0;DEBUG_CLIP_RECTANGLE0 - - - - - - - - true - DESIGN_MODE - $(SolutionDir)build\Release - - - - + + + - - + + + + + + - - + + + + + + Crow.%(Filename).template + + + + + - - - - - - - - - - - - - - + - - - - Crow.Button.template - - - Crow.CheckBox.template - - - Crow.ComboBox.template - - - Crow.Expandable.template - - - Crow.DirectoryView.template - - - Crow.FileDialog.template - - - Crow.GroupBox.template - - - Crow.ListBox.template - - - Crow.MessageBox.template - - - Crow.Popper.template - - - Crow.RadioButton.template - - - Crow.ScrollBar.template - - - Crow.Slider.template - - - Crow.Spinner.template - - - Crow.TabItem.template - - - Crow.TreeView.template - - - Crow.Window.template - - - - Crow.MenuItem.template - - - Crow.Menu.template - - - Crow.ColorPicker.template - - - Crow.ToolWindow.template - - - Crow.FileItems.template - - - Crow.DefaultItem.template - - - Crow.ScrollingListBox.template - - - - Crow.ArrowBut.template - - - - Crow.CheckBox2.template - - - Crow.Tooltip.template - - - Crow.ContextMenu.template - - - Crow.DockWindow.template - - - Crow.HScrollBar.template - - - PreserveNewest - - - - - - - - - - - - + diff --git a/Crow/src/GraphicObjects/Container.cs b/Crow/src/GraphicObjects/Container.cs index 8bff8100..ce54514e 100644 --- a/Crow/src/GraphicObjects/Container.cs +++ b/Crow/src/GraphicObjects/Container.cs @@ -63,7 +63,7 @@ namespace Crow /// override this to handle specific steps in child addition in derived class, /// and don't forget to call the base.SetChild /// - public virtual void SetChild(Widget _child) + public new virtual void SetChild(Widget _child) { base.SetChild (_child); } diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 9ba6462a..038df670 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -119,10 +119,10 @@ namespace Crow protected virtual void InitBackend () { if (Environment.OSVersion.Platform == PlatformID.Unix) backend = new Crow.XCB.XCBBackend(); + //backend = new Crow.XLib.XLibBackend (); else backend = new Crow.Win32.Win32Backend(); - - //backend = new Crow.XLib.XLibBackend (); + backend.Init (this); initTooltip (); @@ -185,7 +185,7 @@ namespace Crow { while (running) { Update (); - Thread.Sleep (1); + Thread.Sleep (30); } } diff --git a/Crow/src/backends/win32/WinBackend.cs b/Crow/src/backends/win32/WinBackend.cs index 183adc12..0b3f873c 100755 --- a/Crow/src/backends/win32/WinBackend.cs +++ b/Crow/src/backends/win32/WinBackend.cs @@ -29,95 +29,88 @@ using System.Runtime.InteropServices; using System.Text; using OpenToolkit.NT.Native; -namespace Crow.Win32 -{ - - public class Win32Backend : IBackend - { - public void CleanUp() - { - User32.Window.ReleaseDC(handle, hdc); - User32.Window.DestroyWindow(handle); - } - - public void Flush() - { +namespace Crow.Win32 { + + public class Win32Backend : IBackend { + public void CleanUp () { + User32.Window.ReleaseDC (handle, hdc); + User32.Window.DestroyWindow (handle); + } + + public void Flush () { iFace.surf.Flush (); - //throw new NotImplementedException(); - } - - WindowProc WindowProcedureDelegate; - string className = "myWindowClass"; - IntPtr instance = Marshal.GetHINSTANCE(typeof(Win32Backend).Module); - IntPtr handle = IntPtr.Zero; - IntPtr hdc = IntPtr.Zero; + //throw new NotImplementedException(); + } + + WindowProc WindowProcedureDelegate; + string className = "myWindowClass"; + IntPtr instance;// = Marshal.GetHINSTANCE(typeof(Win32Backend).Module); + IntPtr handle = IntPtr.Zero; + IntPtr hdc = IntPtr.Zero; Interface iFace; - public void Init(Interface _iFace) - { + public void Init (Interface _iFace) { iFace = _iFace; - WindowProcedureDelegate = WindowProcedure; - - Rect rect = new Rect - { - Left = iFace.ClientRectangle.Left, - Top = iFace.ClientRectangle.Top, - Right = iFace.ClientRectangle.Right, - Bottom = iFace.ClientRectangle.Bottom - }; - - User32.Window.AdjustWindowRectEx(ref rect, 0, false, 0); - - ExtendedWindowClass wc = new ExtendedWindowClass - { - Size = ExtendedWindowClass.SizeInBytes, - Style = 0, - WindowProc = WindowProcedureDelegate, - ClassExtra = 0, - WindowExtra = 0, - Instance = instance, - Icon = IntPtr.Zero, - Cursor = User32.Cursor.LoadCursor(CursorName.Arrow), - //Background = Gdi32.GetStockObject(GetStockObjectType.BlackBrush), - MenuName = null, - ClassName = className, - }; - - ushort atom = User32.WindowClass.RegisterClassEx(ref wc); - - handle = User32.Window.CreateWindowEx( - ExtendedWindowStyles.ClientEdge, - className, - "The title of my window", - WindowStyles.OverlappedWindow, - - rect.Left, - rect.Top, - rect.Width, - rect.Height, - IntPtr.Zero, - IntPtr.Zero, - instance, - IntPtr.Zero - ); - - User32.Window.ShowWindow(handle, ShowWindowCommand.Show); - - hdc = User32.Window.GetDC(handle); - iFace.surf = new Cairo.Win32Surface(hdc); - - } - - public void ProcessEvents() - { + WindowProcedureDelegate = WindowProcedure; + + Rect rect = new Rect + { + Left = iFace.ClientRectangle.Left, + Top = iFace.ClientRectangle.Top, + Right = iFace.ClientRectangle.Right, + Bottom = iFace.ClientRectangle.Bottom + }; + + User32.Window.AdjustWindowRectEx (ref rect, 0, false, 0); + + ExtendedWindowClass wc = new ExtendedWindowClass + { + Size = ExtendedWindowClass.SizeInBytes, + Style = 0, + WindowProc = WindowProcedureDelegate, + ClassExtra = 0, + WindowExtra = 0, + Instance = instance, + Icon = IntPtr.Zero, + Cursor = User32.Cursor.LoadCursor (CursorName.Arrow), + //Background = Gdi32.GetStockObject(GetStockObjectType.BlackBrush), + MenuName = null, + ClassName = className, + }; + + ushort atom = User32.WindowClass.RegisterClassEx (ref wc); + + handle = User32.Window.CreateWindowEx ( + ExtendedWindowStyles.ClientEdge, + className, + "The title of my window", + WindowStyles.OverlappedWindow, + + rect.Left, + rect.Top, + rect.Width, + rect.Height, + IntPtr.Zero, + IntPtr.Zero, + instance, + IntPtr.Zero + ); + + User32.Window.ShowWindow (handle, ShowWindowCommand.Show); + + hdc = User32.Window.GetDC (handle); + iFace.surf = new Cairo.Win32Surface (hdc); + + } + + public void ProcessEvents () { Msg msg; - while (User32.Message.PeekMessage(out msg, IntPtr.Zero, 0, 0, PeekMessageActions.Remove)) - { - User32.Message.TranslateMessage(ref msg); - User32.Message.DispatchMessage(ref msg); - } - } + while (User32.Message.PeekMessage (out msg, IntPtr.Zero, 0, 0, PeekMessageActions.Remove)) { + User32.Message.TranslateMessage (ref msg); + User32.Message.DispatchMessage (ref msg); + } + } public bool IsDown (Key key) { return false; @@ -140,19 +133,17 @@ namespace Crow.Win32 } } - void HandleWindowPositionChanged(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) - { - var pos = Marshal.PtrToStructure(lParam); - if (pos.HWnd == handle) - { - Rectangle bounds = new Rectangle(pos.X, pos.Y, pos.Width, pos.Height); + void HandleWindowPositionChanged (IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) { + var pos = Marshal.PtrToStructure (lParam); + if (pos.HWnd == handle) { + Rectangle bounds = new Rectangle (pos.X, pos.Y, pos.Width, pos.Height); User32.Window.SetWindowPos ( - handle, - IntPtr.Zero, - bounds.X, - bounds.Y, + handle, + IntPtr.Zero, + bounds.X, + bounds.Y, bounds.Width, bounds.Height, SetWindowPosFlags.NoZOrder | SetWindowPosFlags.NoOwnerZOrder | @@ -163,153 +154,151 @@ namespace Crow.Win32 } } - static Key GetKey(int code) - { - switch (code) - { - // 0 - 15 - case 0: return Key.NoSymbol; - case 1: return Key.Escape; - case 2: return Key.key_1; - case 3: return Key.key_2; - case 4: return Key.key_3; - case 5: return Key.key_4; - case 6: return Key.key_5; - case 7: return Key.key_6; - case 8: return Key.key_7; - case 9: return Key.key_8; - case 10: return Key.key_9; - case 11: return Key.key_0; - case 12: return Key.minus; - case 13: return Key.plus; - case 14: return Key.BackSpace; - case 15: return Key.Tab; + static Key GetKey (int code) { + switch (code) { + // 0 - 15 + case 0: return Key.NoSymbol; + case 1: return Key.Escape; + case 2: return Key.key_1; + case 3: return Key.key_2; + case 4: return Key.key_3; + case 5: return Key.key_4; + case 6: return Key.key_5; + case 7: return Key.key_6; + case 8: return Key.key_7; + case 9: return Key.key_8; + case 10: return Key.key_9; + case 11: return Key.key_0; + case 12: return Key.minus; + case 13: return Key.plus; + case 14: return Key.BackSpace; + case 15: return Key.Tab; // 16-31 - case 16: return Key.Q; - case 17: return Key.W; - case 18: return Key.E; - case 19: return Key.R; - case 20: return Key.T; - case 21: return Key.Y; - case 22: return Key.U; - case 23: return Key.I; - case 24: return Key.O; - case 25: return Key.P; - case 26: return Key.bracketleft; - case 27: return Key.bracketright; - case 28: return Key.Return; - case 29: return Key.Control_L; - case 30: return Key.A; - case 31: return Key.S; + case 16: return Key.Q; + case 17: return Key.W; + case 18: return Key.E; + case 19: return Key.R; + case 20: return Key.T; + case 21: return Key.Y; + case 22: return Key.U; + case 23: return Key.I; + case 24: return Key.O; + case 25: return Key.P; + case 26: return Key.bracketleft; + case 27: return Key.bracketright; + case 28: return Key.Return; + case 29: return Key.Control_L; + case 30: return Key.A; + case 31: return Key.S; // 32 - 47 - case 32: return Key.D; - case 33: return Key.F; - case 34: return Key.G; - case 35: return Key.H; - case 36: return Key.J; - case 37: return Key.K; - case 38: return Key.L; - case 39: return Key.semicolon; - case 40: return Key.quotedbl; - case 41: return Key.grave; - case 42: return Key.Shift_L; - case 43: return Key.backslash; - case 44: return Key.Z; - case 45: return Key.X; - case 46: return Key.C; - case 47: return Key.V; + case 32: return Key.D; + case 33: return Key.F; + case 34: return Key.G; + case 35: return Key.H; + case 36: return Key.J; + case 37: return Key.K; + case 38: return Key.L; + case 39: return Key.semicolon; + case 40: return Key.quotedbl; + case 41: return Key.grave; + case 42: return Key.Shift_L; + case 43: return Key.backslash; + case 44: return Key.Z; + case 45: return Key.X; + case 46: return Key.C; + case 47: return Key.V; // 48 - 63 - case 48: return Key.B; - case 49: return Key.N; - case 50: return Key.M; - case 51: return Key.comma; - case 52: return Key.period; - case 53: return Key.slash; - case 54: return Key.Shift_R; - case 55: return Key.Print; - case 56: return Key.Alt_L; - case 57: return Key.space; - case 58: return Key.Caps_Lock; - case 59: return Key.F1; - case 60: return Key.F2; - case 61: return Key.F3; - case 62: return Key.F4; - case 63: return Key.F5; + case 48: return Key.B; + case 49: return Key.N; + case 50: return Key.M; + case 51: return Key.comma; + case 52: return Key.period; + case 53: return Key.slash; + case 54: return Key.Shift_R; + case 55: return Key.Print; + case 56: return Key.Alt_L; + case 57: return Key.space; + case 58: return Key.Caps_Lock; + case 59: return Key.F1; + case 60: return Key.F2; + case 61: return Key.F3; + case 62: return Key.F4; + case 63: return Key.F5; // 64 - 79 - case 64: return Key.F6; - case 65: return Key.F7; - case 66: return Key.F8; - case 67: return Key.F9; - case 68: return Key.F10; - case 69: return Key.Num_Lock; - case 70: return Key.Scroll_Lock; - case 71: return Key.Home; - case 72: return Key.Up; - case 73: return Key.Page_Up; - case 74: return Key.KP_Subtract; - case 75: return Key.Left; - case 76: return Key.KP_5; - case 77: return Key.Right; - case 78: return Key.KP_Add; - case 79: return Key.End; + case 64: return Key.F6; + case 65: return Key.F7; + case 66: return Key.F8; + case 67: return Key.F9; + case 68: return Key.F10; + case 69: return Key.Num_Lock; + case 70: return Key.Scroll_Lock; + case 71: return Key.Home; + case 72: return Key.Up; + case 73: return Key.Page_Up; + case 74: return Key.KP_Subtract; + case 75: return Key.Left; + case 76: return Key.KP_5; + case 77: return Key.Right; + case 78: return Key.KP_Add; + case 79: return Key.End; // 80 - 95 - case 80: return Key.Down; - case 81: return Key.Page_Down; - case 82: return Key.Insert; - case 83: return Key.Delete; - case 84: return Key.NoSymbol; - case 85: return Key.NoSymbol; - case 86: return Key.NoSymbol; - case 87: return Key.F11; - case 88: return Key.F12; - case 89: return Key.Pause; - case 90: return Key.NoSymbol; - case 91: return Key.Meta_L; - case 92: return Key.Meta_R; - case 93: return Key.Menu; - case 94: return Key.NoSymbol; - case 95: return Key.NoSymbol; + case 80: return Key.Down; + case 81: return Key.Page_Down; + case 82: return Key.Insert; + case 83: return Key.Delete; + case 84: return Key.NoSymbol; + case 85: return Key.NoSymbol; + case 86: return Key.NoSymbol; + case 87: return Key.F11; + case 88: return Key.F12; + case 89: return Key.Pause; + case 90: return Key.NoSymbol; + case 91: return Key.Meta_L; + case 92: return Key.Meta_R; + case 93: return Key.Menu; + case 94: return Key.NoSymbol; + case 95: return Key.NoSymbol; // 96 - 106 - case 96: return Key.NoSymbol; - case 97: return Key.NoSymbol; - case 98: return Key.NoSymbol; - case 99: return Key.NoSymbol; - case 100: return Key.F13; - case 101: return Key.F14; - case 102: return Key.F15; - case 103: return Key.F16; - case 104: return Key.F17; - case 105: return Key.F18; - case 106: return Key.F19; - - default: return Key.NoSymbol; + case 96: return Key.NoSymbol; + case 97: return Key.NoSymbol; + case 98: return Key.NoSymbol; + case 99: return Key.NoSymbol; + case 100: return Key.F13; + case 101: return Key.F14; + case 102: return Key.F15; + case 103: return Key.F16; + case 104: return Key.F17; + case 105: return Key.F18; + case 106: return Key.F19; + + default: return Key.NoSymbol; } } const long ExtendedBit = 1 << 24; // Used to distinguish left and right control, alt and enter keys. void handleKeyboard (IntPtr lParam, IntPtr wParam, bool pressed) { - bool extended = (lParam.ToInt64() & ExtendedBit) != 0; - uint scancode = (uint)((lParam.ToInt64() >> 16) & 0xFF); + bool extended = (lParam.ToInt64 () & ExtendedBit) != 0; + uint scancode = (uint)((lParam.ToInt64 () >> 16) & 0xFF); //ushort repeat_count = unchecked((ushort)((ulong)lParam.ToInt64() & 0xffffu)); -// VirtualKey vkey = (VirtualKey)wParam; -// var key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out bool is_valid); + // VirtualKey vkey = (VirtualKey)wParam; + // var key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out bool is_valid); Key k = GetKey ((int)scancode); - if (pressed) + if (pressed) iFace.ProcessKeyDown (k); else - iFace.ProcessKeyUp (k); + iFace.ProcessKeyUp (k); } void handleChar (IntPtr lParam, IntPtr wParam) { char c = IntPtr.Size == 4 ? - (char)wParam.ToInt32() : - (char)wParam.ToInt64(); + (char)wParam.ToInt32 () : + (char)wParam.ToInt64 (); if (!char.IsControl (c)) iFace.ProcessKeyPress (c); @@ -317,153 +306,151 @@ namespace Crow.Win32 - IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) - { - var result = IntPtr.Zero; - - - switch (message) - { - case WindowMessage.MouseMove: - iFace.ProcessMouseMove - ((int)((uint)lParam.ToInt32() & 0x0000FFFF), (int)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16)); - break; - case WindowMessage.LButtonDown: - iFace.ProcessMouseButtonDown(Crow.MouseButton.Left); - return IntPtr.Zero; - case WindowMessage.RButtonDown: - iFace.ProcessMouseButtonDown(Crow.MouseButton.Right); - return IntPtr.Zero; - case WindowMessage.MButtonDown: - iFace.ProcessMouseButtonDown(Crow.MouseButton.Middle); - return IntPtr.Zero; - case WindowMessage.LButtonUp: - iFace.ProcessMouseButtonUp(Crow.MouseButton.Left); - return IntPtr.Zero; - case WindowMessage.RButtonUp: - iFace.ProcessMouseButtonUp(Crow.MouseButton.Right); - return IntPtr.Zero; - case WindowMessage.MButtonUp: - iFace.ProcessMouseButtonUp(Crow.MouseButton.Middle); - return IntPtr.Zero; - case WindowMessage.MouseWheel: - iFace.ProcessMouseWheelChanged ((((long)wParam << 32) >> 48) / 120.0f); - return IntPtr.Zero; - case WindowMessage.MouseHWheel: - iFace.ProcessMouseWheelChanged ((((long)wParam << 32) >> 48) / 120.0f); - return IntPtr.Zero; - case WindowMessage.KeyDown: - case WindowMessage.SystemKeyDown: - handleKeyboard (lParam, wParam, true); - return IntPtr.Zero; - case WindowMessage.KeyUp: - case WindowMessage.SystemKeyUp: - handleKeyboard (lParam, wParam, false); - return IntPtr.Zero; - case WindowMessage.Char: - handleChar (lParam, wParam); - break; - case WindowMessage.WindowPosChanged: - HandleWindowPositionChanged(handle, message, wParam, lParam); - break; - - - /*case WindowMessage.Activate: - HandleActivate(handle, message, wParam, lParam); - break; - - case WindowMessage.EnterMenuLoop: - case WindowMessage.EnterSizeMove: - HandleEnterModalLoop(handle, message, wParam, lParam); - break; - - case WindowMessage.ExitMenuLoop: - case WindowMessage.ExitSizeMove: - HandleExitModalLoop(handle, message, wParam, lParam); - break; - - case WindowMessage.EraseBackground: - // This is triggered only when the client area changes. - // As such it does not affect steady-state performance. - break; - - - case WindowMessage.StyleChanged: - HandleStyleChanged(handle, message, wParam, lParam); - break; - - case WindowMessage.Size: - HandleSize(handle, message, wParam, lParam); - break; - - case WindowMessage.SetCursor: - result = HandleSetCursor(handle, message, wParam, lParam); - break; - - case WindowMessage.CaptureChanged: - HandleCaptureChanged(handle, message, wParam, lParam); - break; - - case WindowMessage.Char: - HandleChar(handle, message, wParam, lParam); - break; - - - - case WindowMessage.MouseLeave: - HandleMouseLeave(handle, message, wParam, lParam); - break; - - case WindowMessage.MouseWheel: - HandleMouseWheel(handle, message, wParam, lParam); - return IntPtr.Zero; - - case WindowMessage.MouseHWheel: - HandleMouseHWheel(handle, message, wParam, lParam); - return IntPtr.Zero; - - - // Keyboard events: - case WindowMessage.KeyDown: - case WindowMessage.KeyUp: - case WindowMessage.SystemKeyDown: - case WindowMessage.SystemKeyUp: - HandleKeyboard(handle, message, wParam, lParam); - return IntPtr.Zero; - - case WindowMessage.SystemChar: - return IntPtr.Zero; - - case WindowMessage.KillFocus: - HandleKillFocus(handle, message, wParam, lParam); - break; - - case WindowMessage.DropFiles: - HandleDropFiles(handle, message, wParam, lParam); - break; - - case WindowMessage.Create: - HandleCreate(handle, message, wParam, lParam); - break; - case WindowMessage.Paint: - dc = User32.Window.BeginPaint(handle, out paintStruct); - - return IntPtr.Zero;*/ - case WindowMessage.Close: - User32.Window.DestroyWindow(handle); - return IntPtr.Zero; - case WindowMessage.Destroy: - User32.Message.PostQuitMessage(0); - //User32.WindowClass.UnregisterClass(className, instance); - break; - } - - if (result != IntPtr.Zero) - return result; + IntPtr WindowProcedure (IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) { + var result = IntPtr.Zero; + + + switch (message) { + case WindowMessage.MouseMove: + iFace.ProcessMouseMove + ((int)((uint)lParam.ToInt32 () & 0x0000FFFF), (int)(((uint)lParam.ToInt32 () & 0xFFFF0000) >> 16)); + break; + case WindowMessage.LButtonDown: + iFace.ProcessMouseButtonDown (Crow.MouseButton.Left); + return IntPtr.Zero; + case WindowMessage.RButtonDown: + iFace.ProcessMouseButtonDown (Crow.MouseButton.Right); + return IntPtr.Zero; + case WindowMessage.MButtonDown: + iFace.ProcessMouseButtonDown (Crow.MouseButton.Middle); + return IntPtr.Zero; + case WindowMessage.LButtonUp: + iFace.ProcessMouseButtonUp (Crow.MouseButton.Left); + return IntPtr.Zero; + case WindowMessage.RButtonUp: + iFace.ProcessMouseButtonUp (Crow.MouseButton.Right); + return IntPtr.Zero; + case WindowMessage.MButtonUp: + iFace.ProcessMouseButtonUp (Crow.MouseButton.Middle); + return IntPtr.Zero; + case WindowMessage.MouseWheel: + iFace.ProcessMouseWheelChanged ((((long)wParam << 32) >> 48) / 120.0f); + return IntPtr.Zero; + case WindowMessage.MouseHWheel: + iFace.ProcessMouseWheelChanged ((((long)wParam << 32) >> 48) / 120.0f); + return IntPtr.Zero; + case WindowMessage.KeyDown: + case WindowMessage.SystemKeyDown: + handleKeyboard (lParam, wParam, true); + return IntPtr.Zero; + case WindowMessage.KeyUp: + case WindowMessage.SystemKeyUp: + handleKeyboard (lParam, wParam, false); + return IntPtr.Zero; + case WindowMessage.Char: + handleChar (lParam, wParam); + break; + case WindowMessage.WindowPosChanged: + HandleWindowPositionChanged (handle, message, wParam, lParam); + break; + + + /*case WindowMessage.Activate: + HandleActivate(handle, message, wParam, lParam); + break; + + case WindowMessage.EnterMenuLoop: + case WindowMessage.EnterSizeMove: + HandleEnterModalLoop(handle, message, wParam, lParam); + break; + + case WindowMessage.ExitMenuLoop: + case WindowMessage.ExitSizeMove: + HandleExitModalLoop(handle, message, wParam, lParam); + break; + + case WindowMessage.EraseBackground: + // This is triggered only when the client area changes. + // As such it does not affect steady-state performance. + break; + + + case WindowMessage.StyleChanged: + HandleStyleChanged(handle, message, wParam, lParam); + break; + + case WindowMessage.Size: + HandleSize(handle, message, wParam, lParam); + break; + + case WindowMessage.SetCursor: + result = HandleSetCursor(handle, message, wParam, lParam); + break; + + case WindowMessage.CaptureChanged: + HandleCaptureChanged(handle, message, wParam, lParam); + break; + + case WindowMessage.Char: + HandleChar(handle, message, wParam, lParam); + break; + + + + case WindowMessage.MouseLeave: + HandleMouseLeave(handle, message, wParam, lParam); + break; + + case WindowMessage.MouseWheel: + HandleMouseWheel(handle, message, wParam, lParam); + return IntPtr.Zero; + + case WindowMessage.MouseHWheel: + HandleMouseHWheel(handle, message, wParam, lParam); + return IntPtr.Zero; + + + // Keyboard events: + case WindowMessage.KeyDown: + case WindowMessage.KeyUp: + case WindowMessage.SystemKeyDown: + case WindowMessage.SystemKeyUp: + HandleKeyboard(handle, message, wParam, lParam); + return IntPtr.Zero; + + case WindowMessage.SystemChar: + return IntPtr.Zero; + + case WindowMessage.KillFocus: + HandleKillFocus(handle, message, wParam, lParam); + break; + + case WindowMessage.DropFiles: + HandleDropFiles(handle, message, wParam, lParam); + break; + + case WindowMessage.Create: + HandleCreate(handle, message, wParam, lParam); + break; + case WindowMessage.Paint: + dc = User32.Window.BeginPaint(handle, out paintStruct); + + return IntPtr.Zero;*/ + case WindowMessage.Close: + User32.Window.DestroyWindow (handle); + return IntPtr.Zero; + case WindowMessage.Destroy: + User32.Message.PostQuitMessage (0); + //User32.WindowClass.UnregisterClass(className, instance); + break; + } - return User32.Window.DefWindowProc(handle, message, wParam, lParam); - } + if (result != IntPtr.Zero) + return result; + + return User32.Window.DefWindowProc (handle, message, wParam, lParam); + } - } + } } diff --git a/Crow/src/backends/xcb/XCBBackend.cs b/Crow/src/backends/xcb/XCBBackend.cs index 93a9be63..59376a8e 100644 --- a/Crow/src/backends/xcb/XCBBackend.cs +++ b/Crow/src/backends/xcb/XCBBackend.cs @@ -409,15 +409,13 @@ namespace Crow.XCB xcb_window_class_t.INPUT_OUTPUT, scr.root_visual, mask, intPtr); } - xcb_map_window (conn, win); xcb_flush (conn); - IntPtr visual = findVisual (scr_it, scr.root_visual); - loadCursors (); + //loadCursors (); iFace.surf = new Cairo.XcbSurface (conn, win, visual, iFace.ClientRectangle.Width, iFace.ClientRectangle.Height); } diff --git a/Samples/CrowIDE/CrowIDE.csproj b/Samples/CrowIDE/CrowIDE.csproj new file mode 100644 index 00000000..6670a8ed --- /dev/null +++ b/Samples/CrowIDE/CrowIDE.csproj @@ -0,0 +1,47 @@ + + + + net472 + net472 + Exe + Crow.Coding.CrowIDE + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\obj\$(Configuration) + false + false + 0.8.0 + + + + full + true + TRACE;DEBUG + + + + + + + + + + + + + + CrowIDE.icons.%(Filename)%(Extension) + + + + + Crow.Coding.%(Filename).template + + + Crow.%(Filename).template + + + + + + + diff --git a/Samples/CrowIDE/CrowIDE.userprefs b/Samples/CrowIDE/CrowIDE.userprefs new file mode 100644 index 00000000..0f4ab212 --- /dev/null +++ b/Samples/CrowIDE/CrowIDE.userprefs @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/CrowIDE/DefaultTemplateOverrides/ContextMenu.template b/Samples/CrowIDE/DefaultTemplateOverrides/ContextMenu.template new file mode 100644 index 00000000..38e6b7bf --- /dev/null +++ b/Samples/CrowIDE/DefaultTemplateOverrides/ContextMenu.template @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/Samples/CrowIDE/DefaultTemplateOverrides/MenuItem.template b/Samples/CrowIDE/DefaultTemplateOverrides/MenuItem.template new file mode 100644 index 00000000..2ed8496a --- /dev/null +++ b/Samples/CrowIDE/DefaultTemplateOverrides/MenuItem.template @@ -0,0 +1,29 @@ + + + + + + + diff --git a/Samples/CrowIDE/DefaultTemplateOverrides/TabItem.template b/Samples/CrowIDE/DefaultTemplateOverrides/TabItem.template new file mode 100644 index 00000000..c07119b8 --- /dev/null +++ b/Samples/CrowIDE/DefaultTemplateOverrides/TabItem.template @@ -0,0 +1,19 @@ + + + + + + + diff --git a/Samples/CrowIDE/IDE.style b/Samples/CrowIDE/IDE.style new file mode 100644 index 00000000..5b5054ab --- /dev/null +++ b/Samples/CrowIDE/IDE.style @@ -0,0 +1,64 @@ +Label { + Foreground="Black"; +} +icon { + Width="14"; + Height="14"; +} +MemberViewLabel { + Margin="1"; + Height="Fit"; + Width="50%"; + Background="White"; +} +MemberViewHStack { + Focusable="true"; + Height="Fit"; + Spacing="1"; + MouseEnter="{Background=SteelBlue}"; + MouseLeave="{Background=Transparent}"; +} + +IcoBut { + Template = "#Crow.Coding.IcoBut.template"; + MinimumSize = "10,10"; + Width = "8"; + Height = "14"; + Background = "Black"; +} + +WinSchema { + Template="#Crow.Coding.ui.DockWindows.WinSchemaItem.template"; + Focusable = "true"; + MinimumSize="150,50"; + Width = "Fit"; + Height = "Fit"; +} +TabItem { + AllowDrag="false"; + Background="Grey"; + SelectedBackground="0.9,0.9,0.91,1.0"; + Foreground="Black"; +} +TreeItemBorder { + CornerRadius="2"; + Margin="0"; + //Focusable="true"; + Height="Fit"; + Width="Stretched"; + Foreground="Transparent"; + MouseEnter="{Foreground=DimGrey}"; + MouseLeave="{Foreground=Transparent}"; +} +TreeIcon { + Margin="0"; + Width="14"; + Height="14"; +} +Splitter { + Thickness="1"; + Background="RoyalBlue"; +} +DockWindow { + Background="0.98,0.98,0.99,0.9"; +} diff --git a/Samples/CrowIDE/icons/basic_floppydisk.svg b/Samples/CrowIDE/icons/basic_floppydisk.svg new file mode 100644 index 00000000..55d901d4 --- /dev/null +++ b/Samples/CrowIDE/icons/basic_floppydisk.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/binding.svg b/Samples/CrowIDE/icons/binding.svg new file mode 100644 index 00000000..04f669ec --- /dev/null +++ b/Samples/CrowIDE/icons/binding.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/blank-file.svg b/Samples/CrowIDE/icons/blank-file.svg new file mode 100644 index 00000000..5880a3ab --- /dev/null +++ b/Samples/CrowIDE/icons/blank-file.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/center-align.svg b/Samples/CrowIDE/icons/center-align.svg new file mode 100644 index 00000000..92e3fac8 --- /dev/null +++ b/Samples/CrowIDE/icons/center-align.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/cogwheel.svg b/Samples/CrowIDE/icons/cogwheel.svg new file mode 100644 index 00000000..c104c470 --- /dev/null +++ b/Samples/CrowIDE/icons/cogwheel.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/compile.svg b/Samples/CrowIDE/icons/compile.svg new file mode 100644 index 00000000..c1a14e77 --- /dev/null +++ b/Samples/CrowIDE/icons/compile.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/copy-file.svg b/Samples/CrowIDE/icons/copy-file.svg new file mode 100644 index 00000000..63c2dd37 --- /dev/null +++ b/Samples/CrowIDE/icons/copy-file.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/cs-file.svg b/Samples/CrowIDE/icons/cs-file.svg new file mode 100644 index 00000000..5ddb69a3 --- /dev/null +++ b/Samples/CrowIDE/icons/cs-file.svg @@ -0,0 +1,11 @@ + + + + + Layer 1 + + + c + # + + \ No newline at end of file diff --git a/Samples/CrowIDE/icons/curly-brackets.svg b/Samples/CrowIDE/icons/curly-brackets.svg new file mode 100644 index 00000000..89ef798c --- /dev/null +++ b/Samples/CrowIDE/icons/curly-brackets.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/drawsvg.svg b/Samples/CrowIDE/icons/drawsvg.svg new file mode 100644 index 00000000..36ef290e --- /dev/null +++ b/Samples/CrowIDE/icons/drawsvg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Samples/CrowIDE/icons/edit.svg b/Samples/CrowIDE/icons/edit.svg new file mode 100644 index 00000000..73569d8d --- /dev/null +++ b/Samples/CrowIDE/icons/edit.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/eraser.svg b/Samples/CrowIDE/icons/eraser.svg new file mode 100644 index 00000000..5dd73bac --- /dev/null +++ b/Samples/CrowIDE/icons/eraser.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/expand-arrows-1.svg b/Samples/CrowIDE/icons/expand-arrows-1.svg new file mode 100644 index 00000000..5a77b1d1 --- /dev/null +++ b/Samples/CrowIDE/icons/expand-arrows-1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/file-code.svg b/Samples/CrowIDE/icons/file-code.svg new file mode 100644 index 00000000..2dc00db0 --- /dev/null +++ b/Samples/CrowIDE/icons/file-code.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/file.svg b/Samples/CrowIDE/icons/file.svg new file mode 100644 index 00000000..9d06b00b --- /dev/null +++ b/Samples/CrowIDE/icons/file.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/font-file.svg b/Samples/CrowIDE/icons/font-file.svg new file mode 100644 index 00000000..20beac14 --- /dev/null +++ b/Samples/CrowIDE/icons/font-file.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/light-bulb.svg b/Samples/CrowIDE/icons/light-bulb.svg new file mode 100644 index 00000000..4193a750 --- /dev/null +++ b/Samples/CrowIDE/icons/light-bulb.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/magic-wand.svg b/Samples/CrowIDE/icons/magic-wand.svg new file mode 100644 index 00000000..8b406918 --- /dev/null +++ b/Samples/CrowIDE/icons/magic-wand.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/magnet.svg b/Samples/CrowIDE/icons/magnet.svg new file mode 100644 index 00000000..10335f69 --- /dev/null +++ b/Samples/CrowIDE/icons/magnet.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/move-arrows.svg b/Samples/CrowIDE/icons/move-arrows.svg new file mode 100644 index 00000000..ecbb2f91 --- /dev/null +++ b/Samples/CrowIDE/icons/move-arrows.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/open-folder-1.svg b/Samples/CrowIDE/icons/open-folder-1.svg new file mode 100644 index 00000000..90294692 --- /dev/null +++ b/Samples/CrowIDE/icons/open-folder-1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/open.svg b/Samples/CrowIDE/icons/open.svg new file mode 100644 index 00000000..bd8d7d9b --- /dev/null +++ b/Samples/CrowIDE/icons/open.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/paint-brush.svg b/Samples/CrowIDE/icons/paint-brush.svg new file mode 100644 index 00000000..2bdd5bed --- /dev/null +++ b/Samples/CrowIDE/icons/paint-brush.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/palette.svg b/Samples/CrowIDE/icons/palette.svg new file mode 100644 index 00000000..8e425f70 --- /dev/null +++ b/Samples/CrowIDE/icons/palette.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/paragraph.svg b/Samples/CrowIDE/icons/paragraph.svg new file mode 100644 index 00000000..826aa63f --- /dev/null +++ b/Samples/CrowIDE/icons/paragraph.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/paste-on-document.svg b/Samples/CrowIDE/icons/paste-on-document.svg new file mode 100644 index 00000000..b0a705ee --- /dev/null +++ b/Samples/CrowIDE/icons/paste-on-document.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/pin.svg b/Samples/CrowIDE/icons/pin.svg new file mode 100644 index 00000000..b36340b8 --- /dev/null +++ b/Samples/CrowIDE/icons/pin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/previous.svg b/Samples/CrowIDE/icons/previous.svg new file mode 100644 index 00000000..566c8a3e --- /dev/null +++ b/Samples/CrowIDE/icons/previous.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/question.svg b/Samples/CrowIDE/icons/question.svg new file mode 100644 index 00000000..fb8e3d3f --- /dev/null +++ b/Samples/CrowIDE/icons/question.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/redo.svg b/Samples/CrowIDE/icons/redo.svg new file mode 100644 index 00000000..59fcc904 --- /dev/null +++ b/Samples/CrowIDE/icons/redo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/reply.svg b/Samples/CrowIDE/icons/reply.svg new file mode 100644 index 00000000..d008cb34 --- /dev/null +++ b/Samples/CrowIDE/icons/reply.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/save.svg b/Samples/CrowIDE/icons/save.svg new file mode 100644 index 00000000..6aa6714e --- /dev/null +++ b/Samples/CrowIDE/icons/save.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/scissors.svg b/Samples/CrowIDE/icons/scissors.svg new file mode 100644 index 00000000..4b5a2255 --- /dev/null +++ b/Samples/CrowIDE/icons/scissors.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/search.svg b/Samples/CrowIDE/icons/search.svg new file mode 100644 index 00000000..4a931b35 --- /dev/null +++ b/Samples/CrowIDE/icons/search.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/share-arrow.svg b/Samples/CrowIDE/icons/share-arrow.svg new file mode 100644 index 00000000..e0eb2462 --- /dev/null +++ b/Samples/CrowIDE/icons/share-arrow.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/sign-out.svg b/Samples/CrowIDE/icons/sign-out.svg new file mode 100644 index 00000000..c5951fc0 --- /dev/null +++ b/Samples/CrowIDE/icons/sign-out.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/text-file.svg b/Samples/CrowIDE/icons/text-file.svg new file mode 100644 index 00000000..eafca90c --- /dev/null +++ b/Samples/CrowIDE/icons/text-file.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/text-label.svg b/Samples/CrowIDE/icons/text-label.svg new file mode 100644 index 00000000..8fa91967 --- /dev/null +++ b/Samples/CrowIDE/icons/text-label.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Border.svg b/Samples/CrowIDE/icons/toolbox/Crow.Border.svg new file mode 100644 index 00000000..09eb7ac7 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Border.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Button.svg b/Samples/CrowIDE/icons/toolbox/Crow.Button.svg new file mode 100644 index 00000000..01f5c6c3 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Button.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.CheckBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.CheckBox.svg new file mode 100644 index 00000000..2f0b0834 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.CheckBox.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.ColorPicker.svg b/Samples/CrowIDE/icons/toolbox/Crow.ColorPicker.svg new file mode 100644 index 00000000..517a26a9 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.ColorPicker.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.ComboBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.ComboBox.svg new file mode 100644 index 00000000..1cb88fa2 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.ComboBox.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Container.svg b/Samples/CrowIDE/icons/toolbox/Crow.Container.svg new file mode 100644 index 00000000..d7d1dc8a --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Container.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.DirectoryView.svg b/Samples/CrowIDE/icons/toolbox/Crow.DirectoryView.svg new file mode 100644 index 00000000..90294692 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.DirectoryView.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Docker.svg b/Samples/CrowIDE/icons/toolbox/Crow.Docker.svg new file mode 100644 index 00000000..e38a283e --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Docker.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Expandable.svg b/Samples/CrowIDE/icons/toolbox/Crow.Expandable.svg new file mode 100644 index 00000000..1c56d56d --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Expandable.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.FileDialog.svg b/Samples/CrowIDE/icons/toolbox/Crow.FileDialog.svg new file mode 100644 index 00000000..25142ea0 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.FileDialog.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Grid.svg b/Samples/CrowIDE/icons/toolbox/Crow.Grid.svg new file mode 100644 index 00000000..6151f971 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Grid.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Group.svg b/Samples/CrowIDE/icons/toolbox/Crow.Group.svg new file mode 100644 index 00000000..eae67f63 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Group.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.GroupBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.GroupBox.svg new file mode 100644 index 00000000..e4697799 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.GroupBox.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.HorizontalStack.svg b/Samples/CrowIDE/icons/toolbox/Crow.HorizontalStack.svg new file mode 100644 index 00000000..f8e70257 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.HorizontalStack.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.IMLContainer.svg b/Samples/CrowIDE/icons/toolbox/Crow.IMLContainer.svg new file mode 100644 index 00000000..b5687bac --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.IMLContainer.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Image.svg b/Samples/CrowIDE/icons/toolbox/Crow.Image.svg new file mode 100644 index 00000000..11356c0e --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Image.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Label.svg b/Samples/CrowIDE/icons/toolbox/Crow.Label.svg new file mode 100644 index 00000000..65bb85b7 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Label.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.ListBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.ListBox.svg new file mode 100644 index 00000000..40d16734 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.ListBox.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Menu.svg b/Samples/CrowIDE/icons/toolbox/Crow.Menu.svg new file mode 100644 index 00000000..b6b21119 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Menu.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.MenuItem.svg b/Samples/CrowIDE/icons/toolbox/Crow.MenuItem.svg new file mode 100644 index 00000000..c8bd8470 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.MenuItem.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.MessageBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.MessageBox.svg new file mode 100644 index 00000000..16ebd72c --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.MessageBox.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.ProgressBar.svg b/Samples/CrowIDE/icons/toolbox/Crow.ProgressBar.svg new file mode 100644 index 00000000..884f1854 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.ProgressBar.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.RadioButton.svg b/Samples/CrowIDE/icons/toolbox/Crow.RadioButton.svg new file mode 100644 index 00000000..6c33e84b --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.RadioButton.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.ScrollBar.svg b/Samples/CrowIDE/icons/toolbox/Crow.ScrollBar.svg new file mode 100644 index 00000000..91a1f847 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.ScrollBar.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Scroller.svg b/Samples/CrowIDE/icons/toolbox/Crow.Scroller.svg new file mode 100644 index 00000000..bbc97197 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Scroller.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Shape.svg b/Samples/CrowIDE/icons/toolbox/Crow.Shape.svg new file mode 100644 index 00000000..de5dd372 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Shape.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Slider.svg b/Samples/CrowIDE/icons/toolbox/Crow.Slider.svg new file mode 100644 index 00000000..fe41c2ba --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Slider.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Spinner.svg b/Samples/CrowIDE/icons/toolbox/Crow.Spinner.svg new file mode 100644 index 00000000..5fa848ac --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Spinner.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Splitter.svg b/Samples/CrowIDE/icons/toolbox/Crow.Splitter.svg new file mode 100644 index 00000000..9fcd9dd7 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Splitter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TabItem.svg b/Samples/CrowIDE/icons/toolbox/Crow.TabItem.svg new file mode 100644 index 00000000..a9aaed33 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TabItem.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TabView.svg b/Samples/CrowIDE/icons/toolbox/Crow.TabView.svg new file mode 100644 index 00000000..942358b4 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TabView.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TemplatedContainer.svg b/Samples/CrowIDE/icons/toolbox/Crow.TemplatedContainer.svg new file mode 100644 index 00000000..34a0aa26 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TemplatedContainer.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TemplatedGroup.svg b/Samples/CrowIDE/icons/toolbox/Crow.TemplatedGroup.svg new file mode 100644 index 00000000..14ea6f37 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TemplatedGroup.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TextBox.svg b/Samples/CrowIDE/icons/toolbox/Crow.TextBox.svg new file mode 100644 index 00000000..c1fc2bb2 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TextBox.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.TreeView.svg b/Samples/CrowIDE/icons/toolbox/Crow.TreeView.svg new file mode 100644 index 00000000..b863291b --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.TreeView.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.VerticalStack.svg b/Samples/CrowIDE/icons/toolbox/Crow.VerticalStack.svg new file mode 100644 index 00000000..c3c3ec9c --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.VerticalStack.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Window.svg b/Samples/CrowIDE/icons/toolbox/Crow.Window.svg new file mode 100644 index 00000000..74b0a24b --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Window.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/Crow.Wrapper.svg b/Samples/CrowIDE/icons/toolbox/Crow.Wrapper.svg new file mode 100644 index 00000000..9e69e415 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/Crow.Wrapper.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/bar-chart.svg b/Samples/CrowIDE/icons/toolbox/bar-chart.svg new file mode 100644 index 00000000..ff86c961 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/bar-chart.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/bar-menu.svg b/Samples/CrowIDE/icons/toolbox/bar-menu.svg new file mode 100644 index 00000000..87ec0610 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/bar-menu.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/bullets.svg b/Samples/CrowIDE/icons/toolbox/bullets.svg new file mode 100644 index 00000000..81fb1f06 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/bullets.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/calendar.svg b/Samples/CrowIDE/icons/toolbox/calendar.svg new file mode 100644 index 00000000..9ceaa1ea --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/calendar.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/check-square-1.svg b/Samples/CrowIDE/icons/toolbox/check-square-1.svg new file mode 100644 index 00000000..e198007c --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/check-square-1.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/database.svg b/Samples/CrowIDE/icons/toolbox/database.svg new file mode 100644 index 00000000..65a8f065 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/database.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/ellipsis.svg b/Samples/CrowIDE/icons/toolbox/ellipsis.svg new file mode 100644 index 00000000..cff94ccf --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/ellipsis.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/exclamation-circle-1.svg b/Samples/CrowIDE/icons/toolbox/exclamation-circle-1.svg new file mode 100644 index 00000000..cc1b2689 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/exclamation-circle-1.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/exclamation-circle.svg b/Samples/CrowIDE/icons/toolbox/exclamation-circle.svg new file mode 100644 index 00000000..b140e7c8 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/exclamation-circle.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/file-code.svg b/Samples/CrowIDE/icons/toolbox/file-code.svg new file mode 100644 index 00000000..a2fd2d19 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/file-code.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/grab.svg b/Samples/CrowIDE/icons/toolbox/grab.svg new file mode 100644 index 00000000..25bc5719 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/grab.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/hard-drive-1.svg b/Samples/CrowIDE/icons/toolbox/hard-drive-1.svg new file mode 100644 index 00000000..a71a5248 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/hard-drive-1.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/hash.svg b/Samples/CrowIDE/icons/toolbox/hash.svg new file mode 100644 index 00000000..82196fbc --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/hash.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/info.svg b/Samples/CrowIDE/icons/toolbox/info.svg new file mode 100644 index 00000000..a8c90f4c --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/info.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/layout.svg b/Samples/CrowIDE/icons/toolbox/layout.svg new file mode 100644 index 00000000..3d59d765 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/layout.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/line-list.svg b/Samples/CrowIDE/icons/toolbox/line-list.svg new file mode 100644 index 00000000..ec15f7b8 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/line-list.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/list.svg b/Samples/CrowIDE/icons/toolbox/list.svg new file mode 100644 index 00000000..9aad88fa --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/list.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/modal-list.svg b/Samples/CrowIDE/icons/toolbox/modal-list.svg new file mode 100644 index 00000000..f1d8f70b --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/modal-list.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/options.svg b/Samples/CrowIDE/icons/toolbox/options.svg new file mode 100644 index 00000000..a56f6bed --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/options.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/package.svg b/Samples/CrowIDE/icons/toolbox/package.svg new file mode 100644 index 00000000..07f8b37e --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/package.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/padding.svg b/Samples/CrowIDE/icons/toolbox/padding.svg new file mode 100644 index 00000000..d93b2464 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/padding.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/picture-file.svg b/Samples/CrowIDE/icons/toolbox/picture-file.svg new file mode 100644 index 00000000..c45a6ad2 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/picture-file.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/pointer.svg b/Samples/CrowIDE/icons/toolbox/pointer.svg new file mode 100644 index 00000000..605c0e28 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/pointer.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/puzzle-piece.svg b/Samples/CrowIDE/icons/toolbox/puzzle-piece.svg new file mode 100644 index 00000000..b09c47e4 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/puzzle-piece.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/refresh-file.svg b/Samples/CrowIDE/icons/toolbox/refresh-file.svg new file mode 100644 index 00000000..248e4203 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/refresh-file.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/sliders.svg b/Samples/CrowIDE/icons/toolbox/sliders.svg new file mode 100644 index 00000000..81f72d18 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/sliders.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/split-browser-1.svg b/Samples/CrowIDE/icons/toolbox/split-browser-1.svg new file mode 100644 index 00000000..4dfd93a3 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/split-browser-1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/table.svg b/Samples/CrowIDE/icons/toolbox/table.svg new file mode 100644 index 00000000..0b421224 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/table.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/tasks.svg b/Samples/CrowIDE/icons/toolbox/tasks.svg new file mode 100644 index 00000000..8793c884 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/tasks.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Samples/CrowIDE/icons/toolbox/warning.svg b/Samples/CrowIDE/icons/toolbox/warning.svg new file mode 100644 index 00000000..f5a25735 --- /dev/null +++ b/Samples/CrowIDE/icons/toolbox/warning.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/tools.svg b/Samples/CrowIDE/icons/tools.svg new file mode 100644 index 00000000..5326f199 --- /dev/null +++ b/Samples/CrowIDE/icons/tools.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Samples/CrowIDE/icons/trash.svg b/Samples/CrowIDE/icons/trash.svg new file mode 100644 index 00000000..e73a5e33 --- /dev/null +++ b/Samples/CrowIDE/icons/trash.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/undo.svg b/Samples/CrowIDE/icons/undo.svg new file mode 100644 index 00000000..f78f1349 --- /dev/null +++ b/Samples/CrowIDE/icons/undo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/CrowIDE/icons/xml-file.svg b/Samples/CrowIDE/icons/xml-file.svg new file mode 100644 index 00000000..04204353 --- /dev/null +++ b/Samples/CrowIDE/icons/xml-file.svg @@ -0,0 +1,8 @@ + + + + + + +</> + \ No newline at end of file diff --git a/Samples/CrowIDE/icons/zoom-in.svg b/Samples/CrowIDE/icons/zoom-in.svg new file mode 100644 index 00000000..60c41d14 --- /dev/null +++ b/Samples/CrowIDE/icons/zoom-in.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/icons/zoom-out.svg b/Samples/CrowIDE/icons/zoom-out.svg new file mode 100644 index 00000000..bd4eec3a --- /dev/null +++ b/Samples/CrowIDE/icons/zoom-out.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/CrowIDE/images/save.svg b/Samples/CrowIDE/images/save.svg new file mode 100644 index 00000000..7bdc5518 --- /dev/null +++ b/Samples/CrowIDE/images/save.svg @@ -0,0 +1,3421 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/CrowIDE/src/CrowIDE.cs b/Samples/CrowIDE/src/CrowIDE.cs new file mode 100644 index 00000000..1b6ed151 --- /dev/null +++ b/Samples/CrowIDE/src/CrowIDE.cs @@ -0,0 +1,289 @@ +// +// HelloCube.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; +using System.IO; +using Crow; + +namespace Crow.Coding +{ + class CrowIDE : CrowVkWin + { + static void Main (string [] args) + { + using (CrowIDE app = new CrowIDE ()) { + app.initIde (); + app.reloadWinConfigs (); + app.Run (); + app.saveWinConfigs (); + } + } + + protected override void onLoad () + { + + } + public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, cmdCloseSolution, CMDQuit, + CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, + CMDAbout, CMDOptions, + CMDViewGTExp, CMDViewProps, CMDViewProj, CMDViewProjProps, CMDViewErrors, CMDViewSolution, CMDViewEditor, CMDViewProperties, + CMDViewToolbox, CMDViewSchema, CMDViewStyling,CMDViewDesign, + CMDCompile; + + void initCommands () { + CMDNew = new Command(new Action(() => newFile())) { Caption = "New", Icon = new SvgPicture("#CrowIDE.icons.blank-file.svg"), CanExecute = true}; + CMDOpen = new Command(new Action(() => openFileDialog())) { Caption = "Open...", Icon = new SvgPicture("#CrowIDE.icons.open.svg") }; + CMDSave = new Command(new Action(() => saveFileDialog())) { Caption = "Save", Icon = new SvgPicture("#CrowIDE.icons.save.svg"), CanExecute = false}; + CMDSaveAs = new Command(new Action(() => saveFileDialog())) { Caption = "Save As...", Icon = new SvgPicture("#CrowIDE.icons.save.svg"), CanExecute = false}; + //CMDQuit = new Command(new Action(() => running = false)) { Caption = "Quit", Icon = new SvgPicture("#CrowIDE.icons.sign-out.svg") }; + CMDUndo = new Command(new Action(() => undo())) { Caption = "Undo", Icon = new SvgPicture("#CrowIDE.icons.undo.svg"), CanExecute = false}; + CMDRedo = new Command(new Action(() => redo())) { Caption = "Redo", Icon = new SvgPicture("#CrowIDE.icons.redo.svg"), CanExecute = false}; + //CMDCut = new Command(new Action(() => Quit (null, null))) { Caption = "Cut", Icon = new SvgPicture("#CrowIDE.icons.scissors.svg"), CanExecute = false}; + //CMDCopy = new Command(new Action(() => Quit (null, null))) { Caption = "Copy", Icon = new SvgPicture("#CrowIDE.icons.copy-file.svg"), CanExecute = false}; + //CMDPaste = new Command(new Action(() => Quit (null, null))) { Caption = "Paste", Icon = new SvgPicture("#CrowIDE.icons.paste-on-document.svg"), CanExecute = false}; + CMDHelp = new Command(new Action(() => System.Diagnostics.Debug.WriteLine("help"))) { Caption = "Help", Icon = new SvgPicture("#CrowIDE.icons.question.svg") }; + CMDOptions = new Command(new Action(() => loadWindow("#CrowIDE.ui.Options.crow"))) { Caption = "Editor Options", Icon = new SvgPicture("#CrowIDE.icons.tools.svg") }; + + cmdCloseSolution = new Command(new Action(() => closeSolution())) + { Caption = "Close Solution", Icon = new SvgPicture("#CrowIDE.icons.paste-on-document.svg"), CanExecute = false}; + + CMDViewErrors = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winErrors.crow",this))) + { Caption = "Errors pane"}; + CMDViewSolution = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winSolution.crow",this))) + { Caption = "Solution Tree", CanExecute = false}; + CMDViewEditor = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winEditor.crow",this))) + { Caption = "Editor Pane"}; + CMDViewProperties = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winProperties.crow",this))) + { Caption = "Properties"}; + CMDViewDesign = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winDesign.crow",this))) + { Caption = "Quick Design", CanExecute = true}; + CMDViewToolbox = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winToolbox.crow",this))) + { Caption = "Toolbox", CanExecute = false}; + CMDViewSchema = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winSchema.crow",this))) + { Caption = "IML Shematic View", CanExecute = true}; + CMDViewStyling = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winStyleView.crow",this))) + { Caption = "Styling Explorer", CanExecute = true}; + + CMDViewGTExp = new Command(new Action(() => loadWindow ("#CrowIDE.ui.DockWindows.winGTExplorer.crow",this))) + { Caption = "Graphic Tree Explorer", CanExecute = true}; + CMDCompile = new Command(new Action(() => compileSolution())) + { Caption = "Compile", CanExecute = false}; + CMDViewProjProps = new Command(new Action(loadProjProps)) + { Caption = "Project Properties", CanExecute = false}; + } + + void openFileDialog () { + crow.AddWidget (instFileDlg.CreateInstance()).DataSource = this; + } + void openOptionsDialog(){} + void newFile() { + currentSolution.OpenedItems.AddElement(new ProjectFile()); + } + void saveFileDialog() {} + void undo() {} + void redo() {} + void closeSolution (){ + if (currentSolution != null) + currentSolution.CloseSolution (); + CurrentSolution = null; + } + + public void saveWinConfigs() { + Configuration.Global.Set ("WinConfigs", mainDock.ExportConfig ()); + Configuration.Global.Save (); + } + public void reloadWinConfigs() { + string conf = Configuration.Global.Get("WinConfigs"); + if (string.IsNullOrEmpty (conf)) + return; + mainDock.ImportConfig (conf, this); + } + + + static void App_KeyboardKeyDown (object sender, KeyEventArgs e) + { + Console.WriteLine((byte)e.Key); + //#if DEBUG_LOG + /*switch (e.Key) { + case Key.F2: + DebugLog.save (app); + break; + }*/ + //#endif + } + + + + IML.Instantiator instFileDlg; + Solution currentSolution; + Project currentProject; + DockStack mainDock; + + public static Interface MainIFace; + public static CrowIDE MainWin; + + void initIde() { + + initCommands (); + + Widget go = crow.Load (@"#CrowIDE.ui.CrowIDE.crow"); + go.DataSource = this; + + mainDock = go.FindByName ("mainDock") as DockStack; + ReopenLastSolution = false; + if (ReopenLastSolution && !string.IsNullOrEmpty (LastOpenSolution)) { + CurrentSolution = Solution.LoadSolution (LastOpenSolution); + //lock(MainIFace.UpdateMutex) + CurrentSolution.ReopenItemsSavedInUserConfig (); + } + + instFileDlg = IML.Instantiator.CreateFromImlFragment + (MainIFace, ""); + + /*DockWindow dw = loadWindow ("#CrowIDE.ui.DockWindows.winEditor.crow", this) as DockWindow; + dw.DockingPosition = Alignment.Center; + dw.Dock (mainDock); + dw = loadWindow ("#CrowIDE.ui.DockWindows.winSolution.crow", this) as DockWindow; + dw.DockingPosition = Alignment.Right; + dw.Dock (mainDock); + dw = loadWindow ("#CrowIDE.ui.DockWindows.winToolbox.crow", this) as DockWindow; + dw.DockingPosition = Alignment.Left; + dw.Dock (mainDock);*/ + + //Console.WriteLine (); + } + + void loadProjProps () { + loadWindow ("#CrowIDE.ui.ProjectProperties.crow"); + } + void compileSolution () { + //ProjectItem pi = CurrentSolution.SelectedItem; + Project p = CurrentSolution?.Projects[1]; + if (p == null) + return; + p.Compile (); + } + + public string CurrentDirectory { + get { return Crow.Configuration.Global.Get("CurrentDirectory");} + set { + Crow.Configuration.Global.Set ("CurrentDirectory", value); + } + } + public Solution CurrentSolution { + get { return currentSolution; } + set { + if (currentSolution == value) + return; + + currentSolution = value; + + CMDCompile.CanExecute = (currentSolution != null); + cmdCloseSolution.CanExecute = (currentSolution != null); + CMDViewSolution.CanExecute = (currentSolution != null); + + lock (MainIFace) { + NotifyValueChanged ("CurrentSolution", currentSolution); + } + } + } + public Project CurrentProject { + get { return currentProject; } + set { + if (currentProject == value) + return; + currentProject = value; + + CMDViewProjProps.CanExecute = (currentProject != null); + + lock (MainIFace) { + NotifyValueChanged ("CurrentProject", currentProject); + } + } + } + + public string LastOpenSolution { + get { return Crow.Configuration.Global.Get("LastOpenSolution");} + set { + if (LastOpenSolution == value) + return; + Crow.Configuration.Global.Set ("LastOpenSolution", value); + NotifyValueChanged ("LastOpenSolution", value); + } + } + public bool ReopenLastSolution { + get { return Crow.Configuration.Global.Get("ReopenLastSolution");} + set { + if (ReopenLastSolution == value) + return; + Crow.Configuration.Global.Set ("ReopenLastSolution", value); + NotifyValueChanged ("ReopenLastSolution", value); + } + } + + public void onFileOpen (object sender, EventArgs e) + { + FileDialog fd = sender as FileDialog; + + string filePath = fd.SelectedFileFullPath; + + try { + string ext = Path.GetExtension (filePath); + if (string.Equals (ext, ".sln", StringComparison.InvariantCultureIgnoreCase)) { + CurrentSolution = Solution.LoadSolution (filePath); + LastOpenSolution = filePath; +// }else if (string.Equals (ext, ".csproj", StringComparison.InvariantCultureIgnoreCase)) { +// currentProject = new Project (filePath); + } + } catch (Exception ex) { + crow.LoadIMLFragment (""); + } + } + + Window loadWindow(string path, object dataSource = null){ + try { + Widget g = MainIFace.FindByName (path); + if (g != null) + return g as Window; + g = MainIFace.Load (path); + g.Name = path; + g.DataSource = dataSource; + return g as Window; + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + return null; + } + void closeWindow (string path){ + Widget g = MainIFace.FindByName (path); + if (g != null) + MainIFace.DeleteWidget (g); + } + + protected void onCommandSave(object sender, MouseButtonEventArgs e){ + System.Diagnostics.Debug.WriteLine("save"); + } + + void actionOpenFile(){ + System.Diagnostics.Debug.WriteLine ("OpenFile action"); + } + } +} \ No newline at end of file diff --git a/Samples/CrowIDE/src/DesignInterface.cs b/Samples/CrowIDE/src/DesignInterface.cs new file mode 100644 index 00000000..82c604c8 --- /dev/null +++ b/Samples/CrowIDE/src/DesignInterface.cs @@ -0,0 +1,190 @@ +// +// DesignInterface.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.Collections.Generic; +using System.IO; + + +namespace Crow.Coding +{ + public class DesignInterface : Interface, IValueChange + { + #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); + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + public DesignInterface (vkvg.Device dev) : base(dev) + { + } + + public ProjectFile ProjFile; + + + + public override Widget CreateInstance (string path) + { + ProjectFile pi; + + if (ProjFile.Project.solution.GetProjectFileFromPath (path, out pi)) + return CreateITorFromIMLFragment (pi.Source).CreateInstance(); + + return null; + } + public override Stream GetStreamFromPath (string path) + { + ProjectFile pi; + if (ProjFile.Project.solution.GetProjectFileFromPath (path, out pi)) { + return new FileStream (pi.AbsolutePath, FileMode.Open); + } + throw new Exception ($"In Design File not found: {path}"); + } + + + public override 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); + if (!ActiveWidget.IsDragged)//if active is dragged, process mouse move as it was not visible. + return true; + } + + if (HoverWidget != null) { + + //check topmost graphicobject first + Widget tmp = HoverWidget; + Widget topc = null; + while (tmp is Widget) { + topc = tmp; + tmp = tmp.LogicalParent as Widget; + } + int idxhw = GraphicTree.IndexOf (topc); + if (idxhw != 0) { + int i = 0; + while (i < idxhw) { + if (GraphicTree [i].localLogicalParentIsNull) { + if (GraphicTree [i].MouseIsIn (e.Position)) { + while (HoverWidget != null) { + HoverWidget.onMouseLeave (HoverWidget, e); + HoverWidget = HoverWidget.LogicalParent as Widget; + } + + GraphicTree [i].checkHoverWidget (e); + return true; + } + } + i++; + } + } + + if (HoverWidget.MouseIsIn (e.Position)) { + if (!(HoverWidget is TemplatedControl)) + HoverWidget.checkHoverWidget (e); + return true; + } else { + HoverWidget.onMouseLeave (HoverWidget, e); + //seek upward from last focused graph obj's + while (HoverWidget.LogicalParent as Widget != null) { + HoverWidget = HoverWidget.LogicalParent as Widget; + if (HoverWidget.MouseIsIn (e.Position)) { + HoverWidget.checkHoverWidget (e); + return true; + } else + HoverWidget.onMouseLeave (HoverWidget, e); + } + } + } + + //top level graphic obj's parsing + lock (GraphicTree) { + for (int i = 0; i < GraphicTree.Count; i++) { + Widget g = GraphicTree [i]; + if (g.MouseIsIn (e.Position)) { + if (!(HoverWidget is TemplatedControl)) + g.checkHoverWidget (e); + if (g is Window) + PutOnTop (g); + return true; + } + } + } + HoverWidget = null; + return false; + } + + protected override void processLayouting () + { + #if MEASURE_TIME + layoutingMeasure.StartCycle(); + #endif + + if (Monitor.TryEnter (LayoutMutex)) { + DiscardQueue = new Queue (); + LayoutingQueueItem lqi; + while (LayoutingQueue.Count > 0) { + lqi = LayoutingQueue.Dequeue (); + //Console.WriteLine (lqi.ToString ()); + #if DEBUG_LAYOUTING + currentLQI = lqi; + curLQIsTries.Add(currentLQI); + #endif + lqi.ProcessLayouting (); + } + LayoutingQueue = DiscardQueue; + Monitor.Exit (LayoutMutex); + DiscardQueue = null; + } + + #if MEASURE_TIME + layoutingMeasure.StopCycle(); + #endif + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs new file mode 100644 index 00000000..7d5efec9 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs @@ -0,0 +1,530 @@ +// +// CodeTextBuffer.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 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; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Threading; + +namespace Crow.Coding +{ + /// + /// Code buffer, lines are arranged in a List, new line chars are removed during string.split on '\n...', + /// + public class CodeBuffer + { + public ReaderWriterLockSlim editMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + + //those events are handled in SourceEditor to help keeping sync between textbuffer,parser and editor. + //modified lines are marked for reparse + #region Events + public event EventHandler LineUpadateEvent; + public event EventHandler LineRemoveEvent; + public event EventHandler LineAdditionEvent; + public event EventHandler FoldingEvent; + public event EventHandler BufferCleared; + public event EventHandler SelectionChanged; + public event EventHandler PositionChanged; + #endregion + + string lineBreak = Interface.LineBreak; + List lines = new List(); + public int longestLineIdx = 0; + public int longestLineCharCount = 0; + /// + /// real position in char arrays, tab = 1 char + /// + int _currentLine = 0; + int _currentCol = 0; + + public int LineCount { get { return lines.Count;}} + public int IndexOf (CodeLine cl) { + return lines.IndexOf (cl); + } + + public CodeLine this[int i] + { + get { return i < LineCount ? lines[i] : null; } + set { + if (lines [i] == value) + return; + editMutex.EnterWriteLock (); + lines [i] = value; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + } + + public void RemoveAt(int i){ + editMutex.EnterWriteLock (); + lines.RemoveAt (i); + editMutex.ExitWriteLock (); + LineRemoveEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void Insert(int i, string item){ + editMutex.EnterWriteLock (); + lines.Insert (i, item); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void Add(CodeLine item){ + editMutex.EnterWriteLock (); + lines.Add (item); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (lines.Count - 1)); + } + public void AddRange (string[] items){ + int start = lines.Count; + editMutex.EnterWriteLock (); + for (int i = 0; i < items.Length; i++) + lines.Add (items [i]); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + } + public void AddRange (CodeLine[] items){ + int start = lines.Count; + editMutex.EnterWriteLock (); + lines.AddRange (items); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + } + public void Clear () { + editMutex.EnterWriteLock (); + longestLineCharCount = 0; + lines.Clear (); + editMutex.ExitWriteLock (); + BufferCleared.Raise (this, null); + } + public void UpdateLine(int i, string newContent){ + editMutex.EnterWriteLock (); + this [i].Content = newContent; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void AppenedLine(int i, string newContent){ + editMutex.EnterWriteLock (); + this [i].Content += newContent; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void RemoveLeadingTab (int l) { + if (this [l] [0] == '\t') { + UpdateLine (l, this [l].Content.Substring (1)); + return; + } + int i = 0; + while (i < Interface.TabSize) { + if (this [l] [i] != ' ') + break; + i++; + } + if (i > 0) + UpdateLine (l, this [l].Content.Substring (i)); + } + public void ToogleFolding (int line) { + if (!this [line].IsFoldable) + return; + editMutex.EnterWriteLock (); + this [line].IsFolded = !this [line].IsFolded; + editMutex.ExitWriteLock (); + FoldingEvent.Raise (this, new CodeBufferEventArgs (line)); + } + public void Load(string rawSource, string lineBrkRegex = @"\r\n|\r|\n|\\\n") { + this.Clear(); + + if (string.IsNullOrEmpty (rawSource)) + return; + + AddRange (Regex.Split (rawSource, lineBrkRegex)); + + lineBreak = detectLineBreakKind (rawSource); + } + + /// + /// Finds the longest visual line as printed on screen with tabulation replaced with n spaces + /// + public void FindLongestVisualLine(){ + longestLineCharCount = 0; + editMutex.EnterReadLock (); + for (int i = 0; i < this.LineCount; i++) { + if (lines[i].PrintableLength > longestLineCharCount) { + longestLineCharCount = lines[i].PrintableLength; + longestLineIdx = i; + } + } + editMutex.ExitReadLock (); + //Debug.WriteLine ("Longest line: {0}->{1}", longestLineIdx, longestLineCharCount); + } + /// line break could be '\r' or '\n' or '\r\n' + static string detectLineBreakKind(string buffer){ + string strLB = ""; + + if (string.IsNullOrEmpty(buffer)) + return Interface.LineBreak; + int i = 0; + while ( i < buffer.Length) { + if (buffer [i] == '\r') { + strLB += '\r'; + i++; + } + if (i < buffer.Length) { + if (buffer [i] == '\r') + return "\r"; + if (buffer[i] == '\n') + strLB += '\n'; + } + if (!string.IsNullOrEmpty (strLB)) + return strLB; + i++; + } + return Interface.LineBreak; + } + /// + /// return all lines with linebreaks + /// + public string FullText{ + get { + if (lines.Count == 0) + return ""; + string tmp = ""; + editMutex.EnterReadLock (); + for (int i = 0; i < lines.Count -1; i++) + tmp += lines [i].Content + this.lineBreak; + tmp += lines [lines.Count - 1].Content; + editMutex.ExitReadLock (); + return tmp; + } + } + + /// + /// unfolded and not in folds line count + /// + public int UnfoldedLines { + get { + int i = 0, vl = 0; + editMutex.EnterReadLock (); + while (i < LineCount) { + if (this [i].IsFolded) { + i = GetEndNodeIndex (i); + if (i < 0) { + Console.WriteLine ("error folding"); + break; + } + } + i++; + vl++; + } + editMutex.ExitReadLock (); + //Debug.WriteLine ("unfolded lines: " + vl); + return vl; + } + } + + /// + /// convert visual position to buffer position + /// + Point getBuffPos (Point visualPos) { + int i = 0; + int buffCol = 0; + while (i < visualPos.X) { + if (this [visualPos.Y] [buffCol] == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + return new Point (buffCol, visualPos.Y); + } + + public int GetEndNodeIndex (int line) { + return IndexOf (this [line].SyntacticNode.EndLine); + } + + int ConverteTabulatedPosOfCurLine (int column) { + int tmp = 0; + int i = 0; + while (i < lines [_currentLine].Content.Length){ + if (lines [_currentLine].Content [i] == '\t') + tmp += 4; + else + tmp++; + if (tmp > column) + break; + i++; + } + return i; + } + + public int CurrentTabulatedColumn { + get { + return lines [_currentLine].Content.Substring (0, _currentCol). + Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + } + /// + /// Gets visual position computed from actual buffer position + /// +// public Point TabulatedPosition { +// get { return new Point (TabulatedColumn, _currentLine); } +// } + /// + /// set buffer current position from visual position + /// +// public void SetBufferPos(Point tabulatedPosition) { +// CurrentPosition = getBuffPos(tabulatedPosition); +// } + + #region Editing and moving cursor + Point selStartPos = -1; //selection start (row,column) + Point selEndPos = -1; //selection end (row,column) + + public bool SelectionInProgress { get { return selStartPos >= 0; }} + public void SetSelStartPos () { + selStartPos = selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + public void SetSelEndPos () { + selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + public void SetSelectionOnFullLines () { + if (!SelectionInProgress) + return; + Point s = new Point (0, SelectionStart.Y); + Point e = new Point (this [SelectionEnd.Y].Length, SelectionEnd.Y); + selStartPos = s; + selEndPos = e; + SelectionChanged.Raise (this, null); + } + /// + /// Set selection in buffer to -1, empty selection + /// + public void ResetSelection () { + selStartPos = selEndPos = -1; + SelectionChanged.Raise (this, null); + } + + public string SelectedText { + get { + if (SelectionIsEmpty) + return ""; + Point selStart = SelectionStart; + Point selEnd = SelectionEnd; + if (selStart.Y == selEnd.Y) + return this [selStart.Y].Content.Substring (selStart.X, selEnd.X - selStart.X); + string tmp = ""; + tmp = this [selStart.Y].Content.Substring (selStart.X); + for (int l = selStart.Y + 1; l < selEnd.Y; l++) { + tmp += Interface.LineBreak + this [l].Content; + } + tmp += Interface.LineBreak + this [selEnd.Y].Content.Substring (0, selEnd.X); + return tmp; + } + } + /// + /// ordered selection start and end positions in char units + /// + public Point SelectionStart { + get { return selEndPos < 0 || selStartPos.Y < selEndPos.Y ? selStartPos : + selStartPos.Y > selEndPos.Y ? selEndPos : + selStartPos.X < selEndPos.X ? selStartPos : selEndPos; } + } + public Point SelectionEnd { + get { return selEndPos < 0 || selStartPos.Y > selEndPos.Y ? selStartPos : + selStartPos.Y < selEndPos.Y ? selEndPos : + selStartPos.X > selEndPos.X ? selStartPos : selEndPos; } + } + public bool SelectionIsEmpty + { get { return selEndPos == selStartPos; } } + int requestedColumn = -1; + /// + /// Current column in buffer coordinate, tabulation = 1 char + /// + public int CurrentColumn{ + get { return _currentCol; } + set { + if (value == _currentCol) + return; + + editMutex.EnterReadLock (); + + if (value < 0) + _currentCol = 0; + else if (value > lines [_currentLine].Length) + _currentCol = lines [_currentLine].Length; + else + _currentCol = value; + + requestedColumn = CurrentTabulatedColumn; + + editMutex.ExitReadLock (); + + PositionChanged.Raise (this, null); + } + } + /// + /// Current row in buffer coordinate, tabulation = 1 char + /// + public int CurrentLine{ + get { return _currentLine; } + set { + if (value == _currentLine) + return; + + editMutex.EnterReadLock (); + + if (LineCount == 0) + _currentLine = 0; + else if (value >= lines.Count) + _currentLine = lines.Count-1; + else if (value < 0) + _currentLine = 0; + else + _currentLine = value; +// if (_currentCol < 0) +// requestedColumn = tabu _currentCol; + int tabulatedRequestedCol = ConverteTabulatedPosOfCurLine(requestedColumn); + if (requestedColumn > lines [_currentLine].PrintableLength) + _currentCol = lines [_currentLine].Length; + else + //_currentCol = requestedColumn; + _currentCol = tabulatedRequestedCol; + //Debug.WriteLine ("buff cur line: " + _currentLine); + + editMutex.ExitReadLock(); + + PositionChanged.Raise (this, null); + } + } + public CodeLine CurrentCodeLine { + get { return this [_currentLine]; } + } + /// + /// Current position in buffer coordinate, tabulation = 1 char + /// + public Point CurrentPosition { + get { return new Point(CurrentColumn, CurrentLine); } +// set { +// _currentCol = value.X; +// _currentLine = value.Y; +// } + } + /// + /// get char at current position in buffer + /// + protected Char CurrentChar { get { return lines [CurrentLine] [CurrentColumn]; } } + + public void GotoWordStart(){ + if (this[CurrentLine].Length == 0) + return; + CurrentColumn--; + //skip white spaces + while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) + CurrentColumn--; + while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) + CurrentColumn--; + if (!char.IsLetterOrDigit (this.CurrentChar)) + CurrentColumn++; + } + public void GotoWordEnd(){ + //skip white spaces + if (CurrentColumn >= this [CurrentLine].Length - 1) + return; + while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) + CurrentColumn++; + while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) + CurrentColumn++; + if (char.IsLetterOrDigit (this.CurrentChar)) + CurrentColumn++; + } + public void DeleteChar() + { + editMutex.EnterWriteLock (); + if (SelectionIsEmpty) { + if (CurrentColumn == 0) { + if (CurrentLine == 0) { + editMutex.ExitWriteLock (); + return; + } + CurrentLine--; + CurrentColumn = this [CurrentLine].Length; + AppenedLine (CurrentLine, this [CurrentLine + 1].Content); + RemoveAt (CurrentLine + 1); + editMutex.ExitWriteLock (); + return; + } + CurrentColumn--; + UpdateLine (CurrentLine, this [CurrentLine].Content.Remove (CurrentColumn, 1)); + } else { + int linesToRemove = SelectionEnd.Y - SelectionStart.Y + 1; + int l = SelectionStart.Y; + + if (linesToRemove > 0) { + UpdateLine (l, this [l].Content.Remove (SelectionStart.X, this [l].Length - SelectionStart.X) + + this [SelectionEnd.Y].Content.Substring (SelectionEnd.X, this [SelectionEnd.Y].Length - SelectionEnd.X)); + l++; + for (int c = 0; c < linesToRemove - 1; c++) + RemoveAt (l); + CurrentLine = SelectionStart.Y; + CurrentColumn = SelectionStart.X; + } else + UpdateLine (l, this [l].Content.Remove (SelectionStart.X, SelectionEnd.X - SelectionStart.X)); + CurrentColumn = SelectionStart.X; + ResetSelection (); + } + editMutex.ExitWriteLock (); + } + /// + /// Insert new string at caret position, should be sure no line break is inside. + /// + /// String. + public void Insert(string str) + { + if (!SelectionIsEmpty) + this.DeleteChar (); + string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray(); + UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[0])); + CurrentColumn += strLines[0].Length; + for (int i = 1; i < strLines.Length; i++) { + InsertLineBreak (); + UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[i])); + CurrentColumn += strLines[i].Length; + } + } + /// + /// Insert a line break. + /// + public void InsertLineBreak() + { + if (CurrentColumn > 0) { + Insert (CurrentLine + 1, this [CurrentLine].Content.Substring (CurrentColumn)); + UpdateLine (CurrentLine, this [CurrentLine].Content.Substring (0, CurrentColumn)); + } else + Insert(CurrentLine, ""); + + CurrentColumn = 0; + CurrentLine++; + } + #endregion + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs new file mode 100644 index 00000000..07dd25b6 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Crow.Coding +{ + public class CodeBufferEventArgs : EventArgs { + public int LineStart; + public int LineCount; + + public CodeBufferEventArgs(int lineNumber) { + LineStart = lineNumber; + LineCount = 1; + } + public CodeBufferEventArgs(int lineStart, int lineCount) { + LineStart = lineStart; + LineCount = lineCount; + } + } + +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs new file mode 100644 index 00000000..23f43fba --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs @@ -0,0 +1,82 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +namespace Crow.Coding +{ + public class CodeLine + { + public string Content; + public List Tokens; + public int EndingState = 0; + public Node SyntacticNode; + public ParserException exception; + + public CodeLine (string _content){ + Content = _content; + Tokens = null; + exception = null; + } + + public char this[int i] + { + get { return Content[i]; } + set { + if (Content [i] == value) + return; + StringBuilder sb = new StringBuilder(Content); + sb[i] = value; + Content = sb.ToString(); + Tokens = null; + //LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + } + public bool IsFoldable { get { return SyntacticNode == null ? false : + SyntacticNode.EndLine != SyntacticNode.StartLine && SyntacticNode.EndLine != null; } } + public int FoldingLevel { get { return IsFoldable ? SyntacticNode.Level : 0; } } + public bool IsFolded = false; + public bool IsParsed { + get { return Tokens != null; } + } + public string PrintableContent { + get { + return string.IsNullOrEmpty (Content) ? "" : Content.Replace ("\t", new String (' ', Interface.TabSize)); + } + } + public int PrintableLength { + get { + return PrintableContent.Length; + } + } + public int Length { + get { + return string.IsNullOrEmpty (Content) ? 0 : Content.Length; + } + } + public int FirstNonBlankTokIndex { + get { return Tokens == null ? -1 : Tokens.FindIndex (tk=>tk.Type != BufferParser.TokenType.WhiteSpace); } + } + + public void SetLineInError (ParserException ex) { + Tokens = null; + exception = ex; + } + +// public static implicit operator string(CodeLine sl) { +// return sl == null ? "" : sl.Content; +// } + public static implicit operator CodeLine(string s) { + return new CodeLine(s); + } + public static bool operator ==(string s1, CodeLine s2) + { + return string.Equals (s1, s2.Content); + } + public static bool operator !=(string s1, CodeLine s2) + { + return !string.Equals (s1, s2.Content); + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/Node.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/Node.cs new file mode 100644 index 00000000..9db55428 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/Node.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace Crow.Coding +{ + public class Node + { + public Node Parent; + public string Name; + public string Type; + public CodeLine StartLine; + public CodeLine EndLine; + public Dictionary Attributes = new Dictionary (); + + public List Children = new List(); + + public Node () + { + } + + public void AddChild (Node child) { + child.Parent = this; + Children.Add (child); + } + + public int Level { + get { return Parent == null ? 1 : Parent.Level + 1; } + } + + public override string ToString () + { + return string.Format ("Name:{0}, Type:{1}\n\tparent:{2}", Name, Type, Parent); + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs new file mode 100644 index 00000000..e8c87182 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs @@ -0,0 +1,527 @@ +// +// CodeTextBuffer.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 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; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Threading; +using System.Text; + +namespace Crow.Text +{ + /// + /// Code buffer, lines are arranged in a List, new line chars are removed during string.split on '\n...', + /// + public class TextBuffer + { + public ReaderWriterLockSlim editMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + static Regex slb = new Regex ("\\n");//single char line break used internaly + Regex reghexLineBrk = new Regex(@"\r\n|\r|\n|\\\n");//original text line break regex + + #region Events + public event EventHandler LineUpadateEvent; + public event EventHandler LineRemoveEvent; + public event EventHandler LineAdditionEvent; + public event EventHandler BufferCleared; + public event EventHandler SelectionChanged; + public event EventHandler PositionChanged; + #endregion + + StringBuilder buffer = new StringBuilder(); + string lineBreak = Interface.LineBreak;//detected linebreak kind in original source + List lineLength = new List();//line length table + /// + /// real position in char arrays, tab = 1 char + /// + int _currentLine = 0; + int _currentCol = 0; + + /// + /// Gets the total line count. + /// + public int LineCount { get { return lineLength.Count;}} + + /// + /// get a substring in the buffer + /// + /// a new string + /// absolute index in the buffer + /// length of the substring + public string GetSubString (int idx, int length){ + return buffer.ToString (idx, length); + } + /// + /// Gets length of a line. + /// + /// length of line + /// line nuber + public int GetLineLength (int lineIdx) { + return lineLength [lineIdx]; + } + /// + /// get a single charactere in the buffer + /// + /// a single char + /// absolute index in the buffer + public char GetCharAt (int idx){ + return buffer [idx]; + } + /// + /// return full text with original line breaks + /// + /// a string containing the full text + public string FullText { + get { return buffer.Replace("\n", lineBreak).ToString (); } + set { + Load (value); + } + } + /// + /// Gets the buffer pointer of a line + /// + /// absolute index of the line in the buffer + /// line number + public int GetBufferIndexOfLine (int i) { + int ptr = 0; + editMutex.EnterReadLock (); + for (int j = 0; j < i; j++) { + ptr += lineLength [j]; + } + editMutex.ExitReadLock (); + return ptr; + } + /// + /// Gets the buffer pointer for the current position + /// + /// absolute index in the buffer of current position + public int BufferIndexOfCurrentPosition { + get {return GetBufferIndexOfLine (_currentLine) + _currentCol;} + } + public int this[int i] + { + get { + int ptr = 0; + editMutex.EnterReadLock (); + for (int j = 0; j < i; j++) { + ptr += lineLength [j]; + } + editMutex.ExitReadLock (); + return ptr; + } + } + /// + /// remove line number i + /// + /// index of the line + public void RemoveLine(int i){ + editMutex.EnterWriteLock (); + buffer.Remove (GetBufferIndexOfLine (i), lineLength [i]); + lineLength.RemoveAt (i); + editMutex.ExitWriteLock (); + LineRemoveEvent.Raise (this, new TextBufferEventArgs (i)); + } + /// + /// insert string without linebreaks at position i in buff + /// + /// absolute index in the buffer + /// linebreak free string + public void InsertAt(int i, string str){ + editMutex.EnterWriteLock (); + buffer.Insert (this [i], str); + lineLength.Insert (i, str.Length); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (i)); + } + public void AddLine(string str){ + editMutex.EnterWriteLock (); + if (lineLength.LastOrDefault() == 0) { + buffer.Append (str); + lineLength [lineLength.Count - 1] = str.Length; + lineLength.Add (0); + } + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (lineLength.Count - 1)); + } + public void AddRange (string[] items){ + int start = lineLength.Count; + editMutex.EnterWriteLock (); + for (int i = 0; i < items.Length; i++) + AddLine (items [i]); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (start, items.Length)); + } + public void Clear () { + editMutex.EnterWriteLock (); + lineLength.Clear (); + buffer.Clear (); + editMutex.ExitWriteLock (); + BufferCleared.Raise (this, null); + } + public void UpdateLine(int i, string newContent){ + editMutex.EnterWriteLock (); + int ptrL = this [i]; + buffer.Remove (ptrL, lineLength [i]); + buffer.Insert (ptrL, newContent); + lineLength [i] = newContent.Length; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new TextBufferEventArgs (i)); + } + public void AppenedLine(int i, string newContent){ + editMutex.EnterWriteLock (); + int ptr = this [i] + lineLength [i]; + if (i < LineCount - 1) + ptr--; + buffer.Insert(ptr, newContent); + lineLength [i] += newContent.Length; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new TextBufferEventArgs (i)); + } + /// + /// Insert new string at caret position, should be sure no line break is inside. + /// + /// String. + public void InsertAt(string str) + { + if (!SelectionIsEmpty) + this.Delete (); + + editMutex.EnterWriteLock (); + + string tmp = reghexLineBrk.Replace (str, "\n");//use single char line break in buffer + int buffPtr = this [CurrentLine] + CurrentColumn; + buffer.Insert (buffPtr, tmp); + + int lPtr = CurrentLine, strPtr = 0; + int remainingLength = lineLength [lPtr] - CurrentColumn; + lineLength [lPtr] = CurrentColumn; + foreach (Match match in slb.Matches(tmp)) + { + lineLength [lPtr] += match.Index + 1 - strPtr; + lPtr++; + lineLength.Insert (lPtr, 0); + strPtr = match.Index + 1; + //CurrentLine++; + } + remainingLength += tmp.Length - strPtr; + lineLength [lPtr] += remainingLength; + + CurrentLine = lPtr; + if (strPtr == 0) + CurrentColumn += tmp.Length; + else + CurrentColumn = tmp.Length - strPtr; + + editMutex.ExitWriteLock (); + if (strPtr>0) + LineAdditionEvent.Raise (this, null); + else + LineUpadateEvent.Raise (this, null); + } + /// + /// Insert a line break. + /// + public void InsertLineBreak() + { + editMutex.EnterWriteLock (); + buffer.Insert (this [CurrentLine] + CurrentColumn, '\n'); + int lgdiff = lineLength [CurrentLine] - CurrentColumn; + lineLength.Insert (CurrentLine + 1, lineLength [CurrentLine] - CurrentColumn); + lineLength [CurrentLine] = CurrentColumn + 1; + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, null); + CurrentColumn = 0; + CurrentLine++; + } + public void Delete() + { + editMutex.EnterWriteLock (); + if (SelectionIsEmpty) { + if (CurrentColumn == 0) { + if (CurrentLine == 0) { + editMutex.ExitWriteLock (); + return; + } + + buffer.Remove (this [CurrentLine] - 1, 1); + + int col = lineLength [CurrentLine - 1] - 1; + lineLength [CurrentLine - 1] += lineLength [CurrentLine] - 1; + lineLength.RemoveAt (CurrentLine); + + CurrentLine--; + CurrentColumn = col; + + editMutex.ExitWriteLock (); + LineRemoveEvent.Raise (this, null); + return; + } + CurrentColumn--; + buffer.Remove (this [CurrentLine] + CurrentColumn, 1); + lineLength [CurrentLine]--; + } else { + int linesToRemove = SelectionEnd.Y - SelectionStart.Y; + int ptr = this [SelectionStart.Y] + SelectionStart.X; + int length = lineLength [SelectionStart.Y] - SelectionStart.X; + int l = 1; + while (l <= linesToRemove ) { + length += lineLength [SelectionStart.Y + l]; + l++; + } + length -= lineLength [SelectionEnd.Y] - SelectionEnd.X; + buffer.Remove (ptr, length); + lineLength [SelectionStart.Y] = SelectionStart.X + lineLength [SelectionEnd.Y] - SelectionEnd.X; + lineLength.RemoveRange (SelectionStart.Y + 1, linesToRemove); + + CurrentLine = SelectionStart.Y; + CurrentColumn = SelectionStart.X; + ResetSelection (); + + if (linesToRemove > 0) + LineRemoveEvent.Raise (this, null); + else + LineUpadateEvent.Raise (this, null); + } + editMutex.ExitWriteLock (); + } + public void Load(string rawSource) { + this.Clear(); + + if (string.IsNullOrEmpty (rawSource)) + return; + + lineBreak = reghexLineBrk.Match (rawSource).Value;//store original line break + string tmp = reghexLineBrk.Replace (rawSource, "\n");//use single char line break in buffer + int ptr = 0; + foreach (Match match in slb.Matches(tmp)) + { + int l = match.Index + 1; + int lg = l - ptr; + lineLength.Add (lg); + ptr = l; + } + lineLength.Add (0); + + buffer = new StringBuilder (tmp); + } + +// public int CurrentTabulatedColumn { +// get { +//// return lines [_currentLine].Content.Substring (0, _currentCol). +//// Replace ("\t", new String (' ', Interface.TabSize)).Length; +// } +// } + + #region moving cursor an selection + Point selStartPos = -1; //selection start (row,column) + Point selEndPos = -1; //selection end (row,column) + + public bool SelectionInProgress { get { return selStartPos >= 0; }} + public void SetSelStartPos () { + selStartPos = selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + public void SetSelEndPos () { + selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + /// + /// Set selection in buffer to -1, empty selection + /// + public void ResetSelection () { + selStartPos = selEndPos = -1; + SelectionChanged.Raise (this, null); + } + /// + /// ordered selection start and end positions in char units + /// + public Point SelectionStart { + get { return selEndPos < 0 || selStartPos.Y < selEndPos.Y ? selStartPos : + selStartPos.Y > selEndPos.Y ? selEndPos : + selStartPos.X < selEndPos.X ? selStartPos : selEndPos; } + } + public Point SelectionEnd { + get { return selEndPos < 0 || selStartPos.Y > selEndPos.Y ? selStartPos : + selStartPos.Y < selEndPos.Y ? selEndPos : + selStartPos.X > selEndPos.X ? selStartPos : selEndPos; } + } + public bool SelectionIsEmpty + { get { return selEndPos == selStartPos; } } + /// + /// Current column in buffer coordinate, tabulation = 1 char + /// + public int CurrentColumn{ + get { return _currentCol; } + set { + if (value == _currentCol) + return; + + editMutex.EnterWriteLock (); + + if (value < 0) + _currentCol = 0; + else if (value >= lineLength [_currentLine]) { + if (_currentLine < LineCount -1 && value > lineLength [_currentLine] - 1) + _currentCol = lineLength [_currentLine] - 1; + else + _currentCol = lineLength [_currentLine]; + }else + _currentCol = value; + + editMutex.ExitWriteLock (); + + PositionChanged.Raise (this, null); + } + } + /// + /// Current row in buffer coordinate, tabulation = 1 char + /// + public int CurrentLine{ + get { return _currentLine; } + set { + if (value == _currentLine) + return; + + editMutex.EnterWriteLock (); + + if (value >= lineLength.Count) + _currentLine = lineLength.Count-1; + else if (value < 0) + _currentLine = 0; + else + _currentLine = value; + + int c = _currentCol; + _currentCol = 0; + CurrentColumn = c; + + editMutex.ExitWriteLock(); + + PositionChanged.Raise (this, null); + } + } + /// + /// Current position in buffer coordinate, tabulation = 1 char + /// + public Point CurrentPosition { + get { return new Point(CurrentColumn, CurrentLine); } + } + /// + /// get char at current position in buffer + /// + protected Char CurrentChar { get { return buffer[this [CurrentLine]]; } } + public string SelectedText { + get { + if (SelectionIsEmpty) + return ""; + Point selStart = SelectionStart; + Point selEnd = SelectionEnd; + + int ptr = this [selStart.Y] + selStart.X; + int length = lineLength[selStart.Y] - selStart.X; + for (int i = selStart.Y+1; i <= selEnd.Y; i++) + length += lineLength [i]; + length -= lineLength[selEnd.Y] - selEnd.X; + + return buffer.ToString (ptr, length); + } + } + + public void GotoWordStart(){ + if (_currentCol == 0) + MoveLeft (); + if (_currentCol == 0) + return; + int ptrStart = BufferIndexOfCurrentPosition; + int ptr = ptrStart; + char c; + //skip white spaces + do { + ptr--; + c = this.GetCharAt (ptr); + } while (!char.IsLetterOrDigit (c) && c != '\n' && ptr > 1); + + do { + ptr--; + c = this.GetCharAt (ptr); + } while (char.IsLetterOrDigit (c) && c != '\n' && ptr > 1); + + if (ptr == 0) + CurrentColumn = 0; + else + CurrentColumn -= ptrStart - ptr - 1; + } + public void GotoWordEnd(){ + int limx = GetLineLength (_currentLine); + if (_currentLine < lineLength.Count - 1) + limx--; + + if (_currentCol == limx) { + MoveRight (); + limx = GetLineLength (_currentLine); + if (_currentLine < lineLength.Count - 1) + limx--; + } + + int ptrLine = GetBufferIndexOfLine(_currentLine); + int ptrCol = _currentCol; + + char c; + //skip white spaces + do { + c = GetCharAt (ptrLine+ptrCol); + ptrCol++; + } while (!char.IsLetterOrDigit (c) && ptrCol < limx); + + do { + c = GetCharAt (ptrLine + ptrCol); + ptrCol++; + } while (char.IsLetterOrDigit (c) && ptrCol < limx); + CurrentColumn = ptrCol - 1; + } + /// + /// Moves cursor one char to the left, move up if cursor reaches start of line + /// + public void MoveLeft(){ + if (CurrentColumn == 0) { + CurrentLine--; + CurrentColumn = int.MaxValue; + } else + CurrentColumn--; + } + /// + /// Moves cursor one char to the right, move down if cursor reaches end of line + /// + public void MoveRight(){ + if (_currentLine < LineCount -1){ + if (CurrentColumn >= lineLength [CurrentLine] - 1) { + CurrentColumn = 0; + CurrentLine++; + return; + } + } + CurrentColumn++; + } + + #endregion + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs new file mode 100644 index 00000000..3b67bb1c --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Crow.Text +{ + public class TextBufferEventArgs : EventArgs { + public int LineStart; + public int LineCount; + + public TextBufferEventArgs(int lineNumber) { + LineStart = lineNumber; + LineCount = 1; + } + public TextBufferEventArgs(int lineStart, int lineCount) { + LineStart = lineStart; + LineCount = lineCount; + } + } + +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs new file mode 100644 index 00000000..8b16b9a8 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs @@ -0,0 +1,699 @@ +// +// ScrollingTextBox.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 vkvg; + +namespace Crow.Text +{ + /// + /// Scrolling text box optimized for monospace fonts, for coding + /// + public class TextEditor : Crow.Coding.Editor + { + #region CTOR + public TextEditor (): base() + { + buffer = new TextBuffer (); + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + buffer.SelectionChanged += Buffer_SelectionChanged; + buffer.PositionChanged += Buffer_PositionChanged; + //buffer.Add (""); + } + #endregion + + string oldSource = ""; + volatile bool isDirty = false; + + #region private and protected fields + int visibleLines = 1; + int visibleColumns = 1; + + TextBuffer buffer; + + Color selBackground; + Color selForeground; + int selStartCol; + int selEndCol; + + protected Rectangle rText; + protected FontExtents fe; + protected TextExtents te; + + Point mouseLocalPos; + bool doubleClicked = false; + #endregion + + /// + /// Updates visible line in widget, adapt max scroll y and updatePrintedLines + /// + void updateVisibleLines(){ + visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); + NotifyValueChanged ("VisibleLines", visibleLines); + updateMaxScrollY (); + RegisterForGraphicUpdate (); +// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); + } + void updateVisibleColumns(){ + visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width)/ fe.MaxXAdvance); + NotifyValueChanged ("VisibleColumns", visibleColumns); + RegisterForGraphicUpdate (); +// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); + } + void updateMaxScrollX (int longestTabulatedLineLength) { + MaxScrollX = Math.Max (0, longestTabulatedLineLength - visibleColumns); + if (longestTabulatedLineLength > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / longestTabulatedLineLength); + } + void updateMaxScrollY () { + int lc = buffer.LineCount; + MaxScrollY = Math.Max (0, lc - visibleLines); + if (lc > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / lc); + + } + + + + #region Editor overrides + protected override void updateEditorFromProjFile () + { + buffer.editMutex.EnterWriteLock (); + loadSource (); + buffer.editMutex.ExitWriteLock (); + + isDirty = false; + oldSource = projFile.Source; + 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 projFile != null && buffer != null; } + } + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + editorMutex.EnterWriteLock (); + + MaxScrollX = MaxScrollY = 0; + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + + editorMutex.ExitWriteLock (); + } + void Buffer_LineAdditionEvent (object sender, TextBufferEventArgs e) + { + updateMaxScrollY (); + RegisterForGraphicUpdate (); + isDirty = true; + } + void Buffer_LineRemoveEvent (object sender, TextBufferEventArgs e) + { + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineUpadateEvent (object sender, TextBufferEventArgs e) + { + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_PositionChanged (object sender, EventArgs e) + { + int cc = getTabulatedColumn (buffer.CurrentPosition); + + if (cc > visibleColumns + ScrollX) { + ScrollX = cc - visibleColumns; + } else if (cc < ScrollX) + ScrollX = cc; + + if (buffer.CurrentLine >= visibleLines + ScrollY - 1) + ScrollY = buffer.CurrentLine - visibleLines + 1; + else if (buffer.CurrentLine < ScrollY) + ScrollY = buffer.CurrentLine; + + RegisterForGraphicUpdate (); + notifyPositionChanged (); + } + + void Buffer_SelectionChanged (object sender, EventArgs e) + { + RegisterForGraphicUpdate (); + } + #endregion + + void notifyPositionChanged (){ + try { + NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); + NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + } + + #region Public Crow Properties + public int CurrentLine{ + get { return buffer == null ? 0 : buffer.CurrentLine+1; } + set { + try { + int l = value - 1; + if (l == buffer.CurrentLine) + return; + buffer.CurrentLine = l; + } catch (Exception ex) { + Console.WriteLine ("Error cur column: " + 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) { + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } + } + } + [DefaultValue("Blue")] + public virtual Color SelectionBackground { + get { return selBackground; } + set { + if (value == selBackground) + return; + selBackground = value; + NotifyValueChanged ("SelectionBackground", selBackground); + RegisterForRedraw (); + } + } + [DefaultValue("White")] + public virtual Color SelectionForeground { + get { return selForeground; } + set { + if (value == selForeground) + return; + selForeground = value; + NotifyValueChanged ("SelectionForeground", selForeground); + RegisterForRedraw (); + } + } + public override int ScrollY { + get { + return base.ScrollY; + } + set { + if (value == base.ScrollY) + return; + editorMutex.EnterWriteLock (); + base.ScrollY = value; + editorMutex.ExitWriteLock (); + RegisterForGraphicUpdate (); + } + } + #endregion + + + void loadSource () { + buffer.Load (projFile.Source); + projFile.RegisteredEditors [this] = true; + updateMaxScrollY (); + RegisterForGraphicUpdate (); + } + + int getTabulatedColumn (int col, int line) { + return buffer.GetSubString (buffer [line], + buffer.GetLineLength (line)).Substring(0,col).Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + int getTabulatedColumn (Point pos) { + return getTabulatedColumn (pos.X,pos.Y); + } + + #region Drawing + void drawLines(Context gr, Rectangle cb) { + int longestTabulatedLine = 0; + for (int i = 0; i < visibleLines; i++) { + int lineIndex = i + ScrollY; + if (lineIndex >= buffer.LineCount)//TODO:need optimize + break; + + double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; + + int lineLength = buffer.GetLineLength (lineIndex); + if (lineIndex < buffer.LineCount - 1)//dont print line break + lineLength--; + string lstr = buffer.GetSubString (buffer [lineIndex], + lineLength).Replace ("\t", new String (' ', Interface.TabSize)); + + int lstrLength = lstr.Length; + if (lstrLength > longestTabulatedLine) + longestTabulatedLine = lstrLength; + + if (ScrollX < lstrLength) + lstr = lstr.Substring (ScrollX); + else + lstr = ""; + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + + if (lineIndex == buffer.SelectionStart.Y) { + rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; + rLineW -= (selStartCol - ScrollX) * fe.MaxXAdvance; + } + if (lineIndex == buffer.SelectionEnd.Y) + rLineW -= (lstr.Length - selEndCol + ScrollX) * fe.MaxXAdvance; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (SelectionBackground); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (SelectionForeground); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + + + } + + updateMaxScrollX(longestTabulatedLine); + } + #endregion + + #region GraphicObject overrides + public override Font Font { + get { return base.Font; } + set { + base.Font = value; + + using (Surface img = new Surface (IFace.dev, 1, 1)) { + using (Context gr = new Context (img)) { + gr.FontFace = Font.Name; + gr.FontSize = (uint)Font.Size; + + fe = gr.FontExtents; + } + } + MaxScrollY = 0; + RegisterForGraphicUpdate (); + } + } + protected override int measureRawSize(LayoutingType lt) + { + if (lt == LayoutingType.Height) + return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; + + return 0;// (int)(fe.MaxXAdvance * buffer.GetLineLength(buffer.longestLineIdx)) + Margin * 2; + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + + if (layoutType == LayoutingType.Height) + updateVisibleLines (); + else if (layoutType == LayoutingType.Width) + updateVisibleColumns (); + } + + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + gr.FontFace = Font.Name; + gr.FontSize = (uint)Font.Size; + //gr.FontOptions = Interface.FontRenderingOptions; + //gr.Antialias = Interface.Antialias; + + Rectangle cb = ClientRectangle; + + Foreground.SetAsSource (gr); + + buffer.editMutex.EnterReadLock (); + editorMutex.EnterReadLock (); + + #region draw text cursor + if (buffer.SelectionInProgress){ + selStartCol = getTabulatedColumn (buffer.SelectionStart); + selEndCol = getTabulatedColumn (buffer.SelectionEnd); + }else if (HasFocus && CurrentLine >= 0){ + gr.LineWidth = 1.0; + double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance ; + double cursorY = cb.Y + (buffer.CurrentLine - ScrollY) * (fe.Ascent+fe.Descent); + gr.MoveTo (0.5 + cursorX, cursorY); + gr.LineTo (0.5 + cursorX, cursorY + fe.Ascent+fe.Descent); + gr.Stroke(); + } + #endregion + + drawLines (gr, cb); + + editorMutex.ExitReadLock (); + + buffer.editMutex.ExitReadLock (); + + } + #endregion + + int getBufferColFromVisualCol (int line, int column) { + int i = 0; + int buffCol = 0; + int buffPtr = buffer [line]; + while (i < column && buffCol < buffer.GetLineLength(line)) { + if (buffer.GetCharAt(buffPtr + buffCol) == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + return buffCol; + } + + + #region Mouse handling + + int hoverLine = -1; + public int HoverLine { + get { return hoverLine; } + set { + if (hoverLine == value) + return; + hoverLine = value; + NotifyValueChanged ("HoverLine", hoverLine); + } + } + void updateHoverLine () { +// int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); +// hvl = Math.Min (PrintedLines.Count, hvl); +// HoverLine = buffer.IndexOf (PrintedLines[hvl]); + } + void updateCurrentPosFromMouseLocalPos(){ + + buffer.CurrentLine = ScrollY + (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X) / fe.MaxXAdvance); + buffer.CurrentColumn = getBufferColFromVisualCol (buffer.CurrentLine, curVisualCol); + } + + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { + base.onMouseEnter (sender, e); + IFace.MouseCursor = MouseCursor.IBeam; + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); + IFace.MouseCursor = MouseCursor.Arrow; + } + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; + + updateHoverLine (); + + if (e.Mouse.LeftButton == ButtonState.Released || !buffer.SelectionInProgress) + return; + + //mouse is down + updateCurrentPosFromMouseLocalPos(); + buffer.SetSelEndPos (); + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + if (!Focusable) + return; + + base.onMouseDown (sender, e); + + if (doubleClicked) { + doubleClicked = false; + return; + } + + updateCurrentPosFromMouseLocalPos (); + buffer.SetSelStartPos (); + } + public override void onMouseUp (object sender, MouseButtonEventArgs e) + { + base.onMouseUp (sender, e); + + if (buffer.SelectionIsEmpty) + buffer.ResetSelection (); + } + + public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) + { + //doubleClicked = true; + base.onMouseDoubleClick (sender, e); + + buffer.GotoWordStart (); + buffer.SetSelStartPos (); + buffer.GotoWordEnd (); + buffer.SetSelEndPos (); + } + + public override void onMouseWheel (object sender, MouseWheelEventArgs e) + { + base.onMouseWheel (sender, e); + } + #endregion + + #region Keyboard handling + public override void onKeyDown (object sender, KeyEventArgs e) + { + //base.onKeyDown (sender, e); + + Key key = e.Key; + + if (IFace.Ctrl) { + switch (key) { + case Key.S: + projFile.Save (); + break; + case Key.W: + editorMutex.EnterWriteLock (); + if (IFace.Shift) + projFile.Redo (null); + else + projFile.Undo (null); + editorMutex.ExitWriteLock (); + break; + default: + Console.WriteLine (""); + break; + } + } + + switch (key) + { + case Key.Backspace: + buffer.Delete (); + break; + case Key.Delete: + if (buffer.SelectionIsEmpty) + buffer.MoveRight (); +// else if (e.Shift) +// IFace.Clipboard = buffer.SelectedText; + buffer.Delete (); + break; + case Key.Enter: + case Key.KeypadEnter: + if (!buffer.SelectionIsEmpty) + buffer.Delete (); + buffer.InsertLineBreak (); + break; + case Key.Escape: + buffer.ResetSelection (); + break; + case Key.Home: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + break; + case Key.End: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + break; + case Key.Insert: + if (IFace.Shift) + buffer.InsertAt (IFace.Clipboard); + else if (IFace.Ctrl && !buffer.SelectionIsEmpty) + IFace.Clipboard = buffer.SelectedText; + break; + case Key.Left: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.GotoWordStart (); + else + buffer.MoveLeft (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.GotoWordStart (); + else + buffer.MoveLeft(); + break; + case Key.Right: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.GotoWordEnd (); + else + buffer.MoveRight (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.GotoWordEnd (); + else + buffer.MoveRight (); + break; + case Key.Up: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + CurrentLine--; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + CurrentLine--; + break; + case Key.Down: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + CurrentLine++; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + CurrentLine++; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + CurrentLine += visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + CurrentLine += visibleLines; + break; + case Key.PageUp: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + CurrentLine -= visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + CurrentLine -= visibleLines; + break; + case Key.Tab: + buffer.InsertAt ("\t"); + break; + default: + break; + } + RegisterForGraphicUpdate(); + } + public override void onKeyPress (object sender, KeyPressEventArgs e) + { + base.onKeyPress (sender, e); + + buffer.InsertAt (e.KeyChar.ToString()); + buffer.ResetSelection (); + } + #endregion + } +} \ No newline at end of file diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs new file mode 100644 index 00000000..f7b2e518 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs @@ -0,0 +1,19 @@ +using System; + +namespace Crow.Coding +{ + public struct TextFormatting { + public Color Foreground; + public Color Background; + public bool Bold; + public bool Italic; + + public TextFormatting(Color fg, Color bg, bool bold = false, bool italic = false){ + Foreground = fg; + Background = bg; + Bold = bold; + Italic = italic; + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/CodeBuffer/Token.cs b/Samples/CrowIDE/src/Editors/CodeBuffer/Token.cs new file mode 100644 index 00000000..8b4df5e5 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/CodeBuffer/Token.cs @@ -0,0 +1,71 @@ +// +// Token.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 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.Coding +{ + public struct Token + { + public BufferParser.TokenType Type; + public string Content; + public Point Start; + public Point End; + + public string PrintableContent { + get { return string.IsNullOrEmpty(Content) ? "" : Content.Replace("\t", new String(' ', Interface.TabSize)); } + } + +// public Token (TokenType tokType, string content = ""){ +// Type = tokType; +// Content = content; +// } + + public bool IsNull { get { return IsEmpty && Type == BufferParser.TokenType.Unknown; }} + public bool IsEmpty { get { return string.IsNullOrEmpty(Content); }} + + public static bool operator == (Token t, System.Enum tt){ + return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); + } + public static bool operator != (Token t, System.Enum tt){ + return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); + } + public static bool operator == (System.Enum tt, Token t){ + return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); + } + public static bool operator != (System.Enum tt, Token t){ + return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); + } + + public static Token operator +(Token t, char c){ + t.Content += c; + return t; + } + public static Token operator +(Token t, string s){ + t.Content += s; + return t; + } + public override string ToString () + { + return string.Format ("[Tok{2}->{3}:{0}: {1}]", Type,Content,Start,End); + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/EditPane.cs b/Samples/CrowIDE/src/Editors/EditPane.cs new file mode 100644 index 00000000..a75522f0 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/EditPane.cs @@ -0,0 +1,57 @@ +// +// EditPane.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 Crow; +using System.Linq; + +namespace Crow.Coding +{ + public class EditPane : TemplatedGroup + { + public EditPane () {} + + object selectedItemElement = null; + + public override int SelectedIndex { + get { + return base.SelectedIndex; + } + set { + base.SelectedIndex = value; + } + } + public object SelectedItemElement { + get { return selectedItemElement; } + set { + if (selectedItemElement == value) + return; + selectedItemElement = value; + NotifyValueChanged ("SelectedItemElement", selectedItemElement); + } + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/Editor.cs b/Samples/CrowIDE/src/Editors/Editor.cs new file mode 100644 index 00000000..102debb5 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Editor.cs @@ -0,0 +1,105 @@ +// +// 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 (Monitor.TryEnter (IFace.UpdateMutex)) { + if (!projFile.RegisteredEditors [this]) { + projFile.RegisteredEditors [this] = true; + updateEditorFromProjFile (); + } else if (EditorIsDirty) { + EditorIsDirty = false; + updateProjFileFromEditor (); + } + updateCheckPostProcess (); + Monitor.Exit (IFace.UpdateMutex); + } + } + Thread.Sleep (100); + } + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/ImlSchematicEditor.cs b/Samples/CrowIDE/src/Editors/ImlSchematicEditor.cs new file mode 100644 index 00000000..64541c90 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/ImlSchematicEditor.cs @@ -0,0 +1,132 @@ +// +// ImlVisualEditor.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; +using Crow; +using System.Threading; +using System.Xml.Serialization; +using System.ComponentModel; +using System.IO; +using System.Collections.Generic; +using Crow.IML; +using System.Text; +using System.Xml; + +namespace Crow.Coding +{ + public class ImlSchematicEditor : TemplatedGroup + { + #region CTOR + public ImlSchematicEditor () + { + } + #endregion + + ProjectFile projNode; + Widget selectedItem; + ImlProjectItem imlProjFile; + Exception imlError = null; + + bool drawGrid, snapToGrid; + int gridSpacing; + + [DefaultValue(true)] + public bool DrawGrid { + get { return drawGrid; } + set { + if (drawGrid == value) + return; + drawGrid = value; + NotifyValueChanged ("DrawGrid", drawGrid); + RegisterForRedraw (); + } + } + [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 { + if (gridSpacing == value) + return; + gridSpacing = value; + NotifyValueChanged ("GridSpacing", gridSpacing); + RegisterForRedraw (); + } + } + public Widget SelectedItem { + get { return selectedItem; } + set { + if (selectedItem == value) + return; + selectedItem = value; + NotifyValueChanged ("SelectedItem", selectedItem); + RegisterForRedraw (); + } + } +// public override ProjectFile ProjectNode { +// get { +// return projNode; +// } +// set { +// if (projNode == value) +// return; +// projNode = value; +// NotifyValueChanged ("ProjectNode", projNode); +// +// if (projNode is ImlProjectItem) +// imlProjFile = projNode as ImlProjectItem; +// else +// imlProjFile = null; +// } +// } + + +// protected override bool EditorIsDirty { +// get { +// throw new NotImplementedException (); +// } +// set { +// throw new NotImplementedException (); +// } +// } +// protected override void updateProjFileFromEditor () +// { +// +// } +// protected override void updateEditorFromProjFile () { +// +// } +// protected override void updateCheckPostProcess () +// { +// +// } + + + } +} diff --git a/Samples/CrowIDE/src/Editors/ImlVisualEditor.cs b/Samples/CrowIDE/src/Editors/ImlVisualEditor.cs new file mode 100644 index 00000000..75d8206b --- /dev/null +++ b/Samples/CrowIDE/src/Editors/ImlVisualEditor.cs @@ -0,0 +1,908 @@ +// +// ImlVisualEditor.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; +using Crow; +using System.Threading; +using System.Xml.Serialization; +using System.ComponentModel; +using System.IO; +using System.Collections.Generic; +using Crow.IML; +using System.Text; +using System.Xml; +using System.Diagnostics; +using vkvg; + +namespace Crow.Coding +{ + public class ImlVisualEditor : Editor + { + #region CTOR + public ImlVisualEditor () : base() + { + //imlVE = new DesignInterface (Interface.de); + initCommands (); + } + #endregion + + protected override void onInitialized (object sender, EventArgs e) + { + initIcons (); + base.onInitialized (sender, e); + } + DesignInterface imlVE; + Widget selectedItem; + ImlProjectItem imlProjFile; + + bool editorIsDirty = false;//needed when tree is empty + bool drawGrid, snapToGrid; + int gridSpacing, zoom = 100; + Measure designWidth, designHeight; + bool updateEnabled; + + Picture icoMove, icoStyle; + Rectangle rIcons = default(Rectangle); + Size iconSize = new Size(11,11); + + public List Commands; + Crow.Command cmdDelete; + + void initCommands () { + cmdDelete = new Crow.Command (new Action (() => deleteObject (SelectedItem))) + { Caption = "Delete", Icon = new SvgPicture ("#CrowIDE.icons.save.svg"), CanExecute = true }; + Commands = new List (new Crow.Command[] { cmdDelete }); + } + + void initIcons () { + icoMove = new SvgPicture ("#CrowIDE.icons.move-arrows.svg"); + + // icoStyle = new SvgPicture (); + // icoStyle.Load (IFace, "#CrowIDE.icons.palette.svg"); + } + + [DefaultValue(true)] + public bool DrawGrid { + get { return drawGrid; } + set { + if (drawGrid == value) + return; + drawGrid = value; + NotifyValueChanged ("DrawGrid", drawGrid); + RegisterForRedraw (); + } + } + [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 { + if (gridSpacing == value) + return; + gridSpacing = value; + NotifyValueChanged ("GridSpacing", gridSpacing); + RegisterForRedraw (); + } + } + [DefaultValue(100)] + public int Zoom { + get { return zoom; } + set { + if (zoom == value) + return; + + zoom = value; + NotifyValueChanged ("Zoom", zoom); + Width = (int)(designWidth * zoom / 100.0); + Height = (int)(designHeight * zoom / 100.0); + } + } + [DefaultValue("512")] + public Measure DesignWidth { + get { return designWidth; } + set { + if (designWidth == value) + return; + designWidth = value; + NotifyValueChanged ("DesignWidth", designWidth); + Width = (int)(designWidth * zoom / 100.0); + } + } + [DefaultValue("400")] + public Measure DesignHeight { + get { return designHeight; } + set { + if (designHeight == value) + return; + designHeight = value; + NotifyValueChanged ("DesignHeight", designHeight); + Height = (int)(designHeight * zoom / 100.0); + } + } + + public Widget SelectedItem { + get { return selectedItem; } + set { + if (selectedItem == value) + return; + selectedItem = value; + + if (selectedItem == null) + cmdDelete.CanExecute = false; + else + cmdDelete.CanExecute = true; + + NotifyValueChanged ("SelectedItem", selectedItem); + RegisterForGraphicUpdate (); + } + } + /// PoinprojFilever the widget + public virtual Widget HoverWidget + { + get { return imlVE.HoverWidget; } + set { + if (HoverWidget == value) + return; + + imlVE.HoverWidget = value; + + NotifyValueChanged ("HoverWidget", HoverWidget); + } + } + /// + /// use to disable update if tab is not the visible one + /// + public bool UpdateEnabled { + get { return updateEnabled; } + set { + if (value == updateEnabled) + return; + updateEnabled = value; + NotifyValueChanged ("UpdateEnabled", updateEnabled); + } + } + + public List GraphicTree { + get { return imlVE.GraphicTree; } + } + + [XmlIgnore]public List LQIs { + get { return imlVE.LQIs; } + } + + #region editor overrides + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; + } + set { + base.ProjectNode = value; + imlProjFile = projFile as ImlProjectItem; + imlVE.ProjFile = imlProjFile; + } + } + + protected override bool EditorIsDirty { + get { return imlProjFile == null ? false : + imlProjFile.Instance == null ? editorIsDirty : + imlProjFile.Instance.design_HasChanged | editorIsDirty; } + set { + editorIsDirty = value; + if (GraphicTree.Count == 0) + return; + if (GraphicTree [0] != null) + GraphicTree [0].design_HasChanged = value; + } + } + protected override bool IsReady { + get { return updateEnabled && imlVE != null && imlProjFile != null; } + } + + protected override void updateProjFileFromEditor () + { + Debug.WriteLine("\t\tImlEditor updateProjFileFromEditor"); + try { + if (imlProjFile.Instance == null) + projFile.UpdateSource(this, @""); + else + 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 () { + Debug.WriteLine("\t\tImlEditor 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; + } + } + } + } + Widget 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); + + } + SelectedItem = go; + } catch (Exception ex) { + Error = ex; + } + } + protected override void updateCheckPostProcess () + { + if (Error != null) { + RegisterForRedraw (); + return; + } + imlVE.Update (); + bool isDirty = false; + + lock (imlVE.RenderMutex) + isDirty = imlVE.IsDirty; + + if (isDirty) { + lock (IFace.UpdateMutex) + RegisterForRedraw (); + } + } + #endregion + + #region GraphicObject overrides + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + switch (layoutType) { + case LayoutingType.Width: + DesignWidth = Slot.Width * 100 / zoom; + imlVE.ProcessResize (new Size(designWidth,designHeight)); + break; + case LayoutingType.Height: + DesignHeight = Slot.Height * 100 / zoom; + imlVE.ProcessResize (new Size(designWidth,designHeight)); + break; + } + } + + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + Widget oldHW = HoverWidget; + Rectangle scr = this.ScreenCoordinates (this.getSlot ()); + ProcessMouseMove (e.X - scr.X, e.Y - scr.Y); + + Widget newHW = HoverWidget; + if (newHW == null) + return; + + if (draggedObj != null) { + if (draggedObj.Parent == null) { + if (tryAddObjectTo (newHW, draggedObj)) { + RegisterForRedraw (); + return; + } + } else if (newHW != draggedObj) { + //lock (imlVE.UpdateMutex) { + ILayoutable possibleParent = getPossibleParent (newHW, draggedObj); + if (possibleParent == null) { + Group g = newHW.Parent as Group; + if (g != null && g != draggedObj) { + removeObject (draggedObj); + g.InsertChild (g.Children.IndexOf (newHW), draggedObj); + RegisterForRedraw (); + return; + } + } else if (possibleParent != draggedObj.Parent) { + removeObject (draggedObj); + if (tryAddObjectTo (possibleParent, draggedObj)) { + RegisterForRedraw (); + return; + } + } + //} + } + } + + if (oldHW == newHW) + return; + //RegisterForRedraw (); + + } + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { + base.onMouseEnter (sender, e); + if (IFace.DragAndDropOperation != null && draggedObj == null) + return; + IFace.FocusedWidget = this; + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); +// IFace.FocusedWidget = null; + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + if (e.Mouse.RightButton == ButtonState.Pressed) { + base.onMouseDown (sender, e); + return; + } + SelectedItem = HoverWidget; + +// if (SelectedItem != null && projFile != null) { +// projFile.CurrentLine = SelectedItem.design_line; +// projFile.CurrentColumn = SelectedItem.design_column; +// } + + } + + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + Rectangle cb = new Rectangle (0, 0, designWidth, designHeight); + + gr.Save (); + + double z = zoom / 100.0; + + gr.Scale (z, z); + + if (drawGrid) { + double gridLineWidth = 0.2 / z; + double glhw = gridLineWidth / 2.0; + int nbLines = cb.Width / gridSpacing; + double d = cb.Left + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (d - glhw, cb.Y); + gr.LineTo (d - glhw, cb.Bottom); + d += gridSpacing; + } + nbLines = cb.Height / gridSpacing; + d = cb.Top + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (cb.X, d - glhw); + gr.LineTo (cb.Right, d - glhw); + d += gridSpacing; + } + gr.LineWidth = gridLineWidth; + Foreground.SetAsSource (gr, cb); + gr.Stroke (); + } + + lock (imlVE.RenderMutex) { + gr.SetSourceSurface (imlVE.surf, cb.Left, cb.Top); + gr.Paint (); + imlVE.IsDirty = false; + } + /*if (Error == null) { + gr.SetSourceColor (Color.Black); + gr.Rectangle (cb, 1.0 / z); + } else { + gr.SetSourceColor (Color.LavenderBlush); + gr.Rectangle (cb, 2.0 / z); + string[] lerrs = Error.ToString ().Split ('\n'); + Point p = cb.Center; + p.Y -= lerrs.Length * 20; + foreach (string le in lerrs) { + drawCenteredTextLine(gr, p, le); + p.Y += 20; + + } + } + gr.Stroke ();*/ + + Rectangle hr; + + /* + if (SelectedItem?.Parent != null) { + + gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); + gr.SetFontSize (Font.Size); + gr.FontOptions = Interface.FontRenderingOptions; + gr.Antialias = Interface.Antialias; + + Widget g = SelectedItem; + hr = g.ScreenCoordinates (g.getSlot ()); + +// Rectangle rIcons = new Rectangle (iconSize); +// rIcons.Width *= 4; +// rIcons.Top = hr.Bottom; +// rIcons.Left = hr.Right - rIcons.Width + iconSize.Width; + Rectangle rIcoMove = new Rectangle (hr.BottomRight, iconSize); +// Rectangle rIcoStyle = rIcoMove; +// rIcoStyle.Left += iconSize.Width + 4; + + using (Surface mask = new ImageSurface (Format.Argb32, cb.Width, cb.Height)) { + using (Context ctx = new Context (mask)) { + ctx.Save(); + ctx.SetSourceRGBA(1.0,1.0,1.0,0.4); + ctx.Paint (); + ctx.Rectangle (hr); + ctx.Operator = Operator.Clear; + ctx.Fill (); + } + + gr.SetSourceSurface (mask, 0, 0); + gr.Paint (); + + using (Surface ol = new ImageSurface (Format.Argb32, cb.Width, cb.Height)) { + using (Context ctx = new Context (ol)) { + ctx.SetSourceColor (Color.Black); + drawDesignOverlay (ctx, g, cb, hr, 0.4 / z, 6.5); + } + + gr.SetSourceSurface (ol, 0, 0); + gr.Paint (); + } + + drawIcon (gr, icoMove, rIcoMove); + //drawIcon (gr, icoStyle, rIcoStyle); + + } + }*/ + if (HoverWidget != null) { + hr = HoverWidget.ScreenCoordinates (HoverWidget.getSlot ()); + gr.SetSourceColor (Color.SkyBlue); + //gr.SetDash (new double[]{ 5.0, 3.0 }, 0.0); + gr.Rectangle (hr, 0.4 / z); + } + gr.Restore (); + } + + void drawIcon (Context gr, Picture pic, Rectangle r) {/* +// gr.SetSourceColor (Color.Black); +// CairoHelpers.CairoRectangle (gr, r.Inflated (1), 2, 1.0); + gr.SetSourceColor (Color.White); + CairoHelpers.CairoRectangle (gr, r.Inflated (1), 2); + gr.Fill (); + gr.Operator = Operator.Clear; + pic.Paint (gr, r); + gr.Operator = Operator.Over;*/ + } + void drawDesignOverlay (Context gr, Widget g, Rectangle cb, Rectangle hr, double coteStroke, double space = 6.5){ + /* + double z = zoom / 100.0; + double coteW = 3, coteL = 5; + bool fill = true; + Crow.Cairo.PointD p1 = new Crow.Cairo.PointD (hr.X + 0.5, hr.Y - space); + Crow.Cairo.PointD p2 = new Crow.Cairo.PointD (hr.Right - 0.5, hr.Y - space); + + if (p1.Y < cb.Top) { + if (hr.Bottom > cb.Bottom - space) + p1.Y = p2.Y = hr.Bottom - space; + else + p1.Y = p2.Y = hr.Bottom + space; + } + + if (g.Width.IsFit) + gr.DrawCoteInverse (p1, p2, coteStroke, fill, coteW, coteL); + else if (g.Width.IsRelativeToParent) { + gr.DrawCote (p1, p2, coteStroke, fill, coteW, coteL); + if (g.Width.Value < 100) + drawCenteredTextLine (gr, p1.Add(p2.Substract(p1).Divide (2)), g.Width.ToString()); + }else if (g.Width.IsFixed) { + gr.DrawCoteFixed (p1, p2, coteStroke * 2.0, coteW); + drawCenteredTextLine (gr, p1.Add(p2.Substract(p1).Divide (2)), g.Width.Value.ToString()); + } + + p1 = new Crow.Cairo.PointD (hr.X - space, hr.Top + 0.5); + p2 = new Crow.Cairo.PointD (hr.X - space, hr.Bottom - 0.5); + + if (p1.X < cb.Left) { + if (hr.Right > cb.Right - space) + p1.X = p2.X = hr.Right - space; + else + p1.X = p2.X = hr.Right + space; + } + if (g.Height.IsFit) + gr.DrawCoteInverse (p1, p2, coteStroke, fill, coteW, coteL); + else if (g.Height.IsRelativeToParent){ + gr.DrawCote (p1, p2, coteStroke, fill, coteW, coteL); + if (g.Height.Value < 100) + drawCenteredTextLine (gr, p1.Add(p2.Substract(p1).Divide (2)), g.Height.ToString()); + }else if (g.Width.IsFixed) { + gr.DrawCoteFixed (p1, p2, coteStroke * 2.0, coteW); + drawCenteredTextLine (gr, p1.Add(p2.Substract(p1).Divide (2)), g.Height.Value.ToString()); + } + + // hr.Inflate (2); + //gr.SetDash (new double[]{ 1.0, 4.0 }, 0.0); + //gr.SetSourceColor (Color.Grey); +// gr.Rectangle (hr,coteStroke); +// gr.Stroke (); + gr.Operator = Operator.Over; + */ + } + + void drawCenteredTextLine (Context gr, Point center, string txt){ + drawCenteredTextLine (gr, new PointD(center.X,center.Y), txt); + } + void drawCenteredTextLine (Context gr, PointD center, string txt){ + if (string.IsNullOrEmpty(txt)) + return; + FontExtents fe = gr.FontExtents; + TextExtents te = gr.TextExtents (txt); + + Rectangle rText = new Rectangle( + (int)(center.X - te.Width / 2), (int)(center.Y - (fe.Ascent + fe.Descent) / 2), + (int)te.Width, (int)(fe.Ascent + fe.Descent)); + + gr.Operator = Operator.Clear; + Rectangle r = rText; + r.Inflate (2); + gr.Rectangle (r); + gr.Fill (); + gr.Operator = Operator.Over; + + gr.MoveTo (rText.X, rText.Y + fe.Ascent); + gr.ShowText (txt); + gr.Fill (); + + } + protected override void onDragEnter (object sender, DragDropEventArgs e) + { + base.onDragEnter (sender, e); + GraphicObjectDesignContainer godc = e.DragSource.DataSource as GraphicObjectDesignContainer; + if (godc == null) + return; + createDraggedObj (godc.CrowType); + } + protected override void onDragLeave (object sender, DragDropEventArgs e) + { + base.onDragLeave (sender, e); + GraphicObjectDesignContainer godc = e.DragSource.DataSource as GraphicObjectDesignContainer; + if (godc == null) + return; + ClearDraggedObj (); + } + + protected override void onStartDrag (object sender, DragDropEventArgs e) + { + base.onStartDrag (sender, e); + if (SelectedItem == null) + return; + + Widget dumy = new Widget (IFace); + dumy.EndDrag += dumyOnEndDrag; + dumy.Drop += dumyOnDrop; + dumy.IsDragged = true; + IFace.ActiveWidget = dumy; + e.DragSource.IsDragged = false; + IFace.DragAndDropOperation.DragSource = dumy; + draggedObj = SelectedItem; + int dragIconSize = 48; + lock (IFace.UpdateMutex) { + IFace.DragImageHeight = dragIconSize; + IFace.DragImageWidth = dragIconSize; + IFace.DragImage = draggedObj.CreateIcon(dragIconSize); + } + removeObject (draggedObj); + SelectedItem = null; + HoverWidget = null; + } + void dumyOnEndDrag (object sender, DragDropEventArgs e) + { + IFace.ClearDragImage (); + } + void dumyOnDrop (object sender, DragDropEventArgs e) + { + ClearDraggedObj (false); + IFace.ClearDragImage (); + } + #endregion + + + #region draggedObj handling + + public Widget draggedObj = null; + + void createDraggedObj (Type crowType) { + lock (imlVE.UpdateMutex) { + draggedObj = imlVE.CreateITorFromIMLFragment ("<" + crowType.Name + "/>").CreateInstance (); + } + } + + public void ClearDraggedObj (bool removeFromTree = true) { + if (removeFromTree) + deleteObject (draggedObj); + draggedObj = null; + } + #endregion + + void removeObject (Widget go) { + if (go == null) + return; + if (go.Parent == null) + return; +// lock (imlVE.UpdateMutex) { + Interface i = go.Parent as Interface; + if (i != null) { + i.RemoveWidget (go); + imlProjFile.Instance = null; + } else { + Container c = go.Parent as Container; + if (c != null) + c.SetChild (null); + else { + TemplatedContainer tc = go.Parent as TemplatedContainer; + if (tc != null) + tc.Content = null; + else { + Group g = go.Parent as Group; + if (g != null) + g.RemoveChild (go); + } + } + } + EditorIsDirty = true; + //} + } + void deleteObject (Widget go) { + if (go == null) + return; + //lock (imlVE.UpdateMutex) { + removeObject (go); + go.Dispose (); + //} + } + + ILayoutable getPossibleParent (ILayoutable parent, Widget go) { + if (go == null) + return null; +// lock (imlVE.UpdateMutex) { + + Interface i = null; + if (parent == null) + i = imlVE; + else + i = parent as Interface; + if (i != null) + return i.GraphicTree.Count > 0 ? null : i; + + Container c = parent as Container; + if (c != null) + return c.Child == null || c.Child == go ? c : null; + + TemplatedContainer tc = parent as TemplatedContainer; + if (tc != null) + return tc.Content == null || tc.Content == go? tc : null; + + return parent as Group; +// } + } + bool tryAddObjectTo (ILayoutable parent, Widget go) { + if (go == null) + return false; +// lock (imlVE.UpdateMutex) { + Interface i = null; + if (parent == null) + i = imlVE; + else + i = parent as Interface; + if (i != null) { + if (i.GraphicTree.Count > 0) + return false; + i.AddWidget (go); + imlProjFile.Instance = go; + EditorIsDirty = true; + return true; + } + Container c = parent as Container; + if (c != null) { + if (c.Child != null) + return false; + //return tryAddObjectTo (c.Parent, go); + c.SetChild (go); + EditorIsDirty = true; + return true; + } + TemplatedContainer tc = parent as TemplatedContainer; + if (tc != null) { + if (tc.Content != null) + return false; + //return tryAddObjectTo (c.Parent, go); + tc.Content = (go); + EditorIsDirty = true; + return true; + } + Group g = parent as Group; + if (g != null) { + g.AddChild (go); + EditorIsDirty = true; + return true; + } + return false;//tryAddObjectTo (parent.Parent, go); +// } + } + + + + void WidgetCheckOver (Widget go, MouseMoveEventArgs e){ + Type tGo = go.GetType(); + if (typeof(TemplatedGroup).IsAssignableFrom (tGo)) { + + } else if (typeof(TemplatedContainer).IsAssignableFrom (tGo)) { + TemplatedContainer c = go as TemplatedContainer; + if (c.Content?.MouseIsIn (e.Position) == true) { + WidgetCheckOver (c.Content, e); + return; + } + } else if (typeof(TemplatedControl).IsAssignableFrom (tGo)) { + } else if (typeof(Group).IsAssignableFrom (tGo)) { + Group c = go as Group; + for (int i = c.Children.Count -1; i >= 0; i--) { + if (c.Children[i].MouseIsIn (e.Position)) { + WidgetCheckOver (c.Children[i], e); + return; + } + } + } else if (typeof(Crow.Container).IsAssignableFrom (tGo)) { + Crow.Container c = go as Crow.Container; + if (c.Child?.MouseIsIn (e.Position)==true) { + WidgetCheckOver (c.Child, e); + return; + } + } + HoverWidget = go; + WidgetMouseEnter (go, e); + } + void WidgetMouseLeave (Widget go, MouseMoveEventArgs e){ + + } + void WidgetMouseEnter (Widget go, MouseMoveEventArgs e){ + + } + void WidgetMouseMove (Widget go, MouseMoveEventArgs e){} + + public bool ProcessMouseMove(int x, int y) + { + int deltaX = x - imlVE.Mouse.X; + int deltaY = y - imlVE.Mouse.Y; + imlVE.Mouse.X = x; + imlVE.Mouse.Y = y; + MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY); + e.Mouse = imlVE.Mouse; + + if (imlVE.ActiveWidget != null) { + //TODO, ensure object is still in the graphic tree + //send move evt even if mouse move outside bounds + WidgetMouseMove (imlVE.ActiveWidget, e); + return true; + } + + if (HoverWidget != null) { + //TODO, ensure object is still in the graphic tree + //check topmost graphicobject first + Widget tmp = HoverWidget; + Widget topc = null; + while (tmp is Widget) { + topc = tmp; + tmp = tmp.LogicalParent as Widget; + } + int idxhw = imlVE.GraphicTree.IndexOf (topc); + if (idxhw != 0) { + int i = 0; + while (i < idxhw) { + if (imlVE.GraphicTree [i].LogicalParent == imlVE.GraphicTree [i].Parent) { + if (imlVE.GraphicTree [i].MouseIsIn (e.Position)) { + while (imlVE.HoverWidget != null) { + WidgetMouseLeave (imlVE.HoverWidget, e); + imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as Widget; + } + + WidgetCheckOver (GraphicTree [i], e); + return true; + } + } + i++; + } + } + + + if (imlVE.HoverWidget.MouseIsIn (e.Position)) { + WidgetCheckOver (imlVE.HoverWidget, (e)); + return true; + } else { + WidgetMouseLeave (imlVE.HoverWidget, e); + //seek upward from last focused graph obj's + while (imlVE.HoverWidget.LogicalParent as Widget != null) { + imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as Widget; + if (imlVE.HoverWidget.MouseIsIn (e.Position)) { + WidgetCheckOver (imlVE.HoverWidget, e); + return true; + } else + WidgetMouseLeave (imlVE.HoverWidget, e); + } + } + } + + //top level graphic obj's parsing + lock (imlVE.GraphicTree) { + for (int i = 0; i < imlVE.GraphicTree.Count; i++) { + Widget g = imlVE.GraphicTree [i]; + if (g.MouseIsIn (e.Position)) { + WidgetCheckOver (g, e); + return true; + } + } + } + imlVE.HoverWidget = null; + return false; + + } + + void GTView_SelectedItemChanged (object sender, SelectionChangeEventArgs e) + { + SelectedItem = e.NewValue as Widget; + } + + + public override void onKeyDown (object sender, KeyEventArgs e) + { + + switch (e.Key) { + case Key.Delete: + if (selectedItem == null) + return; + deleteObject (selectedItem); + break; + case Key.Escape: + SelectedItem = null; + break; + } + } + } +} diff --git a/Samples/CrowIDE/src/Editors/Parsers/BufferParser.cs b/Samples/CrowIDE/src/Editors/Parsers/BufferParser.cs new file mode 100644 index 00000000..c193c7db --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Parsers/BufferParser.cs @@ -0,0 +1,380 @@ +using System; +using System.IO; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Crow.Coding +{ + /// + /// base class for tokenizing sources + /// + public abstract class BufferParser + { + /// + /// Default tokens, this enum may be overriden in derived parser with the new keyword, + /// see XMLParser for example. + /// + public enum TokenType { + Unknown = 0, + WhiteSpace = 1, + NewLine = 2, + LineComment = 3, + BlockCommentStart = 4, + BlockComment = 5, + BlockCommentEnd = 6, + Preprocessor = 7, + Identifier = 8, + Keyword = 9, + OpenBlock = 10, + CloseBlock = 11, + StatementEnding = 12, + OperatorOrPunctuation = 13, + IntegerLitteral = 14, + RealLitteral = 15, + StringLitteralOpening = 16, + StringLitteralClosing = 17, + StringLitteral = 18, + CharLitteralOpening = 19, + CharLitteralClosing = 20, + CharLitteral = 21, + BoolLitteral = 22, + NullLitteral = 23, + Type = 24, + } + + #region CTOR + public BufferParser (CodeBuffer _buffer) + { + buffer = _buffer; + + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + //buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + } + + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + + } + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + reparseSource (); + } + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) + TryParseBufferLine (e.LineStart + i); + reparseSource (); + } + #endregion + + internal int currentLine = 0; + internal int currentColumn = 0; + + int syntTreeDepth = 0; + public int SyntacticTreeDepth { + get { return syntTreeDepth;} + set { + syntTreeDepth = value; + if (syntTreeDepth > SyntacticTreeMaxDepth) + SyntacticTreeMaxDepth = syntTreeDepth; + } + } + public int SyntacticTreeMaxDepth = 0; + + protected CodeBuffer buffer; + protected Token currentTok; + protected bool eol = true; + protected Point CurrentPosition { + get { return new Point (currentLine, currentColumn); } + set { + currentLine = value.Y; + currentColumn = value.X; + } + } + + public Node RootNode; + + public abstract void ParseCurrentLine(); + public abstract void SyntaxAnalysis (); + public void reparseSource () { + for (int i = 0; i < buffer.LineCount; i++) { + if (!buffer[i].IsParsed) + TryParseBufferLine (i); + } + try { + SyntaxAnalysis (); + } catch (Exception ex) { + Debug.WriteLine ("Syntax Error: " + ex.ToString ()); + if (ex is ParserException) + SetLineInError (ex as ParserException); + } + } + public void TryParseBufferLine(int lPtr) { + buffer [lPtr].exception = null; + currentLine = lPtr; + currentColumn = 0; + eol = false; + + try { + ParseCurrentLine (); + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + if (ex is ParserException) + SetLineInError (ex as ParserException); + } + + } + + public virtual void SetLineInError(ParserException ex) { + currentTok = default(Token); + if (ex.Line >= buffer.LineCount) + ex.Line = buffer.LineCount - 1; + if (buffer [ex.Line].IsFolded) + buffer.ToogleFolding (ex.Line); + buffer [ex.Line].SetLineInError (ex); + } + public virtual string LineBrkRegex { + get { return @"\r\n|\r|\n|\\\\n"; } + } + void updateFolding () { + // Stack foldings = new Stack(); + // bool inStartTag = false; + // + // for (int i = 0; i < parser.Tokens.Count; i++) { + // TokenList tl = parser.Tokens [i]; + // tl.foldingTo = null; + // int fstTK = tl.FirstNonBlankTokenIndex; + // if (fstTK > 0 && fstTK < tl.Count - 1) { + // if (tl [fstTK + 1] != XMLParser.TokenType.ElementName) + // continue; + // if (tl [fstTK] == XMLParser.TokenType.ElementStart) { + // //search closing tag + // int tkPtr = fstTK+2; + // while (tkPtr < tl.Count) { + // if (tl [tkPtr] == XMLParser.TokenType.ElementClosing) + // + // tkPtr++; + // } + // if (tl.EndingState == (int)XMLParser.States.Content) + // foldings.Push (tl); + // else if (tl.EndingState == (int)XMLParser.States.StartTag) + // inStartTag = true; + // continue; + // } + // if (tl [fstTK] == XMLParser.TokenType.ElementEnd) { + // TokenList tls = foldings.Pop (); + // int fstTKs = tls.FirstNonBlankTokenIndex; + // if (tls [fstTK + 1].Content == tl [fstTK + 1].Content) { + // tl.foldingTo = tls; + // continue; + // } + // parser.CurrentPosition = tls [fstTK + 1].Start; + // parser.SetLineInError(new ParserException(parser, "closing tag not corresponding")); + // } + // + // } + // } + } + + #region low level parsing + protected void addCharToCurTok(char c, Point position){ + currentTok.Start = position; + currentTok += c; + } + /// + /// Read one char from current position in buffer and store it into the current token + /// + /// if true, set the Start position of the current token to the current position + protected void readToCurrTok(bool startOfTok = false){ + if (startOfTok) + currentTok.Start = CurrentPosition; + currentTok += Read(); + } + /// + /// read n char from the buffer and store it into the current token + /// + protected void readToCurrTok(int length) { + for (int i = 0; i < length; i++) + currentTok += Read (); + } + /// + /// Save current token into current TokensLine and raz current token + /// + protected void saveAndResetCurrentTok() { + currentTok.End = CurrentPosition; + buffer[currentLine].Tokens.Add (currentTok); + currentTok = default(Token); + } + /// + /// read one char and add current token to current TokensLine, current token is reset + /// + /// Type of the token + /// set start of token to current position + protected void readAndResetCurrentTok(System.Enum type, bool startToc = false) { + readToCurrTok (); + saveAndResetCurrentTok (type); + } + /// + /// Save current tok + /// + /// set the type of the tok + protected void saveAndResetCurrentTok(System.Enum type) { + currentTok.Type = (TokenType)type; + saveAndResetCurrentTok (); + } + protected void setPreviousTokOfTypeTo (TokenType inType, TokenType newType) { + for (int i = currentLine; i >= 0; i--) { + int j = buffer [i].Tokens.Count - 1; + while (j >= 0) { + if (buffer [i].Tokens [j].Type == inType) { + Token t = buffer [i].Tokens [j]; + t.Type = newType; + buffer [i].Tokens [j] = t; + return; + } + j--; + } + } + } + /// + /// Peek next char, emit '\n' if current column > buffer's line length + /// Throw error if eof is true + /// + protected virtual char Peek() { + if (eol) + throw new ParserException (currentLine, currentColumn, "Unexpected End of line"); + return currentColumn < buffer [currentLine].Length ? + buffer [currentLine] [currentColumn] : '\n'; + } + /// + /// Peek n char from buffer or less if remaining char in buffer's line is less than requested + /// if end of line is reached, no '\n' will be emitted, instead, empty string is returned. '\n' should be checked only + /// with single char Peek(). + /// Throw error is eof is true + /// + /// Length. + protected virtual string Peek(int length) { + if (eol) + return "";//throw new ParserException (currentLine, currentColumn, "Unexpected End of Line"); + int lg = Math.Min(length, Math.Max (buffer [currentLine].Length - currentColumn, buffer [currentLine].Length - currentColumn - length)); + if (lg == 0) + return ""; + return buffer [currentLine].Content.Substring (currentColumn, lg); + } + /// + /// read one char from buffer at current position, if '\n' is read, current line is incremented + /// and column is reset to 0 + /// + protected virtual char Read() { + char c = Peek (); + if (c == '\n') + eol = true; + currentColumn++; + return c; + } + protected virtual string Read(int charCount){ + string tmp = ""; + for (int i = 0; i < charCount; i++) { + if (eol) + break; + tmp += Read (); + } + return tmp; + } + /// + /// read until end of line is reached + /// + /// string read + protected virtual string ReadLine () { + StringBuilder tmp = new StringBuilder(); + char c = Read (); + while (!eol) { + tmp.Append (c); + c = Read (); + } + return tmp.ToString(); + } + /// + /// read until end expression is reached or end of line. + /// + /// string read minus the ending expression that has to be read after + /// Expression to search for + protected virtual string ReadLineUntil (string endExp){ + string tmp = ""; + + while (!eol) { + if (buffer [currentLine].Length - currentColumn - endExp.Length < 0) { + tmp += ReadLine(); + break; + } + if (string.Equals (Peek (endExp.Length), endExp)) + return tmp; + tmp += Read(); + } + return tmp; + } + /// + /// skip white spaces, but not line break. Save spaces in a WhiteSpace token. + /// + protected void SkipWhiteSpaces () { + if (currentTok.Type != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "current token should be reset to unknown (0) before skiping white spaces"); + while (!eol) { + if (!char.IsWhiteSpace (Peek ())||Peek()=='\n') + break; + readToCurrTok (currentTok.Type == TokenType.Unknown); + currentTok.Type = TokenType.WhiteSpace; + } + if (currentTok.Type != TokenType.Unknown) + saveAndResetCurrentTok (); + } + #endregion + + protected Node addChildNode (Node curNode, CodeLine cl, int tokPtr, string type = "") { + Node n = new Node () { Name = cl.Tokens [tokPtr].Content, StartLine = cl, Type = type }; + curNode.AddChild (n); + if (cl.SyntacticNode == null) + cl.SyntacticNode = n; + SyntacticTreeDepth++; + return n; + } + protected void closeNodeAndGoUp (ref Node n, CodeLine cl, string type = ""){ + while (n != null) { + if (n.Type == type) { + n.EndLine = cl; + n = n.Parent; + SyntacticTreeDepth--; + break; + } + n = n.Parent; + SyntacticTreeDepth--; + } + } + protected void closeNodeAndGoUp (ref Node n, CodeLine cl){ + SyntacticTreeDepth--; + n.EndLine = cl; + n = n.Parent; + } + + protected void initSyntaxAnalysis () { + RootNode = new Node () { Name = "RootNode", Type="Root" }; + SyntacticTreeDepth = SyntacticTreeMaxDepth = 0; + } + + + protected void throwParserException(string msg){ + throw new ParserException (currentLine, currentColumn, msg); + } + } +} \ No newline at end of file diff --git a/Samples/CrowIDE/src/Editors/Parsers/CSharpParser.cs b/Samples/CrowIDE/src/Editors/Parsers/CSharpParser.cs new file mode 100644 index 00000000..23655aa6 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Parsers/CSharpParser.cs @@ -0,0 +1,386 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Linq; + +namespace Crow.Coding +{ + public class CSharpParser : BufferParser + { + #region keywords + string[] keywords = new string[] { + "abstract", + "as", + "ascending", + "async", + "await", + "base", + "bool", + "break", + "byte", + "case", + "catch", + "char", + "checked", + "class", + "const", + "continue", + "decimal", + "default", + "delegate", + "descending", + "do", + "double", + "dynamic", + "else", + "enum", + "equals", + "event", + "explicit", + "extern", + "false", + "finally", + "fixed", + "float", + "for", + "foreach", + "from", + "get", + "goto", + "group", + "if", + "implicit", + "in", + "int", + "interface", + "internal", + "is", + "join", + "let", + "lock", + "long", + "nameof", + "namespace", + "new", + "null", + "object", + "operator", + "orderby", + "out", + "override", + "params", + "partial", + "private", + "protected", + "public", + "readonly", + "ref", + "return", + "sbyte", + "sealed", + "select", + "set", + "short", + "sizeof", + "stackalloc", + "static", + "string", + "struct", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "uint", + "ulong", + "unchecked", + "unsafe", + "ushort", + "using", + "value", + "var", + "virtual", + "void", + "volatile", + "when", + "where", + "while", + "yield " + }; + #endregion + + public enum States + { + init, + BlockComment, + InNameSpace, + InClass, + InMember, + Unknown, + } + + public CSharpParser (CodeBuffer _buffer) : base(_buffer) + { + } + + #region Regular Expression for validity checks + static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}"); + static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNewLineChar = new Regex(@"\u000D|\u000A|\u0085|\u2028|\u2029"); + static Regex rxWhiteSpaceChar = new Regex(@"\p{Zs}|\u0009|\u000B|\u000C"); + static Regex rxDecimal = new Regex(@"[0-9]+"); + static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + + public static bool CharIsValidCharStartName (char c) { + return rxNameStartChar.IsMatch(new string(new char[]{c})); + } + public static bool CharIsValidCharName (char c) { + return rxNameChar.IsMatch(new string(new char[]{c})); + } + + public bool nextCharIsValidCharStartName + { + get { return CharIsValidCharStartName(Peek()); } + } + public bool nextCharIsValidCharName + { + get { return CharIsValidCharName(Peek()); } + } + #endregion + + States curState = States.init; + States savedState = States.init; + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + while (! eol) { + if (currentTok.IsNull) + SkipWhiteSpaces (); + + if (curState == States.BlockComment) { + currentTok.Start = CurrentPosition; + currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; + currentTok += ReadLineUntil ("*/"); + if (Peek (2) == "*/") { + readToCurrTok (2); + curState = savedState; + } + saveAndResetCurrentTok (); + continue; + } + + switch (Peek()) { + case '\n': + eol = true; + if (!currentTok.IsNull) + saveAndResetCurrentTok (); + break; + case '#': + readToCurrTok (true); + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Preprocessor); + break; + case '/': + readToCurrTok (true); + switch (Peek ()) { + case '*': + readToCurrTok (); + currentTok += ReadLine (); + //currentTok.Type = (Parser.TokenType)TokenType.BlockComment; + savedState = curState; + curState = States.BlockComment; + saveAndResetCurrentTok (TokenType.BlockComment); + break; + case '/': + //readToCurrTok (); + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.LineComment); + //currentTok.Type = (Parser.TokenType)TokenType.LineComment; + break; + default: + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Unknown); + break; + } + break; + case '{': + if (currentTok.IsNull) + readAndResetCurrentTok (TokenType.OpenBlock, true); + else + readToCurrTok (); + break; + case '}': + if (currentTok.IsNull) + readAndResetCurrentTok (TokenType.CloseBlock, true); + else + readToCurrTok (); + break; + case '\\'://unicode escape sequence + if (!(currentTok.Type == TokenType.Identifier || + currentTok.IsEmpty || currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral)) { + saveAndResetCurrentTok (); + } + Point pos = CurrentPosition; + Read (); + char escChar = Read (); + + if (escChar == 'u') { + char c = char.ConvertFromUtf32 (int.Parse (Read (4), System.Globalization.NumberStyles.HexNumber))[0]; + if (currentTok.IsEmpty) { + if (!CharIsValidCharStartName (c)) + throwParserException ("expecting identifier start"); + currentTok.Start = pos; + currentTok.Type = TokenType.Identifier; + } else if (currentTok.Type == TokenType.Identifier) { + if (!CharIsValidCharName (c)) + throwParserException ("expecting identifier valid char"); + } + currentTok += c; + break; + } + currentTok += new String (new char[] { '\\', escChar }); + break; + case '\'': + if (currentTok.IsNull) { + readAndResetCurrentTok (TokenType.CharLitteralOpening, true); + currentTok.Type = TokenType.CharLitteral; + } else if (currentTok.Type == TokenType.CharLitteral) { + saveAndResetCurrentTok (); + readAndResetCurrentTok (TokenType.CharLitteralClosing, true); + } else if (currentTok.Type == TokenType.StringLitteral){ + readToCurrTok (); + } else + throwParserException ("unexpected character: (\')"); + break; + case '"': + if (currentTok.IsNull) { + readAndResetCurrentTok (TokenType.StringLitteralOpening, true); + currentTok.Type = TokenType.StringLitteral; + } else if (currentTok.Type == TokenType.StringLitteral) { + saveAndResetCurrentTok (); + readAndResetCurrentTok (TokenType.StringLitteralClosing, true); + } else + throwParserException ("unexpected character: (\")"); + break; + default: + if (currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral) { + readToCurrTok (currentTok.IsEmpty); + } else if (currentTok.IsNull) { + if (nextCharIsValidCharStartName) { + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + + if (keywords.Contains (currentTok.Content)) + saveAndResetCurrentTok (TokenType.Keyword); + else + saveAndResetCurrentTok (TokenType.Identifier); + continue; + } else + readAndResetCurrentTok(TokenType.Unknown, true); + } else + readAndResetCurrentTok(TokenType.Unknown, true); + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + int ptrLine = 0; + while (ptrLine < buffer.LineCount) { + CodeLine cl = buffer [ptrLine]; + if (cl.Tokens == null){ + ptrLine++; + continue; + } + cl.SyntacticNode = null; + + int tokPtr = 0; + bool onlyWhiteSpace = true; + while (tokPtr < cl.Tokens.Count) { + if (cl.Tokens [tokPtr].Type == TokenType.WhiteSpace) { + tokPtr++; + continue; + } + + if (cl.Tokens [tokPtr].Type == TokenType.LineComment && onlyWhiteSpace) { + int startLine = ptrLine; + ptrLine++; + while (ptrLine < buffer.LineCount) { + int idx = buffer [ptrLine].FirstNonBlankTokIndex; + if (idx < 0) + break; + if (buffer [ptrLine].Tokens [idx].Type != TokenType.LineComment) + break; + ptrLine++; + } + ptrLine--; + if (ptrLine - startLine > 0) { + currentNode = addChildNode (currentNode, cl, tokPtr, "comment"); + closeNodeAndGoUp (ref currentNode, buffer [ptrLine], "comment"); + } + break; + } + + switch (cl.Tokens [tokPtr].Type) { + case TokenType.BlockCommentStart: + case TokenType.OpenBlock: + currentNode = addChildNode (currentNode, cl, tokPtr); + break; + case TokenType.CloseBlock: + case TokenType.BlockCommentEnd: + closeNodeAndGoUp (ref currentNode, cl); + break; + case TokenType.Preprocessor: + if (cl.Tokens [tokPtr].Content.StartsWith ("#region", StringComparison.Ordinal)) { + currentNode = addChildNode (currentNode, cl, tokPtr, "region"); + } else if (cl.Tokens [tokPtr].Content.StartsWith ("#endregion", StringComparison.Ordinal)) { + + closeNodeAndGoUp (ref currentNode, cl,"region"); + } + break; + } + onlyWhiteSpace = false; + tokPtr++; + } + ptrLine++; + } + /*ptrLine = 0; + while (ptrLine < buffer.LineCount) { + CodeLine cl = buffer [ptrLine]; + if (cl.IsFoldable) { + if (cl.SyntacticNode.Type == "comment" || cl.SyntacticNode.Type == "region") + cl.IsFolded = true; + } + ptrLine++; + }*/ + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/Parsers/StyleParser.cs b/Samples/CrowIDE/src/Editors/Parsers/StyleParser.cs new file mode 100644 index 00000000..9a1e74cd --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Parsers/StyleParser.cs @@ -0,0 +1,179 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Linq; + +namespace Crow.Coding +{ + public class StyleParser : BufferParser + { + enum States { init, classNames, members, value, endOfStatement } + + public StyleParser (CodeBuffer _buffer) : base(_buffer) + { + } + + #region Character ValidityCheck + static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}"); + static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxDecimal = new Regex(@"[0-9]+"); + static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + + public bool nextCharIsValidCharStartName + { + get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } + } + public bool nextCharIsValidCharName + { + get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } + } + #endregion + + States curState = States.classNames; + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + while (! eol) { + SkipWhiteSpaces (); + + if (eol) + break; + + if (Peek () == '\n') { + if (currentTok != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + Read (); + eol = true; + continue; + } + + switch (Peek()) { + case '/': + readToCurrTok (true); + switch (Peek ()) { + case '/': + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.LineComment); + break; + default: + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Unknown); + break; + } + break; + case ',': + if (curState != States.init && curState != States.classNames ) + throw new ParserException (currentLine, currentColumn, "Unexpected char ','"); + readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); + curState = States.classNames; + break; + case '{': + if (!(curState == States.init || curState == States.classNames)) + throw new ParserException (currentLine, currentColumn, "Unexpected char '{'"); + readAndResetCurrentTok (TokenType.OpenBlock, true); + curState = States.members; + break; + case '}': + if (curState != States.members) + throw new ParserException (currentLine, currentColumn, "Unexpected char '}'"); + readAndResetCurrentTok (TokenType.CloseBlock, true); + curState = States.classNames; + break; + case '=': + if (curState == States.classNames) + throw new ParserException (currentLine, currentColumn, "Unexpected char '='"); + setPreviousTokOfTypeTo (TokenType.Type, TokenType.Identifier); + readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); + curState = States.value; + break; + case '"': + if (curState != States.value) + throw new ParserException (currentLine, currentColumn, "Unexpected char '\"'"); + readAndResetCurrentTok (TokenType.StringLitteralOpening, true); + + while (!eol) { + currentTok += ReadLineUntil ("\""); + if (currentTok.Content [currentTok.Content.Length - 1] == '\\') + readToCurrTok (); + else + break; + } + if (eol) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + saveAndResetCurrentTok (TokenType.StringLitteral); + + readAndResetCurrentTok (TokenType.StringLitteralClosing, true); + curState = States.endOfStatement; + break; + case ';': + if (curState != States.endOfStatement) + throw new ParserException (currentLine, currentColumn, "Unexpected end of statement"); + readAndResetCurrentTok (TokenType.StatementEnding, true); + curState = States.members; + break; + default: + if (currentTok.Type != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "error curtok not null"); + if (curState == States.value) + throw new ParserException (currentLine, currentColumn, "expecting value enclosed in '\"'"); + if (curState == States.endOfStatement) + throw new ParserException (currentLine, currentColumn, "expecting end of statement"); + + if (nextCharIsValidCharStartName) { + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + } + saveAndResetCurrentTok (TokenType.Type); + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + for (int i = 0; i < buffer.LineCount; i++) { + CodeLine cl = buffer[i]; + if (cl.Tokens == null) + continue; + cl.SyntacticNode = null; + + int tokPtr = 0; + while (tokPtr < cl.Tokens.Count) { + switch (cl.Tokens [tokPtr].Type) { + case TokenType.OpenBlock: + currentNode = addChildNode (currentNode, cl, tokPtr, "style"); + break; + case TokenType.CloseBlock: + closeNodeAndGoUp (ref currentNode, cl, "style"); + break; + } + tokPtr++; + } + } + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/Parsers/XMLParser.cs b/Samples/CrowIDE/src/Editors/Parsers/XMLParser.cs new file mode 100644 index 00000000..8e95408e --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Parsers/XMLParser.cs @@ -0,0 +1,307 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Linq; + +namespace Crow.Coding +{ + public class XMLParser : BufferParser + { + public new enum TokenType { + Unknown = BufferParser.TokenType.Unknown, + WhiteSpace = BufferParser.TokenType.WhiteSpace, + NewLine = BufferParser.TokenType.NewLine, + LineComment = BufferParser.TokenType.LineComment, + BlockCommentStart = BufferParser.TokenType.BlockCommentStart, + BlockComment = BufferParser.TokenType.BlockComment, + BlockCommentEnd = BufferParser.TokenType.BlockCommentEnd, + ElementName = BufferParser.TokenType.Type, + AttributeName = BufferParser.TokenType.Identifier, + ElementClosing = BufferParser.TokenType.StatementEnding, + Affectation = BufferParser.TokenType.OperatorOrPunctuation, + AttributeValueOpening = BufferParser.TokenType.StringLitteralOpening, + AttributeValueClosing = BufferParser.TokenType.StringLitteralClosing, + AttributeValue = BufferParser.TokenType.StringLitteral, + XMLDecl = BufferParser.TokenType.Preprocessor, + Doctype = BufferParser.TokenType.Keyword, + ElementStart = 50, + ElementEnd = 51, + } + + public enum States + { + init, //first statement of prolog, xmldecl should only apear in this state + prolog, //misc before doctypedecl + InternalSubset, //doctype declaration subset + ExternalSubsetInit, + ExternalSubset, + BlockComment, + DTDEnd,//doctype finished + XML,//normal xml + StartTag,//inside start tag + Content,//after start tag with no closing slash + EndTag + } + + #region CTOR + public XMLParser (CodeBuffer _buffer) : base(_buffer) {} + #endregion + + enum Keywords + { + DOCTYPE, + ELEMENT, + ATTLIST, + ENTITY, + NOTATION + } + + States curState = States.init; + + #region Regular Expression for validity checks + //private static Regex rxValidChar = new Regex("[\u0020-\uD7FF]"); + private static Regex rxValidChar = new Regex(@"\u0009|\u000A|\u000D|[\u0020-\uD7FF]|[\uE000-\uFFFD]"); //| [\u10000-\u10FFFF] unable to set those plans + private static Regex rxNameStartChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]"); // | [\u10000-\uEFFFF] + private static Regex rxNameChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|-|\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]");//[\u10000-\uEFFFF]| + private static Regex rxDecimal = new Regex(@"[0-9]+"); + private static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + private static Regex rxAttributeValue = new Regex(@"[^<]"); + private static Regex rxEntityValue = new Regex(@"[^<]"); + private static Regex rxPubidChar = new Regex(@"\u0020|\u000D|\u000A|[a-zA-Z0-9]|[-\(\)\+\,\./:=\?;!\*#@\$_%]"); + #endregion + + #region Character ValidityCheck + public bool nextCharIsValidCharStartName + { + get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } + } + public bool nextCharIsValidCharName + { + get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } + } + #endregion + + public override void SetLineInError (ParserException ex) + { + base.SetLineInError (ex); + //buffer[ex.Line].Tokens.EndingState = (int)States.init; + } + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + + while (! eol) { + SkipWhiteSpaces (); + + if (eol) + break; + + if (Peek () == '\n') { + if (currentTok != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + Read (); + eol = true; + continue; + } + + if (curState == States.BlockComment) { + if (currentTok != TokenType.Unknown) + Debugger.Break (); + + currentTok.Start = CurrentPosition; + currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; + currentTok += ReadLineUntil ("-->"); + if (Peek (3) == "-->") { + readToCurrTok (3); + curState = States.XML; + } + saveAndResetCurrentTok (); + continue; + } + + switch (Peek()) { + case '<': + readToCurrTok (true); + switch (Peek()) { + case '?': + if (curState != States.init) + throw new ParserException (currentLine, currentColumn, "xml decl may appear only on first line"); + readToCurrTok (); + currentTok += ReadLineUntil ("?>"); + if (Peek (2) != "?>") + throw new ParserException (currentLine, currentColumn, "expecting '?>'"); + readToCurrTok (2); + saveAndResetCurrentTok (TokenType.XMLDecl); + curState = States.prolog; + break; + case '!': + readToCurrTok (); + switch (Peek()) { + case '-': + readToCurrTok (); + if (Peek () != '-') + throw new ParserException (currentLine, currentColumn, "Expecting comment start tag"); + readToCurrTok (); + currentTok += ReadLineUntil ("--"); + if (Peek (3) == "-->") { + readToCurrTok (3); + }else + curState = States.BlockComment; + saveAndResetCurrentTok (TokenType.BlockComment); + break; + case 'D': + case 'd': + string tmp = Read (7); + currentTok += tmp; + if (!string.Equals (tmp, "DOCTYPE", StringComparison.OrdinalIgnoreCase)) + throw new ParserException (currentLine, currentColumn, "Expecting 'doctype'"); + saveAndResetCurrentTok (TokenType.Doctype); + break; + default: + throw new ParserException (currentLine, currentColumn, "error"); + } + break; + default: + if (!(curState == States.Content || curState == States.XML || curState == States.init || curState == States.prolog)) + throw new ParserException (currentLine, currentColumn, "Unexpected char: '<'"); + if (Peek () == '/') { + curState = States.EndTag; + readToCurrTok (); + saveAndResetCurrentTok (TokenType.ElementEnd); + } else { + curState = States.StartTag; + saveAndResetCurrentTok (TokenType.ElementStart); + } + + if (!nextCharIsValidCharStartName) + throw new ParserException (currentLine, currentColumn, "Expected element name"); + + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + + saveAndResetCurrentTok (TokenType.ElementName); + break; + } + break; + case '/': + if (curState != States.StartTag) + throw new ParserException (currentLine, currentColumn, "Unexpected char: '/'"); + readToCurrTok (true); + if (Peek () != '>') + throw new ParserException (currentLine, currentColumn, "Expecting '>'"); + readAndResetCurrentTok (TokenType.ElementEnd); + + curState = States.XML; + break; + case '>': + readAndResetCurrentTok (TokenType.ElementClosing, true); + switch (curState) { + case States.EndTag: + curState = States.XML; + break; + case States.StartTag: + curState = States.Content; + break; + default: + throw new ParserException (currentLine, currentColumn, "Unexpected char: '>'"); + } + break; + default: + switch (curState) { + case States.StartTag: + if (!nextCharIsValidCharStartName) + throw new ParserException (currentLine, currentColumn, "Expected attribute name"); + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + saveAndResetCurrentTok (TokenType.AttributeName); + + SkipWhiteSpaces (); + + if (Peek () != '=') + throw new ParserException (currentLine, currentColumn, "Expecting: '='"); + readAndResetCurrentTok (TokenType.Affectation, true); + + SkipWhiteSpaces (); + + char openAttVal = Peek (); + if (openAttVal != '"' && openAttVal != '\'') + throw new ParserException (currentLine, currentColumn, "Expecting attribute value enclosed either in '\"' or in \"'\""); + readAndResetCurrentTok (TokenType.AttributeValueOpening, true); + + currentTok.Start = CurrentPosition; + currentTok.Content = ReadLineUntil (new string (new char[]{ openAttVal })); + saveAndResetCurrentTok (TokenType.AttributeValue); + + if (Peek () != openAttVal) + throw new ParserException (currentLine, currentColumn, string.Format ("Expecting {0}", openAttVal)); + readAndResetCurrentTok (TokenType.AttributeValueClosing, true); + break; + default: + throw new ParserException (currentLine, currentColumn, "unexpected char: " + Peek ()); + } + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + for (int i = 0; i < buffer.LineCount; i++) { + CodeLine cl = buffer[i]; + if (cl.Tokens == null) + continue; + cl.SyntacticNode = null; + + int tokPtr = 0; + while (tokPtr < cl.Tokens.Count) { + switch ((XMLParser.TokenType)cl.Tokens [tokPtr].Type) { + case TokenType.ElementStart: + tokPtr++; + currentNode = addChildNode (currentNode, cl, tokPtr, "Element"); + break; + case TokenType.ElementEnd: + tokPtr++; + if (tokPtr < cl.Tokens.Count) { + if ((XMLParser.TokenType)cl.Tokens [tokPtr].Type == TokenType.ElementName && + cl.Tokens [tokPtr].Content != currentNode.Name) + throw new ParserException (currentLine, currentColumn, "Closing tag mismatch"); + } + closeNodeAndGoUp (ref currentNode, cl, "Element"); + break; + case TokenType.ElementClosing: + //currentNode = currentNode.Parent; + break; + default: + break; + } + tokPtr++; + } + } + } + } +} + diff --git a/Samples/CrowIDE/src/Editors/Parsers2/Tokenizer.cs b/Samples/CrowIDE/src/Editors/Parsers2/Tokenizer.cs new file mode 100644 index 00000000..bcda1ec6 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/Parsers2/Tokenizer.cs @@ -0,0 +1,67 @@ +// +// Tokenizer.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 Crow.Text; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Crow.Coding2 +{ + public static class TokenType { + public const int Undefine = 0; + public const int WhiteSpace = 0; + } + public class Token { + public int ptr; + public int length; + } + + public class Tokenizer + { + #region Regular Expression for validity checks + public Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + public Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}"); + public Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + public Regex rxNewLineChar = new Regex(@"\u000D|\u000A|\u0085|\u2028|\u2029"); + public Regex rxWhiteSpaceChar = new Regex(@"\p{Zs}|\u0009|\u000B|\u000C"); + public Regex rxDecimal = new Regex(@"[0-9]+"); + public Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + #endregion + + public List Tokens; + + public Tokenizer (TextBuffer buffer) + { + } + + + public void Tokenize () { + + } + + } +} + diff --git a/Samples/CrowIDE/src/Editors/SourceEditor.cs b/Samples/CrowIDE/src/Editors/SourceEditor.cs new file mode 100644 index 00000000..ca55ee09 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/SourceEditor.cs @@ -0,0 +1,1209 @@ +// +// ScrollingTextBox.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 System.Collections.Generic; +using System.Diagnostics; +using vkvg; + +namespace Crow.Coding +{ + /// + /// Scrolling text box optimized for monospace fonts, for coding + /// + public class SourceEditor : Editor + { + #region CTOR + public SourceEditor (): base() + { + formatting.Add ((int)XMLParser.TokenType.AttributeName, new TextFormatting (Color.DarkSlateGrey, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementName, new TextFormatting (Color.DarkBlue, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementStart, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementEnd, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementClosing, new TextFormatting (Color.Black, Color.Transparent)); + + formatting.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormatting (Color.Crimson, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormatting (Color.Crimson, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormatting (Color.FireBrick, Color.Transparent, false, true)); + formatting.Add ((int)XMLParser.TokenType.XMLDecl, new TextFormatting (Color.ForestGreen, Color.Transparent)); + + formatting.Add ((int)BufferParser.TokenType.BlockComment, new TextFormatting (Color.Grey, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.LineComment, new TextFormatting (Color.Grey, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.OperatorOrPunctuation, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.Teal, Color.Transparent)); + //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"); + + buffer = new CodeBuffer (); + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + buffer.SelectionChanged += Buffer_SelectionChanged; + buffer.PositionChanged += Buffer_PositionChanged; + buffer.FoldingEvent += Buffer_FoldingEvent; + buffer.Add (new CodeLine("")); + } + #endregion + + string oldSource = ""; + //save requested position on error, and try it on next move + int requestedLine = 0, requestedCol = 0; + volatile bool isDirty = false; + + const int leftMarginGap = 10;//gap between items in margin and text + const int foldSize = 9;//folding rectangles size + const int foldHSpace = 4;//folding level tabulation x + int foldMargin { get { return parser == null ? 0 : parser.SyntacticTreeMaxDepth * foldHSpace; }}//folding margin size + + #region private and protected fields + bool foldingEnabled = true; + int leftMargin = 0; //margin used to display line numbers, folding errors,etc... + int visibleLines = 1; + int visibleColumns = 1; + int firstPrintedLine = -1; + int printedCurrentLine = 0;//Index of the currentline in the PrintedLines array + + CodeBuffer buffer; + BufferParser parser; + List PrintedLines;//list of lines visible in the Editor depending on scrolling and folding + + Dictionary formatting = new Dictionary(); + Dictionary parsing = new Dictionary(); + + Color selBackground; + Color selForeground; + int selStartCol; + int selEndCol; + + protected Rectangle rText; + protected FontExtents fe; + protected TextExtents te; + + Point mouseLocalPos; + bool doubleClicked = false; + #endregion + + void measureLeftMargin () { + leftMargin = 0; + if (PrintLineNumbers) + leftMargin += (int)Math.Ceiling((double)buffer.LineCount.ToString().Length * fe.MaxXAdvance) +6; + if (foldingEnabled) + leftMargin += foldMargin; + if (leftMargin > 0) + leftMargin += leftMarginGap; + updateVisibleColumns (); + } + void findLongestLineAndUpdateMaxScrollX() { + buffer.FindLongestVisualLine (); + updateMaxScrollX (); +// Debug.WriteLine ("SourceEditor: Find Longest line and update maxscrollx: {0} visible cols:{1}", MaxScrollX, visibleColumns); + } + /// + /// Updates visible line in widget, adapt max scroll y and updatePrintedLines + /// + void updateVisibleLines(){ + visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); + NotifyValueChanged ("VisibleLines", visibleLines); + updateMaxScrollY (); + updatePrintedLines (); + RegisterForGraphicUpdate (); +// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); + } + void updateVisibleColumns(){ + visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance); + NotifyValueChanged ("VisibleColumns", visibleColumns); + updateMaxScrollX (); +// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); + } + void updateMaxScrollX () { + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + if (buffer.longestLineCharCount > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount); + } + void updateMaxScrollY () { + if (parser == null || !foldingEnabled) { + MaxScrollY = Math.Max (0, buffer.LineCount - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } else { + MaxScrollY = Math.Max (0, buffer.UnfoldedLines - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } + } + void updatePrintedLines () { + buffer.editMutex.EnterReadLock (); + editorMutex.EnterWriteLock (); + + PrintedLines = new List (); + int curL = 0; + int i = 0; + + while (curL < buffer.LineCount && i < ScrollY) { + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + curL++; + i++; + } + + firstPrintedLine = curL; + i = 0; + while (i < visibleLines && curL < buffer.LineCount) { + PrintedLines.Add (buffer [curL]); + + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + + curL++; + i++; + } + + buffer.editMutex.ExitReadLock (); + editorMutex.ExitWriteLock (); + } + void updateOnScreenCurLineFromBuffCurLine(){ + printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); + } + void toogleFolding (int line) { + if (parser == null || !foldingEnabled) + return; + buffer.ToogleFolding (line); + } + + #region Editor overrides + protected override void updateEditorFromProjFile () + { + Debug.WriteLine("\t\tSourceEditor updateEditorFromProjFile"); + + //buffer.editMutex.EnterWriteLock (); + loadSource (); + //buffer.editMutex.ExitWriteLock (); + + isDirty = false; + oldSource = projFile.Source; + CurrentLine = requestedLine; + CurrentColumn = requestedCol; + projFile.RegisteredEditors [this] = true; + } + protected override void updateProjFileFromEditor () + { + Debug.WriteLine("\t\tSourceEditor 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 projFile != null && buffer != null; } + } + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + editorMutex.EnterWriteLock (); + + buffer.longestLineCharCount = 0; + buffer.longestLineIdx = 0; + measureLeftMargin (); + MaxScrollX = MaxScrollY = 0; + PrintedLines = null; + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + + editorMutex.ExitWriteLock (); + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + int charCount = buffer[lptr].PrintableLength; + if (charCount > buffer.longestLineCharCount) { + buffer.longestLineIdx = lptr; + buffer.longestLineCharCount = charCount; + }else if (lptr <= buffer.longestLineIdx) + buffer.longestLineIdx++; + if (parser == null) + continue; + parser.TryParseBufferLine (e.LineStart + i); + } + + if (parser != null) + parser.reparseSource (); + + measureLeftMargin (); + + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + if (lptr <= buffer.longestLineIdx) + trigFindLongestLine = true; + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + measureLeftMargin (); + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + + int lptr = e.LineStart + i; + if (lptr == buffer.longestLineIdx) + trigFindLongestLine = true; + else if (buffer[lptr].PrintableLength > buffer.longestLineCharCount) { + buffer.longestLineCharCount = buffer[lptr].PrintableLength; + buffer.longestLineIdx = lptr; + } + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_PositionChanged (object sender, EventArgs e) + { + //Console.WriteLine ("Position changes: ({0},{1})", buffer.CurrentLine, buffer.CurrentColumn); + int cc = buffer.CurrentTabulatedColumn; + + if (cc > visibleColumns + ScrollX) { + ScrollX = cc - visibleColumns; + } else if (cc < ScrollX) + ScrollX = cc; + + RegisterForGraphicUpdate (); + updateOnScreenCurLineFromBuffCurLine (); + notifyPositionChanged (); + } + + void Buffer_SelectionChanged (object sender, EventArgs e) + { + RegisterForGraphicUpdate (); + } + void Buffer_FoldingEvent (object sender, CodeBufferEventArgs e) + { + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + } + #endregion + + 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 ()); + } + } + + #region Public Crow Properties + public int CurrentLine{ + get { return buffer == null ? 0 : buffer.CurrentLine+1; } + set { + try { + int l = value - 1; + if (l == buffer.CurrentLine) + return; + buffer.CurrentLine = l; + l = buffer.CurrentLine; //reaffect from buffer where bound check is made + if ((bool)buffer [l]?.IsFolded) + buffer.ToogleFolding (l); + } catch (Exception ex) { + requestedLine = value - 1; + Console.WriteLine ("Error cur column: " + ex); + } + } + } + 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 ()); + } + } + } + public bool PrintLineNumbers + { + get { return Configuration.Global.Get ("PrintLineNumbers"); } + set { + if (PrintLineNumbers == value) + return; + Configuration.Global.Set ("PrintLineNumbers", value); + NotifyValueChanged ("PrintLineNumbers", PrintLineNumbers); + measureLeftMargin (); + RegisterForGraphicUpdate (); + } + } + [DefaultValue("SteelBlue")] + public virtual Color SelectionBackground { + get { return selBackground; } + set { + if (value == selBackground) + return; + selBackground = value; + NotifyValueChanged ("SelectionBackground", selBackground); + RegisterForRedraw (); + } + } + [DefaultValue("White")] + public virtual Color SelectionForeground { + get { return selForeground; } + set { + if (value == selForeground) + return; + selForeground = value; + NotifyValueChanged ("SelectionForeground", selForeground); + RegisterForRedraw (); + } + } + public override int ScrollY { + get { + return base.ScrollY; + } + set { + if (value == base.ScrollY) + return; + base.ScrollY = value; + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + 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 + /// + int PrintedCurrentLine { + get { return printedCurrentLine;} + set { + if (value < 0) { + ScrollY += value; + printedCurrentLine = 0; + } else if (PrintedLines.Count < visibleLines && value >= PrintedLines.Count) { + printedCurrentLine = PrintedLines.Count - 1; + }else if (value >= visibleLines) { + ScrollY += value - visibleLines + 1; + printedCurrentLine = visibleLines - 1; + }else + printedCurrentLine = value; + //Debug.WriteLine ("printed current line:" + printedCurrentLine.ToString ()); + //update position in buffer + buffer.CurrentLine = buffer.IndexOf (PrintedLines[printedCurrentLine]); + } + } + int getTabulatedColumn (int col, int line) { + return buffer [line].Content.Substring (0, col).Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + int getTabulatedColumn (Point pos) { + return getTabulatedColumn (pos.X,pos.Y); + } + /// + /// Moves cursor one char to the left, move up if cursor reaches start of line + /// + /// true if move succeed + public bool MoveLeft(){ + if (buffer.CurrentColumn == 0) { + if (printedCurrentLine == 0) + return false; + PrintedCurrentLine--; + buffer.CurrentColumn = int.MaxValue; + } else + buffer.CurrentColumn--; + return true; + } + /// + /// Moves cursor one char to the right, move down if cursor reaches end of line + /// + /// true if move succeed + public bool MoveRight(){ + if (buffer.CurrentColumn >= buffer.CurrentCodeLine.Length) { + if (PrintedCurrentLine == buffer.UnfoldedLines - 1) + return false; + buffer.CurrentColumn = 0; + PrintedCurrentLine++; + } else + buffer.CurrentColumn++; + return true; + } + + #region Drawing + void drawLine(Context gr, Rectangle cb, int i) { + CodeLine cl = PrintedLines[i]; + int lineIndex = buffer.IndexOf(cl); + + double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; + + //Draw line numbering + Color mgFg = Color.Grey; + Color mgBg = Color.White; + if (PrintLineNumbers){ + Rectangle mgR = new Rectangle ((int)x, (int)y, leftMargin - leftMarginGap, (int)Math.Ceiling((fe.Ascent+fe.Descent))); + if (cl.exception != null) { + mgBg = Color.Red; + if (buffer.CurrentLine == lineIndex) + mgFg = Color.White; + else + mgFg = Color.LightGrey; + }else if (buffer.CurrentLine == lineIndex && HasFocus) { + mgFg = Color.Black; + mgBg = Color.DarkGrey; + } + string strLN = (lineIndex+1).ToString (); + gr.SetSourceColor (mgBg); + gr.Rectangle (mgR); + gr.Fill(); + gr.SetSourceColor (mgFg); + + gr.MoveTo (cb.X + (int)(gr.TextExtents (buffer.LineCount.ToString()).Width - gr.TextExtents (strLN).Width), y + fe.Ascent); + gr.ShowText (strLN); + gr.Fill (); + } + + + + //draw folding + if (foldingEnabled){ + + Rectangle rFld = new Rectangle (cb.X + leftMargin - leftMarginGap - foldMargin, + (int)(y + (fe.Ascent + fe.Descent) / 2.0 - foldSize / 2.0), foldSize, foldSize); + + gr.SetSourceColor (Color.Black); + gr.LineWidth = 1.0; + + int level = 0; + bool closingNode = false; + + if (currentNode != null) { + if (cl == currentNode.EndLine) { + currentNode = currentNode.Parent; + closingNode = true; + } + if (currentNode != null) + level = currentNode.Level - 1; + } + + for (int l = 0; l < level; l++) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent + fe.Descent); + rFld.Left += foldHSpace; + } + if (closingNode) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent / 2 + 0.5); + gr.LineTo (rFld.Center.X + 0.5 + foldSize / 2, y + fe.Ascent / 2 + 0.5); + closingNode = false; + } + //gr.SetDash (new double[]{ 1.5 },0.0); + gr.SetSourceColor (Color.Grey); + gr.Stroke (); + //gr.SetDash (new double[]{}, 0.0); + + if (cl.IsFoldable) { + gr.Rectangle (rFld); + gr.SetSourceColor (Color.White); + gr.Fill(); + gr.SetSourceColor (Color.Black); + gr.Rectangle (rFld, 1.0); + if (cl.IsFolded) { + gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2); + gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2); + }else + currentNode = cl.SyntacticNode; + + gr.MoveTo (rFld.Left + 2, rFld.Center.Y + 0.5); + gr.LineTo (rFld.Right - 2, rFld.Center.Y + 0.5); + gr.Stroke (); + } + } + + gr.SetSourceColor (Foreground); + x += leftMargin; + + if (cl.Tokens == null) + drawRawCodeLine (gr, x, y, i, lineIndex); + else + drawParsedCodeLine (gr, x, y, i, lineIndex); + } + Node currentNode = null; +// void drawParsed(Context gr){ +// if (PrintedLines == null) +// return; +// +// gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); +// gr.SetFontSize (Font.Size); +// gr.FontOptions = Interface.FontRenderingOptions; +// gr.Antialias = Interface.Antialias; +// +// Rectangle cb = ClientRectangle; +// gr.Save (); +// CairoHelpers.CairoRectangle (gr, cb, CornerRadius); +// gr.Clip (); +// +// bool selectionInProgress = false; +// +// Foreground.SetAsSource (gr); +// +// #region draw text cursor +// if (SelBegin != SelRelease) +// selectionInProgress = true; +// else if (HasFocus){ +// gr.LineWidth = 1.0; +// double cursorX = + leftMargin + cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; +// gr.MoveTo (0.5 + cursorX, cb.Y + printedCurrentLine * (fe.Ascent+fe.Descent)); +// gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); +// gr.Stroke(); +// } +// #endregion +// +// for (int i = 0; i < PrintedLines.Count; i++) +// drawTokenLine (gr, i, selectionInProgress, cb); +// +// gr.Restore (); +// } + void drawRawCodeLine(Context gr, double x, double y, int i, int lineIndex) { + string lstr = buffer[lineIndex].PrintableContent; + if (ScrollX < lstr.Length) + lstr = lstr.Substring (ScrollX); + else + lstr = ""; + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + + //System.Diagnostics.Debug.WriteLine ("sel start: " + buffer.SelectionStart + " sel end: " + buffer.SelectionEnd); + if (lineIndex == buffer.SelectionStart.Y) { + rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; + rLineW -= selStartCol * fe.MaxXAdvance; + } + if (lineIndex == buffer.SelectionEnd.Y) + rLineW -= (lstr.Length - selEndCol) * fe.MaxXAdvance; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (SelectionBackground); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (SelectionForeground); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + } + void drawParsedCodeLine (Context gr, double x, double y, int i, int lineIndex) { + int lPtr = 0; + CodeLine cl = PrintedLines[i]; + + for (int t = 0; t < cl.Tokens.Count; t++) { + string lstr = cl.Tokens [t].PrintableContent; + if (lPtr < ScrollX) { + if (lPtr - ScrollX + lstr.Length <= 0) { + lPtr += lstr.Length; + continue; + } + lstr = lstr.Substring (ScrollX - lPtr); + lPtr += ScrollX - lPtr; + } + Color bg = this.Background; + Color fg = this.Foreground; + Color selbg = this.SelectionBackground; + Color selfg = this.SelectionForeground; + FontSlant fts = FontSlant.Normal; + FontWeight ftw = FontWeight.Normal; + + if (formatting.ContainsKey ((int)cl.Tokens [t].Type)) { + TextFormatting tf = formatting [(int)cl.Tokens [t].Type]; + bg = tf.Background; + fg = tf.Foreground; + if (tf.Bold) + ftw = FontWeight.Bold; + if (tf.Italic) + fts = FontSlant.Italic; + } + + gr.FontFace = Font.Name; + gr.SetSourceColor (fg); + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (buffer.SelectionInProgress && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y && + !(lineIndex == buffer.SelectionStart.Y && lPtr + lstr.Length <= selStartCol) && + !(lineIndex == buffer.SelectionEnd.Y && selEndCol <= lPtr)) { + + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + double startAdjust = 0.0; + + if ((lineIndex == buffer.SelectionStart.Y) && (selStartCol < lPtr + lstr.Length) && (selStartCol > lPtr)) + startAdjust = (selStartCol - lPtr) * fe.MaxXAdvance; + rLineX += startAdjust; + if ((lineIndex == buffer.SelectionEnd.Y) && (selEndCol < lPtr + lstr.Length)) + rLineW = (selEndCol - lPtr) * fe.MaxXAdvance; + rLineW -= startAdjust; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (selbg); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (selfg); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + x += (int)lstr.Length * fe.MaxXAdvance; + lPtr += lstr.Length; + } + } + + #endregion + + #region GraphicObject overrides + public override Font Font { + get { return base.Font; } + set { + base.Font = value; + /* + using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) { + using (Context gr = new Context (img)) { + gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); + gr.SetFontSize (Font.Size); + + fe = gr.FontExtents; + } + }*/ + MaxScrollY = 0; + RegisterForGraphicUpdate (); + } + } + protected override int measureRawSize(LayoutingType lt) + { + if (lt == LayoutingType.Height) + return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; + + return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2 + leftMargin; + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + + if (layoutType == LayoutingType.Height) + updateVisibleLines (); + else if (layoutType == LayoutingType.Width) + updateVisibleColumns (); + } + + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + gr.FontFace = Font.Name; + gr.FontSize = (uint)Font.Size; + + Rectangle cb = ClientRectangle; + + Foreground.SetAsSource (gr); + + buffer.editMutex.EnterReadLock (); + editorMutex.EnterReadLock (); + + #region draw text cursor + if (buffer.SelectionInProgress){ + selStartCol = getTabulatedColumn (buffer.SelectionStart); + selEndCol = getTabulatedColumn (buffer.SelectionEnd); + }else if (HasFocus && printedCurrentLine >= 0){ + gr.LineWidth = 1.0; + double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance + leftMargin; + gr.MoveTo (0.5 + cursorX, cb.Y + (printedCurrentLine) * (fe.Ascent+fe.Descent)); + gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); + gr.Stroke(); + } + #endregion + + if (PrintedLines?.Count > 0) { + int unfoldedLines = buffer.UnfoldedLines; + currentNode = null; + CodeLine cl = PrintedLines[0]; + int idx0 = buffer.IndexOf(cl); + int li = idx0-1; + while (li >= 0) { + if (buffer [li].IsFoldable && !buffer [li].IsFolded) { + if (buffer.IndexOf(buffer [li].SyntacticNode.EndLine) > idx0){ + currentNode = buffer [li].SyntacticNode; + break; + } + } + li--; + } + + for (int i = 0; i < visibleLines; i++) { + if (i + ScrollY >= unfoldedLines)//TODO:need optimize + break; + drawLine (gr, cb, i); + } + } + + editorMutex.ExitReadLock (); + + buffer.editMutex.ExitReadLock (); + + } + #endregion + + #region Mouse handling + + int hoverLine = -1; + public int HoverLine { + get { return hoverLine; } + set { + if (hoverLine == value) + return; + hoverLine = value; + NotifyValueChanged ("HoverLine", hoverLine); + NotifyValueChanged ("HoverError", buffer [hoverLine].exception); + } + } + void updateHoverLine () { + if (PrintedLines.Count > 0) { + int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent + fe.Descent))); + hvl = Math.Min (PrintedLines.Count - 1, hvl); + HoverLine = buffer.IndexOf (PrintedLines [hvl]); + } else + HoverLine = 0; + } + void updateCurrentPosFromMouseLocalPos(){ + PrintedCurrentLine = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X - leftMargin) / fe.MaxXAdvance); + + int i = 0; + int buffCol = 0; + while (i < curVisualCol && buffCol < buffer.CurrentCodeLine.Length) { + if (buffer.CurrentCodeLine[buffCol] == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + buffer.CurrentColumn = buffCol; + } + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { + base.onMouseEnter (sender, e); + if (e.X - ScreenCoordinates(Slot).X < leftMargin + ClientRectangle.X) + IFace.MouseCursor = MouseCursor.Arrow; + else + IFace.MouseCursor = MouseCursor.IBeam; + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); + IFace.MouseCursor = MouseCursor.Arrow; + } + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; + + updateHoverLine (); + + if (!e.Mouse.IsButtonDown (MouseButton.Left)) { + if (mouseLocalPos.X < leftMargin) + IFace.MouseCursor = MouseCursor.Arrow; + else + IFace.MouseCursor = MouseCursor.IBeam; + return; + } + + if (!HasFocus || !buffer.SelectionInProgress) + return; + + //mouse is down + updateCurrentPosFromMouseLocalPos(); + buffer.SetSelEndPos (); + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + if (!this.Focusable) + return; + + if (mouseLocalPos.X >= leftMargin) + base.onMouseDown (sender, e); + + if (doubleClicked) { + doubleClicked = false; + return; + } + + if (mouseLocalPos.X < leftMargin) { + toogleFolding (buffer.IndexOf (PrintedLines [(int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent)))])); + return; + } + + updateCurrentPosFromMouseLocalPos (); + buffer.SetSelStartPos (); + } + public override void onMouseUp (object sender, MouseButtonEventArgs e) + { + base.onMouseUp (sender, e); + + if (buffer.SelectionIsEmpty) + buffer.ResetSelection (); + } + + public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) + { + doubleClicked = true; + base.onMouseDoubleClick (sender, e); + + buffer.GotoWordStart (); + buffer.SetSelStartPos (); + buffer.GotoWordEnd (); + buffer.SetSelEndPos (); + } + public void MakeSelection (int lineStart, int colStart, int lineEnd, int colEnd) { + buffer.CurrentLine = lineStart; + buffer.CurrentColumn = colStart; + buffer.SetSelStartPos (); + buffer.CurrentLine = lineEnd; + buffer.CurrentColumn = colEnd; + buffer.SetSelEndPos (); + } + public override void onMouseWheel (object sender, MouseWheelEventArgs e) + { + base.onMouseWheel (sender, e); + } + #endregion + + #region Keyboard handling + public override void onKeyDown (object sender, KeyEventArgs e) + { + //base.onKeyDown (sender, e); + + Key key = e.Key; + + if (IFace.Ctrl) { + switch (key) { + case Key.S: + projFile.Save (); + break; + case Key.W: + editorMutex.EnterWriteLock (); + if (IFace.Shift) + projFile.Redo (null); + else + projFile.Undo (null); + editorMutex.ExitWriteLock (); + break; + default: + Console.WriteLine (""); + break; + } + } + + switch (key) + { + case Key.Backspace: + buffer.DeleteChar (); + break; + case Key.Delete: + if (buffer.SelectionIsEmpty) + MoveRight (); + else if (IFace.Shift) + IFace.Clipboard = buffer.SelectedText; + buffer.DeleteChar (); + break; + case Key.Enter: + case Key.KeypadEnter: + if (!buffer.SelectionIsEmpty) + buffer.DeleteChar (); + buffer.InsertLineBreak (); + break; + case Key.Escape: + buffer.ResetSelection (); + break; + case Key.Home: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + break; + case Key.End: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + break; + case Key.Insert: + if (IFace.Shift) + buffer.Insert (IFace.Clipboard); + else if (IFace.Ctrl && !buffer.SelectionIsEmpty) + IFace.Clipboard = buffer.SelectedText; + break; + case Key.Left: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.GotoWordStart (); + else + MoveLeft (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.GotoWordStart (); + else + MoveLeft(); + break; + case Key.Right: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (IFace.Ctrl) + buffer.GotoWordEnd (); + else + MoveRight (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (IFace.Ctrl) + buffer.GotoWordEnd (); + else + MoveRight (); + break; + case Key.Up: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine--; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine--; + break; + case Key.Down: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine++; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine++; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine += visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine += visibleLines; + break; + case Key.PageUp: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine -= visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine -= visibleLines; + break; + case Key.Tab: + if (IFace.Shift) { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + //TODO + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) + buffer.RemoveLeadingTab (i); + buffer.SetSelectionOnFullLines (); + } else { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + buffer.Insert ("\t"); + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) { + buffer.UpdateLine (i, "\t" + buffer [i].Content); + } + } + + break; + case Key.F8: + toogleFolding (buffer.CurrentLine); + break; + default: + break; + } + RegisterForGraphicUpdate(); + } + public override void onKeyPress (object sender, KeyPressEventArgs e) + { + base.onKeyPress (sender, e); + + buffer.Insert (e.KeyChar.ToString()); + buffer.ResetSelection (); + } + #endregion + } +} \ No newline at end of file diff --git a/Samples/CrowIDE/src/Editors/SvgEditor.cs b/Samples/CrowIDE/src/Editors/SvgEditor.cs new file mode 100644 index 00000000..d81b1154 --- /dev/null +++ b/Samples/CrowIDE/src/Editors/SvgEditor.cs @@ -0,0 +1,140 @@ +// +// 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 vkvg; + +namespace Crow.Coding +{ + public class SvgEditor : Editor + { + SvgPicture _pic = new SvgPicture(); + + int zoom; + + [DefaultValue(100)] + public int Zoom { + get { return zoom; } + set { + if (zoom == value) + return; + zoom = value; + NotifyValueChanged ("Zoom", zoom); + updateMaxScrolls (); + RegisterForGraphicUpdate (); + } + } + + void updateMaxScrolls() { + MaxScrollX = Math.Max(0, _pic.Dimensions.Width * zoom / 100 - Slot.Width); + MaxScrollY = Math.Max(0, _pic.Dimensions.Height * zoom / 100 - Slot.Height); + + if (Slot.Width + MaxScrollX > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / (Slot.Width + MaxScrollX)); + else + NotifyValueChanged ("ChildWidthRatio", 0); + + if (Slot.Height + MaxScrollY > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / (Slot.Height + MaxScrollY)); + else + NotifyValueChanged ("ChildHeightRatio", 0); + } + #region editor overrides + protected override void updateEditorFromProjFile () + { + Error = null; + try { + editorMutex.EnterWriteLock(); + _pic.LoadSvgFragment (projFile.Source); + _pic.Scaled = true; + _pic.KeepProportions = true; + } catch (Exception ex) { + Error = ex; + } + editorMutex.ExitWriteLock (); + updateMaxScrolls (); + RegisterForGraphicUpdate (); + } + protected override void updateProjFileFromEditor () + { + throw new NotImplementedException (); + } + protected override bool EditorIsDirty { + get { return false; } + set { + throw new NotImplementedException (); + } + } + protected override bool IsReady { + get { return projFile != null; } + } + #endregion + + #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); + + Rectangle r = ClientRectangle; + Foreground.SetAsSource (gr, r); + gr.Rectangle (r, 0.1); + gr.Stroke (); + + r.Width = _pic.Dimensions.Width * zoom / 100; + r.Height = _pic.Dimensions.Height * zoom / 100; + + gr.Save (); + + editorMutex.EnterReadLock (); + + gr.Translate (-ScrollX, -ScrollY); + if (_pic != null) + _pic.Paint (gr, r); + editorMutex.ExitReadLock (); + + gr.Restore (); + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + if ((layoutType | LayoutingType.Sizing) > 0) + updateMaxScrolls (); + } + #endregion + } +} + diff --git a/Samples/CrowIDE/src/Extensions.cs b/Samples/CrowIDE/src/Extensions.cs new file mode 100644 index 00000000..86c5834f --- /dev/null +++ b/Samples/CrowIDE/src/Extensions.cs @@ -0,0 +1,45 @@ +// +// Extensions.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; +using System.Collections.Generic; + +namespace Crow +{ + public static partial class Extensions + { + public static string GetIcon(this Widget go){ + return "#CrowIDE.icons.toolbox." + go.GetType().FullName + ".svg"; + } + public static List GetChildren(this Widget go){ + Type goType = go.GetType(); + if (typeof (Group).IsAssignableFrom (goType)) + return (go as Group).Children; + if (typeof(Container).IsAssignableFrom (goType)) + return new List( new Widget[] { (go as Container).Child }); + if (typeof(TemplatedContainer).IsAssignableFrom (goType)) + return new List( new Widget[] { (go as TemplatedContainer).Content }); + if (typeof(TemplatedGroup).IsAssignableFrom (goType)) + return (go as TemplatedGroup).Items; + + return new List(); + } + } +} diff --git a/Samples/CrowIDE/src/GraphicObjectDesignContainer.cs b/Samples/CrowIDE/src/GraphicObjectDesignContainer.cs new file mode 100644 index 00000000..166181d8 --- /dev/null +++ b/Samples/CrowIDE/src/GraphicObjectDesignContainer.cs @@ -0,0 +1,85 @@ +// +// GraphicObjectDesignContainer.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; + +namespace Crow.Coding +{ + public class GraphicObjectDesignContainer + { + #region CTOR + public GraphicObjectDesignContainer (Type crowType) + { + CrowType = crowType; + } + #endregion + + int dragIconSize = 32; + public Type CrowType; + + public string IconPath { + get { return "#CrowIDE.icons.toolbox." + CrowType.FullName + ".svg"; } + } + public string DisplayName { + get { return CrowType.Name; } + } + void onStartDrag (object sender, EventArgs e) + { + /* + Widget go = sender as Widget; + + lock (go.IFace.UpdateMutex) { + go.IFace.DragImageHeight = dragIconSize; + go.IFace.DragImageWidth = dragIconSize; + SvgPicture pic = new SvgPicture (IconPath); + //pic.Load (go.IFace, IconPath); + ImageSurface img = new ImageSurface (Format.Argb32, dragIconSize, dragIconSize); + using (Context ctx = new Context (img)) { + Rectangle r = new Rectangle (0, 0, dragIconSize, dragIconSize); + pic.Paint (ctx, r); + ctx.Operator = Operator.In; + ctx.SetSourceRGBA (1.0, 1.0, 1.0, 1.0); + ctx.Rectangle (r); + ctx.Fill (); + + } + go.IFace.DragImage = img; + }*/ + } + void onEndDrag (object sender, DragDropEventArgs e) + { + (sender as Widget).IFace.ClearDragImage (); + + } + void onDrop (object sender, DragDropEventArgs e) + { + ImlVisualEditor imlVE = e.DropTarget as ImlVisualEditor; + if (imlVE != null) + imlVE.ClearDraggedObj (false); + (sender as Widget).IFace.ClearDragImage (); + } + } +} + diff --git a/Samples/CrowIDE/src/INetProject.cs b/Samples/CrowIDE/src/INetProject.cs new file mode 100644 index 00000000..53d81a1f --- /dev/null +++ b/Samples/CrowIDE/src/INetProject.cs @@ -0,0 +1,35 @@ +// +// INetProject.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; + +namespace Crow.Coding +{ + public interface INetProject + { + + } +} + diff --git a/Samples/CrowIDE/src/MemberView/CategoryContainer.cs b/Samples/CrowIDE/src/MemberView/CategoryContainer.cs new file mode 100644 index 00000000..fbf3fe2c --- /dev/null +++ b/Samples/CrowIDE/src/MemberView/CategoryContainer.cs @@ -0,0 +1,65 @@ +// +// CategoryContainer.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; + +namespace Crow.Coding +{ + public class CategoryContainer : IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + bool _isExpanded = true; + + public PropertyContainer[] Properties; + public string Name; + + public bool IsExpanded + { + get { return _isExpanded; } + set + { + if (value == _isExpanded) + return; + + _isExpanded = value; + + NotifyValueChanged ("IsExpanded", _isExpanded); + } + } + + public CategoryContainer (string categoryName, PropertyContainer[] properties){ + Name = categoryName; + Properties = properties; + } + } +} + diff --git a/Samples/CrowIDE/src/MemberView/MembersView.cs b/Samples/CrowIDE/src/MemberView/MembersView.cs new file mode 100644 index 00000000..b8dad3d0 --- /dev/null +++ b/Samples/CrowIDE/src/MemberView/MembersView.cs @@ -0,0 +1,139 @@ +// +// MembersView.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; +using Crow; +using System.Xml.Serialization; +using System.ComponentModel; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; + +namespace Crow.Coding +{ + public class MembersView : ListBox + { + object instance; + ImlProjectItem projFile; + + public MembersView () : base() {} + + //cache property containers per type + //Dictionary propContainersCache = new Dictionary(); + Dictionary> categoryContainersCache = new Dictionary> (); + + [DefaultValue(null)] + public virtual object Instance { + get { return instance; } + set { + if (instance == value) + return; + object lastInst = instance; + + instance = value; + NotifyValueChanged ("Instance", instance); + + if (Instance is Widget) { + NotifyValueChanged ("SelectedItemName", Instance.GetType().Name + (Instance as Widget).design_id + + ":" + (Instance as Widget).design_imlPath ); + }else + NotifyValueChanged ("SelectedItemName", ""); + + if (instance == null) { + Data = null; + return; + } + + Type it = instance.GetType (); + if (!categoryContainersCache.ContainsKey (it.FullName)) { + MemberInfo[] members = it.GetMembers (BindingFlags.Public | BindingFlags.Instance); + List props = new List (); + foreach (MemberInfo m in members) { + if (m.MemberType == MemberTypes.Property) { + PropertyInfo pi = m as PropertyInfo; + if (!pi.CanWrite) + continue; + if (pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)) != null) + continue; + props.Add (new PropertyContainer (this, pi)); + } + } + //propContainersCache.Add (it.FullName, props.OrderBy (p => p.Name).ToArray ()); + List categories = new List (); + + foreach (IGrouping ig in props.OrderBy (p => p.Name).GroupBy(pc=>pc.DesignCategory)) { + categories.Add(new CategoryContainer(ig.Key, ig.ToArray())); + } + categoryContainersCache.Add (it.FullName, categories); + } + + + Data = categoryContainersCache[it.FullName]; + + if (lastInst != instance) { + foreach (CategoryContainer cc in categoryContainersCache [it.FullName]) { + foreach (PropertyContainer pc in cc.Properties) { + pc.NotifyValueChanged ("Value", pc.Value); + pc.NotifyValueChanged ("LabForeground", pc.LabForeground); + } + } + } + } + } + public ImlProjectItem 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); + } + } + +// public void updateSource () { +// if (projFile == null) +// return; +// projFile.UpdateSource (this, (Instance as GraphicObject).GetIML ()); +// } + +// public override void Paint (ref Context ctx) +// { +// base.Paint (ref ctx); +// +// if (SelectedIndex < 0) +// return; +// +// Rectangle r = Parent.ContextCoordinates(Items [SelectedIndex].Slot); +// ctx.SetSourceRGB (0, 0, 1); +// ctx.Rectangle (r); +// ctx.LineWidth = 2; +// ctx.Stroke (); +// } + + } +} diff --git a/Samples/CrowIDE/src/MemberView/PropertyContainer.cs b/Samples/CrowIDE/src/MemberView/PropertyContainer.cs new file mode 100644 index 00000000..4d043ab4 --- /dev/null +++ b/Samples/CrowIDE/src/MemberView/PropertyContainer.cs @@ -0,0 +1,222 @@ +// +// PropertyContainer.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.Reflection; +using System.Linq; +using System.Collections.Generic; +using System.Diagnostics; +using System.ComponentModel; + +namespace Crow.Coding +{ + public class PropertyContainer : IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + PropertyInfo pi; + MembersView mview; + Command cmdReset, cmdGoToStyle; + + public List Commands; + + #region CTOR + public PropertyContainer(MembersView mv, PropertyInfo prop){ + mview = mv; + pi = prop; + + cmdReset = new Crow.Command (new Action (() => Reset ())) { Caption = "Reset to default" }; + cmdGoToStyle = new Crow.Command (new Action (() => GotoStyle ())) { Caption = "Goto style" }; + + Commands = new List (new Crow.Command[] { cmdReset, cmdGoToStyle }); + } + #endregion + + public string DesignCategory { + get { + DesignCategory dca = (DesignCategory)pi.GetCustomAttribute (typeof(DesignCategory)); + return dca == null ? "Divers" : dca.Name; + } + } + public string Name { get { return pi.Name; }} + public object Value { + get { + return mview.ProjectNode?.SelectedItem == null ? null : pi.GetValue(mview.ProjectNode.SelectedItem); + } + set { + try { + if (value == Value) + return; + Widget g = Instance; + string valstr = null, oldval = null; + + if (value != null) + valstr = value.ToString(); + + if (HasStyling) + oldval = g.design_style_values[Name]; + else if (HasDefaultValue) + oldval = DefaultValue?.ToString(); + else if (IsSetByIML) + oldval = g.design_iml_values [Name]; + + if (valstr == oldval){ + if (IsSetByIML){ + g.design_iml_values.Remove(Name); + Debug.WriteLine("iml attrib removed {0}.{1}", g.Name, Name); + }else + return; + }else{ + if (IsSetByIML){ + g.design_iml_values [Name] = valstr; + Debug.WriteLine("iml update {0}.{1} = {2}", g.Name, Name, valstr); + }else{ + g.design_iml_values.Add(Name,valstr); + Debug.WriteLine("iml add {0}.{1} = {2}", g.Name, Name, valstr); + } + } + + if (!pi.PropertyType.IsAssignableFrom(value.GetType()) && pi.PropertyType != typeof(string)){ + if (pi.PropertyType.IsEnum) { + if (value is string) { + pi.SetValue (g, Enum.Parse (pi.PropertyType, (string)value)); + }else + pi.SetValue (g, value); + } else { + MethodInfo me = pi.PropertyType.GetMethod + ("Parse", BindingFlags.Static | BindingFlags.Public, + System.Type.DefaultBinder, new Type [] {typeof (string)},null); + pi.SetValue (g, me.Invoke (null, new object[] { value }), null); + } + }else + pi.SetValue(g, value); + + Debug.WriteLine("\t\tPropContainer set design_dirty to instance"); + + mview.ProjectNode.Instance.design_HasChanged = true; + NotifyValueChanged ("Value", value); + NotifyValueChanged ("LabForeground", LabForeground); + } catch (Exception ex) { + Debug.WriteLine ("Error setting property:"+ ex.ToString()); + } + // + } + } + /// + /// for style attribute which is a string, return Style as type + /// + public string Type { get { return pi.PropertyType.IsEnum ? + "System.Enum" + : pi.Name == "Style" ? "Style" : pi.PropertyType.FullName; }} + + public object[] Choices { + get { + return pi.PropertyType.IsEnum ? + Enum.GetValues (pi.PropertyType).Cast().ToArray() : + mview.ProjectNode.Project.solution.AvailaibleStyles; + } + } + /// + /// Current graphicobject instance + /// + public Widget Instance { + get { return mview.ProjectNode.SelectedItem as Widget; } + } + public object DefaultValue { + get { return ((DefaultValueAttribute)(pi.GetCustomAttribute (typeof (DefaultValueAttribute)))).Value; } + } + public bool HasDefaultValue { + get { return pi.GetCustomAttribute (typeof(DefaultValueAttribute))!=null; } + } + /// + /// return true if current value comes from IML attributes + /// + public bool IsSetByIML { + get { return Instance.design_iml_values.ContainsKey (Name); } + } + /// + /// return true if member default value comes from style + /// + public bool HasStyling { + get { return Instance.design_style_locations.ContainsKey(Name); } + } + /// + /// Return true if current value comes from styling + /// + public bool IsSetByStyling { + get { return IsSetByIML ? false : HasStyling; } + } + + + public Fill LabForeground { + get { return IsSetByIML ? Color.DarkBlue : HasStyling ? Color.Black : Color.Grey;} + } + + /// + /// reset to default value + /// + public void Reset () { + Widget inst = mview.ProjectNode.SelectedItem as Widget; + if (!inst.design_iml_values.ContainsKey (Name)) + return; + inst.design_iml_values.Remove (Name); + + NotifyValueChanged ("LabForeground", LabForeground); + mview.ProjectNode.UpdateSource(this, mview.ProjectNode.Instance.GetIML()); + //mview.ProjectNode.Instance.design_HasChanged = true; + //should reinstantiate to get default + } + public void GotoStyle(){ + Widget g = Instance; + if (!g.design_style_locations.ContainsKey (Name)) + return; + FileLocation fl = g.design_style_locations [Name]; + ProjectFile pf; + if (!mview.ProjectNode.Project.TryGetProjectFileFromPath ("#" + fl.FilePath, out pf)) + return; + + if (!pf.IsOpened) + pf.Open (); + + pf.CurrentLine = fl.Line; + pf.CurrentColumn = fl.Column; + + pf.IsSelected = true; + + } + + public override string ToString () + { + return string.Format ("{0} = {1}", Name, Value); + } + } +} + diff --git a/Samples/CrowIDE/src/Project.cs b/Samples/CrowIDE/src/Project.cs new file mode 100644 index 00000000..a3ffa636 --- /dev/null +++ b/Samples/CrowIDE/src/Project.cs @@ -0,0 +1,519 @@ +// +// Project.cs +// +// Author: +// jp <> +// +// 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.Xml; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using Crow; +using System.Text.RegularExpressions; + +namespace Crow.Coding { + public class Project : IValueChange { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged (string MemberName, object _value) { + ValueChanged.Raise (this, new ValueChangeEventArgs (MemberName, _value)); + } + #endregion + + bool isLoaded = false; + bool isExpanded; + XmlDocument xmlDoc; + XmlNode nodeProject; + XmlNode nodeProps; + XmlNodeList nodesItems; + SolutionProject solutionProject; + Crow.Command cmdSave, cmdOpen, cmdCompile, cmdSetAsStartProj, cmdNewFile; + + #region CTOR + public Project (Solution sol, SolutionProject sp) { + solutionProject = sp; + + solution = sol; + + cmdSave = new Crow.Command (new Action (() => Save ())) { Caption = "Save", Icon = new SvgPicture ("#CrowIDE.icons.save.svg"), CanExecute = true }; + cmdOpen = new Crow.Command (new Action (() => Load ())) { Caption = "Open", Icon = new SvgPicture ("#CrowIDE.icons.open.svg"), CanExecute = false }; + cmdCompile = new Crow.Command (new Action (() => Compile ())) { + Caption = "Compile", + Icon = "#CrowIDE.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", + Icon = new SvgPicture ("#CrowIDE.icons.blank-file.svg"), + CanExecute = true + }; + + Commands = new List (new Crow.Command[] { cmdOpen, cmdSave, cmdSetAsStartProj, cmdCompile, cmdNewFile }); + + Load (); + } + #endregion + + public Solution solution; + public List Commands; + public CompilerResults CompilationResults; + public List dependantProjects = new List (); + public Project ParentProject = null; + List rootItems; + List flattenNodes; + + public string Name { + get { return solutionProject.ProjectName; } + } + public bool IsLoaded { + get { return isLoaded; } + set { + if (isLoaded == value) + return; + isLoaded = value; + NotifyValueChanged ("IsLoaded", isLoaded); + } + } + public bool IsExpanded { + get { return isExpanded; } + set { + if (value == isExpanded) + return; + isExpanded = value; + NotifyValueChanged ("IsExpanded", isExpanded); + } + } + public bool IsStartupProject { + get { return solution.StartupProject == this; } + } + public string Path { + get { return System.IO.Path.Combine (solution.SolutionFolder, solutionProject.RelativePath.Replace ('\\', '/')); } + } + public string RootDir { + get { return System.IO.Path.GetDirectoryName (Path); } + } + + + + public List RootItems { + get { return rootItems; } + } + + void buildTreeNodes () { + ProjectNode root = new ProjectNode (this, ItemType.VirtualGroup, RootNamespace); + List items = new List (); + foreach (XmlNode i in nodesItems) { + foreach (XmlNode f in i.ChildNodes) { + items.Add (new ProjectItem (this, f)); + } + } + + flattenNodes = new List (); + + ProjectNode refs = new ProjectNode (this, ItemType.ReferenceGroup, "References"); + root.AddChild (refs); + + foreach (ProjectItem pn in items) { + switch (pn.Type) { + case ItemType.Reference: + refs.AddChild (pn); + flattenNodes.Add (pn); + break; + case ItemType.ProjectReference: + ProjectReference pr = new ProjectReference (pn); + refs.AddChild (pr); + flattenNodes.Add (pr); + break; + case ItemType.Compile: + case ItemType.None: + case ItemType.EmbeddedResource: + ProjectNode curNode = root; + string[] folds = pn.Path.Split ('/'); + for (int i = 0; i < folds.Length - 1; i++) { + ProjectNode nextNode = curNode.ChildNodes.FirstOrDefault (n => n.DisplayName == folds[i] && n.Type == ItemType.VirtualGroup); + if (nextNode == null) { + nextNode = new ProjectNode (this, ItemType.VirtualGroup, folds[i]); + curNode.AddChild (nextNode); + } + curNode = nextNode; + } + ProjectNode f = null; + switch (pn.Extension) { + /*case ".cs": + f = new CSProjectFile (pn); + break;*/ + case ".crow": + case ".template": + case ".goml": + case ".itemp": + case ".imtl": + f = new ImlProjectItem (pn); + break; + case ".style": + f = new StyleProjectItem (pn); + break; + default: + f = new ProjectFile (pn); + break; + } + curNode.AddChild (f); + flattenNodes.Add (f); + break; + } + } + root.SortChilds (); + + rootItems = root.ChildNodes; + } + + #region Project properties + public string ToolsVersion { + get { return nodeProject?.Attributes["ToolsVersion"]?.Value; } + } + public string DefaultTargets { + get { return nodeProject?.Attributes["DefaultTargets"]?.Value; } + } + public string ProjectGuid { + get { return solutionProject.ProjectGuid; } + } + public string AssemblyName { + get { return nodeProps["AssemblyName"]?.InnerText; } + } + public string OutputType { + get { return nodeProps["OutputType"]?.InnerText; } + } + public string RootNamespace { + get { return nodeProps["RootNamespace"]?.InnerText; } + } + public bool AllowUnsafeBlocks { + get { + return nodeProps["AllowUnsafeBlocks"] == null ? false : + bool.Parse (nodeProps["AllowUnsafeBlocks"]?.InnerText); + } + } + public bool NoStdLib { + get { + return nodeProps["NoStdLib"] == null ? false : + bool.Parse (nodeProps["NoStdLib"]?.InnerText); + } + } + public bool TreatWarningsAsErrors { + get { + return nodeProps["TreatWarningsAsErrors"] == null ? false : + bool.Parse (nodeProps["TreatWarningsAsErrors"]?.InnerText); + } + } + public bool SignAssembly { + get { return bool.Parse (nodeProps["SignAssembly"]?.InnerText); } + } + public string TargetFrameworkVersion { + get { return nodeProps["TargetFrameworkVersion"]?.InnerText; } + } + public string Description { + get { return nodeProps["Description"]?.InnerText; } + } + public string OutputPath { + get { return nodeProps["OutputPath"]?.InnerText; } + } + public string IntermediateOutputPath { + get { return nodeProps["IntermediateOutputPath"]?.InnerText; } + } + public string StartupObject { + get { return nodeProps["StartupObject"]?.InnerText; } + } + public bool DebugSymbols { + get { return nodeProps["DebugSymbols"] == null ? false : bool.Parse (nodeProps["DebugSymbols"]?.InnerText); } + } + public int WarningLevel { + get { return nodeProps["WarningLevel"] == null ? 0 : int.Parse (nodeProps["WarningLevel"]?.InnerText); } + } + + #endregion + + + public void AddNewFile () { + Window.Show (CrowIDE.MainIFace, "#CrowIDE.ui.NewFile.crow", true).DataSource = this; + } + + public void Load () { + + xmlDoc = new XmlDocument (); + using (Stream ins = new FileStream (this.Path, FileMode.Open)) { + xmlDoc.Load (new XmlTextReader (ins) { Namespaces = false }); + } + + nodeProject = xmlDoc.SelectSingleNode ("Project"); + XmlNodeList nodesProps = xmlDoc.SelectNodes ("/Project/PropertyGroup"); + + foreach (XmlNode n in nodesProps) { + if (n.Attributes["Condition"] == null) + nodeProps = n; + } + nodesItems = xmlDoc.SelectNodes ("/Project/ItemGroup"); + + if (ProjectGuid != solutionProject.ProjectGuid) + throw new Exception ("Project GUID not matching with solution"); + + buildTreeNodes (); + + IsLoaded = true; + } + + public void Save () { + + } + + void setAsStartupProject () { + solution.StartupProject = this; + } + static Regex regexDirTokens = new Regex (@"\$\(([^\)]*)\)|([^\$]*)"); + + string getDirectoryWithTokens (string dir) { + Match m = regexDirTokens.Match (dir); + string tmp = ""; + while (m.Success) { + if (m.Value == @"$(SolutionDir)") + tmp = System.IO.Path.Combine (tmp, solution.SolutionFolder); + else if (m.Value == @"$(Configuration)") + tmp = System.IO.Path.Combine (tmp, "Debug"); + else + tmp = System.IO.Path.Combine (tmp, m.Value); + + if (tmp.EndsWith (@"\") || tmp.EndsWith (@"/")) + tmp = tmp.Remove (tmp.Length - 1); + + m = m.NextMatch (); + } + return tmp; + } + public string Compile () { + if (ParentProject != null) + ParentProject.Compile (); + + CSharpCodeProvider cp = new CSharpCodeProvider (); + CompilerParameters parameters = new CompilerParameters (); + + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + parameters.ReferencedAssemblies.Add (p.Compile ()); + } + + string outputDir = getDirectoryWithTokens (this.OutputPath); + string objDir = getDirectoryWithTokens (this.IntermediateOutputPath); + + Directory.CreateDirectory (outputDir); + Directory.CreateDirectory (objDir); + + parameters.OutputAssembly = System.IO.Path.Combine (outputDir, this.AssemblyName); + + // True - exe file generation, false - dll file generation + if (this.OutputType == "Library") { + parameters.GenerateExecutable = false; + parameters.CompilerOptions += " /target:library"; + parameters.OutputAssembly += ".dll"; + } else { + parameters.GenerateExecutable = true; + parameters.CompilerOptions += " /target:exe"; + parameters.OutputAssembly += ".exe"; + parameters.MainClass = this.StartupObject; + } + + parameters.GenerateInMemory = false; + parameters.IncludeDebugInformation = this.DebugSymbols; + parameters.TreatWarningsAsErrors = this.TreatWarningsAsErrors; + parameters.WarningLevel = this.WarningLevel; + parameters.CompilerOptions += " /noconfig"; + if (this.AllowUnsafeBlocks) + parameters.CompilerOptions += " /unsafe"; + parameters.CompilerOptions += " /delaysign+"; + parameters.CompilerOptions += " /debug:full /debug+"; + parameters.CompilerOptions += " /optimize-"; + parameters.CompilerOptions += " /define:\"DEBUG;TRACE\""; + parameters.CompilerOptions += " /nostdlib"; + + + + foreach (ProjectItem pi in flattenNodes.Where (p => p.Type == ItemType.Reference)) { + + if (string.IsNullOrEmpty (pi.HintPath)) { + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/" + pi.Path + ".dll"; + continue; + } + parameters.ReferencedAssemblies.Add (pi.Path); + string fullHintPath = System.IO.Path.GetFullPath (System.IO.Path.Combine (RootDir, pi.HintPath.Replace ('\\', '/'))); + if (File.Exists (fullHintPath)) { + string outPath = System.IO.Path.Combine (outputDir, System.IO.Path.GetFileName (fullHintPath)); + if (!File.Exists (outPath)) + File.Copy (fullHintPath, outPath); + } + } + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/System.Core.dll"; + parameters.CompilerOptions += " /reference:/usr/lib/mono/4.5/mscorlib.dll"; + //parameters.ReferencedAssemblies.Add ("System.Core"); + //parameters.ReferencedAssemblies.Add ("mscorlib.dll"); + + + IEnumerable pfs = flattenNodes.OfType (); + + foreach (ProjectFile pi in pfs.Where (p => p.Type == ItemType.EmbeddedResource)) { + + string absPath = pi.AbsolutePath; + string logicName = pi.LogicalName; + if (string.IsNullOrEmpty (logicName)) + parameters.CompilerOptions += string.Format (" /resource:{0},{1}", absPath, this.Name + "." + pi.Path.Replace ('/', '.')); + else + parameters.CompilerOptions += string.Format (" /resource:{0},{1}", absPath, logicName); + } + foreach (ProjectFile pi in pfs.Where (p => p.Type == ItemType.None)) { + if (pi.CopyToOutputDirectory == CopyToOutputState.Never) + continue; + string source = pi.AbsolutePath; + string target = System.IO.Path.Combine (outputDir, pi.Path); + Directory.CreateDirectory (System.IO.Path.GetDirectoryName (target)); + + if (File.Exists (target)) { + if (pi.CopyToOutputDirectory == CopyToOutputState.PreserveNewest) { + if (DateTime.Compare ( + System.IO.File.GetLastWriteTime (source), + System.IO.File.GetLastWriteTime (target)) < 0) + continue; + } + File.Delete (target); + } + System.Diagnostics.Debug.WriteLine ("copy " + source + " to " + target); + File.Copy (source, target); + } + string[] files = pfs.Where (p => p.Type == ItemType.Compile).Select (p => p.AbsolutePath).ToArray (); + + System.Diagnostics.Debug.WriteLine ("---- start compilation of :" + parameters.OutputAssembly); + System.Diagnostics.Debug.WriteLine (parameters.CompilerOptions); + + CompilationResults = cp.CompileAssemblyFromFile (parameters, files); + + solution.UpdateErrorList (); + + return parameters.OutputAssembly; + } + + public bool TryGetProjectFileFromAbsolutePath (string absolutePath, out ProjectFile pi) { + pi = flattenNodes.OfType ().FirstOrDefault + (pp => pp.AbsolutePath == absolutePath); + return pi != null; + } + public bool TryGetProjectFileFromPath (string path, out ProjectFile pi) { + if (path.StartsWith ("#", StringComparison.Ordinal)) + pi = flattenNodes.OfType ().FirstOrDefault + (pp => pp.Type == ItemType.EmbeddedResource && pp.ResourceID == path.Substring (1)); + else + pi = flattenNodes.OfType ().FirstOrDefault (pp => pp.Path == path); + + if (pi != null) + return true; + + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + if (p.TryGetProjectFileFromPath (path, out pi)) + return true; + } + //TODO: search referenced assemblies + return false; + } + + public void GetDefaultTemplates () { + IEnumerable tmpFiles = + flattenNodes.OfType ().Where (pp => pp.Extension == ".template"); + + foreach (ProjectFile pi in tmpFiles.Where ( + pp => pp.Type == ItemType.None && pp.CopyToOutputDirectory != CopyToOutputState.Never)) { + + string clsName = System.IO.Path.GetFileNameWithoutExtension (pi.Path); + if (solution.DefaultTemplates.ContainsKey (clsName)) + continue; + solution.DefaultTemplates[clsName] = pi.AbsolutePath; + } + foreach (ProjectFile pi in tmpFiles.Where (pp => pp.Type == ItemType.EmbeddedResource)) { + string resId = pi.ResourceID; + string clsName = resId.Substring (0, resId.Length - 9); + if (solution.DefaultTemplates.ContainsKey (clsName)) + continue; + solution.DefaultTemplates[clsName] = pi.Path; + } + + foreach (Project p in ReferencedProjects) + p.GetDefaultTemplates (); + } + // void searchTemplatesIn(Assembly assembly){ + // if (assembly == null) + // return; + // foreach (string resId in assembly + // .GetManifestResourceNames () + // .Where (r => r.EndsWith (".template", StringComparison.OrdinalIgnoreCase))) { + // string clsName = resId.Substring (0, resId.Length - 9); + // if (DefaultTemplates.ContainsKey (clsName)) + // continue; + // DefaultTemplates[clsName] = "#" + resId; + // } + // } + + public List ReferencedProjects { + get { + List tmp = new List (); + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p != null) + tmp.Add (p); + } + return tmp; + } + } + + public void GetStyling () { + try { + foreach (ProjectFile pi in flattenNodes.OfType ().Where (pp => pp.Type == ItemType.EmbeddedResource && pp.Extension == ".style")) { + using (Stream s = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (pi.Source))) { + new StyleReader (solution.Styling, s, pi.ResourceID); + } + } + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + foreach (ProjectReference pr in flattenNodes.OfType ()) { + Project p = solution.Projects.FirstOrDefault (pp => pp.ProjectGuid == pr.ProjectGUID); + if (p == null) + throw new Exception ("referenced project not found"); + p.GetStyling (); + } + + //TODO:get styling from referenced assemblies + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/CSProjectFile.cs b/Samples/CrowIDE/src/ProjectTree/CSProjectFile.cs new file mode 100644 index 00000000..586e2261 --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/CSProjectFile.cs @@ -0,0 +1,72 @@ +// +// ProjectNodes.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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Crow.Coding +{ + public class CSProjectFile : ProjectFile + { + CSharpSyntaxTree tree; + + + #region CTOR + public CSProjectFile (ProjectItem pi) : base (pi){ + } + #endregion + + public override void UpdateSource(object sender, string newSrc) + { + base.UpdateSource(sender, newSrc); + + tree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText (Source, CSharpParseOptions.Default); + } + + public override void Open () { + base.Open (); + + tree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText (Source, CSharpParseOptions.Default); + + CompilationUnitSyntax root = (CompilationUnitSyntax)tree.GetRoot (); + MemberDeclarationSyntax firstMember = root.Members [0]; + + Console.WriteLine ( firstMember.GetType().FullName); + + SyntaxToken tok = root.GetFirstToken(); + + while (tok.Value != null) { + Console.Write (tok.Text); + tok = tok.GetNextToken (true,true); + } + Console.Out.Flush (); + } + + + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/ImlProjectItem.cs b/Samples/CrowIDE/src/ProjectTree/ImlProjectItem.cs new file mode 100644 index 00000000..8487f838 --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/ImlProjectItem.cs @@ -0,0 +1,89 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class ImlProjectItem : ProjectFile + { + #region CTOR + public ImlProjectItem (ProjectItem pi) : base (pi){ + } + #endregion + + Widget instance; + Measure designWidth, designHeight; + + /// + /// instance created with an instantiator from the source by a DesignInterface, + /// for now, the one in ImlVisualEditor + /// + public Widget Instance { + get { return instance; } + set { + if (instance == value) + return; + instance = value; + NotifyValueChanged ("Instance", instance); + } + } + + public Measure DesignWidth { + get { return designWidth; } + set { + if (designWidth == value) + return; + designWidth = value; + NotifyValueChanged ("DesignWidth", designWidth); + } + } + public Measure DesignHeight { + get { return designHeight; } + set { + if (designHeight == value) + return; + designHeight = value; + NotifyValueChanged ("DesignHeight", designHeight); + } + } + + + public List GraphicTree { + get { return new List (new Widget[] {instance}); } + } + + void GTView_SelectedItemChanged (object sender, SelectionChangeEventArgs e){ + SelectedItem = e.NewValue; + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/ProjectFile.cs b/Samples/CrowIDE/src/ProjectTree/ProjectFile.cs new file mode 100644 index 00000000..294a28f5 --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/ProjectFile.cs @@ -0,0 +1,323 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Xml; + +namespace Crow.Coding { + public class ProjectFile : ProjectItem { + bool isOpened = false; + DateTime accessTime; + string source; + string origSource; + object selectedItem; + int curLine, curColumn; + + internal ReaderWriterLockSlim srcEditMtx = new ReaderWriterLockSlim(); + + public Dictionary RegisteredEditors = new Dictionary(); + List undoStack = new List(); + List redoStack = new List(); + + public Crow.Command cmdSave, cmdSaveAs, cmdOpen, cmdClose, cmdUndo, cmdRedo; + + void initCommands (){ + cmdSave = new Crow.Command (new Action (() => Save ())) + { Caption = "Save", Icon = new SvgPicture ("#CrowIDE.icons.save.svg"), CanExecute = false }; + cmdSaveAs = new Crow.Command (new Action (() => SaveAs ())) + { Caption = "Save As ..", Icon = new SvgPicture ("#CrowIDE.icons.save.svg"), CanExecute = false }; + cmdOpen = new Crow.Command (new Action (() => Open ())) + { Caption = "Open", Icon = new SvgPicture ("#CrowIDE.icons.open.svg"), CanExecute = true }; + cmdClose = new Crow.Command (new Action (() => OnQueryClose (this,null))) + { Caption = "Close", Icon = new SvgPicture ("#CrowIDE.icons.open.svg"), CanExecute = false }; + cmdUndo = new Crow.Command (new Action (() => Undo (null))) + { Caption = "Undo", Icon = new SvgPicture ("#CrowIDE.icons.undo.svg"), CanExecute = false }; + cmdRedo = new Crow.Command (new Action (() => Redo (null))) + { Caption = "Redo", Icon = new SvgPicture ("#CrowIDE.icons.redo.svg"), CanExecute = false }; + + Commands.Insert (0, cmdOpen); + Commands.Insert (1, cmdSave); + Commands.Insert (2, cmdSaveAs); + Commands.Insert (3, cmdUndo); + Commands.Insert (4, cmdRedo); + Commands.Add (cmdClose); + } + public ProjectFile () { + initCommands(); + } + public ProjectFile (ProjectItem pi) + : base (pi.Project, pi.node) { + initCommands (); + } + + public string ResourceID { + get { + return Type != ItemType.EmbeddedResource ? null : + node.SelectSingleNode ("LogicalName") == null ? + Project.Name + "." + Path.Replace ('/', '.') : + LogicalName; + } + } + public string LogicalName { + get { + return node.SelectSingleNode ("LogicalName")?.InnerText; + } + } + public bool IsOpened { + get { return isOpened; } + set { + if (isOpened == value) + return; + isOpened = value; + + cmdOpen.CanExecute = !isOpened; + cmdClose.CanExecute = isOpened; + cmdSave.CanExecute = isOpened && IsDirty; + + if (isOpened) + Project.solution.OpenItem (this); + else + Project.solution.CloseItem (this); + + NotifyValueChanged ("IsOpened", isOpened); + } + } + + public void UnregisterEditor (object editor){ + lock(RegisteredEditors){ + RegisteredEditors.Remove (editor); + } + } + public void RegisterEditor (object editor) { + lock(RegisteredEditors){ + RegisteredEditors.Add (editor, false); + } + } + public virtual void UpdateSource (object sender, string newSrc){ + System.Diagnostics.Debug.WriteLine ("update source by {0}", sender); + Source = newSrc; + signalOtherRegisteredEditors (sender); + } + public void SignalEditorOfType (){ + lock (RegisteredEditors) { + object[] keys = RegisteredEditors.Keys.ToArray (); + foreach (object ed in keys) { + T editor = (T)ed; + if (editor == null) + continue; + RegisteredEditors [editor] = false; + break; + } + } + } + protected void signalOtherRegisteredEditors (object sender) { + lock (RegisteredEditors) { + object[] keys = RegisteredEditors.Keys.ToArray (); + foreach (object editor in keys) { + if (editor != sender) + RegisteredEditors [editor] = false; + } + } + } + public string Source { + get { + if (!IsOpened) { + using (StreamReader sr = new StreamReader (AbsolutePath)) + source = sr.ReadToEnd (); + + } else { + if (DateTime.Compare ( + accessTime, + System.IO.File.GetLastWriteTime (AbsolutePath)) < 0) + Console.WriteLine ("File has been modified outside CrowIDE"); + } + return source; + } + set { + if (source == value) + return; + + srcEditMtx.EnterWriteLock (); + + undoStack.Add (source); + cmdUndo.CanExecute = true; + redoStack.Clear (); + cmdRedo.CanExecute = false; + source = value; + + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + + cmdSave.CanExecute = cmdSaveAs.CanExecute = IsDirty; + + srcEditMtx.ExitWriteLock (); + } + } + public bool IsDirty { + get { return source != origSource; } + } + public int CurrentColumn{ + get { return curColumn; } + set { + if (curColumn == value) + return; + curColumn = value; + NotifyValueChanged ("CurrentColumn", curColumn); + } + } + public int CurrentLine{ + get { return curLine; } + set { + if (curLine == value) + return; + curLine = value; + NotifyValueChanged ("CurrentLine", curLine); + } + } + + public object SelectedItem { + get { return selectedItem; } + set { + if (selectedItem == value) + return; + selectedItem= value; + Project.solution.SelectedItemElement = value; + NotifyValueChanged ("SelectedItem", selectedItem); + } + } + + public CopyToOutputState CopyToOutputDirectory { + get { + XmlNode xn = node.SelectSingleNode ("CopyToOutputDirectory"); + return xn == null ? CopyToOutputState.Never : + (CopyToOutputState)Enum.Parse (typeof(CopyToOutputState), xn.InnerText, true); + } + } + + public virtual void Open () { + accessTime = System.IO.File.GetLastWriteTime (AbsolutePath); + using (StreamReader sr = new StreamReader (AbsolutePath)) { + source = sr.ReadToEnd (); + } + origSource = source; + IsOpened = true; + NotifyValueChanged ("IsDirty", false); + } + public virtual void Save () { + if (!IsDirty) + return; + using (StreamWriter sw = new StreamWriter (AbsolutePath)) { + sw.Write (source); + } + origSource = source; + NotifyValueChanged ("IsDirty", false); + } + public virtual void SaveAs () { + if (!IsDirty) + return; + using (StreamWriter sw = new StreamWriter (AbsolutePath)) { + sw.Write (source); + } + origSource = source; + NotifyValueChanged ("IsDirty", false); + } + public void Close () { + origSource = source = null; + IsOpened = false; + } + public void Undo(object sender){ + undo(); + signalOtherRegisteredEditors (sender); + } + public void Redo(object sender){ + redo(); + signalOtherRegisteredEditors (sender); + } + + void undo () { + if (undoStack.Count == 0) + return; + + srcEditMtx.EnterWriteLock (); + string step = undoStack [undoStack.Count -1]; + redoStack.Add (source); + cmdRedo.CanExecute = true; + undoStack.RemoveAt(undoStack.Count -1); + + source = step; + + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + cmdSave.CanExecute = IsDirty; + + if (undoStack.Count == 0) + cmdUndo.CanExecute = false; + srcEditMtx.ExitWriteLock (); + } + + void redo () { + if (redoStack.Count == 0) + return; + srcEditMtx.EnterWriteLock (); + string step = redoStack [redoStack.Count -1]; + undoStack.Add (source); + cmdUndo.CanExecute = true; + redoStack.RemoveAt(redoStack.Count -1); + source = step; + NotifyValueChanged ("Source", source); + NotifyValueChanged ("IsDirty", IsDirty); + cmdSave.CanExecute = IsDirty; + + if (redoStack.Count == 0) + cmdRedo.CanExecute = false; + srcEditMtx.ExitWriteLock (); + + } + + public void onDoubleClick (object sender, MouseButtonEventArgs e){ + if (IsOpened) + return; + Open (); + } + + public void onClick (object sender, MouseButtonEventArgs e){ + IsSelected = true; + } + public void OnQueryClose (object sender, EventArgs e){ + if (IsDirty) { + MessageBox mb = MessageBox.ShowModal (CrowIDE.MainIFace, + MessageBox.Type.YesNoCancel, $"{DisplayName} has unsaved changes.\nSave it now?"); + mb.Yes += (object _sender, EventArgs _e) => { Save (); Close (); }; + mb.No += (object _sender, EventArgs _e) => Close(); + } else + Close (); + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/ProjectItem.cs b/Samples/CrowIDE/src/ProjectTree/ProjectItem.cs new file mode 100644 index 00000000..afa3e3ed --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/ProjectItem.cs @@ -0,0 +1,116 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class ProjectItem : ProjectNode { + #region CTOR + public ProjectItem() {} + public ProjectItem (Project project, XmlNode _node) : base (project){ + node = _node; + } + #endregion + + public XmlNode node; + + public override Picture Icon { + get { + switch (Extension) + { + case ".cs": + return new SvgPicture("#CrowIDE.icons.cs-file.svg"); + case ".crow": + return new SvgPicture("#CrowIDE.icons.xml-file.svg"); + case ".xml": + return new SvgPicture("#CrowIDE.icons.xml-file.svg"); + default: + return base.Icon; + } + } + } + + public string Extension { + get { return System.IO.Path.GetExtension (Path); } + } + public string Path { + get { + return node.Attributes["Include"]?.Value.Replace('\\','/'); + } + } + public string AbsolutePath { + get { + return System.IO.Path.Combine (Project.RootDir, Path); + } + } + public override ItemType Type { + get { + return (ItemType)Enum.Parse (typeof(ItemType), node.Name, true); + } + } + public override string DisplayName { + get { + return Type == ItemType.Reference ? + Path : + Path.Split ('/').LastOrDefault(); + } + } + public string HintPath { + get { return node.SelectSingleNode ("HintPath")?.InnerText; } + } + + public override bool IsSelected { + get { + return isSelected; + } + set { + if (value == isSelected) + return; + + isSelected = value; + + NotifyValueChanged ("IsSelected", isSelected); + + if (isSelected) { + Project.solution.SelectedItem = this; + Project.IsExpanded = true; + ProjectNode pn = Parent; + while (pn != null) { + pn.IsExpanded = true; + pn = pn.Parent; + } + } + } + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/ProjectNodes.cs b/Samples/CrowIDE/src/ProjectTree/ProjectNodes.cs new file mode 100644 index 00000000..bafb9cbd --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/ProjectNodes.cs @@ -0,0 +1,159 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public enum ItemType { + ReferenceGroup, + Reference, + ProjectReference, + VirtualGroup, + Folder, + None, + Compile, + EmbeddedResource, + } + public enum CopyToOutputState { + Never, + Always, + PreserveNewest + } + public class ProjectNode : IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + #region CTOR + public ProjectNode (Project project, ItemType _type, string _name) : this(project){ + type = _type; + name = _name; + initCommands (); + } + public ProjectNode (Project project){ + Project = project; + initCommands (); + } + public ProjectNode (){ + initCommands (); + } + #endregion + + void initCommands () { + Commands = new List (); + } + + ProjectNode parent; + bool isExpanded; + protected bool isSelected; + ItemType type; + string name; + List childNodes = new List(); + + public Project Project; + public List Commands;//list of command available for that node + + public virtual Crow.Picture Icon { + get { + switch (Type) { + case ItemType.Reference: + return new SvgPicture ("#Crow.Icons.assembly.svg"); + case ItemType.ProjectReference: + return new SvgPicture("#Crow.Icons.projectRef.svg"); + default: + return new SvgPicture("#CrowIDE.icons.blank-file.svg"); + } + } + } + public ProjectNode Parent { + get { return parent; } + set { parent = value; } + } + public virtual ItemType Type { + get { return type; } + } + public virtual string DisplayName { + get { return name; } + } + public List ChildNodes { + get { return childNodes; } + } + public void AddChild (ProjectNode pn) { + childNodes.Add(pn); + pn.Parent = this; + } + public void RemoveChild (ProjectNode pn){ + pn.Parent = null; + childNodes.Remove (pn); + } + public void SortChilds () { + foreach (ProjectNode pn in childNodes) + pn.SortChilds (); + childNodes = childNodes.OrderBy(c=>c.Type).ThenBy(cn=>cn.DisplayName).ToList(); + } + + public bool IsExpanded + { + get { return isExpanded; } + set + { + if (value == isExpanded) + return; + isExpanded = value; + NotifyValueChanged ("IsExpanded", isExpanded); + } + } + public virtual bool IsSelected + { + get { return isSelected; } + set + { + if (value == isSelected) + return; + + isSelected = value; + + NotifyValueChanged ("IsSelected", isSelected); + } + } + public override string ToString () + { + return DisplayName; + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/ProjectReference.cs b/Samples/CrowIDE/src/ProjectTree/ProjectReference.cs new file mode 100644 index 00000000..84870746 --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/ProjectReference.cs @@ -0,0 +1,51 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class ProjectReference : ProjectItem { + public ProjectReference (ProjectItem pi) : base (pi.Project, pi.node){ + } + public string ProjectGUID { + get { + return node.SelectSingleNode ("Project")?.InnerText; + } + } + public override string DisplayName { + get { + return node.SelectSingleNode ("Name").InnerText; + } + } + } +} + diff --git a/Samples/CrowIDE/src/ProjectTree/StyleProjectItem.cs b/Samples/CrowIDE/src/ProjectTree/StyleProjectItem.cs new file mode 100644 index 00000000..1de77cd7 --- /dev/null +++ b/Samples/CrowIDE/src/ProjectTree/StyleProjectItem.cs @@ -0,0 +1,50 @@ +// +// ProjectNodes.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.Collections.Generic; +using System.Linq; +using System.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class StyleProjectItem : ProjectFile + { + #region CTOR + public StyleProjectItem (ProjectItem pi) : base (pi){ + } + #endregion + + public override void UpdateSource (object sender, string newSrc) + { + base.UpdateSource (sender, newSrc); + Project.solution.ReloadStyling (); + } + } +} + diff --git a/Samples/CrowIDE/src/Solution.cs b/Samples/CrowIDE/src/Solution.cs new file mode 100644 index 00000000..c6b1fbc1 --- /dev/null +++ b/Samples/CrowIDE/src/Solution.cs @@ -0,0 +1,541 @@ +// +// Solution.cs +// +//code taken in project https://sourceforge.net/projects/syncproj/ +// no licence info was included, I took the liberty to modify it. +// Author: +// tarmopikaro +// 2018 Jean-Philippe Bruyère +//MIT-licenced + +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml.Serialization; +using Crow; + +namespace Crow.Coding{ + public class SolutionProject { + public string ProjectHostGuid; + public string ProjectName; + public string RelativePath; + public string ProjectGuid; + } + public class StyleItemContainer { + public object Value; + public string Name; + public StyleItemContainer(string name, object _value){ + Name = name; + Value = _value; + } + } + public class StyleContainer : IValueChange { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + Style style; + bool isExpanded; + + public string Name; + public List Items; + public bool IsExpanded + { + get { return isExpanded; } + set + { + if (value == isExpanded) + return; + isExpanded = value; + NotifyValueChanged ("IsExpanded", isExpanded); + } + } + public StyleContainer(string name, Style _style){ + Name = name; + style = _style; + + Items = new List (); + foreach (string k in style.Keys) { + Items.Add(new StyleItemContainer(k, style[k])); + } + } + } + + + /// +/// .sln loaded into class. +/// + public class Solution: IValueChange + { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + ProjectItem selectedItem = null; + object selectedItemElement = null; + ObservableList openedItems = new ObservableList(); + ObservableList toolboxItems; + + public Dictionary Styling; + public Dictionary DefaultTemplates; + + public List