<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591;1587;1570;1572;1573;1574</NoWarn>
- <DefineConstants>DESIGN_MODE;_MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS</DefineConstants>
+ <DefineConstants>DESIGN_MODE;MEASURE_TIME;_DEBUG_HIGHLIGHT_FOCUS</DefineConstants>
<EnableDefaultItems>false</EnableDefaultItems>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<!--<AllowUnsafeBlocks>true</AllowUnsafeBlocks>-->
public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, false, false)
{
hWin = glfwWindowHandle;
+ PerformanceMeasure.InitMeasures ();
}
public Interface (int width = 800, int height = 600, bool startUIThread = true, bool createSurface = true)
{
if (createSurface)
initSurface ();
+ PerformanceMeasure.InitMeasures ();
+
if (startUIThread) {
Thread t = new Thread (InterfaceThread) {
IsBackground = true
};
t.Start ();
- }
-
- PerformanceMeasure.InitMeasures ();
+ }
}
#endregion
public readonly string ChangedText;
public int End => Start + Length;
+
+ public int CharDiff => ChangedText.Length - Length;
public TextChange (int position, int length, string changedText) {
Start = position;
Length = length;
}
if (!string.IsNullOrEmpty (_text)) {
- Foreground.SetAsSource (IFace, gr);
+ Foreground?.SetAsSource (IFace, gr);
TextExtents extents;
Span<byte> bytes = stackalloc byte[128];
using Crow;
using Glfw;
-namespace tests
+namespace Samples
{
public class BasicTests : SampleBase
{
using System;
using System.Runtime.CompilerServices;
using Crow;
+using Samples;
namespace BindingTest
{
using System;
using Crow.Cairo;
using System.Threading;
+using Samples;
namespace Crow
{
+++ /dev/null
-
-
-using Crow;
-
-namespace DebugLogAnalyzer {
- 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;})
- );
- 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) => {
- System.IO.File.Delete(fi.FullName);
- Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
- (listContainer.Parent as Group).RemoveChild(listContainer);
- };
- })
- );
-
- }
-}
\ No newline at end of file
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;
}
}
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;
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);
}
}
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 {
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 {
}
- 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 {
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) {
-// 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)
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 ()
{
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)
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;
}
}
- void resetUndoRedo () {
- undoStack.Clear ();
- redoStack.Clear ();
- CMDUndo.CanExecute = false;
- CMDRedo.CanExecute = false;
- }
void showError (Exception ex) {
NotifyValueChanged ("ErrorMessage", ex);
NotifyValueChanged ("ShowError", true);
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;
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 {
NotifyValueChanged (DebugLogFilePath);
}
}
- bool debugLogRecording;
- public bool DebugLogRecording {
- get => debugLogRecording;
- set {
- if (debugLogRecording == value)
- return;
- debugLogRecording = value;
- NotifyValueChanged(debugLogRecording);
- }
- }
public override bool OnKeyDown (Key key) {
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>
<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">
using System.Linq;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+using System.Collections;
namespace Crow
{
}
ListBox overlay;
- List<String> suggestions;
- public List<String> Suggestions {
+ IList suggestions;
+ public IList Suggestions {
get => suggestions;
set {
suggestions = value;
.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}");
}
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}");
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;
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 ();
}
hideOverlay ();
base.onMouseDown (sender, e);
}
+
public override void onKeyDown(object sender, KeyEventArgs e)
{
if (suggestionsActive) {
overlay.onKeyDown (this, e);
return;
case Key.Tab:
+ case Key.Enter:
+ case Key.KeypadEnter:
completeToken ();
return;
}
--- /dev/null
+
+
+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
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));
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}");
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
PI_End = 0x0402,// '?>'
Operator = 0x0800,
EqualSign = 0x0801,
- AttributeValue = 0x2000,
+ AttributeValue = 0x2000,
+ AttributeValueOpen = 0x2001,
+ AttributeValueClose = 0x2002,
Keyword = 0x1000,
ElementOpen = 0x0403,// '<'
EndElementOpen = 0x0404,// '</'
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}");
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();
using System.Runtime.InteropServices;
using System.Threading;
-namespace Crow
+namespace Samples
{
public class SampleBase : Interface
{
initCommands();
base.OnInitialized();
}
+ protected override void processDrawing(Crow.Cairo.Context ctx)
+ {
+ base.processDrawing(ctx);
+ }
public override bool OnKeyDown(Key key)
{
--- /dev/null
+// 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
+++ /dev/null
-<?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>
</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
<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
<?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>