EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfTests", "Samples\PerfTests\PerfTests.csproj", "{18EBB41F-815E-4BF5-B80F-C9E2FAB2993A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DebugLogAnalyzer", "Samples\DebugLogAnalyzer\DebugLogAnalyzer.csproj", "{7915538F-B2B1-414C-95A3-1FC58E3286B9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
{18EBB41F-815E-4BF5-B80F-C9E2FAB2993A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18EBB41F-815E-4BF5-B80F-C9E2FAB2993A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18EBB41F-815E-4BF5-B80F-C9E2FAB2993A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7915538F-B2B1-414C-95A3-1FC58E3286B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7915538F-B2B1-414C-95A3-1FC58E3286B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7915538F-B2B1-414C-95A3-1FC58E3286B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7915538F-B2B1-414C-95A3-1FC58E3286B9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
{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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {00D4E149-7131-49F4-BAAD-559AA961A78E}
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
- <DefineConstants>$(DefineConstants);DEBUG_LOG;DEBUG;TRACE;DEBUG_LAYOUTING;DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
+ <DefineConstants>$(DefineConstants);_DEBUG_LOG;DEBUG;TRACE;DEBUG_LAYOUTING;DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE</DefineConstants>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
IconMargin = "1";
ToggleIconSize = "16";
+TooltipBackground = "Khaki";
+TooltipForeground = "DimGrey";
+TooltipMargin = "3";
+
WindowBackgroundColor = "DarkGrey";
WindowBorderColor = "Grey";
WindowBorderWidth = "1";
Height = "Fit";
Width = "Stretched";
VerticalAlignment = "Top";
- SelectionBackground = "${ControlHighlight}";
- SelectionColoring = "false";
+ //SelectionBackground = "${ControlHighlight}";
+ //SelectionColoring = "false";
}
MenuItem {
Caption = "MenuItem";
MouseEnter = "{Background=${ControlHighlight}}";
MouseLeave = "{Background=${MenuBackground}}";
//SelectionBackground = "${ControlHighlight}";
- SelectionBackground = "Transparent";
- SelectionColoring = "false";
+ //SelectionBackground = "Transparent";
+ //SelectionColoring = "false";
+}
+ListItem {
+ //Selected = "{Background=${ControlHighlight}}";
+ //Unselected = "{Background=Transparent}";
+ //Margin="1";
}
MessageBox {
Background = "0.1,0.1,0.2,0.85";
<?xml version="1.0" encoding="UTF-8" ?>
<MenuItem MinimumSize="20,20" Height="Fit" Width="160" Caption="Context Menu" Data="{ContextCommands}" Orientation="Vertical"
- IsOpened ="true" Visible="{/IsOpened}" SelectionBackground="Transparent"
- Background="Red">
+ IsOpened ="true" Visible="{/IsOpened}" Background="Red">
<Template>
<HorizontalStack>
<Border Background="DimGrey" Foreground="DimGrey" CornerRadius="5">
</HorizontalStack>
</Template>
<ItemTemplate>
- <MenuItem Command="{}" Width="150" PopWidth="120" SelectionBackground="Transparent" IsEnabled="{CanExecute}">
+ <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"
<?xml version="1.0"?>
-<Container Height="Fit" Margin="0" Focusable="true"
- HorizontalAlignment="Left"
- MouseEnter="{Background=SteelBlue}"
- MouseLeave="{Background=Transparent}">
+<ListItem Height="Fit" Margin="0" Focusable="true" HorizontalAlignment="Left"
+ Selected = "{Background=${ControlHighlight}}"
+ Unselected = "{Background=Transparent}">
<Label Text="{}" HorizontalAlignment="Left" />
-</Container>
+</ListItem>
<TreeView IsRoot="true" Name="treeView" Data="{./FileSystemEntries}" Background="{./Background}"
SelectedItemChanged="./onSelectedItemChanged">
<ItemTemplate DataType="System.IO.FileInfo">
- <Border CornerRadius="2" Margin="0" Focusable="true" Height="Fit" Width="Stretched" Foreground="Transparent"
- MouseEnter="{Foreground=DimGrey}"
- MouseLeave="{Foreground=Transparent}">
+ <ListItem CornerRadius="2" Margin="0" Height="Fit" Width="Stretched"
+ Selected="{Background=${ControlHighlight}}"
+ Unselected="{Background=Transparent}">
<HorizontalStack>
- <Image Margin="1" Width="14" Height="14"
- Path="#Crow.Icons.file.svg"/>
+ <Image Margin="1" Width="14" Height="14" Path="#Crow.Icons.file.svg"/>
<Label Text="{Name}" Width="Stretched"/>
</HorizontalStack>
- </Border>
+ </ListItem>
</ItemTemplate>
<ItemTemplate DataType="System.IO.DirectoryInfo" Data="GetFileSystemInfosOrdered">
- <Expandable Caption="{Name}" MouseDoubleClick="/onClickForExpand">
- <Template>
- <VerticalStack>
- <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
- Foreground="Transparent"
- MouseEnter="{Foreground=DimGrey}"
- MouseLeave="{Foreground=Transparent}">
- <HorizontalStack 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
+ 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>
<Widget Height="16" Background="Red"/>
</ItemTemplate>
<ItemTemplate DataType="System.IO.FileInfo">
- <HorizontalStack Focusable="true" Height="Fit">
- <Image Margin="2" Width="16" Height="16"
- Path="#Crow.Icons.file.svg"/>
- <Label Text="{Name}" Width="Stretched"
- MouseEnter="{Background=RoyalBlue}"
- MouseLeave="{Background=Transparent}"/>
- </HorizontalStack>
+ <ListItem Height="Fit"
+ Selected = "{Background=${ControlHighlight}}"
+ Unselected = "{Background=Transparent}">
+ <HorizontalStack>
+ <Image Margin="2" Width="16" Height="16" Path="#Crow.Icons.file.svg"/>
+ <Label Text="{Name}" Width="Stretched"/>
+ </HorizontalStack>
+ </ListItem>
</ItemTemplate>
<ItemTemplate DataType="System.IO.DirectoryInfo">
- <Border Foreground="Transparent" Focusable="true" Height="Fit">
- <HorizontalStack
- MouseEnter="{Background=RoyalBlue}"
- MouseLeave="{Background=Transparent}">
- <Image Margin="2" Width="16" Height="16"
- Path="#Crow.Icons.folder.svg"/>
+ <ListItem Height="Fit"
+ Selected = "{Background=${ControlHighlight}}"
+ Unselected = "{Background=Transparent}">
+ <HorizontalStack>
+ <Image Margin="2" Width="16" Height="16" Path="#Crow.Icons.folder.svg"/>
<Label Text="{Name}" Width="Stretched"/>
<Label Text="{LastAccessTime}" />
</HorizontalStack>
- </Border>
+ </ListItem>
</ItemTemplate>
<?xml version="1.0"?>
-<Container Background="{./Background}">
- <Group>
+<Container Background="{./Background}" >
+ <Group CacheEnabled="true">
<VerticalStack Spacing="0">
<Widget Height="6"/>
<Border CornerRadius="{./CornerRadius}" BorderWidth="1" Margin="10" Foreground="{./Foreground}">
<Container Name="Content" Margin="0" MinimumSize="70,10"/>
</Border>
</VerticalStack>
- <Label Text="{./Caption}" VerticalAlignment="Top" Left="8" Background="Clear" Margin="1"/>
+ <Label Text="{./Caption}" VerticalAlignment="Top" Left="8" Background="Clear" Margin="1" CacheEnabled="true"/>
</Group>
</Container>
\ No newline at end of file
<?xml version="1.0"?>
-<Popper Font="{./Font}" Caption="{./Caption}" Background="{./Background}" PopDirection="{./PopDirection}"
- Foreground = "{./Foreground}" CanPop="{./HasChildren}"
- IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
- <Template>
- <CheckBox IsChecked="{²./IsPopped}" Caption="{./Caption}" Background="{./Background}" Foreground="{./Foreground}">
- <Template>
- <Border Name="border1"
- MinimumSize = "60,0"
- Foreground="Transparent"
- Background="{./Background}">
- <Label Text="{./Caption}"
- Foreground="{./Foreground}"
- Margin="2" HorizontalAlignment="Left"
- Font="{./Font}" />
- </Border>
- </Template>
- </CheckBox>
- </Template>
- <Border Foreground="DimGrey" Width="{../PopWidth}" Height="{../PopHeight}" Background="${MenuBackground}">
- <VerticalStack Name="ItemsContainer"/>
- </Border>
-</Popper>
\ No newline at end of file
+<ListItem>
+ <Popper Font="{./Font}" Caption="{./Caption}" Background="{./Background}" PopDirection="{./PopDirection}"
+ Foreground = "{./Foreground}" CanPop="{./HasChildren}"
+ IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
+ <Template>
+ <CheckBox IsChecked="{²./IsPopped}" Caption="{./Caption}" Background="{./Background}" Foreground="{./Foreground}">
+ <Template>
+ <Border Name="border1"
+ MinimumSize = "60,0"
+ Foreground="Transparent"
+ Background="{./Background}">
+ <Label Text="{./Caption}"
+ Foreground="{./Foreground}"
+ Margin="2" HorizontalAlignment="Left"
+ Font="{./Font}" />
+ </Border>
+ </Template>
+ </CheckBox>
+ </Template>
+ <Border Foreground="DimGrey" Width="{../PopWidth}" Height="{../PopHeight}" Background="${MenuBackground}">
+ <VerticalStack Name="ItemsContainer" Width="Stretched" />
+ </Border>
+ </Popper>
+</ListItem>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
-<Border Fit="true" Foreground="DimGrey" Background="Khaki">
- <Label Margin="3" Foreground="DimGrey" Multiline="true" Text="{Tooltip}"/>
+<Border Fit="true" Foreground="${TooltipForeground}" Background="${TooltipBackground}">
+ <Label Margin="${TooltipMargin}" Foreground="${TooltipForeground}" Multiline="true" Text="{Tooltip}"/>
</Border>
--- /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.Threading;
+
+namespace Crow
+{
+ public class DbgEvent : DbgEventSource
+ {
+ public long begin, end;
+ public int threadId;
+ public DbgEvtType type;
+ public DbgEvent parentEvent;
+ public bool HasChildEvents => Events != null && Events.Count > 0;
+ public override long Duration => end - begin;
+ 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)
+ Events = new List<DbgEvent> () { evt };
+ else
+ Events.Add (evt);
+ evt.parentEvent = this;
+ }
+
+ public DbgEvent () { }
+ public DbgEvent (long timeStamp, DbgEvtType evt)
+ {
+ type = evt;
+ begin = timeStamp;
+ end = timeStamp;
+ threadId = Thread.CurrentThread.ManagedThreadId;
+ }
+
+ public static DbgEvent Parse (string str)
+ {
+ if (str == null)
+ return null;
+ string [] tmp = str.Trim ().Split (';');
+
+ DbgEvtType evtType = (DbgEvtType)Enum.Parse (typeof (DbgEvtType), tmp [3]);
+
+ if (evtType.HasFlag (DbgEvtType.Widget)) {
+ if (evtType.HasFlag (DbgEvtType.Layouting))
+ return new DbgLayoutEvent () {
+ begin = long.Parse (tmp [0]),
+ end = long.Parse (tmp [1]),
+ threadId = int.Parse (tmp [2]),
+ type = evtType,
+ InstanceIndex = int.Parse (tmp [4]),
+ layouting = (LayoutingType)Enum.Parse (typeof (LayoutingType), tmp [5]),
+ result = evtType == DbgEvtType.GOProcessLayouting ?
+ (LayoutingQueueItem.Result)Enum.Parse (typeof (LayoutingQueueItem.Result), tmp [6])
+ : LayoutingQueueItem.Result.Unknown,
+ 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 new DbgEvent () {
+ begin = long.Parse (tmp [0]),
+ end = long.Parse (tmp [1]),
+ threadId = int.Parse (tmp [2]),
+ type = evtType,
+ };
+ }
+ public override string ToString ()
+ => $"{begin};{end};{threadId};{type}";
+
+ }
+ public class DbgWidgetEvent : DbgEvent
+ {
+ public int 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.Crimson;
+ }
+ if (type.HasFlag (DbgEvtType.Lock))
+ return Colors.DarkMagenta;
+ return Colors.White;
+ }
+ }
+ public override bool IsWidgetEvent => true;
+ public DbgWidgetEvent () { }
+#if DEBUG_LOG
+ public DbgWidgetEvent (long timeStamp, DbgEvtType evt, Widget w) : base (timeStamp, evt)
+ {
+ InstanceIndex = w.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;
+ }
+#endif
+ public override string ToString ()
+ => $"{base.ToString ()};{layouting};{result};{OldSlot};{NewSlot}";
+ }
+}
\ 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.Runtime.CompilerServices;
+
+namespace Crow
+{
+ //base class for both events and widgetRecord having an event list
+ public abstract class DbgEventSource : IValueChange
+ {
+ 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 {
+ get {
+ if (Events == null)
+ return 0;
+ long tot = 0;
+ foreach (DbgEvent e in Events)
+ tot += e.Duration;
+ return tot;
+ }
+ }
+
+
+ }
+}
\ 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 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;
+#if DEBUG_LOG
+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;
+ }
+ }*/
+}
+#endif
\ 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.Linq;
+
+namespace Crow
+{
+ /// <summary>
+ /// Recorded Widget instance data.
+ /// </summary>
+ public class DbgWidgetRecord : DbgEventSource
+ {
+ public DbgWidgetRecord ()
+ {
+ Events = new List<DbgEvent> ();
+ }
+ public int listIndex;//prevent doing an IndexOf on list for each event to know y pos on screen
+ //public int instanceNum;//class instantiation order, used to bind events to objs
+ public string name;
+ //0 is the main graphic tree, for other obj tree not added to main tree, it range from 1->n
+ //useful to track events for obj shown later, not on start
+ public int treeIndex;
+ public int yIndex;//index in parenting, the whole main graphic tree is one continuous suite
+ public int xLevel;//depth
+ public String Width;
+ public String Height;
+
+ public static DbgWidgetRecord Parse (string str)
+ {
+ DbgWidgetRecord g = new DbgWidgetRecord ();
+ if (str == null)
+ return null;
+ string [] tmp = str.Trim ().Split (';');
+ g.name = tmp [0];
+ g.yIndex = int.Parse (tmp [1]);
+ g.xLevel = int.Parse (tmp [2]);
+ g.Width = tmp [3];
+ g.Height = tmp [4];
+ return g;
+ }
+
+ public List<DbgWidgetEvent> RootEvents => Events.OfType<DbgWidgetEvent> ().Where (
+ e => (e.parentEvent != null && !e.parentEvent.type.HasFlag (DbgEvtType.Widget)) ||
+ (e.parentEvent is DbgWidgetEvent w && w.InstanceIndex != e.InstanceIndex)).ToList();
+
+ public override string ToString () => $"{name}";
+ }
+}
\ 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 Crow.Cairo;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+
+
+namespace Crow
+{
+ [Flags]
+ public enum DbgEvtType {
+ ////9 nth bit set for iface event
+ IFace = 0x10000,
+ Focus = 0x20000,
+ Override = 0x40000,
+ 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,
+
+ HoverWidget = Focus | 0x01,
+ FocusedWidget = Focus | 0x02,
+ ActiveWidget = Focus | 0x03,
+
+ //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 | 0x10,
+ GORegisterForRedraw = Widget | 0x11,
+
+ 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
+ }
+#if DEBUG_LOG
+ public static class DbgLogger
+ {
+ public static DbgEvtType IncludeEvents = DbgEvtType.All;
+ public static DbgEvtType DiscardEvents = DbgEvtType.Focus;
+
+ static bool logevt (DbgEvtType evtType)
+ => (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) != 0;
+
+
+ static object logMutex = new object ();
+ static Stopwatch chrono = Stopwatch.StartNew ();
+ static List<DbgEvent> events = new List<DbgEvent> ();
+ //started events per thread
+ static Dictionary<int, Stack<DbgEvent>> startedEvents = new Dictionary<int, Stack<DbgEvent>> ();
+ //helper for fetching current event list to add next event to while recording
+ static List<DbgEvent> curEventList {
+ get {
+ if (startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId)) {
+ if (startedEvents [Thread.CurrentThread.ManagedThreadId].Count == 0)
+ return events;
+ DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Peek ();
+ if (e.Events == null)
+ e.Events = new List<DbgEvent> ();
+ return e.Events;
+ }
+ return events;
+ }
+ }
+
+ public static DbgEvent StartEvent (DbgEvtType evtType, params object[] data)
+ {
+ if (!logevt (evtType))
+ return null;
+ lock (logMutex) {
+ chrono.Stop ();
+ DbgEvent evt = addEventInternal (evtType, data);
+ if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
+ startedEvents [Thread.CurrentThread.ManagedThreadId] = new Stack<DbgEvent> ();
+ startedEvents [Thread.CurrentThread.ManagedThreadId].Push (evt);
+ chrono.Start ();
+ return evt;
+ }
+ }
+ public static DbgEvent EndEvent (DbgEvtType evtType, bool discardIfNoChildEvents = false)
+ {
+ if (!logevt (evtType))
+ return null;
+
+ lock (logMutex) {
+ chrono.Stop ();
+ if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
+ throw new Exception ("Current thread has no event started");
+ DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
+ if (e.type != evtType)
+ throw new Exception ($"Begin/end event logging mismatch: {e.type}/{evtType}");
+ if (discardIfNoChildEvents && (e.Events == null || e.Events.Count == 0))
+ curEventList.Remove (e);
+ else
+ e.end = chrono.ElapsedTicks;
+ chrono.Start ();
+ return e;
+ }
+ }
+ /// <summary>
+ /// End event by reference to cancel unended events on failure
+ /// </summary>
+ public static DbgEvent EndEvent (DbgEvtType evtType, DbgEvent evt)
+ {
+ if (!logevt (evtType))
+ return null;
+
+ lock (logMutex) {
+ chrono.Stop ();
+ if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
+ throw new Exception ("Current thread has no event started");
+ DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
+ while (e != evt)
+ e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
+ e.end = chrono.ElapsedTicks;
+ chrono.Start ();
+ return e;
+ }
+ }
+
+ public static DbgEvent AddEvent (DbgEvtType evtType, params object [] data) {
+ if (!logevt (evtType))
+ return null;
+
+ lock (logMutex) {
+ chrono.Stop ();
+ DbgEvent evt = addEventInternal (evtType, data);
+ chrono.Start ();
+ return evt;
+ }
+ }
+
+ static DbgEvent addEventInternal (DbgEvtType evtType, params object [] data)
+ {
+ DbgEvent evt = null;
+ 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);
+ else if (data [0] is LayoutingQueueItem lqi)
+ evt = new DbgLayoutEvent (chrono.ElapsedTicks, evtType, lqi);
+ else
+ evt = new DbgEvent (chrono.ElapsedTicks, evtType);
+
+ curEventList.Add (evt);
+ return evt;
+ }
+
+ static void parseTree (Widget go, int level = 0, int y = 1) {
+ if (go == null)
+ return;
+
+ go.yIndex = y;
+ go.xLevel = level;
+
+ Group gr = go as Group;
+ if (gr != null) {
+ foreach (Widget g in gr.Children)
+ parseTree (g, level + 1, y + 1);
+
+ } else {
+ PrivateContainer pc = go as PrivateContainer;
+ if (pc != null)
+ parseTree (pc.getTemplateRoot, level + 1, y + 1);
+ }
+ }
+ /// <summary>
+ /// Clear all recorded events from logger.
+ /// </summary>
+ public static void Reset ()
+ {
+ lock (logMutex) {
+ startedEvents.Clear ();
+ events.Clear ();
+ chrono.Restart ();
+ }
+ }
+ /// <summary>
+ /// Save recorded events to disk
+ /// </summary>
+ /// <param name="iface">Iface.</param>
+ public static void save(Interface iface, string dbgLogFilePath = "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}");
+ }
+ }
+ s.WriteLine ("[Events]");
+ saveEventList (s, events);
+ }
+ }
+ }
+
+ 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
+}
+
+
--- /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.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Crow
+{
+ public static class Logger
+ {
+ [Flags]
+ public enum LogType
+ {
+ Info = 1,
+ Warning = 2,
+ Error = 4,
+ }
+
+ public static LogType CurrentLogLevel = LogType.Error;
+
+ static Stopwatch timer = Stopwatch.StartNew ();
+
+
+ public static void LOG(string message = null, [CallerMemberName] string caller = null) {
+ Console.WriteLine ($"{timer.ElapsedMilliseconds, 10} {caller}: {message}");
+ }
+ }
+}
-//
-// SelectionChangeEventArgs.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
{
public object NewValue;
-
public SelectionChangeEventArgs (object _newValue) : base()
{
NewValue = _newValue;
--- /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;
+namespace Crow
+{
+ public class TreeExpandEventArg : EventArgs
+ {
+ /// <summary>
+ /// Source of the expand/collapse event
+ /// </summary>
+ public Expandable SourceWidget;
+ public TreeExpandEventArg (Expandable sourceWidget)
+ {
+
+ }
+ }
+}
-//
-// SolidColor.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
using System.Collections.Generic;
if (t != null) {
knownGOTypes.Add (typeName, t);
return t;
- }
+ }
+
+ foreach (Type expT in Assembly.GetEntryAssembly ().GetExportedTypes ()) {
+ if (expT.Name != typeName)
+ continue;
+ knownGOTypes.Add (typeName, expT);
+ return expT;
+ }
+
foreach (Assembly a in Interface.crowAssemblies) {
foreach (Type expT in a.GetExportedTypes ()) {
if (expT.Name != typeName)
protected void initTooltip ()
{
- ToolTipContainer = CreateInstance ("#Crow.Tooltip.template");
Thread t = new Thread (toolTipThreadFunc);
t.IsBackground = true;
t.Start ();
Widget g = _hoverWidget;
while (g != null) {
if (!string.IsNullOrEmpty (g.Tooltip)) {
+ if (g.Tooltip.StartsWith("#", StringComparison.Ordinal)) {
+ //custom tooltip container
+ ToolTipContainer = CreateInstance (g.Tooltip);
+ } else
+ ToolTipContainer = CreateInstance ("#Crow.Tooltip.template");
+ ToolTipContainer.LayoutChanged += ToolTipContainer_LayoutChanged;
AddWidget (ToolTipContainer);
ToolTipContainer.DataSource = g;
ToolTipContainer.Top = MousePosition.Y + 10;
void resetTooltip ()
{
if (tooltipVisible) {
- //ToolTipContainer.DataSource = null;
+ ToolTipContainer.LayoutChanged -= ToolTipContainer_LayoutChanged;
+ ToolTipContainer.DataSource = null;
RemoveWidget (ToolTipContainer);
tooltipVisible = false;
+ ToolTipContainer.Dispose ();
+ ToolTipContainer = null;
}
tooltipTimer.Restart ();
}
+ void ToolTipContainer_LayoutChanged (object sender, LayoutingEventArgs e)
+ {
+ 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.Height < tc.ClientRectangle.Height) {
+ if (PopDirection.HasFlag (Alignment.Bottom)) {
+ if (r.Bottom + ttc.Slot.Height > tc.ClientRectangle.Bottom)
+ ttc.Top = r.Top - ttc.Slot.Height;
+ else
+ ttc.Top = r.Bottom;
+ } else if (PopDirection.HasFlag (Alignment.Top)) {
+ if (r.Top - ttc.Slot.Height < tc.ClientRectangle.Top)
+ ttc.Top = r.Bottom;
+ else
+ ttc.Top = r.Top - ttc.Slot.Height;
+ } else
+ ttc.Top = r.Top;
+ } else
+ ttc.Top = 0;
+ }*/
+ }
#endregion
#region Contextual menu
}
#if DEBUG_LOG
DbgLogger.StartEvent (DbgEvtType.GOProcessLayouting, this);
+ Slot = graphicObject.Slot;
#endif
LayoutingTries++;
if (!Layoutable.UpdateLayout (LayoutType)) {
else{
result = Result.Success;
}
- Slot = graphicObject.LastSlots;
NewSlot = graphicObject.Slot;
(DbgLogger.EndEvent (DbgEvtType.GOProcessLayouting) as DbgLayoutEvent).SetLQI (this);
#endif
-//
-// Expandable.cs
+// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
using System.ComponentModel;
-using System.Xml.Serialization;
namespace Crow
{
childrenRWLock.ExitWriteLock();
- g.RegisteredLayoutings = LayoutingType.None;
+ //g.RegisteredLayoutings = LayoutingType.None;
g.LayoutChanged += OnChildLayoutChanges;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
}
return tmp;
}
+ public override Widget FindByType<T> ()
+ {
+ if (this is T)
+ return this;
+ Widget tmp = null;
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (Widget w in Children) {
+ tmp = w.FindByType<T> ();
+ if (tmp != null)
+ break;
+ }
+
+ childrenRWLock.ExitReadLock ();
+
+ return tmp;
+ }
public override bool Contains (Widget goToFind)
{
foreach (Widget w in Children) {
--- /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.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// Top container to use as ItemTemplate's root for TemplatedGroups (lists, treeviews, ...) that add selection
+ /// status and events
+ /// </summary>
+ public class ListItem : Container
+ {
+ #region CTOR
+ public ListItem (){}
+ public ListItem (Interface iface, string style = null) : base (iface, style) { }
+ #endregion
+
+ bool isSelected;
+
+ public event EventHandler Selected;
+ public event EventHandler Unselected;
+
+ [DefaultValue (false)]
+ public virtual bool IsSelected {
+ get { return isSelected; }
+ set {
+ if (isSelected == value)
+ return;
+ isSelected = value;
+
+ if (isSelected)
+ Selected.Raise (this, null);
+ else
+ Unselected.Raise (this, null);
+
+ NotifyValueChangedAuto (isSelected);
+ }
+ }
+ }
+}
return child == null ? null : child.FindByName (nameToFind);
}
+ public override Widget FindByType<T> ()
+ {
+ if (this is T)
+ return this;
+
+ return child == null ? null : child.FindByType<T> ();
+ }
public override bool Contains (Widget goToFind)
{
return child == goToFind ? true :
return Content == null ? null : Content.FindByName (nameToFind);
}
+ public override Widget FindByType<T> ()
+ {
+ if (this is T)
+ return this;
+
+ return Content == null ? null : Content.FindByType<T> ();
+ }
public override bool Contains (Widget goToFind)
{
if (Content == goToFind)
/// <returns>widget identified by name, or null if not found</returns>
/// <param name="nameToFind">widget's name to find</param>
public override Widget FindByName (string nameToFind) => nameToFind == this.Name ? this : null;
+ public override Widget FindByType<T> () => this is TemplatedControl ? this : null;
public Widget FindByNameInTemplate (string nameToFind) => child?.FindByName (nameToFind);
/// <summary>
///onDraw is overrided to prevent default drawing of background, template top container
using System.ComponentModel;
using System.Linq;
using System.Threading;
+using Crow.Cairo;
using Crow.IML;
namespace Crow {
#region events
public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
+ /// <summary>
+ /// raised when root widget of item template is a 'ListItem' and this item is selected.
+ /// </summary>
+ public event EventHandler<SelectionChangeEventArgs> SelectedItemContainerChanged;
public event EventHandler Loaded;
#endregion
IEnumerable data;
- int _selectedIndex = -1;
- Color selBackground, selForeground;
- bool selColoring;
int itemPerPage = 50;
CrowThread loadingThread = null;
: items.Children;
}
}
- /// <summary>
- /// Enable SelectionBackground and SelectionForeground color for selected item
- /// </summary>
- [DefaultValue (false)]
- public bool SelectionColoring {
- get => selColoring;
- set {
- if (selColoring == value)
- return;
- selColoring = value;
- NotifyValueChangedAuto (selColoring);
- }
- }
- [DefaultValue(-1)]public virtual int SelectedIndex{
- get { return _selectedIndex; }
- set {
- if (value == _selectedIndex)
- return;
- if (selColoring && _selectedIndex >= 0 && Items.Count > _selectedIndex) {
- Items[_selectedIndex].Foreground = Colors.Transparent;
- Items[_selectedIndex].Background = Colors.Transparent;
- }
-
- _selectedIndex = value;
+ object selectedItem;
+ Widget selectedItemContainer = null;
- if (selColoring && _selectedIndex >= 0 && Items.Count > _selectedIndex) {
- Items[_selectedIndex].Foreground = SelectionForeground;
- Items[_selectedIndex].Background = SelectionBackground;
- }
-
- NotifyValueChangedAuto (_selectedIndex);
- NotifyValueChanged ("SelectedItem", SelectedItem);
- SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
- }
- }
[XmlIgnore]public virtual object SelectedItem{
- get { return data == null ? null : _selectedIndex < 0 ? data.GetDefaultValue() : data is IList tmp ? tmp[_selectedIndex] : null; }
+ get => selectedItem;
set {
- if (data == null) {
- SelectedIndex = -1;
- return;
- }
- //TODO:double check if value type will be notified to binding sys
- if (value == SelectedItem)
+ if (SelectedItem == value)
return;
-
- SelectedIndex = (int)((IList)data)?.IndexOf (value);
+
+ selectedItem = value;
+
+ NotifyValueChanged ("SelectedItem", SelectedItem);
+ SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
}
}
+
[XmlIgnore]public bool HasItems {
get { return Items.Count > 0; }
}
loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
loadingThread.Start ();
- NotifyValueChanged ("SelectedIndex", _selectedIndex);
- NotifyValueChanged ("SelectedItem", SelectedItem);
- SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
+ //NotifyValueChanged ("SelectedIndex", _selectedIndex);
+ //NotifyValueChanged ("SelectedItem", SelectedItem);
NotifyValueChanged ("HasItems", HasItems);
}
}
}
- [DefaultValue("SteelBlue")]
- public virtual Color SelectionBackground {
- get { return selBackground; }
- set {
- if (value == selBackground)
- return;
- selBackground = value;
- NotifyValueChangedAuto (selBackground);
- RegisterForRedraw ();
- }
- }
- [DefaultValue("White")]
- public virtual Color SelectionForeground {
- get { return selForeground; }
- set {
- if (value == selForeground)
- return;
- selForeground = value;
- NotifyValueChangedAuto (selForeground);
- RegisterForRedraw ();
- }
- }
protected void raiseSelectedItemChanged(){
SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
public virtual void ClearItems()
{
- _selectedIndex = -1;
- NotifyValueChanged ("SelectedIndex", _selectedIndex);
- NotifyValueChanged ("SelectedItem", null);
+ selectedItemContainer = null;
+ SelectedItem = null;
items.ClearChildren ();
NotifyValueChanged ("HasChildren", false);
}
return null;
}
+ public override Widget FindByType<T> ()
+ {
+ if (this is T)
+ return this;
+
+ foreach (Widget w in Items) {
+ Widget r = w.FindByType<T> ();
+ if (r != null)
+ return r;
+ }
+ return null;
+ }
public override bool Contains (Widget goToFind)
{
foreach (Widget w in Items) {
g.MouseClick += itemClick;
Monitor.Exit (IFace.LayoutMutex);
- if (iTemp.Expand != null && g is Expandable) {
+ if (iTemp.Expand != null) {
Expandable e = g as Expandable;
- e.Expand += iTemp.Expand;
- if ((o as ICollection) == null)
- e.GetIsExpandable = new BooleanTestOnInstance((instance) => true);
- else
- e.GetIsExpandable = iTemp.HasSubItems;
+ if (e == null)
+ e = g.FindByType<Expandable> () as Expandable;
+
+ if (e != null) {
+ e.Expand += iTemp.Expand;
+ if ((o as ICollection) == null)
+ e.GetIsExpandable = new BooleanTestOnInstance ((instance) => true);
+ else
+ e.GetIsExpandable = iTemp.HasSubItems;
+ }
+ }
+
+ if (g is ListItem li) {
+ li.Selected += Li_Selected;
}
g.DataSource = o;
}
+ //void expandable_expandevent (object sender, EventHandler )
+ void Li_Selected (object sender, EventArgs e)
+ {
+ SelectedItemContainerChanged.Raise (this, new SelectionChangeEventArgs (sender));
+ }
// protected void _list_LayoutChanged (object sender, LayoutingEventArgs e)
// {
}
internal virtual void itemClick(object sender, MouseButtonEventArgs e){
//SelectedIndex = (int)((IList)data)?.IndexOf((sender as Widget).DataSource);
- SelectedIndex = items.Children.IndexOf(sender as Widget);
+ if (selectedItemContainer is ListItem li)
+ li.IsSelected = false;
+ selectedItemContainer = sender as Widget;
+ if (selectedItemContainer is ListItem nli)
+ nli.IsSelected = true;
+ if (selectedItemContainer == null)
+ return;
+ SelectedItem = selectedItemContainer.DataSource;
+ //SelectedIndex = items.Children.IndexOf(sender as Widget);
}
bool emitHelperIsAlreadyExpanded (Widget go){
//if their are expandable, some functions and events are added
public class TreeView : TemplatedGroup
{
- Widget selectedItemContainer = null;
bool isRoot;
#region CTOR
NotifyValueChangedAuto (isRoot);
}
}
- [XmlIgnore]public override object SelectedItem {
- get {
- return selectedItemContainer == null ?
- "" : selectedItemContainer.DataSource;
- }
- }
- internal override void itemClick (object sender, MouseButtonEventArgs e)
- {
- Widget tmp = sender as Widget;
- //if (!tmp.HasFocus)
- // return;
- /*if (selectedItemContainer != null) {
- selectedItemContainer.Foreground = Color.Transparent;
- selectedItemContainer.Background = Color.Transparent;
- }*/
- selectedItemContainer = tmp;
- //selectedItemContainer.Foreground = SelectionForeground;
- //selectedItemContainer.Background = SelectionBackground;
- NotifyValueChanged ("SelectedItem", SelectedItem);
- raiseSelectedItemChanged ();
- }
void onExpandAll_MouseClick (object sender, MouseButtonEventArgs e)
{
loadDefaultValues ();
}
#region private fields
- LayoutingType registeredLayoutings = LayoutingType.All;
+ LayoutingType registeredLayoutings;// = LayoutingType.All;
ILayoutable logicalParent;
ILayoutable parent;
string name;
return cb;
}
}
+ /// <summary>
+ /// Compute rectangle position on surface of the context. It ma be the first cached surface in parenting chain,
+ /// or the top backend surface if no cached widget is part of the current widget tree.
+ /// </summary>
+ /// <returns>A new rectangle with same dimension as the input one with x and y relative to the context surface</returns>
+ /// <param name="r">A rectangle to compute the coordinate for.</param>
public virtual Rectangle ContextCoordinates(Rectangle r){
Widget go = Parent as Widget;
if (go == null)
r + Parent.ClientRectangle.Position :
Parent.ContextCoordinates (r);
}
+
+ public virtual Rectangle RelativeSlot (Widget target)
+ {
+ if (this == target)
+ return Slot;
+ if (Parent is Widget p)
+ return Slot + p.RelativeSlot (target).Position + Margin;
+ return Slot + new Point(Margin, Margin);
+ }
public virtual Rectangle ScreenCoordinates (Rectangle r){
try {
return
public event EventHandler<DataSourceChangeEventArgs> ParentChanged;
/// <summary>Occurs when the logical parent has changed</summary>
public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged;
+ public event EventHandler Painted;
#endregion
internal bool hasDoubleClick => MouseDoubleClick != null;
get {
return rootDataLevel ? dataSource : dataSource == null ?
LogicalParent == null ? null :
- LogicalParent is Widget ? (LogicalParent as Widget).DataSource : null :
+ LogicalParent is Widget w ? w.DataSource : null :
dataSource;
}
}
/// <summary>
- /// If true, lock datasource seeking upward in logic or graphic tree to this widget
+ /// If true, lock datasource seeking upward in logic or graphic tree to this widget.
/// </summary>
[DesignCategory ("Data")][DefaultValue(false)]
public virtual bool RootDataLevel {
NotifyValueChangedAuto (style);
}
}
+ /// <summary>
+ /// Gets or sets a tooltip to show when mouse stay still over the control.
+ /// </summary>
+ /// <remarks>
+ /// By default, the tooltip container widget that will be show is defined in '#Crow.Tooltip.template' and the widget
+ /// tooltip string is interpreted as a single string helper message that may be a binding expression.
+ /// If the widget Tooltip property start with a '#', the tooltip string will be interpreted as a resource path of
+ /// a custom IML template to show, which will have its datasource set to the widget triggering the tooltip.
+ /// </remarks>
+ /// <value>A single helpt string that may comes from a binding expression, or by starting with a '#',
+ /// You may provide a custom tooltip template resource path.</value>
[DesignCategory ("Divers")]
public virtual string Tooltip {
get { return tooltip; }
public virtual Widget FindByName(string nameToFind){
return string.Equals(nameToFind, name, StringComparison.Ordinal) ? this : null;
}
+ public virtual Widget FindByType<T> ()
+ {
+ return this is T ? this : null;
+ }
public virtual bool Contains(Widget goToFind){
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RegisterForRedraw ()
{
-#if DEBUG
+#if DEBUG_LOG
if (disposed) {
DbgLogger.AddEvent (DbgEvtType.GORegisterForRedraw | DbgEvtType.AlreadyDisposed, this);
return;
/// <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 ?
contentSize.Width + 2 * margin: contentSize.Height + 2 * margin;
}
Rectangle rb = Slot + Parent.ClientRectangle.Position;
if (clearBackground) {
- ctx.Save ();
- ctx.Operator = Operator.Clear;
- ctx.Rectangle (rb);
- ctx.Fill ();
- ctx.Restore ();
+ ctx.Operator = Operator.Clear;
+ ctx.Rectangle (rb);
+ ctx.Fill ();
+ ctx.Operator = Operator.Over;
}
ctx.SetSourceSurface (bmp, rb.X, rb.Y);
}
LastPaintedSlot = Slot;
}
+ Painted.Raise (this, null);
}
void paintDisabled(Context gr, Rectangle rb){
gr.Operator = Operator.Xor;
+++ /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 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/512.0, yScale = 1.0, leftMargin, topMargin = 0.0;
- string logFile;
- DbgWidgetRecord curWidget;
- DbgEvent curEvent;
-
- List<DbgEvent> events;
- List<DbgWidgetRecord> objs;
-
- public List<DbgEvent> Events => events;
- public List<DbgWidgetRecord> Widgets => objs;
-
-
- long currentTick = 0, selStart = -1, selEnd = -1, minTicks = 0, maxTicks = 0, visibleTicks = 0;
- int currentLine = -1;
- int visibleLines = 1;
- Point mousePos;
-
- public string LogFile {
- get { return logFile; }
- set {
- if (logFile == value)
- return;
- logFile = value;
-
- Console.WriteLine ("before load");
- loadDebugFile ();
- Console.WriteLine ("after load");
-
- NotifyValueChanged ("LogFile", logFile);
- RegisterForGraphicUpdate ();
- }
- }
- 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;
- }
- loadDebugFile ();
- }
- }
- public override int ScrollY {
- get => base.ScrollY;
- set {
- base.ScrollY = value;
-
- if (objs == 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);
- }
- }
-
- public DbgWidgetRecord CurrentWidget {
- get => curWidget;
- internal set {
- if (curWidget == value)
- return;
- curWidget = value;
- NotifyValueChanged (nameof (CurrentWidget), curWidget);
- }
- }
- public DbgEvent CurrentEvent {
- get => curEvent;
- internal set {
- if (curEvent == value)
- return;
-
- if (curEvent != null)
- curEvent.IsSelected = false;
- curEvent = value;
- if (curEvent != null) {
- curEvent.IsSelected = true;
- curEvent.IsExpanded = true;
- }
-
- NotifyValueChanged (nameof (CurrentEvent), curEvent);
- }
- }
-
-
- 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 (objs == null)
- return;
-
- gr.LineWidth = 1.0;
-
- Rectangle cb = ClientRectangle;
-
- double penY = topMargin + ClientRectangle.Top;
-
- for (int i = 0; i < visibleLines; i++) {
- if (i + ScrollY >= objs.Count)
- break;
- int gIdx = i + ScrollY;
- DbgWidgetRecord g = objs [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 (gr);
-
- gr.MoveTo (penX, penY - gr.FontExtents.Descent);
- gr.ShowText (g.name + gIdx);
-
- gr.SetSource (Crow.Colors.White);
- gr.MoveTo (cb.X, penY - gr.FontExtents.Descent);
- gr.ShowText ((i + ScrollY).ToString ());
- }
-
- 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 (ref Cairo.Context ctx)
- {
- base.Paint (ref ctx);
-
- Rectangle r = new Rectangle(mousePos.X, 0, 1, Slot.Height);
- Rectangle ctxR = ContextCoordinates (r);
- Rectangle cb = ClientRectangle;
-
- ctx.Rectangle (ctxR);
- ctx.SetSource (Colors.CornflowerBlue);
- ctx.Fill();
-
- ctx.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- ctx.SetFontSize (Font.Size);
- ctx.FontOptions = Interface.FontRenderingOptions;
- ctx.Antialias = Interface.Antialias;
-
- ctx.MoveTo (ctxR.X, 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.SetSourceRGBA (0.1, 0.1, 0.1, 0.4);
- 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:
- 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);
- }
-
- 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 = (currentLine < 0 || currentLine >= objs.Count) ? null : objs [currentLine];
- CurrentEvent = curWidget?.Events.FirstOrDefault (ev => ev.begin <= currentTick && ev.end >= currentTick);
- selStart = currentTick;
- selEnd = -1;
- }
-
- RegisterForRedraw ();
- }
- public override void onMouseUp (object sender, MouseButtonEventArgs e)
- {
- base.onMouseUp (sender, e);
-
- 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;
- }
- }
- async void loadDebugFile ()
- {
- await loadDebugFileAsync ();
- }
-
-
-
- async Task loadDebugFileAsync ()
- {
- if (!File.Exists (logFile))
- return;
-
- events = new List<DbgEvent> ();
- objs = new List<DbgWidgetRecord> ();
- minTicks = maxTicks = 0;
- leftMargin = topMargin = 0.0;
-
- using (Context gr = new Context (IFace.surf)) {
- double maxNameWidth = 0.0;
-
- gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- gr.SetFontSize (Font.Size);
-
- 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);
- double nameWidth = gr.TextExtents (o.name).Width + 5.0 * o.xLevel;
- if (nameWidth > maxNameWidth)
- maxNameWidth = nameWidth;
- }
-
- 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 (evt.end > maxTicks)
- maxTicks = evt.end;
- 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))
- objs [(evt as DbgWidgetEvent).InstanceIndex].Events.Add (evt);
- }
- if (events.Count > 0)
- minTicks = events [0].begin;
- }
- }
-
- leftMargin = 2.5 + maxNameWidth;
- topMargin = 2.0 * fe.Height;
-
- updateVisibleLines ();
- updateVisibleTicks ();
- }
- NotifyValueChanged ("Widgets", Widgets);
- NotifyValueChanged ("Events", Events);
- }
-
- 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 (objs == null)
- MaxScrollX = 0;
- else
- MaxScrollX = (int)Math.Max (0L, maxTicks - minTicks - visibleTicks);
- }
- void updateMaxScrollY ()
- {
- if (objs == null)
- MaxScrollY = 0;
- else
- MaxScrollY = Math.Max (0, objs.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;
- }
- void zoom (long start, long end) {
- //Rectangle cb = ClientRectangle;
- //cb.X += (int)leftMargin;
- XScale = ((double)ClientRectangle.Width - leftMargin)/(end - start);
- ScrollX = (int)(start - minTicks);
- }
- }
-}
-
-
+++ /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.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading;
-
-
-namespace Crow
-{
- [Flags]
- public enum DbgEvtType {
- ////9 nth bit set for iface event
- IFace = 0x10000,
- Focus = 0x20000,
- Override = 0x40000,
- 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,
-
- HoverWidget = Focus | 0x01,
- FocusedWidget = Focus | 0x02,
- ActiveWidget = Focus | 0x03,
-
- //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 | 0x10,
- GORegisterForRedraw = Widget | 0x11,
-
- 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,
- 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
- }
-#if DEBUG_LOG
- public static class DbgLogger
- {
- public static DbgEvtType IncludeEvents = DbgEvtType.All;
- public static DbgEvtType DiscardEvents = DbgEvtType.Focus;
-
- static bool logevt (DbgEvtType evtType)
- => (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) != 0;
-
-
- static object logMutex = new object ();
- static Stopwatch chrono = Stopwatch.StartNew ();
- static List<DbgEvent> events = new List<DbgEvent> ();
- //started events per thread
- static Dictionary<int, Stack<DbgEvent>> startedEvents = new Dictionary<int, Stack<DbgEvent>> ();
- //helper for fetching current event list to add next event to while recording
- static List<DbgEvent> curEventList {
- get {
- if (startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId)) {
- if (startedEvents [Thread.CurrentThread.ManagedThreadId].Count == 0)
- return events;
- DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Peek ();
- if (e.Events == null)
- e.Events = new List<DbgEvent> ();
- return e.Events;
- }
- return events;
- }
- }
-
- public static DbgEvent StartEvent (DbgEvtType evtType, params object[] data)
- {
- if (!logevt (evtType))
- return null;
- lock (logMutex) {
- chrono.Stop ();
- DbgEvent evt = addEventInternal (evtType, data);
- if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
- startedEvents [Thread.CurrentThread.ManagedThreadId] = new Stack<DbgEvent> ();
- startedEvents [Thread.CurrentThread.ManagedThreadId].Push (evt);
- chrono.Start ();
- return evt;
- }
- }
- public static DbgEvent EndEvent (DbgEvtType evtType, bool discardIfNoChildEvents = false)
- {
- if (!logevt (evtType))
- return null;
-
- lock (logMutex) {
- chrono.Stop ();
- if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
- throw new Exception ("Current thread has no event started");
- DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
- if (e.type != evtType)
- throw new Exception ($"Begin/end event logging mismatch: {e.type}/{evtType}");
- if (discardIfNoChildEvents && (e.Events == null || e.Events.Count == 0))
- curEventList.Remove (e);
- else
- e.end = chrono.ElapsedTicks;
- chrono.Start ();
- return e;
- }
- }
- /// <summary>
- /// End event by reference to cancel unended events on failure
- /// </summary>
- public static DbgEvent EndEvent (DbgEvtType evtType, DbgEvent evt)
- {
- if (!logevt (evtType))
- return null;
-
- lock (logMutex) {
- chrono.Stop ();
- if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId))
- throw new Exception ("Current thread has no event started");
- DbgEvent e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
- while (e != evt)
- e = startedEvents [Thread.CurrentThread.ManagedThreadId].Pop ();
- e.end = chrono.ElapsedTicks;
- chrono.Start ();
- return e;
- }
- }
-
- public static DbgEvent AddEvent (DbgEvtType evtType, params object [] data) {
- if (!logevt (evtType))
- return null;
-
- lock (logMutex) {
- chrono.Stop ();
- DbgEvent evt = addEventInternal (evtType, data);
- chrono.Start ();
- return evt;
- }
- }
-
- static DbgEvent addEventInternal (DbgEvtType evtType, params object [] data)
- {
- DbgEvent evt = null;
- 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);
- else if (data [0] is LayoutingQueueItem lqi)
- evt = new DbgLayoutEvent (chrono.ElapsedTicks, evtType, lqi);
- else
- evt = new DbgEvent (chrono.ElapsedTicks, evtType);
-
- curEventList.Add (evt);
- return evt;
- }
-
- static void parseTree (Widget go, int level = 0, int y = 1) {
- if (go == null)
- return;
-
- go.yIndex = y;
- go.xLevel = level;
-
- Group gr = go as Group;
- if (gr != null) {
- foreach (Widget g in gr.Children)
- parseTree (g, level + 1, y + 1);
-
- } else {
- PrivateContainer pc = go as PrivateContainer;
- if (pc != null)
- parseTree (pc.getTemplateRoot, level + 1, y + 1);
- }
- }
- /// <summary>
- /// Clear all recorded events from logger.
- /// </summary>
- public static void Reset ()
- {
- lock (logMutex) {
- startedEvents.Clear ();
- events.Clear ();
- chrono.Restart ();
- }
- }
- /// <summary>
- /// Save recorded events to disk
- /// </summary>
- /// <param name="iface">Iface.</param>
- public static void save(Interface iface, string dbgLogFilePath = "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}");
- }
- }
- s.WriteLine ("[Events]");
- saveEventList (s, events);
- }
- }
- }
-
- 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
-}
-
-
//testFiles = new string [] { @"Interfaces/TemplatedControl/testEnumSelector.crow" };
//testFiles = new string [] { @"Interfaces/Divers/all.crow" };
//testFiles = new string [] { @"Interfaces/Divers/gauge.crow" };
- testFiles = new string [] { @"Interfaces/Divers/testSlider.crow" };
+ //testFiles = new string [] { @"Interfaces/Stack/StretchedInFit4.crow" };
+ testFiles = new string [] { @"Interfaces/TemplatedGroup/1.crow" };
//testFiles = new string [] { @"Interfaces/Divers/colorPicker2.crow" };
testFiles = testFiles.Concat (Directory.GetFiles (@"Interfaces/GraphicObject", "*.crow")).ToArray ();
testFiles = testFiles.Concat (Directory.GetFiles (@"Interfaces/Container", "*.crow")).ToArray ();
Quit ();
break;
case Key.F2:
+ //if (IsKeyDown (Key.LeftShift))
+ //DbgLogger.Reset ();
+ //DbgLogger.save (this);
+ return false;
+ case Key.F3:
idx--;
break;
- case Key.F3:
+ case Key.F4:
idx++;
break;
case Key.F1:
//TestList.Add ("new string");
NotifyValueChanged ("TestList", TestList);
break;
- case Key.F4:
- Load ("Interfaces/TemplatedContainer/testWindow.goml").DataSource = this;
- return false;
case Key.F5:
Load ("Interfaces/Divers/testFileDialog.crow").DataSource = this;
return false;
--- /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.SetSourceRGB (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 (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 (ref Cairo.Context ctx)
+ {
+ base.Paint (ref 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.SetSourceRGBA (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);
+ }
+ }
+}
+
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+ <ItemGroup>
+ <EmbeddedResource Include="ui\**\*.*">
+ <LogicalName>Dbg.%(Filename)%(Extension)</LogicalName>
+ </EmbeddedResource>
+</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)
+ {
+#if NETCOREAPP3_1
+ DllMapCore.Resolve.Enable (true);
+#endif
+ 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 ("/var/tmp/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)
+[assembly: Crow.Crow ]
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<ItemTemplate Data="Events">
+ <ListItem IsSelected="{²IsSelected}" Height="Fit"
+ Selected="{/exp.Background=${ControlHighlight}}"
+ Unselected="{/exp.Background=Transparent}">
+ <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
+ <Template>
+ <VerticalStack>
+ <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
+ Foreground="Transparent"
+ Background="{./Background}"
+ MouseEnter="{Foreground=DimGrey}"
+ MouseLeave="{Foreground=Transparent}">
+ <HorizontalStack Spacing="2" >
+ <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand"
+ Path="{./Image}"
+ Visible="{HasChildEvents}"
+ SvgSub="{./IsExpanded}"
+ 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"/>
+ <DbgEventWidget Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" Width="Stretched" Height="5"/>
+ </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>
+<ItemTemplate Data="Events" DataType="DbgWidgetEvent">
+ <ListItem IsSelected="{²IsSelected}" Height="Fit"
+ Selected="{/exp.Background=${ControlHighlight}}"
+ Unselected="{/exp.Background=Transparent}">
+ <Expandable Name="exp" Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
+ <Template>
+ <VerticalStack>
+ <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
+ Foreground="Transparent"
+ Background="{./Background}"
+ MouseEnter="{Foreground=DimGrey}"
+ MouseLeave="{Foreground=Transparent}">
+ <HorizontalStack Spacing="2" >
+ <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand"
+ Path="{./Image}"
+ Visible="{HasChildEvents}"
+ SvgSub="{./IsExpanded}"
+ 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="{InstanceIndex}" Width="40" Font="mono, 8" TextAlignment="Center" Background="DimGrey"/>
+ <DbgEventWidget Event="{}" Tooltip="#Dbg.DbgEvtTooltip.crow" Width="Stretched" Height="5"/>
+ </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>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<Border Fit="true" Foreground="${TooltipForeground}" Background="${TooltipBackground}">
+ <VerticalStack Fit="true" Margin="${TooltipMargin}" DataSource="{HoverEvent}">
+ <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="{Duration}" 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"/>
+ </HorizontalStack>
+ <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
+ <Label Text="End:" Foreground="${TooltipForeground}" Width="50%"/>
+ <Label Text="{end}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>
+ </HorizontalStack>
+ <VerticalStack Height="Fit" Width="Stretched" >
+ <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>
+ <!--<Label Text="{}" Foreground="${TooltipForeground}"/>-->
+ </VerticalStack>
+</Border>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<VerticalStack>
+ <VerticalStack Height="40%">
+ <DbgLogViewer Visible="true" Name="dbv" Events="{Events}" Widgets="{Widgets}" MouseWheelSpeed="10" Font="mono, 8"
+ CurrentEvent="{²CurrentEvent}" CurrentWidget="{²CurrentWidget}" Background="Onyx"/>
+ <ScrollBar Style="HScrollBar" Maximum="{../dbv.MaxScrollX}" Value="{²../dbv.ScrollX}"/>
+ <HorizontalStack Height="Fit" DataSource="{CurrentWidget}">
+ <Label Text="{name}"/>
+ <Label Text="{listIndex}"/>
+ <Label Text="{treeIndex}"/>
+ <Label Text="{yIndex}"/>
+ <Label Text="{xLevel}"/>
+ <Label Text="Width:"/>
+ <Label Text="{Width}"/>
+ <Label Text="Height:"/>
+ <Label Text="{Height}"/>
+ <Label Text="ScrollX"/>
+ <Label Text="{../../dbv.ScrollX}"/>
+ </HorizontalStack>
+ </VerticalStack>
+ <Splitter/>
+ <HorizontalStack Height="40%">
+ <VerticalStack Width="Stretched">
+ <TreeView Height="Stretched" Name="dbgTV" Data="{Events}" SelectedItem="{²CurrentEvent}" Background="DarkGrey"
+ SelectedItemContainerChanged="onSelectedItemContainerChanged" Painted="onTvPainted"
+ ItemTemplate="#Dbg.DbgEventTreeItems.itemp"/>
+ <ListBox Data="{CurWidgetRootEvents}" Height="100" 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="20" VerticalAlignment="Center"/>
+ </ListItem>
+ </ItemTemplate>
+ <Template>
+ <Wrapper Name="ItemsContainer" Spacing="0" Background="DarkGrey"/>
+ </Template>
+ </ListBox>
+ </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="{Duration}" 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"/>
+ </HorizontalStack>
+ <HorizontalStack Height="Fit" Width="Stretched" Spacing="2">
+ <Label Text="End:" Foreground="${TooltipForeground}" Width="50%"/>
+ <Label Text="{end}" Foreground="${TooltipForeground}" Width="Stretched" TextAlignment="Right"/>
+ </HorizontalStack>
+ <VerticalStack Height="Fit" Width="Stretched" >
+ <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>
+ <!--<Label Text="{}" Foreground="${TooltipForeground}"/>-->
+ </VerticalStack>
+ </HorizontalStack>
+ <Splitter/>
+ <VerticalStack Name="vs">
+
+ <VerticalStack DataSource="{CurrentEvent}">
+ <ListBox Data="{Events}" Height="100" SelectedItem="{²CurrentEvent}">
+ <ItemTemplate>
+ <ListItem Margin="0" IsSelected="{²IsSelected}" Height="12"
+ Selected="{Background=${ControlHighlight}}"
+ Unselected="{Background=Transparent}">
+ <HorizontalStack>
+ <Label Text="{type}" Width="80"/>
+ <DbgEventWidget Height="8" Width="Stretched" Event="{}"/>
+ </HorizontalStack>
+ </ListItem>
+ </ItemTemplate>
+ </ListBox>
+ </VerticalStack>
+ </VerticalStack>
+</VerticalStack>
\ No newline at end of file
-<Project Sdk="Microsoft.NET.Sdk">
- <ItemGroup>
- <EmbeddedResource Include="ui\**\*.*">
- <LogicalName>HelloWorld.%(Filename)%(Extension)</LogicalName>
- </EmbeddedResource>
- </ItemGroup>
-</Project>
+<?xml version="1.0" encoding="UTF-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+ <ItemGroup>
+ <EmbeddedResource Include="ui\**\*.*">
+ <LogicalName>HelloWorld.%(Filename)%(Extension)</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+</Project>
\ No newline at end of file
using (Interface app = new Interface ()) {
app.Initialized += (sender, e) => (sender as Interface).Load ("#HelloWorld.helloworld.crow");
app.Run ();
+
+ DbgLogger.save (app);
}
}
}
using System.Text;
using Crow.IML;
using System.Runtime.CompilerServices;
+using Glfw;
namespace ShowCase
{
reloadFromFile ();
}
-
- static void App_KeyboardKeyDown (object sender, KeyEventArgs e)
+ public override bool OnKeyDown (Key key)
{
-#if DEBUG_LOG
- switch (e.Key) {
+ switch (key) {
case Key.F2:
- DebugLog.save (sender as Interface);
- break;
+ //DbgLogger.save (this);
+ return true;
}
-#endif
+ return base.OnKeyDown (key);
}
+
public void goUpDirClick (object sender, MouseButtonEventArgs e)
{
string root = Directory.GetDirectoryRoot (CurrentDir);
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Threading;
using Crow;
=> $"{Prop1}, {Prop2}";
}
+ public class TestClassVC : IValueChange
+ {
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
+ public void NotifyValueChanged (object _value, [CallerMemberName] string caller = null)
+ => ValueChanged.Raise (this, new ValueChangeEventArgs (caller, _value));
+ string prop1, prop2;
+ public string Prop1 {
+ get => prop1;
+ set {
+ if (prop1 == value)
+ return;
+ prop1 = value;
+ NotifyValueChanged (prop1);
+ }
+ }
+ public string Prop2 {
+ get => prop2;
+ set {
+ if (prop2 == value)
+ return;
+ prop2 = value;
+ NotifyValueChanged (prop2);
+ }
+
+
+
+ }
+
+ public override string ToString ()
+ => $"{Prop1}, {Prop2}";
+
+ }
+ TestClass tcInstance;// = new TestClass () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
+ TestClassVC tcVCInstance;// = new TestClassVC () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
+ TestClass tcInstance1 = new TestClass () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
+ TestClassVC tcVCInstance1 = new TestClassVC () { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
+ TestClass tcInstance2 = new TestClass () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
+ TestClassVC tcVCInstance2 = new TestClassVC () { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
+
+ public TestClass TcInstance {
+ get => tcInstance;
+ set {
+ if (tcInstance == value)
+ return;
+ tcInstance = value;
+ NotifyValueChanged (tcInstance);
+ }
+ }
+ public TestClassVC TcVCInstance {
+ get => tcVCInstance;
+ set {
+ if (tcVCInstance == value)
+ return;
+ tcVCInstance = value;
+ NotifyValueChanged (tcVCInstance);
+ }
+ }
+
+ void tcInstance_ChangeProperties_MouseClick (object sender, MouseButtonEventArgs e)
+ {
+ }
+ public void tcInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e)
+ {
+ if (TcInstance == tcInstance1)
+ TcInstance = tcInstance2;
+ else
+ TcInstance = tcInstance1;
+ }
+ void tcVCInstance_ChangeInstance_MouseClick (object sender, MouseButtonEventArgs e)
+ {
+ TcVCInstance = new TestClassVC () { Prop1 = "prop1 value changed", Prop2 = "prop2 value changed" };
+ }
+
public IEnumerable<TestClass> List3 = new List<TestClass> (new TestClass[]
{
new TestClass { Prop1 = "string1", Prop2="prop2-1" },
Template= "Interfaces/CheckBox2.imlt";
Background = "Jet";
Checked="{Background=MediumSeaGreen}";
- Unchecked = "{Background=Jet}";
+ Unchecked = "{Background=Jet}";
}
CheckBox3 {
Template= "Interfaces/CheckBox2.imlt";
Width = "50%";
}
DbgLogViewer{
- Background = "Onyx";
+ //Background = "Onyx";
Font = "mono, 8";
Foreground = "LightGrey";
Focusable = "true";
-<Label Font="{./Font}" Text="{./Caption}" Height="{./HeightPolicy}" Width="{./WidthPolicy}"
- Margin="3"
+<Label Font="{./Font}" Text="{./Caption}" Width="Stretched"
+ Margin="5"
Background="{./Background}"
Foreground="DimGrey"
TextAlignment="Center"
--- /dev/null
+<VerticalStack Fit="true">
+ <VerticalStack DataSourceType="Crow.TestClass" DataSource="{TcInstance}" Margin="10" Background="Onyx" Fit="true">
+ <Label Text="{Prop1}"/>
+ <Label Text="{Prop2}"/>
+ </VerticalStack>
+ <HorizontalStack>
+ <Button Caption="Change Instance" MouseClick="tcInstance_ChangeInstance_MouseClick"/>
+ </HorizontalStack>
+</VerticalStack>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<HorizontalStack>
- <TreeView Width="20%" Data="{../dbv.Events}" SelectedItemChanged="onSelectedItemChanged">
- <ItemTemplate Data="Events">
- <Expandable Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
- <Template>
- <VerticalStack>
- <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
- Foreground="Transparent"
- MouseEnter="{Foreground=DimGrey}"
- MouseLeave="{Foreground=Transparent}">
- <HorizontalStack Spacing="2" Background="Onyx">
- <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand"
- Path="{./Image}"
- Visible="{HasChildEvents}"
- SvgSub="{./IsExpanded}"
- 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"/>
- <DbgEventWidget Event="{}" Tooltip="{/HoverEvent}" TicksPerPixel="200" Width="Fit" Height="5"/>
- </HorizontalStack>
- </Border>
- <Container Name="Content" Visible="false"/>
- </VerticalStack>
- </Template>
- <HorizontalStack Height="Fit">
- <Widget Width="12" Height="10"/>
- <VerticalStack Height="Fit" Name="ItemsContainer"/>
- </HorizontalStack>
- </Expandable>
- </ItemTemplate>
- <ItemTemplate Data="Events" DataType="DbgWidgetEvent">
- <Expandable Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true" IsExpanded="{²IsExpanded}">
- <Template>
- <VerticalStack>
- <Border CornerRadius="2" Margin="0" Height="Fit" MouseDoubleClick="./onClickForExpand"
- Foreground="Transparent"
- MouseEnter="{Foreground=DimGrey}"
- MouseLeave="{Foreground=Transparent}">
- <HorizontalStack Spacing="2" Background="Onyx">
- <Image Margin="1" Width="9" Height="9" Focusable="true" MouseDown="./onClickForExpand"
- Path="{./Image}"
- Visible="{HasChildEvents}"
- SvgSub="{./IsExpanded}"
- 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="{InstanceIndex}" Width="40" Font="mono, 8" TextAlignment="Center" Background="DimGrey"/>
- <DbgEventWidget Event="{}" Tooltip="{/HoverEvent}" TicksPerPixel="200" Width="Fit" Height="5"/>
- </HorizontalStack>
- </Border>
- <Container Name="Content" Visible="false"/>
- </VerticalStack>
- </Template>
- <HorizontalStack Height="Fit">
- <Widget Width="12" Height="10"/>
- <VerticalStack Height="Fit" Name="ItemsContainer"/>
- </HorizontalStack>
- </Expandable>
- </ItemTemplate>
- </TreeView>
- <Splitter/>
- <VerticalStack>
- <DbgLogViewer Visible="true" Name="dbv" LogFile="debug.log" MouseWheelSpeed="10" Font="mono, 8"/>
- <ScrollBar Style="HScrollBar" Maximum="{../dbv.MaxScrollX}" Value="{²../dbv.ScrollX}"/>
- <HorizontalStack Height="Fit" DataSource="{../../dbv.CurrentWidget}">
- <Label Text="{name}"/>
- <Label Text="{listIndex}"/>
- <Label Text="{instanceNum}"/>
- <Label Text="{treeIndex}"/>
- <Label Text="{yIndex}"/>
- <Label Text="{xLevel}"/>
- </HorizontalStack>
- <ListBox Data="{RootEvents}" Height="100" DataSource="{../../dbv.CurrentWidget}">
- <ItemTemplate>
- <DbgEventWidget Height="10" Width="Fit" Event="{}" Tooltip="{/HoverEvent}" TicksPerPixel="100"/>
- </ItemTemplate>
- <Template>
- <Wrapper Name="ItemsContainer" Spacing="2" Background="DarkGrey"/>
- </Template>
- </ListBox>
- <!--<DbgEventWidget Height="20" Width="Stretched" Event="{../../dbv.CurrentEvent}"/>-->
- <VerticalStack DataSource="{../../dbv.CurrentEvent}">
- <HorizontalStack>
- <Label Text="{type}"/>
- <Label Text="{begin}"/>
- <Label Text="{end}"/>
- <Label Text="{Duration}"/>
- </HorizontalStack>
- <ListBox Data="{events}" Height="100">
- <ItemTemplate>
- <DbgEventWidget Height="20" Width="Stretched" Event="{}"/>
- </ItemTemplate>
- </ListBox>
- </VerticalStack>
- </VerticalStack>
-</HorizontalStack>
\ No newline at end of file
--- /dev/null
+<HorizontalStack Margin="50">
+ <Widget Background="SeaGreen" Width="33%"/>
+ <Splitter/>
+ <Widget Background="SeaGreen" Width="33%"/>
+ <Splitter/>
+ <Widget Background="SeaGreen"/>
+</HorizontalStack>
+++ /dev/null
-<?xml version="1.0"?>
-<HorizontalStack Width="80%" Height="50%">
- <Border Width="45%" CornerRadius="10" BorderWidth="1">
- <VerticalStack>
- <VerticalStack Height="45%">
- <CheckBox Height="25%" IsChecked="false" Caption="Check 1" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="false" Caption="Check 2" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="true" Caption="Check 3" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="false" Caption="Check 4" Background="hgradient|0:LimeGreen|1:Transparent"/>
- </VerticalStack>
- <Splitter Thickness="3"/>
- <VerticalStack Height="45%">
- <CheckBox Height="25%" IsChecked="false" Caption="Check 1" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="false" Caption="Check 2" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="true" Caption="Check 3" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox Height="25%" IsChecked="false" Caption="Check 4" Background="hgradient|0:LimeGreen|1:Transparent"/>
- </VerticalStack>
- </VerticalStack>
- </Border>
- <Splitter Thickness="3"/>
- <Border Width="45%" CornerRadius="10" BorderWidth="1">
- <VerticalStack Width="50%" Height="50%" Background="DimGrey">
- <RadioButton IsChecked="false" Caption="Choice 1" Background="hgradient|0:DarkRed|1:Transparent"/>
- <RadioButton IsChecked="false" Caption="Choice 2" Background="hgradient|0:DarkRed|1:Transparent"/>
- <RadioButton IsChecked="true" Caption="Choice 3" Background="hgradient|0:DarkRed|1:Transparent"/>
- <RadioButton IsChecked="false" Caption="Choice 4" Background="hgradient|0:DarkRed|1:Transparent"/>
- </VerticalStack>
- </Border>
- <Splitter Thickness="3"/>
-</HorizontalStack>
+++ /dev/null
-<?xml version="1.0"?>
-<VerticalStack Fit="true">
- <Widget CornerRadius="5" Height="10" Width="600" Background="vgradient|0:Transparent|0.5:White|1:Transparent"/>
- <HorizontalStack Fit="true" HorizontalAlignment="Left">
- <Border Fit="true" CornerRadius="10" BorderWidth="1">
- <VerticalStack Margin="10">
- <CheckBox IsChecked="false" Caption="Check 1" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox IsChecked="false" Caption="Check 2" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox IsChecked="true" Caption="Check 3" Background="hgradient|0:LimeGreen|1:Transparent"/>
- <CheckBox IsChecked="false" Caption="Check 4" Background="hgradient|0:LimeGreen|1:Transparent"/>
- </VerticalStack>
- </Border>
- <Splitter/>
- <Border Fit="true" CornerRadius="10" BorderWidth="1">
- <VerticalStack Margin="10">
- <RadioButton IsChecked="false" Caption="Choice 1" Background="hgradient|0:DarkRed|1:Transparent"/>
- <Splitter/>
- <RadioButton Width="Stretched" IsChecked="false" Caption="Choice 2" Background="hgradient|0:DarkRed|1:Transparent"/>
- <RadioButton IsChecked="true" Caption="Choice 3" Background="hgradient|0:DarkRed|1:Transparent"/>
- <RadioButton IsChecked="false" Caption="Choice 4" Background="hgradient|0:DarkRed|1:Transparent"/>
- </VerticalStack>
- </Border>
- <Splitter Thickness="3" />
- <Border Fit="true" CornerRadius="10" BorderWidth="1" MaximumSize="150,150" MinimumSize="50,50">
- <VerticalStack Margin="10">
- <Label Text="label 1" Background="hgradient|0:Blue|1:Transparent"/>
- <Label Text="label 2" Background="hgradient|0:Blue|1:Transparent"/>
- <Label Text="label 3" Background="hgradient|0:Blue|1:Transparent"/>
- <Label Text="label 4" Width="Stretched" Background="hgradient|0:Blue|1:Transparent"/>
- </VerticalStack>
- </Border>
- <Splitter/>
- <Border Fit="true" CornerRadius="10" BorderWidth="1">
- <VerticalStack Margin="10">
- <Button Caption="Button 1" Background="hgradient|0:Red|1:DarkRed" CornerRadius="5"/>
- <Button Caption="Button 2" Background="hgradient|0:Green|1:Blue" CornerRadius="3"/>
- <Button Caption="Button 3" Background="hgradient|0:DarkRed|1:Transparent" CornerRadius="0"/>
- <Button Caption="Button 4" Background="hgradient|0:DarkRed|1:Transparent" CornerRadius="8"/>
- </VerticalStack>
- </Border>
- <Splitter/>
- </HorizontalStack>
- <Widget CornerRadius="5" Height="10" Width="600" Background="vgradient|0:Transparent|0.5:White|1:Transparent"/>
-</VerticalStack>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0"?>
-<GenericStack Orientation="Vertical" Spacing="0"
- Background="{./Background}"
- MouseEnter="{/caption.Foreground=White}"
- MouseLeave="{/caption.Foreground=Grey}">
- <HorizontalStack Left="{./TabOffset}"
- Name="TabTitle"
- HorizontalAlignment="Left"
- Height="{./TabHeight}"
- Width="{./TabWidth}">
- <Label Name="caption" Text="{./Caption}" Foreground="Grey" Width="Stretched"/>
- <Label Text="{./ViewIndex}" Foreground="Green"/>
- <Label Text="{./TabOffset}" Foreground="Red"/>
- <Border CornerRadius="5" BorderWidth="1" Foreground="Transparent" Height="12" Width="12"
- MouseEnter="{Foreground=White}" MouseLeave="{Foreground=Transparent}">
- <Image Focusable="true" Name="Image" Margin="0" Width="Stretched" Height="Stretched" Path="#Crow.Icons.exit2.svg"
- MouseClick="./butCloseTabClick"/>
- </Border>
- </HorizontalStack>
- <Container Margin="20">
- <Container Background="DimGrey" Name="Content"/>
- </Container>
-</GenericStack>
-
<?xml version="1.0"?>
-<Border Foreground="Transparent" Focusable="true" HorizontalAlignment="Left" Height="Fit">
- <HorizontalStack Margin="1" Spacing="3"
- MouseEnter="{Background=LightBlue}"
- MouseLeave="{Background=Transparent}">
+<ListItem HorizontalAlignment="Left" Height="Fit"
+ Selected = "{Background=${ControlHighlight}}"
+ Unselected = "{Background=Transparent}">
+ <HorizontalStack Margin="1" Spacing="3">
<Widget Height="12" Width="20" Background="{}" Margin="0" CornerRadius="5"/>
<Label Text="{}" Margin="0" Width="Stretched"/>
</HorizontalStack>
-</Border>
+</ListItem>