diff options
Diffstat (limited to 'Samples')
19 files changed, 529 insertions, 632 deletions
diff --git a/Samples/BasicTests/BasicTests.cs b/Samples/BasicTests/BasicTests.cs index 954d4879..13bb41fe 100644 --- a/Samples/BasicTests/BasicTests.cs +++ b/Samples/BasicTests/BasicTests.cs @@ -5,7 +5,7 @@ using System.Linq; using Crow; using Glfw; -namespace tests +namespace Samples { public class BasicTests : SampleBase { diff --git a/Samples/BindingTest/Program.cs b/Samples/BindingTest/Program.cs index 469e3473..019e3ce6 100644 --- a/Samples/BindingTest/Program.cs +++ b/Samples/BindingTest/Program.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using Crow; +using Samples; namespace BindingTest { diff --git a/Samples/DebugLogAnalyzer/src/DebugInterface.cs b/Samples/DebugLogAnalyzer/src/DebugInterface.cs index 26a1eddf..1653f163 100644 --- a/Samples/DebugLogAnalyzer/src/DebugInterface.cs +++ b/Samples/DebugLogAnalyzer/src/DebugInterface.cs @@ -5,6 +5,7 @@ using System; using Crow.Cairo; using System.Threading; +using Samples; namespace Crow { diff --git a/Samples/DebugLogAnalyzer/src/Program.cs b/Samples/DebugLogAnalyzer/src/Program.cs index 9c2e7117..8cee874a 100644 --- a/Samples/DebugLogAnalyzer/src/Program.cs +++ b/Samples/DebugLogAnalyzer/src/Program.cs @@ -12,12 +12,13 @@ using System.Collections.Generic; using Encoding = System.Text.Encoding; using Crow.DebugLogger; using System.Linq; +using Samples; namespace DebugLogAnalyzer { - public class Program : SampleBase + public class Program : SampleBaseForEditor { - public static Program CurrentProgramInstance; + static void Main (string [] args) { DbgLogger.IncludeEvents = DbgEvtType.None; @@ -29,13 +30,8 @@ namespace DebugLogAnalyzer } } protected override void OnInitialized () { - initCommands (); - base.OnInitialized (); - if (string.IsNullOrEmpty (CurrentDir)) - CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces"); - Load ("#Dbg.main.crow").DataSource = this; //crowContainer = FindByName ("CrowContainer") as Container; editor = FindByName ("tb") as TextBox; @@ -92,25 +88,11 @@ namespace DebugLogAnalyzer NotifyValueChanged (searchWidget); } } - - - - public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane, - CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions, - CMDGotoParentEvent, CMDEventHistoryForward, CMDEventHistoryBackward; + public Command CMDGotoParentEvent, CMDEventHistoryForward, CMDEventHistoryBackward; public CommandGroup EventCommands, DirectoryCommands; - public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs); - void initCommands () + protected override void initCommands () { - CMDNew = new Command ("New", new Action (onNewFile), "#Icons.blank-file.svg"); - CMDSave = new Command ("Save", new Action (onSave), "#Icons.save.svg", false); - CMDSaveAs = new Command ("Save As...", new Action (onSaveAs), "#Icons.save.svg"); - CMDQuit = new Command ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg"); - CMDUndo = new Command ("Undo", new Action (undo),"#Icons.undo.svg", false); - CMDRedo = new Command ("Redo", new Action (redo),"#Icons.redo.svg", false); - CMDCut = new Command ("Cut", new Action (() => cut ()), "#Icons.scissors.svg", false); - CMDCopy = new Command ("Copy", new Action (() => copy ()), "#Icons.copy-file.svg", false); - CMDPaste= new Command ("Paste", new Action (() => paste ()), "#Icons.paste-on-document.svg", false); + base.initCommands (); CMDGotoParentEvent = new Command("parent", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }, null, false); CMDEventHistoryBackward = new Command("back.", currentEventHistoryGoBack, null, false); @@ -212,29 +194,7 @@ namespace DebugLogAnalyzer } } public List<DbgWidgetEvent> CurWidgetRootEvents => curWidget == null? new List<DbgWidgetEvent>() : curWidget.RootEvents; - public DbgEvtType RecordedEvents { - get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents)); - set { - if (RecordedEvents == value) - return; - Configuration.Global.Set (nameof (RecordedEvents), value); - if (DebugLogRecording) - DbgLogger.IncludeEvents = RecordedEvents; - NotifyValueChanged(RecordedEvents); - } - } - public DbgEvtType DiscardedEvents { - get => Configuration.Global.Get<DbgEvtType> (nameof (DiscardedEvents)); - set { - if (DiscardedEvents == value) - return; - Configuration.Global.Set (nameof (DiscardedEvents), value); - if (DebugLogRecording) - DbgLogger.DiscardEvents = DiscardedEvents; - NotifyValueChanged(DiscardedEvents); - } - } - public bool DebugLoggingEnabled => DbgLogger.IsEnabled; + public bool DebugLogToFile { get => Configuration.Global.Get<bool> (nameof(DebugLogToFile)); set { @@ -253,15 +213,6 @@ namespace DebugLogAnalyzer NotifyValueChanged (DebugLogFilePath); } }*/ - public bool DebugLogRecording { - get => debugLogRecording; - set { - if (debugLogRecording == value) - return; - debugLogRecording = value; - NotifyValueChanged(debugLogRecording); - } - } public bool DebugLogOnStartup { get => Configuration.Global.Get<bool> (nameof(DebugLogOnStartup)); set { @@ -273,45 +224,8 @@ namespace DebugLogAnalyzer } - const string _defaultFileName = "unnamed.txt"; - string source = "", origSource; - TextBox editor; - Stack<TextChange> undoStack = new Stack<TextChange> (); - Stack<TextChange> redoStack = new Stack<TextChange> (); - TextSpan selection; Exception currentException; - public string CurrentDir { - get => Configuration.Global.Get<string> (nameof (CurrentDir)); - set { - if (CurrentDir == value) - return; - Configuration.Global.Set (nameof (CurrentDir), value); - NotifyValueChanged (CurrentDir); - } - } - public string CurrentFile { - get => Configuration.Global.Get<string> (nameof (CurrentFile)); - set { - if (CurrentFile == value) - return; - Configuration.Global.Set (nameof (CurrentFile), value); - NotifyValueChanged (CurrentFile); - } - } - public new bool IsDirty => source != origSource; - public string Source { - get => source; - set { - if (source == value) - return; - source = value; - CMDSave.CanExecute = IsDirty; - NotifyValueChanged (source); - NotifyValueChanged ("IsDirty", IsDirty); - } - } - string SelectedText => - selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString (); + public Exception CurrentException { get => currentException; set { @@ -326,195 +240,6 @@ namespace DebugLogAnalyzer public bool ShowError => currentException != null; public string CurrentExceptionMSG => currentException == null ? "" : currentException.Message; - - - void undo () { - if (undoStack.TryPop (out TextChange tch)) { - redoStack.Push (tch.Inverse (source)); - CMDRedo.CanExecute = true; - apply (tch); - editor.SetCursorPosition (tch.End + tch.ChangedText.Length); - } - if (undoStack.Count == 0) - CMDUndo.CanExecute = false; - } - void redo () { - if (redoStack.TryPop (out TextChange tch)) { - undoStack.Push (tch.Inverse (source)); - CMDUndo.CanExecute = true; - apply (tch); - editor.SetCursorPosition (tch.End + tch.ChangedText.Length); - } - if (redoStack.Count == 0) - CMDRedo.CanExecute = false; - } - void cut () { - copy (); - applyChange (new TextChange (selection.Start, selection.Length, "")); - } - void copy () { - Clipboard = SelectedText; - } - void paste () { - applyChange (new TextChange (selection.Start, selection.Length, Clipboard)); - } - bool disableTextChangedEvent = false; - void apply (TextChange change) { - Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)]; - ReadOnlySpan<char> src = source.AsSpan (); - src.Slice (0, change.Start).CopyTo (tmp); - if (!string.IsNullOrEmpty (change.ChangedText)) - change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start)); - src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length)); - disableTextChangedEvent = true; - Source = tmp.ToString (); - disableTextChangedEvent = false; - } - void applyChange (TextChange change) { - undoStack.Push (change.Inverse (source)); - redoStack.Clear (); - CMDUndo.CanExecute = true; - CMDRedo.CanExecute = false; - apply (change); - } - - void resetUndoRedo () { - undoStack.Clear (); - redoStack.Clear (); - CMDUndo.CanExecute = false; - CMDRedo.CanExecute = false; - } - - void onNewFile () { - if (IsDirty) { - MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?").Yes += (sender, e) => newFile (); - } else - newFile (); - } - void onSave () - { - if (!File.Exists (CurrentFile)) { - onSaveAs (); - return; - } - save (); - } - void onSaveAs () - { - string dir = Path.GetDirectoryName (CurrentFile); - if (string.IsNullOrEmpty (dir)) - dir = Directory.GetCurrentDirectory (); - LoadIMLFragment (@"<FileDialog Width='60%' Height='50%' Caption='Save as ...' CurrentDirectory='" + - dir + "' SelectedFile='" + - Path.GetFileName(CurrentFile) + "' OkClicked='saveFileDialog_OkClicked'/>").DataSource = this; - } - void saveFileDialog_OkClicked (object sender, EventArgs e) - { - FileDialog fd = sender as FileDialog; - - if (string.IsNullOrEmpty (fd.SelectedFileFullPath)) - return; - - if (File.Exists(fd.SelectedFileFullPath)) { - MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "File exists, overwrite?"); - mb.Yes += (sender2, e2) => { - CurrentFile = fd.SelectedFileFullPath; - save (); - }; - return; - } - - CurrentFile = fd.SelectedFileFullPath; - save (); - } - - void newFile() - { - disableTextChangedEvent = true; - Source = @"<Label Text='Hello World' Background='MediumSeaGreen' Margin='10'/>"; - disableTextChangedEvent = false; - resetUndoRedo (); - if (!string.IsNullOrEmpty (CurrentFile)) - CurrentFile = Path.Combine (Path.GetDirectoryName (CurrentFile), "newfile.crow"); - else - CurrentFile = Path.Combine (CurrentDir, "newfile.crow"); - } - - void save () { - using (Stream s = new FileStream(CurrentFile, FileMode.Create)) { - s.WriteByte (0xEF); - s.WriteByte (0xBB); - s.WriteByte (0xBF); - byte [] buff = Encoding.UTF8.GetBytes (source); - s.Write (buff, 0, buff.Length); - } - origSource = source; - NotifyValueChanged ("IsDirty", IsDirty); - CMDSave.CanExecute = false; - } - - void reloadFromFile () { - disableTextChangedEvent = true; - if (File.Exists (CurrentFile)) { - using (Stream s = new FileStream (CurrentFile, FileMode.Open)) { - using (StreamReader sr = new StreamReader (s)) - Source = origSource = sr.ReadToEnd (); - } - } - disableTextChangedEvent = false; - resetUndoRedo (); - } - - public void goUpDirClick (object sender, MouseButtonEventArgs e) - { - string root = Directory.GetDirectoryRoot (CurrentDir); - if (CurrentDir == root) - return; - CurrentDir = Directory.GetParent (CurrentDir).FullName; - } - - void Dv_SelectedItemChanged (object sender, SelectionChangeEventArgs e) - { - FileSystemInfo fi = e.NewValue as FileSystemInfo; - if (fi == null) - return; - if (fi is DirectoryInfo) - return; - - if (IsDirty) { - MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?"); - mb.Yes += (mbsender, mbe) => { CurrentFile = fi.FullName; reloadFromFile (); }; - return; - } - - CurrentFile = fi.FullName; - reloadFromFile (); - } - void onTextChanged (object sender, TextChangeEventArgs e) { - if (disableTextChangedEvent) - return; - applyChange (e.Change); - } - - void onSelectedTextChanged (object sender, EventArgs e) { - selection = (sender as Label).Selection; - Console.WriteLine($"selection:{selection.Start} length:{selection.Length}"); - CMDCut.CanExecute = CMDCopy.CanExecute = !selection.IsEmpty; - } - void textView_KeyDown (object sender, Crow.KeyEventArgs e) { - if (Ctrl) { - if (e.Key == Glfw.Key.W) { - if (Shift) - CMDRedo.Execute (); - else - CMDUndo.Execute (); - } else if (e.Key == Glfw.Key.S) { - onSave (); - } - } - } - - public override bool OnKeyDown (Key key) { diff --git a/Samples/ShowCase/ShowCase.cs b/Samples/ShowCase/ShowCase.cs index ed5d8575..95d15a85 100644 --- a/Samples/ShowCase/ShowCase.cs +++ b/Samples/ShowCase/ShowCase.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2019 Bruyère Jean-Philippe <jp_bruyere@hotmail.com> +// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com> // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) @@ -13,10 +13,11 @@ using System.Diagnostics; using Crow.Text; using System.Collections.Generic; using Encoding = System.Text.Encoding; +using Samples; namespace ShowCase { - class Showcase : SampleBase + class Showcase : SampleBaseForEditor { static void Main () { @@ -28,42 +29,17 @@ namespace ShowCase using (Showcase app = new Showcase ()) { //app.Theme = @"C:\Users\Jean-Philippe\source\Crow\Themes\TestTheme"; + CurrentProgramInstance = app; app.Run (); } } - public Container crowContainer; + public Container crowContainer; - public string CurrentDir { - get => Configuration.Global.Get<string> (nameof (CurrentDir)); - set { - if (CurrentDir == value) - return; - Configuration.Global.Set (nameof (CurrentDir), value); - NotifyValueChanged (CurrentDir); - } - } - public string CurrentFile { - get => Configuration.Global.Get<string> (nameof (CurrentFile)); - set { - if (CurrentFile == value) - return; - Configuration.Global.Set (nameof (CurrentFile), value); - NotifyValueChanged (CurrentFile); - } - } - - public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane, - CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions; - - const string _defaultFileName = "unnamed.txt"; - string source = "", origSource; - TextBox editor; Stopwatch reloadChrono = new Stopwatch (); - public new bool IsDirty => source != origSource; - public string Source { + public override string Source { get => source; set { if (source == value) @@ -75,153 +51,8 @@ namespace ShowCase NotifyValueChanged (source); NotifyValueChanged ("IsDirty", IsDirty); } - } - public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs); - - Stack<TextChange> undoStack = new Stack<TextChange> (); - Stack<TextChange> redoStack = new Stack<TextChange> (); - TextSpan selection; - string SelectedText => - selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString (); - - void undo () { - if (undoStack.TryPop (out TextChange tch)) { - redoStack.Push (tch.Inverse (source)); - CMDRedo.CanExecute = true; - apply (tch); - editor.SetCursorPosition (tch.End + tch.ChangedText.Length); - } - if (undoStack.Count == 0) - CMDUndo.CanExecute = false; - } - void redo () { - if (redoStack.TryPop (out TextChange tch)) { - undoStack.Push (tch.Inverse (source)); - CMDUndo.CanExecute = true; - apply (tch); - editor.SetCursorPosition (tch.End + tch.ChangedText.Length); - } - if (redoStack.Count == 0) - CMDRedo.CanExecute = false; - } - void cut () { - copy (); - applyChange (new TextChange (selection.Start, selection.Length, "")); - } - void copy () { - Clipboard = SelectedText; - } - void paste () { - applyChange (new TextChange (selection.Start, selection.Length, Clipboard)); - } - bool disableTextChangedEvent = false; - void apply (TextChange change) { - Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)]; - ReadOnlySpan<char> src = source.AsSpan (); - src.Slice (0, change.Start).CopyTo (tmp); - if (!string.IsNullOrEmpty (change.ChangedText)) - change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start)); - src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length)); - disableTextChangedEvent = true; - Source = tmp.ToString (); - disableTextChangedEvent = false; } - - void initCommands () - { - CMDNew = new Command ("New", new Action (onNewFile), "#Icons.blank-file.svg"); - CMDSave = new Command ("Save", new Action (onSave), "#Icons.save.svg", false); - CMDSaveAs = new Command ("Save As...", new Action (onSaveAs), "#Icons.save.svg"); - CMDQuit = new Command ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg"); - CMDUndo = new Command ("Undo", new Action (undo),"#Icons.undo.svg", false); - CMDRedo = new Command ("Redo", new Action (redo),"#Icons.redo.svg", false); - CMDCut = new Command ("Cut", new Action (() => cut ()), "#Icons.scissors.svg", false); - CMDCopy = new Command ("Copy", new Action (() => copy ()), "#Icons.copy-file.svg", false); - CMDPaste= new Command ("Paste", new Action (() => paste ()), "#Icons.paste-on-document.svg", false); - - } - void onNewFile () { - if (IsDirty) { - MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?"); - mb.Yes += (sender, e) => newFile (); - } else - newFile (); - } - void onSave () - { - if (!File.Exists (CurrentFile)) { - onSaveAs (); - return; - } - save (); - } - void onSaveAs () - { - string dir = Path.GetDirectoryName (CurrentFile); - if (string.IsNullOrEmpty (dir)) - dir = Directory.GetCurrentDirectory (); - LoadIMLFragment (@"<FileDialog Width='60%' Height='50%' Caption='Save as ...' CurrentDirectory='" + - dir + "' SelectedFile='" + - Path.GetFileName(CurrentFile) + "' OkClicked='saveFileDialog_OkClicked'/>").DataSource = this; - } - void saveFileDialog_OkClicked (object sender, EventArgs e) - { - FileDialog fd = sender as FileDialog; - - if (string.IsNullOrEmpty (fd.SelectedFileFullPath)) - return; - - if (File.Exists(fd.SelectedFileFullPath)) { - MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "File exists, overwrite?"); - mb.Yes += (sender2, e2) => { - CurrentFile = fd.SelectedFileFullPath; - save (); - }; - return; - } - - CurrentFile = fd.SelectedFileFullPath; - save (); - } - - void newFile() - { - disableTextChangedEvent = true; - Source = @"<Label Text='Hello World' Background='MediumSeaGreen' Margin='10'/>"; - disableTextChangedEvent = false; - resetUndoRedo (); - if (!string.IsNullOrEmpty (CurrentFile)) - CurrentFile = Path.Combine (Path.GetDirectoryName (CurrentFile), "newfile.crow"); - else - CurrentFile = Path.Combine (CurrentDir, "newfile.crow"); - } - - void save () { - using (Stream s = new FileStream(CurrentFile, FileMode.Create)) { - s.WriteByte (0xEF); - s.WriteByte (0xBB); - s.WriteByte (0xBF); - byte [] buff = Encoding.UTF8.GetBytes (source); - s.Write (buff, 0, buff.Length); - } - origSource = source; - NotifyValueChanged ("IsDirty", IsDirty); - CMDSave.CanExecute = false; - } - - void reloadFromFile () { - hideError (); - disableTextChangedEvent = true; - if (File.Exists (CurrentFile)) { - using (Stream s = new FileStream (CurrentFile, FileMode.Open)) { - using (StreamReader sr = new StreamReader (s)) - Source = origSource = sr.ReadToEnd (); - } - } - disableTextChangedEvent = false; - resetUndoRedo (); - } void reloadFromSource () { hideError (); Widget g = null; @@ -241,12 +72,6 @@ namespace ShowCase } } - void resetUndoRedo () { - undoStack.Clear (); - redoStack.Clear (); - CMDUndo.CanExecute = false; - CMDRedo.CanExecute = false; - } void showError (Exception ex) { NotifyValueChanged ("ErrorMessage", ex); NotifyValueChanged ("ShowError", true); @@ -255,70 +80,12 @@ namespace ShowCase NotifyValueChanged ("ShowError", false); } - public void goUpDirClick (object sender, MouseButtonEventArgs e) - { - string root = Directory.GetDirectoryRoot (CurrentDir); - if (CurrentDir == root) - return; - CurrentDir = Directory.GetParent (CurrentDir).FullName; - } - - void Dv_SelectedItemChanged (object sender, SelectionChangeEventArgs e) - { - FileSystemInfo fi = e.NewValue as FileSystemInfo; - if (fi == null) - return; - if (fi is DirectoryInfo) - return; - if (IsDirty) { - MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?"); - mb.Yes += (mbsender, mbe) => { CurrentFile = fi.FullName; reloadFromFile (); }; - return; - } - CurrentFile = fi.FullName; - reloadFromFile (); - } - void onTextChanged (object sender, TextChangeEventArgs e) { - if (disableTextChangedEvent) - return; - applyChange (e.Change); - } - void applyChange (TextChange change) { - undoStack.Push (change.Inverse (source)); - redoStack.Clear (); - CMDUndo.CanExecute = true; - CMDRedo.CanExecute = false; - apply (change); - } - - void onSelectedTextChanged (object sender, EventArgs e) { - selection = (sender as Label).Selection; - Console.WriteLine($"selection:{selection.Start} length:{selection.Length}"); - CMDCut.CanExecute = CMDCopy.CanExecute = !selection.IsEmpty; - } - void textView_KeyDown (object sender, Crow.KeyEventArgs e) { - if (Ctrl) { - if (e.Key == Glfw.Key.W) { - if (Shift) - CMDRedo.Execute (); - else - CMDUndo.Execute (); - } else if (e.Key == Glfw.Key.S) { - onSave (); - } - } - } protected override void OnInitialized () { - initCommands (); - base.OnInitialized (); - if (string.IsNullOrEmpty (CurrentDir)) - CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces"); - Load ("#ShowCase.showcase.crow").DataSource = this; crowContainer = FindByName ("CrowContainer") as Container; editor = FindByName ("tb") as TextBox; @@ -341,29 +108,7 @@ namespace ShowCase reloadChrono.Reset (); } - public DbgEvtType RecordedEvents { - get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents)); - set { - if (RecordedEvents == value) - return; - Configuration.Global.Set (nameof (RecordedEvents), value); - if (DebugLogRecording) - DbgLogger.IncludeEvents = RecordedEvents; - NotifyValueChanged(RecordedEvents); - } - } - public DbgEvtType DiscardedEvents { - get => Configuration.Global.Get<DbgEvtType> (nameof (DiscardedEvents)); - set { - if (DiscardedEvents == value) - return; - Configuration.Global.Set (nameof (DiscardedEvents), value); - if (DebugLogRecording) - DbgLogger.DiscardEvents = DiscardedEvents; - NotifyValueChanged(DiscardedEvents); - } - } - public bool DebugLoggingEnabled => DbgLogger.IsEnabled; + public bool DebugLogToFile { get => !DbgLogger.ConsoleOutput; set { @@ -383,16 +128,6 @@ namespace ShowCase NotifyValueChanged (DebugLogFilePath); } } - bool debugLogRecording; - public bool DebugLogRecording { - get => debugLogRecording; - set { - if (debugLogRecording == value) - return; - debugLogRecording = value; - NotifyValueChanged(debugLogRecording); - } - } public override bool OnKeyDown (Key key) { diff --git a/Samples/ShowCase/ui/showcase.crow b/Samples/ShowCase/ui/showcase.crow index 529c4772..1236b705 100644 --- a/Samples/ShowCase/ui/showcase.crow +++ b/Samples/ShowCase/ui/showcase.crow @@ -6,7 +6,57 @@ Background="Jet" MouseEnter="{Background=Grey}" MouseLeave="{Background=Jet}" /> <TextBox Text="{²CurrentDir}" Margin="2"/> </HorizontalStack> - <DirectoryView Margin="1" Name="dv" CurrentDirectory="{CurrentDir}" SelectedItemChanged="Dv_SelectedItemChanged"/> + <DirectoryView Margin="1" Name="dv" CurrentDirectory="{CurrentDir}" SelectedItemChanged="Dv_SelectedItemChanged"> + <Template> + <TreeView IsRoot="true" Name="treeView" Data="{./FileSystemEntries}" Background="{./Background}" + SelectedItemChanged="./onSelectedItemChanged"> + <ItemTemplate DataType="System.IO.FileInfo"> + <ListItem CornerRadius="2" Margin="0" Height="Fit" Width="Stretched" + ContextCommands="{GetCommands}" + Selected="{Background=${ControlHighlight}}" + Unselected="{Background=Transparent}"> + <HorizontalStack> + <Image Margin="1" Width="14" Height="14" Path="#Crow.Icons.file.svg"/> + <Label Text="{Name}" Width="Stretched"/> + </HorizontalStack> + </ListItem> + </ItemTemplate> + <ItemTemplate DataType="System.IO.DirectoryInfo" Data="GetFileSystemInfosOrdered"> + <ListItem ContextCommands="{GetCommands}" + Selected="{/exp.Background=${ControlHighlight}}" + Unselected="{/exp.Background=Transparent}"> + <Expandable Name="exp" Caption="{Name}" MouseDoubleClick="/onClickForExpand"> + <Template> + <VerticalStack> + <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand" + Foreground="Transparent" + MouseEnter="{Foreground=DimGrey}" + MouseLeave="{Foreground=Transparent}"> + <HorizontalStack Background="{./Background}" Spacing="1"> + <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand" + Path="{./Image}" + Visible="{./IsExpandable}" + SvgSub="{./IsExpanded}" + MouseEnter="{Background=LightGrey}" + MouseLeave="{Background=Transparent}"/> + <Image Margin="1" Width="16" Height="16" + Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/> + <Label Text="{./Caption}"/> + </HorizontalStack> + </Border> + <Container Name="Content" Visible="false"/> + </VerticalStack> + </Template> + <HorizontalStack Height="Fit"> + <Widget Width="12" Height="10"/> + <VerticalStack Height="Fit" Name="ItemsContainer"/> + </HorizontalStack> + </Expandable> + </ListItem> + </ItemTemplate> + </TreeView> + </Template> + </DirectoryView> </VerticalStack> <Splitter Width="6" /> <VerticalStack> @@ -31,9 +81,9 @@ <Button Style="IcoButton" Command="{CMDNew}" /> <Button Style="IcoButton" Command="{CMDSave}" /> <Button Style="IcoButton" Command="{CMDSaveAs}" /> - <!--<Button Style="IcoButton" Command="{CMDUndo}" /> + <Button Style="IcoButton" Command="{CMDUndo}" /> <Button Style="IcoButton" Command="{CMDRedo}" /> - <Button Style="IcoButton" Command="{CMDCut}" /> + <!--<Button Style="IcoButton" Command="{CMDCut}" /> <Button Style="IcoButton" Command="{CMDCopy}" /> <Button Style="IcoButton" Command="{CMDPaste}" />--> <Popper IsVisible="{DebugLoggingEnabled}" Fit="true"> diff --git a/Samples/common/src/Editor.cs b/Samples/common/src/Editor.cs index b9b0ae90..7b9d5c10 100644 --- a/Samples/common/src/Editor.cs +++ b/Samples/common/src/Editor.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using System.Linq; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Collections; namespace Crow { @@ -30,8 +31,8 @@ namespace Crow } ListBox overlay; - List<String> suggestions; - public List<String> Suggestions { + IList suggestions; + public IList Suggestions { get => suggestions; set { suggestions = value; @@ -49,19 +50,25 @@ namespace Crow .Select (s => s.Name).ToArray (); - string [] getAllCrowTypeMembers (string crowTypeName) { + IEnumerable<MemberInfo> getAllCrowTypeMembers (string crowTypeName) { Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName); return crowType.GetMembers (BindingFlags.Public | BindingFlags.Instance). Where (m=>((m is PropertyInfo pi && pi.CanWrite) || (m is EventInfo)) && - m.GetCustomAttribute<XmlIgnoreAttribute>() == null).Select (mb=>mb.Name).ToArray(); + m.GetCustomAttribute<XmlIgnoreAttribute>() == null); } + MemberInfo getCrowTypeMember (string crowTypeName, string memberName) { + Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName); + return crowType.GetMember (memberName, BindingFlags.Public | BindingFlags.Instance).FirstOrDefault (); + } + public override void OnTextChanged(object sender, TextChangeEventArgs e) { base.OnTextChanged(sender, e); //Task.Run(()=>parse()); parse(); - tryGetSuggestions (); + if (HasFocus) + tryGetSuggestions (); //Console.WriteLine ($"{pos}: {suggestionTok.AsString (_text)} {suggestionTok}"); } @@ -80,13 +87,54 @@ namespace Crow Suggestions = allWidgetNames.Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); } else if (currentNode is AttributeSyntax attribNode) { if (currentNode.Parent is ElementTagSyntax eltTag) { - if (currentToken.Type == TokenType.AttributeName && eltTag.NameToken.HasValue) { - Suggestions = getAllCrowTypeMembers (eltTag.NameToken.Value.AsString (_text)) - .Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + if (eltTag.NameToken.HasValue) { + if (currentToken.Type == TokenType.AttributeName) { + Suggestions = getAllCrowTypeMembers (eltTag.NameToken.Value.AsString (_text)) + .Where (s => s.Name.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + } else if (attribNode.NameToken.HasValue) { + if (currentToken.Type == TokenType.AttributeValue) { + MemberInfo mi = getCrowTypeMember ( + eltTag.NameToken.Value.AsString (_text), attribNode.NameToken.Value.AsString (_text)); + if (mi is PropertyInfo pi) { + if (pi.PropertyType.IsEnum) + Suggestions = Enum.GetNames (pi.PropertyType) + .Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + else if (pi.PropertyType == typeof(bool)) + Suggestions = (new string[] {"true", "false"}). + Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + else if (pi.PropertyType == typeof (Measure)) + Suggestions = (new string[] {"Stretched", "Fit"}). + Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + else if (pi.PropertyType == typeof (Fill)) + Suggestions = FastEnumUtility.FastEnum.GetValues<Colors> () + .Where (s => s.ToString().StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + } + } else if (currentToken.Type == TokenType.AttributeValueOpen) { + MemberInfo mi = getCrowTypeMember ( + eltTag.NameToken.Value.AsString (_text), attribNode.NameToken.Value.AsString (_text)); + if (mi is PropertyInfo pi) { + if (pi.PropertyType.IsEnum) + Suggestions = Enum.GetNames (pi.PropertyType).ToList (); + else if (pi.PropertyType == typeof(bool)) + Suggestions = new List<string> (new string[] {"true", "false"}); + else if (pi.PropertyType == typeof (Fill)) + Suggestions = FastEnumUtility.FastEnum.GetValues<Colors> ().ToList (); + else if (pi.PropertyType == typeof (Measure)) + Suggestions = new List<string> (new string[] {"Stretched", "Fit"}); + } + } + } } } - } else if (currentNode is ElementStartTagSyntax eltStartTag) { - Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text)).ToList (); + } else if (currentToken.Type != TokenType.AttributeValueClose && + currentToken.Type != TokenType.EmptyElementClosing && + currentToken.Type != TokenType.ClosingSign && + currentNode is ElementStartTagSyntax eltStartTag) { + if (currentToken.Type == TokenType.AttributeName) + Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text)) + .Where (s => s.Name.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList (); + else + Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text)).ToList (); } else { /*SyntaxNode curNode = source.FindNodeIncludingPosition (pos); Console.WriteLine ($"Current Node: {curNode}"); @@ -101,7 +149,35 @@ namespace Crow lock (IFace.UpdateMutex) { if (overlay == null) { overlay = IFace.LoadIMLFragment<ListBox>(@" - <ListBox Style='suggestionsListBox' Data='{Suggestions}' /> + <ListBox Style='suggestionsListBox' Data='{Suggestions}' > + <ItemTemplate> + <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' + Selected = '{Background=${ControlHighlight}}' + Unselected = '{Background=Transparent}'> + <Label Text='{}' HorizontalAlignment='Left' /> + </ListItem> + </ItemTemplate> + <ItemTemplate DataType='MemberInfo'> + <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' + Selected = '{Background=${ControlHighlight}}' + Unselected = '{Background=Transparent}'> + <HorizontalStack> + <Image Picture='{GetIcon}' Width='16' Height='16'/> + <Label Text='{Name}' HorizontalAlignment='Left' /> + </HorizontalStack> + </ListItem> + </ItemTemplate> + <ItemTemplate DataType='Colors'> + <ListItem Height='Fit' Margin='0' Focusable='false' HorizontalAlignment='Left' + Selected = '{Background=${ControlHighlight}}' + Unselected = '{Background=Transparent}'> + <HorizontalStack> + <Widget Background='{}' Width='20' Height='14'/> + <Label Text='{}' HorizontalAlignment='Left' /> + </HorizontalStack> + </ListItem> + </ItemTemplate> + </ListBox> "); overlay.DataSource = this; overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0; @@ -116,12 +192,25 @@ namespace Crow overlay.IsVisible = false; } void completeToken () { - string selectedSugg = overlay.SelectedItem as string; + string selectedSugg = overlay.SelectedItem is MemberInfo mi ? + mi.Name : overlay.SelectedItem?.ToString (); if (selectedSugg == null) return; - if (currentToken.Type == TokenType.ElementOpen || currentToken.Type == TokenType.WhiteSpace) + if (currentToken.Type == TokenType.ElementOpen || + currentToken.Type == TokenType.WhiteSpace || + currentToken.Type == TokenType.AttributeValueOpen) update (new TextChange (currentToken.End, 0, selectedSugg)); - else + else if (currentToken.Type == TokenType.AttributeName && currentNode is AttributeSyntax attrib) { + if (attrib.ValueToken.HasValue) { + TextChange tc = new TextChange (currentToken.Start, currentToken.Length, selectedSugg); + update (tc); + selectionStart = lines.GetLocation (attrib.ValueToken.Value.Start + tc.CharDiff + 1); + CurrentLoc = lines.GetLocation (attrib.ValueToken.Value.End + tc.CharDiff - 1); + } else { + update (new TextChange (currentToken.Start, currentToken.Length, selectedSugg + "=\"\"")); + MoveLeft (); + } + } else update (new TextChange (currentToken.Start, currentToken.Length, selectedSugg)); hideOverlay (); } @@ -129,6 +218,7 @@ namespace Crow hideOverlay (); base.onMouseDown (sender, e); } + public override void onKeyDown(object sender, KeyEventArgs e) { if (suggestionsActive) { @@ -149,6 +239,8 @@ namespace Crow overlay.onKeyDown (this, e); return; case Key.Tab: + case Key.Enter: + case Key.KeypadEnter: completeToken (); return; } diff --git a/Samples/DebugLogAnalyzer/src/Extensions.cs b/Samples/common/src/Extensions.cs index 58047aaa..b4b0a1e5 100644 --- a/Samples/DebugLogAnalyzer/src/Extensions.cs +++ b/Samples/common/src/Extensions.cs @@ -1,24 +1,27 @@ +using System.Reflection; using Crow; -namespace DebugLogAnalyzer { +namespace Samples { public static class Extensions { public static CommandGroup GetCommands (this System.IO.DirectoryInfo di) => new CommandGroup( - new Command ("Set as root", ()=> {Program.CurrentProgramInstance.CurrentDir = di.FullName;}) + new Command ("Set as root", ()=> {SampleBaseForEditor.CurrentProgramInstance.CurrentDir = di.FullName;}) ); public static CommandGroup GetCommands (this System.IO.FileInfo fi) => new CommandGroup( new Command ("Delete", (sender0) => { - MessageBox.ShowModal (Program.CurrentProgramInstance, MessageBox.Type.YesNo, $"Delete {fi.Name}?").Yes += (sender, e) => { + MessageBox.ShowModal (SampleBaseForEditor.CurrentProgramInstance, MessageBox.Type.YesNo, $"Delete {fi.Name}?").Yes += (sender, e) => { System.IO.File.Delete(fi.FullName); Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget; (listContainer.Parent as Group).RemoveChild(listContainer); }; }) - ); + ); + public static Picture GetIcon (this MemberInfo mi) + => mi is EventInfo ? new BmpPicture("#Icons.event.png") : new BmpPicture("#Icons.property.png"); } }
\ No newline at end of file diff --git a/Samples/common/src/ImlParsing/Syntax.cs b/Samples/common/src/ImlParsing/Syntax.cs index fd410eaf..a38e1558 100644 --- a/Samples/common/src/ImlParsing/Syntax.cs +++ b/Samples/common/src/ImlParsing/Syntax.cs @@ -128,8 +128,12 @@ namespace Crow Exceptions.Add (new SyntaxException ("Extra equal sign in attribute syntax", iter.Current)); else attrib.EqualToken = iter.Current; - else if (iter.Current.Type == TokenType.AttributeValue) { - attrib.ValueToken = attrib.EndToken = iter.Current; + else if (iter.Current.Type == TokenType.AttributeValueOpen) + attrib.ValueOpenToken = iter.Current; + else if (iter.Current.Type == TokenType.AttributeValue) + attrib.ValueToken = iter.Current; + else if (iter.Current.Type == TokenType.AttributeValueClose) { + attrib.ValueCloseToken = attrib.EndToken = iter.Current; CurrentNode = CurrentNode.Parent; } else { Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current)); @@ -232,7 +236,7 @@ namespace Crow public XmlSource Source => Root.source; public bool Contains (int pos) => EndToken.HasValue ? - StartToken.Start <= pos && EndToken.Value.End >= pos : false; + StartToken.Start <= pos && EndToken.Value.End > pos : false; public void Dump (int level = 0) { Console.WriteLine ($"{new string('\t', level)}{this}"); @@ -303,8 +307,10 @@ namespace Crow public class AttributeSyntax : SyntaxNode { public Token? NameToken { get; internal set; } public Token? EqualToken { get; internal set; } + public Token? ValueOpenToken { get; internal set; } + public Token? ValueCloseToken { get; internal set; } public Token? ValueToken { get; internal set; } public AttributeSyntax (Token startTok) : base (startTok) {} - public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue; + public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue & ValueOpenToken.HasValue & ValueCloseToken.HasValue; } }
\ No newline at end of file diff --git a/Samples/common/src/ImlParsing/TokenType.cs b/Samples/common/src/ImlParsing/TokenType.cs index f9d7bcc6..3289d5ae 100644 --- a/Samples/common/src/ImlParsing/TokenType.cs +++ b/Samples/common/src/ImlParsing/TokenType.cs @@ -26,7 +26,9 @@ namespace Crow PI_End = 0x0402,// '?>' Operator = 0x0800, EqualSign = 0x0801, - AttributeValue = 0x2000, + AttributeValue = 0x2000, + AttributeValueOpen = 0x2001, + AttributeValueClose = 0x2002, Keyword = 0x1000, ElementOpen = 0x0403,// '<' EndElementOpen = 0x0404,// '</' diff --git a/Samples/common/src/ImlParsing/XmlSource.cs b/Samples/common/src/ImlParsing/XmlSource.cs index f520dcf3..f70aec24 100644 --- a/Samples/common/src/ImlParsing/XmlSource.cs +++ b/Samples/common/src/ImlParsing/XmlSource.cs @@ -25,9 +25,10 @@ namespace Crow syntaxAnalyser.Process (); sw.Stop(); - foreach (Token t in Tokens) + /*foreach (Token t in Tokens) Console.WriteLine ($"{t,-40} {Source.AsSpan(t.Start, t.Length).ToString()}"); - syntaxAnalyser.Root.Dump(); + syntaxAnalyser.Root.Dump();*/ + Console.WriteLine ($"Syntax Analysis done in {sw.ElapsedMilliseconds}(ms) {sw.ElapsedTicks}(ticks)"); foreach (SyntaxException ex in syntaxAnalyser.Exceptions) Console.WriteLine ($"{ex}"); @@ -212,9 +213,13 @@ namespace Crow case '\'': case '"': char q = reader.Read(); - if (reader.TryReadUntil (q)) + addTok (ref reader, TokenType.AttributeValueOpen); + if (reader.TryReadUntil (q)) { + addTok (ref reader, TokenType.AttributeValue); reader.Advance (); - addTok (ref reader, TokenType.AttributeValue); + addTok (ref reader, TokenType.AttributeValueClose); + } else + addTok (ref reader, TokenType.AttributeValue); break; case '=': reader.Advance(); diff --git a/Samples/common/src/SampleBase.cs b/Samples/common/src/SampleBase.cs index 1e849d6f..0c381048 100644 --- a/Samples/common/src/SampleBase.cs +++ b/Samples/common/src/SampleBase.cs @@ -10,7 +10,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -namespace Crow +namespace Samples { public class SampleBase : Interface { @@ -356,6 +356,10 @@ namespace Crow initCommands(); base.OnInitialized(); } + protected override void processDrawing(Crow.Cairo.Context ctx) + { + base.processDrawing(ctx); + } public override bool OnKeyDown(Key key) { diff --git a/Samples/common/src/SampleBaseForEditor.cs b/Samples/common/src/SampleBaseForEditor.cs new file mode 100644 index 00000000..4af718a2 --- /dev/null +++ b/Samples/common/src/SampleBaseForEditor.cs @@ -0,0 +1,312 @@ +// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com> +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + +using System; +using Crow; +using System.IO; +using System.Text; +using Crow.IML; +using System.Runtime.CompilerServices; +using Glfw; +using System.Diagnostics; +using Crow.Text; +using System.Collections.Generic; +using Encoding = System.Text.Encoding; + +namespace Samples +{ + public class SampleBaseForEditor : SampleBase + { + public static SampleBaseForEditor CurrentProgramInstance; + + protected override void OnInitialized () { + initCommands (); + + base.OnInitialized (); + + if (string.IsNullOrEmpty (CurrentDir)) + CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces"); + + } + + protected const string _defaultFileName = "unnamed.txt"; + protected string source = "", origSource; + protected TextBox editor; + bool debugLogRecording; + + + public string CurrentDir { + get => Configuration.Global.Get<string> (nameof (CurrentDir)); + set { + if (CurrentDir == value) + return; + Configuration.Global.Set (nameof (CurrentDir), value); + NotifyValueChanged (CurrentDir); + } + } + public string CurrentFile { + get => Configuration.Global.Get<string> (nameof (CurrentFile)); + set { + if (CurrentFile == value) + return; + Configuration.Global.Set (nameof (CurrentFile), value); + NotifyValueChanged (CurrentFile); + } + } + public virtual string Source { + get => source; + set { + if (source == value) + return; + source = value; + CMDSave.CanExecute = IsDirty; + NotifyValueChanged (source); + NotifyValueChanged ("IsDirty", IsDirty); + } + } + public bool DebugLoggingEnabled => DbgLogger.IsEnabled; + + public DbgEvtType RecordedEvents { + get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents)); + set { + if (RecordedEvents == value) + return; + Configuration.Global.Set (nameof (RecordedEvents), value); + if (DebugLogRecording) + DbgLogger.IncludeEvents = RecordedEvents; + NotifyValueChanged(RecordedEvents); + } + } + public DbgEvtType DiscardedEvents { + get => Configuration.Global.Get<DbgEvtType> (nameof (DiscardedEvents)); + set { + if (DiscardedEvents == value) + return; + Configuration.Global.Set (nameof (DiscardedEvents), value); + if (DebugLogRecording) + DbgLogger.DiscardEvents = DiscardedEvents; + NotifyValueChanged(DiscardedEvents); + } + } + public bool DebugLogRecording { + get => debugLogRecording; + set { + if (debugLogRecording == value) + return; + debugLogRecording = value; + NotifyValueChanged(debugLogRecording); + } + } + + public new bool IsDirty => source != origSource; + + + public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane, + CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions; + public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs); + protected virtual void initCommands () + { + CMDNew = new Command ("New", new Action (onNewFile), "#Icons.blank-file.svg"); + CMDSave = new Command ("Save", new Action (onSave), "#Icons.save.svg", false); + CMDSaveAs = new Command ("Save As...", new Action (onSaveAs), "#Icons.save.svg"); + CMDQuit = new Command ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg"); + CMDUndo = new Command ("Undo", new Action (undo),"#Icons.undo.svg", false); + CMDRedo = new Command ("Redo", new Action (redo),"#Icons.redo.svg", false); + CMDCut = new Command ("Cut", new Action (cut), "#Icons.scissors.svg", false); + CMDCopy = new Command ("Copy", new Action (copy), "#Icons.copy-file.svg", false); + CMDPaste= new Command ("Paste", new Action (paste), "#Icons.paste-on-document.svg", false); + } + + + protected Stack<TextChange> undoStack = new Stack<TextChange> (); + protected Stack<TextChange> redoStack = new Stack<TextChange> (); + protected TextSpan selection; + protected string SelectedText => + selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString (); + + protected void undo () { + if (undoStack.TryPop (out TextChange tch)) { + redoStack.Push (tch.Inverse (source)); + CMDRedo.CanExecute = true; + apply (tch); + editor.SetCursorPosition (tch.End + tch.ChangedText.Length); + } + if (undoStack.Count == 0) + CMDUndo.CanExecute = false; + } + protected void redo () { + if (redoStack.TryPop (out TextChange tch)) { + undoStack.Push (tch.Inverse (source)); + CMDUndo.CanExecute = true; + apply (tch); + editor.SetCursorPosition (tch.End + tch.ChangedText.Length); + } + if (redoStack.Count == 0) + CMDRedo.CanExecute = false; + } + protected void resetUndoRedo () { + undoStack.Clear (); + redoStack.Clear (); + CMDUndo.CanExecute = false; + CMDRedo.CanExecute = false; + } + + protected void cut () { + copy (); + applyChange (new TextChange (selection.Start, selection.Length, "")); + } + protected void copy () { + Clipboard = SelectedText; + } + protected void paste () { + applyChange (new TextChange (selection.Start, selection.Length, Clipboard)); + } + protected void onNewFile () { + if (IsDirty) { + MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?").Yes += (sender, e) => newFile (); + } else + newFile (); + } + protected void onSave () + { + if (!File.Exists (CurrentFile)) { + onSaveAs (); + return; + } + save (); + } + protected void onSaveAs () + { + string dir = Path.GetDirectoryName (CurrentFile); + if (string.IsNullOrEmpty (dir)) + dir = Directory.GetCurrentDirectory (); + LoadIMLFragment (@"<FileDialog Width='60%' Height='50%' Caption='Save as ...' CurrentDirectory='" + + dir + "' SelectedFile='" + + Path.GetFileName(CurrentFile) + "' OkClicked='saveFileDialog_OkClicked'/>").DataSource = this; + } + protected void saveFileDialog_OkClicked (object sender, EventArgs e) + { + FileDialog fd = sender as FileDialog; + + if (string.IsNullOrEmpty (fd.SelectedFileFullPath)) + return; + + if (File.Exists(fd.SelectedFileFullPath)) { + MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "File exists, overwrite?"); + mb.Yes += (sender2, e2) => { + CurrentFile = fd.SelectedFileFullPath; + save (); + }; + return; + } + + CurrentFile = fd.SelectedFileFullPath; + save (); + } + + protected void newFile() + { + disableTextChangedEvent = true; + Source = @"<Label Text='Hello World' Background='MediumSeaGreen' Margin='10'/>"; + disableTextChangedEvent = false; + resetUndoRedo (); + if (!string.IsNullOrEmpty (CurrentFile)) + CurrentFile = Path.Combine (Path.GetDirectoryName (CurrentFile), "newfile.crow"); + else + CurrentFile = Path.Combine (CurrentDir, "newfile.crow"); + } + + protected void save () { + using (Stream s = new FileStream(CurrentFile, FileMode.Create)) { + s.WriteByte (0xEF); + s.WriteByte (0xBB); + s.WriteByte (0xBF); + byte [] buff = Encoding.UTF8.GetBytes (source); + s.Write (buff, 0, buff.Length); + } + origSource = source; + NotifyValueChanged ("IsDirty", IsDirty); + CMDSave.CanExecute = false; + } + + protected void reloadFromFile () { + disableTextChangedEvent = true; + if (File.Exists (CurrentFile)) { + using (Stream s = new FileStream (CurrentFile, FileMode.Open)) { + using (StreamReader sr = new StreamReader (s)) + Source = origSource = sr.ReadToEnd (); + } + } + disableTextChangedEvent = false; + resetUndoRedo (); + } + protected bool disableTextChangedEvent = false; + protected void apply (TextChange change) { + Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)]; + ReadOnlySpan<char> src = source.AsSpan (); + src.Slice (0, change.Start).CopyTo (tmp); + if (!string.IsNullOrEmpty (change.ChangedText)) + change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start)); + src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length)); + disableTextChangedEvent = true; + Source = tmp.ToString (); + disableTextChangedEvent = false; + } + protected void applyChange (TextChange change) { + undoStack.Push (change.Inverse (source)); + redoStack.Clear (); + CMDUndo.CanExecute = true; + CMDRedo.CanExecute = false; + apply (change); + } + public void goUpDirClick (object sender, MouseButtonEventArgs e) + { + string root = Directory.GetDirectoryRoot (CurrentDir); + if (CurrentDir == root) + return; + CurrentDir = Directory.GetParent (CurrentDir).FullName; + } + + protected void Dv_SelectedItemChanged (object sender, SelectionChangeEventArgs e) + { + FileSystemInfo fi = e.NewValue as FileSystemInfo; + if (fi == null) + return; + if (fi is DirectoryInfo) + return; + + if (IsDirty) { + MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?"); + mb.Yes += (mbsender, mbe) => { CurrentFile = fi.FullName; reloadFromFile (); }; + return; + } + + CurrentFile = fi.FullName; + reloadFromFile (); + } + protected void onTextChanged (object sender, TextChangeEventArgs e) { + if (disableTextChangedEvent) + return; + applyChange (e.Change); + } + + protected void onSelectedTextChanged (object sender, EventArgs e) { + selection = (sender as Label).Selection; + Console.WriteLine($"selection:{selection.Start} length:{selection.Length}"); + CMDCut.CanExecute = CMDCopy.CanExecute = !selection.IsEmpty; + } + protected void textView_KeyDown (object sender, Crow.KeyEventArgs e) { + if (Ctrl) { + if (e.Key == Glfw.Key.W) { + if (Shift) + CMDRedo.Execute (); + else + CMDUndo.Execute (); + } else if (e.Key == Glfw.Key.S) { + onSave (); + } + } + } + } +}
\ No newline at end of file diff --git a/Samples/common/ui/Interfaces/Experimental/DockWindow.template b/Samples/common/ui/Interfaces/Experimental/DockWindow.template deleted file mode 100644 index 6c91312b..00000000 --- a/Samples/common/ui/Interfaces/Experimental/DockWindow.template +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0"?> -<!--<Widget Background="{./Background}"/>--> -<Border BorderWidth="1" Foreground="Black" CornerRadius="{./CornerRadius}" - Background="{./Background}" - MouseEnter="./onBorderMouseEnter" - MouseLeave="./onBorderMouseLeave"> - <VerticalStack Spacing="0"> - <HorizontalStack Height="Fit"> - <Label Text="{./Name}" TextAlignment="Left" Width="Fit" - Foreground="White" /> - <Label Text="{./DockingPosition}" TextAlignment="Left" Width="Fit" - Foreground="White" /> - </HorizontalStack> - <Label Text="{./Width}" TextAlignment="Left" Width="Fit" - Foreground="White" /> - <Label Text="{./Height}" TextAlignment="Left" Width="Fit" - Foreground="White" /> - - <HorizontalStack Visible="{./IsDocked}" Height="Fit" Margin="1" Background="Grey"> - <Label Text="{./Caption}" TextAlignment="Left" Width="Stretched" - Foreground="Jet" /> - <Image Width="8" Height="8" Focusable="true" Margin="0" Path="#Crow.Icons.exit2.svg" - MouseClick="./butQuitPress"/> - </HorizontalStack> - <HorizontalStack Background="vgradient|0:0.5,0.6,0.5,0.5|1:0.2,0.3,0.3,0.7" - Name="hs" Margin="0" Spacing="0" Height="Fit" Visible="{./IsFloating}"> - <Widget Width="5"/> - <Image Margin="1" Width="10" Height="10" Path="{./Icon}"/> - <Label Width="Stretched" Foreground="White" Margin="1" TextAlignment="Left" Text="{./Caption}" /> - <Border CornerRadius="6" BorderWidth="1" Foreground="Transparent" Height="10" Width="10" - MouseEnter="{Foreground=White}" MouseLeave="{Foreground=Transparent}"> - <Image Focusable="true" Name="Image" Margin="0" Path="#Crow.Icons.exit2.svg" - MouseClick="./butQuitPress"/> - </Border> - <Widget Width="5"/> - </HorizontalStack> - <Container Name="Content" MinimumSize="50,50"/> - </VerticalStack> -</Border> diff --git a/Samples/common/ui/Interfaces/Experimental/multiColorPick.crow b/Samples/common/ui/Interfaces/Experimental/multiColorPick.crow index 5b01c069..e30dd7ae 100644 --- a/Samples/common/ui/Interfaces/Experimental/multiColorPick.crow +++ b/Samples/common/ui/Interfaces/Experimental/multiColorPick.crow @@ -19,7 +19,7 @@ </ColorPicker> </Template> </ColorPicker> - <Border CornerRadius="5" Width="60" Height="40" Background="{../cp.CurrentColor}"> + <Border CornerRadius="5" Margin="10" Width="Fit" Height="40" Background="{../cp.CurrentColor}"> <Label Text="{../../cp.CurrentColor}"/> </Border> </VerticalStack>
\ No newline at end of file diff --git a/Samples/common/ui/Interfaces/Wrapper/1.1.crow b/Samples/common/ui/Interfaces/Wrapper/1.1.crow index e51cf308..6afbff21 100644 --- a/Samples/common/ui/Interfaces/Wrapper/1.1.crow +++ b/Samples/common/ui/Interfaces/Wrapper/1.1.crow @@ -8,7 +8,7 @@ <Widget Width="50%" Height="50" Background="SeaGreen"/> <Widget Width="50" Height="50" Background="SeaGreen"/> <Widget Width="50" Height="50" Background="SeaGreen"/> - <Widget Width="50" Height="50%" Background="SeaGreen"/> + <Widget Width="50%" Height="50" Background="SeaGreen"/> <Widget Width="50" Height="50" Background="SeaGreen"/> </Wrapper> </Window>
\ No newline at end of file diff --git a/Samples/common/ui/icons/event.png b/Samples/common/ui/icons/event.png Binary files differnew file mode 100755 index 00000000..8a27233f --- /dev/null +++ b/Samples/common/ui/icons/event.png diff --git a/Samples/common/ui/icons/property.png b/Samples/common/ui/icons/property.png Binary files differnew file mode 100755 index 00000000..1226c16f --- /dev/null +++ b/Samples/common/ui/icons/property.png diff --git a/Samples/common/ui/templates/Suggestions.template b/Samples/common/ui/templates/Suggestions.template index 5a4349d7..8bc55747 100644 --- a/Samples/common/ui/templates/Suggestions.template +++ b/Samples/common/ui/templates/Suggestions.template @@ -1,13 +1,13 @@ <?xml version="1.0"?> -<Border BorderWidth="1" Background="{./Background}" Height="Stretched"> - <!--<HorizontalStack Margin="1">--> +<Border BorderWidth="1" Background="{./Background}" Height="Stretched" Focusable="false"> + <HorizontalStack Margin="1"> <Scroller Name="ItemsScroller" Margin="2"> <VerticalStack Height="Fit" MinimumSize="10,10" Name="ItemsContainer" Margin="0" VerticalAlignment="Top"/> </Scroller> - <!--<ScrollBar Name="scrollbar1" Value="{²../ItemsScroller.ScrollY}" + <ScrollBar Name="scrollbar1" Value="{²../ItemsScroller.ScrollY}" LargeIncrement="{../ItemsScroller.PageHeight}" SmallIncrement="30" CursorSize="{../ItemsScroller.ChildHeightRatio}" Maximum="{../ItemsScroller.MaxScrollY}" Orientation="Vertical" Width="12" /> - </HorizontalStack>--> + </HorizontalStack> </Border> |