diff options
Diffstat (limited to 'Samples/common')
| -rw-r--r-- | Samples/common/src/Editor.cs | 120 | ||||
| -rw-r--r-- | Samples/common/src/Extensions.cs | 27 | ||||
| -rw-r--r-- | Samples/common/src/ImlParsing/Syntax.cs | 14 | ||||
| -rw-r--r-- | Samples/common/src/ImlParsing/TokenType.cs | 4 | ||||
| -rw-r--r-- | Samples/common/src/ImlParsing/XmlSource.cs | 13 | ||||
| -rw-r--r-- | Samples/common/src/SampleBase.cs | 6 | ||||
| -rw-r--r-- | Samples/common/src/SampleBaseForEditor.cs | 312 | ||||
| -rw-r--r-- | Samples/common/ui/Interfaces/Experimental/DockWindow.template | 39 | ||||
| -rw-r--r-- | Samples/common/ui/Interfaces/Experimental/multiColorPick.crow | 2 | ||||
| -rw-r--r-- | Samples/common/ui/Interfaces/Wrapper/1.1.crow | 2 | ||||
| -rwxr-xr-x | Samples/common/ui/icons/event.png | bin | 0 -> 241 bytes | |||
| -rwxr-xr-x | Samples/common/ui/icons/property.png | bin | 0 -> 257 bytes | |||
| -rw-r--r-- | Samples/common/ui/templates/Suggestions.template | 8 |
13 files changed, 478 insertions, 69 deletions
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/common/src/Extensions.cs b/Samples/common/src/Extensions.cs new file mode 100644 index 00000000..b4b0a1e5 --- /dev/null +++ b/Samples/common/src/Extensions.cs @@ -0,0 +1,27 @@ + + +using System.Reflection; +using Crow; + +namespace Samples { + public static class Extensions { + + public static CommandGroup GetCommands (this System.IO.DirectoryInfo di) => + new CommandGroup( + 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 (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> |