]> O.S.I.I.S - jp/crow.git/commitdiff
implement theme from directory
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 2 Mar 2021 10:57:39 +0000 (11:57 +0100)
committerj-p <jp_bruyere@hotmail.com>
Tue, 2 Mar 2021 11:01:06 +0000 (12:01 +0100)
30 files changed:
Crow.sln
Crow/Crow.csproj
Crow/src/2d/Size.cs
Crow/src/DebugUtils/DebugLogger.cs
Crow/src/Fill/BmpPicture.cs
Crow/src/Fill/SvgPicture.cs
Crow/src/IML/CompilerServices.cs
Crow/src/IML/Instantiator.cs
Crow/src/Interface.cs
Crow/src/ItemTemplate.cs
Crow/src/Widgets/Scroller.cs
Crow/src/Widgets/Shape.cs
Crow/src/Widgets/Spinner.cs
Crow/src/styling/StyleReader.cs
Samples/PathPainter/Painter.cs [new file with mode: 0644]
Samples/PathPainter/PathPainter.csproj [new file with mode: 0644]
Samples/PathPainter/Program.cs [new file with mode: 0644]
Samples/PathPainter/ui/Icons/Lines.svg [new file with mode: 0644]
Samples/PathPainter/ui/Icons/Rect.svg [new file with mode: 0644]
Samples/PathPainter/ui/Icons/Select.svg [new file with mode: 0644]
Samples/PathPainter/ui/Painter.style [new file with mode: 0644]
Samples/PathPainter/ui/Spinner.template [new file with mode: 0644]
Samples/PathPainter/ui/colorSelector.template [new file with mode: 0644]
Samples/PathPainter/ui/main.crow [new file with mode: 0644]
Samples/ShowCase/ShowCase.cs
Samples/common/SampleBase.cs
Samples/common/ui/Interfaces/Divers/chess.crow [new file with mode: 0644]
Themes/TestTheme/DefaultTemplates/Crow/Window.template [new file with mode: 0644]
Themes/TestTheme/Images/Crow/Icons/checkbox.svg [new file with mode: 0644]
Themes/TestTheme/theme.style [new file with mode: 0644]

index 473cfabce8f49f941f839dbe5895674f22cebea4..afc71387a60e787e64056f28abdbffa366137dbd 100644 (file)
--- 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}
index 840469c89220740edd5d4644f6de340a05e1ed4d..f09f66dc8636f2f204d381645e878be7d9533c3a 100644 (file)
                <PackageProjectUrl>https://github.com/jpbruyere/Crow/wiki</PackageProjectUrl>
                <PackageLicenseExpression>MIT</PackageLicenseExpression>
                <PackageIcon>crow.png</PackageIcon>
-               <PackageCopyright>Copyright 2013-2020</PackageCopyright>
+               <PackageCopyright>Copyright 2013-2021</PackageCopyright>
                <PackageReleaseNotes>
                </PackageReleaseNotes>
                <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
                <GenerateDocumentationFile>true</GenerateDocumentationFile>
                <NoWarn>$(NoWarn);1591;1587;1570;1572;1573;1574</NoWarn>
-               <DefineConstants>DESIGN_MODE;_MEASURE_TIME</DefineConstants>            
+               <DefineConstants>_DESIGN_MODE;_MEASURE_TIME</DefineConstants>           
                <EnableDefaultItems>false</EnableDefaultItems>
                <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
                <!--<AllowUnsafeBlocks>true</AllowUnsafeBlocks>-->
index 935ff656a70f9a2a52f6d38a7fcc265ac47c86cc..ee023285b837cd2091340c532dc27d99f6e7f414 100644 (file)
@@ -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
 
 
index 0c5d7f6c0c41805f3c4d1d1edef449747080e446..0696c4e83a86db38336cdace3d240f0848952bb4 100644 (file)
@@ -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,
index 70f36d3f76d3a35434b2fd488239633ecfbf2889..0f67323d2810f1dd4fbe8916ba8d1501d3595607 100644 (file)
@@ -13,44 +13,48 @@ namespace Crow
        /// <summary>
        /// Derived from FILL for loading and drawing bitmaps in the interface
        /// </summary>
-       public class BmpPicture : Picture
-       {
+       public class BmpPicture : Picture {
                byte[] image = null;
 
                #region CTOR
                /// <summary>
                /// Initializes a new instance of BmpPicture.
                /// </summary>
-               public BmpPicture () {}
+               public BmpPicture () { }
                /// <summary>
                /// Initializes a new instance of BmpPicture by loading the image pointed by the path argument
                /// </summary>
                /// <param name="path">image path, may be embedded</param>
-               public BmpPicture (string path) : base(path) { }
+               public BmpPicture (string path) : base (path) { }
                #endregion
                /// <summary>
                /// load the image for rendering from the path given as argument
                /// </summary>
-               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))
                {
index f461a54420114fb559fcdd1b3a88ace915796eba..4f378be44972356c5800f91211debee47707793c 100644 (file)
@@ -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));
index c1d4edd7ce0bc334cea833faa5b3a41c499baa5e..d8033b2831361622c9c1c61cfd1bd651abb14947 100644 (file)
@@ -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) {
index 3a249a1ed0aea8bb5291cd13d6c7b124b2a8a498..a7ca4f2f3271f3ab2c15cd6722e7aa2f0c5e9770 100644 (file)
@@ -1568,7 +1568,7 @@ namespace Crow.IML {
                /// </remarks>
                /// <returns>the corresponding type object</returns>
                /// <param name="typeName">graphic object type name without its namespace</param>
-               Type tryGetGOType (string typeName){
+               internal static Type tryGetGOType (string typeName){
                        if (knownGOTypes.ContainsKey (typeName))
                                return knownGOTypes [typeName];
                        Type t = Type.GetType ("Crow." + typeName);
index 895c2c4c73735d2368ed2f285ae9bf07923efa53..5dbac92f4d7d9938e116b0fcbc26f6d914f67baf 100644 (file)
@@ -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
                /// </summary>
                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
                /// <summary>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.
                /// </summary>
-               public Dictionary<String, Instantiator> Instantiators = new Dictionary<string, Instantiator>();
-               public Dictionary<String, Instantiator> Templates = new Dictionary<string, Instantiator> ();
+               public Dictionary<String, Instantiator> Instantiators;          
                /// <summary>
                /// default templates dic by metadata token
                /// </summary>
-               public Dictionary<int, Instantiator> DefaultTemplates = new Dictionary<int, Instantiator> ();
+               public Dictionary<int, Instantiator> DefaultTemplates;
                /// <summary>
                /// Item templates stored with their index
                /// </summary>
-               public Dictionary<String, ItemTemplate> ItemTemplates = new Dictionary<string, ItemTemplate> ();
+               public Dictionary<String, ItemTemplate> ItemTemplates;
 
                public List<CrowThread> CrowThreads = new List<CrowThread>();//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);
                /// <summary>Store one loader per StyleKey</summary>
-               public Dictionary<String, LoaderInvoker> DefaultValuesLoader = new Dictionary<string, LoaderInvoker>();
+               public Dictionary<String, LoaderInvoker> DefaultValuesLoader;
                /// <summary>Store dictionnary of member/value per StyleKey</summary>
                public Dictionary<string, Style> Styling;
                /// <summary>
@@ -498,11 +503,9 @@ namespace Crow
                public Dictionary<string, string> StylingConstants;
                /// <summary> parse all styling data's during application startup and build global Styling Dictionary </summary>
                protected virtual void loadStyling() {
-                       StylingConstants = new Dictionary<string, string> ();
-                       Styling = new Dictionary<string, Style> ();
-
                        //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<string, string> (initCapacity);
+                       Styling = new Dictionary<string, Style> (initCapacity);
+                       DefaultValuesLoader = new Dictionary<string, LoaderInvoker> (initCapacity);
+                       Instantiators = new Dictionary<string, Instantiator> (initCapacity);
+                       DefaultTemplates = new Dictionary<int, Instantiator> (initCapacity);                    
+                       ItemTemplates = new Dictionary<string, ItemTemplate> (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
                /// <summary>
@@ -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)
                {
index cf182b42c0b1cf5df027959a10c35cab82f11dd8..d1c28e2b2f7674e1218113b75452190523823429 100644 (file)
@@ -95,8 +95,8 @@ namespace Crow
                /// <param name="ImlFragment">IML fragment to parse</param>
                /// <param name="_dataType">type this item will be choosen for, or member of the data item</param>
                /// <param name="_fetchDataMethod">for hierarchical data, method to call for children fetching</param>
-               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;
index 9065a51f5f269971be2b86290e71211560a90306..314a7503ea6ca66e80c7ec4e7834b8ae64123b59 100644 (file)
@@ -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){
index e1f816d514a8b806aa2e42c5f402cab52c2752c2..020b0a711d35bae37fe17a972862498a13350367 100644 (file)
@@ -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 ();
                        }
                }
 
index c1cfdbbb7706a7b9d5324a7ab0b4c1cd9dfd0bed..8126f8d5c8957206e4452fad5f282a339676829a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2019  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 
@@ -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;
                }
 
        }
index f4898b14be89b8c2312dabfd78a9a5d898beb839..fb7c43cc16c155e982d614ab8c58e9ce7a257a9c 100644 (file)
@@ -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 (file)
index 0000000..7e3c97b
--- /dev/null
@@ -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 ();
+            }
+        }
+
+               /// <summary>
+               /// Path expression, for syntax see 'PathParser'.
+               /// </summary>
+               public string Path {
+                       get { return path; }
+                       set {
+                               if (path == value)
+                                       return;
+                               path = value;
+                               contentSize = default (Size);
+                               NotifyValueChangedAuto (path);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               /// <summary>
+               /// Default stroke width, may be overriden by a 'S' command in the path string.
+               /// </summary>
+               /// <value>The width of the stoke.</value>
+               [DefaultValue (1.0)]
+               public double StrokeWidth {
+                       get { return strokeWidth; }
+                       set {
+                               if (strokeWidth == value)
+                                       return;
+                               strokeWidth = value;
+                               contentSize = default (Size);
+                               NotifyValueChangedAuto (strokeWidth);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               /// <summary>
+               /// View box size in pixel
+               /// </summary>
+               [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 (file)
index 0000000..173ecf8
--- /dev/null
@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+       <ItemGroup>
+               <EmbeddedResource Include="ui\**\*.*">
+                       <LogicalName>ui.%(Filename)%(Extension)</LogicalName>
+               </EmbeddedResource>
+       </ItemGroup>
+</Project>
diff --git a/Samples/PathPainter/Program.cs b/Samples/PathPainter/Program.cs
new file mode 100644 (file)
index 0000000..5993c85
--- /dev/null
@@ -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 (file)
index 0000000..9fb54c4
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#dddddd" d="M1 11.9l-1 4.1 4.1-1 9.2-9.2-3.1-3.1-9.2 9.2zM1.5 15l-0.4-0.5 0.4-2 2 2-2 0.5zM10.9 4.4l-8.1 8-0.6-0.6 8.1-8 0.6 0.6z"></path>
+<path fill="#dddddd" d="M15.3 0.7c-1.1-1.1-2.6-0.5-2.6-0.5l-1.5 1.5 3.1 3.1 1.5-1.5c0-0.1 0.6-1.5-0.5-2.6zM13.4 1.6l-0.5-0.5c0.6-0.6 1.1-0.1 1.1-0.1l-0.6 0.6z"></path>
+</svg>
diff --git a/Samples/PathPainter/ui/Icons/Rect.svg b/Samples/PathPainter/ui/Icons/Rect.svg
new file mode 100644 (file)
index 0000000..d7d1dc8
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#dddddd" d="M15 1h-14v14h14v-14zM14 14h-12v-12h12v12z"></path>
+</svg>
diff --git a/Samples/PathPainter/ui/Icons/Select.svg b/Samples/PathPainter/ui/Icons/Select.svg
new file mode 100644 (file)
index 0000000..605c0e2
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#dddddd" d="M11.6 5c-0.2 0-0.5 0-0.6 0 0-0.2-0.2-0.6-0.4-0.8s-0.6-0.4-1.1-0.4c-0.2 0-0.4 0-0.6 0.1-0.1-0.2-0.2-0.3-0.3-0.5-0.2-0.2-0.5-0.4-1.1-0.4-0.2 0-0.4 0-0.5 0.1v-1.7c0-0.6-0.4-1.4-1.4-1.4-0.4 0-0.8 0.2-1.1 0.4-0.5 0.6-0.5 1.4-0.5 1.4v4.3c-0.6 0.1-1.1 0.3-1.4 0.6-0.6 0.7-0.6 1.6-0.6 2.8 0 0.2 0 0.5 0 0.7 0 1.4 0.7 2.1 1.4 2.8l0.3 0.4c1.3 1.2 2.4 1.6 5.1 1.6 2.9 0 4.2-1.6 4.2-5.1v-2.5c0-0.7-0.2-2.1-1.4-2.4zM12 7.4v2.6c0 3.4-1.3 4.1-3.2 4.1-2.4 0-3.3-0.3-4.3-1.3-0.1-0.1-0.2-0.2-0.4-0.4-0.7-0.8-1.1-1.2-1.1-2.2 0-0.2 0-0.5 0-0.7 0-1 0-1.7 0.3-2.1 0.1-0.1 0.4-0.2 0.7-0.2v0.5l-0.3 1.5c0 0.1 0 0.1 0.1 0.2s0.2 0 0.2 0l1-1.2c0-0.1 0-0.2 0-0.2v-6.2c0-0.1 0-0.5 0.2-0.7 0.1 0 0.2-0.1 0.4-0.1 0.3 0 0.4 0.3 0.4 0.4v3.1c0 0 0 0 0 0v1.2c0 0.3 0.2 0.6 0.5 0.6s0.5-0.3 0.5-0.5v-1.3c0 0 0 0 0 0 0-0.1 0.1-0.5 0.5-0.5 0.3 0 0.5 0.1 0.5 0.4v1.3c0 0.3 0.2 0.6 0.5 0.6s0.5-0.3 0.5-0.5v-0.7c0-0.1 0.1-0.3 0.5-0.3 0.2 0 0.3 0.1 0.3 0.1 0.2 0.1 0.2 0.4 0.2 0.4v0.8c0 0.3 0.2 0.5 0.4 0.5 0.3 0 0.5-0.1 0.5-0.4 0-0.1 0.1-0.2 0.2-0.3 0 0 0.1 0 0.2 0 0.6 0.2 0.7 1.2 0.7 1.5 0-0.1 0-0.1 0 0z"></path>
+</svg>
diff --git a/Samples/PathPainter/ui/Painter.style b/Samples/PathPainter/ui/Painter.style
new file mode 100644 (file)
index 0000000..02ad3e3
--- /dev/null
@@ -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 (file)
index 0000000..b4baf52
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<VerticalStack>
+       <Label Text="{./Caption}"/>
+       <Border Style="ControlBorder" Background="{./Background}" CornerRadius="{./CornerRadius}">
+               <HorizontalStack Spacing="1">
+                       <TextBox Style="ControlEditableText" Foreground="{./Foreground}" Font="{./Font}" Width="Stretched"
+                               Text="{²./Value}" TextAlignment="Right" />
+                       <VerticalStack Width="16" Height="Stretched" Spacing="0" Margin="0">
+                               <Shape KeepProportions="false" Margin="1" Style="ArrowBut" Height="50%" MouseDown="./onUp" Size="10,10" Path="M 4.5,0.5 L 9.5,9.5 L 0.5,9.5 Z F"/>
+                               <Shape KeepProportions="false" Margin="1" Style="ArrowBut"      Height="50%" MouseDown="./onDown" Size="10,10" Path="M 0.5,0.5 L 9.5,0.5 L 4.5,9.5 Z F"/>
+                       </VerticalStack>
+               </HorizontalStack>
+       </Border>
+</VerticalStack>
\ No newline at end of file
diff --git a/Samples/PathPainter/ui/colorSelector.template b/Samples/PathPainter/ui/colorSelector.template
new file mode 100644 (file)
index 0000000..cc12a62
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<CheckBox Caption="{./Caption}" IsChecked="{²./IsPopped}" Foreground="{./Foreground}" Background="{./Background}">
+       <Template>
+               <Border Style="ControlBorder" CornerRadius="{./CornerRadius}">
+                       <HorizontalStack Spacing="10" Margin="5">
+                               <Label Style="ControlCaption" Text="{./Caption}" />
+                               <Border Foreground="White" Width="30" Height="20" Background="{./Background}" CornerRadius="5"/>
+                       </HorizontalStack>
+               </Border>
+       </Template>
+</CheckBox>            
\ No newline at end of file
diff --git a/Samples/PathPainter/ui/main.crow b/Samples/PathPainter/ui/main.crow
new file mode 100644 (file)
index 0000000..bb0a629
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<HorizontalStack Background="DarkGrey" >
+       <VerticalStack>
+               <HorizontalStack Height="Fit">
+                       <EnumSelector Fit="true" Caption="Draw Mode" EnumValue="{²../../painter.CurrentDrawMode}" />
+                       <ComboBox Data="{../../painter.Zooms}" SelectedItem="{²../../painter.Zoom}" Width="60"/>
+               </HorizontalStack>
+               <HorizontalStack>                       
+                       <Border Foreground="Black" Width="Stretched" Height="Stretched" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Top">
+                               <Painter Name="painter" ShapeForeground="{Foreground}" ShapeBackground="{Background}"
+                                                Zoom="1"
+                                                Size="{Size}" Path="{²CurrentPath}" StrokeWidth="{StrokeWidth}"/>
+                       </Border>
+                       <ScrollBar Value="{²../painter.ScrollY}"
+                                       LargeIncrement="{../painter.PageHeight}" SmallIncrement="1"
+                                       CursorRatio="{../painter.ChildHeightRatio}" Maximum="{../painter.MaxScrollY}" />
+               </HorizontalStack>
+               <ScrollBar Style="HScrollBar" Value="{²../painter.ScrollX}"
+                               LargeIncrement="{../painter.PageWidth}" SmallIncrement="1"
+                               CursorRatio="{../painter.ChildWidthRatio}" Maximum="{../painter.MaxScrollX}" />         
+       </VerticalStack>
+       <Splitter/>
+       <VerticalStack Margin="2" Spacing="2">
+               <TextBox Width="Stretched" Text="{²CurrentPath}"/>
+               <HorizontalStack Height="Fit">
+                       <Spinner Caption="Stroke Width" SmallIncrement="0.1" LargeIncrement="0.5" Value="{²StrokeWidth}" Width="Fit" Template="#ui.Spinner.template"/>
+                       <Spinner Caption="Size" Value="{²CurrentSize}" Width="Fit" Template="#ui.Spinner.template"/>
+                       <Popper Caption="Foreground" Background="{Foreground}" Fit="True" Template="#ui.colorSelector.template">
+                               <ColorPicker CurrentColor="{²Foreground}" Background="Onyx" Width="{../PopWidth}"/>
+                       </Popper>
+                       <Popper Caption="Background" Background="{Background}" Fit="True" Template="#ui.colorSelector.template">
+                               <ColorPicker CurrentColor="{²Background}" Background="Onyx" Width="{../PopWidth}"/>
+                       </Popper>
+               </HorizontalStack>
+               <Group Height="200" Background="Jet">
+                       <Shape Left="23" Top="9" Margin="0" Width="16" Height="16" Foreground="{Foreground}" Background="{Background}" Size="{Size}" Path="{CurrentPath}" StrokeWidth="{StrokeWidth}"/>
+                       <Shape Left="17" Top="31" Margin="0" Width="32" Height="32" Foreground="{Foreground}" Background="{Background}" Size="{Size}" Path="{CurrentPath}" StrokeWidth="{StrokeWidth}"/>
+                       <Shape Left="65" Top="1" Margin="0" Width="64" Height="64" Foreground="{Foreground}" Background="{Background}" Size="{Size}" Path="{CurrentPath}" StrokeWidth="{StrokeWidth}"/>
+                       <Shape Left="1" Top="66" Margin="0" Width="128" Height="128" Foreground="{Foreground}" Background="{Background}" Size="{Size}" Path="{CurrentPath}" StrokeWidth="{StrokeWidth}"/>
+               </Group>
+       
+       </VerticalStack>
+</HorizontalStack>
index 8c2184b5e98e03d001743872a72b9b098d452ab6..a1a5be2adbbdd8e42fee61d7fd1a4b209d29ee18 100644 (file)
@@ -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;
index 8307faed06ce435d9f2a73644237a62485ac5467..71fb65f1c361aa24e12fde716f52175a2b3227de 100644 (file)
@@ -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<Command> Commands;
-               public int intValue = 500;
-               VerticalAlignment currentVAlign;
+        #region Test values for Binding
+        public List<Command> 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<String> List2 = new List<string> (new string[]
-                       {
-                               "string1",
-                               "string2",
-                               "string3",
-                               "string4",
-                               "string5",
-                               "string6",
-                               "string7",
-                               "string8",
-                               "string8",
-                               "string8",
-                               "string8",
-                               "string8",
-                               "string8",
-                               "string9"
-                       }
-               );
-               public IEnumerable<String> 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<String> List2 = new List<string> (new string[]
+            {
+                "string1",
+                "string2",
+                "string3",
+                "string4",
+                "string5",
+                "string6",
+                "string7",
+                "string8",
+                "string8",
+                "string8",
+                "string8",
+                "string8",
+                "string8",
+                "string9"
+            }
+        );
+        public IEnumerable<String> 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<ValueChangeEventArgs> 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<ValueChangeEventArgs> 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<TestClass> List3 = new List<TestClass> (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<string> TestList3Props1 => List3.Select (sc => sc.Prop1).ToList ();
-               public IEnumerable<TestClass> 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<TestClass> List3 = new List<TestClass> (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<string> TestList3Props1 => List3.Select (sc => sc.Prop1).ToList ();
+        public IEnumerable<TestClass> 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<Colors> testList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors> ().ToList ();//.ColorDic.Values//.OrderBy(c=>c.Hue)
-                                                                                                                                                                                                               //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation)
-                                                                                                                                                                                                               //.ToList ();
-               public IList<Colors> 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<Colors>)FastEnumUtility.FastEnum.GetValues<Colors> ().ToList ();
+        IList<Colors> testList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors> ().ToList ();//.ColorDic.Values//.OrderBy(c=>c.Hue)
+                                                                                                        //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation)
+                                                                                                        //.ToList ();
+        public IList<Colors> 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<Colors>)FastEnumUtility.FastEnum.GetValues<Colors> ().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<Command> {
-                               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<Command> {
+                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 (file)
index 0000000..30b86d4
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<HorizontalStack Height="Fit" Background="vgradient|0:Grey|0.3:Jet|0.7:Jet|1:Black" VerticalAlignment="Bottom" Margin="10">
+       <CheckBox Caption="Hint" IsChecked="{²EnableHint}"/>   
+       <Button Caption="Undo" MouseClick="onUndoClick"/>
+       <Button Caption="N" MouseClick="onNewGameClick"/>
+       <Button Caption="Options" MouseClick="onOptionsClick"/>
+       <Widget Width="Stretched" Height="1"/>
+       <Button Caption="Quit" MouseClick="onQuitClick"/>
+       <VerticalStack Style="hsStatus" >
+               <Label Style="labStatus" Text="State:"/>
+               <Label Style="labStatus2" Text="{CurrentState}" />              
+       </VerticalStack >
+       <VerticalStack Style="hsStatus" >
+               <Label Style="labStatus" Text="Hover:"/>
+               <Label Style="labStatus2" Text="{SelCell}"/>
+       </VerticalStack>
+       <Image Width="30" Height="20" Path="#Crow.Icons.IconAlerte.svg" Visible="{StockfishNotFound}"/>
+       <Label Text="Stockfish not found" Font="droid bold, 10" Visible="{StockfishNotFound}"/>
+</HorizontalStack>
diff --git a/Themes/TestTheme/DefaultTemplates/Crow/Window.template b/Themes/TestTheme/DefaultTemplates/Crow/Window.template
new file mode 100644 (file)
index 0000000..15e258e
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<Border Name="SizeHandle" Style="winBorder"  CornerRadius="{./CornerRadius}" Background="{./Background}" >
+       <Container Name="Content" MinimumSize="0,0" />
+</Border>
diff --git a/Themes/TestTheme/Images/Crow/Icons/checkbox.svg b/Themes/TestTheme/Images/Crow/Icons/checkbox.svg
new file mode 100644 (file)
index 0000000..789d055
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="svg2"
+   viewBox="0 0 64 64"
+   height="64"
+   width="64"
+   sodipodi:docname="checkbox.svg"
+   inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1600"
+     inkscape:window-height="877"
+     id="namedview10"
+     showgrid="false"
+     inkscape:zoom="11.09375"
+     inkscape:cx="39.255379"
+     inkscape:cy="32"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <defs
+     id="defs4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="False">
+    <rect
+       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3.38882232;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="background-0"
+       width="50.832325"
+       height="50.832325"
+       x="7.1542463"
+       y="10.990663" />
+  </g>
+  <g
+     id="True">
+    <rect
+       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3.38882232;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="background"
+       width="50.832333"
+       height="50.832333"
+       x="7.1542463"
+       y="10.990663" />
+    <path
+       style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.819638;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 26.899301,40.904569 c 0,0 -4.557927,-12.130528 -17.039071,-16.083111 C 23.373133,46.449804 25.903228,60.091295 25.903228,60.091295 36.930826,34.779909 41.845629,25.237669 55.533596,15.957127 38.337726,22.362558 33.488807,27.75341 26.899301,40.904569 Z"
+       id="checkmark" />
+  </g>
+</svg>
diff --git a/Themes/TestTheme/theme.style b/Themes/TestTheme/theme.style
new file mode 100644 (file)
index 0000000..dfd5099
--- /dev/null
@@ -0,0 +1,23 @@
+ControlBackground = "DarkRed";
+ControlBorderColor = "White";
+ControlBorderWidth = "2";
+ControlCaptionColor = "White";
+ControlCaptionHoverColor = "RoyalBlue";
+ControlCornerRadius = "5";
+ControlInsideMargin = "5";
+ControlHighlight = "RoyalBlue";
+IconSize = "16";
+IconMargin = "2";
+ToggleIconSize = "32";
+
+TooltipBackground = "Khaki";
+TooltipForeground = "DimGrey";
+TooltipMargin = "3";
+
+WindowBackgroundColor = "DarkGrey";
+WindowBorderColor = "White";
+WindowBorderWidth = "2";
+WindowTitleBarBackground = "vgradient|0:Onyx|1:Green";
+WindowTitleBarForeground = "Black";
+
+MenuBackground = "DarkGrey";
\ No newline at end of file