From: Jean-Philippe Bruyère Date: Thu, 15 Apr 2021 04:28:27 +0000 (+0200) Subject: wip X-Git-Tag: v0.9.5-beta~27 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=412e93ade521562145cf602cd340c4485fa15e37;p=jp%2Fcrow.git wip --- diff --git a/Crow/Crow.csproj b/Crow/Crow.csproj index 86b42dab..7004eb0d 100644 --- a/Crow/Crow.csproj +++ b/Crow/Crow.csproj @@ -31,7 +31,7 @@ full - $(DefineConstants);DEBUG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE + $(DefineConstants);DEBUG;TRACE;_DEBUG_DISPOSE;_DEBUG_BINDING;_DEBUG_CLIP_RECTANGLE;_DEBUG_DRAGNDROP true diff --git a/Crow/Default.style b/Crow/Default.style index 3c09d3b9..f482eb0b 100644 --- a/Crow/Default.style +++ b/Crow/Default.style @@ -23,7 +23,7 @@ WindowTitleBarForeground = "White"; MenuBackground = "Jet"; -InactiveTabItem = "Jet"; +InactiveTabItem = "DarkGrey"; Button, CheckBox, RadioButton, ComboBox, Expandable, MessageBox, Popper, Slider, Spinner, TextBox { @@ -292,4 +292,16 @@ ColorSlider { ColorPicker { Height="Fit"; MinimumSize="200,100"; +} +TableRow { + Width="Stretched"; +} +TableHeaderRow { + Height="Fit"; + Width="Stretched";//TODO:Force it to stretched programmatically +} +TableHeaderLabel { + Margin = "1"; + Background = "Jet"; + Foreground = "LightGrey"; } \ No newline at end of file diff --git a/Crow/src/Colors.cs b/Crow/src/Colors.cs index 1318764c..c1152031 100644 --- a/Crow/src/Colors.cs +++ b/Crow/src/Colors.cs @@ -13,7 +13,7 @@ namespace Crow { AliceBlue = 0xF0F8FFFF, AntiqueWhite = 0xFAEBD7FF, - Aqua = 0x00FFFFFF, + //Aqua = 0x00FFFFFF, Aquamarine = 0x7FFFD4FF, Azure = 0xF0FFFFFF, Beige = 0xF5F5DCFF, diff --git a/Crow/src/DebugUtils/DbgEvent.cs b/Crow/src/DebugUtils/DbgEvent.cs index 1c0b79af..c43cc15a 100644 --- a/Crow/src/DebugUtils/DbgEvent.cs +++ b/Crow/src/DebugUtils/DbgEvent.cs @@ -18,8 +18,8 @@ namespace Crow.DebugLogger public bool HasChildEvents => Events != null && Events.Count > 0; public override long Duration => end - begin; public double DurationMS => Math.Round ((double)Duration / Stopwatch.Frequency * 1000.0, 4); - public double BeginMS => Math.Round ((double)begin / Stopwatch.Frequency * 1000.0, 4); - public double EndMS => Math.Round ((double)end / Stopwatch.Frequency * 1000.0, 4); + public double BeginMS => Math.Round ((double)begin / Stopwatch.Frequency, 6); + public double EndMS => Math.Round ((double)end / Stopwatch.Frequency, 6); public virtual bool IsWidgetEvent => false; public virtual bool IsLayoutEvent => false; diff --git a/Crow/src/DebugUtils/DbgWidgetEvent.cs b/Crow/src/DebugUtils/DbgWidgetEvent.cs index ae363999..9b9a2b15 100644 --- a/Crow/src/DebugUtils/DbgWidgetEvent.cs +++ b/Crow/src/DebugUtils/DbgWidgetEvent.cs @@ -23,6 +23,10 @@ namespace Crow.DebugLogger public override Color Color { get { switch (type) { + case DbgEvtType.GOMeasure: + case DbgEvtType.GOSearchLargestChild: + case DbgEvtType.GOSearchTallestChild: + return Colors.HotPink; case DbgEvtType.GOClassCreation: return Colors.DarkSlateGrey; case DbgEvtType.GOInitialization: @@ -32,7 +36,7 @@ namespace Crow.DebugLogger case DbgEvtType.GORegisterClip: return Colors.Turquoise; case DbgEvtType.GOResetClip: - return Colors.DarkRed; + return Colors.DarkSalmon; case DbgEvtType.GORegisterForGraphicUpdate: return Colors.LightPink; case DbgEvtType.GOEnqueueForRepaint: diff --git a/Crow/src/DebugUtils/DbgWidgetRecord.cs b/Crow/src/DebugUtils/DbgWidgetRecord.cs index 0dd676f7..2fde7377 100644 --- a/Crow/src/DebugUtils/DbgWidgetRecord.cs +++ b/Crow/src/DebugUtils/DbgWidgetRecord.cs @@ -21,7 +21,7 @@ namespace Crow.DebugLogger 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 InstanceIndex; public int yIndex;//index in parenting, the whole main graphic tree is one continuous suite public int xLevel;//depth public String Width; @@ -34,10 +34,11 @@ namespace Crow.DebugLogger 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]; + g.InstanceIndex = int.Parse (tmp [1]); + g.yIndex = int.Parse (tmp [2]); + g.xLevel = int.Parse (tmp [3]); + g.Width = tmp [4]; + g.Height = tmp [5]; return g; } diff --git a/Crow/src/DebugUtils/DebugLogger.cs b/Crow/src/DebugUtils/DebugLogger.cs index eb096f80..3a65ad55 100644 --- a/Crow/src/DebugUtils/DebugLogger.cs +++ b/Crow/src/DebugUtils/DebugLogger.cs @@ -104,10 +104,11 @@ namespace Crow lock (logMutex) { chrono.Stop (); if (!startedEvents.ContainsKey (Thread.CurrentThread.ManagedThreadId)) - throw new Exception ("Current thread has no event started"); + throw new Exception ($"Current thread has no event started\n{new System.Diagnostics.StackTrace()}"); + DbgLayoutEvent e = startedEvents[Thread.CurrentThread.ManagedThreadId].Pop () as DbgLayoutEvent; if (e?.type != evtType) - throw new Exception ($"Begin/end event logging mismatch: {e.type}/{evtType}"); + throw new Exception ($"Begin/end event logging mismatch: {e.type}/{evtType}\n{new System.Diagnostics.StackTrace()}"); e.end = chrono.ElapsedTicks; e.SetLQI (lqi.LayoutType, lqi.result, lqi.Slot, lqi.NewSlot); chrono.Start (); @@ -177,23 +178,18 @@ namespace Crow return evt; } - static void parseTree (Widget go, int level = 0, int y = 1) { + static void parseTree (Widget go, int xLevel = 1, int y = 0) { if (go == null) return; go.yIndex = y; - go.xLevel = level; + go.xLevel = xLevel; - 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); - } + if (go is Group gr) { + for (int i = 0; i < gr.Children.Count; i++) + parseTree (gr.Children[i], xLevel + 1, i); + } else if (go is PrivateContainer pc) + parseTree (pc.getTemplateRoot, xLevel + 1); } static void saveEventList (StreamWriter s, List evts, int level = 0) { @@ -235,23 +231,34 @@ namespace Crow #endif } [Conditional("DEBUG_LOG")] - public static void Save(Interface iface, Stream stream) { + public static void Save(Interface iface, Stream stream, int startingWidgetsIndex = -1, bool saveEvents = true) { #if DEBUG_LOG using (StreamWriter writer = new StreamWriter (stream, Encoding.UTF8, 1024, true)) { lock (logMutex) lock (iface.UpdateMutex) { chrono.Stop(); - foreach (Widget go in iface.GraphicTree) - parseTree (go); - writer.WriteLine ("[GraphicObjects]"); - for (int i = 0; i < Widget.GraphicObjects.Count; i++) { - Widget g = Widget.GraphicObjects [i]; - writer.WriteLine ($"{g.GetType ().Name};{g.yIndex};{g.xLevel};{g.Width};{g.Height}"); + if (startingWidgetsIndex >= 0 ) { + foreach (Widget go in iface.GraphicTree) + parseTree (go); + + if (saveEvents) + writer.WriteLine ("[GraphicObjects]"); + for (int i = startingWidgetsIndex; i < Widget.GraphicObjects.Count; i++) { + Widget g = Widget.GraphicObjects [i]; + writer.WriteLine ($"{g.GetType ().Name};{g.instanceIndex};{g.yIndex};{g.xLevel};{g.Width};{g.Height}"); + } } - - writer.WriteLine ("[Events]"); - saveEventList (writer, events); + + if (saveEvents) { + if (startingWidgetsIndex >= 0) + writer.WriteLine ("[Events]"); + saveEventList (writer, events); + } + if (startedEvents.Count > 0) + Console.WriteLine ($"[DebugLogger]Warning: Started events not null when events saved!"); + startedEvents.Clear (); + events.Clear (); chrono.Start(); } } @@ -267,20 +274,24 @@ namespace Crow public static void Load (Stream stream, List events, List widgets) { using (StreamReader reader = new StreamReader (stream)) { - - if (reader.ReadLine () != "[GraphicObjects]") - return; - while (!reader.EndOfStream) { - string l = reader.ReadLine (); - if (l == "[Events]") - break; - DbgWidgetRecord o = DbgWidgetRecord.Parse (l); - o.listIndex = widgets.Count; - widgets.Add (o); + + if (widgets != null) { + if (events != null && reader.ReadLine () != "[GraphicObjects]") + return; + while (!reader.EndOfStream) { + string l = reader.ReadLine (); + if (l == "[Events]") + break; + DbgWidgetRecord o = DbgWidgetRecord.Parse (l); + o.listIndex = widgets.Count; + widgets.Add (o); + } } - Stack startedEvents = new Stack (); + if (events == null) + return; + Stack startedEvents = new Stack (); if (!reader.EndOfStream) { while (!reader.EndOfStream) { int level = 0; @@ -308,12 +319,14 @@ namespace Crow } } startedEvents.Push (evt); - if (evt.type.HasFlag (DbgEvtType.Widget)) { + /*if (evt.type.HasFlag (DbgEvtType.Widget)) { DbgWidgetEvent dwe = evt as DbgWidgetEvent; if (dwe.InstanceIndex >= 0) widgets [dwe.InstanceIndex].Events.Add (evt); - } + }*/ } + startedEvents.Pop(); + } } } diff --git a/Crow/src/EventArgs/ListChangedEventArg.cs b/Crow/src/EventArgs/ListChangedEventArg.cs index 3651e3ba..2d8553b8 100644 --- a/Crow/src/EventArgs/ListChangedEventArg.cs +++ b/Crow/src/EventArgs/ListChangedEventArg.cs @@ -2,6 +2,8 @@ // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; +using System.Collections.Generic; + namespace Crow { public class ListChangedEventArg : EventArgs @@ -14,4 +16,11 @@ namespace Crow Element = element; } } + public class ListClearEventArg : EventArgs + { + public IEnumerable Elements; + public ListClearEventArg (IEnumerable elements) { + Elements = elements; + } + } } diff --git a/Crow/src/IML/CompilerServices.cs b/Crow/src/IML/CompilerServices.cs index fc22d1e1..644902f0 100644 --- a/Crow/src/IML/CompilerServices.cs +++ b/Crow/src/IML/CompilerServices.cs @@ -77,7 +77,7 @@ namespace Crow.IML internal static MethodInfo miGetDataSource = typeof(Widget).GetProperty("DataSource").GetGetMethod (); internal static EventInfo eiLogicalParentChanged = typeof(Widget).GetEvent("LogicalParentChanged"); - internal static MethodInfo miIFaceCreateInstance = typeof(Interface).GetMethod ("CreateInstance", BindingFlags.Instance | BindingFlags.Public); + internal static MethodInfo miIFaceCreateInstance = typeof(Interface).GetMethods().First (m => m.Name == "CreateInstance" && m.IsGenericMethod == false); internal static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate", BindingFlags.Instance | BindingFlags.Public); internal static MethodInfo miAddITemp = typeof(Dictionary).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) }); diff --git a/Crow/src/IObservableList.cs b/Crow/src/IObservableList.cs index 4fab1e81..4c8ae236 100644 --- a/Crow/src/IObservableList.cs +++ b/Crow/src/IObservableList.cs @@ -10,7 +10,7 @@ namespace Crow event EventHandler ListAdd; event EventHandler ListRemove; event EventHandler ListEdit; - event EventHandler ListClear; + event EventHandler ListClear; void Insert (); void Remove (); diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 5fc9d2b9..60f0e221 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -721,6 +721,14 @@ namespace Crow return tmp; } } + public T LoadIMLFragment (string imlFragment) where T : Widget + { + lock (UpdateMutex) { + T tmp = CreateITorFromIMLFragment (imlFragment).CreateInstance(); + AddWidget (tmp); + return tmp; + } + } /// /// Create an instantiator bound to this interface from the IML fragment /// @@ -746,6 +754,18 @@ namespace Crow return tmp; } } + public T Load (string path) where T : Widget + { + lock (UpdateMutex) { + DbgLogger.StartEvent (DbgEvtType.IFaceLoad); + + T tmp = CreateInstance (path); + AddWidget (tmp); + + DbgLogger.EndEvent (DbgEvtType.IFaceLoad); + return tmp; + } + } /// /// Create an instance of a GraphicObject linked to this interface but not added to the GraphicTree /// @@ -753,6 +773,8 @@ namespace Crow /// path of the iml file to load public virtual Widget CreateInstance (string path) => GetInstantiator (path).CreateInstance (); + public virtual T CreateInstance (string path) where T : Widget + => GetInstantiator (path).CreateInstance (); /// /// Fetch instantiator from cache or create it. /// @@ -985,13 +1007,6 @@ namespace Crow ctx.PushGroup (); - for (int i = 0; i < clipping.NumRectangles; i++) - ctx.Rectangle (clipping.GetRectangle (i)); - - ctx.ClipPreserve (); - ctx.Operator = Operator.Clear; - ctx.Fill (); - ctx.Operator = Operator.Over; for (int i = GraphicTree.Count -1; i >= 0 ; i--){ Widget p = GraphicTree[i]; @@ -1031,6 +1046,15 @@ namespace Crow #endif ctx.PopGroupToSource (); + + for (int i = 0; i < clipping.NumRectangles; i++) + ctx.Rectangle (clipping.GetRectangle (i)); + + ctx.ClipPreserve (); + ctx.Operator = Operator.Clear; + ctx.Fill (); + ctx.Operator = Operator.Over; + ctx.Paint (); @@ -1698,10 +1722,10 @@ namespace Crow if (e.LayoutType == LayoutingType.X) { if (ttc.Slot.Right > clientRectangle.Right) - ttc.Left = clientRectangle.Right - ttc.Slot.Width; + ttc.Left = MousePosition.X - ttc.Slot.Width - 10; }else if (e.LayoutType == LayoutingType.Y) { if (ttc.Slot.Bottom > clientRectangle.Bottom) - ttc.Top = clientRectangle.Bottom - ttc.Slot.Height; + ttc.Top = MousePosition.Y - ttc.Slot.Height - 10; }/* if (ttc.Slot.Height < tc.ClientRectangle.Height) { if (PopDirection.HasFlag (Alignment.Bottom)) { diff --git a/Crow/src/ObservableList.cs b/Crow/src/ObservableList.cs index 6d7b71c7..8cb64806 100644 --- a/Crow/src/ObservableList.cs +++ b/Crow/src/ObservableList.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Crow { @@ -21,7 +22,7 @@ namespace Crow public event EventHandler ListAdd; public event EventHandler ListRemove; public event EventHandler ListEdit; - public event EventHandler ListClear; + public event EventHandler ListClear; #endregion public ObservableList() : base () {} @@ -57,13 +58,17 @@ namespace Crow } public new void Remove (T elem) { int idx = IndexOf (elem); - base.RemoveAt (idx); + if (idx < 0) + Console.WriteLine ($"ObsList.Remove idx < 0: {new System.Diagnostics.StackTrace()}"); + else + base.RemoveAt (idx); ListRemove.Raise (this, new ListChangedEventArg (idx, elem)); } public new void Clear () { + ListClearEventArg eventArg = new ListClearEventArg (this.Cast()); base.Clear (); - ListClear.Raise (this, null); + ListClear.Raise (this, eventArg); } public void Remove () { if (selectedIndex < 0) diff --git a/Crow/src/Widgets/Border.cs b/Crow/src/Widgets/Border.cs index b308f00f..c702d9ac 100644 --- a/Crow/src/Widgets/Border.cs +++ b/Crow/src/Widgets/Border.cs @@ -87,19 +87,19 @@ namespace Crow #endregion #region GraphicObject override - [XmlIgnore]public override Rectangle ClientRectangle { + /*[XmlIgnore]public override Rectangle ClientRectangle { get { Rectangle cb = base.ClientRectangle; cb.Inflate (- BorderWidth); return cb; } - } + }*/ - public override int measureRawSize (LayoutingType lt) + /*public override int measureRawSize (LayoutingType lt) { int tmp = base.measureRawSize (lt); return tmp < 0 ? tmp : tmp + 2 * BorderWidth; - } + }*/ protected override void onDraw (Context gr) { drawborder2 (gr); diff --git a/Crow/src/Widgets/DockStack.cs b/Crow/src/Widgets/DockStack.cs index f0eaa176..df1cc6f1 100644 --- a/Crow/src/Widgets/DockStack.cs +++ b/Crow/src/Widgets/DockStack.cs @@ -325,14 +325,14 @@ namespace Crow dw.savedSlot = Rectangle.Parse (getConfAttrib (conf, ref i)); dw.wasResizable = Boolean.Parse (getConfAttrib (conf, ref i)); dw.Resizable = false; - - dw.IsDocked = true; + dw.DataSource = dataSource; return dw; } void importConfig (string conf, ref int i, object dataSource) { if (conf [i++] != '(') - return; + return; + DockWindow dw = null; while (i < conf.Length - 4) { string sc = conf.Substring (i, 4); i += 4; @@ -343,12 +343,17 @@ namespace Crow tv.Height = Measure.Parse (getConfAttrib (conf, ref i)); this.AddChild (tv); i++; - while (conf [i] != ')') - tv.AddItem (importDockWinConfig (conf, ref i, dataSource)); + while (conf [i] != ')') { + dw = importDockWinConfig (conf, ref i, dataSource); + tv.AddItem (dw); + dw.IsDocked = true; + } i++; break; - case "WIN;": - this.AddChild (importDockWinConfig (conf, ref i, dataSource)); + case "WIN;": + dw = importDockWinConfig (conf, ref i, dataSource); + this.AddChild (dw); + dw.IsDocked = true; break; case "STK;": DockStack ds = new DockStack (IFace); diff --git a/Crow/src/Widgets/DockWindow.cs b/Crow/src/Widgets/DockWindow.cs index 4c99c637..096ef0e1 100644 --- a/Crow/src/Widgets/DockWindow.cs +++ b/Crow/src/Widgets/DockWindow.cs @@ -31,10 +31,14 @@ namespace Crow return; isDocked = value; NotifyValueChangedAuto (isDocked); - NotifyValueChanged ("IsFloating", !isDocked); + NotifyValueChanged ("IsFloating", IsFloating); + NotifyValueChanged ("IsDockedInTabView", IsDockedInTabView); + NotifyValueChanged ("IsDockedInStack", IsDockedInStack); } } - [XmlIgnore] public bool IsFloating { get { return !isDocked; }} + [XmlIgnore] public bool IsFloating => !isDocked; + [XmlIgnore] public bool IsDockedInTabView => LogicalParent is TabView; + [XmlIgnore] public bool IsDockedInStack => Parent is DockStack; public Alignment DockingPosition { get { return docking; } diff --git a/Crow/src/Widgets/HorizontalStack.cs b/Crow/src/Widgets/HorizontalStack.cs index 13676e30..b4fbea09 100644 --- a/Crow/src/Widgets/HorizontalStack.cs +++ b/Crow/src/Widgets/HorizontalStack.cs @@ -2,26 +2,23 @@ // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) - namespace Crow { /// /// group control stacking its children horizontally /// public class HorizontalStack : GenericStack - { + { #region CTOR - protected HorizontalStack () : base(){} - public HorizontalStack(Interface iface) : base(iface) - { - } + protected HorizontalStack() : base() { } + public HorizontalStack(Interface iface, string style = null) : base(iface, style) { } #endregion - [XmlIgnore] - public override Orientation Orientation - { - get => Orientation.Horizontal; - set { base.Orientation = Orientation.Horizontal; } - } - } + [XmlIgnore] + public override Orientation Orientation + { + get => Orientation.Horizontal; + set { base.Orientation = Orientation.Horizontal; } + } + } } diff --git a/Crow/src/Widgets/Label.cs b/Crow/src/Widgets/Label.cs index f8574959..c8b4b238 100644 --- a/Crow/src/Widgets/Label.cs +++ b/Crow/src/Widgets/Label.cs @@ -609,6 +609,8 @@ namespace Crow } public override int measureRawSize(LayoutingType lt) { + DbgLogger.StartEvent(DbgEvtType.GOMeasure, this, lt); + if ((bool)lines?.IsEmpty) getLines (); @@ -624,6 +626,7 @@ namespace Crow measureTextBounds (gr); } } + DbgLogger.EndEvent(DbgEvtType.GOMeasure); return Margin * 2 + (lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width); } diff --git a/Crow/src/Widgets/MenuItem.cs b/Crow/src/Widgets/MenuItem.cs index d56f5213..b00101a5 100644 --- a/Crow/src/Widgets/MenuItem.cs +++ b/Crow/src/Widgets/MenuItem.cs @@ -151,8 +151,10 @@ namespace Crow if (hasClick) base.onMouseClick (sender, e); - if (!IsOpened) - (LogicalParent as Menu).AutomaticOpening = false; + if (!IsOpened) + if (LogicalParent is Menu m) + m.AutomaticOpening = false; + } void closeMenu () { MenuItem tmp = LogicalParent as MenuItem; diff --git a/Crow/src/Widgets/OldLabel.cs b/Crow/src/Widgets/OldLabel.cs index b7d62c1f..17179ae3 100644 --- a/Crow/src/Widgets/OldLabel.cs +++ b/Crow/src/Widgets/OldLabel.cs @@ -482,6 +482,8 @@ namespace Crow { } protected override void onDraw (Context gr) { + DbgLogger.StartEvent(DbgEvtType.GODraw, this); + base.onDraw (gr); gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); @@ -681,6 +683,7 @@ namespace Crow { } gr.Restore (); + DbgLogger.EndEvent (DbgEvtType.GODraw); } #endregion diff --git a/Crow/src/Widgets/TabView.cs b/Crow/src/Widgets/TabView.cs index 68538e8d..8872b92b 100644 --- a/Crow/src/Widgets/TabView.cs +++ b/Crow/src/Widgets/TabView.cs @@ -27,6 +27,9 @@ namespace Crow orientation = value; NotifyValueChangedAuto (orientation); NotifyValueChanged ("OppositeOrientation", OppositeOrientation); + NotifyValueChanged ("TabWidth", TabWidth); + NotifyValueChanged ("TabHeight", TabHeight); + RegisterForLayouting (LayoutingType.Sizing); } } public Orientation OppositeOrientation @@ -34,7 +37,28 @@ namespace Crow public Measure TabWidth => orientation == Orientation.Vertical ? Measure.Stretched : Measure.Fit; public Measure TabHeight - => orientation == Orientation.Horizontal ? Measure.Stretched : Measure.Fit; + => orientation == Orientation.Horizontal ? Measure.Stretched : Measure.Fit; + + public override void RemoveItem(Widget g, bool disposeChild = true) + { + if (SelectedItem != g) { + base.RemoveItem(g, disposeChild); + return; + } + + int idx = Items.IndexOf (g); + base.RemoveItem(g, disposeChild); + + if (idx >= Items.Count) + selectedItemContainer = Items.LastOrDefault(); + else + selectedItemContainer = Items[idx]; + + if (selectedItemContainer == null) + return; + selectedItemContainer.IsVisible = true; + SelectedItem = selectedItemContainer; + } } } diff --git a/Crow/src/Widgets/TemplatedGroup.cs b/Crow/src/Widgets/TemplatedGroup.cs index aea5c78d..a1ac759c 100644 --- a/Crow/src/Widgets/TemplatedGroup.cs +++ b/Crow/src/Widgets/TemplatedGroup.cs @@ -126,7 +126,7 @@ namespace Crow { } object selectedItem; - Widget selectedItemContainer = null; + protected Widget selectedItemContainer = null; [XmlIgnore]public virtual object SelectedItem{ get => selectedItem; @@ -231,7 +231,7 @@ namespace Crow { itemsContainer.Children [e.Index].DataSource = e.Element; } - void Ol_ListClear (object sender, ListChangedEventArg e) { + void Ol_ListClear (object sender, ListClearEventArg e) { cancelLoadingThread (); if (this.isPaged) { throw new NotImplementedException (); @@ -254,18 +254,20 @@ namespace Crow { g.LogicalParent = this; NotifyValueChanged ("HasChildren", true); } - public virtual void RemoveItem(Widget g) - { - g.LogicalParent = null; - itemsContainer.DeleteChild (g); + public virtual void RemoveItem(Widget g, bool disposeChild = true) + { + if (disposeChild) + itemsContainer.DeleteChild (g); + else + itemsContainer.RemoveChild (g); if (itemsContainer.Children.Count == 0) NotifyValueChanged ("HasChildren", false); } public virtual void ClearItems() { - selectedItemContainer = null; - SelectedItem = null; + /*selectedItemContainer = null; + SelectedItem = null;*/ itemsContainer.ClearChildren (); NotifyValueChanged ("HasChildren", false); @@ -455,9 +457,9 @@ namespace Crow { iTemp = ItemTemplates ["default"]; } if (loadingThread == null) - Monitor.Enter(IFace.LayoutMutex); + Monitor.Enter(IFace.UpdateMutex); else { - while (!Monitor.TryEnter(IFace.LayoutMutex)) { + while (!Monitor.TryEnter(IFace.UpdateMutex)) { if (loadingThread.cancelRequested) return; Thread.Sleep(1); @@ -472,7 +474,7 @@ namespace Crow { // if (isPaged) g.LogicalParent = this; g.MouseClick += itemClick; - Monitor.Exit (IFace.LayoutMutex); + Monitor.Exit (IFace.UpdateMutex); if (iTemp.Expand != null) { Expandable e = g as Expandable; @@ -588,14 +590,14 @@ namespace Crow { /*if (dataParent is IValueChange vc) { }*/ - if (datas is IObservableList ol) { + /*if (datas is IObservableList ol) { ol.ListAdd += (sender, e) => loadItem (e.Element, itemsContainer, dataTest); ol.ListRemove += (sender, e) => itemsContainer.DeleteChild (e.Index); ol.ListEdit += (sender, e) => itemsContainer.Children [e.Index].DataSource = e.Element; ol.ListClear += (sender, e) => { lock (IFace.UpdateMutex) itemsContainer.ClearChildren ();}; - } + }*/ } void onDatasChanged (object sender, ValueChangeEventArgs e) { diff --git a/Crow/src/Widgets/Wrapper.cs b/Crow/src/Widgets/Wrapper.cs index a0fac536..ead1f533 100644 --- a/Crow/src/Widgets/Wrapper.cs +++ b/Crow/src/Widgets/Wrapper.cs @@ -215,7 +215,7 @@ namespace Crow return; } RegisterForLayouting (LayoutingType.ArrangeChildren); - raiseLayoutChanged (new LayoutingEventArgs (layoutType)); + raiseLayoutChanged (layoutType); } #endregion } diff --git a/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj b/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj index 057ee24c..54413ba6 100644 --- a/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj +++ b/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj @@ -7,7 +7,7 @@ - + Dbg.%(Filename)%(Extension) diff --git a/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs b/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs index 19666ee2..6af3f6df 100644 --- a/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs +++ b/Samples/DebugLogAnalyzer/src/DbgEventWidget.cs @@ -10,6 +10,18 @@ using DebugLogAnalyzer; namespace Crow { + public class DbgEventView : TemplatedContainer { + DbgEvent evt; + public DbgEvent Event { + get => evt; + set { + if (evt == value) + return; + evt = value; + NotifyValueChangedAuto (evt); + } + } + } public class DbgEventWidget : Widget { public DbgEventWidget (){} diff --git a/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs b/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs index 1273c9e6..d39cc62a 100644 --- a/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs +++ b/Samples/DebugLogAnalyzer/src/DbgLogViewer.cs @@ -300,7 +300,7 @@ namespace Crow double penX = 5.0 * g.xLevel + cb.Left; - if (g.yIndex == 0) + if (g.xLevel == 0) gr.SetSource (Crow.Colors.LightSalmon); else if (currentLine == g.listIndex) gr.SetSource(Colors.RoyalBlue); @@ -434,11 +434,17 @@ namespace Crow ctxR.Width = Math.Max (1, ctxR.Width); ctx.Rectangle (ctxR); - //ctx.SetSourceColor (Color.LightYellow); - ctx.SetSource (Colors.Jet); + ctx.SetSource (0.0,0.2,0.8,0.15); + //ctx.SetSource (Colors.Jet); ctx.Fill(); ctx.Operator = Cairo.Operator.Over; + str = $"{ticksToMS(Math.Abs (selEnd - selStart))} (ms)"; + + ctx.MoveTo (ctxR.Center.X - ctx.TextExtents (str).Width / 2, ctxR.Y + fe.Height); + ctx.SetSource (Colors.Black); + ctx.ShowText (str); + } public override void OnLayoutChanges (LayoutingType layoutType) { @@ -469,7 +475,7 @@ namespace Crow int lastLine = hoverLine; updateMouseLocalPos (e.Position); - if (IFace.IsDown (Glfw.MouseButton.Left) && selStart >= 0) + if ((IFace.IsDown (Glfw.MouseButton.Left) || IFace.IsDown (Glfw.MouseButton.Middle)) && selStart >= 0) selEnd = hoverTick; else if (IFace.IsDown(Glfw.MouseButton.Right)) { if (lastTick >= 0 && hoverTick >= 0) @@ -479,28 +485,30 @@ namespace Crow updateMouseLocalPos (e.Position); } else { HoverWidget = (hoverLine < 0 || hoverLine >= widgets.Count) ? null : widgets [hoverLine]; - HoverEvent = hoverWidget?.Events.FirstOrDefault (ev => ev.begin <= hoverTick && ev.end >= hoverTick); - Task.Run (() => findHoverEvent (hoverWidget, hoverTick)); + //HoverEvent = hoverWidget?.Events.FirstOrDefault (ev => ev.begin <= hoverTick && ev.end >= hoverTick); + double tickPerPixel = (double)visibleTicks / ClientRectangle.Width; + //Console.WriteLine ($"ticks per pixel: {tickPerPixel}"); + Task.Run (() => findHoverEvent (hoverWidget, hoverTick, (int)tickPerPixel)); } RegisterForRepaint(); e.Handled = true; base.onMouseMove (sender, e); - } - void findHoverEvent (DbgWidgetRecord widget, long tick) { - DbgEvent tmp = widget?.Events.FirstOrDefault (ev => ev.begin <= tick && ev.end >= tick); + } + void findHoverEvent (DbgWidgetRecord widget, long tick, long precision = 0) { + DbgEvent tmp = widget?.Events.FirstOrDefault (ev => ev.begin - precision <= tick && ev.end + precision >= tick); if (tmp == null) { - tmp = Events.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin <= tick && ev.end >= tick).FirstOrDefault(); + tmp = Events.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin - precision <= tick && ev.end + precision >= tick).FirstOrDefault(); while(tmp != null) { - DbgEvent che = tmp.Events?.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin <= tick && ev.end >= tick).FirstOrDefault(); + DbgEvent che = tmp.Events?.Where(e=>e.type.HasFlag(DbgEvtType.IFace)).Where (ev => ev.begin - precision <= tick && ev.end + precision >= tick).FirstOrDefault(); if (che == null) break; tmp = che; } } else { while(tmp != null) { - DbgEvent che = tmp.Events?.OfType()?.Where(ev=>ev.InstanceIndex == widget.listIndex && ev.begin <= tick && ev.end >= tick).FirstOrDefault(); + DbgEvent che = tmp.Events?.OfType()?.Where(ev=>ev.InstanceIndex == widget.listIndex && ev.begin - precision <= tick && ev.end + precision >= tick).FirstOrDefault(); if (che == null) break; tmp = che; @@ -510,21 +518,23 @@ namespace Crow } public override void onMouseClick(object sender, MouseButtonEventArgs e) { - if (e.Button == Glfw.MouseButton.Left && selEnd < 0) { - currentTick = hoverTick; - currentLine = hoverLine; - CurrentWidget = hoverWidget; - CurrentEvent = hoverEvent; + if (e.Button == Glfw.MouseButton.Left) { + if (selEnd < 0) { + currentTick = hoverTick; + currentLine = hoverLine; + CurrentWidget = hoverWidget; + CurrentEvent = hoverEvent; + } + selStart = -1; + selEnd = -1; } - selStart = -1; - selEnd = -1; e.Handled = true; base.onMouseClick(sender, e); } public override void onMouseDown (object sender, MouseButtonEventArgs e) { - if (e.Button == Glfw.MouseButton.Left) { + if (e.Button == Glfw.MouseButton.Left || e.Button == Glfw.MouseButton.Middle) { selStart = hoverTick; selEnd = -1; } @@ -561,7 +571,9 @@ namespace Crow if (IFace.Shift) ScrollX -= (int)((double)(e.Delta * MouseWheelSpeed) / xScale); - else if (IFace.Ctrl) { + else if (IFace.Ctrl) + ScrollY -= e.Delta * MouseWheelSpeed; + else { if (e.Delta > 0) { XScale *= 2.0; } else { @@ -569,8 +581,7 @@ namespace Crow XScale *= 0.5; } ScrollX = (long)(hoverTick - (long)((double)Math.Max(0, mousePos.X - (long)leftMargin) / xScale) - minTicks); - }else - ScrollY -= e.Delta * MouseWheelSpeed; + } } public override void onKeyDown (object sender, KeyEventArgs e) diff --git a/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs b/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs index 5432b05e..c6920ca5 100644 --- a/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs +++ b/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using CrowDbgShared; using System.Collections.Generic; using Crow.DebugLogger; +using System.Linq; namespace Crow { @@ -27,7 +28,10 @@ namespace Crow Type dbgIfaceType; Action delResize; Func delMouseMove; + Func delMouseWheelChanged; Func delMouseDown, delMouseUp; + Func delKeyPress; + Func delKeyDown, delKeyUp; Action delResetDirtyState; Action delResetDebugger; Action delSaveDebugLog; @@ -178,12 +182,24 @@ namespace Crow delMouseMove = (Func)Delegate.CreateDelegate(typeof(Func), dbgIFace, dbgIfaceType.GetMethod("OnMouseMove")); + delMouseWheelChanged = (Func)Delegate.CreateDelegate(typeof(Func), + dbgIFace, dbgIfaceType.GetMethod("OnMouseWheelChanged")); + + delMouseDown = (Func)Delegate.CreateDelegate(typeof(Func), dbgIFace, dbgIfaceType.GetMethod("OnMouseButtonDown")); delMouseUp = (Func)Delegate.CreateDelegate(typeof(Func), dbgIFace, dbgIfaceType.GetMethod("OnMouseButtonUp")); + delKeyDown = (Func)Delegate.CreateDelegate(typeof(Func), + dbgIFace, dbgIfaceType.GetMethod("OnKeyDown")); + delKeyUp = (Func)Delegate.CreateDelegate(typeof(Func), + dbgIFace, dbgIfaceType.GetMethod("OnKeyUp")); + delKeyPress = (Func)Delegate.CreateDelegate(typeof(Func), + dbgIFace, dbgIfaceType.GetMethod("OnKeyPress")); + + delGetSurfacePointer = (IntPtrGetterDelegate)Delegate.CreateDelegate(typeof(IntPtrGetterDelegate), dbgIFace, dbgIfaceType.GetProperty("SurfacePointer").GetGetMethod()); delSetSource = (Action)Delegate.CreateDelegate(typeof(Action), @@ -218,19 +234,60 @@ namespace Crow } public override bool CacheEnabled { get => true; set => base.CacheEnabled = true; } + public override void onKeyDown(object sender, KeyEventArgs e) + { + if (initialized) { + try + { + e.Handled = delKeyDown (e.Key); + } + catch (System.Exception ex) + { + Console.WriteLine($"[Error][DebugIFace key down]{ex}"); + } + } + base.onKeyDown(sender, e); + } + public override void onKeyUp(object sender, KeyEventArgs e) + { + if (initialized) { + try + { + e.Handled = delKeyUp (e.Key); + } + catch (System.Exception ex) + { + Console.WriteLine($"[Error][DebugIFace key up]{ex}"); + } + } + base.onKeyUp(sender, e); + } + public override void onKeyPress(object sender, KeyPressEventArgs e) + { + if (initialized) { + try + { + e.Handled = delKeyPress (e.KeyChar); + } + catch (System.Exception ex) + { + Console.WriteLine($"[Error][DebugIFace key press]{ex}"); + } + } + base.onKeyPress(sender, e); + } public override void onMouseMove(object sender, MouseMoveEventArgs e) { if (initialized) { try { Point m = ScreenPointToLocal (e.Position); - delMouseMove (m.X, m.Y); + e.Handled = delMouseMove (m.X, m.Y); } catch (System.Exception ex) { Console.WriteLine($"[Error][DebugIFace mouse move]{ex}"); - } - e.Handled = true; + } } base.onMouseMove(sender, e); } @@ -239,13 +296,12 @@ namespace Crow if (initialized) { try { - delMouseDown (e.Button); + e.Handled = delMouseDown (e.Button); } catch (System.Exception ex) { Console.WriteLine($"[Error][DebugIFace mouse down]{ex}"); - } - e.Handled=true; + } } base.onMouseDown (sender, e); } @@ -254,16 +310,29 @@ namespace Crow if (initialized) { try { - delMouseUp (e.Button); + e.Handled = delMouseUp (e.Button); } catch (System.Exception ex) { Console.WriteLine($"[Error][DebugIFace mouse up]{ex}"); - } - e.Handled=true; + } } base.onMouseUp (sender, e); } + public override void onMouseWheel(object sender, MouseWheelEventArgs e) + { + if (initialized) { + try + { + e.Handled = delMouseWheelChanged (e.Delta); + } + catch (System.Exception ex) + { + Console.WriteLine($"[Error][DebugIFace mouse wheel change]{ex}"); + } + } + base.onMouseWheel(sender, e); + } protected override void RecreateCache() { @@ -286,22 +355,52 @@ namespace Crow } + int firstWidgetIndexToGet = 0; void getLog () { + DebugLogAnalyzer.Program dla = IFace as DebugLogAnalyzer.Program; + using (Stream stream = new MemoryStream (1024)) { Type debuggerType = crowAssembly.GetType("Crow.DbgLogger"); - debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(Stream)}).Invoke(null, new object[] {dbgIFace, stream}); + MethodInfo miSave = debuggerType.GetMethod("Save", + new Type[] { + dbgIfaceType, + typeof(Stream), + typeof(int), + typeof(bool) + }); + + + widgets = new List(); + events = new List(); + miSave.Invoke(null, new object[] {dbgIFace, stream, firstWidgetIndexToGet, true}); //debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(string)}).Invoke(null, new object[] {dbgIFace, "debug.log"}); //delSaveDebugLog(dbgIFace, "debug.log"); stream.Seek(0, SeekOrigin.Begin); - events = new List(); - widgets = new List(); DbgLogger.Load (stream, events, widgets); - //DbgLogger.Load ("debug.log", events, widgets); - DebugLogAnalyzer.Program dla = IFace as DebugLogAnalyzer.Program; - dla.Widgets = widgets; - dla.Events = events; + + lock (dla.UpdateMutex) { + for (int i = 0; i < widgets.Count; i++) { + widgets[i].listIndex = dla.Widgets.Count; + dla.Widgets.Add (widgets[i]); + } + for (int i = 0; i < events.Count; i++) { + dla.Events.Add (events[i]); + updateWidgetEvents (dla.Widgets, events[i]); + } + } + firstWidgetIndexToGet += widgets.Count; + if (widgets.Count > 0 && firstWidgetIndexToGet != widgets.Last().InstanceIndex + 1) + Debugger.Break (); } } + void updateWidgetEvents (List widgets, DbgEvent evt) { + if (evt is DbgWidgetEvent we) + widgets.FirstOrDefault (w => w.InstanceIndex == we.InstanceIndex)?.Events.Add (we); + if (evt.Events == null) + return; + foreach (DbgEvent e in evt.Events) + updateWidgetEvents (widgets, e); + } public virtual object GetScreenCoordinates () => ScreenCoordinates(Slot).TopLeft; } diff --git a/Samples/DebugLogAnalyzer/src/Program.cs b/Samples/DebugLogAnalyzer/src/Program.cs index 7da9f5a1..a2711dda 100644 --- a/Samples/DebugLogAnalyzer/src/Program.cs +++ b/Samples/DebugLogAnalyzer/src/Program.cs @@ -11,6 +11,7 @@ using Crow.Text; using System.Collections.Generic; using Encoding = System.Text.Encoding; using Crow.DebugLogger; +using System.Linq; namespace DebugLogAnalyzer { @@ -41,7 +42,8 @@ namespace DebugLogAnalyzer /*TreeView tv = FindByName("dbgTV") as TreeView; dbgTreeViewScroller = tv.FindByNameInTemplate ("scroller1") as Scroller;*/ - + if (DebugLogOnStartup) + DebugLogRecording = true; if (!File.Exists (CurrentFile)) newFile (); @@ -50,20 +52,52 @@ namespace DebugLogAnalyzer reloadFromFile (); } + + public override void UpdateFrame() + { + base.UpdateFrame(); + + } + - List events = new List(); - List widgets = new List(); - DbgEvent curEvent = new DbgEvent(); + ObservableList events = new ObservableList(); + ObservableList widgets = new ObservableList(); + DbgEvent curEvent; + bool disableCurrentEventHistory; + Stack CurrentEventHistoryForward = new Stack(); + Stack CurrentEventHistoryBackward = new Stack(); DbgWidgetRecord curWidget = new DbgWidgetRecord(); bool debugLogRecording; - Scroller dbgTreeViewScroller; int targetTvScroll = -1; + public string[] AllEventTypes => Enum.GetNames (typeof(DbgEvtType)); + string searchEventType; + DbgWidgetRecord searchWidget; + public string SearchEventType { + get => searchEventType; + set { + if (searchEventType == value) + return; + searchEventType = value; + NotifyValueChanged (searchEventType); + } + } + + public DbgWidgetRecord SearchWidget { + get => searchWidget; + set { + if (searchWidget == value) + return; + searchWidget = value; + NotifyValueChanged (searchWidget); + } + } public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, CMDShowLeftPane, - CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions; + CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions, + CMDGotoParentEvent, CMDEventHistoryForward, CMDEventHistoryBackward; public CommandGroup EventCommands, DirectoryCommands; public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs); void initCommands () @@ -78,8 +112,12 @@ namespace DebugLogAnalyzer CMDCopy = new Command ("Copy", new Action (() => copy ()), "#Icons.copy-file.svg", false); CMDPaste= new Command ("Paste", new Action (() => paste ()), "#Icons.paste-on-document.svg", false); + CMDGotoParentEvent = new Command("parent", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }, null, false); + CMDEventHistoryBackward = new Command("back.", currentEventHistoryGoBack, null, false); + CMDEventHistoryForward = new Command("forw.", currentEventHistoryGoForward, null, false); + EventCommands = new CommandGroup( - new Command("Goto parent event", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }) + CMDGotoParentEvent, CMDEventHistoryBackward, CMDEventHistoryForward ); DirectoryCommands = new CommandGroup( new Command("Set as root directory", ()=> { CurrentEvent = CurrentEvent?.parentEvent; }) @@ -100,7 +138,7 @@ namespace DebugLogAnalyzer NotifyValueChanged(CrowDbgAssemblyLocation); } } - public List Events { + public ObservableList Events { get => events; set { if (events == value) @@ -109,7 +147,7 @@ namespace DebugLogAnalyzer NotifyValueChanged (nameof (Events), events); } } - public List Widgets { + public ObservableList Widgets { get => widgets; set { if (widgets == value) @@ -118,18 +156,83 @@ namespace DebugLogAnalyzer NotifyValueChanged (nameof (Widgets), widgets); } } + /*IEnumerable widgetEvents (DbgWidgetRecord wr, DbgEvent evt) { + if (evt is DbgWidgetEvent we && we.InstanceIndex == wr.InstanceIndex) + yield return we; + if (evt.Events != null) { + foreach (DbgEvent e in evt.Events) + foreach (DbgWidgetEvent ye in widgetEvents (wr, e)) + yield return ye; + } + } + IEnumerable currentWidgetEvents; + + public IEnumerable CurrentWidgetEvents { + get => currentWidgetEvents; + set { + currentWidgetEvents = value; + NotifyValueChanged (currentWidgetEvents); + curWidget.Events = new List (currentWidgetEvents); + } + } + IEnumerable getCurrentWidgetEvents () { + if (CurrentWidget == null) + yield return null; + else { + foreach (DbgEvent evt in Events) + foreach (DbgWidgetEvent dwe in widgetEvents (CurrentWidget, evt)) + yield return dwe; + } + }*/ + + public DbgEvent CurrentEvent { get => curEvent; set { if (curEvent == value) return; + + if (!disableCurrentEventHistory) { + CurrentEventHistoryForward.Clear (); + CMDEventHistoryForward.CanExecute = false; + if (!(value == null || curEvent == null)) { + CurrentEventHistoryBackward.Push (curEvent); + CMDEventHistoryBackward.CanExecute = true; + } + } curEvent = value; + NotifyValueChanged (nameof (CurrentEvent), curEvent); NotifyValueChanged ("CurEventChildEvents", curEvent?.Events); - + if (CurrentEvent != null && CurrentEvent.parentEvent != null) + CMDGotoParentEvent.CanExecute = true; + else + CMDGotoParentEvent.CanExecute = false; + } + } + void currentEventHistoryGoBack () { + disableCurrentEventHistory = true; + if (CurrentEvent != null) { + CurrentEventHistoryForward.Push (CurrentEvent); + CMDEventHistoryForward.CanExecute = true; } + CurrentEvent = CurrentEventHistoryBackward.Pop (); + CMDEventHistoryBackward.CanExecute = CurrentEventHistoryBackward.Count > 0; + + disableCurrentEventHistory = false; + } + + void currentEventHistoryGoForward () { + disableCurrentEventHistory = true; + CurrentEventHistoryBackward.Push (CurrentEvent); + CMDEventHistoryBackward.CanExecute = true; + CurrentEvent = CurrentEventHistoryForward.Pop (); + CMDEventHistoryForward.CanExecute = CurrentEventHistoryForward.Count > 0; + + disableCurrentEventHistory = false; } + public DbgWidgetRecord CurrentWidget { get => curWidget; set { @@ -138,8 +241,7 @@ namespace DebugLogAnalyzer curWidget = value; NotifyValueChanged (nameof (CurrentWidget), curWidget); NotifyValueChanged ("CurWidgetRootEvents", curWidget?.RootEvents); - NotifyValueChanged ("CurWidgetEvents", curWidget?.Events); - + NotifyValueChanged ("CurrentWidgetEvents", curWidget?.Events); } } public List CurWidgetRootEvents => curWidget == null? new List() : curWidget.RootEvents; @@ -192,7 +294,16 @@ namespace DebugLogAnalyzer debugLogRecording = value; NotifyValueChanged(debugLogRecording); } - } + } + public bool DebugLogOnStartup { + get => Configuration.Global.Get (nameof(DebugLogOnStartup)); + set { + if (DbgLogger.ConsoleOutput != value) + return; + Configuration.Global.Set (nameof(DebugLogOnStartup), value); + NotifyValueChanged(DebugLogOnStartup); + } + } const string _defaultFileName = "unnamed.txt"; diff --git a/Samples/DebugLogAnalyzer/ui/ComboBox.template b/Samples/DebugLogAnalyzer/ui/ComboBox.template new file mode 100644 index 00000000..1b8e439c --- /dev/null +++ b/Samples/DebugLogAnalyzer/ui/ComboBox.template @@ -0,0 +1,30 @@ + + + diff --git a/Samples/DebugLogAnalyzer/ui/DbgEventTreeItems.itemp b/Samples/DebugLogAnalyzer/ui/DbgEventTreeItems.itemp index 96de2dc6..0dd44c74 100644 --- a/Samples/DebugLogAnalyzer/ui/DbgEventTreeItems.itemp +++ b/Samples/DebugLogAnalyzer/ui/DbgEventTreeItems.itemp @@ -19,7 +19,7 @@ MouseEnter="{Background=LightGrey}" MouseLeave="{Background=Transparent}"/>