From 25a2b0d668dfea62e53a1fcf50ed32b43cfc2c68 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Tue, 2 Mar 2021 11:57:39 +0100 Subject: [PATCH] implement theme from directory --- Crow.sln | 7 + Crow/Crow.csproj | 4 +- Crow/src/2d/Size.cs | 2 + Crow/src/DebugUtils/DebugLogger.cs | 1 + Crow/src/Fill/BmpPicture.cs | 50 +- Crow/src/Fill/SvgPicture.cs | 21 +- Crow/src/IML/CompilerServices.cs | 2 +- Crow/src/IML/Instantiator.cs | 2 +- Crow/src/Interface.cs | 146 +++++- Crow/src/ItemTemplate.cs | 4 +- Crow/src/Widgets/Scroller.cs | 4 +- Crow/src/Widgets/Shape.cs | 5 +- Crow/src/Widgets/Spinner.cs | 12 +- Crow/src/styling/StyleReader.cs | 5 +- Samples/PathPainter/Painter.cs | 203 +++++++ Samples/PathPainter/PathPainter.csproj | 7 + Samples/PathPainter/Program.cs | 76 +++ Samples/PathPainter/ui/Icons/Lines.svg | 7 + Samples/PathPainter/ui/Icons/Rect.svg | 6 + Samples/PathPainter/ui/Icons/Select.svg | 6 + Samples/PathPainter/ui/Painter.style | 3 + Samples/PathPainter/ui/Spinner.template | 14 + Samples/PathPainter/ui/colorSelector.template | 11 + Samples/PathPainter/ui/main.crow | 43 ++ Samples/ShowCase/ShowCase.cs | 6 +- Samples/common/SampleBase.cs | 495 +++++++++--------- .../common/ui/Interfaces/Divers/chess.crow | 19 + .../DefaultTemplates/Crow/Window.template | 4 + .../TestTheme/Images/Crow/Icons/checkbox.svg | 75 +++ Themes/TestTheme/theme.style | 23 + 30 files changed, 954 insertions(+), 309 deletions(-) create mode 100644 Samples/PathPainter/Painter.cs create mode 100644 Samples/PathPainter/PathPainter.csproj create mode 100644 Samples/PathPainter/Program.cs create mode 100644 Samples/PathPainter/ui/Icons/Lines.svg create mode 100644 Samples/PathPainter/ui/Icons/Rect.svg create mode 100644 Samples/PathPainter/ui/Icons/Select.svg create mode 100644 Samples/PathPainter/ui/Painter.style create mode 100644 Samples/PathPainter/ui/Spinner.template create mode 100644 Samples/PathPainter/ui/colorSelector.template create mode 100644 Samples/PathPainter/ui/main.crow create mode 100644 Samples/common/ui/Interfaces/Divers/chess.crow create mode 100644 Themes/TestTheme/DefaultTemplates/Crow/Window.template create mode 100644 Themes/TestTheme/Images/Crow/Icons/checkbox.svg create mode 100644 Themes/TestTheme/theme.style diff --git a/Crow.sln b/Crow.sln index 473cfabc..afc71387 100644 --- a/Crow.sln +++ b/Crow.sln @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dockableWindows", "Samples\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingTest", "Samples\BindingTest\BindingTest.csproj", "{242094B3-A1F1-44F8-B78D-D819B595DDBA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PathPainter", "Samples\PathPainter\PathPainter.csproj", "{4066FE1E-3508-4361-ABAA-21601F632ED8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -83,6 +85,10 @@ Global {242094B3-A1F1-44F8-B78D-D819B595DDBA}.Debug|Any CPU.Build.0 = Debug|Any CPU {242094B3-A1F1-44F8-B78D-D819B595DDBA}.Release|Any CPU.ActiveCfg = Release|Any CPU {242094B3-A1F1-44F8-B78D-D819B595DDBA}.Release|Any CPU.Build.0 = Release|Any CPU + {4066FE1E-3508-4361-ABAA-21601F632ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4066FE1E-3508-4361-ABAA-21601F632ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4066FE1E-3508-4361-ABAA-21601F632ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4066FE1E-3508-4361-ABAA-21601F632ED8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -97,6 +103,7 @@ Global {6E361E34-D266-4BEB-97F4-E209E01C6246} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} {E19FD3DB-902A-4C99-8BF0-5ACAFFE35608} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} {242094B3-A1F1-44F8-B78D-D819B595DDBA} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} + {4066FE1E-3508-4361-ABAA-21601F632ED8} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {00D4E149-7131-49F4-BAAD-559AA961A78E} diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index 840469c8..f09f66dc 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -17,13 +17,13 @@ https://github.com/jpbruyere/Crow/wiki MIT crow.png - Copyright 2013-2020 + Copyright 2013-2021 True true $(NoWarn);1591;1587;1570;1572;1573;1574 - DESIGN_MODE;_MEASURE_TIME + _DESIGN_MODE;_MEASURE_TIME false false diff --git a/Crow/src/2d/Size.cs b/Crow/src/2d/Size.cs index 935ff656..ee023285 100644 --- a/Crow/src/2d/Size.cs +++ b/Crow/src/2d/Size.cs @@ -46,6 +46,8 @@ namespace Crow public static Size operator + (Size s, int i) => new Size (s.Width + i, s.Height + i); public static Size operator * (Size s, int i) => new Size (s.Width * i, s.Height * i); public static Size operator / (Size s, int i) => new Size (s.Width / i, s.Height / i); + + public static Size operator * (Size s, double i) => new Size ((int)(s.Width * i), (int)(s.Height * i)); #endregion diff --git a/Crow/src/DebugUtils/DebugLogger.cs b/Crow/src/DebugUtils/DebugLogger.cs index 0c5d7f6c..0696c4e8 100644 --- a/Crow/src/DebugUtils/DebugLogger.cs +++ b/Crow/src/DebugUtils/DebugLogger.cs @@ -31,6 +31,7 @@ namespace Crow IFaceLoad = IFace | 0x05, IFaceInit = IFace | 0x06, CreateITor = IFace | 0x07, + IFaceReleadTheme = IFace | 0x08, HoverWidget = IFace | Focus | Widget | 0x01, FocusedWidget = IFace | Focus | Widget | 0x02, diff --git a/Crow/src/Fill/BmpPicture.cs b/Crow/src/Fill/BmpPicture.cs index 70f36d3f..0f67323d 100644 --- a/Crow/src/Fill/BmpPicture.cs +++ b/Crow/src/Fill/BmpPicture.cs @@ -13,44 +13,48 @@ namespace Crow /// /// Derived from FILL for loading and drawing bitmaps in the interface /// - public class BmpPicture : Picture - { + public class BmpPicture : Picture { byte[] image = null; #region CTOR /// /// Initializes a new instance of BmpPicture. /// - public BmpPicture () {} + public BmpPicture () { } /// /// Initializes a new instance of BmpPicture by loading the image pointed by the path argument /// /// image path, may be embedded - public BmpPicture (string path) : base(path) { } + public BmpPicture (string path) : base (path) { } #endregion /// /// load the image for rendering from the path given as argument /// - void load (Interface iFace) - { + void load (Interface iFace) { if (iFace.sharedPictures.ContainsKey (Path)) { - sharedPicture sp = iFace.sharedPictures [Path]; + sharedPicture sp = iFace.sharedPictures[Path]; image = (byte[])sp.Data; Dimensions = sp.Dims; return; } using (Stream stream = iFace.GetStreamFromPath (Path)) { + load (stream); + //loadBitmap (new System.Drawing.Bitmap (stream)); + iFace.sharedPictures[Path] = new sharedPicture (image, Dimensions); + } + } + void load (Stream stream) { #if STB_SHARP - StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha); - image = new byte [stbi.Data.Length]; - //rgba to argb for cairo. - for (int i = 0; i < stbi.Data.Length; i += 4) { - image [i] = stbi.Data[i + 2]; - image [i + 1] = stbi.Data [i + 1]; - image [i + 2] = stbi.Data [i]; - image [i + 3] = stbi.Data [i + 3]; - } - Dimensions = new Size (stbi.Width, stbi.Height); + StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha); + image = new byte[stbi.Data.Length]; + //rgba to argb for cairo. + for (int i = 0; i < stbi.Data.Length; i += 4) { + image[i] = stbi.Data[i + 2]; + image[i + 1] = stbi.Data[i + 1]; + image[i + 2] = stbi.Data[i]; + image[i + 3] = stbi.Data[i + 3]; + } + Dimensions = new Size (stbi.Width, stbi.Height); #else using (StbImage stbi = new StbImage (stream)) { image = new byte [stbi.Size]; @@ -64,12 +68,12 @@ namespace Crow Dimensions = new Size (stbi.Width, stbi.Height); } #endif - - //loadBitmap (new System.Drawing.Bitmap (stream)); - } - iFace.sharedPictures [Path] = new sharedPicture (image, Dimensions); } - + internal static sharedPicture CreateSharedPicture (Stream stream) { + BmpPicture pic = new BmpPicture (); + pic.load (stream); + return new sharedPicture (pic.image, pic.Dimensions); + } //load image via System.Drawing.Bitmap, cairo load png only @@ -93,7 +97,7 @@ namespace Crow bitmap.UnlockBits (data); }*/ -#region implemented abstract members of Fill + #region implemented abstract members of Fill public override void SetAsSource (Interface iFace, Context ctx, Rectangle bounds = default(Rectangle)) { diff --git a/Crow/src/Fill/SvgPicture.cs b/Crow/src/Fill/SvgPicture.cs index f461a544..4f378be4 100644 --- a/Crow/src/Fill/SvgPicture.cs +++ b/Crow/src/Fill/SvgPicture.cs @@ -35,16 +35,21 @@ namespace Crow Dimensions = sp.Dims; return; } - using (Stream stream = iFace.GetStreamFromPath (Path)) { - using (MemoryStream ms = new MemoryStream ()) { - stream.CopyTo (ms); - - hSVG = new Rsvg.Handle (ms.ToArray ()); - Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height); - } - } + using (Stream stream = iFace.GetStreamFromPath (Path)) + load (stream); iFace.sharedPictures [Path] = new sharedPicture (hSVG, Dimensions); } + void load (Stream stream) { + using (BinaryReader sr = new BinaryReader (stream)) { + hSVG = new Rsvg.Handle (sr.ReadBytes ((int)stream.Length)); + Dimensions = new Size (hSVG.Dimensions.Width, hSVG.Dimensions.Height); + } + } + internal static sharedPicture CreateSharedPicture (Stream stream) { + SvgPicture pic = new SvgPicture (); + pic.load (stream); + return new sharedPicture (pic.hSVG, pic.Dimensions); + } public void LoadSvgFragment (string fragment) { hSVG = new Rsvg.Handle (System.Text.Encoding.Unicode.GetBytes(fragment)); diff --git a/Crow/src/IML/CompilerServices.cs b/Crow/src/IML/CompilerServices.cs index c1d4edd7..d8033b28 100644 --- a/Crow/src/IML/CompilerServices.cs +++ b/Crow/src/IML/CompilerServices.cs @@ -535,7 +535,7 @@ namespace Crow.IML il.Emit (OpCodes.Pop);//remove null string from stack il.Emit (OpCodes.Ldstr, "");//replace with empty string il.MarkLabel (endConvert); - } else if ((origType.IsEnum || origType == typeof (Enum)) && destType.IsEnum) {//TODO:double check this (multiple IsEnum test, no check of enum underlying type + } else if ((origType.IsEnum || origType == typeof (Enum)) && (destType.IsEnum) || destType == typeof (Enum)) {//TODO:double check this (multiple IsEnum test, no check of enum underlying type il.Emit (OpCodes.Unbox_Any, destType); return; } else if (origType.IsValueType) { diff --git a/Crow/src/IML/Instantiator.cs b/Crow/src/IML/Instantiator.cs index 3a249a1e..a7ca4f2f 100644 --- a/Crow/src/IML/Instantiator.cs +++ b/Crow/src/IML/Instantiator.cs @@ -1568,7 +1568,7 @@ namespace Crow.IML { /// /// the corresponding type object /// graphic object type name without its namespace - Type tryGetGOType (string typeName){ + internal static Type tryGetGOType (string typeName){ if (knownGOTypes.ContainsKey (typeName)) return knownGOTypes [typeName]; Type t = Type.GetType ("Crow." + typeName); diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 895c2c4c..5dbac92f 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; +using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -15,6 +16,7 @@ using System.Threading; using Crow.Cairo; using Crow.IML; using Glfw; +using Path = System.IO.Path; namespace Crow { @@ -260,7 +262,9 @@ namespace Crow /// public void Init () { DbgLogger.StartEvent (DbgEvtType.IFaceInit); + initDictionaries (); loadStyling (); + loadThemeFiles (); initTooltip (); initContextMenus (); OnInitialized (); @@ -300,7 +304,9 @@ namespace Crow // TODO: dispose managed state (managed objects). } - currentCursor?.Dispose (); + currentCursor?.Dispose (); + disposeContextMenus (); + if (ownWindow) { Glfw3.DestroyWindow (hWin); Glfw3.Terminate (); @@ -442,16 +448,15 @@ namespace Crow /// each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here /// on the first instance creation of a IML item. /// - public Dictionary Instantiators = new Dictionary(); - public Dictionary Templates = new Dictionary (); + public Dictionary Instantiators; /// /// default templates dic by metadata token /// - public Dictionary DefaultTemplates = new Dictionary (); + public Dictionary DefaultTemplates; /// /// Item templates stored with their index /// - public Dictionary ItemTemplates = new Dictionary (); + public Dictionary ItemTemplates; public List CrowThreads = new List();//used to monitor thread finished @@ -483,7 +488,7 @@ namespace Crow /// The compilation is done on the first object instancing, and is also done for custom widgets public delegate void LoaderInvoker(object instance); /// Store one loader per StyleKey - public Dictionary DefaultValuesLoader = new Dictionary(); + public Dictionary DefaultValuesLoader; /// Store dictionnary of member/value per StyleKey public Dictionary Styling; /// @@ -498,11 +503,9 @@ namespace Crow public Dictionary StylingConstants; /// parse all styling data's during application startup and build global Styling Dictionary protected virtual void loadStyling() { - StylingConstants = new Dictionary (); - Styling = new Dictionary (); - //fetch styling info in this order, if member styling is alreadey referenced in previous //assembly, it's ignored. + loadThemeStyle (); loadStylingFromAssembly (Assembly.GetExecutingAssembly ()); foreach (Assembly a in crowAssemblies) { @@ -518,7 +521,7 @@ namespace Crow .GetManifestResourceNames () .Where (r => r.EndsWith (".style", StringComparison.OrdinalIgnoreCase))) { using (StyleReader sr = new StyleReader (assembly.GetManifestResourceStream (s))) - sr.Parse (StylingConstants, Styling, s); + sr.Parse (StylingConstants, Styling, s); } } public void LoadStyle (string stylePath) { @@ -532,6 +535,120 @@ namespace Crow } #endregion + #region Theming + string theme; + public string Theme { + get => theme; + set { + if (theme == value) + return; + theme = value; + NotifyValueChanged (theme); + + if (StylingConstants == null)//iFace not yet initialized + return; + lock (UpdateMutex) { + DbgLogger.StartEvent (DbgEvtType.IFaceReleadTheme); + disposeContextMenus (); + initDictionaries (); + loadStyling (); + loadThemeFiles (); + initContextMenus (); + DbgLogger.EndEvent (DbgEvtType.IFaceReleadTheme); + } + } + } + protected void initDictionaries () { + const int initCapacity = 20; + StylingConstants = new Dictionary (initCapacity); + Styling = new Dictionary (initCapacity); + DefaultValuesLoader = new Dictionary (initCapacity); + Instantiators = new Dictionary (initCapacity); + DefaultTemplates = new Dictionary (initCapacity); + ItemTemplates = new Dictionary (initCapacity); + } + void loadThemeFiles () { + if (string.IsNullOrEmpty (Theme)) + return; + try { + if (Directory.Exists (theme)) { + string path = Path.Combine (Theme, "Images"); + if (Directory.Exists (path)) { + foreach (string pic in Directory.GetFiles (path, "*.*", SearchOption.AllDirectories)) { + string resId = $"#{pic.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}"; + using (Stream s = new FileStream (pic, FileMode.Open, FileAccess.Read)) { + if (resId.EndsWith (".svg", StringComparison.OrdinalIgnoreCase)) + sharedPictures[resId] = SvgPicture.CreateSharedPicture (s); + else + sharedPictures[resId] = BmpPicture.CreateSharedPicture (s); + } + } + } + if (Directory.Exists (path)) { + path = Path.Combine (Theme, "DefaultTemplates"); + foreach (string iml in Directory.GetFiles (path, "*.*", SearchOption.AllDirectories)) { + string resId = $"#{iml.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}"; + int mdTok = Instantiator.tryGetGOType (resId.Substring (6, resId.Length - 15)).MetadataToken; + using (Stream s = new FileStream (iml, FileMode.Open, FileAccess.Read)) + DefaultTemplates[mdTok] = new IML.Instantiator (this, s, resId); + } + } + path = Path.Combine (Theme, "IML"); + if (Directory.Exists (path)) { + foreach (string iml in Directory.GetFiles (path, "*.*", SearchOption.AllDirectories)) { + string resId = $"#{iml.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}"; + using (Stream s = new FileStream (iml, FileMode.Open, FileAccess.Read)) + Instantiators[path] = new Instantiator (this, s, path); + } + } + path = Path.Combine (Theme, "ItemTemplates"); + if (Directory.Exists (path)) { + foreach (string iml in Directory.GetFiles (path, "*.*", SearchOption.AllDirectories)) { + string resId = $"#{iml.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}"; + using (Stream s = new FileStream (iml, FileMode.Open, FileAccess.Read)) + ItemTemplates[path] = new ItemTemplate (this, s, path); + } + } + return; + } + using (ZipArchive archive = ZipFile.Open (Theme, ZipArchiveMode.Read)) { + foreach (ZipArchiveEntry entry in archive.Entries.Where (e => e.FullName.StartsWith ("Images"))) { + Console.WriteLine (entry.FullName); + } + foreach (ZipArchiveEntry entry in archive.Entries.Where (e => e.FullName.StartsWith ("IML"))) { + Console.WriteLine (entry.FullName); + } + } + } catch (Exception e) { + throw new Exception ($"[Theme] Error reading theme ({Theme})", e); + } + } + void loadThemeStyle () { + if (string.IsNullOrEmpty (Theme)) + return; + try { + if (Directory.Exists (theme)) { + string stylePath = Directory.GetFiles (theme, "*.style").FirstOrDefault (); + using (Stream s = new FileStream (stylePath, FileMode.Open, FileAccess.Read)) { + using (StyleReader sr = new StyleReader (s)) + sr.Parse (StylingConstants, Styling, stylePath); + } + return; + } + using (ZipArchive archive = ZipFile.Open (Theme, ZipArchiveMode.Read)) { + ZipArchiveEntry zipStyle = archive.Entries.FirstOrDefault (e => e.FullName.EndsWith (".style", StringComparison.OrdinalIgnoreCase)); + if (zipStyle != null) { + using (Stream s = zipStyle.Open ()) { + using (StyleReader sr = new StyleReader (s)) + sr.Parse (StylingConstants, Styling, zipStyle.FullName); + } + } + } + } catch (Exception e) { + throw new Exception ($"[Theme] Error reading theme style ({Theme})", e); + } + } + #endregion #region Load/Save /// @@ -1085,7 +1202,7 @@ namespace Crow #region Mouse and Keyboard Handling MouseCursor cursor = MouseCursor.top_left_arrow; - void loadCursors () + [Obsolete]void loadCursors () { const int minimumSize = 24; @@ -1157,7 +1274,6 @@ namespace Crow XCursor.Cursors [MouseCursor.xterm] = XCursorFile.Load (this, "#Crow.Cursors.xterm").Cursors.First (c => c.Width >= minimumSize); } - Stopwatch lastMouseDown = Stopwatch.StartNew (), mouseRepeatTimer = new Stopwatch (); bool doubleClickTriggered; //next mouse up will trigger a double click MouseButtonEventArgs lastMouseDownEvent; @@ -1491,6 +1607,12 @@ namespace Crow ctxMenuContainer = CreateInstance ("#Crow.ContextMenu.template") as MenuItem; ctxMenuContainer.LayoutChanged += CtxMenuContainer_LayoutChanged; } + protected void disposeContextMenus () { + if (ctxMenuContainer == null) + return; + ctxMenuContainer.LayoutChanged -= CtxMenuContainer_LayoutChanged; + ctxMenuContainer.Dispose (); + } void CtxMenuContainer_LayoutChanged (object sender, LayoutingEventArgs e) { diff --git a/Crow/src/ItemTemplate.cs b/Crow/src/ItemTemplate.cs index cf182b42..d1c28e2b 100644 --- a/Crow/src/ItemTemplate.cs +++ b/Crow/src/ItemTemplate.cs @@ -95,8 +95,8 @@ namespace Crow /// IML fragment to parse /// type this item will be choosen for, or member of the data item /// for hierarchical data, method to call for children fetching - public ItemTemplate (Interface _iface, Stream ImlFragment, string _dataTest, string _dataType, string _fetchDataMethod) - :base(_iface, ImlFragment) + public ItemTemplate (Interface _iface, Stream ImlFragment, string _dataTest = "TypeOf", string _dataType = "default", string _fetchDataMethod = null) + : base(_iface, ImlFragment) { strDataType = _dataType; fetchMethodName = _fetchDataMethod; diff --git a/Crow/src/Widgets/Scroller.cs b/Crow/src/Widgets/Scroller.cs index 9065a51f..314a7503 100644 --- a/Crow/src/Widgets/Scroller.cs +++ b/Crow/src/Widgets/Scroller.cs @@ -259,11 +259,11 @@ namespace Crow if (lt == LayoutingType.Height) { MaxScrollY = child.Slot.Height - cb.Height; if (child.Slot.Height > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / child.Slot.Height); + NotifyValueChanged ("ChildHeightRatio", (double)Slot.Height / child.Slot.Height); } else if (lt == LayoutingType.Width) { MaxScrollX = child.Slot.Width - cb.Width; if (child.Slot.Width > 0) - NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / child.Slot.Width); + NotifyValueChanged ("ChildWidthRatio", (double)Slot.Width / child.Slot.Width); } } void onChildListCleared(object sender, EventArgs e){ diff --git a/Crow/src/Widgets/Shape.cs b/Crow/src/Widgets/Shape.cs index e1f816d5..020b0a71 100644 --- a/Crow/src/Widgets/Shape.cs +++ b/Crow/src/Widgets/Shape.cs @@ -185,9 +185,10 @@ namespace Crow if (size == value) return; size = value; - contentSize = default (Size); + contentSize = default; NotifyValueChangedAuto (size); - RegisterForLayouting (LayoutingType.Sizing); + //RegisterForLayouting (LayoutingType.Sizing); + RegisterForGraphicUpdate (); } } diff --git a/Crow/src/Widgets/Spinner.cs b/Crow/src/Widgets/Spinner.cs index c1cfdbbb..8126f8d5 100644 --- a/Crow/src/Widgets/Spinner.cs +++ b/Crow/src/Widgets/Spinner.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2019 Bruyère Jean-Philippe +// Copyright (c) 2013-2021 Bruyère Jean-Philippe // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) @@ -22,11 +22,17 @@ namespace Crow } void onUp (object sender, MouseButtonEventArgs e) { - Value += this.SmallIncrement; + if (IFace.Ctrl) + Value += SmallIncrement; + else + Value += LargeIncrement; } void onDown (object sender, MouseButtonEventArgs e) { - Value -= this.SmallIncrement; + if (IFace.Ctrl) + Value -= SmallIncrement; + else + Value -= LargeIncrement; } } diff --git a/Crow/src/styling/StyleReader.cs b/Crow/src/styling/StyleReader.cs index f4898b14..fb7c43cc 100644 --- a/Crow/src/styling/StyleReader.cs +++ b/Crow/src/styling/StyleReader.cs @@ -162,8 +162,9 @@ namespace Crow throw new ParserException (line, column, "Unexpected end of statement", resId); ReadChar (); if (targetsClasses.Count == 0) { - //style constants - StylingConstants[currentProperty] = token.ToString (); + //style constants, only the first occurence is kept + if (!StylingConstants.ContainsKey (currentProperty)) + StylingConstants[currentProperty] = token.ToString (); curState = States.classNames; } else { foreach (string tc in targetsClasses) { diff --git a/Samples/PathPainter/Painter.cs b/Samples/PathPainter/Painter.cs new file mode 100644 index 00000000..7e3c97bb --- /dev/null +++ b/Samples/PathPainter/Painter.cs @@ -0,0 +1,203 @@ +using Crow.Cairo; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace Crow +{ + public class Painter : ScrollingObject + { + #region CTOR + protected Painter () { } + public Painter (Interface iface, string style = null) : base (iface, style) { } + #endregion + + public class Point + { + public double X; + public double Y; + } + + public enum DrawMode + { + Select, + Lines, + Rect, + Arc, + } + DrawMode currentDrawMode = DrawMode.Select; + public DrawMode CurrentDrawMode { + get => currentDrawMode; + set { + if (value == currentDrawMode) + return; + currentDrawMode = value; + NotifyValueChanged ("CurrentDrawMode", currentDrawMode); + updateMouseCursor (); + } + } + + void updateMouseCursor () { + if (currentDrawMode == DrawMode.Select) + MouseCursor = MouseCursor.arrow; + else + MouseCursor = MouseCursor.crosshair; + } + + public double[] Zooms => new double[] { 0.5, 1.0, 2.0, 4.0, 8.0, 16.0 }; + + string path; + double strokeWidth; + Size size; + double zoom; + Fill shapeBackground, shapeForeground; + + [DefaultValue(1.0)] + public double Zoom { + get => zoom; + set { + if (zoom == value) + return; + zoom = value; + NotifyValueChangedAuto (zoom); + RegisterForGraphicUpdate (); + updateMaxScrolls (); + } + } + + /// + /// Path expression, for syntax see 'PathParser'. + /// + public string Path { + get { return path; } + set { + if (path == value) + return; + path = value; + contentSize = default (Size); + NotifyValueChangedAuto (path); + RegisterForGraphicUpdate (); + } + } + /// + /// Default stroke width, may be overriden by a 'S' command in the path string. + /// + /// The width of the stoke. + [DefaultValue (1.0)] + public double StrokeWidth { + get { return strokeWidth; } + set { + if (strokeWidth == value) + return; + strokeWidth = value; + contentSize = default (Size); + NotifyValueChangedAuto (strokeWidth); + RegisterForGraphicUpdate (); + } + } + /// + /// View box size in pixel + /// + [DefaultValue ("32,32")] + public Size Size { + get { return size; } + set { + if (size == value) + return; + size = value; + NotifyValueChangedAuto (size); + //RegisterForLayouting (LayoutingType.Sizing); + RegisterForGraphicUpdate (); + updateMaxScrolls (); + } + } + + [DefaultValue ("White")] + public virtual Fill ShapeBackground { + get => shapeBackground; + set { + if (shapeBackground == value) + return; + shapeBackground = value; + NotifyValueChangedAuto (shapeBackground); + RegisterForRedraw (); + } + } + [DefaultValue ("Black")] + public virtual Fill ShapeForeground { + get => shapeForeground; + set { + if (shapeForeground == value) + return; + shapeForeground = value; + NotifyValueChangedAuto (shapeForeground); + RegisterForRedraw (); + } + } + + public override void OnLayoutChanges (LayoutingType layoutType) { + base.OnLayoutChanges (layoutType); + + if (layoutType == LayoutingType.Height) + NotifyValueChanged ("PageHeight", Slot.Height); + else if (layoutType == LayoutingType.Width) + NotifyValueChanged ("PageWidth", Slot.Width); + else + return; + updateMaxScrolls (); + } + public override void onMouseEnter (object sender, MouseMoveEventArgs e) { + base.onMouseEnter (sender, e); + updateMouseCursor (); + } + protected override void onDraw (Context gr) { + base.onDraw (gr); + + if (string.IsNullOrEmpty (path)) + return; + + Rectangle cr = ClientRectangle; + + gr.Save (); + gr.Translate (-ScrollX, -ScrollY); + gr.Scale (Zoom, Zoom); + + Rectangle r = new Rectangle (cr.Position, size); + shapeBackground.SetAsSource (IFace, gr); + gr.Rectangle (r); + gr.Fill (); + + gr.LineWidth = strokeWidth; + ShapeForeground.SetAsSource (IFace, gr, cr); + + using (PathParser parser = new PathParser (path)) + parser.Draw (gr); + + gr.Restore (); + } + + public override void onMouseWheel (object sender, MouseWheelEventArgs e) { + if (e.Delta > 0) + Zoom *= 2.0; + else + Zoom /= 2.0; + e.Handled = true; + base.onMouseWheel (sender, e); + } + + void updateMaxScrolls () { + Rectangle cb = ClientRectangle; + Size scalledSize = size * Zoom; + + MaxScrollX = scalledSize.Width - cb.Width; + if (scalledSize.Width > 0) + NotifyValueChanged ("ChildWidthRatio", (double)cb.Width / scalledSize.Width); + + MaxScrollY = scalledSize.Height - cb.Height; + if (scalledSize.Height > 0) + NotifyValueChanged ("ChildHeightRatio", (double)cb.Height / scalledSize.Height); + } + } +} diff --git a/Samples/PathPainter/PathPainter.csproj b/Samples/PathPainter/PathPainter.csproj new file mode 100644 index 00000000..173ecf80 --- /dev/null +++ b/Samples/PathPainter/PathPainter.csproj @@ -0,0 +1,7 @@ + + + + ui.%(Filename)%(Extension) + + + diff --git a/Samples/PathPainter/Program.cs b/Samples/PathPainter/Program.cs new file mode 100644 index 00000000..5993c852 --- /dev/null +++ b/Samples/PathPainter/Program.cs @@ -0,0 +1,76 @@ +using Crow; +using System; + +namespace PathPainter +{ + class Program : SampleBase + { + static void Main (string[] args) { + using (Program app = new Program ()) + app.Run (); + } + + protected override void OnInitialized () { + base.OnInitialized (); + Load ("#ui.main.crow").DataSource = this; + } + string currentPath = "M 5.5,0.5 L 10.5,10.5 L 0.5,10.5 Z F"; + int currentSize = 11; + double zoom = 1.0; + double strokeWidth = 1.0; + Color foreground = Colors.Black; + Color background = Colors.White; + + public Measure DesignSize => (int)(zoom * currentSize); + + public double StrokeWidth { + get => strokeWidth; + set { + if (strokeWidth == value) + return; + strokeWidth = value; + NotifyValueChanged (strokeWidth); + } + } + public string CurrentPath { + get => currentPath; + set { + if (currentPath == value) + return; + currentPath = value; + NotifyValueChanged (currentPath); + } + } + public Size Size => new Size (currentSize); + public int CurrentSize { + get => currentSize; + set { + if (currentSize == value) + return; + currentSize = value; + NotifyValueChanged (currentSize); + NotifyValueChanged ("Size", (object)new Size (currentSize)); + NotifyValueChanged ("CurrentPath", (object)CurrentPath); + } + } + public Color Foreground { + get => foreground; + set { + if (foreground == value) + return; + foreground = value; + NotifyValueChanged (foreground); + } + } + public Color Background { + get => background; + set { + if (background == value) + return; + background = value; + NotifyValueChanged (background); + } + } + + } +} diff --git a/Samples/PathPainter/ui/Icons/Lines.svg b/Samples/PathPainter/ui/Icons/Lines.svg new file mode 100644 index 00000000..9fb54c4b --- /dev/null +++ b/Samples/PathPainter/ui/Icons/Lines.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Samples/PathPainter/ui/Icons/Rect.svg b/Samples/PathPainter/ui/Icons/Rect.svg new file mode 100644 index 00000000..d7d1dc8a --- /dev/null +++ b/Samples/PathPainter/ui/Icons/Rect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/PathPainter/ui/Icons/Select.svg b/Samples/PathPainter/ui/Icons/Select.svg new file mode 100644 index 00000000..605c0e28 --- /dev/null +++ b/Samples/PathPainter/ui/Icons/Select.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/Samples/PathPainter/ui/Painter.style b/Samples/PathPainter/ui/Painter.style new file mode 100644 index 00000000..02ad3e34 --- /dev/null +++ b/Samples/PathPainter/ui/Painter.style @@ -0,0 +1,3 @@ +DrawModeStyle { + Template="#polytest.ui.iconCheckBox.template"; +} \ No newline at end of file diff --git a/Samples/PathPainter/ui/Spinner.template b/Samples/PathPainter/ui/Spinner.template new file mode 100644 index 00000000..b4baf524 --- /dev/null +++ b/Samples/PathPainter/ui/Spinner.template @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/Samples/PathPainter/ui/colorSelector.template b/Samples/PathPainter/ui/colorSelector.template new file mode 100644 index 00000000..cc12a623 --- /dev/null +++ b/Samples/PathPainter/ui/colorSelector.template @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/Samples/PathPainter/ui/main.crow b/Samples/PathPainter/ui/main.crow new file mode 100644 index 00000000..bb0a6297 --- /dev/null +++ b/Samples/PathPainter/ui/main.crow @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/ShowCase/ShowCase.cs b/Samples/ShowCase/ShowCase.cs index 8c2184b5..a1a5be2a 100644 --- a/Samples/ShowCase/ShowCase.cs +++ b/Samples/ShowCase/ShowCase.cs @@ -21,12 +21,14 @@ namespace ShowCase static void Main () { DbgLogger.IncludeEvents = DbgEvtType.Widget; - DbgLogger.DiscardEvents = DbgEvtType.Focus; + DbgLogger.DiscardEvents = DbgEvtType.Focus | DbgEvtType.IFace; Environment.SetEnvironmentVariable ("FONTCONFIG_PATH", @"C:\Users\Jean-Philippe\source\vcpkg\installed\x64-windows\tools\fontconfig\fonts"); - using (Showcase app = new Showcase ()) + using (Showcase app = new Showcase ()) { + //app.Theme = @"C:\Users\Jean-Philippe\source\Crow\Themes\TestTheme"; app.Run (); + } } public Container crowContainer; diff --git a/Samples/common/SampleBase.cs b/Samples/common/SampleBase.cs index 8307faed..71fb65f1 100644 --- a/Samples/common/SampleBase.cs +++ b/Samples/common/SampleBase.cs @@ -1,19 +1,20 @@ -using System.Net.NetworkInformation; -using System.Runtime.InteropServices; +using Crow; +using Glfw; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.NetworkInformation; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; -using Crow; -using Glfw; namespace Crow { - public class SampleBase : Interface { -#if NETCOREAPP + public class SampleBase : Interface + { +#if NETCOREAPP static IntPtr resolveUnmanaged (Assembly assembly, String libraryName) { switch (libraryName) @@ -31,270 +32,266 @@ namespace Crow System.Runtime.Loader.AssemblyLoadContext.Default.ResolvingUnmanagedDll+=resolveUnmanaged; } #endif - public Version CrowVersion => Assembly.GetAssembly (typeof (Widget)).GetName ().Version; + public Version CrowVersion => Assembly.GetAssembly (typeof (Widget)).GetName ().Version; - #region Test values for Binding - public List Commands; - public int intValue = 500; - VerticalAlignment currentVAlign; + #region Test values for Binding + public List Commands; + public int intValue = 500; + VerticalAlignment currentVAlign; - DirectoryInfo curDir = new DirectoryInfo (Path.GetDirectoryName (Assembly.GetEntryAssembly ().Location)); - public FileSystemInfo[] CurDirectory => curDir.GetFileSystemInfos (); - public string MultilineText = - $"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,\nLorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,"; - //public string MultilineText = $"a\n"; - TextAlignment textAlignment = TextAlignment.Left; - public TextAlignment TextAlignment { - get => textAlignment; - set { - if (textAlignment == value) - return; - textAlignment = value; - NotifyValueChanged (textAlignment); - } - } + DirectoryInfo curDir = new DirectoryInfo (Path.GetDirectoryName (Assembly.GetEntryAssembly ().Location)); + public FileSystemInfo[] CurDirectory => curDir.GetFileSystemInfos (); + public string MultilineText = + $"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,\nLorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,"; + //public string MultilineText = $"a\n"; + TextAlignment textAlignment = TextAlignment.Left; + public TextAlignment TextAlignment { + get => textAlignment; + set { + if (textAlignment == value) + return; + textAlignment = value; + NotifyValueChanged (textAlignment); + } + } - public int IntValue { - get => intValue; - set { - if (IntValue == value) - return; - intValue = value; - NotifyValueChanged ("IntValue", intValue); - } - } - public VerticalAlignment CurrentVAlign { - get => currentVAlign; - set { - if (currentVAlign == value) - return; - currentVAlign = value; - NotifyValueChanged ("CurrentVAlign", currentVAlign); - } - } - void onSpinnerValueChange (object sender, ValueChangeEventArgs e) { - if (e.MemberName != "Value") - return; - intValue = Convert.ToInt32 (e.NewValue); - } - void change_alignment (object sender, EventArgs e) { - RadioButton rb = sender as RadioButton; - if (rb == null) - return; - NotifyValueChanged ("alignment", Enum.Parse (typeof (Alignment), rb.Caption)); - } - public IEnumerable List2 = new List (new string[] - { - "string1", - "string2", - "string3", - "string4", - "string5", - "string6", - "string7", - "string8", - "string8", - "string8", - "string8", - "string8", - "string8", - "string9" - } - ); - public IEnumerable TestList2 { - set { - List2 = value; - NotifyValueChanged ("TestList2", testList); - } - get { return List2; } - } - public class TestClass - { - public string Prop1 { get; set; } - public string Prop2 { get; set; } + public int IntValue { + get => intValue; + set { + if (IntValue == value) + return; + intValue = value; + NotifyValueChanged ("IntValue", intValue); + } + } + public VerticalAlignment CurrentVAlign { + get => currentVAlign; + set { + if (currentVAlign == value) + return; + currentVAlign = value; + NotifyValueChanged ("CurrentVAlign", currentVAlign); + } + } + void onSpinnerValueChange (object sender, ValueChangeEventArgs e) { + if (e.MemberName != "Value") + return; + intValue = Convert.ToInt32 (e.NewValue); + } + void change_alignment (object sender, EventArgs e) { + RadioButton rb = sender as RadioButton; + if (rb == null) + return; + NotifyValueChanged ("alignment", Enum.Parse (typeof (Alignment), rb.Caption)); + } + public IEnumerable List2 = new List (new string[] + { + "string1", + "string2", + "string3", + "string4", + "string5", + "string6", + "string7", + "string8", + "string8", + "string8", + "string8", + "string8", + "string8", + "string9" + } + ); + public IEnumerable TestList2 { + set { + List2 = value; + NotifyValueChanged ("TestList2", testList); + } + get { return List2; } + } + public class TestClass + { + public string Prop1 { get; set; } + public string Prop2 { get; set; } - public override string ToString () - => $"{Prop1}, {Prop2}"; + public override string ToString () + => $"{Prop1}, {Prop2}"; - } - public class TestClassVC : IValueChange - { - public event EventHandler ValueChanged; - public void NotifyValueChanged (object _value, [CallerMemberName] string caller = null) - => ValueChanged.Raise (this, new ValueChangeEventArgs (caller, _value)); - string prop1, prop2; - public string Prop1 { - get => prop1; - set { - if (prop1 == value) - return; - prop1 = value; - NotifyValueChanged (prop1); - } - } - public string Prop2 { - get => prop2; - set { - if (prop2 == value) - return; - prop2 = value; - NotifyValueChanged (prop2); - } + } + public class TestClassVC : IValueChange + { + public event EventHandler ValueChanged; + public void NotifyValueChanged (object _value, [CallerMemberName] string caller = null) + => ValueChanged.Raise (this, new ValueChangeEventArgs (caller, _value)); + string prop1, prop2; + public string Prop1 { + get => prop1; + set { + if (prop1 == value) + return; + prop1 = value; + NotifyValueChanged (prop1); + } + } + public string Prop2 { + get => prop2; + set { + if (prop2 == value) + return; + prop2 = value; + NotifyValueChanged (prop2); + } - } + } - public override string ToString () - => $"{Prop1}, {Prop2}"; + public override string ToString () + => $"{Prop1}, {Prop2}"; - } - TestClass tcInstance;// = new TestClass () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" }; - TestClassVC tcVCInstance;// = new TestClassVC () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" }; - TestClass tcInstance1 = new TestClass () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" }; - TestClassVC tcVCInstance1 = new TestClassVC () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" }; - TestClass tcInstance2 = new TestClass () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" }; - TestClassVC tcVCInstance2 = new TestClassVC () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" }; + } + TestClass tcInstance;// = new TestClass () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" }; + TestClassVC tcVCInstance;// = new TestClassVC () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" }; + TestClass tcInstance1 = new TestClass () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" }; + TestClassVC tcVCInstance1 = new TestClassVC () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" }; + TestClass tcInstance2 = new TestClass () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" }; + TestClassVC tcVCInstance2 = new TestClassVC () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" }; - public TestClass TcInstance { - get => tcInstance; - set { - if (tcInstance == value) - return; - tcInstance = value; - NotifyValueChanged (tcInstance); - } - } - public TestClassVC TcVCInstance { - get => tcVCInstance; - set { - if (tcVCInstance == value) - return; - tcVCInstance = value; - NotifyValueChanged (tcVCInstance); - } - } + public TestClass TcInstance { + get => tcInstance; + set { + if (tcInstance == value) + return; + tcInstance = value; + NotifyValueChanged (tcInstance); + } + } + public TestClassVC TcVCInstance { + get => tcVCInstance; + set { + if (tcVCInstance == value) + return; + tcVCInstance = value; + NotifyValueChanged (tcVCInstance); + } + } - void tcInstance_ChangeProperties_MouseClick (object sender, MouseButtonEventArgs e) - { - } - public void tcInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e) - { - if (TcInstance == tcInstance1) - TcInstance = tcInstance2; - else - TcInstance = tcInstance1; - } - void tcVCInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e) - { - TcVCInstance = new TestClassVC () { Prop1 = "prop1 value changed", Prop2 = "prop2 value changed" }; - } + void tcInstance_ChangeProperties_MouseClick (object sender, MouseButtonEventArgs e) { + } + public void tcInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e) { + if (TcInstance == tcInstance1) + TcInstance = tcInstance2; + else + TcInstance = tcInstance1; + } + void tcVCInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e) { + TcVCInstance = new TestClassVC () { Prop1 = "prop1 value changed", Prop2 = "prop2 value changed" }; + } - public IEnumerable List3 = new List (new TestClass[] - { - new TestClass { Prop1 = "string1", Prop2="prop2-1" }, - new TestClass { Prop1 = "string2", Prop2="prop2-2" }, - new TestClass { Prop1 = "string3", Prop2="prop2-3" }, - } - ); - public IEnumerable TestList3Props1 => List3.Select (sc => sc.Prop1).ToList (); - public IEnumerable TestList3 { - set { - List3 = value; - NotifyValueChanged ("TestList3", testList); - } - get { return List3; } - } - string prop1; - public string TestList3SelProp1 { - get => prop1; - set { - if (prop1 == value) - return; - prop1 = value; + public IEnumerable List3 = new List (new TestClass[] + { + new TestClass { Prop1 = "string1", Prop2="prop2-1" }, + new TestClass { Prop1 = "string2", Prop2="prop2-2" }, + new TestClass { Prop1 = "string3", Prop2="prop2-3" }, + } + ); + public IEnumerable TestList3Props1 => List3.Select (sc => sc.Prop1).ToList (); + public IEnumerable TestList3 { + set { + List3 = value; + NotifyValueChanged ("TestList3", testList); + } + get { return List3; } + } + string prop1; + public string TestList3SelProp1 { + get => prop1; + set { + if (prop1 == value) + return; + prop1 = value; - NotifyValueChanged (prop1); - } - } + NotifyValueChanged (prop1); + } + } - string selString; - public string TestList2SelectedString { - get => selString; - set { - if (selString == value) - return; - selString = value; - NotifyValueChanged (selString); - } - } + string selString; + public string TestList2SelectedString { + get => selString; + set { + if (selString == value) + return; + selString = value; + NotifyValueChanged (selString); + } + } - IList testList = (IList)FastEnumUtility.FastEnum.GetValues ().ToList ();//.ColorDic.Values//.OrderBy(c=>c.Hue) - //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation) - //.ToList (); - public IList TestList { - set { - testList = value; - NotifyValueChanged ("TestList", testList); - } - get { return testList; } - } - void OnClear (object sender, MouseButtonEventArgs e) => TestList = null; - void OnLoadList (object sender, MouseButtonEventArgs e) => TestList = (IList)FastEnumUtility.FastEnum.GetValues ().ToList (); + IList testList = (IList)FastEnumUtility.FastEnum.GetValues ().ToList ();//.ColorDic.Values//.OrderBy(c=>c.Hue) + //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation) + //.ToList (); + public IList TestList { + set { + testList = value; + NotifyValueChanged ("TestList", testList); + } + get { return testList; } + } + void OnClear (object sender, MouseButtonEventArgs e) => TestList = null; + void OnLoadList (object sender, MouseButtonEventArgs e) => TestList = (IList)FastEnumUtility.FastEnum.GetValues ().ToList (); - string curSources = ""; - public string CurSources { - get { return curSources; } - set { - if (value == curSources) - return; - curSources = value; - NotifyValueChanged (curSources); - } - } - bool boolVal = true; - public bool BoolVal { - get { return boolVal; } - set { - if (boolVal == value) - return; - boolVal = value; - NotifyValueChanged (boolVal); - } - } + string curSources = ""; + public string CurSources { + get { return curSources; } + set { + if (value == curSources) + return; + curSources = value; + NotifyValueChanged (curSources); + } + } + bool boolVal = true; + public bool BoolVal { + get { return boolVal; } + set { + if (boolVal == value) + return; + boolVal = value; + NotifyValueChanged (boolVal); + } + } #endregion - protected override void OnInitialized () - { - Commands = new List { - new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 1 clicked")) { Caption = "Action 1" }, - new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 2 clicked")) { Caption = "Action 2" }, - new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 3 clicked")) { Caption = "Action 3" } - }; - base.OnInitialized (); - } + protected override void OnInitialized () { + Commands = new List { + new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 1 clicked")) { Caption = "Action 1" }, + new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 2 clicked")) { Caption = "Action 2" }, + new Command(() => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 3 clicked")) { Caption = "Action 3" } + }; + base.OnInitialized (); + } - public override bool OnKeyDown (Key key) { - - switch (key) { - case Key.F5: - Load ("Interfaces/Divers/testFileDialog.crow").DataSource = this; - return true; - case Key.F6: - Load ("Interfaces/Divers/0.crow").DataSource = this; - return true; - case Key.F7: - Load ("Interfaces/Divers/perfMeasures.crow").DataSource = this; - return true; - case Key.F2: - if (IsKeyDown (Key.LeftShift)) - DbgLogger.Reset (); - DbgLogger.Save (this); - return true; - } - return base.OnKeyDown (key); - } - } + public override bool OnKeyDown (Key key) { + + switch (key) { + case Key.F5: + Load ("Interfaces/Divers/testFileDialog.crow").DataSource = this; + return true; + case Key.F6: + Load ("Interfaces/Divers/0.crow").DataSource = this; + return true; + case Key.F7: + Load ("Interfaces/Divers/perfMeasures.crow").DataSource = this; + return true; + case Key.F2: + if (IsKeyDown (Key.LeftShift)) + DbgLogger.Reset (); + DbgLogger.Save (this); + return true; + } + return base.OnKeyDown (key); + } + } } \ No newline at end of file diff --git a/Samples/common/ui/Interfaces/Divers/chess.crow b/Samples/common/ui/Interfaces/Divers/chess.crow new file mode 100644 index 00000000..30b86d46 --- /dev/null +++ b/Samples/common/ui/Interfaces/Divers/chess.crow @@ -0,0 +1,19 @@ + + + +