]> O.S.I.I.S - jp/crow.git/commitdiff
DebugLog, event bindings resolutions, enumSelector bitfields, wip
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 2 Apr 2021 05:54:52 +0000 (07:54 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Fri, 2 Apr 2021 05:54:52 +0000 (07:54 +0200)
66 files changed:
Crow.sln
Crow/Crow.csproj
Crow/Default.style
Crow/Templates/TabView.template
Crow/src/Colors.cs
Crow/src/Command.cs
Crow/src/DebugUtils/DbgEvent.cs
Crow/src/DebugUtils/DbgEventSource.cs
Crow/src/DebugUtils/DbgEventTypeColors.cs [deleted file]
Crow/src/DebugUtils/DbgEventWidget (copie).cs [deleted file]
Crow/src/DebugUtils/DbgEvtType.cs [new file with mode: 0644]
Crow/src/DebugUtils/DbgLayoutEvent.cs [new file with mode: 0644]
Crow/src/DebugUtils/DbgWidgetEvent.cs [new file with mode: 0644]
Crow/src/DebugUtils/DbgWidgetRecord.cs
Crow/src/DebugUtils/DebugLogger.cs
Crow/src/IML/Instantiator.cs
Crow/src/Interface.cs
Crow/src/Mono.Cairo/Context.cs
Crow/src/Widgets/Button.cs
Crow/src/Widgets/EnumSelector.cs
Crow/src/Widgets/GenericStack.cs
Crow/src/Widgets/Group.cs
Crow/src/Widgets/MenuItem.cs
Crow/src/Widgets/ScrollBar.cs
Crow/src/Widgets/ScrollingObject.cs
Crow/src/Widgets/Slider.cs
Crow/src/Widgets/TabView.cs
Crow/src/Widgets/Widget.cs
Crow/src/Widgets/Wrapper.cs
CrowDbgShared/CrowDbgShared.csproj [new file with mode: 0644]
CrowDbgShared/src/SharedDelegates.cs [new file with mode: 0644]
Directory.Build.props
Samples/BasicTests/BasicTests.cs
Samples/ControlLib/Class1.cs [deleted file]
Samples/ControlLib/ControlLib.csproj [deleted file]
Samples/CrowDebugger/CrowDebugAssemblyLoadContext.cs [new file with mode: 0644]
Samples/CrowDebugger/CrowDebugger.csproj [new file with mode: 0644]
Samples/CrowDebugger/Program.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/DbgEventWidget.cs [deleted file]
Samples/DebugLogAnalyzer/DbgLogViewer.cs [deleted file]
Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj
Samples/DebugLogAnalyzer/Program.cs [deleted file]
Samples/DebugLogAnalyzer/src/DbgEventWidget.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/DbgLogViewer.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/DebugInterface.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/Editor.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/Extensions.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/src/Program.cs [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/Button.template [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/DbgEventTreeItems.itemp
Samples/DebugLogAnalyzer/ui/DbgEvtTooltip.crow
Samples/DebugLogAnalyzer/ui/DebugLog.crow [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/EnumSelector.template [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/dbg.style [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/dbglog.crow
Samples/DebugLogAnalyzer/ui/focused.crow [new file with mode: 0644]
Samples/DebugLogAnalyzer/ui/main.crow [new file with mode: 0644]
Samples/ShowCase/ShowCase.cs
Samples/ShowCase/ShowCase.csproj
Samples/ShowCase/ui/showcase.crow
Samples/common/SampleBase.cs
Samples/common/ui/Interfaces/Wrapper/1.1.crow
Samples/common/ui/Interfaces/cbRecording.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/log.xml [deleted file]
Samples/common/ui/Interfaces/menutest.crow [new file with mode: 0644]

index afc71387a60e787e64056f28abdbffa366137dbd..7db03c154f09fad7393d63186de623f1f8fb4b09 100644 (file)
--- a/Crow.sln
+++ b/Crow.sln
@@ -1,4 +1,4 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 16
 VisualStudioVersion = 16.0.30104.148
 MinimumVisualStudioVersion = 10.0.40219.1
@@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{728545
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crow", "Crow\Crow.csproj", "{C2980F9B-4798-4C05-99E2-E174810F7C7B}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CrowDbgShared", "CrowDbgShared\CrowDbgShared.csproj", "{91F1CE07-EECE-4F1D-A3EE-7239B563654A}"
+EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}"
        ProjectSection(SolutionItems) = preProject
                Samples\Directory.Build.props = Samples\Directory.Build.props
@@ -19,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorld", "Samples\Hello
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShowCase", "Samples\ShowCase\ShowCase.csproj", "{56329D48-D382-4850-93DE-59C453894E8A}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlLib", "Samples\ControlLib\ControlLib.csproj", "{91F1CE07-EECE-4F1D-A3EE-7239B563654A}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "unitTests", "unitTests\unitTests.csproj", "{0CC6DFAB-2E4A-4786-976C-89053D5EA6A2}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTests", "Samples\BasicTests\BasicTests.csproj", "{7AEB6DD5-916E-4415-84E1-78EC6E5881CE}"
@@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BindingTest", "Samples\Bind
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PathPainter", "Samples\PathPainter\PathPainter.csproj", "{4066FE1E-3508-4361-ABAA-21601F632ED8}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowDebugger", "Samples\CrowDebugger\CrowDebugger.csproj", "{F86711E7-CACE-4050-82BF-0229CCEFDBA3}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -89,6 +91,10 @@ Global
                {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
+               {F86711E7-CACE-4050-82BF-0229CCEFDBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {F86711E7-CACE-4050-82BF-0229CCEFDBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {F86711E7-CACE-4050-82BF-0229CCEFDBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {F86711E7-CACE-4050-82BF-0229CCEFDBA3}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -96,7 +102,6 @@ Global
        GlobalSection(NestedProjects) = preSolution
                {F535A8AB-CD93-49AB-B1B0-FFF9AE51ED6A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
                {56329D48-D382-4850-93DE-59C453894E8A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
-               {91F1CE07-EECE-4F1D-A3EE-7239B563654A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
                {7AEB6DD5-916E-4415-84E1-78EC6E5881CE} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
                {18EBB41F-815E-4BF5-B80F-C9E2FAB2993A} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
                {7915538F-B2B1-414C-95A3-1FC58E3286B9} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
@@ -104,6 +109,7 @@ Global
                {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}
+               {F86711E7-CACE-4050-82BF-0229CCEFDBA3} = {B2C7855A-2878-47FD-AD32-9A83DB4AB8C6}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {00D4E149-7131-49F4-BAAD-559AA961A78E}
index 9cff5e2dbf62532ef61acc279d6abdc2e397d7d4..86b42dab2f191c3d5b6d77147440c56cb0675ca8 100644 (file)
@@ -31,7 +31,7 @@
        </PropertyGroup>
        <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
                <DebugType>full</DebugType>
-               <DefineConstants>$(DefineConstants);DEBUG;_DEBUG_LOG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
+               <DefineConstants>$(DefineConstants);DEBUG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
                <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
        </PropertyGroup>
        <ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
@@ -40,7 +40,7 @@
        </ItemGroup>
        <ItemGroup>
                <PackageReference Include="FastEnum" Version="1.5.3" />
-               <PackageReference Include="glfw-sharp" Version="0.2.11-beta" />
+               <PackageReference Include="glfw-sharp" Version="$(GlfwSharpVersion)" />
        </ItemGroup>
 
        <PropertyGroup Condition=" '$(CrowStbSharp)' == 'true'">
                <PackageReference Include="StbImageSharp" Version="2.22.4" />
        </ItemGroup>
 
+       <PropertyGroup Condition=" '$(CrowDebugLogEnabled)' == 'true'" >
+               <DefineConstants>$(DefineConstants);DEBUG_LOG</DefineConstants>
+       </PropertyGroup>
+       <ItemGroup>
+               <ProjectReference Include="..\CrowDbgShared\CrowDbgShared.csproj" />
+       </ItemGroup>
+
        <ItemGroup>
                <Content Include="..\Images\crow.png" Pack="true" PackagePath="" />
                <Compile Include="src\**\*.cs" Exclude="src\Mono.Cairo\NativeMethods-internal.cs" />
index 9833be47892d43ffeb17ac52448191002547e50a..622f5b793affe8d1ecc462eabf184935494cd4d3 100644 (file)
@@ -26,6 +26,7 @@ MenuBackground = "Jet";
 Button, CheckBox, RadioButton, ComboBox, Expandable,
 MessageBox, Popper, Slider, Spinner, TextBox {
        //Focusable = "true";
+       Foreground="${ControlForeground}";
        Height = "Fit";
        Background = "${ControlBackground}";
        CornerRadius = "${ControlCornerRadius}";
@@ -40,7 +41,10 @@ GroupBox { Caption = "Group Box"; }
 
 Control {
        Margin="${ControlInsideMargin}";
-       Spacing="3";
+       Spacing="3";    
+       //Foreground  = "${ControlForeground}";
+       //MouseEnter    = "{Foreground=${ControlCaptionHoverColor}}";
+       //MouseLeave    = "{Foreground=${ControlForeground}}";  
 }
 ControlBorder {
        BorderWidth     = "${ControlBorderWidth}";
@@ -48,9 +52,9 @@ ControlBorder {
        Margin = "${ControlInsideMargin}";
 }
 ControlCaption {
-       Foreground  = "${ControlForeground}";
-       MouseEnter      = "{Foreground=${ControlCaptionHoverColor}}";
-       MouseLeave      = "{Foreground=${ControlForeground}}";
+       //Foreground  = "${ControlForeground}";
+       //MouseEnter    = "{Foreground=${ControlCaptionHoverColor}}";
+       //MouseLeave    = "{Foreground=${ControlForeground}}";
 }
 ControlEditableText {
        Foreground      = "${ControlForeground}";
index cfe1a701189bd09b4081e5c0abf22d8141cfa615..a524bbf9bb907607edeaddc8b2c4ab75000ebd30 100644 (file)
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
-<VerticalStack Spacing="0" > 
-       <ListBox Data="{./Items}" Fit="true" HorizontalAlignment="Left" VerticalAlignment="Top" SelectedItem="{²./SelectedItem}"> 
+<VerticalStack Spacing="0" Background="{./Background}"
+       <ListBox  Data="{./Items}" Fit="true" HorizontalAlignment="Left" VerticalAlignment="Top" SelectedItem="{²./SelectedItem}"> 
                <Template>
-                       <HorizontalStack Name="ItemsContainer" Background="{./Background}" />
+                       <HorizontalStack Name="ItemsContainer" />
                </Template>
                <ItemTemplate>
                        <ListItem Fit="true" Background="Transparent" IsSelected="{IsVisible}"
-                                       Selected="{.DataSource.Visible='true'};{Background=Grey}"
+                                       Selected="{.DataSource.Visible='true'};{Background=.DataSource.Background}"
                                        Unselected="{.DataSource.Visible='false'};{Background=Transparent}"> 
                                <Label Text="{Name}" Margin="5" />
                        </ListItem>
                </ItemTemplate>
        </ListBox>
-       <Group Name="ItemsContainer" Background="Grey"/>
+       <Group Name="ItemsContainer" />
 </VerticalStack>
 
index ba2ad7e8dae2c6b7268e146c41dd55a017dcab69..1318764cd08d5c468a94e80a7ae6683b5983974f 100644 (file)
@@ -317,7 +317,8 @@ namespace Crow
                /// <param name="_A">normalized alpha component</param>
                public Color AdjustAlpha(double _A)
                {
-                       return new Color (this.R, this.G, this.B, _A);
+                       float[] tmp = floatArray;
+                       return new Color (tmp[0], tmp[1], tmp[2], _A);
                }
 
                public override bool Equals (object obj)
index 34d48c4f1696ce3c5d14c52366ac02d83a913817..51f0bc0a804ed3fa71fe821b261ed7680dbae208 100644 (file)
@@ -86,11 +86,17 @@ namespace Crow {
                #region CTOR
                public Command () {}
                /// <summary>
-               /// Initializes a new instance of Command with the action pass as argument.
+               /// Initializes a new instance of Command with the action passed as argument.
                /// </summary>
                /// <param name="_executeAction">action to excecute when command is triggered</param>
-               public Command (Action _executeAction)
-               {
+               public Command (Action _executeAction) {
+                       execute = _executeAction;
+               }
+               /// <summary>
+               /// Initializes a new instance of Command with the action<object> passed as argument.
+               /// </summary>
+               /// <param name="_executeAction">action to excecute when command is triggered</param>
+               public Command (Action<object> _executeAction) {
                        execute = _executeAction;
                }
                public Command (string caption, Action executeAction, string icon = null, bool _canExecute = true)
@@ -99,10 +105,17 @@ namespace Crow {
                        execute = executeAction;
                        canExecute = _canExecute;
                }
+               public Command (string caption, Action<object> executeAction, string icon = null, bool _canExecute = true)
+                       :base (caption, icon)
+               {                                       
+                       execute = executeAction;
+                       canExecute = _canExecute;
+               }
                
                #endregion
 
-               Action execute;         
+               Delegate execute;               
+
                bool canExecute = true;
                
                /// <summary>
@@ -122,12 +135,16 @@ namespace Crow {
                /// <summary>
                /// trigger the execution of the command
                /// </summary>
-               public virtual void Execute(){
+               public virtual void Execute (object sender = null){
                        if (execute != null && CanExecute){
-                               Task task = new Task(execute);
+                               Task task =     (execute is Action a) ?
+                                       task = new Task(a) :                            
+                               (execute is Action<object> o) ?
+                                       task = new Task(o, sender) : throw new Exception("Invalid Delegate type in Crow.Command, expecting Action or Action<object>");
                                task.Start();
                        }
                }
+
                internal override void raiseAllValuesChanged()
                {
                        base.raiseAllValuesChanged();
index fe056f790b5dfe05dfa1773426b1f4ee3f147812..a9969716db87d621752fc1f38ab9465e9eb1a09b 100644 (file)
@@ -1,77 +1,28 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+using System.Diagnostics;
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 using System;
 using System.Collections.Generic;
 using System.Threading;
 
-namespace Crow
+namespace Crow.DebugLogger
 {
        public class DbgEvent : DbgEventSource
        {
                public long begin, end;
                public int threadId;
                public DbgEvtType type;
+               public DbgEvtType Category => type & DbgEvtType.All;
                public DbgEvent parentEvent;
                public bool HasChildEvents => Events != null && Events.Count > 0;
                public override long Duration => end - begin;
+               public double DurationMS => Math.Round ((double)Duration / Stopwatch.Frequency * 1000.0, 4);
+               public double BeginMS => Math.Round ((double)begin / Stopwatch.Frequency * 1000.0, 4);
+               public double EndMS => Math.Round ((double)end / Stopwatch.Frequency * 1000.0, 4);
                public virtual bool IsWidgetEvent => false;
                public virtual bool IsLayoutEvent => false;
 
-               bool isSelected;
-               bool isExpanded;
-               Widget listContainer;
-
-               public bool IsSelected {
-                       get => isSelected;
-                       set {
-                               if (isSelected == value)
-                                       return;
-                               isSelected = value;
-                               NotifyValueChangedAuto (isSelected);
-                       }
-               }
-               public bool IsExpanded {
-                       get => isExpanded;
-                       set {
-                               if (isExpanded == value)
-                                       return;
-                               isExpanded = value;
-                               if (isExpanded && parentEvent != null)
-                                       parentEvent.IsExpanded = true;
-                               NotifyValueChangedAuto (isExpanded);
-                       }
-               }
-               public Widget ListContainer {
-                       get => listContainer;
-                       set {
-                               if (listContainer == value)
-                                       return;
-                               listContainer = value;
-                               NotifyValueChangedAuto (listContainer);
-                       }
-               }
-
-               public virtual Color Color {
-                       get {
-                               switch (type) {
-                               case DbgEvtType.Layouting:
-                                       return Colors.Yellow;
-                               case DbgEvtType.Clipping:
-                                       return Colors.DarkTurquoise;
-                               case DbgEvtType.Drawing:
-                                       return Colors.MidnightBlue;
-                               case DbgEvtType.Update:
-                                       return Colors.Grey;
-                               case DbgEvtType.IFaceLoad:
-                                       return Colors.Teal;
-                               default:
-                                       return Colors.White;
-                               }
-
-                       }
-               }
-
                public void AddEvent (DbgEvent evt)
                {
                        if (Events == null)
@@ -113,13 +64,20 @@ namespace Crow
                                                OldSlot = Rectangle.Parse (tmp [7]),
                                                NewSlot = Rectangle.Parse (tmp [8]),
                                        };
-                               return new DbgWidgetEvent () {
-                                       begin = long.Parse (tmp [0]),
-                                       end = long.Parse (tmp [1]),
-                                       threadId = int.Parse (tmp [2]),
-                                       type = evtType,
-                                       InstanceIndex = int.Parse (tmp [4]),
-                               };
+                               return (tmp.Length < 5) ?
+                                                       new DbgWidgetEvent () {
+                                                               begin = long.Parse (tmp [0]),
+                                                               end = long.Parse (tmp [1]),
+                                                               threadId = int.Parse (tmp [2]),
+                                                               type = evtType,
+                                                               InstanceIndex = -1,
+                                                       } : new DbgWidgetEvent () {
+                                                               begin = long.Parse (tmp [0]),
+                                                               end = long.Parse (tmp [1]),
+                                                               threadId = int.Parse (tmp [2]),
+                                                               type = evtType,
+                                                               InstanceIndex = int.Parse (tmp [4]),
+                                                       };
                        }
                        return new DbgEvent () {
                                begin = long.Parse (tmp [0]),
@@ -128,120 +86,27 @@ namespace Crow
                                type = evtType,
                        };
                }
-               public virtual string Print()
+               public virtual string Print ()
                        => $"{begin,10}:{threadId,-2}:{type,-20}:";
                public override string ToString ()
                        => $"{begin};{end};{threadId};{type}";
-                       
-       }
-       public class DbgWidgetEvent : DbgEvent
-       {
-               public int InstanceIndex;
-               public override Color Color {
+               public virtual Color Color {
                        get {
                                switch (type) {
-                               case DbgEvtType.GOClassCreation:
-                                       return Colors.DarkSlateGrey;
-                               case DbgEvtType.GOInitialization:
-                                       return Colors.DarkOliveGreen;
-                               case DbgEvtType.GOClippingRegistration:
-                                       return Colors.MediumTurquoise;
-                               case DbgEvtType.GORegisterClip:
-                                       return Colors.Turquoise;
-                               case DbgEvtType.GORegisterForGraphicUpdate:
-                                       return Colors.LightPink;
-                               case DbgEvtType.GOEnqueueForRepaint:
-                                       return Colors.LightSalmon;
-                               case DbgEvtType.GONewDataSource:
-                                       return Colors.MediumVioletRed;
-                               case DbgEvtType.GODraw:
-                                       return Colors.SteelBlue;
-                               case DbgEvtType.GORecreateCache:
-                                       return Colors.CornflowerBlue;
-                               case DbgEvtType.GOUpdateCache:
-                                       return Colors.SteelBlue;
-                               case DbgEvtType.GOPaint:
-                                       return Colors.RoyalBlue;
-                               case DbgEvtType.GOLockUpdate:
-                                       return Colors.SaddleBrown;
-                               case DbgEvtType.GOLockClipping:
-                                       return Colors.Sienna;
-                               case DbgEvtType.GOLockRender:
-                                       return Colors.BurlyWood;
-                               case DbgEvtType.GOLockLayouting:
-                                       return Colors.GoldenRod;
-                               case DbgEvtType.TGCancelLoadingThread:
-                                       return Colors.Maroon;
+                               case DbgEvtType.ProcessLayouting:
+                                       return Colors.Yellow;
+                               case DbgEvtType.ClippingRegistration:
+                                       return Colors.DarkTurquoise;
+                               case DbgEvtType.ProcessDrawing:
+                                       return Colors.MidnightBlue;
+                               case DbgEvtType.Update:
+                                       return Colors.Grey;
+                               case DbgEvtType.IFaceLoad:
+                                       return Colors.Teal;
                                default:
                                        return Colors.White;
                                }
                        }
-               }
-               public override bool IsWidgetEvent => true;
-               public DbgWidgetEvent () { }
-               public DbgWidgetEvent (long timeStamp, DbgEvtType evt, Widget w) : base (timeStamp, evt)
-               {
-#if DEBUG_LOG
-                       InstanceIndex = w.instanceIndex;
-#endif
-               }
-#if DEBUG_LOG
-        public override string Print () 
-            => $"{base.Print ()} {Widget.GraphicObjects[InstanceIndex]}";        
-#endif
-        public override string ToString ()
-                       => $"{base.ToString ()};{InstanceIndex}";
-       }
-       public class DbgLayoutEvent : DbgWidgetEvent
-       {
-               public LayoutingType layouting;
-               public LayoutingQueueItem.Result result;
-               public Rectangle OldSlot, NewSlot;
-               public override Color Color {
-                       get {
-                               if (type == DbgEvtType.GORegisterLayouting)
-                                       return Colors.GreenYellow;
-                               if (type == DbgEvtType.GOProcessLayoutingWithNoParent)
-                                       return Colors.DarkRed;
-                               switch (result) {
-                               case LayoutingQueueItem.Result.Success:
-                                       return Colors.Green;
-                               case LayoutingQueueItem.Result.Deleted:
-                                       return Colors.Red;
-                               case LayoutingQueueItem.Result.Discarded:
-                                       return Colors.OrangeRed;
-                               default:
-                                       return Colors.Orange;
-                               }
-                       }
-               }
-               public override bool IsLayoutEvent => true;
-               public DbgLayoutEvent () { }
-#if DEBUG_LOG
-               public DbgLayoutEvent (long timeStamp, DbgEvtType evt, LayoutingQueueItem lqi) :
-                       base (timeStamp, evt, lqi.graphicObject)
-               {
-                       layouting = lqi.LayoutType;
-                       result = lqi.result;
-                       OldSlot = lqi.Slot;
-                       NewSlot = lqi.NewSlot;
-               }
-               public void SetLQI (LayoutingQueueItem lqi)
-               {
-                       layouting = lqi.LayoutType;
-                       result = lqi.result;
-                       OldSlot = lqi.Slot;
-                       NewSlot = lqi.NewSlot;
-               }
-#else
-               public DbgLayoutEvent (long timeStamp, DbgEvtType evt, LayoutingQueueItem lqi) {}
-               public void SetLQI (LayoutingQueueItem lqi) { }
-
-#endif
-               public override string Print ()
-                       => $"{layouting} {result} {OldSlot}->{NewSlot} {base.Print ()}";
-
-               public override string ToString ()
-                       => $"{base.ToString ()};{layouting};{result};{OldSlot};{NewSlot}";
+               }               
        }
 }
\ No newline at end of file
index 409f214784058bea25464bda5b6c5dc6a9d22dc8..133b5edeb9c005fa0f132e0e356c833d8a19e60c 100644 (file)
@@ -5,17 +5,11 @@ using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 
-namespace Crow
+namespace Crow.DebugLogger
 {
        //base class for both events and widgetRecord having an event list
-       public abstract class DbgEventSource : IValueChange
+       public abstract class DbgEventSource
        {
-               public event EventHandler<ValueChangeEventArgs> ValueChanged;
-               public virtual void NotifyValueChanged (string MemberName, object _value)
-                       => ValueChanged.Raise (this, new ValueChangeEventArgs (MemberName, _value));
-               public void NotifyValueChangedAuto (object _value, [CallerMemberName] string caller = null)
-                       => NotifyValueChanged (caller, _value);
-
                //flattened event list of this widget
                public List<DbgEvent> Events;
                public virtual long Duration {
diff --git a/Crow/src/DebugUtils/DbgEventTypeColors.cs b/Crow/src/DebugUtils/DbgEventTypeColors.cs
deleted file mode 100644 (file)
index d287190..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using Crow.Cairo;
-using System.Linq;
-
-namespace Crow
-{
-       /*public class DbgEventTypeColors : Widget
-       {
-               protected override void onDraw (Context gr)
-               {
-                       base.onDraw (gr);
-
-                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
-                       gr.SetFontSize (Font.Size);
-                       gr.FontOptions = Interface.FontRenderingOptions;
-                       gr.Antialias = Interface.Antialias;
-
-                       DbgEvtType[] types = DbgLogViewer.colors.Keys.ToArray ();
-                       Color[] colors = DbgLogViewer.colors.Values.ToArray ();
-
-                       Rectangle r = ClientRectangle;
-                       FontExtents fe = gr.FontExtents;
-
-                       double penY = fe.Height + r.Top;
-                       double penX = (double)r.Left;
-
-
-                       for (int i = 0; i < types.Length; i++) {
-                               string n = types [i].ToString();
-                               Color c = colors[i];
-                               Foreground.SetAsSource (gr);
-
-                               gr.MoveTo (penX + 25.0, penY - fe.Descent);
-                               gr.ShowText (n);
-
-                               Rectangle rc = new Rectangle((int)penX, (int)(penY - fe.Height), 20, (int)fe.Height);
-                               rc.Inflate (-2);
-                               gr.Rectangle (rc);
-                               gr.StrokePreserve ();
-
-                               gr.SetSource (c);
-                               gr.Fill ();
-
-                               penY += fe.Height;
-
-                       }
-               }
-       }*/
-}
-
diff --git a/Crow/src/DebugUtils/DbgEventWidget (copie).cs b/Crow/src/DebugUtils/DbgEventWidget (copie).cs
deleted file mode 100644 (file)
index f6b4dc6..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using Crow.Cairo;
-
-namespace Crow
-{
-       /*
-       /// <summary>
-       /// Compressed event list without gaps
-       /// </summary>
-       public class DbgEventListWidget : Widget
-       {
-               public DbgEventListWidget (){}
-
-               DbgWidgetRecord wRec;
-               public DbgWidgetRecord WidgetRecord {
-                       get => wRec;
-                       set {
-                               if (wRec == value)
-                                       return;
-                               wRec = value;
-                               pixelPerTick = WidgetRecord == null ? 0 : (double)ClientRectangle.Width / WidgetRecord.Duration;
-                               NotifyValueChangedAuto (wRec);
-                               RegisterForRedraw ();
-                       }
-               }
-
-               double pixelPerTick;
-
-               public override void OnLayoutChanges (LayoutingType layoutType)
-               {
-                       if (layoutType == LayoutingType.Width)
-                               pixelPerTick = WidgetRecord == null ? 0 : (double)ClientRectangle.Width / WidgetRecord.Duration;
-                       base.OnLayoutChanges (layoutType);
-               }
-
-               protected override void onDraw (Context gr)
-               {
-                       if (WidgetRecord == null || WidgetRecord.Duration == 0) {
-                               base.onDraw (gr);
-                               return;
-                       }
-
-                       Rectangle cb = ClientRectangle;
-
-                       drawEvent (gr, cb.Height, WidgetRecord);
-               }
-               void drawEvent (Context ctx, int h, DbgEvent dbge)
-               {
-                       double w = dbge.Duration == 0 ? 1.0 : dbge.Duration * pixelPerTick;
-                       double x = (dbge.begin - WidgetRecord.begin) * pixelPerTick;
-
-                       ctx.Rectangle (x, Margin, w, h);
-                       ctx.SetSource (dbge.Color);
-                       ctx.Fill ();
-                       if (dbge.Events == null)
-                               return;
-                       foreach (DbgEvent e in dbge.Events)
-                               drawEvent (ctx, h, e);
-               }
-
-               public override void onMouseMove (object sender, MouseMoveEventArgs e)
-               {
-                       if (WidgetRecord != null) {
-                               Point m = ScreenPointToLocal (e.Position);
-                               long curTick = (long)(m.X / pixelPerTick) + WidgetRecord.begin;
-                               NotifyValueChanged ("HoverEvent", hoverEvent (WidgetRecord, curTick));
-                               e.Handled = true;
-                       }
-                       base.onMouseMove (sender, e);
-               }
-
-               DbgEvent hoverEvent (DbgEvent hevt, long curTick){
-                       if (hevt.Events != null) {
-                               foreach (DbgEvent e in hevt.Events) {
-                                       if (curTick >= e.begin && curTick <= e.end)
-                                               return hoverEvent (e, curTick);
-                               }
-                       }
-                       return hevt;
-               }
-       }*/
-}
diff --git a/Crow/src/DebugUtils/DbgEvtType.cs b/Crow/src/DebugUtils/DbgEvtType.cs
new file mode 100644 (file)
index 0000000..24fd99f
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace Crow
+{
+       [Flags]
+       public enum DbgEvtType : Int32 {
+               None                                                    = 0,
+               IFace                                                   = 0x40000000,
+               Widget                                                  = 0x20000000,
+
+               Warning                                                 = 0x10000000,
+               Error                                                   = 0x08000000,
+
+               Binding                                                 = 0x800000,
+               Lock                                                    = 0x400000,
+               Layouting                                               = 0x200000,
+               Clipping                                                = 0x100000,
+               Drawing                                                 = 0x080000,
+
+               Focus                                                   = 0x040000,
+               Override                                                = 0x020000,
+               TemplatedGroup                                  = 0x010000,
+               Dispose                                                 = 0x008000,
+
+               Update                                                  = IFace | 0x004000,
+               ProcessLayouting                                = IFace | Update | Lock | Layouting,
+               ClippingRegistration                    = IFace | Update | Lock | Clipping,
+               ProcessDrawing                                  = IFace | Update | Lock | Drawing,
+               IFaceLoad                                               = IFace | 0x01,
+               IFaceInit                                               = IFace | 0x02,
+               CreateITor                                              = IFace | 0x04,
+               IFaceReloadTheme                                = IFace | 0x08,
+
+               HoverWidget                                             = Focus | Widget | 0x01,
+               FocusedWidget                                   = Focus | Widget | 0x02,
+               ActiveWidget                                    = Focus | Widget | 0x04,
+               UnfocusedWidget                                 = Focus | Widget | 0x08,
+
+               //10 nth bit set for graphic obj
+               GOClassCreation                                 = Widget | 0x01,
+               GOInitialization                                = Widget | 0x02,
+               GORegisterForGraphicUpdate              = Widget | 0x04,
+               GOEnqueueForRepaint                             = Widget | 0x08,
+               GONewDataSource                                 = Widget | 0x10,
+               GONewParent                                             = Widget | 0x20,
+               GONewLogicalParent                              = Widget | 0x40,
+               GOAddChild                                              = Widget | 0x80,
+
+               GOSearchLargestChild                    = Widget | 0x09,
+               GOSearchTallestChild                    = Widget | 0x0A,
+               GORegisterForRedraw                             = Widget | 0x0B,
+               GOComputeChildrenPositions              = Widget | 0x0C,
+               GOOnChildLayoutChange                   = Widget | 0x0D,
+
+               AlreadyDisposed                                 = Dispose | Widget | Error | 0x01,
+               DisposedByGC                                    = Dispose | Widget | Error | 0x02,
+               Disposing                                               = Dispose | Widget | 0x01,
+
+               GOClippingRegistration                  = Clipping | Widget | 0x01,
+               GORegisterClip                                  = Clipping | Widget | 0x02,
+               GORegisterLayouting                     = Layouting | Widget | 0x01,
+               GOProcessLayouting                              = Layouting | Widget | 0x02,
+               GOProcessLayoutingWithNoParent  = Layouting | Widget | Warning | 0x01,
+               GOMeasure                                               = Widget | 0x03,
+               GODraw                                                  = Drawing | Widget | 0x01,
+               GORecreateCache                                 = Drawing | Widget | 0x02,
+               GOUpdateCache                                   = Drawing | Widget | 0x03,
+               GOPaint                                                 = Drawing | Widget | 0x04,
+
+               GOLockUpdate                                    = Widget | Lock | 0x01,
+               GOLockClipping                                  = Widget | Lock | 0x02,
+               GOLockRender                                    = Widget | Lock | 0x03,
+               GOLockLayouting                                 = Widget | Lock | 0x04,
+
+               TGLoadingThread                                 = Widget | TemplatedGroup | 0x01,
+               TGCancelLoadingThread                   = Widget | TemplatedGroup | 0x02,
+
+               All = 0x7FFFFF00
+       }
+}
\ No newline at end of file
diff --git a/Crow/src/DebugUtils/DbgLayoutEvent.cs b/Crow/src/DebugUtils/DbgLayoutEvent.cs
new file mode 100644 (file)
index 0000000..4444fe3
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Crow.DebugLogger
+{
+       public class DbgLayoutEvent : DbgWidgetEvent
+       {
+               public LayoutingType layouting;
+               public LayoutingQueueItem.Result result;
+               public Rectangle OldSlot, NewSlot;
+               public override bool IsLayoutEvent => true;
+               public DbgLayoutEvent () { }
+               public DbgLayoutEvent (long timeStamp, DbgEvtType evt, int widgetInstanceIndex,
+                       LayoutingType layouting, LayoutingQueueItem.Result result, Rectangle oldSlot, Rectangle newSlot) :
+                       base (timeStamp, evt, widgetInstanceIndex)
+               {
+                       SetLQI (layouting, result, oldSlot, newSlot);
+               }
+               public void SetLQI (LayoutingType layouting, LayoutingQueueItem.Result result, Rectangle oldSlot, Rectangle newSlot)
+               {
+                       this.layouting = layouting;
+                       this.result = result;
+                       OldSlot = oldSlot;
+                       NewSlot = newSlot;
+               }
+               public override string Print()
+                       => $"{base.Print()} {layouting} {result} {OldSlot}->{NewSlot}";
+
+               public override string ToString ()
+                       => $"{base.ToString ()};{layouting};{result};{OldSlot};{NewSlot}";
+               public override Color Color {
+                       get {
+                       if (type == DbgEvtType.GORegisterLayouting)
+                               return Colors.GreenYellow;
+                       if (type == DbgEvtType.GOProcessLayoutingWithNoParent)
+                               return Colors.DarkRed;
+                       switch (result) {
+                       case LayoutingQueueItem.Result.Success:
+                               return Colors.Green;
+                       case LayoutingQueueItem.Result.Deleted:
+                               return Colors.Red;
+                       case LayoutingQueueItem.Result.Discarded:
+                               return Colors.OrangeRed;
+                       default:
+                               return Colors.Orange;
+                       }                                       }
+               }                       
+       }
+}
\ No newline at end of file
diff --git a/Crow/src/DebugUtils/DbgWidgetEvent.cs b/Crow/src/DebugUtils/DbgWidgetEvent.cs
new file mode 100644 (file)
index 0000000..3ec58df
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Crow.DebugLogger
+{      
+       public class DbgWidgetEvent : DbgEvent
+       {
+               public int InstanceIndex;
+               public override bool IsWidgetEvent => true;
+               public DbgWidgetEvent () { }
+               public DbgWidgetEvent (long timeStamp, DbgEvtType evt, int widgetInstanceIndex) : base (timeStamp, evt)
+               {
+                       InstanceIndex = widgetInstanceIndex;
+               }
+               //public override string Print() => $"{base.Print()}:{InstanceIndex}"
+               
+        public override string ToString ()
+                       => $"{base.ToString ()};{InstanceIndex}";
+               public override Color Color {
+                       get {
+                               switch (type) {
+                               case DbgEvtType.GOClassCreation:
+                                       return Colors.DarkSlateGrey;
+                               case DbgEvtType.GOInitialization:
+                                       return Colors.DarkOliveGreen;
+                               case DbgEvtType.GOClippingRegistration:
+                                       return Colors.MediumTurquoise;
+                               case DbgEvtType.GORegisterClip:
+                                       return Colors.Turquoise;
+                               case DbgEvtType.GORegisterForGraphicUpdate:
+                                       return Colors.LightPink;
+                               case DbgEvtType.GOEnqueueForRepaint:
+                                       return Colors.LightSalmon;
+                               case DbgEvtType.GONewDataSource:
+                                       return Colors.MediumVioletRed;
+                               case DbgEvtType.GODraw:
+                                       return Colors.SteelBlue;
+                               case DbgEvtType.GORecreateCache:
+                                       return Colors.CornflowerBlue;
+                               case DbgEvtType.GOUpdateCache:
+                                       return Colors.SteelBlue;
+                               case DbgEvtType.GOPaint:
+                                       return Colors.RoyalBlue;
+                               case DbgEvtType.GOLockUpdate:
+                                       return Colors.SaddleBrown;
+                               case DbgEvtType.GOLockClipping:
+                                       return Colors.Sienna;
+                               case DbgEvtType.GOLockRender:
+                                       return Colors.BurlyWood;
+                               case DbgEvtType.GOLockLayouting:
+                                       return Colors.GoldenRod;
+                               case DbgEvtType.TGCancelLoadingThread:
+                                       return Colors.Maroon;
+                               default:
+                                       return Colors.White;
+                               }
+                       }
+               }                       
+       }       
+}
\ No newline at end of file
index 8aaf1c47c3310933b9acb00803bc0bffcbd2aeac..0dd676f7f096bc2abf59b4433f3ccad357ae394f 100644 (file)
@@ -5,7 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 
-namespace Crow
+namespace Crow.DebugLogger
 {
        /// <summary>
        /// Recorded Widget instance data.
index 207ae2178cda0571e33381deef3e87c509938979..eb096f80de6750ae1c0fa2c137c1836e7875219b 100644 (file)
@@ -1,95 +1,33 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+using System.Text;
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
 //
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 
 using System;
-using Crow.Cairo;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Threading;
 
+using Crow.DebugLogger;
 
 namespace Crow
-{
-       [Flags]
-       public enum DbgEvtType {
-               ////9 nth bit set for iface event
-               IFace                                                   = 0x10000,
-               Focus                                                   = 0x20000,
-               Override                                                = 0x40000,
-               Binding                                                 = 0x80000,
-               Widget                                                  = 0x00100,
-               //GOLayouting                                   = 0x00200,
-               //Drawing                                               = 0x00400,
-               Lock                                                    = 0x00800,
-               Layouting                                               = IFace | 0x01000,
-               Clipping                                                = IFace | 0x02000,
-               Drawing                                                 = IFace | 0x04000,
-               Update                                                  = IFace | 0x08000,
-               IFaceLoad                                               = IFace | 0x05,
-               IFaceInit                                               = IFace | 0x06,
-               CreateITor                                              = IFace | 0x07,
-               IFaceReleadTheme                                = IFace | 0x08,
-
-               HoverWidget                                             = IFace | Focus | Widget | 0x01,
-               FocusedWidget                                   = IFace | Focus | Widget | 0x02,
-               ActiveWidget                                    = IFace | Focus | Widget | 0x03,
-               UnfocusedWidget                                 = IFace | Focus | Widget | 0x04,
-
-               //10 nth bit set for graphic obj
-               TemplatedGroup                                  = 0x1000,
-               Dispose                                                 = 0x2000,
-               Warning                                                 = 0x4000,
-               Error                                                   = 0x8000,
-               GOClassCreation                                 = Widget | 0x01,
-               GOInitialization                                = Widget | 0x02,
-               GORegisterForGraphicUpdate              = Widget | 0x03,
-               GOEnqueueForRepaint                             = Widget | 0x04,
-               GONewDataSource                                 = Widget | 0x05,
-               GONewParent                                             = Widget | 0x06,
-               GONewLogicalParent                              = Widget | 0x07,
-               GOAddChild                                              = Widget | 0x08,
-
-               GOSearchLargestChild                    = Widget | 0x09,
-               GOSearchTallestChild                    = Widget | 0x0A,
-               GORegisterForRedraw                             = Widget | 0x0B,
-
-               AlreadyDisposed                                 = Dispose | Widget | Error | 0x01,
-               DisposedByGC                                    = Dispose | Widget | Error | 0x02,
-               Disposing                                               = Dispose | Widget | 0x01,
-
-               GOClippingRegistration                  = Clipping | Widget | 0x01,
-               GORegisterClip                                  = Clipping | Widget | 0x02,
-               GORegisterLayouting                     = Layouting | Widget | 0x01,
-               GOProcessLayouting                              = Layouting | Widget | 0x02,
-               GOProcessLayoutingWithNoParent  = Layouting | Widget | Warning | 0x01,
-               GOMeasure                                               = Widget | 0x03,
-               GODraw                                                  = Drawing | Widget | 0x01,
-               GORecreateCache                                 = Drawing | Widget | 0x02,
-               GOUpdateCache                                   = Drawing | Widget | 0x03,
-               GOPaint                                                 = Drawing | Widget | 0x04,
-
-               GOLockUpdate                                    = Widget | Lock | 0x01,
-               GOLockClipping                                  = Widget | Lock | 0x02,
-               GOLockRender                                    = Widget | Lock | 0x03,
-               GOLockLayouting                                 = Widget | Lock | 0x04,
-
-               TGLoadingThread                                 = Widget | TemplatedGroup | 0x01,
-               TGCancelLoadingThread                   = Widget | TemplatedGroup | 0x02,
-
-               All = 0x0FFFFFFF
-       }
-       
+{      
        public static class DbgLogger
        {
                public static DbgEvtType IncludeEvents = DbgEvtType.All;
                public static DbgEvtType DiscardEvents = DbgEvtType.Focus;
                public static bool ConsoleOutput = true;
 
+
+#if DEBUG_LOG
                static bool logevt (DbgEvtType evtType)
-                       => (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;
+                       //=> IncludeEvents != DbgEvtType.None && (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;
+                       /*=> IncludeEvents == DbgEvtType.All ||
+                               IncludeEvents != DbgEvtType.None && (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;*/
+                       => IncludeEvents == DbgEvtType.All || (IncludeEvents != DbgEvtType.None && (evtType & IncludeEvents) == IncludeEvents);
+                       
 
 
                static object logMutex = new object ();
@@ -111,10 +49,15 @@ namespace Crow
                                return events;
                        }
                }
+               public static readonly bool IsEnabled = true;
+#else
+               public static readonly bool IsEnabled = false;
+#endif
 
                [Conditional ("DEBUG_LOG")]
                public static void StartEvent (DbgEvtType evtType, params object[] data)
                {
+#if DEBUG_LOG
                        if (!logevt (evtType))
                                return;
                        lock (logMutex) {
@@ -125,11 +68,13 @@ namespace Crow
                                startedEvents [Thread.CurrentThread.ManagedThreadId].Push (evt);
                                chrono.Start ();                                
                        }
+#endif
                }
 
                [Conditional ("DEBUG_LOG")]
                public static void EndEvent (DbgEvtType evtType, bool discardIfNoChildEvents = false)
                {
+#if DEBUG_LOG                  
                        if (!logevt (evtType))
                                return;
 
@@ -146,11 +91,13 @@ namespace Crow
                                        e.end = chrono.ElapsedTicks;
                                chrono.Start ();
                        }
+#endif
                }
 
                // End layouting queue event and set the corresponding lqi
                [Conditional ("DEBUG_LOG")]
                public static void EndEvent (DbgEvtType evtType, LayoutingQueueItem lqi) {
+#if DEBUG_LOG                  
                        if (!logevt (evtType))
                                return;
 
@@ -162,10 +109,10 @@ namespace Crow
                                if (e?.type != evtType)
                                        throw new Exception ($"Begin/end event logging mismatch: {e.type}/{evtType}");
                                e.end = chrono.ElapsedTicks;
-                               e.SetLQI (lqi);
+                               e.SetLQI (lqi.LayoutType, lqi.result, lqi.Slot, lqi.NewSlot);
                                chrono.Start ();
                        }
-
+#endif
                }
                /// <summary>
                /// End event by reference to cancel unended events on failure
@@ -190,7 +137,8 @@ namespace Crow
                }*/
 
                [Conditional("DEBUG_LOG")]
-               public static void AddEvent (DbgEvtType evtType, params object [] data) { 
+               public static void AddEvent (DbgEvtType evtType, params object [] data) {
+#if DEBUG_LOG                  
                        if (!logevt (evtType))
                                return;
 
@@ -199,33 +147,36 @@ namespace Crow
                                DbgEvent evt = addEventInternal (evtType, data);
                                chrono.Start ();
                        }
+#endif
                }
 
+#if DEBUG_LOG
                static DbgEvent addEventInternal (DbgEvtType evtType, params object [] data)
                {
                        DbgEvent evt = null;
-#if DEBUG_LOG
                        if (data == null || data.Length == 0)
                                evt = new DbgEvent (chrono.ElapsedTicks, evtType);
                        else if (data [0] is Widget w)
-                               evt = new DbgWidgetEvent (chrono.ElapsedTicks, evtType, w);
+                               evt = new DbgWidgetEvent (chrono.ElapsedTicks, evtType, w.instanceIndex);
                        else if (data [0] is LayoutingQueueItem lqi)
-                               evt = new DbgLayoutEvent (chrono.ElapsedTicks, evtType, lqi);
+                               evt = new DbgLayoutEvent (chrono.ElapsedTicks, evtType, lqi.graphicObject.instanceIndex, lqi.LayoutType, lqi.result, lqi.Slot, lqi.NewSlot);
                        else
                                evt = new DbgEvent (chrono.ElapsedTicks, evtType);
 
                        if (ConsoleOutput) {
                                if (evt.type.HasFlag (DbgEvtType.Error)) {
                                        Console.ForegroundColor = ConsoleColor.Red;
-                               }
-                               Console.WriteLine (evt.Print());
+                               }                               
+                               if (evt is DbgWidgetEvent we) 
+                                       Console.WriteLine ($"{evt.Print()} {Widget.GraphicObjects[we.InstanceIndex]}");
+                               else
+                                       Console.WriteLine ($"{evt.Print()}");
                                Console.ResetColor ();
                        } else
                                curEventList.Add (evt);
-#endif
                        return evt;
                }
-#if DEBUG_LOG
+
                static void parseTree (Widget go, int level = 0, int y = 1) {
                        if (go == null)
                                return;
@@ -244,61 +195,126 @@ namespace Crow
                                        parseTree (pc.getTemplateRoot, level + 1, y + 1);                               
                        }
                }
+               static void saveEventList (StreamWriter s, List<DbgEvent> evts, int level = 0)
+               {
+                       foreach (DbgEvent e in evts) {
+                               if (e == null)
+                                       continue;
+                               s.WriteLine (new string ('\t', level) + e);
+                               if (e.Events != null)
+                                       saveEventList (s, e.Events, level + 1);
+                       }
+               }
 
 #endif
                /// <summary>
                /// Clear all recorded events from logger.
                /// </summary>
+               [Conditional("DEBUG_LOG")]
                public static void Reset () {
 #if DEBUG_LOG
                        lock (logMutex) {
-                       startedEvents.Clear ();
+                               startedEvents.Clear ();
                                events.Clear ();
+                               /*lock (Widget.GraphicObjects)
+                                       Widget.GraphicObjects.Clear();*/
                                chrono.Restart ();
                        }
                        Console.WriteLine ($"Crow Debug Log reseted");
-#else
-                       Console.WriteLine ($"Logging disabled, compile Crow with DEBUG and DEBUG_LOG defined to enable logging.");
 #endif
                }
                /// <summary>
                /// Save recorded events to disk
                /// </summary>
-               /// <param name="iface">Iface.</param>          
+               /// <param name="iface">Iface.</param>
                public static void Save(Interface iface, string dbgLogFilePath = "debug.log") {
 #if DEBUG_LOG
-                       lock (logMutex) {
-
-                               foreach (Widget go in iface.GraphicTree)
-                                       parseTree (go);
-
-                               using (StreamWriter s = new StreamWriter (dbgLogFilePath)) {
-                                       s.WriteLine ("[GraphicObjects]");
-                                       lock (Widget.GraphicObjects) {
-                                               //Widget.GraphicObjects = Widget.GraphicObjects.OrderBy (o => o.yIndex).ToList ();
-                                               for (int i = 0; i < Widget.GraphicObjects.Count; i++) {
-                                                       Widget g = Widget.GraphicObjects [i];
-                                                       s.WriteLine ($"{g.GetType ().Name};{g.yIndex};{g.xLevel};{g.Width};{g.Height}");
-                                               }
+                               using (Stream stream = new FileStream (dbgLogFilePath, FileMode.Create, FileAccess.Write))
+                                       Save (iface, stream);
+                       Console.WriteLine ($"Crow Debug Log saved to: {System.IO.Path.GetFullPath(dbgLogFilePath)}");
+#endif
+               }
+               [Conditional("DEBUG_LOG")]
+               public static void Save(Interface iface, Stream stream) {                       
+#if DEBUG_LOG
+                       using (StreamWriter writer = new StreamWriter (stream, Encoding.UTF8, 1024, true)) {
+                               lock (logMutex)
+                               lock (iface.UpdateMutex) {
+                                       chrono.Stop();
+                                       foreach (Widget go in iface.GraphicTree)
+                                               parseTree (go);
+
+                                       writer.WriteLine ("[GraphicObjects]");
+                                       for (int i = 0; i < Widget.GraphicObjects.Count; i++) {
+                                               Widget g = Widget.GraphicObjects [i];
+                                               writer.WriteLine ($"{g.GetType ().Name};{g.yIndex};{g.xLevel};{g.Width};{g.Height}");
                                        }
-                                       s.WriteLine ("[Events]");
-                                       saveEventList (s, events);
+                               
+                                       writer.WriteLine ("[Events]");
+                                       saveEventList (writer, events);
+                                       chrono.Start();
                                }
                        }
-                       Console.WriteLine ($"Crow Debug Log saved to: {dbgLogFilePath}");
-#else
-                       Console.WriteLine ($"Compile Crow with DEBUG and DEBUG_LOG defined to enable logging. No log saved.");
 #endif
                }
-
-               static void saveEventList (StreamWriter s, List<DbgEvent> evts, int level = 0)
+               public static void Load (string logFile, List<DbgEvent> events, List<DbgWidgetRecord> widgets)
                {
-                       foreach (DbgEvent e in evts) {
-                               if (e == null)
-                                       continue;
-                               s.WriteLine (new string ('\t', level) + e);
-                               if (e.Events != null)
-                                       saveEventList (s, e.Events, level + 1);
+                       if (!File.Exists (logFile))
+                               return;
+                       using (Stream stream = new FileStream (logFile, FileMode.Open, FileAccess.Read))
+                               Load (stream, events, widgets);                 
+               }
+               public static void Load (Stream stream, List<DbgEvent> events, List<DbgWidgetRecord> widgets)
+               {                       
+                       using (StreamReader reader = new StreamReader (stream)) {
+                       
+                               if (reader.ReadLine () != "[GraphicObjects]")
+                                       return;
+                               while (!reader.EndOfStream) {
+                                       string l = reader.ReadLine ();
+                                       if (l == "[Events]")
+                                               break;
+                                       DbgWidgetRecord o = DbgWidgetRecord.Parse (l);
+                                       o.listIndex = widgets.Count;
+                                       widgets.Add (o);
+                               }
+
+                               Stack<DbgEvent> startedEvents = new Stack<DbgEvent> ();
+
+                               if (!reader.EndOfStream) {
+                                       while (!reader.EndOfStream) {
+                                               int level = 0;
+                                               while (reader.Peek () == (int)'\t') {
+                                                       reader.Read ();
+                                                       level++;
+                                               }
+                                               DbgEvent evt = DbgEvent.Parse (reader.ReadLine ());                                                     
+                                               if (level == 0) {
+                                                       startedEvents.Clear ();
+                                                       events.Add (evt);
+                                               } else {
+                                                       int levelDiff = level - startedEvents.Count + 1;
+                                                       if (levelDiff > 0) {
+                                                               if (levelDiff > 1)
+                                                                       System.Diagnostics.Debugger.Break ();
+                                                               startedEvents.Peek ().AddEvent (evt);
+                                                       } else {
+                                                               startedEvents.Pop ();
+                                                               if (-levelDiff > startedEvents.Count)
+                                                                       System.Diagnostics.Debugger.Break ();
+                                                               while (startedEvents.Count > level)
+                                                                       startedEvents.Pop ();
+                                                               startedEvents.Peek ().AddEvent (evt);
+                                                       }
+                                               }
+                                               startedEvents.Push (evt);
+                                               if (evt.type.HasFlag (DbgEvtType.Widget)) {
+                                                       DbgWidgetEvent dwe =  evt as DbgWidgetEvent;
+                                                       if (dwe.InstanceIndex >= 0)
+                                                               widgets [dwe.InstanceIndex].Events.Add (evt);
+                                               }
+                                       }
+                               }
                        }
                }
        }
index f43e700d39eb16eba2a24c3ea12b9a2c2403bbcf..b29912bc5f2f54657a2404c9e1a26a0808ab3f5b 100644 (file)
@@ -710,6 +710,11 @@ namespace Crow.IML {
                                } else if (rop.IsSingleName && rop.Tokens [0] == "this") {
                                        il.Emit (OpCodes.Ldarg_0);  //load sender ref onto the stack, the current node
                                        lop.emitSetProperty (il);
+                               } else if (rop.IsCurrentNodeProperty || rop.IsTemplateBinding || rop.LevelsUp > 0) {
+                                       il.Emit (OpCodes.Ldarg_0);  //load sender ref onto the stack, the current nod
+                                       rop.emitGetTarget (il, cancelFinalSet);
+                                       rop.emitGetProperty (il, cancelFinalSet);
+                                       lop.emitSetProperty (il);
                                } else if (rop.LevelsUp == 0 && !string.IsNullOrEmpty (rop.Tokens [0])) {//parsable constant depending on lop type
                                                                                                                                                                                 //if left operand is member of current node, it's easy to fetch type, else we should use reflexion in msil
                                        if (lopPI == null) {//accept GraphicObj members, but it's restricive
index 98df8ceed72e655b45626fe38389ee0ee656cea0..f1a3da1a097acae5fcf9f52a007d6c8a0776fa9f 100644 (file)
@@ -132,6 +132,8 @@ namespace Crow
                Cursor currentCursor;
                bool ownWindow;
 
+               public IntPtr WindowHandle => hWin;
+
                protected void registerGlfwCallbacks ()
                {
                        windows.Add (hWin, this);
@@ -426,7 +428,7 @@ namespace Crow
                /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
                public object RenderMutex = new object();
                /// <summary>Global lock of the update cycle</summary>
-               public object UpdateMutex = new object();
+               public object UpdateMutex = new object();               
                /// <summary>Global lock of the clipping queue</summary>
                public object ClippingMutex = new object();
                //TODO:share resource instances
@@ -553,13 +555,13 @@ namespace Crow
                                if (StylingConstants == null)//iFace not yet initialized
                                        return;
                                lock (UpdateMutex) {
-                                       DbgLogger.StartEvent (DbgEvtType.IFaceReleadTheme);
+                                       DbgLogger.StartEvent (DbgEvtType.IFaceReloadTheme);
                                        disposeContextMenus ();
                                        initDictionaries ();
                                        loadStyling ();
                                        loadThemeFiles ();                                      
                                        initContextMenus ();
-                                       DbgLogger.EndEvent (DbgEvtType.IFaceReleadTheme);
+                                       DbgLogger.EndEvent (DbgEvtType.IFaceReloadTheme);
                                }
                        }
                }
@@ -915,7 +917,7 @@ namespace Crow
                                        Monitor.Exit (LayoutMutex);
                                        return;
                 }
-                               DbgLogger.StartEvent (DbgEvtType.Layouting);
+                               DbgLogger.StartEvent (DbgEvtType.ProcessLayouting);
                                PerformanceMeasure.Begin (PerformanceMeasure.Kind.Layouting);
 
                                DiscardQueue = new Queue<LayoutingQueueItem> (LayoutingQueue.Count);
@@ -928,7 +930,7 @@ namespace Crow
                                LayoutingQueue = DiscardQueue;
 
                                PerformanceMeasure.End (PerformanceMeasure.Kind.Layouting);
-                               DbgLogger.EndEvent (DbgEvtType.Layouting, true);
+                               DbgLogger.EndEvent (DbgEvtType.ProcessLayouting, true);
 
                                Monitor.Exit (LayoutMutex);
                                DiscardQueue = null;
@@ -941,7 +943,7 @@ namespace Crow
                        if (ClippingQueue.Count == 0)
                                return;
 
-                       DbgLogger.StartEvent (DbgEvtType.Clipping);
+                       DbgLogger.StartEvent (DbgEvtType.ClippingRegistration);
                        PerformanceMeasure.Begin (PerformanceMeasure.Kind.Clipping);
 
                        Widget g = null;
@@ -954,26 +956,25 @@ namespace Crow
                        }
 
                        PerformanceMeasure.End (PerformanceMeasure.Kind.Clipping);
-                       DbgLogger.EndEvent (DbgEvtType.Clipping, true);
+                       DbgLogger.EndEvent (DbgEvtType.ClippingRegistration, true);
                }
                /// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
                /// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place</summary>
-               void processDrawing(Context ctx){
+               protected virtual void processDrawing(Context ctx){
 
-                       DbgLogger.StartEvent (DbgEvtType.Drawing);
+                       DbgLogger.StartEvent (DbgEvtType.ProcessDrawing);
 
                        if (DragImage != null)
                                clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight));
 
                        if (!clipping.IsEmpty) {
-                               PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing);
-                               IsDirty = true;
+                               PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing);                             
 
                                ctx.PushGroup ();
 
                                for (int i = GraphicTree.Count -1; i >= 0 ; i--){
                                        Widget p = GraphicTree[i];
-                                       if (!p.Visible)
+                                       if (!p.IsVisible)
                                                continue;
                                        if (clipping.Contains (p.Slot) == RegionOverlap.Out)
                                                continue;
@@ -1025,13 +1026,14 @@ namespace Crow
                                clipping = new Region ();
 
                                PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing);
+                               IsDirty = true;
                        }
 
                        drawTextCursor (ctx);
 
                        debugHighlightFocus (ctx);
                        
-                       DbgLogger.EndEvent (DbgEvtType.Drawing, true);
+                       DbgLogger.EndEvent (DbgEvtType.ProcessDrawing, true);
                }
                #endregion
 
@@ -1613,7 +1615,7 @@ namespace Crow
                }
                void toolTipThreadFunc ()
                {
-                       while (true) {
+                       while (true) {                  
                                if (tooltipTimer.ElapsedMilliseconds > TOOLTIP_DELAY) {
                                        if (!tooltipVisible) {
                                                Widget g = _hoverWidget;
@@ -1654,14 +1656,18 @@ namespace Crow
                }
                void ToolTipContainer_LayoutChanged (object sender, LayoutingEventArgs e)
                {
-                       Widget ttc = sender as Widget;
+                       Widget ttc = sender as Widget;                          
+                                       
                        //tooltip container datasource is the widget triggering the tooltip
                        Rectangle r = ScreenCoordinates ((ttc.DataSource as Widget).Slot);
 
                        if (e.LayoutType == LayoutingType.X) {
-                                       if (ttc.Slot.Right > clientRectangle.Right)
-                                               ttc.Left = clientRectangle.Right - ttc.Slot.Width;
-                       }/* else if (e.LayoutType == LayoutingType.Y) {
+                               if (ttc.Slot.Right > clientRectangle.Right)
+                                       ttc.Left = clientRectangle.Right - ttc.Slot.Width;                                              
+                       }else if (e.LayoutType == LayoutingType.Y) {
+                               if (ttc.Slot.Bottom > clientRectangle.Bottom)
+                                       ttc.Top = clientRectangle.Bottom - ttc.Slot.Height;
+                       }/*
                                if (ttc.Slot.Height < tc.ClientRectangle.Height) {
                                        if (PopDirection.HasFlag (Alignment.Bottom)) {
                                                if (r.Bottom + ttc.Slot.Height > tc.ClientRectangle.Bottom)
@@ -1678,6 +1684,7 @@ namespace Crow
                                } else
                                        ttc.Top = 0;
                        }*/
+
                }
                #endregion
 
index 9253424ed12a42c7d112abf61845322dd40fcf0c..5cd60dc141f35466f21ef256523d19d74d9fd920 100644 (file)
@@ -443,6 +443,10 @@ namespace Crow.Cairo {
                {
                        Rectangle (rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
                }
+               public void Rectangle (Crow.RectangleD rectangle)
+               {
+                       Rectangle (rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
+               }
 
                public void Rectangle (PointD p, double width, double height)
                {
index 35dcee00a7354ee78673dd759f68863002a1f335..009aed78be37ebc76ccad76ac81f5d0125e5e977 100644 (file)
@@ -105,7 +105,7 @@ namespace Crow
 
                public override void onMouseClick (object sender, MouseButtonEventArgs e)
                {
-                       command?.Execute ();
+                       command?.Execute (this);
                        e.Handled = true;
                        base.onMouseClick (sender, e);
                }
index c30c79a42bb22a0c64b5b34a9adec6f68942ce35..aa77839e4ea6630d17d6486a79dae2d72790b7dc 100644 (file)
@@ -37,6 +37,7 @@ namespace Crow
 
                #region private fields
                Enum enumValue;
+               UInt32 bitFieldExcludeMask;
                Type enumType;
                bool enumTypeIsBitsfield;
                string rbStyle, iconsPrefix, iconsExtension;            
@@ -102,19 +103,24 @@ namespace Crow
 
                                                if (enumTypeIsBitsfield) {
                                                        IML.Instantiator iTor = IFace.CreateITorFromIMLFragment ($"<CheckBox Style='{rbStyle}'/>");
-                                                       UInt32 currentValue = Convert.ToUInt32 (EnumValue);
+                                                       UInt32 currentValue = Convert.ToUInt32 (EnumValue);                                                     
+                                                       currentValue &= ~bitFieldExcludeMask;
+                                                       enumValue = (Enum)Enum.ToObject(enumType, currentValue);
 
                                                        foreach (Enum en in enumType.GetEnumValues()) {
+                                                               UInt32 eni = Convert.ToUInt32 (en);
+                                                               if ((eni & bitFieldExcludeMask) != 0)
+                                                                       continue;
+
                                                                CheckBox rb = iTor.CreateInstance<CheckBox> ();
                                                                rb.Caption = en.ToString();
                                                                rb.LogicalParent = this;
-                                                               rb.Tag = $"{iconsPrefix}{en}{IconsExtension}";
-
-                                                               UInt32 eni = Convert.ToUInt32 (en);
+                                                               rb.Tag = $"{iconsPrefix}{en}{IconsExtension}";                                                          
                                                                rb.Tooltip = $"0x{eni:x8}";
+
                                                                if (eni == 0) {
                                                                        rb.IsChecked = currentValue == 0;
-                                                                       rb.Checked += (sender, e) => EnumValue = (Enum)Enum.ToObject(enumType, 0);                                                                              
+                                                                       rb.Checked += (sender, e) => EnumValue = (Enum)Enum.ToObject(enumType, 0);
                                                                } else {                                                                
                                                                        rb.IsChecked = currentValue == 0 ? false : EnumValue.HasFlag (en);
                                                                        rb.Checked += onChecked;
@@ -145,7 +151,10 @@ namespace Crow
 
 
                                        } else if (enumTypeIsBitsfield) {
-                                               UInt32 currentValue = Convert.ToUInt32 (EnumValue);
+                                               UInt32 currentValue = Convert.ToUInt32 (EnumValue);                                             
+                                               currentValue &= ~bitFieldExcludeMask;
+                                               enumValue = (Enum)Enum.ToObject(enumType, currentValue);
+
                                                if (currentValue == 0) {
                                                        foreach (CheckBox rb in enumValueContainer.Children) {
                                                                Enum en = (Enum)Enum.Parse(enumType, rb.Caption);
@@ -181,7 +190,20 @@ namespace Crow
                        }
                }
                #endregion
-
+               /// <summary>
+               /// Include mask for bitfields. Used to ignore enum values in display.
+               /// </summary>
+               /// <value>UInt32 bitfield mask</value>
+               public UInt32 BitFieldExcludeMask {
+                       get => bitFieldExcludeMask;
+                       set {
+                               if (bitFieldExcludeMask == value)
+                                       return;
+                               bitFieldExcludeMask = value;
+                               NotifyValueChangedAuto(bitFieldExcludeMask);
+                               forceRefresh();
+                       }
+               }
                void onChecked (object sender, EventArgs e) {                   
                        Enum en =(Enum)Enum.Parse (enumType, (sender as CheckBox).Caption);
                        UInt32 newVal = Convert.ToUInt32 (en);
index b2fbe650a3cf1ac9e06406d075ceff7c2d11d6a6..d0b94f377ceb827b1953e38ffba3dd36630b4239 100644 (file)
@@ -66,6 +66,7 @@ namespace Crow {
                        return base.measureRawSize (lt);
                }
                public virtual void ComputeChildrenPositions () {
+                       DbgLogger.StartEvent(DbgEvtType.GOComputeChildrenPositions, this);
                        int d = 0;
                        if (Orientation == Orientation.Horizontal) {
                                foreach (Widget c in Children) {
@@ -83,6 +84,7 @@ namespace Crow {
                                }
                        }
                        IsDirty = true;
+                       DbgLogger.EndEvent(DbgEvtType.GOComputeChildrenPositions);
                }
                Widget stretchedGO = null;
                public override bool UpdateLayout (LayoutingType layoutType) {
@@ -145,6 +147,7 @@ namespace Crow {
                }
 
                public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
+                       DbgLogger.StartEvent(DbgEvtType.GOOnChildLayoutChange, this);
                        Widget go = sender as Widget;
                        //Debug.WriteLine ("child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString());
                        switch (arg.LayoutType) {
@@ -157,6 +160,7 @@ namespace Crow {
                                                } else if (stretchedGO != go) {
                                                        go.Slot.Width = 0;
                                                        go.Width = Measure.Fit;
+                                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                                                        return;
                                                }
                                        } else if (stretchedGO == go) {
@@ -172,6 +176,7 @@ namespace Crow {
                                                this.RegisterForLayouting (LayoutingType.Width);
 
                                        this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                                        return;
                                }
                                break;
@@ -184,6 +189,7 @@ namespace Crow {
                                                } else if (stretchedGO != go) {
                                                        go.Slot.Height = 0;
                                                        go.Height = Measure.Fit;
+                                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                                                        return;
                                                }
                                        } else if (stretchedGO == go) {
@@ -198,11 +204,13 @@ namespace Crow {
                                                this.RegisterForLayouting (LayoutingType.Height);
 
                                        this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                                        return;
                                }
                                break;
                        }
                        base.OnChildLayoutChanges (sender, arg);
+                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                }
                #endregion
 
index 480ecaaf0475a15ab781376d72dc11566fffd44a..0500d1290de0044609f21311e3073f8943fa675c 100644 (file)
@@ -326,7 +326,7 @@ namespace Crow
                                        childrenRWLock.EnterReadLock ();
 
                                        foreach (Widget c in Children) {
-                                               if (!c.Visible)
+                                               if (!c.IsVisible)
                                                        continue;
                                                if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
                                                        continue;
@@ -352,12 +352,16 @@ namespace Crow
 
                public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
                {
+                       DbgLogger.StartEvent(DbgEvtType.GOOnChildLayoutChange, this);
+
                        Widget g = sender as Widget;
 
                        switch (arg.LayoutType) {
                        case LayoutingType.Width:
-                               if (Width != Measure.Fit)
+                               if (Width != Measure.Fit) {
+                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                                        return;
+                               }
                                if (g.Slot.Width > contentSize.Width) {
                                        largestChild = g;
                                        contentSize.Width = g.Slot.Width;
@@ -367,8 +371,10 @@ namespace Crow
                                this.RegisterForLayouting (LayoutingType.Width);
                                break;
                        case LayoutingType.Height:
-                               if (Height != Measure.Fit)
+                               if (Height != Measure.Fit) {
+                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);                                   
                                        return;
+                               }
                                if (g.Slot.Height > contentSize.Height) {
                                        tallestChild = g;
                                        contentSize.Height = g.Slot.Height;
@@ -378,6 +384,7 @@ namespace Crow
                                this.RegisterForLayouting (LayoutingType.Height);
                                break;
                        }
+                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
                }
                //TODO: x,y position should be taken in account for computation of width and height
                void resetChildrenMaxSize(){
@@ -392,7 +399,7 @@ namespace Crow
                        largestChild = null;
                        contentSize.Width = 0;
                        for (int i = 0; i < Children.Count; i++) {
-                               if (!Children [i].Visible)
+                               if (!Children [i].IsVisible)
                                        continue;
                                int cw = 0;
                                if (forceMeasure)
@@ -416,7 +423,7 @@ namespace Crow
                        tallestChild = null;
                        contentSize.Height = 0;
                        for (int i = 0; i < Children.Count; i++) {
-                               if (!Children [i].Visible)
+                               if (!Children [i].IsVisible)
                                        continue;
                                int ch = 0;
                                if (forceMeasure)
index b9b9d1f31484b61d3f9cf2cf003260f087f65201..d56f521394594eeec1b2f5638ffa722600bfaadd 100644 (file)
@@ -145,7 +145,7 @@ namespace Crow
                public override void onMouseClick (object sender, MouseButtonEventArgs e)
                {
                        if (command != null) {
-                               command.Execute ();
+                               command.Execute (this);
                                closeMenu ();
                        }
                        if (hasClick)
index fd3dd2448e89de593feccf181b8aae46afca95d3..8ef519f1004a98b5cf0b9b70f322ab59116af5e1 100644 (file)
@@ -34,6 +34,9 @@ namespace Crow
                void updateCursor () {
                        if (cursorRatio < 0)
                                return;
+                       ILayoutable l = cursor?.Parent;
+                       if (l == null)
+                               return;
                        Rectangle r = cursor.Parent.ClientRectangle;
                        if (Orientation == Orientation.Horizontal)
                                CursorSize = (int)(cursorRatio * r.Width);
index 2545ffc7cb6752a3095ec273977d41a81f1dcebe..3173996d77eec94797724195ef65c0d225a27bc4 100644 (file)
@@ -123,11 +123,12 @@ namespace Crow
                /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
                public override void onMouseWheel (object sender, MouseWheelEventArgs e)
                {
-                       base.onMouseWheel (sender, e);
                        if (IFace.Shift)
                                ScrollX += e.Delta * MouseWheelSpeed;
                        else
                                ScrollY -= e.Delta * MouseWheelSpeed;
+                       e.Handled = true;
+                       base.onMouseWheel (sender, e);
                }
                /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
                public override void onKeyDown (object sender, KeyEventArgs e)
index b99fadfd1e8542b229f6e97625b4596cb79a38f8..ca4089ec74a94d193872721da29f52335f80c0b8 100644 (file)
@@ -26,12 +26,12 @@ namespace Crow
                        cursor = child.FindByName ("Cursor");
                        if (cursor == null)
                                return;
-                       (cursor.Parent as Widget).LayoutChanged += HandleCursorContainerLayoutChanged;
+                       (cursor.Parent as Widget).LayoutChanged += HandleCursorContainerLayoutChanged;//too difficult to unregister
                        updateCursorWidgetProps ();
                }
 
                protected virtual void HandleCursorContainerLayoutChanged (object sender, LayoutingEventArgs e)
-               {                       
+               {
                        computeCursorPosition ();
                }
                #endregion
@@ -206,5 +206,11 @@ namespace Crow
                {
                        Value += SmallIncrement;
                }
+
+               protected override void Dispose(bool disposing)
+               {
+                       base.Dispose(disposing);
+
+               }
        }
 }
index 440322fd100bd73edc0f0e52ac41eff8127e2e88..68538e8dc106651042c90e24e42ac18838dda190 100644 (file)
@@ -31,6 +31,10 @@ namespace Crow
                }
                public Orientation OppositeOrientation 
                        => orientation == Orientation.Vertical ? Orientation.Horizontal : Orientation.Vertical;         
+               public Measure TabWidth
+                       => orientation == Orientation.Vertical ? Measure.Stretched : Measure.Fit;               
+               public Measure TabHeight
+                       => orientation == Orientation.Horizontal ? Measure.Stretched : Measure.Fit;             
        }
 }
 
index 81f085258855619b16c1f1109a58b9fb5b92dd8c..47ac67f53ec8ae5192ee21785c93e0b8749feebc 100644 (file)
@@ -290,7 +290,7 @@ namespace Crow
                bool allowDrop;
                string allowedDropTypes;
                string tooltip;
-               IList<Command> contextCommands;
+               CommandGroup contextCommands;
                #endregion
 
                #region public fields
@@ -325,7 +325,7 @@ namespace Crow
                #endregion
 
                #region ILayoutable
-               [XmlIgnore]public LayoutingType RegisteredLayoutings { get { return registeredLayoutings; } set { registeredLayoutings = value; } }
+               [XmlIgnore]public LayoutingType RegisteredLayoutings { get => registeredLayoutings; set => registeredLayoutings = value; }
                //TODO: it would save the recurent cost of a cast in event bubbling if parent type was GraphicObject
                //              or we could add to the interface the mouse events
                /// <summary>
@@ -499,7 +499,7 @@ namespace Crow
                /// </summary>
                [DesignCategory ("Behavior")][DefaultValue(true)]
                public virtual bool CacheEnabled {
-                       get { return cacheEnabled; }
+                       get => cacheEnabled;
                        set {
                                if (cacheEnabled == value)
                                        return;
@@ -510,9 +510,9 @@ namespace Crow
                /// <summary>
                /// If true, rendering of GraphicObject is clipped inside client rectangle
                /// </summary>
-               [DesignCategory ("Appearance")][DefaultValue(false)]
+               [DesignCategory ("Appearance")][DefaultValue(true)]
                public virtual bool ClipToClientRect {
-                       get { return clipToClientRect; }
+                       get => clipToClientRect;
                        set {
                                if (clipToClientRect == value)
                                        return;
@@ -521,11 +521,9 @@ namespace Crow
                                this.RegisterForRedraw ();
                        }
                }
-               #if DEBUG_LOG
-               [XmlIgnore]public string TreePath {
-                       get { return this.GetType().Name + GraphicObjects.IndexOf(this).ToString ();    }
-               }
-               #endif
+#if DEBUG_LOG
+               [XmlIgnore]public string TreePath => this.GetType().Name + GraphicObjects.IndexOf(this).ToString ();
+#endif
                /// <summary>
                /// Name is used in binding to reference other GraphicObjects inside the graphic tree
                /// and by template controls to find special element in their template implementation such
@@ -914,10 +912,18 @@ namespace Crow
                                        return;
 
                                isVisible = value;
-
+                               
                                if (!isVisible)
                                        unshownPostActions ();
                                RegisterForLayouting (LayoutingType.Sizing);
+                               
+                               /*if (isVisible){                                                                               
+                                       IsDirty = true;
+                                       RegisterForLayouting(LayoutingType.Sizing);
+                               } else {
+                                       unshownPostActions ();                                  
+                               }*/
+                               
 
                                NotifyValueChangedAuto (isVisible);
                        }
@@ -1089,8 +1095,8 @@ namespace Crow
                        }
                }
                [DesignCategory ("Divers")]
-               public IList<Command> ContextCommands {
-                       get { return contextCommands; }
+               public CommandGroup ContextCommands {
+                       get => contextCommands;
                        set {
                                if (contextCommands == value)
                                        return;
@@ -1467,7 +1473,7 @@ namespace Crow
                /// <param name="clip">Clip rectangle</param>
                public virtual void RegisterClip(Rectangle clip){
                        if (disposed) {
-                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GORegisterClip);
+                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GORegisterClip, this);
                                return;
                        }
                        DbgLogger.StartEvent(DbgEvtType.GORegisterClip, this);
@@ -1500,43 +1506,49 @@ namespace Crow
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                public void RegisterForGraphicUpdate ()
                {
-#if DEBUG_LOG
                        if (disposed) {
                                DbgLogger.AddEvent (DbgEvtType.GORegisterForGraphicUpdate | DbgEvtType.AlreadyDisposed, this);
                                return;
                        }
-#endif
-                       IsDirty = true;
+                       DbgLogger.StartEvent(DbgEvtType.GORegisterForGraphicUpdate, this);
+
+                       IsDirty = true;                 
                        if (Width.IsFit || Height.IsFit)
                                RegisterForLayouting (LayoutingType.Sizing);
                        else if (RegisteredLayoutings == LayoutingType.None)
                                IFace.EnqueueForRepaint (this);
+
+                       DbgLogger.EndEvent(DbgEvtType.GORegisterForGraphicUpdate);
                }
                /// <summary> query an update of the content without layouting changes</summary>
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                public void RegisterForRedraw ()
                {
-#if DEBUG_LOG
                        if (disposed) {
                                DbgLogger.AddEvent (DbgEvtType.GORegisterForRedraw | DbgEvtType.AlreadyDisposed, this);
                                return;
                        }
-#endif
                        IsDirty = true;
                        if (RegisteredLayoutings == LayoutingType.None)
                                IFace.EnqueueForRepaint (this);
                }
+               public void RegisterForRepaint () {
+                       if (RegisteredLayoutings == LayoutingType.None && !IsDirty)
+                               IFace.EnqueueForRepaint (this);
+               }
                #endregion
 
                #region Layouting
 
                /// <summary> return size of content + margins </summary>
                public virtual int measureRawSize (LayoutingType lt) {
-#if DEBUG_LOG
-                       DbgLogger.AddEvent(DbgEvtType.GOMeasure, this);
-#endif
-                       return lt == LayoutingType.Width ?
+                       DbgLogger.StartEvent(DbgEvtType.GOMeasure, this, lt);
+
+                       int tmp = lt == LayoutingType.Width ?
                                contentSize.Width + 2 * margin: contentSize.Height + 2 * margin;
+
+                       DbgLogger.EndEvent(DbgEvtType.GOMeasure);
+                       return tmp;
                }
 
                internal bool firstUnresolvedFitWidth (out  Widget ancestorInUnresolvedFit)
@@ -1564,12 +1576,11 @@ namespace Crow
                public virtual void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType){ }
                /// <summary> Query a layouting for the type pass as parameter, redraw only if layout changed. </summary>
                public virtual void RegisterForLayouting(LayoutingType layoutType){
-#if DEBUG_LOG
                        if (disposed) {
-                               DbgLogger.AddEvent (DbgEvtType.GORegisterLayouting | DbgEvtType.AlreadyDisposed, this);
+                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed, this);
                                return;
                        }
-#endif
+
                        if (Parent == null)
                                return;
                        DbgLogger.StartEvent (DbgEvtType.GOLockLayouting, this);
@@ -1843,6 +1854,9 @@ namespace Crow
                /// of the widget </summary>
                public virtual void Paint (Context ctx)
                {
+                       if (!IsVisible)
+                               return;
+
                        DbgLogger.StartEvent (DbgEvtType.GOPaint, this);
 
                        //TODO:this test should not be necessary
@@ -1888,10 +1902,12 @@ namespace Crow
                                        ctx.Translate (rb.X, rb.Y);
 
                                        onDraw (ctx);
-                                       if (!IsEnabled)
-                                               paintDisabled (ctx, Slot);
 
                                        ctx.Restore ();
+
+                                       if (!IsEnabled)
+                                               paintDisabled (ctx, rb);
+
                                }
                                LastPaintedSlot = Slot;
                        }
@@ -1900,11 +1916,11 @@ namespace Crow
                        DbgLogger.EndEvent (DbgEvtType.GOPaint);
                }
                void paintDisabled(Context gr, Rectangle rb){
-                       gr.Operator = Operator.Xor;
-                       gr.SetSource (0.1, 0.1, 0.1, 0.8);
+                       //gr.Operator = Operator.Xor;
+                       gr.SetSource (0.2, 0.2, 0.2, 0.8);
                        gr.Rectangle (rb);
                        gr.Fill ();
-                       gr.Operator = Operator.Over;
+                       //gr.Operator = Operator.Over;
                }
                #endregion
 
@@ -2130,6 +2146,21 @@ namespace Crow
                /// Checks to handle when widget is removed from the visible graphic tree
                /// </summary>
                void unshownPostActions () {
+                       //IsDirty = true;
+
+                       /*if (parent is Widget p)
+                               p.RegisterForGraphicUpdate();
+                       else*/
+                       /*try
+                       {
+                               parent?.RegisterClip (ContextCoordinates(LastPaintedSlot));
+                       }
+                       catch (System.Exception e)
+                       {
+                               Debug.WriteLine($"[ERR]:unshownPostActions:{e}");
+                       }*/
+                               
+
                        if (IFace.ActiveWidget != null) {
                                if (IFace.ActiveWidget.IsOrIsInside (this))
                                        IFace.ActiveWidget = null;
@@ -2151,6 +2182,24 @@ namespace Crow
                                        IFace.OnMouseMove (IFace.MousePosition.X, IFace.MousePosition.Y);
                                }
                        }
+                       
+                       /*Slot = default;
+                       try
+                       {
+                               if (LastSlots.Width > 0)
+                                       OnLayoutChanges (LayoutingType.Width);
+                               if (LastSlots.Height > 0)
+                                       OnLayoutChanges (LayoutingType.Height);
+                               OnLayoutChanges (LayoutingType.X);
+                               OnLayoutChanges (LayoutingType.Y);                              
+                       }
+                       catch (System.Exception ex)
+                       {
+                               Console.WriteLine($"[ERROR]Unshown post actions: {ex}");
+                       }
+                       LastSlots = default;
+                       LastPaintedSlot = default;*/
+                       
                }
        }
 }
index 39648139c3656b1efd5639cceae911c87ebf1d6b..a0fac5366f488e491d6280b37c95814435218e15 100644 (file)
@@ -28,7 +28,7 @@ namespace Crow
                        if (Orientation == Orientation.Vertical) {
                                int tallestChild = 0;
                                foreach (Widget c in Children) {
-                                       if (!c.Visible)
+                                       if (!c.IsVisible)
                                                continue;
                                        if (dx + c.Slot.Width > ClientRectangle.Width) {
                                                dx = 0;
@@ -47,7 +47,7 @@ namespace Crow
                        } else {
                                int largestChild = 0;
                                foreach (Widget c in Children) {
-                                       if (!c.Visible)
+                                       if (!c.IsVisible)
                                                continue;
                                        if (dy + c.Slot.Height > ClientRectangle.Height) {
                                                dy = 0;
diff --git a/CrowDbgShared/CrowDbgShared.csproj b/CrowDbgShared/CrowDbgShared.csproj
new file mode 100644 (file)
index 0000000..0ae4978
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">  
+       <PropertyGroup>
+               <OutputType>Library</OutputType>
+               <TargetFrameworks>netstandard2.1</TargetFrameworks>
+               <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+       </PropertyGroup>
+       <ItemGroup>
+               <PackageReference Include="glfw-sharp" Version="$(GlfwSharpVersion)" />
+       </ItemGroup>
+       <ItemGroup>
+               <Compile Include="src\**\*.cs"/>
+       </ItemGroup>
+</Project>
diff --git a/CrowDbgShared/src/SharedDelegates.cs b/CrowDbgShared/src/SharedDelegates.cs
new file mode 100644 (file)
index 0000000..aee1ef1
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Linq;
+using Glfw;
+
+namespace CrowDbgShared
+{
+       public delegate void InterfaceResizeDelegate(int a, int b);
+       public delegate bool InterfaceMouseMoveDelegate(int a, int b);
+       public delegate bool InterfaceMouseButtonDelegate(MouseButton button);
+       public delegate void VoidDelegate();
+       public delegate IntPtr IntPtrGetterDelegate();
+}
+
index 650c49bdcdceba1856dbd7c882037cb3dae1fb3e..41e782011e66e3d623e9be61c4e1b66a29ac5976 100644 (file)
@@ -9,5 +9,7 @@
                <CrowVersion>0.9.4</CrowVersion>
                <CrowPackageVersion>$(CrowVersion)-beta</CrowPackageVersion>
                <CrowStbSharp>true</CrowStbSharp>
+               <CrowDebugLogEnabled>false</CrowDebugLogEnabled>
+               <GlfwSharpVersion>0.2.11-beta</GlfwSharpVersion>
        </PropertyGroup>
 </Project>
index 656c05a37e7727dc3dedb17fa8a05feec552a44d..954d4879d6445954deb5f3468e75b7457b3b9318 100644 (file)
@@ -18,12 +18,12 @@ namespace tests
 
                protected override void OnInitialized ()
                {
-                       Commands = new List<Crow.Command> (new Crow.Command [] {
+                       Commands = new CommandGroup (
                                new Crow.Command("command1", new Action(() => Console.WriteLine ("command1 triggered"))),
                                new Crow.Command("command2", new Action(() => Console.WriteLine ("command2 triggered"))),
                                new Crow.Command("command3", new Action(() => Console.WriteLine ("command3 triggered"))),
-                               new Crow.Command("command4", new Action(() => Console.WriteLine ("command4 triggered"))),
-                       });
+                               new Crow.Command("command4", new Action(() => Console.WriteLine ("command4 triggered")))
+                       );
 
                        // += KeyboardKeyDown1;
 
diff --git a/Samples/ControlLib/Class1.cs b/Samples/ControlLib/Class1.cs
deleted file mode 100644 (file)
index 23bcb16..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-using System;
-
-namespace ControlLib
-{
-       public class Class1
-       {
-       }
-}
diff --git a/Samples/ControlLib/ControlLib.csproj b/Samples/ControlLib/ControlLib.csproj
deleted file mode 100644 (file)
index 2a6fdb4..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">  
-  <PropertyGroup>
-    <TargetFrameworks>netstandard2.1</TargetFrameworks>
-    <EnableDefaultNoneItems>false</EnableDefaultNoneItems>     
-  </PropertyGroup>
-            
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DefineConstants>TRACE;DEBUG</DefineConstants>
-  </PropertyGroup>
-  <ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
-    <Reference Include="System" />
-  </ItemGroup>    
-
-  <ItemGroup>  
-    <ProjectReference Include="..\..\Crow\Crow.csproj" />
-  </ItemGroup>    
-    
-  <ItemGroup>
-    <EmbeddedResource Include="ui\**\*.*">
-      <LogicalName>ControlLib.%(Filename)%(Extension)</LogicalName>
-    </EmbeddedResource>                
-  </ItemGroup>
-</Project>
diff --git a/Samples/CrowDebugger/CrowDebugAssemblyLoadContext.cs b/Samples/CrowDebugger/CrowDebugAssemblyLoadContext.cs
new file mode 100644 (file)
index 0000000..0c629fc
--- /dev/null
@@ -0,0 +1,15 @@
+using System.Threading;
+using System;
+using System.Runtime.Loader;
+using System.Reflection;
+
+namespace CrowDebugger
+{
+       public class CrowDebugAssemblyLoadContext : AssemblyLoadContext
+       {
+               protected override Assembly Load(AssemblyName assemblyName)
+               {
+                       return base.Load(assemblyName);
+               }
+       }
+}
\ No newline at end of file
diff --git a/Samples/CrowDebugger/CrowDebugger.csproj b/Samples/CrowDebugger/CrowDebugger.csproj
new file mode 100644 (file)
index 0000000..c73e0d1
--- /dev/null
@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+  </PropertyGroup>
+
+</Project>
diff --git a/Samples/CrowDebugger/Program.cs b/Samples/CrowDebugger/Program.cs
new file mode 100644 (file)
index 0000000..b15e3b1
--- /dev/null
@@ -0,0 +1,58 @@
+using System.Threading;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace CrowDebugger
+{
+       class Program
+       {
+               const int BUFF_MAX = 1024;
+               static void Main(string[] args)
+               {
+                       AssemblyLoadContext crowLoadCtx = new AssemblyLoadContext("CrowDebuggerLoadContext");
+                       Console.WriteLine("Crow Debugger started.");
+                       char[] buffer = new char[1024];
+                       int buffPtr = 0;
+                       while (true)
+                       {                               
+                               if (Console.KeyAvailable)
+                               {
+                                       ConsoleKeyInfo key = Console.ReadKey(true);
+                                       if (key.Key == ConsoleKey.Enter) {
+                                               Span<char> cmd = buffer.AsSpan(0, buffPtr);
+                                               Console.WriteLine($"=> {cmd.ToString()}");
+                                               if (cmd[0] == 'q' || cmd.SequenceEqual ("quit"))
+                                                       break;
+                                               
+                                               if (cmd.StartsWith("load")) {
+                                                       using(crowLoadCtx.EnterContextualReflection()) {
+                                                               string str = cmd.Slice(5).ToString();
+                                                               Console.WriteLine($"[msg]:Trying to load crow dll from: '{str}'");
+                                                               if (!File.Exists (str)) {
+                                                                       Console.WriteLine ($"[error]:File not found: {str}");
+                                                               } else {
+                                                                       Assembly crowAssembly = crowLoadCtx.LoadFromAssemblyPath (str);
+                                                                       if (crowAssembly == null) {
+                                                                               Console.WriteLine($"[error]:Failed to load crow dll from: {str}");
+                                                                       } else {
+                                                                               Console.WriteLine($"[ok]:Crow Assembly loaded:{crowAssembly.FullName}");
+                                                                               
+                                                                       }
+                                                               }
+                                                       }
+                                               } else
+                                                       Console.WriteLine($"=> {cmd.ToString()}");
+                                               buffPtr = 0;
+                                               continue;
+                                       }
+                                               
+                                       buffer[buffPtr++] = key.KeyChar;
+                               }
+                       }
+
+                       Console.WriteLine("exited");
+               }
+       }
+}
diff --git a/Samples/DebugLogAnalyzer/DbgEventWidget.cs b/Samples/DebugLogAnalyzer/DbgEventWidget.cs
deleted file mode 100644 (file)
index b2af84d..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using Crow.Cairo;
-
-namespace Crow
-{
-       public class DbgEventWidget : Widget
-       {
-               public DbgEventWidget (){}
-
-               DbgEvent evt, hoverEvt;
-               long ticksPerPixel;
-               double pixelPerTick;
-
-               public DbgEvent Event {
-                       get => evt;
-                       set {
-                               if (evt == value)
-                                       return;
-                               evt = value;
-                               updatePixelPerTicks ();
-                               NotifyValueChangedAuto (evt);
-                               RegisterForRedraw ();
-                       }
-               }
-               public DbgEvent HoverEvent {
-                       get => hoverEvt;
-                       private set {
-                               if (hoverEvt == value)
-                                       return;
-                               hoverEvt = value;
-                               NotifyValueChangedAuto (hoverEvt);
-                       }
-               }
-
-               [DefaultValue ("1000")]
-               public long TicksPerPixel {
-                       get => ticksPerPixel;
-                       set {
-                               if (ticksPerPixel == value)
-                                       return;
-                               ticksPerPixel = value;
-                               NotifyValueChangedAuto (ticksPerPixel);
-                               if (Width == Measure.Fit)
-                                       RegisterForLayouting (LayoutingType.Width);
-                       }
-               }
-
-               public override int measureRawSize (LayoutingType lt)
-               {
-                       updatePixelPerTicks ();
-                       if (lt == LayoutingType.Width)
-                               contentSize.Width = Event == null ? 0 : (int)Math.Max(pixelPerTick * Event.Duration, 2);
-                       
-                       return base.measureRawSize (lt);
-               }
-
-               public override void OnLayoutChanges (LayoutingType layoutType)
-               {
-                       if (layoutType == LayoutingType.Width)
-                               updatePixelPerTicks ();
-
-                       base.OnLayoutChanges (layoutType);
-               }
-
-               protected override void onDraw (Context gr)
-               {
-                       if (Event == null) {
-                               base.onDraw (gr);
-                               return;
-                       }
-
-                       gr.LineWidth = 1;
-                       gr.SetDash (new double [] { 1.0, 3.0 }, 0);
-
-                       Rectangle cb = ClientRectangle;
-
-                       if (Event.Duration == 0) {
-                               gr.SetSource (Event.Color);
-                               gr.Rectangle (cb);
-                               gr.Fill ();
-                               return;
-                       }
-
-                       drawEvent (gr, cb.Height, Event);
-               }
-               void drawEvent (Context ctx, int h, DbgEvent dbge)
-               {
-                       double w = Math.Max(dbge.Duration * pixelPerTick, 2.0);
-                       double x = (dbge.begin - Event.begin) * pixelPerTick;
-
-                       ctx.Rectangle (x, Margin, w, h);
-                       ctx.SetSource (dbge.Color);
-                       if (dbge.IsSelected) {
-                               ctx.FillPreserve ();
-                               ctx.SetSource (1, 1, 1);
-                               ctx.Stroke ();
-                       }else
-                               ctx.Fill ();
-
-                       if (dbge.Events == null)
-                               return;
-                       foreach (DbgEvent e in dbge.Events)
-                               drawEvent (ctx, h, e);
-               }
-
-               public override void onMouseMove (object sender, MouseMoveEventArgs e)
-               {
-                       if (Event != null) {
-                               Point m = ScreenPointToLocal (e.Position);
-                               long curTick = (long)(m.X / pixelPerTick) + Event.begin;
-                               /*if (Width == Measure.Fit) 
-                                       NotifyValueChanged ("HoverEvent", Event);
-                               else*/
-                               HoverEvent = hoverEvent (Event, curTick);
-
-                               e.Handled = true;
-                       }
-                       base.onMouseMove (sender, e);
-               }
-
-               DbgEvent hoverEvent (DbgEvent hevt, long curTick){
-                       if (hevt.Events != null) {
-                               foreach (DbgEvent e in hevt.Events) {
-                                       if (curTick >= e.begin && curTick <= e.end)
-                                               return hoverEvent (e, curTick);
-                               }
-                       }
-                       return hevt;
-               }
-               void updatePixelPerTicks ()
-               {
-                       if (Width == Measure.Fit)
-                               pixelPerTick = 1.0 / ticksPerPixel;
-                       else
-                               pixelPerTick = Event == null ? 0 : (double)ClientRectangle.Width / Event.Duration;
-               }
-       }
-}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/DbgLogViewer.cs b/Samples/DebugLogAnalyzer/DbgLogViewer.cs
deleted file mode 100644 (file)
index 49facb5..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Crow.Cairo;
-
-namespace Crow
-{
-       public class DbgLogViewer : ScrollingObject
-       {
-               public static Dictionary<DbgEvtType, Color> colors;
-
-               public static Configuration colorsConf = new Configuration ("dbgcolor.conf");//, Interface.GetStreamFromPath("#Crow.dbgcolor.conf"));
-
-               public static void reloadColors () {
-                       colors = new Dictionary<DbgEvtType, Color>();
-                       foreach (string n in colorsConf.Names) {
-                               DbgEvtType t = (DbgEvtType)Enum.Parse (typeof(DbgEvtType), n);
-                               Color c = colorsConf.Get<Color> (n);
-                               colors.Add (t, c);
-                       }
-
-               }
-               #region CTOR
-               static DbgLogViewer() {
-                       reloadColors ();
-               }
-               protected DbgLogViewer () : base(){}
-               public DbgLogViewer (Interface iface, string style = null) : base(iface, style){}
-               #endregion
-
-               FontExtents fe;
-
-               double xScale = 1.0/1024.0, yScale = 1.0, leftMargin, topMargin = 0.0;
-               DbgWidgetRecord curWidget, hoverWidget;
-               DbgEvent curEvent, hoverEvent;
-
-               List<DbgEvent> events = new List<DbgEvent> ();
-               List<DbgWidgetRecord> widgets = new List<DbgWidgetRecord> ();
-
-               public List<DbgEvent> Events {
-                       get => events;
-                       set {
-                               if (events == value)
-                                       return;
-                               events = value;
-                               NotifyValueChanged (nameof (Events), events);
-                               if (events == null)
-                                       return;
-
-                               maxTicks = 0;
-                               minTicks = long.MaxValue;
-                               foreach (DbgEvent e in events) {
-                                       if (e.begin < minTicks)
-                                               minTicks = e.begin;
-                                       if (e.end > maxTicks)
-                                               maxTicks = e.end;
-                               }
-
-                               visibleTicks = maxTicks - minTicks;
-                               XScale = (ClientRectangle.Width - leftMargin)/visibleTicks;
-                               ScrollX = 0;
-                               ScrollY = 0;
-
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               public List<DbgWidgetRecord> Widgets {
-                       get => widgets;
-                       set {
-                               if (widgets == value)
-                                       return;
-                               widgets = value;
-                               NotifyValueChanged (nameof (Widgets), widgets);
-                               updateMargins ();
-                               updateMaxScrollX ();
-                               updateMaxScrollY ();
-                       }
-               }
-               public DbgWidgetRecord CurrentWidget {
-                       get => curWidget;
-                       set {
-                               if (curWidget == value)
-                                       return;
-                               curWidget = value;
-                               NotifyValueChanged (nameof (CurrentWidget), curWidget);
-                       }
-               }
-               public DbgEvent CurrentEvent {
-                       get => curEvent;
-                       set {
-                               if (curEvent == value)
-                                       return;
-                               if (curEvent != null)
-                                       curEvent.IsSelected = false;
-                               curEvent = value;
-                               if (curEvent != null) {
-                                       curEvent.IsSelected = true;
-                                       if (curEvent is DbgWidgetEvent we) {
-                                               //CurrentWidget = Widgets [we.InstanceIndex];
-                                               currentLine = we.InstanceIndex;
-                                       }
-                                       currentTick = curEvent.begin;
-                                       if (curEvent.begin > minTicks + ScrollX + visibleTicks ||
-                                               curEvent.end < minTicks + ScrollX) {
-                                               ScrollX = (int)(currentTick - visibleTicks / 2);
-                                       }
-                               }
-                               NotifyValueChanged (nameof (CurrentEvent), curEvent);
-                               RegisterForRedraw ();
-                       }
-               }
-               public DbgWidgetRecord HoverWidget {
-                       get => hoverWidget;
-                       internal set {
-                               if (hoverWidget == value)
-                                       return;
-                               hoverWidget = value;
-                               NotifyValueChanged (nameof (HoverWidget), hoverWidget);
-                       }
-               }
-
-               public DbgEvent HoverEvent {
-                       get => hoverEvent;
-                       set {
-                               if (hoverEvent == value)
-                                       return;
-                               hoverEvent = value;
-                               NotifyValueChanged (nameof (HoverEvent), hoverEvent);
-                       }
-               }
-
-               long currentTick = 0, selStart = -1, selEnd = -1, minTicks = 0, maxTicks = 0, visibleTicks = 0;
-               int currentLine = -1;
-               int visibleLines = 1;
-               Point mousePos;
-
-               public double XScale {
-                       get { return xScale; }
-                       set {
-                               if (xScale == value)
-                                       return;
-                               xScale = value;
-                               NotifyValueChanged ("XScale", xScale);
-                               updateVisibleTicks ();
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               public double YScale {
-                       get => yScale;
-                       set {
-                               if (yScale == value)
-                                       return;
-                               yScale = value;
-                               NotifyValueChanged ("YScale", yScale);
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-               public override Font Font {
-                       get { return base.Font; }
-                       set {
-                               base.Font = value;
-                               using (Context gr = new Context (IFace.surf)) {
-                                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
-                                       gr.SetFontSize (Font.Size);
-
-                                       fe = gr.FontExtents;
-                               }
-                               updateMargins ();
-                       }
-               }
-               public override int ScrollY {
-                       get => base.ScrollY;
-                       set {
-                               base.ScrollY = value;
-
-                               if (widgets == null)
-                                       return;
-
-                               Rectangle cb = ClientRectangle;
-                               cb.Left += (int)leftMargin;
-                               cb.Width -= (int)leftMargin;
-                               cb.Y += (int)topMargin;
-                               cb.Height -= (int)topMargin;
-
-                               if (mousePos.Y < cb.Top || mousePos.Y > cb.Bottom)
-                                       currentLine = -1;
-                               else
-                                       currentLine = (int)((double)(mousePos.Y - cb.Top) / fe.Height) + ScrollY;
-
-                               NotifyValueChanged ("CurrentLine", currentLine);
-                       }
-               }
-
-               void drawEvents (Context ctx, List<DbgEvent> evts)
-               {
-                       if (evts == null || evts.Count == 0)
-                               return;
-                       Rectangle cb = ClientRectangle;
-
-                       foreach (DbgEvent evt in evts) {
-                               if (evt.end - minTicks <= ScrollX)
-                                       continue;
-                               if (evt.begin - minTicks > ScrollX + visibleTicks)
-                                       break;
-                               double penY = topMargin + ClientRectangle.Top;
-                               if (evt.type.HasFlag (DbgEvtType.Widget)) {
-                                       DbgWidgetEvent eW = evt as DbgWidgetEvent;
-                                       int lIdx = eW.InstanceIndex - ScrollY;
-                                       if (lIdx < 0 || lIdx > visibleLines)
-                                               continue;
-                                       penY += (lIdx) * fe.Height; 
-                               
-                                       ctx.SetSource (evt.Color);
-
-                                       double x = xScale * (evt.begin - minTicks - ScrollX);
-                                       double w = Math.Max (Math.Max (2.0, 2.0 * xScale), (double)(evt.end - evt.begin) * xScale);
-                                       if (x < 0.0) {
-                                               w += x;
-                                               x = 0.0;
-                                       }
-                                       x += leftMargin + cb.Left;
-                                       double rightDiff = x + w - cb.Right;
-                                       if (rightDiff > 0)
-                                               w -= rightDiff;
-
-                                       ctx.Rectangle (x, penY, w, fe.Height);
-                                       ctx.Fill ();
-                               } else {
-                                       /*double x = xScale * (evt.begin - minTicks - ScrollX);
-                                       x += leftMargin + cb.Left;
-
-                                       double trunc = Math.Truncate (x);
-                                       if (x - trunc > 0.5)
-                                               x = trunc + 0.5;
-                                       else
-                                               x = trunc - 0.5;
-
-
-                                       ctx.SetSource (Colors.Yellow);
-                                       ctx.MoveTo (x, penY);
-                                       ctx.LineTo (x, cb.Bottom);
-                                       ctx.Stroke ();
-                                       string s = evt.type.ToString () [5].ToString ();
-                                       TextExtents te = ctx.TextExtents (s);
-                                       ctx.Rectangle (x - 0.5 * te.Width, penY - te.Height, te.Width, te.Height);
-                                       ctx.Fill ();
-                                       ctx.MoveTo (x - 0.5 * te.Width, penY - ctx.FontExtents.Descent);
-                                       ctx.SetSource (Colors.Jet);
-                                       ctx.ShowText (s);*/
-
-                               }
-                               drawEvents (ctx, evt.Events);
-                       }
-               }
-
-               protected override void onDraw (Cairo.Context gr)
-               {
-                       base.onDraw (gr);
-
-                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
-                       gr.SetFontSize (Font.Size);
-                       gr.FontOptions = Interface.FontRenderingOptions;
-                       gr.Antialias = Cairo.Antialias.None;
-
-                       if (widgets == null)
-                               return;
-
-                       gr.LineWidth = 1.0;
-
-                       Rectangle cb = ClientRectangle;
-
-                       double penY = topMargin + ClientRectangle.Top;
-
-                       for (int i = 0; i < visibleLines; i++) {
-                               if (i + ScrollY >= widgets.Count)
-                                       break;
-                               int gIdx = i + ScrollY;
-                               DbgWidgetRecord g = widgets [gIdx];
-
-                               penY += fe.Height;
-
-                               gr.SetSource (Crow.Colors.Jet);
-                               gr.MoveTo (cb.X, penY - 0.5);
-                               gr.LineTo (cb.Right, penY - 0.5);
-                               gr.Stroke ();
-
-                               double penX = 5.0 * g.xLevel + cb.Left;
-
-                               if (g.yIndex == 0)
-                                       gr.SetSource (Crow.Colors.LightSalmon);
-                               else
-                                       Foreground.SetAsSource (IFace, gr);
-
-                               gr.MoveTo (penX, penY - gr.FontExtents.Descent);
-                               gr.ShowText (g.name + gIdx);
-                       }
-
-                       drawEvents (gr, events);
-                       /*
-                       for (int i = 0; i < visibleLines; i++) { 
-                               foreach (DbgEvent evt in events) {
-                                       if (evt.end - minTicks <= ScrollX)
-                                               continue;
-                                       if (evt.begin - minTicks > ScrollX + visibleTicks)
-                                               break;
-                                       
-                                       
-                               }
-
-                               
-                       }
-                       */
-
-                       gr.MoveTo (cb.Left, topMargin - 0.5 + cb.Top);
-                       gr.LineTo (cb.Right, topMargin - 0.5 + cb.Top);
-
-                       gr.MoveTo (leftMargin + cb.Left, cb.Top);
-                       gr.LineTo (leftMargin + cb.Left, cb.Bottom);
-                       gr.SetSource (Crow.Colors.Grey);
-
-                       penY = topMargin + ClientRectangle.Top;
-
-                       //graduation
-                       int largeGrad = int.Parse ("1" + new string ('0', visibleTicks.ToString ().Length - 1));
-                       int smallGrad = Math.Max (1, largeGrad / 10);
-
-                       long firstVisibleTicks = minTicks + ScrollX;
-                       long curGrad = firstVisibleTicks - firstVisibleTicks % smallGrad + smallGrad;
-
-                       long gg = curGrad - ScrollX - minTicks;
-                       while (gg < visibleTicks ) {
-                               double x = (double)gg * xScale + leftMargin + cb.Left;
-
-                               gr.MoveTo (x, penY - 0.5);
-                               if (curGrad % largeGrad == 0) { 
-                                       gr.LineTo (x, penY - 8.5);
-                                       string str = curGrad.ToString ();
-                                       TextExtents te = gr.TextExtents (str);
-                                       gr.RelMoveTo (-0.5 * te.Width, -2.0);
-                                       gr.ShowText (str);
-                               }else
-                                       gr.LineTo (x, penY - 2.5);
-
-                               curGrad += smallGrad;
-                               gg = curGrad - ScrollX - minTicks;
-                       }
-
-                       gr.Stroke ();
-
-                       //global events
-/*                     foreach (DbgEvent evt in events) {
-                               if (evt.begin - minTicks <= ScrollX)
-                                       continue;
-                               double x = xScale * (evt.begin - minTicks - ScrollX) ;
-                               x += leftMargin + cb.Left;
-
-
-                       }*/
-
-               }
-               public override void Paint (Cairo.Context ctx)
-               {
-                       base.Paint (ctx);
-
-                       Rectangle r = new Rectangle(mousePos.X, 0, 1, Slot.Height);
-                       Rectangle ctxR = ContextCoordinates (r);
-                       Rectangle cb = ClientRectangle;
-                       ctx.LineWidth = 1.0;
-                       double x = xScale * (currentTick - minTicks - ScrollX) + leftMargin;
-                       if (x - Math.Truncate (x) > 0.5)
-                               x = Math.Truncate (x) + 0.5;
-                       else
-                               x = Math.Truncate (x) - 0.5;
-                       ctx.MoveTo (x, cb.Top + topMargin - 4.0);
-                       ctx.LineTo (x, cb.Bottom);
-
-                       //ctx.Rectangle (ctxR);
-                       ctx.SetSource (Colors.CornflowerBlue);
-                       ctx.Stroke();
-
-                       ctx.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
-                       ctx.SetFontSize (Font.Size);
-                       ctx.FontOptions = Interface.FontRenderingOptions;
-                       ctx.Antialias = Interface.Antialias;
-
-                       ctx.MoveTo (ctxR.X - ctx.TextExtents (currentTick.ToString ()).Width / 2, ctxR.Y + fe.Height);
-                       ctx.ShowText (currentTick.ToString ());
-
-                       ctx.Operator = Cairo.Operator.Add;
-
-                       if (currentLine >= 0) {
-                               double y = fe.Height * (currentLine - ScrollY) + topMargin + cb.Top;
-                               r = new Rectangle (cb.Left,  (int)y, cb.Width, (int)fe.Height);
-
-                               ctx.Operator = Cairo.Operator.Add;
-                               ctx.SetSource (0.1, 0.1, 0.1, 0.4);
-                               ctx.Rectangle (ContextCoordinates (r));
-                               ctx.Fill ();
-                       }
-
-                       if (CurrentWidget != null) {
-
-                       }
-
-                       if (selStart < 0 || selEnd < 0) {
-                               ctx.Operator = Cairo.Operator.Over;
-                               return;
-                       }
-                       double selStartX = (double)(selStart - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
-                       double selEndX = (double)(selEnd - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
-
-                       if (selStartX < selEndX) {
-                               ctxR.X = (int)selStartX;
-                               ctxR.Width = (int)(selEndX - selStartX);
-                       } else {
-                               ctxR.X = (int)selEndX;
-                               ctxR.Width = (int)(selStartX - selEndX);
-                       }
-
-                       ctxR.Width = Math.Max (1, ctxR.Width);
-                       ctx.Rectangle (ctxR);
-                       //ctx.SetSourceColor (Color.LightYellow);
-                       ctx.SetSource (Colors.Jet);
-                       ctx.Fill();
-                       ctx.Operator = Cairo.Operator.Over;
-
-               }
-               public override void OnLayoutChanges (LayoutingType layoutType)
-               {
-                       base.OnLayoutChanges (layoutType);
-                       switch (layoutType) {
-                       case LayoutingType.Width:
-                               if (xScale < 0) {
-                                       visibleTicks = maxTicks - minTicks;
-                                       XScale = (ClientRectangle.Width - leftMargin) / visibleTicks;
-                               }
-                               updateVisibleTicks ();
-                               break;
-                       case LayoutingType.Height:
-                               updateVisibleLines ();
-                               break;
-                       }
-               }
-
-               public override void onMouseLeave (object sender, MouseMoveEventArgs e)
-               {
-                       base.onMouseLeave (sender, e);
-                       currentLine = -1;
-                       currentTick = 0;
-               }
-               public override void onMouseMove (object sender, MouseMoveEventArgs e)
-               {
-                       base.onMouseMove (sender, e);
-
-                       long lastTick = currentTick;
-                       updateMouseLocalPos (e.Position);
-
-                       if (IFace.IsDown (Glfw.MouseButton.Left) && selStart >= 0)
-                               selEnd = currentTick;
-                       else if (IFace.IsDown(Glfw.MouseButton.Right)) {
-                               ScrollX += (int)(lastTick - currentTick);
-                               updateMouseLocalPos (e.Position);
-                       } else {
-                               HoverWidget = (currentLine < 0 || currentLine >= widgets.Count) ? null : widgets [currentLine];
-                               HoverEvent = hoverWidget?.Events.FirstOrDefault (ev => ev.begin <= currentTick && ev.end >= currentTick);
-                       }
-
-                       if (RegisteredLayoutings == LayoutingType.None && !IsDirty)
-                               IFace.EnqueueForRepaint (this);
-                       
-               }
-               public override void onMouseDown (object sender, MouseButtonEventArgs e)
-               {
-                       base.onMouseDown (sender, e);
-
-                       if (e.Button == Glfw.MouseButton.Left) {
-                               CurrentWidget = hoverWidget;
-                               CurrentEvent = hoverEvent;
-                               selStart = currentTick;
-                               selEnd = -1;
-                       }
-
-                       RegisterForRedraw ();
-               }
-               public override void onMouseUp (object sender, MouseButtonEventArgs e)
-               {
-                       base.onMouseUp (sender, e);
-
-                       if (e.Button == Glfw.MouseButton.Left && selEnd > 0 && selEnd != selStart) {
-                               long scrX = 0;
-                               if (selStart < selEnd) {
-                                       visibleTicks = selEnd - selStart;
-                                       scrX = selStart - minTicks;
-                               } else {
-                                       visibleTicks = selStart - selEnd;
-                                       scrX = selEnd - minTicks;
-                               }
-                               XScale = (ClientRectangle.Width - leftMargin) / visibleTicks;
-                               ScrollX = (int)scrX;
-                       }
-                       selStart = -1;
-                       selEnd = -1;
-
-                       RegisterForRedraw ();
-               }
-
-               /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
-               public override void onMouseWheel (object sender, MouseWheelEventArgs e)
-               {                       
-                       base.onMouseWheel (sender, e);
-
-                       if (IFace.Shift)
-                               ScrollX -= (int)((double)(e.Delta * MouseWheelSpeed) / xScale);
-                       else if (IFace.Ctrl) {
-                               if (e.Delta > 0) {
-                                       XScale *= 2.0;
-                               } else {
-                                       if (MaxScrollX > 0)
-                                               XScale *= 0.5;
-                               }
-                               ScrollX = (int)(currentTick - (int)((double)Math.Max(0, mousePos.X - (int)leftMargin) / xScale) - minTicks);
-                       }else
-                               ScrollY -= e.Delta * MouseWheelSpeed;
-               }
-
-               public override void onKeyDown (object sender, KeyEventArgs e)
-               {
-                       base.onKeyDown (sender, e);
-
-                       if (e.Key == Glfw.Key.F3) {
-                               if (selEnd < 0)
-                                       return;
-                               if (selEnd < selStart)
-                                       zoom (selEnd, selStart);
-                               else
-                                       zoom (selStart, selEnd);
-                               selEnd = selStart = -1;
-                       }
-               }
-
-               void updateMargins ()
-               {
-                       leftMargin = topMargin = 0.0;
-
-                       if (widgets == null)
-                               return;
-
-                       using (Context gr = new Context (IFace.surf)) {
-                               double maxNameWidth = 0.0;
-
-                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
-                               gr.SetFontSize (Font.Size);
-
-                               foreach (DbgWidgetRecord o in widgets) {
-                                       double nameWidth = gr.TextExtents (o.name).Width + 5.0 * o.xLevel;
-                                       if (nameWidth > maxNameWidth)
-                                               maxNameWidth = nameWidth;
-                               }
-
-                               leftMargin = 10.5 + maxNameWidth;
-                               topMargin = 2.0 * fe.Height;
-
-                               RegisterForGraphicUpdate ();
-                       }
-               }
-
-               void updateVisibleLines ()
-               {
-                       visibleLines = fe.Height < 1 ? 1 : (int)Math.Floor (((double)ClientRectangle.Height - topMargin) / fe.Height);
-                       NotifyValueChanged ("VisibleLines", visibleLines);
-                       updateMaxScrollY ();
-               }
-               void updateVisibleTicks ()
-               {
-                       visibleTicks = Math.Max (0, (long)((double)(ClientRectangle.Width - leftMargin) / XScale));
-                       NotifyValueChanged ("VisibleTicks", visibleTicks);
-                       updateMaxScrollX ();
-               }
-
-               void updateMaxScrollX ()
-               {
-                       if (widgets == null)
-                               MaxScrollX = 0;
-                       else
-                               MaxScrollX = (int)Math.Max (0L, maxTicks - minTicks - visibleTicks);
-               }
-               void updateMaxScrollY ()
-               {
-                       if (widgets == null)
-                               MaxScrollY = 0;
-                       else
-                               MaxScrollY = Math.Max (0, widgets.Count - visibleLines);
-               }
-
-               void updateMouseLocalPos (Point mPos)
-               {
-                       Rectangle r = ScreenCoordinates (Slot);
-                       Rectangle cb = ClientRectangle;
-                       cb.Left += (int)leftMargin;
-                       cb.Width -= (int)leftMargin;
-                       cb.Y += (int)topMargin;
-                       cb.Height -= (int)topMargin;
-
-                       mousePos = mPos - r.Position;
-
-                       mousePos.X = Math.Max (cb.X, mousePos.X);
-                       mousePos.X = Math.Min (cb.Right, mousePos.X);
-
-                       if (mousePos.Y < cb.Top || mousePos.Y > cb.Bottom)
-                               currentLine = -1;
-                       else
-                               currentLine = (int)((double)(mousePos.Y - cb.Top) / fe.Height) + ScrollY;
-
-                       NotifyValueChanged ("CurrentLine", currentLine);
-
-                       mousePos.Y = Math.Max (cb.Y, mousePos.Y);
-                       mousePos.Y = Math.Min (cb.Bottom, mousePos.Y);
-
-                       currentTick = (int)((double)(mousePos.X - cb.X) / xScale) + minTicks + ScrollX;
-                       RegisterForRedraw ();
-               }
-               void zoom (long start, long end) {                                              
-                       //Rectangle cb = ClientRectangle;
-                       //cb.X += (int)leftMargin;
-                       XScale = ((double)ClientRectangle.Width - leftMargin)/(end - start);
-                       ScrollX = (int)(start - minTicks);
-               }
-       }
-}
-
-
index df93e6865f4c6469b38447552448f326fa93fe71..057ee24cdd03b97c7d2299b0a7ee09cddc3fe323 100644 (file)
@@ -1,9 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project Sdk="Microsoft.NET.Sdk">
+       <PropertyGroup>
+               <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+       </PropertyGroup>
        <ItemGroup>
-               <EmbeddedResource Include="ui\**\*.*">
+               <Compile Include="src\**\*.cs"/>
+       </ItemGroup>
+       <ItemGroup>
+               <EmbeddedResource Include="ui\*.*">
                        <LogicalName>Dbg.%(Filename)%(Extension)</LogicalName>
-               </EmbeddedResource>
-</ItemGroup>
+               </EmbeddedResource>     
+       </ItemGroup>
+       <ItemGroup>
+               <ProjectReference Include="..\..\CrowDbgShared\CrowDbgShared.csproj" />
+       </ItemGroup>
 
 </Project>
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/Program.cs b/Samples/DebugLogAnalyzer/Program.cs
deleted file mode 100644 (file)
index 7493a84..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Crow;
-using Crow.Cairo;
-
-namespace DebugLogAnalyzer
-{
-       public class Program : SampleBase
-       {
-               static void Main (string [] args)
-               {
-                       using (Program app = new Program ()) 
-                               app.Run ();
-               }
-
-               List<DbgEvent> events = new List<DbgEvent>();
-               List<DbgWidgetRecord> widgets = new List<DbgWidgetRecord>();
-               DbgEvent curEvent = new DbgEvent();
-               DbgWidgetRecord curWidget = new DbgWidgetRecord();
-
-               public List<DbgEvent> Events {
-                       get => events;
-                       set {
-                               if (events == value)
-                                       return;
-                               events = value;
-                               NotifyValueChanged (nameof (Events), events);
-                       }
-               }
-               public List<DbgWidgetRecord> Widgets {
-                       get => widgets;
-                       set {
-                               if (widgets == value)
-                                       return;
-                               widgets = value;
-                               NotifyValueChanged (nameof (Widgets), widgets);
-                       }
-               }
-               public DbgEvent CurrentEvent {
-                       get => curEvent;
-                       set {
-                               if (curEvent == value)
-                                       return;
-
-                               if (curEvent != null)
-                                       curEvent.IsSelected = false;
-                               curEvent = value;
-                               if (curEvent != null) {
-                                       curEvent.IsSelected = true;
-                                       if (curEvent.parentEvent != null)
-                                               curEvent.parentEvent.IsExpanded = true;
-                               }
-
-                               NotifyValueChanged (nameof (CurrentEvent), curEvent);
-                       }
-               }
-               public DbgWidgetRecord CurrentWidget {
-                       get => curWidget;
-                       set {
-                               if (curWidget == value)
-                                       return;
-                               curWidget = value;
-                               NotifyValueChanged (nameof (CurrentWidget), curWidget);
-                               NotifyValueChanged ("CurWidgetRootEvents", CurWidgetRootEvents);
-                       }
-               }
-               public List<DbgWidgetEvent> CurWidgetRootEvents => curWidget == null? new List<DbgWidgetEvent>() : curWidget.RootEvents;
-
-               Scroller dbgTreeViewScroller;
-
-               protected override void OnInitialized ()
-               {
-                       Load ("#Dbg.dbglog.crow").DataSource = this;
-
-                       TreeView tv = FindByName("dbgTV") as TreeView;
-                       dbgTreeViewScroller = tv.FindByNameInTemplate ("scroller1") as Scroller;
-
-                       loadDebugFile ("debug.log");
-               }
-
-               void loadDebugFile (string logFile)
-               {
-                       if (!File.Exists (logFile))
-                               return;
-
-                       List<DbgEvent> evts = new List<DbgEvent> ();
-                       List<DbgWidgetRecord> objs = new List<DbgWidgetRecord> ();
-
-                       using (StreamReader s = new StreamReader (logFile)) {
-                               if (s.ReadLine () != "[GraphicObjects]")
-                                       return;
-                               while (!s.EndOfStream) {
-                                       string l = s.ReadLine ();
-                                       if (l == "[Events]")
-                                               break;
-                                       DbgWidgetRecord o = DbgWidgetRecord.Parse (l);
-                                       objs.Add (o);
-                               }
-
-                               Stack<DbgEvent> startedEvents = new Stack<DbgEvent> ();
-
-                               if (!s.EndOfStream) {
-                                       while (!s.EndOfStream) {
-                                               int level = 0;
-                                               while (s.Peek () == (int)'\t') {
-                                                       s.Read ();
-                                                       level++;
-                                               }
-                                               DbgEvent evt = DbgEvent.Parse (s.ReadLine ());                                                  
-                                               if (level == 0) {
-                                                       startedEvents.Clear ();
-                                                       evts.Add (evt);
-                                               } else {
-                                                       int levelDiff = level - startedEvents.Count + 1;
-                                                       if (levelDiff > 0) {
-                                                               if (levelDiff > 1)
-                                                                       System.Diagnostics.Debugger.Break ();
-                                                               startedEvents.Peek ().AddEvent (evt);
-                                                       } else {
-                                                               startedEvents.Pop ();
-                                                               if (-levelDiff > startedEvents.Count)
-                                                                       System.Diagnostics.Debugger.Break ();
-                                                               while (startedEvents.Count > level)
-                                                                       startedEvents.Pop ();
-                                                               startedEvents.Peek ().AddEvent (evt);
-                                                       }
-                                               }
-                                               startedEvents.Push (evt);
-                                               if (evt.type.HasFlag (DbgEvtType.Widget))
-                                                       objs [(evt as DbgWidgetEvent).InstanceIndex].Events.Add (evt);
-                                       }
-                               }
-                       }
-                       Widgets = objs;
-                       Events = evts;
-               }
-
-               int targetTvScroll = -1;
-
-               void onTvPainted (object sender, EventArgs e)
-               {
-                       if (targetTvScroll < 0 || targetTvScroll > dbgTreeViewScroller.MaxScrollY + dbgTreeViewScroller.Slot.Height)
-                               return;
-                       dbgTreeViewScroller.MaxScrollY = targetTvScroll;
-                       targetTvScroll = -1;
-               }
-
-               void onSelectedItemContainerChanged (object sender, SelectionChangeEventArgs e)
-               {
-                       TreeView tv = sender as TreeView;
-                       Group it = tv.FindByNameInTemplate ("ItemsContainer") as Group;
-
-                       ListItem li = e.NewValue as ListItem;
-                       Rectangle selRect = li.RelativeSlot (it);
-
-                       if (selRect.Y > dbgTreeViewScroller.ScrollY && selRect.Y < dbgTreeViewScroller.Slot.Height + dbgTreeViewScroller.ScrollY)
-                               return;
-
-                       Console.WriteLine ($"Scroll={dbgTreeViewScroller.ScrollY} selRectY={selRect.Y} MaxScrollY={dbgTreeViewScroller.MaxScrollY} ScrollerH={dbgTreeViewScroller.Slot.Height}");
-                       targetTvScroll = selRect.Y;
-                       if (selRect.Y > dbgTreeViewScroller.MaxScrollY + dbgTreeViewScroller.Slot.Height)
-                               targetTvScroll = selRect.Y;
-                       else {
-                               targetTvScroll = -1;
-                               dbgTreeViewScroller.ScrollY = selRect.Y;
-                       }
-               }
-
-       }
-}
-
diff --git a/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs b/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs
new file mode 100644 (file)
index 0000000..19666ee
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Crow.Cairo;
+using Crow.DebugLogger;
+using DebugLogAnalyzer;
+
+namespace Crow
+{
+       public class DbgEventWidget : Widget
+       {
+               public DbgEventWidget (){}
+
+               DbgEvent evt, hoverEvt;
+               long ticksPerPixel;
+               double pixelPerTick;
+
+               public DbgEvent Event {
+                       get => evt;
+                       set {
+                               if (evt == value)
+                                       return;
+                               evt = value;
+                               updatePixelPerTicks ();
+                               NotifyValueChangedAuto (evt);
+                               RegisterForRedraw ();
+                       }
+               }
+               public DbgEvent HoverEvent {
+                       get => hoverEvt;
+                       private set {
+                               if (hoverEvt == value)
+                                       return;
+                               hoverEvt = value;
+                               NotifyValueChangedAuto (hoverEvt);
+                       }
+               }
+
+               [DefaultValue ("1000")]
+               public long TicksPerPixel {
+                       get => ticksPerPixel;
+                       set {
+                               if (ticksPerPixel == value)
+                                       return;
+                               ticksPerPixel = value;
+                               NotifyValueChangedAuto (ticksPerPixel);
+                               if (Width == Measure.Fit)
+                                       RegisterForLayouting (LayoutingType.Width);
+                       }
+               }
+
+               public override int measureRawSize (LayoutingType lt)
+               {
+                       updatePixelPerTicks ();
+                       if (lt == LayoutingType.Width)
+                               contentSize.Width = Event == null ? 0 : (int)Math.Max(pixelPerTick * Event.Duration, 2);
+                       
+                       return base.measureRawSize (lt);
+               }
+
+               public override void OnLayoutChanges (LayoutingType layoutType)
+               {
+                       if (layoutType == LayoutingType.Width)
+                               updatePixelPerTicks ();
+
+                       base.OnLayoutChanges (layoutType);
+               }
+
+               protected override void onDraw (Context gr)
+               {
+                       if (Event == null) {
+                               base.onDraw (gr);
+                               return;
+                       }
+
+                       gr.LineWidth = 1;
+                       gr.SetDash (new double [] { 1.0, 3.0 }, 0);
+
+                       Rectangle cb = ClientRectangle;
+
+                       if (Event.Duration == 0) {
+                               gr.SetSource (Event.Color);
+                               gr.Rectangle (cb);
+                               gr.Fill ();
+                               return;
+                       }
+
+                       drawEvent (gr, cb.Height, Event);
+               }
+               void drawEvent (Context ctx, int h, DbgEvent dbge)
+               {
+                       double w = Math.Max(dbge.Duration * pixelPerTick, 2.0);
+                       double x = (dbge.begin - Event.begin) * pixelPerTick;
+
+                       ctx.Rectangle (x, 0, w, h);
+                       ctx.SetSource (dbge.Color);
+                       /*if (dbge.IsSelected) {
+                               ctx.FillPreserve ();
+                               ctx.SetSource (1, 1, 1);
+                               ctx.Stroke ();
+                       }else*/
+                               ctx.Fill ();
+
+                       if (dbge.Events == null)
+                               return;
+                       foreach (DbgEvent e in dbge.Events)
+                               drawEvent (ctx, h, e);
+               }
+
+               public override void onMouseMove (object sender, MouseMoveEventArgs e)
+               {
+                       if (Event != null) {
+                               Point m = ScreenPointToLocal (e.Position);
+                               long curTick = (long)(m.X / pixelPerTick) + Event.begin;
+                               HoverEvent = hoverEvent (Event, curTick);
+
+                               e.Handled = true;
+                       }
+                       base.onMouseMove (sender, e);
+               }
+
+               DbgEvent hoverEvent (DbgEvent hevt, long curTick){
+                       if (hevt.Events != null) {
+                               foreach (DbgEvent e in hevt.Events) {
+                                       if (curTick >= e.begin && curTick <= e.end)
+                                               return hoverEvent (e, curTick);
+                               }
+                       }
+                       return hevt;
+               }
+               void updatePixelPerTicks ()
+               {
+                       if (Width == Measure.Fit)
+                               pixelPerTick = 1.0 / ticksPerPixel;
+                       else
+                               pixelPerTick = Event == null ? 0 : (double)ClientRectangle.Width / Event.Duration;
+               }
+       }
+}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs b/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs
new file mode 100644 (file)
index 0000000..1273c9e
--- /dev/null
@@ -0,0 +1,805 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices.ComTypes;
+// Copyright (c) 2013-2020  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Crow.Cairo;
+using Crow.DebugLogger;
+using DebugLogAnalyzer;
+
+namespace Crow
+{
+       public class DbgLogViewer : Widget
+       {
+               public static Dictionary<DbgEvtType, Color> colors;
+
+               public static Configuration colorsConf = new Configuration ("dbgcolor.conf");//, Interface.GetStreamFromPath("#Crow.dbgcolor.conf"));
+
+               public static void reloadColors () {
+                       colors = new Dictionary<DbgEvtType, Color>();
+                       foreach (string n in colorsConf.Names) {
+                               DbgEvtType t = (DbgEvtType)Enum.Parse (typeof(DbgEvtType), n);
+                               Color c = colorsConf.Get<Color> (n);
+                               colors.Add (t, c);
+                       }
+
+               }
+               #region CTOR
+               static DbgLogViewer() {
+                       //reloadColors ();
+                       
+               }
+               protected DbgLogViewer () : base(){}
+               public DbgLogViewer (Interface iface, string style = null) : base(iface, style){}
+               #endregion
+
+               FontExtents fe;
+
+
+               double xScale = 1.0/1024.0, yScale = 1.0, leftMargin, topMargin = 0.0;
+               DbgWidgetRecord curWidget, hoverWidget;
+               DbgEvent curEvent, hoverEvent;
+
+               List<DbgEvent> events = new List<DbgEvent> ();
+               List<DbgWidgetRecord> widgets = new List<DbgWidgetRecord> ();
+               
+
+               public DbgEvtType Filter {
+                       get => Configuration.Global.Get<DbgEvtType> ("DbgLogViewFilter");
+                       set {
+                               if (Filter == value)
+                                       return;                         
+                               Configuration.Global.Set ("DbgLogViewFilter", value);                           
+                               NotifyValueChangedAuto(Filter);
+                               RegisterForGraphicUpdate();
+                       }
+               }
+               public List<DbgEvent> Events {
+                       get => events;
+                       set {
+                               if (events == value)
+                                       return;
+                               events = value;
+                               NotifyValueChanged (nameof (Events), events);
+
+                               maxTicks = minTicks = 0;
+                               if (events != null && events.Count > 0) {                               
+                                       minTicks = long.MaxValue;
+                                       foreach (DbgEvent e in events) {
+                                               if (e.begin < minTicks)
+                                                       minTicks = e.begin;
+                                               if (e.end > maxTicks)
+                                                       maxTicks = e.end;
+                                       }
+                                       visibleTicks = maxTicks - minTicks;
+                                       XScale = (ClientRectangle.Width - leftMargin)/visibleTicks;
+                                       ScrollX = 0;
+                                       ScrollY = 0;
+                               } else {
+                                       maxTicks = 1;
+                                       XScale = 1.0/1024.0;                                    
+                               }
+
+
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               public List<DbgWidgetRecord> Widgets {
+                       get => widgets;
+                       set {
+                               if (widgets == value)
+                                       return;
+                               widgets = value;
+                               NotifyValueChanged (nameof (Widgets), widgets);
+                               updateMargins ();
+                               updateMaxScrollX ();
+                               updateMaxScrollY ();
+                       }
+               }
+               public DbgWidgetRecord CurrentWidget {
+                       get => curWidget;
+                       set {
+                               if (curWidget == value)
+                                       return;
+                               curWidget = value;
+                               NotifyValueChanged (nameof (CurrentWidget), curWidget);
+                               if (CurrentWidget == null)
+                                       return;
+                               if (CurrentWidget.listIndex < scrollY || CurrentWidget.listIndex > scrollY + visibleLines)
+                                       ScrollY = CurrentWidget.listIndex - (visibleLines / 2);
+                               
+                               currentLine = CurrentWidget.listIndex;
+                               RegisterForRedraw();
+                       }
+               }
+               public DbgEvent CurrentEvent {
+                       get => curEvent;
+                       set {
+                               if (curEvent == value)
+                                       return;
+                               /*if (curEvent != null)
+                                       curEvent.IsSelected = false;*/
+                               curEvent = value;
+                               if (curEvent != null) {
+                                       //curEvent.IsSelected = true;
+                                       if (curEvent is DbgWidgetEvent we) {
+                                               //CurrentWidget = Widgets [we.InstanceIndex];
+                                               hoverLine = we.InstanceIndex;
+                                       }
+                                       currentTick = curEvent.begin;
+                                       if (curEvent.begin > minTicks + ScrollX + visibleTicks ||
+                                               curEvent.end < minTicks + ScrollX)                                              
+                                                       ScrollX = curEvent.begin - minTicks - visibleTicks / 2;                                                                                 
+                               }
+                               NotifyValueChanged (nameof (CurrentEvent), curEvent);
+                               RegisterForRedraw ();
+                       }
+               }
+               public DbgWidgetRecord HoverWidget {
+                       get => hoverWidget;
+                       internal set {
+                               if (hoverWidget == value)
+                                       return;
+                               hoverWidget = value;
+                               NotifyValueChanged (nameof (HoverWidget), hoverWidget);
+                       }
+               }
+
+               public DbgEvent HoverEvent {
+                       get => hoverEvent;
+                       set {
+                               if (hoverEvent == value)
+                                       return;
+                               hoverEvent = value;
+                               NotifyValueChanged (nameof (HoverEvent), hoverEvent);
+                       }
+               }
+
+               long hoverTick = 0, currentTick, selStart = -1, selEnd = -1, minTicks = 0, maxTicks = 0, visibleTicks = 0;
+               int hoverLine = -1, currentLine = -1;
+               int visibleLines = 1;
+               Point mousePos;
+
+               public double XScale {
+                       get => xScale;
+                       set {
+                               if (xScale == value)
+                                       return;
+                               xScale = value;
+                               NotifyValueChanged ("XScale", xScale);
+                               updateVisibleTicks ();
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               public double YScale {
+                       get => yScale;
+                       set {
+                               if (yScale == value)
+                                       return;
+                               yScale = value;
+                               NotifyValueChanged ("YScale", yScale);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               public override Font Font {
+                       get { return base.Font; }
+                       set {
+                               base.Font = value;
+                               using (Context gr = new Context (IFace.surf)) {
+                                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                                       gr.SetFontSize (Font.Size);
+
+                                       fe = gr.FontExtents;
+                               }
+                               updateMargins ();
+                       }
+               }
+
+               void drawEvents (Context ctx, List<DbgEvent> evts)
+               {
+                       if (evts == null || evts.Count == 0)
+                               return;
+                       Rectangle cb = ClientRectangle;
+
+                       foreach (DbgEvent evt in evts) {
+                               if ((evt.Category & currentFilter) == currentFilter) {
+                                       if (evt.end - minTicks <= ScrollX)
+                                               continue;
+                                       if (evt.begin - minTicks > ScrollX + visibleTicks)
+                                               break;
+                                       double penY = topMargin + ClientRectangle.Top;
+
+                                       if (evt.type.HasFlag (DbgEvtType.Widget)) {
+                                               DbgWidgetEvent eW = evt as DbgWidgetEvent;
+                                               int lIdx = eW.InstanceIndex - ScrollY;
+                                               if (lIdx >= 0 && lIdx <= visibleLines) {
+                                                       
+                                                       penY += (lIdx) * fe.Height; 
+                                               
+                                                       ctx.SetSource (evt.Color);
+
+                                                       double x = xScale * (evt.begin - minTicks - ScrollX);
+                                                       double w = Math.Max (Math.Max (2.0, 2.0 * xScale), (double)(evt.end - evt.begin) * xScale);
+                                                       if (x < 0.0) {
+                                                               w += x;
+                                                               x = 0.0;
+                                                       }
+                                                       x += leftMargin + cb.Left;
+                                                       double rightDiff = x + w - cb.Right;
+                                                       if (rightDiff > 0)
+                                                               w -= rightDiff;
+                                                       RectangleD r = new RectangleD(x, penY, w, fe.Height);
+                                                       ctx.Rectangle (r);
+                                                       ctx.Fill ();
+                                                       /*if (evt == CurrentEvent) {
+                                                               r.Inflate(2,2);
+                                                               ctx.SetSource(Colors.White);
+                                                               ctx.Rectangle(r);
+                                                               ctx.Stroke();
+                                                       }*/
+                                               }
+                                       } else if (evt.type.HasFlag (DbgEvtType.IFace)) {
+                                               double x = xScale * (evt.begin - minTicks - ScrollX);
+                                               double w = Math.Max (Math.Max (2.0, 2.0 * xScale), (double)(evt.end - evt.begin) * xScale);
+                                               if (x < 0.0) {
+                                                       w += x;
+                                                       x = 0.0;
+                                               }
+                                               x += leftMargin + cb.Left;
+                                               double rightDiff = x + w - cb.Right;
+                                               if (rightDiff > 0)
+                                                       w -= rightDiff;                                 
+                                               //ctx.SetSource (0.9,0.9,0.0,0.1);                                      
+                                               ctx.SetSource (evt.Color.AdjustAlpha(0.15));
+                                               ctx.Rectangle (x, cb.Top + topMargin, w, cb.Height);
+                                               ctx.Fill ();
+                                       }
+                               }
+                               drawEvents (ctx, evt.Events);
+                       }
+               }
+
+               DbgEvtType currentFilter;
+               protected override void onDraw (Cairo.Context gr)
+               {
+                       base.onDraw (gr);
+
+                       gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                       gr.SetFontSize (Font.Size);
+                       gr.FontOptions = Interface.FontRenderingOptions;
+                       gr.Antialias = Cairo.Antialias.None;
+
+                       if (widgets == null)
+                               return;
+
+                       gr.LineWidth = 1.0;
+
+                       Rectangle cb = ClientRectangle;
+
+                       double penY = topMargin + ClientRectangle.Top;
+
+                       for (int i = 0; i < visibleLines; i++) {
+                               if (i + ScrollY >= widgets.Count)
+                                       break;
+                               int gIdx = i + ScrollY;
+                               DbgWidgetRecord g = widgets [gIdx];
+
+                               penY += fe.Height;
+
+                               gr.SetSource (Crow.Colors.Jet);
+                               gr.MoveTo (cb.X, penY - 0.5);
+                               gr.LineTo (cb.Right, penY - 0.5);
+                               gr.Stroke ();
+
+                               double penX = 5.0 * g.xLevel + cb.Left;
+
+                               if (g.yIndex == 0)
+                                       gr.SetSource (Crow.Colors.LightSalmon);
+                               else if (currentLine == g.listIndex)
+                                       gr.SetSource(Colors.RoyalBlue);
+                               else
+                                       Foreground.SetAsSource (IFace, gr);
+
+                               gr.MoveTo (penX, penY - gr.FontExtents.Descent);
+                               gr.ShowText (g.name + gIdx);
+                       }
+
+                       currentFilter = Filter;
+                       drawEvents (gr, events);
+
+                       gr.MoveTo (cb.Left, topMargin - 0.5 + cb.Top);
+                       gr.LineTo (cb.Right, topMargin - 0.5 + cb.Top);
+
+                       gr.MoveTo (leftMargin + cb.Left, cb.Top);
+                       gr.LineTo (leftMargin + cb.Left, cb.Bottom);
+                       gr.SetSource (Crow.Colors.Grey);
+
+                       penY = topMargin + ClientRectangle.Top;
+
+                       //graduation
+                       long largeGrad = long.Parse ("1" + new string ('0', visibleTicks.ToString ().Length - 1));
+                       long smallGrad = Math.Max (1, largeGrad / 10);
+
+                       long firstVisibleTicks = minTicks + ScrollX;
+                       long curGrad = firstVisibleTicks - firstVisibleTicks % smallGrad + smallGrad;
+
+                       long gg = curGrad - ScrollX - minTicks;
+                       while (gg < visibleTicks ) {
+                               double x = (double)gg * xScale + leftMargin + cb.Left;
+
+                               gr.MoveTo (x, penY - 0.5);
+                               if (curGrad % largeGrad == 0) { 
+                                       gr.LineTo (x, penY - 8.5);
+                                       string str = ticksToMS(curGrad);
+                                       TextExtents te = gr.TextExtents (str);
+                                       gr.RelMoveTo (-0.5 * te.Width, -2.0);
+                                       gr.ShowText (str);
+                               }else
+                                       gr.LineTo (x, penY - 2.5);
+
+                               curGrad += smallGrad;
+                               gg = curGrad - ScrollX - minTicks;
+                       }
+
+                       gr.Stroke ();
+
+
+
+               }
+               string ticksToMS(long ticks) => Math.Round ((double)ticks / Stopwatch.Frequency * 1000.0, 2).ToString();
+               public override void Paint (Cairo.Context ctx)
+               {
+                       base.Paint (ctx);
+
+                       Rectangle r = new Rectangle(mousePos.X, 0, 1, Slot.Height);
+                       Rectangle ctxR = ContextCoordinates (r);
+                       Rectangle cb = ClientRectangle;
+                       ctx.LineWidth = 1.0;
+                       if (hoverTick >= 0) {
+                               double x = xScale * (hoverTick - minTicks - ScrollX) + leftMargin;
+                               if (x - Math.Truncate (x) > 0.5)
+                                       x = Math.Truncate (x) + 0.5;
+                               else
+                                       x = Math.Truncate (x) - 0.5;
+                               ctx.MoveTo (x, cb.Top + topMargin - 4.0);
+                               ctx.LineTo (x, cb.Bottom);                              
+                               ctx.SetSource (0.7,0.7,0.7,0.5);
+                               ctx.Stroke();
+                       }
+                       if (currentTick >= 0) {
+                               double x = xScale * (currentTick - minTicks - ScrollX) + leftMargin;
+                               if (x > leftMargin && x < cb.Right) {
+                                       if (x - Math.Truncate (x) > 0.5)
+                                               x = Math.Truncate (x) + 0.5;
+                                       else
+                                               x = Math.Truncate (x) - 0.5;
+                                       ctx.MoveTo (x, cb.Top);
+                                       ctx.LineTo (x, cb.Bottom);                              
+                                       ctx.SetSource (0.2,0.7,1.0,0.6);
+                                       ctx.Stroke();
+                               }
+                       }
+
+                       ctx.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                       ctx.SetFontSize (Font.Size);
+                       ctx.FontOptions = Interface.FontRenderingOptions;
+                       ctx.Antialias = Interface.Antialias;
+
+                       string str = ticksToMS(hoverTick);
+
+                       ctx.MoveTo (ctxR.X - ctx.TextExtents (str).Width / 2, ctxR.Y + fe.Height);
+                       ctx.ShowText (str);
+
+                       ctx.Operator = Cairo.Operator.Add;
+
+                       if (hoverLine >= 0) {
+                               double y = fe.Height * (hoverLine - ScrollY) + topMargin + cb.Top;
+                               r = new Rectangle (cb.Left,  (int)y, cb.Width, (int)fe.Height);
+
+                               ctx.SetSource (0.1, 0.1, 0.1, 0.4);
+                               ctx.Rectangle (ContextCoordinates (r));
+                               ctx.Fill ();
+                       }
+
+                       if (currentLine >= ScrollY && currentLine < scrollY + visibleLines) {
+                               double y = fe.Height * (currentLine - ScrollY) + topMargin + cb.Top;
+                               r = new Rectangle (cb.Left,  (int)y, cb.Width, (int)fe.Height);
+
+                               ctx.SetSource (0.1, 0.1, 0.7, 0.2);
+                               ctx.Rectangle (ContextCoordinates (r));
+                               ctx.Fill ();
+                       }
+
+                       if (selStart < 0 || selEnd < 0) {
+                               ctx.Operator = Cairo.Operator.Over;
+                               return;
+                       }
+                       double selStartX = (double)(selStart - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
+                       double selEndX = (double)(selEnd - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
+
+                       if (selStartX < selEndX) {
+                               ctxR.X = (int)selStartX;
+                               ctxR.Width = (int)(selEndX - selStartX);
+                       } else {
+                               ctxR.X = (int)selEndX;
+                               ctxR.Width = (int)(selStartX - selEndX);
+                       }
+
+                       ctxR.Width = Math.Max (1, ctxR.Width);
+                       ctx.Rectangle (ctxR);
+                       //ctx.SetSourceColor (Color.LightYellow);
+                       ctx.SetSource (Colors.Jet);
+                       ctx.Fill();
+                       ctx.Operator = Cairo.Operator.Over;
+
+               }
+               public override void OnLayoutChanges (LayoutingType layoutType)
+               {
+                       base.OnLayoutChanges (layoutType);
+                       switch (layoutType) {
+                       case LayoutingType.Width:
+                               if (xScale < 0) {
+                                       visibleTicks = maxTicks - minTicks;
+                                       XScale = (ClientRectangle.Width - leftMargin) / visibleTicks;
+                               }
+                               updateVisibleTicks ();
+                               break;
+                       case LayoutingType.Height:
+                               updateVisibleLines ();
+                               break;
+                       }
+               }
+
+               public override void onMouseLeave (object sender, MouseMoveEventArgs e)
+               {
+                       base.onMouseLeave (sender, e);
+                       hoverLine = -1;
+                       hoverTick = 0;
+               }
+               public override void onMouseMove (object sender, MouseMoveEventArgs e)
+               {                       
+                       long lastTick = hoverTick;
+                       int lastLine = hoverLine;
+                       updateMouseLocalPos (e.Position);
+
+                       if (IFace.IsDown (Glfw.MouseButton.Left) && selStart >= 0)
+                               selEnd = hoverTick;
+                       else if (IFace.IsDown(Glfw.MouseButton.Right)) {
+                               if (lastTick >= 0 && hoverTick >= 0)
+                                       ScrollX += lastTick - hoverTick;
+                               if (lastLine >= 0 && hoverLine >= 0)
+                               ScrollY += lastLine - hoverLine;
+                               updateMouseLocalPos (e.Position);
+                       } else {
+                               HoverWidget = (hoverLine < 0 || hoverLine >= widgets.Count) ? null : widgets [hoverLine];
+                               HoverEvent = hoverWidget?.Events.FirstOrDefault (ev => ev.begin <= hoverTick && ev.end >= hoverTick);
+                               Task.Run (() => findHoverEvent (hoverWidget, hoverTick));
+                       }
+
+                       RegisterForRepaint();
+                       
+                       e.Handled = true;
+                       base.onMouseMove (sender, e);
+               }
+               void findHoverEvent (DbgWidgetRecord widget, long tick) {
+                       DbgEvent tmp = widget?.Events.FirstOrDefault (ev => ev.begin <= tick && ev.end >= tick);                        
+                       if (tmp == null) {
+                               tmp = Events.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin <= tick && ev.end >= tick).FirstOrDefault();                              
+                               while(tmp != null) {
+                                       DbgEvent che = tmp.Events?.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin <= tick && ev.end >= tick).FirstOrDefault();
+                                       if (che == null)
+                                               break;
+                                       tmp = che;
+                               }
+                       } else {
+                               while(tmp != null) {
+                                       DbgEvent che = tmp.Events?.OfType<DbgWidgetEvent>()?.Where(ev=>ev.InstanceIndex == widget.listIndex && ev.begin <= tick && ev.end >= tick).FirstOrDefault();
+                                       if (che == null)
+                                               break;
+                                       tmp = che;
+                               }
+                       }
+                       HoverEvent = tmp;
+               }
+               public override void onMouseClick(object sender, MouseButtonEventArgs e)
+               {
+                       if (e.Button == Glfw.MouseButton.Left && selEnd < 0) {
+                               currentTick = hoverTick;
+                               currentLine = hoverLine;
+                               CurrentWidget = hoverWidget;
+                               CurrentEvent = hoverEvent;
+                       }
+                       selStart = -1;
+                       selEnd = -1;
+
+                       e.Handled = true;
+                       base.onMouseClick(sender, e);
+               }
+               public override void onMouseDown (object sender, MouseButtonEventArgs e)
+               {
+                       if (e.Button == Glfw.MouseButton.Left) {
+                               selStart = hoverTick;
+                               selEnd = -1;
+                       }
+
+                       RegisterForRedraw ();
+                       e.Handled = true;
+                       base.onMouseDown (sender, e);
+               }
+               public override void onMouseUp (object sender, MouseButtonEventArgs e)
+               {
+
+                       if (e.Button == Glfw.MouseButton.Left && selEnd > 0 && selEnd != selStart) {
+                               long scrX = 0;
+                               if (selStart < selEnd) {
+                                       visibleTicks = selEnd - selStart;
+                                       scrX = selStart - minTicks;
+                               } else {
+                                       visibleTicks = selStart - selEnd;
+                                       scrX = selEnd - minTicks;
+                               }
+                               XScale = (ClientRectangle.Width - leftMargin) / visibleTicks;
+                               ScrollX = scrX;
+                       }
+
+                       RegisterForRedraw ();
+                       e.Handled = true;
+                       base.onMouseUp (sender, e);
+               }
+
+               /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
+               public override void onMouseWheel (object sender, MouseWheelEventArgs e)
+               {                       
+                       //base.onMouseWheel (sender, e);
+
+                       if (IFace.Shift)
+                               ScrollX -= (int)((double)(e.Delta * MouseWheelSpeed) / xScale);
+                       else if (IFace.Ctrl) {
+                               if (e.Delta > 0) {
+                                       XScale *= 2.0;
+                               } else {
+                                       if (MaxScrollX > 0)
+                                               XScale *= 0.5;
+                               }
+                               ScrollX = (long)(hoverTick - (long)((double)Math.Max(0, mousePos.X - (long)leftMargin) / xScale) - minTicks);
+                       }else
+                               ScrollY -= e.Delta * MouseWheelSpeed;
+               }
+
+               public override void onKeyDown (object sender, KeyEventArgs e)
+               {
+                       base.onKeyDown (sender, e);
+
+                       if (e.Key == Glfw.Key.F3) {
+                               if (selEnd < 0)
+                                       return;
+                               if (selEnd < selStart)
+                                       zoom (selEnd, selStart);
+                               else
+                                       zoom (selStart, selEnd);
+                               selEnd = selStart = -1;
+                       }
+               }
+
+               void updateMargins ()
+               {
+                       leftMargin = topMargin = 0.0;
+
+                       if (widgets == null)
+                               return;
+
+                       using (Context gr = new Context (IFace.surf)) {
+                               double maxNameWidth = 0.0;
+
+                               gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+                               gr.SetFontSize (Font.Size);
+
+                               foreach (DbgWidgetRecord o in widgets) {
+                                       double nameWidth = gr.TextExtents (o.name).Width + 5.0 * o.xLevel;
+                                       if (nameWidth > maxNameWidth)
+                                               maxNameWidth = nameWidth;
+                               }
+
+                               leftMargin = 10.5 + maxNameWidth;
+                               topMargin = 2.0 * fe.Height;
+
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+
+               void updateVisibleLines ()
+               {
+                       visibleLines = fe.Height < 1 ? 1 : (int)Math.Ceiling (((double)ClientRectangle.Height - topMargin) / fe.Height);
+                       NotifyValueChanged ("VisibleLines", visibleLines);
+                       updateMaxScrollY ();
+               }
+               void updateVisibleTicks ()
+               {
+                       visibleTicks = Math.Max (0, (long)((double)(ClientRectangle.Width - leftMargin) / XScale));
+                       NotifyValueChanged ("VisibleTicks", visibleTicks);
+                       updateMaxScrollX ();
+               }
+
+               void updateMaxScrollX ()
+               {
+                       if (widgets == null) {
+                               MaxScrollX = 0;                         
+                       } else {
+                               long tot = maxTicks - minTicks;
+                               MaxScrollX = Math.Max (0L, tot - visibleTicks);
+                               NotifyValueChanged ("ChildWidthRatio", (double)visibleTicks / tot);
+                       }
+               }
+               void updateMaxScrollY ()
+               {
+                       if (widgets == null)
+                               MaxScrollY = 0;
+                       else {
+                               MaxScrollY = Math.Max (0, widgets.Count + 1 - visibleLines);
+                               NotifyValueChanged ("ChildHeightRatio", (double)visibleLines / (widgets.Count + 1));
+                       }
+               }
+
+               void updateMouseLocalPos (Point mPos)
+               {
+                       Rectangle r = ScreenCoordinates (Slot);
+                       Rectangle cb = ClientRectangle;
+                       cb.Left += (int)leftMargin;
+                       cb.Width -= (int)leftMargin;
+                       cb.Y += (int)topMargin;
+                       cb.Height -= (int)topMargin;
+
+                       mousePos = mPos - r.Position;
+
+                       mousePos.X = Math.Max (cb.X, mousePos.X);
+                       mousePos.X = Math.Min (cb.Right, mousePos.X);
+
+                       if (mousePos.Y < cb.Top || mousePos.Y > cb.Bottom)
+                               hoverLine = -1;
+                       else
+                               hoverLine = (int)((double)(mousePos.Y - cb.Top) / fe.Height) + ScrollY;
+
+                       NotifyValueChanged ("CurrentLine", hoverLine);
+
+                       mousePos.Y = Math.Max (cb.Y, mousePos.Y);
+                       mousePos.Y = Math.Min (cb.Bottom, mousePos.Y);
+
+                       hoverTick = (long)((double)(mousePos.X - cb.X) / xScale) + minTicks + ScrollX;
+                       RegisterForRedraw ();
+               }
+               void zoom (long start, long end) {                                              
+                       //Rectangle cb = ClientRectangle;
+                       //cb.X += (int)leftMargin;
+                       XScale = ((double)ClientRectangle.Width - leftMargin)/(end - start);
+                       ScrollX = (int)(start - minTicks);
+               }
+
+
+               long scrollX, maxScrollX;
+               int scrollY, maxScrollY, mouseWheelSpeed;
+
+               /// <summary>
+               /// if true, key stroke are handled in derrived class
+               /// </summary>
+               protected bool KeyEventsOverrides = false;
+
+               /// <summary> Horizontal Scrolling Position </summary>
+               [DefaultValue(0)]
+               public virtual long ScrollX {
+                       get => scrollX;
+                       set {
+                               if (scrollX == value)
+                                       return;
+
+                               long newS = value;
+                               if (newS < 0)
+                                       newS = 0;
+                               else if (newS > maxScrollX)
+                                       newS = maxScrollX;
+
+                               if (newS == scrollX)
+                                       return;
+
+                               scrollX = newS;
+
+                               NotifyValueChangedAuto (scrollX);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               /// <summary> Vertical Scrolling Position </summary>
+               [DefaultValue(0)]
+               public virtual int ScrollY {
+                       get => scrollY;
+                       set {
+                               if (scrollY == value)
+                                       return;
+
+                               int newS = value;
+                               if (newS < 0)
+                                       newS = 0;
+                               else if (newS > maxScrollY)
+                                       newS = maxScrollY;
+
+                               if (newS == scrollY)
+                                       return;
+
+                               scrollY = newS;
+
+                               NotifyValueChangedAuto (scrollY);
+                               RegisterForGraphicUpdate ();
+
+                               if (widgets == null)
+                                       return;
+
+                               Rectangle cb = ClientRectangle;
+                               cb.Left += (int)leftMargin;
+                               cb.Width -= (int)leftMargin;
+                               cb.Y += (int)topMargin;
+                               cb.Height -= (int)topMargin;
+
+                               if (mousePos.Y < cb.Top || mousePos.Y > cb.Bottom)
+                                       hoverLine = -1;
+                               else
+                                       hoverLine = (int)((double)(mousePos.Y - cb.Top) / fe.Height) + ScrollY;
+
+                               NotifyValueChanged ("CurrentLine", hoverLine);                          
+                       }
+               }
+               /// <summary> Horizontal Scrolling maximum value </summary>
+               [DefaultValue(0)]
+               public virtual long MaxScrollX {
+                       get => maxScrollX;
+                       set {
+                               if (maxScrollX == value)
+                                       return;
+
+                               maxScrollX = Math.Max(0, value);
+
+                               if (scrollX > maxScrollX)
+                                       ScrollX = maxScrollX;
+
+                               NotifyValueChangedAuto (maxScrollX);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               /// <summary> Vertical Scrolling maximum value </summary>
+               [DefaultValue(0)]
+               public virtual int MaxScrollY {
+                       get => maxScrollY;
+                       set {
+                               if (maxScrollY == value)
+                                       return;
+
+                               maxScrollY = Math.Max (0, value);
+
+                               if (scrollY > maxScrollY)
+                                       ScrollY = maxScrollY;
+
+                               NotifyValueChangedAuto (maxScrollY);
+                               RegisterForGraphicUpdate ();
+                       }
+               }
+               /// <summary> Mouse Wheel Scrolling multiplier </summary>
+               [DefaultValue(1)]
+               public virtual int MouseWheelSpeed {
+                       get => mouseWheelSpeed;
+                       set {
+                               if (mouseWheelSpeed == value)
+                                       return;
+                               
+                               mouseWheelSpeed = value;
+
+                               NotifyValueChangedAuto (mouseWheelSpeed);
+                       }
+               }
+       }
+}
+
+
diff --git a/Samples/DebugLogAnalyzer/src/DebugInterface.cs b/Samples/DebugLogAnalyzer/src/DebugInterface.cs
new file mode 100644 (file)
index 0000000..c061532
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright (c) 2013-2019  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow.Cairo;
+using System.Threading;
+
+namespace Crow
+{
+       public class DebugInterface : SampleBase {
+               static DebugInterface() {
+                       DbgLogger.IncludeEvents = DbgEvtType.None;
+                       DbgLogger.DiscardEvents = DbgEvtType.None;
+                       DbgLogger.ConsoleOutput = true;
+               }
+               public DebugInterface (IntPtr hWin) : base (hWin)
+               {
+                       surf = new ImageSurface (Format.Argb32, 100, 100);
+               }
+
+               public override void Run()
+               {
+                       Init();
+
+                       Thread t = new Thread (interfaceThread) {
+                               IsBackground = true
+                       };
+                       t.Start ();
+               }
+               public bool Terminate;
+               string source;
+               Action delRegisterForRepaint;//call RegisterForRepaint in the container widget (DebugInterfaceWidget)
+               Action<Exception> delSetCurrentException;
+
+               void interfaceThread () {
+                       while (!Terminate) {
+                               try
+                               {
+                                       Update();       
+                               }
+                               catch (System.Exception ex)
+                               {
+                                       if (Monitor.IsEntered(LayoutMutex))
+                                               Monitor.Exit (LayoutMutex);
+                                       if (Monitor.IsEntered(UpdateMutex))
+                                               Monitor.Exit (UpdateMutex);
+                                       if (Monitor.IsEntered(ClippingMutex))
+                                               Monitor.Exit (ClippingMutex);
+                                       delSetCurrentException (ex);                                    
+                                       ClearInterface();
+                                       Thread.Sleep(1000);     
+                               }
+                               
+                               if (IsDirty)
+                                       delRegisterForRepaint();                                
+                                       
+                               Thread.Sleep (UPDATE_INTERVAL);
+                       }
+               }
+               public IntPtr SurfacePointer {
+                       get {
+                               lock(UpdateMutex)
+                                       return surf.Handle;
+                       }
+               }
+               public void RegisterDebugInterfaceCallback (object w){
+                       Type t = w.GetType();
+                       delRegisterForRepaint = (Action)Delegate.CreateDelegate(typeof(Action), w, t.GetMethod("RegisterForRepaint"));
+                       delSetCurrentException = (Action<Exception>)Delegate.CreateDelegate(typeof(Action<Exception>), w, t.GetProperty("CurrentException").GetSetMethod());
+               }
+               public void ResetDirtyState () {
+                       IsDirty = false;
+               }
+               public string Source {
+                       set {
+                               if (source == value)
+                                       return;
+                               source = value;
+                               if (string.IsNullOrEmpty(source))
+                                       return;
+                               delSetCurrentException(null);
+                               try
+                               {
+                                       lock (UpdateMutex) {
+                                               Widget tmp = CreateITorFromIMLFragment (source).CreateInstance();
+                                               ClearInterface();
+                                               AddWidget (tmp);
+                                               tmp.DataSource = this;
+                                       }                                       
+                               }
+                               catch (IML.InstantiatorException iTorEx)
+                               {
+                                       delSetCurrentException(iTorEx.InnerException);
+                               }
+                               catch (System.Exception ex)
+                               {
+                                       delSetCurrentException(ex);
+                               }
+                       }
+               }
+               public void Resize (int width, int height) {
+                       
+                       lock (UpdateMutex) {
+                               clientRectangle = new Rectangle (0, 0, width, height);
+                               surf?.Dispose();
+                               surf = new ImageSurface (Format.Argb32, width, height);                         
+                               foreach (Widget g in GraphicTree)
+                                       g.RegisterForLayouting (LayoutingType.All);
+                               RegisterClip (clientRectangle);
+                       }                               
+               }                               
+       }
+}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs b/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs
new file mode 100644 (file)
index 0000000..3f331cf
--- /dev/null
@@ -0,0 +1,281 @@
+// Copyright (c) 2013-2019  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Glfw;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.IO;
+using Crow.Cairo;
+using System.Diagnostics;
+using CrowDbgShared;
+using System.Collections.Generic;
+using Crow.DebugLogger;
+
+namespace Crow
+{      
+       public class DebugInterfaceWidget : Widget {
+               
+               string imlSource;
+               List<DbgEvent> events;
+               List<DbgWidgetRecord> widgets;
+               Exception currentException;
+               object dbgIFace;
+               AssemblyLoadContext crowLoadCtx;
+               Assembly crowAssembly, thisAssembly;
+               Type dbgIfaceType;
+               Action<int, int> delResize;
+               Func<int, int, bool> delMouseMove;
+               Func<MouseButton, bool> delMouseDown, delMouseUp;
+               Action delResetDirtyState;
+               Action delResetDebugger;
+               Action<object, string> delSaveDebugLog;
+               IntPtrGetterDelegate delGetSurfacePointer;
+               Action<string> delSetSource;
+
+               FieldInfo fiDbg_IncludeEvents, fiDbg_DiscardEvents, fiDbg_ConsoleOutput;
+               
+               bool initialized, recording;
+               string crowDbgAssemblyLocation;
+               DbgEvtType recordedEvents, discardedEvents;
+
+               public CommandGroup LoggerCommands =>
+                       new CommandGroup(
+                               new Command("Get logs", () => getLog ()),
+                               new Command("Reset logs", () => delResetDebugger ())
+                       );
+               public string IMLSource {
+                       get => imlSource;
+                       set {
+                               if (imlSource == value)
+                                       return;
+                               imlSource = value;
+                               if (initialized)
+                                       delSetSource (imlSource);                               
+                               NotifyValueChangedAuto(imlSource);
+                               RegisterForRedraw();
+                       }
+               }
+               public Exception CurrentException {
+                       get => currentException;
+                       set {
+                               if (currentException == value)
+                                       return;
+                               currentException = value;                                                                       
+                               NotifyValueChangedAuto(currentException);                                                               
+                       }
+               }
+               public string CrowDbgAssemblyLocation {
+                       get => crowDbgAssemblyLocation;
+                       set {
+                               if (crowDbgAssemblyLocation == value)
+                                       return;
+                               crowDbgAssemblyLocation = value;
+                               NotifyValueChangedAuto(CrowDbgAssemblyLocation);
+                               tryStartDebugInterface();
+                       }
+               }
+
+               public bool Recording {
+                       get => recording;
+                       set {
+                               if (recording == value)
+                                       return;
+                               recording = value & initialized;
+                               if (recording) {
+                                       fiDbg_DiscardEvents.SetValue (dbgIFace, DiscardedEvents);
+                                       fiDbg_IncludeEvents.SetValue (dbgIFace, RecordedEvents);                                        
+                               } else {
+                                       fiDbg_DiscardEvents.SetValue (dbgIFace, DiscardedEvents);
+                                       fiDbg_IncludeEvents.SetValue (dbgIFace, RecordedEvents);
+                               }
+                               NotifyValueChangedAuto(recording);
+                       }
+               }
+               public DbgEvtType RecordedEvents {
+                       get => recordedEvents;
+                       set {
+                               if (recordedEvents == value)
+                                       return;
+                               recordedEvents = value;
+                               if (Recording)
+                                       fiDbg_IncludeEvents.SetValue (dbgIFace, value);
+                               NotifyValueChangedAuto (recordedEvents);
+                       }
+               }
+               public DbgEvtType DiscardedEvents {
+                       get => discardedEvents;
+                       set {
+                               if (discardedEvents == value)
+                                       return;                         
+                               discardedEvents = value;
+                               if (Recording)
+                                       fiDbg_DiscardEvents.SetValue (dbgIFace, value);
+                               NotifyValueChangedAuto (discardedEvents);
+                       }
+               }
+               public bool DebugLogToFile {
+                       get => initialized ? !(bool)fiDbg_ConsoleOutput.GetValue (dbgIFace) : false;
+                       set {
+                               if (!initialized || DebugLogToFile == value)
+                                       return;                         
+                               fiDbg_ConsoleOutput.SetValue (dbgIFace, !value);
+                               NotifyValueChangedAuto (DebugLogToFile);
+                       }
+               }
+
+
+               protected override void onInitialized(object sender, EventArgs e)
+               {
+                       base.onInitialized(sender, e);
+
+                       
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       base.Dispose(disposing);                        
+               }
+
+               public bool CrowDebuggerOK => initialized;
+               public bool CrowDebuggerNOK => !initialized;
+               void notifyCrowDebuggerState () {
+                       NotifyValueChanged("CrowDebuggerOK", CrowDebuggerOK);
+                       NotifyValueChanged("CrowDebuggerNOK", CrowDebuggerNOK);
+               }
+
+               void tryStartDebugInterface () {
+                       if (initialized)
+                               return;
+                       if (!File.Exists (crowDbgAssemblyLocation))     {
+                               notifyCrowDebuggerState();
+                               return;
+                       }
+                       
+                       crowLoadCtx = new AssemblyLoadContext("CrowDebuggerLoadContext");
+               
+                       //using (crowLoadCtx.EnterContextualReflection()) {
+                               crowAssembly = crowLoadCtx.LoadFromAssemblyPath (crowDbgAssemblyLocation);
+                               thisAssembly = crowLoadCtx.LoadFromAssemblyPath (new Uri(Assembly.GetEntryAssembly().CodeBase).LocalPath);                              
+
+                               Type debuggerType = crowAssembly.GetType("Crow.DbgLogger");
+                               if (!(bool)debuggerType.GetField("IsEnabled").GetValue(null)) {
+                                       notifyCrowDebuggerState();
+                                       return;
+                               }                               
+
+                               dbgIfaceType = thisAssembly.GetType("Crow.DebugInterface");
+                               
+                               dbgIFace = Activator.CreateInstance (dbgIfaceType, new object[] {IFace.WindowHandle});
+
+                               delResize = (Action<int, int>)Delegate.CreateDelegate(typeof(Action<int, int>),
+                                                                                       dbgIFace, dbgIfaceType.GetMethod("Resize"));
+
+                               delMouseMove = (Func<int, int, bool>)Delegate.CreateDelegate(typeof(Func<int, int, bool>),
+                                                                                       dbgIFace, dbgIfaceType.GetMethod("OnMouseMove"));
+
+                               delMouseDown = (Func<MouseButton, bool>)Delegate.CreateDelegate(typeof(Func<MouseButton, bool>),
+                                                                                       dbgIFace, dbgIfaceType.GetMethod("OnMouseButtonDown"));
+
+                               delMouseUp = (Func<MouseButton, bool>)Delegate.CreateDelegate(typeof(Func<MouseButton, bool>),
+                                                                                       dbgIFace, dbgIfaceType.GetMethod("OnMouseButtonUp"));
+
+                               delGetSurfacePointer = (IntPtrGetterDelegate)Delegate.CreateDelegate(typeof(IntPtrGetterDelegate),
+                                                                                       dbgIFace, dbgIfaceType.GetProperty("SurfacePointer").GetGetMethod());
+                               delSetSource = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>),
+                                                                                       dbgIFace, dbgIfaceType.GetProperty("Source").GetSetMethod());   
+
+                               delResetDirtyState = (Action)Delegate.CreateDelegate(typeof(Action),
+                                                                                       dbgIFace, dbgIfaceType.GetMethod("ResetDirtyState"));
+
+                               fiDbg_IncludeEvents = debuggerType.GetField("IncludeEvents");
+                               fiDbg_DiscardEvents = debuggerType.GetField("DiscardEvents");
+                               fiDbg_ConsoleOutput = debuggerType.GetField("ConsoleOutput");
+                               delResetDebugger = (Action)Delegate.CreateDelegate(typeof(Action),
+                                                                                       null, debuggerType.GetMethod("Reset"));
+                               /*delSaveDebugLog = (Action<object, string>)Delegate.CreateDelegate(typeof(Action<object, string>),
+                                                                                       null, debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(string)}));*/
+
+                               dbgIfaceType.GetMethod("RegisterDebugInterfaceCallback").Invoke (dbgIFace, new object[] {this} );                               
+                               dbgIfaceType.GetMethod("Run").Invoke (dbgIFace, null);
+
+                               initialized = true;
+                                                                               
+                               //Console.WriteLine($"DbgIFace: LoadCtx:{AssemblyLoadContext.GetLoadContext (dbgIFace.GetType().Assembly).Name})");
+                       //}
+               }
+
+               protected override void onDraw(Context gr)
+               {
+                       Console.WriteLine("onDraw");
+                       gr.SetSource(Colors.RoyalBlue);
+                       gr.Paint();
+               }
+               public override bool CacheEnabled { get => true; set => base.CacheEnabled = true; }
+
+               public override void onMouseMove(object sender, MouseMoveEventArgs e)
+               {
+                       if (initialized) {                              
+                               Point m = ScreenPointToLocal (e.Position);                      
+                               delMouseMove (m.X, m.Y);                                                                        
+                               e.Handled = true;
+                       }
+                       base.onMouseMove(sender, e);
+               }
+               public override void onMouseDown(object sender, MouseButtonEventArgs e)
+               {
+                       if (initialized) {                              
+                               delMouseDown (e.Button);
+                               e.Handled=true;
+                       }
+                       base.onMouseDown (sender, e);                   
+               }
+               public override void onMouseUp(object sender, MouseButtonEventArgs e)
+               {
+                       if (initialized) {                              
+                               delMouseUp (e.Button);                  
+                               e.Handled=true;
+                       }
+                       base.onMouseUp (sender, e);
+               }
+
+               protected override void RecreateCache()
+               {
+                       bmp?.Dispose ();                
+                       
+                       if (initialized) {
+                               delResize (Slot.Width, Slot.Height);                    
+                               bmp = Crow.Cairo.Surface.Lookup (delGetSurfacePointer(), false);                                
+                       } else
+                               bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);                                                           
+
+                       IsDirty = false;                        
+               }
+               protected override void UpdateCache(Context ctx)
+               {                       
+                       if (initialized && bmp != null) {                               
+                               paintCache (ctx, Slot + Parent.ClientRectangle.Position);
+                               delResetDirtyState ();                          
+                       }
+                       
+               }
+
+               void getLog () {
+                       using (Stream stream = new MemoryStream (1024)) {
+                               Type debuggerType = crowAssembly.GetType("Crow.DbgLogger");
+                               debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(Stream)}).Invoke(null, new object[] {dbgIFace, stream});
+                               //debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(string)}).Invoke(null, new object[] {dbgIFace, "debug.log"});
+                               //delSaveDebugLog(dbgIFace, "debug.log");
+                               stream.Seek(0, SeekOrigin.Begin);
+                               events = new List<DbgEvent>();
+                               widgets = new List<DbgWidgetRecord>();
+                               DbgLogger.Load (stream, events, widgets);
+                               //DbgLogger.Load ("debug.log", events, widgets);
+                               DebugLogAnalyzer.Program dla = IFace as DebugLogAnalyzer.Program;
+                               dla.Widgets = widgets;
+                               dla.Events = events;
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/src/Editor.cs b/Samples/DebugLogAnalyzer/src/Editor.cs
new file mode 100644 (file)
index 0000000..315a5a9
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright (c) 2013-2019  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Glfw;
+using Crow.Text;
+
+namespace Crow
+{
+       public class Editor : TextBox {
+               public override void onKeyDown(object sender, KeyEventArgs e)
+               {
+                       TextSpan selection = Selection;
+                       if (e.Key == Key.Tab && !selection.IsEmpty) {
+                               int lineStart = lines.GetLocation (selection.Start).Line;
+                               int lineEnd = lines.GetLocation (selection.End).Line;
+
+                               if (IFace.Shift) {
+                                       for (int l = lineStart; l <= lineEnd; l++) {                            
+                                               if (Text[lines[l].Start] == '\t')
+                                                       update (new TextChange (lines[l].Start, 1, ""));
+                                               else if (Char.IsWhiteSpace (Text[lines[l].Start])) {
+                                                       int i = 1;
+                                                       while (i < lines[l].Length && i < Interface.TAB_SIZE && Char.IsWhiteSpace (Text[i]))
+                                                               i++;
+                                                       update (new TextChange (lines[l].Start, i, ""));
+                                               }
+                                       }
+
+                               }else{
+                                       for (int l = lineStart; l <= lineEnd; l++)              
+                                               update (new TextChange (lines[l].Start, 0, "\t"));                              
+                               }
+
+                selectionStart = new CharLocation (lineStart, 0);
+                CurrentLoc = new CharLocation (lineEnd, lines[lineEnd].Length);
+
+                               return;
+                       }
+                       base.onKeyDown(sender, e);                      
+               }
+       }
+}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/src/Extensions.cs b/Samples/DebugLogAnalyzer/src/Extensions.cs
new file mode 100644 (file)
index 0000000..6086384
--- /dev/null
@@ -0,0 +1,23 @@
+
+
+using Crow;
+
+namespace DebugLogAnalyzer {
+       public static class Extensions {
+
+               public static CommandGroup GetCommands (this System.IO.DirectoryInfo di) =>
+                       new CommandGroup(
+                               new Command ("Set as root", ()=> {Program.CurrentProgramInstance.CurrentDir = di.FullName;}));          
+               public static CommandGroup GetCommands (this System.IO.FileInfo fi) =>
+                       new CommandGroup(
+                               new Command ("Delete", (sender0) => {
+                                       MessageBox.ShowModal (Program.CurrentProgramInstance, MessageBox.Type.YesNo, $"Delete {fi.Name}?").Yes += (sender, e) => {
+                                               System.IO.File.Delete(fi.FullName);
+                                               Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
+                                               (listContainer.Parent as Group).RemoveChild(listContainer);
+                                       };
+                               })
+                       );              
+
+       }
+}
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/src/Program.cs b/Samples/DebugLogAnalyzer/src/Program.cs
new file mode 100644 (file)
index 0000000..7da9f5a
--- /dev/null
@@ -0,0 +1,466 @@
+using System.Reflection.PortableExecutable;
+// Copyright (c) 2013-2021  Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow;
+using System.IO;
+using Glfw;
+using Crow.Text;
+using System.Collections.Generic;
+using Encoding = System.Text.Encoding;
+using Crow.DebugLogger;
+
+namespace DebugLogAnalyzer
+{
+       public class Program : SampleBase
+       {
+               public static Program CurrentProgramInstance;
+               static void Main (string [] args)
+               {
+                       DbgLogger.IncludeEvents = DbgEvtType.None;
+                       DbgLogger.DiscardEvents = DbgEvtType.All;
+
+                       using (Program app = new Program ()) {
+                               CurrentProgramInstance = app;
+                               app.Run ();
+                       }
+               }
+               protected override void OnInitialized () {
+                       initCommands ();
+
+                       base.OnInitialized ();
+
+                       if (string.IsNullOrEmpty (CurrentDir))
+                               CurrentDir = Path.Combine (Directory.GetCurrentDirectory (), "Interfaces");
+
+                       Load ("#Dbg.main.crow").DataSource = this;
+                       //crowContainer = FindByName ("CrowContainer") as Container;
+                       editor = FindByName ("tb") as TextBox;
+
+                       /*TreeView tv = FindByName("dbgTV") as TreeView;
+                       dbgTreeViewScroller = tv.FindByNameInTemplate ("scroller1") as Scroller;*/
+
+
+                       if (!File.Exists (CurrentFile))
+                               newFile ();
+                       //I set an empty object as datasource at this level to force update when new
+                       //widgets are added to the interface                                    
+
+                       reloadFromFile ();
+               }
+                       
+               List<DbgEvent> events = new List<DbgEvent>();
+               List<DbgWidgetRecord> widgets = new List<DbgWidgetRecord>();
+               DbgEvent curEvent = new DbgEvent();
+               DbgWidgetRecord curWidget = new DbgWidgetRecord();
+               bool debugLogRecording;
+               Scroller dbgTreeViewScroller;           
+               int targetTvScroll = -1;
+
+
+
+
+               public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane,
+                                       CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions;
+               public CommandGroup EventCommands, DirectoryCommands;
+               public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs);
+               void initCommands ()
+               {
+                       CMDNew  = new Command ("New", new Action (onNewFile), "#Icons.blank-file.svg");                 
+                       CMDSave = new Command ("Save", new Action (onSave), "#Icons.save.svg", false);
+                       CMDSaveAs = new Command ("Save As...", new Action (onSaveAs), "#Icons.save.svg");
+                       CMDQuit = new Command ("Quit", new Action (() => base.Quit ()), "#Icons.exit.svg");
+                       CMDUndo = new Command ("Undo", new Action (undo),"#Icons.undo.svg", false);
+                       CMDRedo = new Command ("Redo", new Action (redo),"#Icons.redo.svg", false);
+                       CMDCut  = new Command ("Cut", new Action (() => cut ()), "#Icons.scissors.svg", false);
+                       CMDCopy = new Command ("Copy", new Action (() => copy ()), "#Icons.copy-file.svg", false);
+                       CMDPaste= new Command ("Paste", new Action (() => paste ()), "#Icons.paste-on-document.svg", false);
+
+                       EventCommands = new CommandGroup(
+                               new Command("Goto parent event", ()=> { CurrentEvent = CurrentEvent?.parentEvent; })
+                       );
+                       DirectoryCommands = new CommandGroup(
+                               new Command("Set as root directory", ()=> { CurrentEvent = CurrentEvent?.parentEvent; })
+                       );
+
+               }
+
+
+               
+
+                       
+               public string CrowDbgAssemblyLocation {
+                       get => Configuration.Global.Get<string>("CrowDbgAssemblyLocation");
+                       set {
+                               if (CrowDbgAssemblyLocation == value)
+                                       return;
+                               Configuration.Global.Set ("CrowDbgAssemblyLocation", value);
+                               NotifyValueChanged(CrowDbgAssemblyLocation);
+                       }
+               }
+               public List<DbgEvent> Events {
+                       get => events;
+                       set {
+                               if (events == value)
+                                       return;
+                               events = value;
+                               NotifyValueChanged (nameof (Events), events);
+                       }
+               }
+               public List<DbgWidgetRecord> Widgets {
+                       get => widgets;
+                       set {
+                               if (widgets == value)
+                                       return;
+                               widgets = value;
+                               NotifyValueChanged (nameof (Widgets), widgets);
+                       }
+               }
+               public DbgEvent CurrentEvent {
+                       get => curEvent;
+                       set {
+                               if (curEvent == value)
+                                       return;
+                               
+                               curEvent = value;
+                               NotifyValueChanged (nameof (CurrentEvent), curEvent);
+                               NotifyValueChanged ("CurEventChildEvents", curEvent?.Events);
+                               
+                       }
+               }
+               public DbgWidgetRecord CurrentWidget {
+                       get => curWidget;
+                       set {
+                               if (curWidget == value)
+                                       return;
+                               curWidget = value;
+                               NotifyValueChanged (nameof (CurrentWidget), curWidget);
+                               NotifyValueChanged ("CurWidgetRootEvents", curWidget?.RootEvents);
+                               NotifyValueChanged ("CurWidgetEvents", curWidget?.Events);
+                               
+                       }
+               }
+               public List<DbgWidgetEvent> CurWidgetRootEvents => curWidget == null? new List<DbgWidgetEvent>() : curWidget.RootEvents;
+               public DbgEvtType RecordedEvents {
+                       get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents));
+                       set {
+                               if (RecordedEvents == value)
+                                       return;                         
+                               Configuration.Global.Set (nameof (RecordedEvents), value);                              
+                               if (DebugLogRecording)
+                                       DbgLogger.IncludeEvents = RecordedEvents;
+                               NotifyValueChanged(RecordedEvents);
+                       }
+               }
+               public DbgEvtType DiscardedEvents {
+                       get => Configuration.Global.Get<DbgEvtType> (nameof (DiscardedEvents));
+                       set {
+                               if (DiscardedEvents == value)
+                                       return;
+                               Configuration.Global.Set (nameof (DiscardedEvents), value);
+                               if (DebugLogRecording)
+                                       DbgLogger.DiscardEvents = DiscardedEvents;
+                               NotifyValueChanged(DiscardedEvents);
+                       }
+               }
+               public bool DebugLoggingEnabled => DbgLogger.IsEnabled;
+               public bool DebugLogToFile {
+                       get => Configuration.Global.Get<bool> (nameof(DebugLogToFile));
+                       set {
+                               if (DbgLogger.ConsoleOutput != value)
+                                       return;                         
+                               Configuration.Global.Set (nameof(DebugLogToFile), value);
+                               NotifyValueChanged(DebugLogToFile);
+                       }
+               }
+               public string DebugLogFilePath {
+                       get => Configuration.Global.Get<string> (nameof (DebugLogFilePath));
+                       set {
+                               if (CurrentFile == value)
+                                       return;
+                               Configuration.Global.Set (nameof (DebugLogFilePath), value);
+                               NotifyValueChanged (DebugLogFilePath);
+                       }
+               }
+               public bool DebugLogRecording {
+                       get => debugLogRecording;
+                       set {
+                               if (debugLogRecording == value)
+                                       return;
+                               debugLogRecording = value;
+                               NotifyValueChanged(debugLogRecording);
+                       }
+               }               
+
+               
+               const string _defaultFileName = "unnamed.txt";
+               string source = "", origSource;         
+               TextBox editor; 
+               Stack<TextChange> undoStack = new Stack<TextChange> ();
+               Stack<TextChange> redoStack = new Stack<TextChange> ();
+               TextSpan selection;
+               Exception currentException;
+               public string CurrentDir {
+                       get => Configuration.Global.Get<string> (nameof (CurrentDir));
+                       set {
+                               if (CurrentDir == value)
+                                       return;
+                               Configuration.Global.Set (nameof (CurrentDir), value);
+                               NotifyValueChanged (CurrentDir);
+                       }
+               }
+               public string CurrentFile {
+                       get => Configuration.Global.Get<string> (nameof (CurrentFile));
+                       set {
+                               if (CurrentFile == value)
+                                       return;
+                               Configuration.Global.Set (nameof (CurrentFile), value);
+                               NotifyValueChanged (CurrentFile);
+                       }
+               }               
+               public new bool IsDirty => source != origSource;
+               public string Source {
+                       get => source;
+                       set {
+                               if (source == value)
+                                       return;
+                               source = value;
+                               CMDSave.CanExecute = IsDirty;
+                               NotifyValueChanged (source);
+                               NotifyValueChanged ("IsDirty", IsDirty);
+                       }
+               }
+               string SelectedText =>  
+                               selection.IsEmpty ? "" : Source.AsSpan (selection.Start, selection.Length).ToString ();
+               public Exception CurrentException {
+                       get => currentException;
+                       set {
+                               if (currentException == value)
+                                       return;
+                               currentException = value;
+                               NotifyValueChanged ("ShowError", ShowError);
+                               NotifyValueChanged ("CurrentExceptionMSG", (object)CurrentExceptionMSG);
+                               NotifyValueChanged (currentException);
+                       }
+               }
+               public bool ShowError => currentException != null;
+               public string CurrentExceptionMSG => currentException == null ? "" : currentException.Message;
+
+       
+
+               void undo () {
+                       if (undoStack.TryPop (out TextChange tch)) {
+                               redoStack.Push (tch.Inverse (source));
+                               CMDRedo.CanExecute = true;
+                               apply (tch);
+                               editor.SetCursorPosition (tch.End + tch.ChangedText.Length);
+                       }
+                       if (undoStack.Count == 0)
+                               CMDUndo.CanExecute = false;
+               }
+               void redo () {
+                       if (redoStack.TryPop (out TextChange tch)) {
+                               undoStack.Push (tch.Inverse (source));
+                               CMDUndo.CanExecute = true;
+                               apply (tch);
+                               editor.SetCursorPosition (tch.End + tch.ChangedText.Length);
+                       }
+                       if (redoStack.Count == 0)
+                               CMDRedo.CanExecute = false;
+               }
+               void cut () {
+                       copy ();
+                       applyChange (new TextChange (selection.Start, selection.Length, ""));
+               }
+               void copy () {
+                       Clipboard = SelectedText;
+               }
+               void paste () {                 
+                       applyChange (new TextChange (selection.Start, selection.Length, Clipboard));
+               }
+               bool disableTextChangedEvent = false;
+               void apply (TextChange change) {
+                       Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)];
+                       ReadOnlySpan<char> src = source.AsSpan ();
+                       src.Slice (0, change.Start).CopyTo (tmp);
+                       if (!string.IsNullOrEmpty (change.ChangedText))
+                               change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
+                       src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
+                       disableTextChangedEvent = true;
+                       Source = tmp.ToString ();
+                       disableTextChangedEvent = false;                        
+               }       
+               void applyChange (TextChange change) {
+                       undoStack.Push (change.Inverse (source));
+                       redoStack.Clear ();
+                       CMDUndo.CanExecute = true;
+                       CMDRedo.CanExecute = false;
+                       apply (change);
+               }
+
+               void resetUndoRedo () {
+                       undoStack.Clear ();
+                       redoStack.Clear ();
+                       CMDUndo.CanExecute = false;
+                       CMDRedo.CanExecute = false;                     
+               }               
+
+               void onNewFile () {
+                       if (IsDirty) {                          
+                               MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?").Yes += (sender, e) => newFile ();
+                       } else
+                               newFile ();
+               }
+               void onSave ()
+               {
+                       if (!File.Exists (CurrentFile)) {
+                               onSaveAs ();
+                               return;
+                       }
+                       save ();
+               }
+               void onSaveAs ()
+               {
+                       string dir = Path.GetDirectoryName (CurrentFile);
+                       if (string.IsNullOrEmpty (dir))
+                               dir = Directory.GetCurrentDirectory ();
+                       LoadIMLFragment (@"<FileDialog Width='60%' Height='50%' Caption='Save as ...' CurrentDirectory='" +
+                               dir + "' SelectedFile='" +
+                               Path.GetFileName(CurrentFile) + "' OkClicked='saveFileDialog_OkClicked'/>").DataSource = this;
+               }
+               void saveFileDialog_OkClicked (object sender, EventArgs e)
+               {
+                       FileDialog fd = sender as FileDialog;
+
+                       if (string.IsNullOrEmpty (fd.SelectedFileFullPath))
+                               return;
+
+                       if (File.Exists(fd.SelectedFileFullPath)) {
+                               MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "File exists, overwrite?");
+                               mb.Yes += (sender2, e2) => {
+                                       CurrentFile = fd.SelectedFileFullPath;
+                                       save ();
+                               };
+                               return;
+                       }
+
+                       CurrentFile = fd.SelectedFileFullPath;
+                       save ();
+               }
+
+               void newFile()
+               {
+                       disableTextChangedEvent = true;
+                       Source = @"<Label Text='Hello World' Background='MediumSeaGreen' Margin='10'/>";
+                       disableTextChangedEvent = false;
+                       resetUndoRedo ();
+                       if (!string.IsNullOrEmpty (CurrentFile))
+                               CurrentFile = Path.Combine (Path.GetDirectoryName (CurrentFile), "newfile.crow");
+                       else
+                               CurrentFile = Path.Combine (CurrentDir, "newfile.crow");
+               }
+
+               void save () {
+                       using (Stream s = new FileStream(CurrentFile, FileMode.Create)) {
+                               s.WriteByte (0xEF);
+                               s.WriteByte (0xBB);
+                               s.WriteByte (0xBF);
+                               byte [] buff = Encoding.UTF8.GetBytes (source);
+                               s.Write (buff, 0, buff.Length);
+                       }
+                       origSource = source;
+                       NotifyValueChanged ("IsDirty", IsDirty);
+                       CMDSave.CanExecute = false;
+               }
+
+               void reloadFromFile () {                        
+                       disableTextChangedEvent = true;
+                       if (File.Exists (CurrentFile)) {
+                               using (Stream s = new FileStream (CurrentFile, FileMode.Open)) {
+                                       using (StreamReader sr = new StreamReader (s))
+                                               Source = origSource = sr.ReadToEnd ();
+                               }
+                       }
+                       disableTextChangedEvent = false;
+                       resetUndoRedo ();
+               }               
+
+               public void goUpDirClick (object sender, MouseButtonEventArgs e)
+               {
+                       string root = Directory.GetDirectoryRoot (CurrentDir);
+                       if (CurrentDir == root)
+                               return;
+                       CurrentDir = Directory.GetParent (CurrentDir).FullName;
+               }
+
+               void Dv_SelectedItemChanged (object sender, SelectionChangeEventArgs e)
+               {
+                       FileSystemInfo fi = e.NewValue as FileSystemInfo;
+                       if (fi == null)
+                               return;
+                       if (fi is DirectoryInfo)
+                               return;
+
+                       if (IsDirty) {
+                               MessageBox mb = MessageBox.ShowModal (this, MessageBox.Type.YesNo, "Current file has unsaved changes, are you sure?");
+                               mb.Yes += (mbsender, mbe) => { CurrentFile = fi.FullName; reloadFromFile (); };
+                               return;
+                       }
+
+                       CurrentFile = fi.FullName;
+                       reloadFromFile ();
+               }
+               void onTextChanged (object sender, TextChangeEventArgs e) {
+                       if (disableTextChangedEvent)
+                               return;
+                       applyChange (e.Change);
+               }               
+               
+               void onSelectedTextChanged (object sender, EventArgs e) {                       
+                       selection = (sender as Label).Selection;
+                       Console.WriteLine($"selection:{selection.Start} length:{selection.Length}");
+                       CMDCut.CanExecute = CMDCopy.CanExecute = !selection.IsEmpty;
+               }
+               void textView_KeyDown (object sender, Crow.KeyEventArgs e) {
+                       if (Ctrl) {
+                               if (e.Key == Glfw.Key.W) {
+                                       if (Shift)
+                                               CMDRedo.Execute ();
+                                       else
+                                               CMDUndo.Execute ();
+                               } else if (e.Key == Glfw.Key.S) {
+                                       onSave ();
+                               }
+                       }
+               }
+
+
+
+        public override bool OnKeyDown (Key key) {
+
+            switch (key) {
+            case Key.F5:
+                Load ("#Dbg.DebugLog.crow").DataSource = this;
+                return true;
+            /*case Key.F6:
+                               if (DebugLogRecording) {
+                                       DbgLogger.IncludeEvents = DbgEvtType.None;
+                                       DbgLogger.DiscardEvents = DbgEvtType.All;
+                                       if (DebugLogToFile && !string.IsNullOrEmpty(DebugLogFilePath))
+                               DbgLogger.Save (this, DebugLogFilePath);
+                                       DebugLogRecording = false;
+                               } else {
+                                       DbgLogger.Reset ();
+                                       DbgLogger.IncludeEvents = RecordedEvents;
+                                       DbgLogger.DiscardEvents = DiscardedEvents;
+                                       DebugLogRecording = true;
+                               }
+                return true;*/
+            }
+            return base.OnKeyDown (key);
+        }
+    }
+}
+
diff --git a/Samples/DebugLogAnalyzer/ui/Button.template b/Samples/DebugLogAnalyzer/ui/Button.template
new file mode 100644 (file)
index 0000000..c7e2fa0
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<Border Background="{./Background}" MinimumSize="50,20" Name="Content"
+                                                       Foreground="Transparent" CornerRadius="{../CornerRadius}" BorderWidth="1"
+                                                       MouseEnter="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black};{caption.Foreground=White}"
+                                                       MouseLeave="{Foreground=Transparent};{caption.Foreground=LightGrey}"
+                                                       MouseDown="{Foreground=vgradient|0:Black|0.05:Grey|0.85:Grey|1:White}"
+                                                       MouseUp="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black}">
+       <HorizontalStack Margin="2">
+               <Image Style="Icon" Path="{./Icon}"/>
+               <Label Font="{./Font}" Name="caption" Margin="3" Foreground="LightGrey" Text="{./Caption}"/>
+       </HorizontalStack>
+</Border>
\ No newline at end of file
index 2f6fbfbfbe5e0fb6e440d4b47c9fd3642462fbf2..96de2dc66205347b40fa366c63e37bf2e77fd1b7 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <ItemTemplate Data="Events">
-       <ListItem IsSelected="{²IsSelected}" Height="Fit"
+       <ListItem Height="Fit"
                                                Selected="{/exp.Background=${ControlHighlight}}"
                                                Unselected="{/exp.Background=Transparent}">
-               <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
+               <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" >
                        <Template>
                                        <VerticalStack>
                                                <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
        </ListItem>
 </ItemTemplate>                
 <ItemTemplate Data="Events" DataType="DbgWidgetEvent">
-       <ListItem IsSelected="{²IsSelected}" Height="Fit"
+       <ListItem  Height="Fit"
                                                Selected="{/exp.Background=${ControlHighlight}}"
                                                Unselected="{/exp.Background=Transparent}">
-               <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
+               <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" >
                        <Template>
                                <VerticalStack>
                                        <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
@@ -53,7 +53,7 @@
                                                                MouseEnter="{Background=LightGrey}"
                                                                MouseLeave="{Background=Transparent}"/>
                                                        <Label Text="{./Caption}" Width="80" Font="mono, 8" />
-                                                       <Label Text="{Duration}" Width="40" Font="mono, 8" TextAlignment="Center" Background="DimGrey"/>
+                                                       <Label Text="{DurationMS}" Width="40" Font="mono, 8" TextAlignment="Center" Background="DimGrey"/>
                                                        <Label Text="{InstanceIndex}" Width="40" Font="mono, 8" TextAlignment="Center" Background="DimGrey"/>
                                                        <DbgEventWidget Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" Width="Stretched" Height="5"/>
                                                </HorizontalStack>
index 9d40f45de7de5f9ad9801ac4109872502680439a..2d5815e92808e024990f9c479833be7f0a432c13 100644 (file)
@@ -8,17 +8,21 @@
                </HorizontalStack>
                <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
                        <Label Text="Duration:" Foreground="White" Width="50%" />       
-                       <Label Text="{Duration}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Right"/>                         
+                       <Label Text="{DurationMS}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Right"/>                               
                </HorizontalStack>
                <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
                        <Label Text="Begin:" Foreground="${TooltipForeground}" Width="50%"/>    
-                       <Label Text="{begin}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                               
+                       <Label Text="{BeginMS}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                             
                </HorizontalStack>
                <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
                        <Label Text="End:" Foreground="${TooltipForeground}" Width="50%"/>      
-                       <Label Text="{end}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                         
+                       <Label Text="{EndMS}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                               
                </HorizontalStack>
-               <VerticalStack Height="Fit" Width="Stretched" >
+               <VerticalStack Height="Fit" Width="Stretched" IsVisible="{IsLayoutEvent}" >
+                       <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                               <Label Text="Layout:" Foreground="White" Width="50%" /> 
+                               <Label Text="{layouting}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                               
+                       </HorizontalStack>
                        <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
                                <Label Text="Result:" Foreground="White" Width="50%" /> 
                                <Label Text="{result}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                          
diff --git a/Samples/DebugLogAnalyzer/ui/DebugLog.crow b/Samples/DebugLogAnalyzer/ui/DebugLog.crow
new file mode 100644 (file)
index 0000000..2683964
--- /dev/null
@@ -0,0 +1,127 @@
+<?xml version="1.0"?>
+<Window Caption="Debug Log" Background="0.05,0.05,0.1,0.9" Width="80%" Height="80%">
+       <VerticalStack>
+               <TabView>
+                       <VerticalStack Name="LogGraph" Background="DarkGrey">
+                               <EnumSelector RadioButtonStyle="CheckBox2" Template="#Dbg.EnumSelector.template"
+                                               Caption="Discarded Events" EnumValue="{²../dbv.Filter}" BitFieldExcludeMask="255" />                                   
+                               <HorizontalStack>
+                                       <DbgLogViewer Visible="true" Name="dbv" Events="{Events}" Widgets="{Widgets}" MouseWheelSpeed="3" Font="mono, 8" 
+                                                                                        CurrentEvent="{²CurrentEvent}" CurrentWidget="{²CurrentWidget}" Background="Onyx"/>
+                                       <ScrollBar Maximum="{../dbv.MaxScrollY}" Value="{²../dbv.ScrollY}" SmallIncrement="1" LargeIncrement="10"
+                                                                                       CursorRatio="{../dbv.ChildHeightRatio}"/>
+                               </HorizontalStack>
+                               <ScrollBar Style="HScrollBar"  Maximum="{../dbv.MaxScrollX}" Value="{²../dbv.ScrollX}" SmallIncrement="1" LargeIncrement="10"
+                                       CursorRatio="{../dbv.ChildWidthRatio}"/>
+                               <HorizontalStack Height="Fit" DataSource="{CurrentWidget}" Spacing="3">
+                                       <Label Style="smallLabValue" Text="{name}"/>
+                                       <Label Style="smallLabValue" Text="{listIndex}"/>
+                                       <Label Style="smallLabValue" Text="{treeIndex}"/>
+                                       <Label Style="smallLabValue" Text="{yIndex}"/>
+                                       <Label Style="smallLabValue" Text="{xLevel}"/>
+                                       <Label Style="smallLabCaption" Text="Width:"/>
+                                       <Label Style="smallLabValue" Text="{Width}"/>
+                                       <Label Style="smallLabCaption" Text="Height:" />
+                                       <Label Style="smallLabValue" Text="{Height}"/>
+                                       <Label Style="smallLabCaption" Text="ScrollX:" />
+                                       <Label Style="smallLabValue" Text="{../../dbv.ScrollX}"/>
+                                       <Label Style="smallLabCaption" Text="MaxScrollX:" />
+                                       <Label Style="smallLabValue" Text="{../../dbv.MaxScrollX}"/>
+                                       <Label Style="smallLabValue" Tooltip="XScale" Text="{../../dbv.XScale}"/>
+                                       <Label Style="smallLabValue" Tooltip="VisibleTicks" Text="{../../dbv.VisibleTicks}"/>                           
+                               </HorizontalStack>
+                       </VerticalStack>
+                       <VerticalStack Name="AllEvents" Width="Stretched" IsVisible="false">
+                               <TreeView Height="Stretched" Name="dbgTV" Data="{Events}" SelectedItem="{²CurrentEvent}" Background="DarkGrey"                                                 
+                                                       ItemTemplate="#Dbg.DbgEventTreeItems.itemp"/> 
+                               <ListBox Data="{CurWidgetEvents}" Height="100" SelectedItem="{²CurrentEvent}">
+                                       <ItemTemplate>
+                                               <ListItem Margin="0" Height="16" Width="Fit"
+                                                                       Selected="{Background=${ControlHighlight}}"
+                                                                       Unselected="{Background=Transparent}">
+                                                       <DbgEventWidget Height="10" Width="Fit" Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" TicksPerPixel="20" VerticalAlignment="Center"/>
+                                               </ListItem>
+                                       </ItemTemplate>
+                                       <Template>
+                                               <Wrapper Name="ItemsContainer" Spacing="1" Background="DarkGrey"/>
+                                       </Template>
+                               </ListBox>                              
+                       </VerticalStack>
+                       <VerticalStack Name="CurWidgetEvents" Width="Stretched" IsVisible="false">
+                               <TreeView Height="Stretched" Data="{CurWidgetEvents}" SelectedItem="{²CurrentEvent}" Background="DarkGrey"                                                     
+                                                       ItemTemplate="#Dbg.DbgEventTreeItems.itemp"/> 
+                       </VerticalStack>
+               </TabView>
+               <Splitter/>
+               <HorizontalStack Height="30%">
+                       <ListBox Data="{Widgets}" Width="50%" SelectedItem="{²CurrentWidget}">
+                               <Template>
+                               </Template>
+                       </ListBox>
+                       <Splitter/>
+                       <VerticalStack>
+                               <HorizontalStack Height="Fit" Background="Onyx" Spacing="5">
+                                       <Label Text="{CurrentWidget}"/>
+                                       <Label Text="events"/>
+                               </HorizontalStack>
+                               <ListBox  Data="{CurWidgetEvents}" Background="Black" SelectedItem="{²CurrentEvent}">
+                                       <ItemTemplate>
+                                               <ListItem Margin="0" Height="16" IsSelected="{²IsSelected}" Width="Fit"
+                                                                       Selected="{Background=${ControlHighlight}}"
+                                                                       Unselected="{Background=Transparent}">
+                                                       <DbgEventWidget Height="10" Width="Fit" Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" TicksPerPixel="300" VerticalAlignment="Center"/>
+                                               </ListItem>
+                                       </ItemTemplate>
+                                       <Template>
+                                               <Wrapper Name="ItemsContainer" Spacing="1" Background="{./Background}"/>
+                                       </Template>
+                               </ListBox>
+                               <!--<TreeView Data="{Events}" SelectedItem="{²CurrentEvent}" Background="DarkGrey"                                                     
+                                                       ItemTemplate="#Dbg.DbgEventTreeItems.itemp"/>-->
+                       </VerticalStack>
+                       <Splitter/>
+                       <VerticalStack Height="Stretched" Width="20%" Margin="${TooltipMargin}" DataSource="{CurrentEvent}">
+                               <Label Text="{type}" Background="{Color}" Foreground="Black" Width="200" TextAlignment="Center" Margin="6"/>
+                               <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Visible="{IsWidgetEvent}" Background="DimGrey" Margin="2">
+                                       <Label Text="Instance:" Foreground="White" Width="50%" />       
+                                       <Label Text="{InstanceIndex}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                           
+                               </HorizontalStack>
+                               <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                                       <Label Text="Duration:" Foreground="White" Width="50%" />       
+                                       <Label Text="{DurationMS}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Right"/>                               
+                               </HorizontalStack>
+                               <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
+                                       <Label Text="Begin:" Foreground="${TooltipForeground}" Width="50%"/>    
+                                       <Label Text="{BeginMS}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                             
+                               </HorizontalStack>
+                               <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
+                                       <Label Text="End:" Foreground="${TooltipForeground}" Width="50%"/>      
+                                       <Label Text="{EndMS}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>                               
+                               </HorizontalStack>
+                               <VerticalStack Height="Fit" Width="Stretched" IsVisible="{IsLayoutEvent}" >
+                                       <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                                               <Label Text="Layout:" Foreground="White" Width="50%" /> 
+                                               <Label Text="{layouting}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                               
+                                       </HorizontalStack>
+                                       <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                                               <Label Text="Result:" Foreground="White" Width="50%" /> 
+                                               <Label Text="{result}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                          
+                                       </HorizontalStack>
+                                       <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                                               <Label Text="Old Slot:" Foreground="White" Width="50%" />       
+                                               <Label Text="{OldSlot}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                         
+                                       </HorizontalStack>
+                                       <HorizontalStack Height="Fit" Width="Stretched" Spacing="2" Background="DimGrey" Margin="2">
+                                               <Label Text="New Slot:" Foreground="White" Width="50%" />       
+                                               <Label Text="{NewSlot}" Foreground="White" Background="Onyx" Width="Stretched" TextAlignment="Center"/>                         
+                                       </HorizontalStack>
+                               </VerticalStack>
+                               <DbgEventWidget Height="10" Width="Stretched" Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" />
+                               <GroupBox Caption="Parent Event" Height="Fit" >
+                                       <DbgEventWidget Height="10" Width="Stretched" Event="{parentEvent}" Tooltip="#Dbg.DbgEvtTooltip.crow" />
+                               </GroupBox>
+                               <!--<Label Text="{}" Foreground="${TooltipForeground}"/>-->
+                       </VerticalStack>                                        
+               </HorizontalStack>
+       </VerticalStack>
+</Window>
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/ui/EnumSelector.template b/Samples/DebugLogAnalyzer/ui/EnumSelector.template
new file mode 100644 (file)
index 0000000..2fffa3f
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<Popper >
+       <Template>
+               <CheckBox IsChecked="{²./IsPopped}">
+                       <Template>
+                               <HorizontalStack Background="{../../../Background}" Margin="5" Spacing="10">
+                                       <Label Text="{../../../../Caption}" Width="Stretched"/>
+                                       <Label Background="SeaGreen" Text="{../../../../EnumValue}" Margin="3"/>
+                               </HorizontalStack>
+                       </Template>
+               </CheckBox>
+       </Template>     
+       <Wrapper Name="Content" Height="Fit" Width="{../PopWidth}" Background="Jet" />  
+</Popper>
\ No newline at end of file
diff --git a/Samples/DebugLogAnalyzer/ui/dbg.style b/Samples/DebugLogAnalyzer/ui/dbg.style
new file mode 100644 (file)
index 0000000..77772f1
--- /dev/null
@@ -0,0 +1,15 @@
+IcoButton {
+       Template = "#Dbg.Button.template";
+       Background = "Onyx";
+}
+CheckBox2 {
+       Width = "200";
+}
+smallLabCaption {
+       Font="mono, 8";
+       Foreground="Grey";
+}
+smallLabValue {
+       Font="mono, 10";
+       Foreground="White";
+}
\ No newline at end of file
index 72d96bf068fb13afd70a52c73f41852682c7f0ec..fd42833c414a972edab914e817cea2bafcbea6b4 100644 (file)
                        <Label Text="{treeIndex}"/>
                        <Label Text="{yIndex}"/>
                        <Label Text="{xLevel}"/>
-                       <Label Text="Width:"/>
+                       <Label Text="Width:" Foreground="Grey"/>
                        <Label Text="{Width}"/>
-                       <Label Text="Height:"/>
+                       <Label Text="Height:" Foreground="Grey"/>
                        <Label Text="{Height}"/>
-                       <Label Text="ScrollX"/>
+                       <Label Text="ScrollX:" Foreground="Grey"/>
                        <Label Text="{../../dbv.ScrollX}"/>
+                       <Label Text="MaxScrollX:" Foreground="Grey"/>
+                       <Label Text="{../../dbv.MaxScrollX}"/>                  
                </HorizontalStack>
        </VerticalStack>
        <Splitter/>
diff --git a/Samples/DebugLogAnalyzer/ui/focused.crow b/Samples/DebugLogAnalyzer/ui/focused.crow
new file mode 100644 (file)
index 0000000..755345a
--- /dev/null
@@ -0,0 +1,17 @@
+<Window Width="80%" Movable="false">
+       <VerticalStack>
+               <HorizontalStack Height="Fit">
+                       <Label Text="Hover:" Width="50" Foreground="Grey"/>
+                       <Label Text="{HoverWidget}" Font="mono, 8"/>
+               </HorizontalStack>
+               <HorizontalStack Height="Fit">
+                       <Label Text="Focus:" Width="50" Foreground="Grey"/>
+                       <Label Text="{FocusedWidget}" Font="mono, 8"/>
+               </HorizontalStack>
+               <HorizontalStack Height="Fit">
+                       <Label Text="Active:" Width="50" Foreground="Grey"/>
+                       <Label Text="{ActiveWidget}" Font="mono, 8"/>
+               </HorizontalStack>              
+       </VerticalStack>
+</Window>
+
diff --git a/Samples/DebugLogAnalyzer/ui/main.crow b/Samples/DebugLogAnalyzer/ui/main.crow
new file mode 100644 (file)
index 0000000..24a50a2
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0"?>
+<VerticalStack Background="DarkGrey">
+       <HorizontalStack >
+               <TabView Width="25%" >
+                       <VerticalStack Name="Explorer" Background="Onyx">
+                               <HorizontalStack Height="Fit" Margin="2" >
+                                       <Image Margin="2" Width="16" Height="16" Path="#Crow.Icons.level-up.svg" MouseClick="goUpDirClick"
+                                                                Background="Jet" MouseEnter="{Background=Grey}" MouseLeave="{Background=Jet}" />                       
+                                       <TextBox Text="{²CurrentDir}" Margin="2"/>
+                               </HorizontalStack>              
+                               <DirectoryView Margin="1" Name="dv" CurrentDirectory="{CurrentDir}" SelectedItemChanged="Dv_SelectedItemChanged">
+                                       <Template>
+                                               <TreeView IsRoot="true" Name="treeView" Data="{./FileSystemEntries}" Background="{./Background}"
+                                                               SelectedItemChanged="./onSelectedItemChanged">
+                                                       <ItemTemplate DataType="System.IO.FileInfo">
+                                                               <ListItem CornerRadius="2" Margin="0" Height="Fit" Width="Stretched"
+                                                                               ContextCommands="{GetCommands}" 
+                                                                               Selected="{Background=${ControlHighlight}}"
+                                                                               Unselected="{Background=Transparent}">
+                                                                       <HorizontalStack>
+                                                                               <Image Margin="1" Width="14" Height="14" Path="#Crow.Icons.file.svg"/>
+                                                                               <Label Text="{Name}" Width="Stretched"/>
+                                                                       </HorizontalStack>
+                                                               </ListItem>
+                                                       </ItemTemplate>
+                                                       <ItemTemplate DataType="System.IO.DirectoryInfo" Data="GetFileSystemInfosOrdered">
+                                                               <ListItem ContextCommands="{GetCommands}"
+                                                                               Selected="{/exp.Background=${ControlHighlight}}"
+                                                                               Unselected="{/exp.Background=Transparent}">
+                                                                       <Expandable Name="exp" Caption="{Name}" MouseDoubleClick="/onClickForExpand">
+                                                                               <Template>
+                                                                                       <VerticalStack>
+                                                                                               <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
+                                                                                                               Foreground="Transparent"
+                                                                                                               MouseEnter="{Foreground=DimGrey}"
+                                                                                                               MouseLeave="{Foreground=Transparent}">
+                                                                                                       <HorizontalStack Background="{./Background}" Spacing="1">
+                                                                                                               <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand"
+                                                                                                                       Path="{./Image}"
+                                                                                                                       Visible="{./IsExpandable}"
+                                                                                                                       SvgSub="{./IsExpanded}"
+                                                                                                                       MouseEnter="{Background=LightGrey}"
+                                                                                                                       MouseLeave="{Background=Transparent}"/>
+                                                                                                               <Image Margin="1" Width="16" Height="16"
+                                                                                                                       Path="#Crow.Icons.folder.svg" SvgSub="{./IsExpanded}"/>
+                                                                                                               <Label Text="{./Caption}"/>
+                                                                                                       </HorizontalStack>
+                                                                                               </Border>
+                                                                                               <Container Name="Content" Visible="false"/>
+                                                                                       </VerticalStack>
+                                                                               </Template>
+                                                                               <HorizontalStack Height="Fit">
+                                                                                       <Widget Width="12" Height="10"/>
+                                                                                       <VerticalStack Height="Fit" Name="ItemsContainer"/>
+                                                                               </HorizontalStack>
+                                                                       </Expandable>
+                                                               </ListItem>
+                                                       </ItemTemplate>
+                                               </TreeView>
+                                       </Template>             
+                               </DirectoryView>
+                       </VerticalStack>
+                       <VerticalStack Name="DebugLogger" Margin="5" IsVisible="false" Background="Onyx">
+                               <HorizontalStack Height="Fit">
+                                       <Image Width="30" Height="20" Path="#Crow.Icons.IconAlerte.svg" Visible="{../../../../dbgIfaceWidget.CrowDebuggerNOK}"/>
+                                       <Label Fit="true" Text="Crow debug assembly path:"/>
+                                       <Widget Width="5" Height="5" Background="SeaGreen" IsVisible="{../../../../dbgIfaceWidget.HasFocus}"/>
+                                       <Widget Width="5" Height="5" Background="Yellow" IsVisible="{../../../../dbgIfaceWidget.IsHover}"/>
+                                       <TextBox Text="{²CrowDbgAssemblyLocation}" Margin="2"/>
+                               </HorizontalStack>                              
+                               <CheckBox Name="cbFile" Caption="Record to file" IsChecked="{²DebugLogToFile}" Background="Onyx"/>
+                               <HorizontalStack Height="Fit" Width="Stretched" IsEnabled="{../cbFile.IsChecked}" Background="Onyx" Margin="5">
+                                       <Label Text="Debug log output file:" Fit="true"/>
+                                       <TextBox Text="{²DebugLogFilePath}"  />
+                               </HorizontalStack>
+                               <EnumSelector RadioButtonStyle="CheckBox2" Template="#Dbg.EnumSelector.template"
+                                               Background="Grey"
+                                               Caption="Recorded Events" EnumValue="{²RecordedEvents}" BitFieldExcludeMask="255" />                                   
+                               <EnumSelector RadioButtonStyle="CheckBox2" Template="#Dbg.EnumSelector.template"
+                                               Background="Onyx"
+                                               Caption="Discarded Events" EnumValue="{²DiscardedEvents}" BitFieldExcludeMask="255" />                                 
+                               <HorizontalStack Height="Fit">
+                                       <CheckBox Caption="Recording" IsChecked="{²DebugLogRecording}" Height="40" Width="60"  
+                                               Checked="{sh.Path='A 8,8,7.5,0,6.3 O 0.8,0,0,1 f O 0,0,0,0.5 G'}"
+                                               Unchecked="{sh.Path='R 0.5,0.5,15,15 f O 0,0,0,1 G'}">
+                                               <Template>
+                                                       <Border Background="Onyx" Margin="10" CornerRadius="5">
+                                                               <Shape Name="sh"  Foreground="Grey" Size="16,16" Path="R 0.5,0.5,15,15 f O 0,0,0,1 G"/> 
+                                                       </Border>
+                                               </Template>
+                                       </CheckBox>
+                                       <Menu Data="{../../../../dbgIfaceWidget.LoggerCommands}" Height="Stretched" Width="Fit">
+                                               <ItemTemplate>
+                                                       <Button Command="{}" Height="Stretched" Width="Fit"/>
+                                               </ItemTemplate>
+                                       </Menu>                                 
+                               </HorizontalStack>                                      
+                       </VerticalStack>                        
+               </TabView>
+               <Splitter Width="6" />
+               <VerticalStack>
+                       <DebugInterfaceWidget Name="dbgIfaceWidget" Height="60%" Background="Black" Focusable="true"
+                                       CrowDbgAssemblyLocation="{²CrowDbgAssemblyLocation}"
+                                       Recording="{²DebugLogRecording}"
+                                       IMLSource="{Source}"
+                                       CurrentException="{²CurrentException}"
+                                       DiscardedEvents="{DiscardedEvents}" RecordedEvents="{RecordedEvents}" DebugLogToFile="{DebugLogToFile}"/>
+                       <Splitter/>
+                       <!--<TabView>-->
+                               <VerticalStack Name="Editor" Spacing="0">
+                                       <HorizontalStack Height="Fit">
+                                               <Button Style="IcoButton" Command="{CMDNew}" />
+                                               <Button Style="IcoButton" Command="{CMDSave}" />
+                                               <Button Style="IcoButton" Command="{CMDSaveAs}" />
+                                               <Button Style="IcoButton" Command="{CMDUndo}" />
+                                               <Button Style="IcoButton" Command="{CMDRedo}" />
+                                               <!--<Button Style="IcoButton" Command="{CMDCut}" />
+                                               <Button Style="IcoButton" Command="{CMDCopy}" />
+                                               <Button Style="IcoButton" Command="{CMDPaste}" />-->
+                                               <Widget Width="Stretched" />
+                                               <Widget Background="Red" IsVisible="{DebugLogRecording}" CornerRadius="10" Width="12" Height="12"/>
+                                       </HorizontalStack>
+
+                                       <HorizontalStack>
+                                               <Editor Name="tb" Text="{Source}" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"                                            
+                                                               TextChanged="onTextChanged" KeyDown="textView_KeyDown" ContextCommands="{EditorCommands}"
+                                                               Foreground="DarkGrey" Background="White"/>
+                                                               <!--SelectionChanged="onSelectedTextChanged"-->
+                                               <ScrollBar Value="{²../tb.ScrollY}"
+                                                               LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
+                                                               CursorRatio="{../tb.ChildHeightRatio}" Maximum="{../tb.MaxScrollY}" />
+                                       </HorizontalStack>
+                                       <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
+                                                       LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
+                                                       CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
+                                       <HorizontalStack Height="Fit" Spacing="10" Background="DarkGrey">
+                                               <Widget Width="10" Height="10" Background="RoyalBlue" Visible="{IsDirty}"/>
+                                               <Label Text="{CurrentFile}" Width="Stretched"/>
+                                               <Widget Width="Stretched"/>
+                                               <Label Text="Line:" Foreground="Grey"/>
+                                               <Label Text="{../../tb.CurrentLine}"  Margin="2"/>
+                                               <Label Text="Col:" Foreground="Grey"/>
+                                               <Label Text="{../../tb.CurrentColumn}" Margin="2"/>
+                                       </HorizontalStack>
+                                       <Popper IsVisible="{ShowError}" Background="Red">
+                                               <Template>
+                                                       <CheckBox IsChecked="{²./IsPopped}" MouseEnter="{IsChecked='true'}" MouseLeave="{IsChecked='false'}">
+                                                               <Template>
+                                                                       <Label Text="{CurrentExceptionMSG}" Background="Red" Foreground="White" Width="Stretched" Margin="2"
+                                                                               Multiline="true"/>
+                                                               </Template>
+                                                       </CheckBox>
+                                               </Template>
+                                               <Label Text="{CurrentException}" Background="DarkRed" Foreground="White" Width="Stretched" Margin="2" Multiline="true"/>
+                                       </Popper>                       
+                               </VerticalStack>
+                               
+                       <!--</TabView>-->
+               </VerticalStack>
+       </HorizontalStack>
+</VerticalStack>
\ No newline at end of file
index 699e84ff10e53fac1c2a5a0035243bc612e2c03f..93c4b21739d4ec4e34f215a4069492319bb5bb55 100644 (file)
@@ -21,8 +21,8 @@ namespace ShowCase
                static void Main ()
                {
                        DbgLogger.IncludeEvents = DbgEvtType.None;
-                       DbgLogger.DiscardEvents = DbgEvtType.Focus | DbgEvtType.IFace;  
-                       DbgLogger.ConsoleOutput = false;                
+                       DbgLogger.DiscardEvents = DbgEvtType.All;
+                       DbgLogger.ConsoleOutput = !Configuration.Global.Get<bool> (nameof (DebugLogToFile));
 
                        Environment.SetEnvironmentVariable ("FONTCONFIG_PATH", @"C:\Users\Jean-Philippe\source\vcpkg\installed\x64-windows\tools\fontconfig\fonts");
 
@@ -36,7 +36,7 @@ namespace ShowCase
                public Container crowContainer;
 
                public string CurrentDir {
-                       get { return Configuration.Global.Get<string> (nameof (CurrentDir)); }
+                       get => Configuration.Global.Get<string> (nameof (CurrentDir));
                        set {
                                if (CurrentDir == value)
                                        return;
@@ -45,7 +45,7 @@ namespace ShowCase
                        }
                }
                public string CurrentFile {
-                       get { return Configuration.Global.Get<string> (nameof (CurrentFile)); }
+                       get => Configuration.Global.Get<string> (nameof (CurrentFile));
                        set {
                                if (CurrentFile == value)
                                        return;
@@ -235,14 +235,8 @@ namespace ShowCase
                                        g.DataSource = this;
                                }
                        } catch (InstantiatorException itorex) {                                
-                               Console.ForegroundColor = ConsoleColor.DarkRed;
-                               Console.WriteLine (itorex);
-                               Console.ResetColor();
-                               showError (itorex.InnerException);
+                               showError (itorex);
                        } catch (Exception ex) {
-                               Console.ForegroundColor = ConsoleColor.DarkRed;
-                               Console.WriteLine (ex);
-                               Console.ResetColor();
                                showError (ex);
                        }
                }
@@ -254,7 +248,7 @@ namespace ShowCase
                        CMDRedo.CanExecute = false;                     
                }
                void showError (Exception ex) {
-                       NotifyValueChanged ("ErrorMessage", (object)ex.Message);
+                       NotifyValueChanged ("ErrorMessage", ex);
                        NotifyValueChanged ("ShowError", true);
                }
                void hideError () {
@@ -347,26 +341,59 @@ namespace ShowCase
                        reloadChrono.Reset ();
                }
 
-               DbgEvtType recordedEvents, discardedEvents;
                public DbgEvtType RecordedEvents {
-                       get => recordedEvents;
+                       get => Configuration.Global.Get<DbgEvtType> (nameof (RecordedEvents));
                        set {
-                               if (recordedEvents == value)
-                                       return;
-                               recordedEvents = value;
-                               NotifyValueChanged(recordedEvents);
+                               if (RecordedEvents == value)
+                                       return;                         
+                               Configuration.Global.Set (nameof (RecordedEvents), value);                              
+                               if (DebugLogRecording)
+                                       DbgLogger.IncludeEvents = RecordedEvents;
+                               NotifyValueChanged(RecordedEvents);
                        }
                }
                public DbgEvtType DiscardedEvents {
-                       get => discardedEvents;
+                       get => Configuration.Global.Get<DbgEvtType> (nameof (DiscardedEvents));
                        set {
-                               if (discardedEvents == value)
+                               if (DiscardedEvents == value)
                                        return;
-                               discardedEvents = value;
-                               NotifyValueChanged(discardedEvents);
+                               Configuration.Global.Set (nameof (DiscardedEvents), value);
+                               if (DebugLogRecording)
+                                       DbgLogger.DiscardEvents = DiscardedEvents;
+                               NotifyValueChanged(DiscardedEvents);
                        }
                }
-               
+               public bool DebugLoggingEnabled => DbgLogger.IsEnabled;
+               public bool DebugLogToFile {
+                       get => !DbgLogger.ConsoleOutput;
+                       set {
+                               if (DbgLogger.ConsoleOutput != value)
+                                       return;
+                               DbgLogger.ConsoleOutput = !value;
+                               Configuration.Global.Set (nameof(DebugLogToFile), DebugLogToFile);
+                               NotifyValueChanged(DebugLogToFile);
+                       }
+               }
+               public string DebugLogFilePath {
+                       get => Configuration.Global.Get<string> (nameof (DebugLogFilePath));
+                       set {
+                               if (CurrentFile == value)
+                                       return;
+                               Configuration.Global.Set (nameof (DebugLogFilePath), value);
+                               NotifyValueChanged (DebugLogFilePath);
+                       }
+               }
+               bool debugLogRecording;
+               public bool DebugLogRecording {
+                       get => debugLogRecording;
+                       set {
+                               if (debugLogRecording == value)
+                                       return;
+                               debugLogRecording = value;
+                               NotifyValueChanged(debugLogRecording);
+                       }
+               }               
+
         public override bool OnKeyDown (Key key) {
 
             switch (key) {
@@ -374,19 +401,19 @@ namespace ShowCase
                 Load ("#ShowCase.DebugLog.crow").DataSource = this;
                 return true;
             case Key.F6:
-                               if (DbgLogger.IncludeEvents == recordedEvents) {
+                               if (DebugLogRecording) {
                                        DbgLogger.IncludeEvents = DbgEvtType.None;
                                        DbgLogger.DiscardEvents = DbgEvtType.All;
+                                       if (DebugLogToFile && !string.IsNullOrEmpty(DebugLogFilePath))
+                               DbgLogger.Save (this, DebugLogFilePath);
+                                       DebugLogRecording = false;
                                } else {
-                                       DbgLogger.IncludeEvents = recordedEvents;
-                                       DbgLogger.DiscardEvents = discardedEvents;
+                                       DbgLogger.Reset ();
+                                       DbgLogger.IncludeEvents = RecordedEvents;
+                                       DbgLogger.DiscardEvents = DiscardedEvents;
+                                       DebugLogRecording = true;
                                }
                 return true;
-            case Key.F2:
-                if (IsKeyDown (Key.LeftShift))
-                    DbgLogger.Reset ();
-                DbgLogger.Save (this);
-                return true;
             }
             return base.OnKeyDown (key);
         }
index 2bc30765a654cb920f9e31315634ad050c4ee9bf..70037e6000b0f9bba246bd8f96ad93daf3a9182b 100644 (file)
@@ -5,4 +5,7 @@
                        <LogicalName>ShowCase.%(Filename)%(Extension)</LogicalName>
                </EmbeddedResource>
        </ItemGroup>
+       <ItemGroup>
+               <ProjectReference Include="$(MSBuildThisFileDirectory)\..\..\CrowDbgShared\CrowDbgShared.csproj" />
+       </ItemGroup>
 </Project>
\ No newline at end of file
index c1ecbaac0e5ebb1f52429c44535f9c7f01235270..3d6b0bad54bae16ff520d9382e82ef29496c8722 100644 (file)
                                <Button Style="IcoButton" Command="{CMDCut}" />
                                <Button Style="IcoButton" Command="{CMDCopy}" />
                                <Button Style="IcoButton" Command="{CMDPaste}" />-->
-                               <EnumSelector RadioButtonStyle="CheckBox2" Caption="Recorded Events" EnumValue="{²RecordedEvents}">
-                                       <Template>
-                                               <Popper Caption="{./Caption}">
-                                                       <Scroller Height="50%" Width="80%" Background="Jet">
-                                                               <Wrapper Name="Content" Height="Fit" VerticalAlignment="Top" />                                                 
-                                                       </Scroller>
-                                               </Popper>
+                               <Popper IsVisible="{DebugLoggingEnabled}" Fit="true">
+                                       <Template>                                      
+                                               <CheckBox IsChecked="{²./IsPopped}">
+                                                       <Template>
+                                                               <HorizontalStack Background="Onyx" Margin="5" Spacing="10">
+                                                                       <Widget Background="Red" IsVisible="{DebugLogRecording}" CornerRadius="10" Width="12" Height="12"/>
+                                                                       <Label Text="Debug Logging" />                                                                  
+                                                               </HorizontalStack>
+                                                       </Template>
+                                               </CheckBox>
                                        </Template>
-                               </EnumSelector>
-                               <Label Text="{RecordedEvents}"/>
-                               <!--<EnumSelector EnumValue="{²DiscardedEvents}"/>-->
-                               <Widget Width="Stretched"/>
-                               <Label Text="Line:" Foreground="Grey"/>
-                               <Label Text="{../../tb.CurrentLine}"  Margin="2"/>
-                               <Label Text="Col:" Foreground="Grey"/>
-                               <Label Text="{../../tb.CurrentColumn}" Margin="2"/>
+                                       <VerticalStack Fit="true" Background="Grey" MinimumSize="300,200" Margin="5">
+                                               <CheckBox Name="cbFile" Caption="Record to file" IsChecked="{²DebugLogToFile}" Background="Onyx"/>
+                                               <HorizontalStack Height="Fit" Width="Stretched" IsEnabled="{../cbFile.IsChecked}" Background="Onyx" Margin="5">
+                                                       <Label Text="Debug log output file:" Fit="true"/>
+                                                       <TextBox Text="{²DebugLogFilePath}"  />
+                                               </HorizontalStack>
+                                               <EnumSelector RadioButtonStyle="CheckBox2" EnumValue="{²RecordedEvents}" Width="Stretched">
+                                                       <Template>
+                                                               <Popper >
+                                                                       <Template>
+                                                                               <CheckBox IsChecked="{²./IsPopped}">
+                                                                                       <Template>
+                                                                                               <HorizontalStack Background="Onyx" Margin="5" Spacing="10">
+                                                                                                       <Label Text="Recorded Events:" Width="Stretched"/>
+                                                                                                       <Label Background="SeaGreen" Text="{RecordedEvents}" Margin="3"/>
+                                                                                               </HorizontalStack>
+                                                                                       </Template>
+                                                                               </CheckBox>
+                                                                       </Template>
+                                                                       <Scroller Height="50%" Width="80%" Background="Jet">
+                                                                               <Wrapper Name="Content" Height="Fit" VerticalAlignment="Top" />                                                 
+                                                                       </Scroller>
+                                                               </Popper>
+                                                       </Template>
+                                               </EnumSelector>                                         
+                                               <EnumSelector RadioButtonStyle="CheckBox2" EnumValue="{²DiscardedEvents}" Width="Stretched">
+                                                       <Template>
+                                                               <Popper >
+                                                                       <Template>
+                                                                               <CheckBox IsChecked="{²./IsPopped}">
+                                                                                       <Template>
+                                                                                               <HorizontalStack Background="Onyx" Margin="5" Spacing="10">
+                                                                                                       <Label Text="Discarded Events:" Width="Stretched"/>
+                                                                                                       <Label Background="SeaGreen" Text="{DiscardedEvents}" Margin="3"/>
+                                                                                               </HorizontalStack>
+                                                                                       </Template>
+                                                                               </CheckBox>
+                                                                       </Template>
+                                                                       <Scroller Height="50%" Width="80%" Background="Jet">
+                                                                               <Wrapper Name="Content" Height="Fit" VerticalAlignment="Top" />                                                 
+                                                                       </Scroller>
+                                                               </Popper>
+                                                       </Template>
+                                               </EnumSelector>                                         
+                                               <Label Text="Press 'F6' to start/stop recording"/>
+                                       </VerticalStack>
+                               </Popper>
                        </HorizontalStack>
                        <HorizontalStack>
                                <Editor Name="tb" Text="{Source}" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"                                            
                        <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
                                        LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
                                        CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
-                       <HorizontalStack Height="Fit">
+                       <HorizontalStack Height="Fit" Spacing="10">
                                <Widget Width="10" Height="10" Background="RoyalBlue" Visible="{IsDirty}"/>
                                <Label Text="{CurrentFile}" Width="Stretched"/>
-                       </HorizontalStack>                      
-                       <Label Visible="{ShowError}" Text="{ErrorMessage}" Background="Red" Foreground="White" Width="Stretched" Margin="2"
-                               Multiline="true"/>
+                               <Widget Width="Stretched"/>
+                               <Label Text="Line:" Foreground="Grey"/>
+                               <Label Text="{../../tb.CurrentLine}"  Margin="2"/>
+                               <Label Text="Col:" Foreground="Grey"/>
+                               <Label Text="{../../tb.CurrentColumn}" Margin="2"/>
+                       </HorizontalStack>
+                       <Popper IsVisible="{ShowError}" Background="Red">
+                               <Template>
+                                       <CheckBox IsChecked="{²./IsPopped}" MouseEnter="{IsChecked='true'}" MouseLeave="{IsChecked='false'}">
+                                               <Template>
+                                                       <Label DataSource="{ErrorMessage}" Text="{Message}" Background="Red" Foreground="White" Width="Stretched" Margin="2"
+                                                               Multiline="true"/>
+                                               </Template>
+                                       </CheckBox>
+                               </Template>
+                               <Label Text="{ErrorMessage}" Background="DarkRed" Foreground="White" Width="Stretched" Margin="2" Multiline="true"/>
+                       </Popper>                       
                </VerticalStack>
        </VerticalStack>
 </HorizontalStack>
index 79e018d0e87ba8fd564b90981f4d2e1d7e1fbd82..59244f1b574d76281e05d4adcd83fe967bdb50d6 100644 (file)
@@ -29,9 +29,16 @@ namespace Crow
                }
 
                static SampleBase () {
-                       System.Runtime.Loader.AssemblyLoadContext.Default.ResolvingUnmanagedDll+=resolveUnmanaged;
+                       System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll+=resolveUnmanaged;
                }
 #endif
+               public SampleBase (IntPtr hWin) : base (800,600,hWin){}
+               public SampleBase () : base (800,600,true,true){}
+               public SampleBase (int width, int height, bool startUIThread, bool createSurface) :
+                       base (width, height, startUIThread, createSurface){
+                               
+                       }
+
         public Version CrowVersion => Assembly.GetAssembly (typeof (Widget)).GetName ().Version;
 
         #region Test values for Binding
index 548aab396e06aad5f6c68603fc3a9e5fb8a87665..e51cf308ae439c161154f990dd7a7edc8d71cd77 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
-<Window Caption="Vertical Wrapper" Width="50%" Height="50%">
-       <Wrapper Orientation="Vertical" Height="Fit" Width="90%" Margin="5" Background="MediumSeaGreen" Spacing="1" >
+<Window Caption="Vertical Wrapper" Width="50%" Height="90%">
+       <Wrapper Orientation="Vertical" Height="Stretched" Width="Fit" Margin="5" Background="MediumSeaGreen" Spacing="1" >
                <Widget Width="50" Height="50" Background="SeaGreen"/>
                <Widget Width="50" Height="50" Background="SeaGreen"/>
                <Widget Width="50" Height="50" Background="SeaGreen"/>
diff --git a/Samples/common/ui/Interfaces/cbRecording.crow b/Samples/common/ui/Interfaces/cbRecording.crow
new file mode 100644 (file)
index 0000000..4834741
--- /dev/null
@@ -0,0 +1,9 @@
+<CheckBox Foreground="Jet" Background="Jet" Height="40" Width="60"  
+       Unchecked="{sh.Path='A 8,8,7.5,0,6.3 O 0.8,0,0,1 f O 0,0,0,0.5 G'};{Background=.Foreground}"
+       Checked="{sh.Path='R 0.5,0.5,15,15 f O 0,0,0,1 G'};{Background=DimGrey}">
+       <Template>
+               <Border Background="{./Background}" Margin="10" CornerRadius="5">
+                       <Shape Name="sh"  Foreground="Grey" Size="16,16" Path="A 8,8,7.5,0,6.3 O 0.8,0,0,1 f O 0,0,0,0.5 G"/>  
+               </Border>
+       </Template>
+</CheckBox>
\ No newline at end of file
diff --git a/Samples/common/ui/Interfaces/log.xml b/Samples/common/ui/Interfaces/log.xml
deleted file mode 100644 (file)
index 882028d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<Container Name="topContainer" HorizontalAlignment="Center" VerticalAlignment="Top"
-       Margin="2"
-       Width="600" Height="-1">
-       <Border Margin="2" BorderWidth="1" Background="0,6;0,6;0,6;0,6" Height="-1">
-               <Group Width="0" Name="logs">
-                       <VerticalStack Name="VerticalStack" Width="0" Focusable="False">
-                               <Label Name="line1" Width="0" Text="Line1" Margin="0"/>
-                               <Label Name="line2" Width="0" Text="Line2" Margin="0"/>
-                               <Label Name="line3" Width="0" Text="Line3" Margin="0"/>
-                               <Label Name="line4" Width="0" Text="Line4" Margin="0"/>
-                       </VerticalStack>
-                       <Button Name="btOk" Background="Grey" Fit="True"
-                               HorizontalAlignment="Right" VerticalAlignment="Bottom"
-                               MouseClick="BtOk_MouseClick">
-                               <Label Text="Ok" Margin="3" Foreground="White" />
-                       </Button>
-               </Group>
-       </Border>
-</Container>
-
diff --git a/Samples/common/ui/Interfaces/menutest.crow b/Samples/common/ui/Interfaces/menutest.crow
new file mode 100644 (file)
index 0000000..6498f64
--- /dev/null
@@ -0,0 +1,31 @@
+<Menu Data="{Commands}">
+       <ItemTemplate>
+<MenuItem Command="{}" Width="150" PopWidth="120" IsEnabled="{CanExecute}">
+                       <Template>
+                               <Popper Font="{./Font}" Caption="{./Caption}"  Background="{./Background}" PopDirection="{./PopDirection}"
+                                       Foreground = "{./Foreground}" CanPop="{./HasChildren}" MouseDown="./onMI_Click"
+                                       IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
+                                       <Template>
+                                               <Border Name="border1"
+                                                               CornerRadius="0"
+                                                               MouseEnter="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black}"
+                                                               MouseLeave="{Foreground=Transparent}"
+                                                               MouseDown="{Foreground=vgradient|0:Black|0.05:Grey|0.85:Grey|1:White}"
+                                                               MouseUp="{Foreground=vgradient|0:White|0.2:Grey|0.9:Grey|1:Black}"
+                                                               MinimumSize = "60,0"
+                                                               Foreground="Transparent"
+                                                               Background="{./Background}">
+                                                               <Label Text="{./Caption}"
+                                                                       Foreground="{./Foreground}"
+                                                                       Margin="1" HorizontalAlignment="Left"
+                                                                       Font="{./Font}" />
+                                               </Border>
+                                       </Template>
+                                       <Border Foreground="DimGrey" Width="{../PopWidth}" Height="{../PopHeight}" Background="DimGrey">
+                                               <VerticalStack Name="ItemsContainer"/>
+                                       </Border>
+                               </Popper>
+                       </Template>
+               </MenuItem>
+       </ItemTemplate>
+</Menu>
\ No newline at end of file