<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.884262,15.143117 c 24.231966,13.49131 34.18672,34.186719 34.18672,34.186719"
- id="path4175"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
+ id="path4175"/>
<path
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0"
id="path4177"
d="M 50.43178,15.408178 C 20.436536,37.282439 16.245061,49.594898 16.245061,49.594898"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:9;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<ItemTemplate DataType="Crow.Command" Path="#Crow.MenuButton.template"/>
<ItemTemplate DataType="Crow.CommandGroup" Data="Commands">
<Popper PopDirection="Right" Caption="{Caption}" IsEnabled="{CanExecute}" Width="Stretched"
- BubbleEvents="All"
MouseEnter="{Background=${ControlHighlight}}"
MouseLeave="{Background=Transparent}">
<Template>
}
/// <summary>
/// Application wide Configuration store utility
- ///
- /// configuration files are automatically stored in **_user/.config/appname/app.config_** on close and every minutes
- /// if some items have changed.
+ ///
+ /// configuration files are automatically stored in **_user/.config/appname/appname.config_** on close and at interval defined by
+ /// the static field `Configuration.AUTO_SAVE_INTERVAL` but only if some items have changed.
/// New items are automaticaly added on first use. Configuration class expose one templated Get and one Templated Set, so
/// creating, storing and retrieving config items is simple as:
- ///
+ ///
/// ```csharp\n
/// //storing\n
/// Configuration.Global.Set ("Option1", 42);\n
/// int op1 = Configuration.Global.Get<int> ("Option1");\n
/// ```\n
/// </summary>
- ///
+ ///
/// **.config** file are simple text files with per line, a key/value pair of the form `option=value`. Keys have to be unique
/// in the application scope.
- ///
+ ///
/// When running the application for the first time, some default options may be necessary. Their can be defined
/// in a special embedded resource text file with the key '**appname.default.config**'
+ ///
+ /// You may also provide a default value when you fetch an item:
+ /// ```csharp\n
+ /// int op1 = Configuration.Global.Get<int> ("Option1", 10);\n
+ /// ```\n
+ ///
public class Configuration
{
volatile bool isDirty = false;
string configPath;
Dictionary<string, ConfigItem> items = new Dictionary<string, ConfigItem> ();
static Configuration globalConfig;
-
- public static Configuration Global { get { return globalConfig; } }
-
+ /// <summary>
+ /// Interval in milliseconds between configuration file saving. Save is done only if an item has changed.
+ /// Default value is 200.
+ /// </summary>
+ public static int AUTO_SAVE_INTERVAL = 200;
+ /// <summary>
+ /// Default application wide store for configuration items. It's created and updated automaticaly when needed.
+ /// It's path is: **_user/.config/appname/appname.config_**.
+ /// </summary>
+ public static Configuration Global => globalConfig;
+ /// <summary>
+ /// Create a custom configuration store with the provided path.
+ /// </summary>
+ /// <param name="path">the full path where to save this configuration store.</param>
+ /// <param name="defaultConf">an optional text stream with default values.</param>
public Configuration (string path, Stream defaultConf = null) {
configPath = path;
if (File.Exists (configPath)) {
using (Stream s = new FileStream (configPath, FileMode.Open))
load (s);
-
- } else if (defaultConf != null) {
+
+ } else if (defaultConf != null) {
load (defaultConf);
}
startSavingThread ();
}
/// <summary>
- /// Create readonly configuration
+ /// Create a readonly configuration
/// </summary>
/// <param name="defaultConf"></param>
- public Configuration (Stream defaultConf = null) {
+ public Configuration (Stream defaultConf = null) {
load (defaultConf);
}
+ /// <summary>
+ /// Get the application configuration directory full path.
+ /// </summary>
+ /// <returns>application configuration directory full path</returns>
public static string AppConfigPath => Path.Combine (
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), ".config") ,
Assembly.GetEntryAssembly ().GetName().Name);
globalConfig = new Configuration (globalConfigPath);
}
+ /// <summary>
+ /// Get all the configuration item names currently present in this configuration store.
+ /// </summary>
+ /// <value>configuration item names</value>
public string[] Names {
get {
return items.Keys.ToArray ();
Thread.Sleep (100);
}
}
+ /// <summary>
+ /// Try to fetch a configuration item by name.
+ /// </summary>
+ /// <param name="key">the configuration item name</param>
+ /// <param name="result">the current value, or the type default if not found in store.</param>
+ /// <typeparam name="T">The type of the configuration item</typeparam>
+ /// <returns>true if the item was present, false otherwise</returns>
public bool TryGet<T> (string key, out T result) {
if (items.ContainsKey (key)){
result = items [key].GetValue<T> ();
return false;
}
/// <summary>
- /// retrive the value of the configuration key given in parameter
+ /// Retrieve an item from this configuration store identified by the key given in parameter
/// </summary>
- /// <param name="key">option name</param>
+ /// <param name="key">configuration item name</param>
+ /// <typeparam name="T">the type of the configuration item</typeparam>
+ /// <returns>The current value or the default one if not yet defined.</returns>
public T Get<T>(string key)
{
return !items.ContainsKey (key) ? default(T) : items [key].GetValue<T> ();
}
/// <summary>
- /// retrive the value of the configuration key given in parameter
+ /// Retrieve an item from this configuration store identified by the key given in parameter, or
+ /// return the default value provided as parameter.
/// </summary>
- /// <param name="key">option name</param>
+ /// <param name="key">configuration item name</param>
+ /// <param name="defaultValue">a default value in case this item is not yet present in the configuration store</param>
+ /// <typeparam name="T">the type of the configuration item</typeparam>
+ /// <returns>The current value or the default one if not yet defined.</returns>
public T Get<T>(string key, T defaultValue)
{
return !items.ContainsKey (key) ? defaultValue : items [key].GetValue<T> ();
- }
+ }
/// <summary>
/// store the value of the configuration key given in parameter
/// </summary>
items[key].Set (value);
isDirty = true;
}
+ /// <summary>
+ /// Save this configuration store with the path provided on creation. This is done automaticaly normaly.
+ /// </summary>
public void Save(){
using (Stream s = new FileStream(configPath,FileMode.Create)){
using (StreamWriter sw = new StreamWriter (s)) {
{
case "cairo":
return NativeLibrary.Load("cairo-2", assembly, null);
- /*case "glfw3":
- return NativeLibrary.Load("glfw", assembly, null);*/
case "rsvg-2.40":
return NativeLibrary.Load("rsvg-2", assembly, null);
}
}
return new CharLocation (result, absolutePosition - lines[result].Start);
}
+ [Obsolete]
public void UpdateLineLengthInPixel (int index, int lengthInPixel) {
lines[index].LengthInPixel = lengthInPixel;
}
#endregion
#region implemented abstract members of TemplatedControl
+ Widget cursorParent;
protected override void loadTemplate (Widget template = null)
{
+ if (cursorParent != null) {
+ cursorParent.LayoutChanged -= HandleCursorContainerLayoutChanged;
+ cursorParent = null;
+ }
base.loadTemplate (template);
cursor = child.FindByName ("Cursor");
if (cursor == null)
return;
- (cursor.Parent as Widget).LayoutChanged += HandleCursorContainerLayoutChanged;//too difficult to unregister
+ cursorParent = cursor.Parent as Widget;
+ cursorParent.LayoutChanged += HandleCursorContainerLayoutChanged;
+
updateCursorWidgetProps ();
}
}
#endregion
-
-
-
protected override void registerUpdate ()
=> RegisterForLayouting (LayoutingType.ArrangeChildren);
base.onMouseMove (sender, e);
}
#endregion
-
- public void OnDecrease (object sender, MouseButtonEventArgs e)
+ /// <summary>
+ /// Handler to decrease current value by `SmallIncrement`
+ /// </summary>
+ /// <param name="sender">event sender</param>
+ /// <param name="e">event argument</param>
+ public void OnDecrease (object sender, EventArgs e)
{
Value -= SmallIncrement;
}
- public void OnIncrease (object sender, MouseButtonEventArgs e)
+ /// <summary>
+ /// Handler to increase current value by `SmallIncrement`
+ /// </summary>
+ /// <param name="sender">event sender</param>
+ /// <param name="e">event argument</param>
+ public void OnIncrease (object sender, EventArgs e)
{
Value += SmallIncrement;
}
protected override void Dispose(bool disposing)
{
- base.Dispose(disposing);
+ if (cursorParent != null) {
+ cursorParent.LayoutChanged -= HandleCursorContainerLayoutChanged;
+ cursorParent = null;
+ }
+ base.Dispose(disposing);
}
}
}
{
class TestInterface : Interface
{
-#if NETCOREAPP
- static IntPtr resolveUnmanaged (Assembly assembly, String libraryName) {
-
- switch (libraryName)
- {
- case "cairo":
- return NativeLibrary.Load("cairo-2", assembly, null);
- case "glfw3":
- return NativeLibrary.Load("glfw", assembly, null);
- case "rsvg-2.40":
- return NativeLibrary.Load("rsvg-2", assembly, null);
- }
- Console.WriteLine ($"[UNRESOLVE] {assembly} {libraryName}");
- return IntPtr.Zero;
- }
-
- static TestInterface () {
- System.Runtime.Loader.AssemblyLoadContext.Default.ResolvingUnmanagedDll+=resolveUnmanaged;
- }
-#endif
readonly int count = 10, updateCycles = 0;
readonly bool screenOutput = false;
readonly string inDirectory = null;//directory to test
</VerticalStack>-->
<Container Name="CrowContainer" Height="60%" Background="Black"/>
<Splitter/>
+ <Menu Data="{EditorAllCommands}" Height="Fit" Width="Stretched">
+ <ItemTemplate DataType="Crow.Command" Path="Interfaces/menuCommand.itmp"/>
+ <ItemTemplate DataType="Crow.CommandGroup" >
+ <MenuItem Data="{Commands}" Width="Fit" IsEnabled="{CanExecute}"
+ Template="Interfaces/menuItem.template"
+ ItemTemplate="Interfaces/menuItem.itmp">
+ </MenuItem>
+ </ItemTemplate>
+ </Menu>
<VerticalStack CacheEnabled="true">
- <Wrapper Orientation="Vertical" Height="Fit">
+ <!-- <Wrapper Orientation="Vertical" Height="Fit">
<Button Style="IcoButton" Command="{CMDNew}" />
<Button Style="IcoButton" Command="{CMDSave}" />
<Button Style="IcoButton" Command="{CMDSaveAs}" />
Tooltip="Add '*source* where you want to load the source in the editor."/>
</VerticalStack>
</Popper>
- </Wrapper>
+ </Wrapper>-->
<HorizontalStack>
<Editor Name="tb" Text="{Source}" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"
- TextChanged="onTextChanged" KeyDown="textView_KeyDown" ContextCommands="{EditorCommands}"
+ TextChanged="onTextChanged" KeyDown="textView_KeyDown" ContextCommands="{EditorEditCommands}"
SelectionChanged="onEditorSelectionChanged"
Foreground="DarkGrey" Background="White" MouseWheelSpeed="20"/>
<ScrollBar Value="{²../tb.ScrollY}"
+using System.IO;
using System.Reflection;
using Crow;
namespace Samples {
public static class Extensions {
- public static CommandGroup GetCommands (this System.IO.DirectoryInfo di) =>
+ public static CommandGroup GetCommands (this DirectoryInfo di) =>
new CommandGroup(
- new ActionCommand ("Set as root", ()=> {SampleBaseForEditor.CurrentProgramInstance.CurrentDir = di.FullName;})
+ new ActionCommand ("Set as root", ()=> {SampleBaseForEditor.CurrentProgramInstance.CurrentDir = di.FullName;})/*,
+ new ActionCommand ("New Directory", (sender0) => {
+ Directory.CreateDirectory (Path.Combine (di.FullName, "new directory"));
+ Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
+ })*/
);
- public static CommandGroup GetCommands (this System.IO.FileInfo fi) =>
+ public static CommandGroup GetCommands (this FileInfo fi) =>
new CommandGroup(
new ActionCommand ("Delete", (sender0) => {
MessageBox.ShowModal (SampleBaseForEditor.CurrentProgramInstance, MessageBox.Type.YesNo, $"Delete {fi.Name}?").Yes += (sender, e) => {
- System.IO.File.Delete(fi.FullName);
+ File.Delete(fi.FullName);
Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
(listContainer.Parent as Group).RemoveChild(listContainer);
};
namespace Crow
{
public class SyntaxException : Exception {
- public readonly Token Token;
+ public readonly Token Token;
public SyntaxException(string message, Token token = default, Exception innerException = null)
: base (message, innerException) {
Token = token;
}
}
- public class SyntaxAnalyser {
+ public class SyntaxAnalyser {
XmlSource source;
IEnumerable<Token> tokens => source.Tokens;
public SyntaxNode Root => CurrentNode;
throw new SyntaxException ("Unexpected end of source");
}
- Token accept (IEnumerator<Token> iter, TokenType acceptedTokenType) {
+ Token accept (IEnumerator<Token> iter, TokenType acceptedTokenType) {
if (iter.Current.Type == acceptedTokenType)
return iter.Current;
else
Token eltOpen = iter.Current;
moveNextOrThrow (iter);
Token eltName = accept (iter, TokenType.ElementName);
-
+
List<SyntaxNode> attributes = readAttributes (iter);
if (iter.Current.Type == TokenType.EmptyElementClosing || iter.Current.Type == TokenType.ClosingSign)
Token eltOpen = iter.Current;
moveNextOrThrow (iter);
Token eltName = accept (iter, TokenType.ElementName);
- moveNextOrThrow (iter);
+ moveNextOrThrow (iter);
return new ElementEndTagSyntax(source, eltOpen, eltName, accept (iter, TokenType.ClosingSign));
}*/
Exceptions = new List<SyntaxException> ();
CurrentNode = new IMLRootSyntax (source);
previousTok = default;
- iter = tokens.GetEnumerator ();
+ iter = tokens.GetEnumerator ();
bool notEndOfSource = iter.MoveNext ();
while (notEndOfSource) {
} else if (iter.Current.Type == TokenType.ElementName)
tag.NameToken = iter.Current;
else if (iter.Current.Type == TokenType.ClosingSign) {
- tag.EndToken = iter.Current;
+ tag.EndToken = iter.Current;
CurrentNode = tag.Parent;
CurrentNode.RemoveChild (tag);
CurrentNode = CurrentNode.AddChild (new ElementSyntax (tag));
Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
CurrentNode.EndToken = previousTok;
CurrentNode = CurrentNode.Parent;
- continue;
+ continue;
}
} else if (CurrentNode is ElementSyntax elt) {
if (iter.Current.Type == TokenType.ElementOpen)
CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
- else if (iter.Current.Type == TokenType.EndElementOpen) {
- elt.EndTag = new ElementEndTagSyntax (iter.Current);
+ else if (iter.Current.Type == TokenType.EndElementOpen) {
+ elt.EndTag = new ElementEndTagSyntax (iter.Current);
CurrentNode = elt.AddChild (elt.EndTag);
}
} else if (CurrentNode is AttributeSyntax attrib) {
Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
CurrentNode.EndToken = previousTok;
CurrentNode = CurrentNode.Parent;
- continue;
+ continue;
}
} else if (CurrentNode is ElementEndTagSyntax eltEndTag) {
if (iter.Current.Type == TokenType.ElementName)
Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
eltEndTag.EndToken = eltEndTag.Parent.EndToken = previousTok;
CurrentNode = CurrentNode.Parent.Parent;
- continue;
+ continue;
}
} else if (CurrentNode is IMLRootSyntax) {
switch (iter.Current.Type) {
Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
pi.EndToken = previousTok;
CurrentNode = CurrentNode.Parent;
- continue;
+ continue;
}
}
}
-
+
previousTok = iter.Current;
notEndOfSource = iter.MoveNext ();
}
if (!CurrentNode.EndToken.HasValue)
CurrentNode.EndToken = previousTok;
CurrentNode = CurrentNode.Parent;
- }
+ }
}
}
public class SyntaxNode {
public SyntaxNode Parent { get; private set; }
List<SyntaxNode> children = new List<SyntaxNode> ();
-
+
public readonly Token StartToken;
public Token? EndToken { get; internal set; }
- public SyntaxNode (Token tokStart, Token? tokEnd = null) {
+ public SyntaxNode (Token tokStart, Token? tokEnd = null) {
StartToken = tokStart;
EndToken = tokEnd;
}
protected ElementTagSyntax (Token startTok)
: base (startTok) {
}
- }
+ }
public class ElementStartTagSyntax : ElementTagSyntax {
public ElementStartTagSyntax (Token startTok)
: base (startTok) {
: base (startTok) {
}
}
-
+
public class EmptyElementSyntax : SyntaxNode {
public readonly ElementStartTagSyntax StartTag;
public EmptyElementSyntax (ElementStartTagSyntax startNode) : base (startNode.StartToken, startNode.EndToken) {
- StartTag = startNode;
+ StartTag = startNode;
AddChild (StartTag);
}
}
public override bool IsComplete => base.IsComplete & StartTag.IsComplete & (EndTag != null && EndTag.IsComplete);
public ElementSyntax (ElementStartTagSyntax startTag)
- : base (startTag.StartToken) {
+ : base (startTag.StartToken) {
StartTag = startTag;
AddChild (StartTag);
}
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 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 & ValueOpenToken.HasValue & ValueCloseToken.HasValue;
}
public ActionCommand 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);
+ public CommandGroup EditorFileCommands, EditorEditCommands, EditorAllCommands;
protected virtual void initCommands ()
{
CMDNew = new ActionCommand ("New", new Action (onNewFile), "#Icons.blank-file.svg");
CMDCut = new ActionCommand ("Cut", new Action (cut), "#Icons.scissors.svg", false);
CMDCopy = new ActionCommand ("Copy", new Action (copy), "#Icons.copy-file.svg", false);
CMDPaste= new ActionCommand ("Paste", new Action (paste), "#Icons.paste-on-document.svg", false);
+
+ EditorFileCommands = new CommandGroup ("File", CMDSave, CMDSaveAs, CMDQuit);
+ EditorEditCommands = new CommandGroup ("Edit", CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste);
+
+ EditorAllCommands = new CommandGroup (EditorFileCommands, EditorEditCommands);
}
<Template>
<Label Text="{./Caption}" Width="Stretched" Height="Stretched" Margin="3"
Background="{./Background}"/>
- </Template>
+ </Template>
<VerticalStack Margin="0" Name="ItemsContainer" Fit="true" Background="Jet"/>
</Popper>
</ItemTemplate>