-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
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
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}"
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
{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
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}
{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}
</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'))">
</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" />
Button, CheckBox, RadioButton, ComboBox, Expandable,
MessageBox, Popper, Slider, Spinner, TextBox {
//Focusable = "true";
+ Foreground="${ControlForeground}";
Height = "Fit";
Background = "${ControlBackground}";
CornerRadius = "${ControlCornerRadius}";
Control {
Margin="${ControlInsideMargin}";
- Spacing="3";
+ Spacing="3";
+ //Foreground = "${ControlForeground}";
+ //MouseEnter = "{Foreground=${ControlCaptionHoverColor}}";
+ //MouseLeave = "{Foreground=${ControlForeground}}";
}
ControlBorder {
BorderWidth = "${ControlBorderWidth}";
Margin = "${ControlInsideMargin}";
}
ControlCaption {
- Foreground = "${ControlForeground}";
- MouseEnter = "{Foreground=${ControlCaptionHoverColor}}";
- MouseLeave = "{Foreground=${ControlForeground}}";
+ //Foreground = "${ControlForeground}";
+ //MouseEnter = "{Foreground=${ControlCaptionHoverColor}}";
+ //MouseLeave = "{Foreground=${ControlForeground}}";
}
ControlEditableText {
Foreground = "${ControlForeground}";
<?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>
/// <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)
#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)
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>
/// <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();
-// 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)
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]),
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
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 {
+++ /dev/null
-// 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;
-
- }
- }
- }*/
-}
-
+++ /dev/null
-// 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;
- }
- }*/
-}
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
using System.Collections.Generic;
using System.Linq;
-namespace Crow
+namespace Crow.DebugLogger
{
/// <summary>
/// Recorded Widget instance data.
-// 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 ();
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) {
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;
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;
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
}*/
[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;
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;
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);
+ }
+ }
+ }
}
}
}
} 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
Cursor currentCursor;
bool ownWindow;
+ public IntPtr WindowHandle => hWin;
+
protected void registerGlfwCallbacks ()
{
windows.Add (hWin, this);
/// <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
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);
}
}
}
Monitor.Exit (LayoutMutex);
return;
}
- DbgLogger.StartEvent (DbgEvtType.Layouting);
+ DbgLogger.StartEvent (DbgEvtType.ProcessLayouting);
PerformanceMeasure.Begin (PerformanceMeasure.Kind.Layouting);
DiscardQueue = new Queue<LayoutingQueueItem> (LayoutingQueue.Count);
LayoutingQueue = DiscardQueue;
PerformanceMeasure.End (PerformanceMeasure.Kind.Layouting);
- DbgLogger.EndEvent (DbgEvtType.Layouting, true);
+ DbgLogger.EndEvent (DbgEvtType.ProcessLayouting, true);
Monitor.Exit (LayoutMutex);
DiscardQueue = null;
if (ClippingQueue.Count == 0)
return;
- DbgLogger.StartEvent (DbgEvtType.Clipping);
+ DbgLogger.StartEvent (DbgEvtType.ClippingRegistration);
PerformanceMeasure.Begin (PerformanceMeasure.Kind.Clipping);
Widget g = null;
}
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;
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
}
void toolTipThreadFunc ()
{
- while (true) {
+ while (true) {
if (tooltipTimer.ElapsedMilliseconds > TOOLTIP_DELAY) {
if (!tooltipVisible) {
Widget g = _hoverWidget;
}
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)
} else
ttc.Top = 0;
}*/
+
}
#endregion
{
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)
{
public override void onMouseClick (object sender, MouseButtonEventArgs e)
{
- command?.Execute ();
+ command?.Execute (this);
e.Handled = true;
base.onMouseClick (sender, e);
}
#region private fields
Enum enumValue;
+ UInt32 bitFieldExcludeMask;
Type enumType;
bool enumTypeIsBitsfield;
string rbStyle, iconsPrefix, iconsExtension;
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;
} 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);
}
}
#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);
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) {
}
}
IsDirty = true;
+ DbgLogger.EndEvent(DbgEvtType.GOComputeChildrenPositions);
}
Widget stretchedGO = null;
public override bool UpdateLayout (LayoutingType layoutType) {
}
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) {
} else if (stretchedGO != go) {
go.Slot.Width = 0;
go.Width = Measure.Fit;
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
return;
}
} else if (stretchedGO == go) {
this.RegisterForLayouting (LayoutingType.Width);
this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
return;
}
break;
} else if (stretchedGO != go) {
go.Slot.Height = 0;
go.Height = Measure.Fit;
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
return;
}
} else if (stretchedGO == go) {
this.RegisterForLayouting (LayoutingType.Height);
this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
return;
}
break;
}
base.OnChildLayoutChanges (sender, arg);
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
}
#endregion
childrenRWLock.EnterReadLock ();
foreach (Widget c in Children) {
- if (!c.Visible)
+ if (!c.IsVisible)
continue;
if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
continue;
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;
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;
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(){
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)
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)
public override void onMouseClick (object sender, MouseButtonEventArgs e)
{
if (command != null) {
- command.Execute ();
+ command.Execute (this);
closeMenu ();
}
if (hasClick)
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);
/// <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)
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
{
Value += SmallIncrement;
}
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ }
}
}
}
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;
}
}
bool allowDrop;
string allowedDropTypes;
string tooltip;
- IList<Command> contextCommands;
+ CommandGroup contextCommands;
#endregion
#region public fields
#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>
/// </summary>
[DesignCategory ("Behavior")][DefaultValue(true)]
public virtual bool CacheEnabled {
- get { return cacheEnabled; }
+ get => cacheEnabled;
set {
if (cacheEnabled == value)
return;
/// <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;
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
return;
isVisible = value;
-
+
if (!isVisible)
unshownPostActions ();
RegisterForLayouting (LayoutingType.Sizing);
+
+ /*if (isVisible){
+ IsDirty = true;
+ RegisterForLayouting(LayoutingType.Sizing);
+ } else {
+ unshownPostActions ();
+ }*/
+
NotifyValueChangedAuto (isVisible);
}
}
}
[DesignCategory ("Divers")]
- public IList<Command> ContextCommands {
- get { return contextCommands; }
+ public CommandGroup ContextCommands {
+ get => contextCommands;
set {
if (contextCommands == value)
return;
/// <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);
[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)
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);
/// 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
ctx.Translate (rb.X, rb.Y);
onDraw (ctx);
- if (!IsEnabled)
- paintDisabled (ctx, Slot);
ctx.Restore ();
+
+ if (!IsEnabled)
+ paintDisabled (ctx, rb);
+
}
LastPaintedSlot = Slot;
}
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
/// 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;
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;*/
+
}
}
}
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;
} 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;
--- /dev/null
+<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>
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using 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();
+}
+
<CrowVersion>0.9.4</CrowVersion>
<CrowPackageVersion>$(CrowVersion)-beta</CrowPackageVersion>
<CrowStbSharp>true</CrowStbSharp>
+ <CrowDebugLogEnabled>false</CrowDebugLogEnabled>
+ <GlfwSharpVersion>0.2.11-beta</GlfwSharpVersion>
</PropertyGroup>
</Project>
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;
+++ /dev/null
-using System;
-
-namespace ControlLib
-{
- public class Class1
- {
- }
-}
+++ /dev/null
-<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>
--- /dev/null
+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
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netcoreapp3.1</TargetFramework>
+ </PropertyGroup>
+
+</Project>
--- /dev/null
+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");
+ }
+ }
+}
+++ /dev/null
-// 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
+++ /dev/null
-// 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);
- }
- }
-}
-
-
<?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
+++ /dev/null
-// 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;
- }
- }
-
- }
-}
-
--- /dev/null
+// 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
--- /dev/null
+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);
+ }
+ }
+ }
+}
+
+
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+
+
+using Crow;
+
+namespace DebugLogAnalyzer {
+ public static class Extensions {
+
+ public static CommandGroup GetCommands (this System.IO.DirectoryInfo di) =>
+ new CommandGroup(
+ new Command ("Set as root", ()=> {Program.CurrentProgramInstance.CurrentDir = di.FullName;}));
+ public static CommandGroup GetCommands (this System.IO.FileInfo fi) =>
+ new CommandGroup(
+ new Command ("Delete", (sender0) => {
+ MessageBox.ShowModal (Program.CurrentProgramInstance, MessageBox.Type.YesNo, $"Delete {fi.Name}?").Yes += (sender, e) => {
+ System.IO.File.Delete(fi.FullName);
+ Widget listContainer = ((sender0 as Widget).LogicalParent as Widget).DataSource as Widget;
+ (listContainer.Parent as Group).RemoveChild(listContainer);
+ };
+ })
+ );
+
+ }
+}
\ No newline at end of file
--- /dev/null
+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);
+ }
+ }
+}
+
--- /dev/null
+<?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
<?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"
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>
</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"/>
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+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
<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/>
--- /dev/null
+<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>
+
--- /dev/null
+<?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
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");
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;
}
}
public string CurrentFile {
- get { return Configuration.Global.Get<string> (nameof (CurrentFile)); }
+ get => Configuration.Global.Get<string> (nameof (CurrentFile));
set {
if (CurrentFile == value)
return;
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);
}
}
CMDRedo.CanExecute = false;
}
void showError (Exception ex) {
- NotifyValueChanged ("ErrorMessage", (object)ex.Message);
+ NotifyValueChanged ("ErrorMessage", ex);
NotifyValueChanged ("ShowError", true);
}
void hideError () {
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) {
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);
}
<LogicalName>ShowCase.%(Filename)%(Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(MSBuildThisFileDirectory)\..\..\CrowDbgShared\CrowDbgShared.csproj" />
+ </ItemGroup>
</Project>
\ No newline at end of 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>
}
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
<?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"/>
--- /dev/null
+<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
+++ /dev/null
-<?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>
-
--- /dev/null
+<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