]> O.S.I.I.S - jp/crow.git/commitdiff
Debug logger improvments and visualization
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 18 Jun 2020 20:22:26 +0000 (22:22 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 18 Jun 2020 20:22:26 +0000 (22:22 +0200)
Crow/src/Interface.cs
Crow/src/LayoutingQueueItem.cs
Crow/src/Widgets/TemplatedGroup.cs
Crow/src/Widgets/Widget.cs
Crow/src/debug/DbgLogViewer.cs
Crow/src/debug/DebugLogger.cs
Images/screenshot4.png [new file with mode: 0644]
Samples/ShowCase/ui/showcase.crow
Samples/common/ui/Interfaces/Divers/colors.crow [new file with mode: 0644]
Samples/common/ui/Interfaces/Divers/dbglog.crow [new file with mode: 0644]

index 8babc221da5bc8deea22467027918b29daf23e8e..8d4766ff58d9daebeef2508a7d998e3f89b496ef 100644 (file)
@@ -114,13 +114,6 @@ namespace Crow
                                };
                                t.Start ();
                        }
-
-#if MEASURE_TIME
-                       PerfMeasures.Add (updateMeasure);
-                       PerfMeasures.Add (drawingMeasure);
-                       PerfMeasures.Add (layoutingMeasure);
-                       PerfMeasures.Add (clippingMeasure);
-#endif
                }
                #endregion
 
@@ -221,27 +214,29 @@ namespace Crow
                        while (!Glfw3.WindowShouldClose (hWin)) {
                                Update ();
                                Thread.Sleep (UPDATE_INTERVAL);
-#if MEASURE_TIME
-                               foreach (PerformanceMeasure m in PerfMeasures) 
-                                       m.NotifyChanges ();
-#endif
                        }
                }
                protected virtual void OnInitialized ()
                {
-                       try {
+                       /*try {
                                Load ("#main.crow").DataSource = this;
-                       } catch { }
+                       } catch { }*/
                        Initialized.Raise (this, null);
                }
                /// <summary>
                /// load styling, init default tooltips and context menus, load main.crow resource if exists.
                /// </summary>
                public void Init () {
+#if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.IFaceInit);
+#endif
                        loadStyling ();
                        initTooltip ();
                        initContextMenus ();
                        OnInitialized ();
+#if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.IFaceInit);
+#endif
                }
                /// <summary>
                /// call Init() then enter the running loop performing ProcessEvents until running==false.
@@ -560,8 +555,14 @@ namespace Crow
                public Widget Load (string path)
                {
                        lock (UpdateMutex) {
+                               #if DEBUG_LOG
+                               DbgLogger.StartEvent (DbgEvtType.IFaceLoad);
+                               #endif
                                Widget tmp = CreateInstance (path);
                                AddWidget (tmp);
+                               #if DEBUG_LOG
+                               DbgLogger.EndEvent (DbgEvtType.IFaceLoad);
+                               #endif
                                return tmp;
                        }
                }
@@ -613,21 +614,13 @@ namespace Crow
 
                                _activeWidget = value;
 
-                               #if DEBUG_FOCUS
+#if DEBUG_LOG
                                NotifyValueChanged("ActiveWidget", _activeWidget);
-                               #endif
+                               DbgLogger.AddEvent (DbgEvtType.ActiveWidget, _activeWidget);
+#endif
 
                                if (_activeWidget != null)
-                               {
                                        _activeWidget.IsActive = true;
-                                       #if DEBUG_FOCUS
-                                       NotifyValueChanged("ActiveWidget", _activeWidget);
-                                       Debug.WriteLine("Active => " + _activeWidget.ToString());
-                               }else
-                                       Debug.WriteLine("Active => null");
-                                       #else
-                               }
-                                       #endif
                        }
                }
                /// <summary>Pointer is over the widget</summary>
@@ -643,9 +636,10 @@ namespace Crow
 
                                _hoverWidget = value;
 
-                               #if DEBUG_FOCUS
+#if DEBUG_LOG
                                NotifyValueChanged("HoverWidget", _hoverWidget);
-                               #endif
+                               DbgLogger.AddEvent (DbgEvtType.HoverWidget, _hoverWidget);
+#endif
 
                                if (DragAndDropOperation == null && FOCUS_ON_HOVER) {
                                        Widget w = _hoverWidget;
@@ -659,15 +653,7 @@ namespace Crow
                                }
 
                                if (_hoverWidget != null)
-                               {
                                        _hoverWidget.IsHover = true;
-#if DEBUG_FOCUS
-                                       Debug.WriteLine("Hover => " + _hoverWidget.ToString());
-                               }else
-                                       Debug.WriteLine("Hover => null");
-#else
-                               }
-#endif                                 
                        }
                }
                /// <summary>Widget has the keyboard or mouse focus</summary>
@@ -679,19 +665,12 @@ namespace Crow
                                if (_focusedWidget != null)
                                        _focusedWidget.HasFocus = false;
                                _focusedWidget = value;
-                               #if DEBUG_FOCUS
+#if DEBUG_LOG
                                NotifyValueChanged("FocusedWidget", _focusedWidget);
-                               #endif
+                               DbgLogger.AddEvent (DbgEvtType.FocusedWidget, _focusedWidget);
+#endif
                                if (_focusedWidget != null)
-                               {
                                        _focusedWidget.HasFocus = true;
-#if DEBUG_FOCUS
-                                       Debug.WriteLine ("Focus => " + _hoverWidget.ToString ());
-                               } else
-                                       Debug.WriteLine ("Focus => null");
-#else
-                               }
-#endif
                        }
                }
                #endregion
@@ -707,7 +686,7 @@ namespace Crow
                                if (g.IsQueueForClipping)
                                        return;
                                #if DEBUG_LOG
-                               DebugLog.AddEvent(DbgEvtType.GOEnqueueForRepaint, g);
+                               DbgLogger.AddEvent(DbgEvtType.GOEnqueueForRepaint, g);
                                #endif  
                                ClippingQueue.Enqueue (g);
                                g.IsQueueForClipping = true;
@@ -742,14 +721,10 @@ namespace Crow
 
                        if (!Monitor.TryEnter (UpdateMutex))
                                return;
-
-                       #if MEASURE_TIME
-                       updateMeasure.StartCycle();
-                       #endif
-
-                       /*#if DEBUG_LOG
-                       DebugLog.AddEvent (DbgEvtType.IFaceUpdate);
-                       #endif*/
+                               
+#if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.IFaceUpdate);
+#endif
 
                        processLayouting ();
 
@@ -761,8 +736,8 @@ namespace Crow
                        }else
                                processDrawing (ctx);
 
-#if MEASURE_TIME
-                       updateMeasure.StopCycle();
+#if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.IFaceUpdate, true);
 #endif
 
                        Monitor.Exit (UpdateMutex);
@@ -771,14 +746,10 @@ namespace Crow
                /// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which
                /// trigger an enqueue for the next Update Cycle</summary>
                protected virtual void processLayouting(){
-                       #if MEASURE_TIME
-                       layoutingMeasure.StartCycle();
-                       #endif
                        if (Monitor.TryEnter (LayoutMutex)) {
-                               #if DEBUG_LOG
-                               if (LayoutingQueue.Count > 0)
-                                       DebugLog.AddEvent (DbgEvtType.IFaceStartLayouting);
-                               #endif
+#if DEBUG_LOG
+                               DbgLogger.StartEvent (DbgEvtType.IFaceLayouting);
+#endif
                                DiscardQueue = new Queue<LayoutingQueueItem> ();
                                //Debug.WriteLine ("======= Layouting queue start =======");
                                LayoutingQueueItem lqi;
@@ -787,27 +758,20 @@ namespace Crow
                                        lqi.ProcessLayouting ();
                                }
                                LayoutingQueue = DiscardQueue;
+#if DEBUG_LOG
+                               DbgLogger.EndEvent (DbgEvtType.IFaceLayouting, true);
+#endif
                                Monitor.Exit (LayoutMutex);
                                DiscardQueue = null;
                        }
-                       /*#if DEBUG_LOG
-                       DebugLog.AddEvent (DbgEvtType.IFaceStartLayouting);
-                       #endif*/
-                       #if MEASURE_TIME
-                       layoutingMeasure.StopCycle();
-                       #endif
                }
                /// <summary>Degueue Widget to clip from DrawingQueue and register the last painted slot and the new one
                /// Clipping rectangles are added at each level of the tree from leef to root, that's the way for the painting
                /// operation to known if it should go down in the tree for further graphic updates and repaints</summary>
                void clippingRegistration(){
-                       #if MEASURE_TIME
-                       clippingMeasure.StartCycle();
-                       #endif
-                       #if DEBUG_LOG
-                       if (ClippingQueue.Count > 0)
-                               DebugLog.AddEvent (DbgEvtType.IFaceStartClipping);
-                       #endif
+#if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.IFaceClipping);
+#endif
                        Widget g = null;
                        while (ClippingQueue.Count > 0) {
                                lock (ClippingMutex) {
@@ -816,23 +780,16 @@ namespace Crow
                                }
                                g.ClippingRegistration ();
                        }
-                       /*#if DEBUG_LOG
-                       DebugLog.AddEvent (DbgEvtType.IFaceEndClipping);
-                       #endif*/
-                       #if MEASURE_TIME
-                       clippingMeasure.StopCycle();
-                       #endif
+#if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.IFaceClipping, true);
+#endif
                }
                /// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
                /// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place</summary>
                void processDrawing(Context ctx){
-                       #if MEASURE_TIME
-                       drawingMeasure.StartCycle();
-                       #endif
-                       #if DEBUG_LOG
-                       if (!clipping.IsEmpty)
-                               DebugLog.AddEvent (DbgEvtType.IFaceStartDrawing);
-                       #endif
+#if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.IFaceDrawing);
+#endif
                        if (DragImage != null)
                                clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight));
                                if (!clipping.IsEmpty) {
@@ -894,12 +851,9 @@ namespace Crow
                                        clipping = new Region ();
                                }
                        
-                       /*#if DEBUG_LOG
-                       DebugLog.AddEvent (DbgEvtType.IFaceEndDrawing);
-                       #endif*/
-                       #if MEASURE_TIME
-                       drawingMeasure.StopCycle();
-                       #endif
+#if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.IFaceDrawing, true);
+#endif
                }
                #endregion
 
@@ -1483,13 +1437,7 @@ namespace Crow
                public Rectangle getSlot () { return ClientRectangle; }
                #endregion
 
-#if MEASURE_TIME
-               public PerformanceMeasure clippingMeasure = new PerformanceMeasure ("Clipping", 1);
-               public PerformanceMeasure layoutingMeasure = new PerformanceMeasure ("Layouting", 1);
-               public PerformanceMeasure updateMeasure = new PerformanceMeasure ("Update", 1);
-               public PerformanceMeasure drawingMeasure = new PerformanceMeasure ("Drawing", 1);
-               public List<PerformanceMeasure> PerfMeasures = new List<PerformanceMeasure> ();
-#endif
+
 #if DEBUG_LAYOUTING
                public List<LQIList> LQIsTries = new List<LQIList>();
                public LQIList curLQIsTries = new LQIList();
index 23556d2b903a2dcfd07d3063ff5825cd99da2210..f1568db3a1c6f735bd29df61c4e72645917c05f5 100644 (file)
@@ -75,7 +75,7 @@ namespace Crow
                        Slot = Rectangle.Zero;
                        NewSlot = Rectangle.Zero;
                        result = Result.Register;
-                       DebugLog.AddEvent (DbgEvtType.GORegisterLayouting, this);
+                       DbgLogger.AddEvent (DbgEvtType.GORegisterLayouting, this);
                        #endif
                }
                #endregion
@@ -95,19 +95,16 @@ namespace Crow
                                //cancel layouting for object without parent, maybe some were in queue when
                                //removed from a listbox
                                #if DEBUG_LOG
-                               DebugLog.AddEvent (DbgEvtType.GOProcessLayoutingWithNoParent, this);
+                               DbgLogger.AddEvent (DbgEvtType.GOProcessLayoutingWithNoParent, this);
                                #endif
                                go.parentRWLock.ExitReadLock ();
                                return;
                        }
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent (DbgEvtType.GOProcessLayouting, this);
+                       DbgLogger.DbgEvent dbgEvt = DbgLogger.StartEvent (DbgEvtType.GOProcessLayouting, this);
                        #endif
                        LayoutingTries++;
                        if (!Layoutable.UpdateLayout (LayoutType)) {
-                               #if DEBUG_LOG
-                               dbgEvt.end = DebugLog.chrono.ElapsedTicks;
-                               #endif
                                if (LayoutingTries < Interface.MaxLayoutingTries) {
                                        Layoutable.RegisteredLayoutings |= LayoutType;
                                        (Layoutable as Widget).IFace.LayoutingQueue.Enqueue (this);
@@ -133,7 +130,7 @@ namespace Crow
                        else{
                                result = Result.Success;
                        }
-                       dbgEvt.data = this;
+                       DbgLogger.EndEvent (DbgEvtType.GOProcessLayouting).data = this;
                        #endif
                        go.parentRWLock.ExitReadLock ();
                }
index d06ea064d0dc064d9f726969f05ba7416b41bc0e..416be3115459bd307b88dff50cfc9e7286589078 100644 (file)
@@ -339,6 +339,9 @@ namespace Crow {
                /// Items loading thread
                /// </summary>
                void loading(){
+#if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.TGLoadingThread, this);
+#endif
                        try {
                                loadPage (data, items, dataTest);
                        } catch (Exception ex) {
@@ -346,20 +349,22 @@ namespace Crow {
                                        Monitor.Exit (IFace.LayoutMutex);
                                System.Diagnostics.Debug.WriteLine ("loading thread aborted: " + ex.ToString());
                        }
-
+#if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.TGLoadingThread);
+#endif
                }
-//                     //if (!ItemTemplates.ContainsKey ("default"))
-//                     //      ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
-//
-//                     for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
-//                             if ((bool)loadingThread?.cancelRequested) {
-//                                     this.Dispose ();
-//                                     return;
-//                             }
-//                             loadPage (i);
-//                             Thread.Sleep (1);
-//                     }
-//             }
+               //                      //if (!ItemTemplates.ContainsKey ("default"))
+               //                      //      ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
+               //
+               //                      for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
+               //                              if ((bool)loadingThread?.cancelRequested) {
+               //                                      this.Dispose ();
+               //                                      return;
+               //                              }
+               //                              loadPage (i);
+               //                              Thread.Sleep (1);
+               //                      }
+               //              }
                void cancelLoadingThread(){
                        if (loadingThread == null)
                                return;
@@ -367,7 +372,7 @@ namespace Crow {
                        bool layoutMx = Monitor.IsEntered (IFace.LayoutMutex);
 
 #if DEBUG_LOG
-                       DebugLog.AddEvent (DbgEvtType.TGCancelLoadingThread, this);
+                       DbgLogger.AddEvent (DbgEvtType.TGCancelLoadingThread, this);
 #endif
 
                        if (layoutMx)
index c98c84ae8d088760e82a42e72a88d1a2346ff6f3..ca693cde8f7a384fb1a18279bbc3e4bc0ab7b003 100644 (file)
@@ -228,7 +228,7 @@ namespace Crow
                        Clipping = new Region ();
                        #if DEBUG_LOG
                        GraphicObjects.Add (this);
-                       DebugLog.AddEvent(DbgEvtType.GOClassCreation, this);
+                       DbgLogger.AddEvent(DbgEvtType.GOClassCreation, this);
                        #endif                  
                }
                /// <summary>
@@ -480,7 +480,7 @@ namespace Crow
                /// If enabled, resulting bitmap of graphic object is cached
                /// speeding up rendering of complex object. Default is enabled.
                /// </summary>
-               [DesignCategory ("Behavior")][DefaultValue(true)]
+               [DesignCategory ("Behavior")][DefaultValue(false)]
                public virtual bool CacheEnabled {
                        get { return cacheEnabled; }
                        set {
@@ -954,14 +954,14 @@ namespace Crow
                                        rootDataLevel = true;
 
                                #if DEBUG_LOG
-                               DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOLockUpdate, this);
+                               DbgLogger.StartEvent(DbgEvtType.GOLockUpdate, this);
                                #endif
                                lock (IFace.UpdateMutex) {
                                        OnDataSourceChanged (this, dse);
                                        NotifyValueChangedAuto (DataSource);
                                }
                                #if DEBUG_LOG
-                               dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                               DbgLogger.EndEvent (DbgEvtType.GOLockUpdate);
                                #endif
                        }
                        get {
@@ -995,7 +995,7 @@ namespace Crow
                public virtual void OnDataSourceChanged(object sender, DataSourceChangeEventArgs e){
                        DataSourceChanged.Raise (this, e);
                        #if DEBUG_LOG
-                       DebugLog.AddEvent(DbgEvtType.GONewDataSource, this);
+                       DbgLogger.AddEvent(DbgEvtType.GONewDataSource, this);
                        #endif
 
                        #if DEBUG_BINDING
@@ -1044,7 +1044,7 @@ namespace Crow
                public void loadDefaultValues()
                {
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOInitialization, this);
+                       DbgLogger.StartEvent (DbgEvtType.GOInitialization, this);
                        #endif
 
                        Type thisType = this.GetType ();
@@ -1165,11 +1165,6 @@ namespace Crow
                        /*} catch (Exception ex) {
                                throw new Exception ("Error applying style <" + styleKey + ">:", ex);
                        }*/
-
-                       #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
-                       #endif
-
                        onInitialized (this, null);
                }
                void setDefaultValue (ILGenerator il, PropertyInfo pi, ref List<Style> styling)
@@ -1227,6 +1222,9 @@ namespace Crow
 
                protected virtual void onInitialized (object sender, EventArgs e){
                        Initialized.Raise(sender, e);
+                       #if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.GOInitialization);
+                       #endif
                }
                bool getDefaultEvent(EventInfo ei, List<Style> styling,
                        out string expression){
@@ -1361,7 +1359,7 @@ namespace Crow
                /// </summary>
                public virtual void ClippingRegistration(){
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOClippingRegistration, this);
+                       DbgLogger.StartEvent (DbgEvtType.GOClippingRegistration, this);
                        #endif  
                        parentRWLock.EnterReadLock ();
                        if (parent != null) {                                   
@@ -1370,7 +1368,7 @@ namespace Crow
                        }
                        parentRWLock.ExitReadLock ();
                        #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                       DbgLogger.EndEvent (DbgEvtType.GOClippingRegistration);
                        #endif
                }
                /// <summary>
@@ -1383,7 +1381,7 @@ namespace Crow
                                return;
                        }
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORegisterClip, this);
+                       DbgLogger.StartEvent(DbgEvtType.GORegisterClip, this);
                        #endif
                        Rectangle cb = ClientRectangle;
                        Rectangle  r = clip + cb.Position;
@@ -1393,18 +1391,29 @@ namespace Crow
                                r.Height -= r.Bottom - cb.Bottom;
                        if (r.Width < 0 || r.Height < 0) {
                                //Debug.WriteLine ($"Invalid clip: {clip}:{r} hnd:{this}");//\n{Environment.StackTrace}");
-                               return;
+                               #if DEBUG_LOG
+                               DbgLogger.EndEvent (DbgEvtType.GORegisterClip);
+                               #endif
+                       return;
                        }
                        if (cacheEnabled && !IsDirty)
                                Clipping.UnionRectangle (r);
-                       if (Parent == null)
+                       if (Parent == null) {
+                               #if DEBUG_LOG
+                               DbgLogger.EndEvent (DbgEvtType.GORegisterClip);
+                               #endif
                                return;
+                       }
                        Widget p = Parent as Widget;
-                       if (p?.IsDirty == true && p?.CacheEnabled == true)
+                       if (p?.IsDirty == true && p?.CacheEnabled == true) {
+                               #if DEBUG_LOG
+                               DbgLogger.EndEvent (DbgEvtType.GORegisterClip);
+                               #endif
                                return;
+                       }
                        Parent.RegisterClip (r + Slot.Position);
                        #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                       DbgLogger.EndEvent (DbgEvtType.GORegisterClip);
                        #endif
                }
                /// <summary> Full update, if width or height is 'Fit' a layouting is requested, and a redraw is done in any case. </summary>
@@ -1433,7 +1442,6 @@ namespace Crow
                                return;
                        }
 #endif
-
                        IsDirty = true;
                        if (RegisteredLayoutings == LayoutingType.None)
                                IFace.EnqueueForRepaint (this);
@@ -1476,15 +1484,19 @@ namespace Crow
 #endif
                        if (Parent == null)
                                return;
-#if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent (DbgEvtType.GOLockLayouting, this);
-#endif
+                       #if DEBUG_LOG
+                       DbgLogger.StartEvent (DbgEvtType.GOLockLayouting, this);
+                       #endif
                        lock (IFace.LayoutMutex) {
                                //prevent queueing same LayoutingType for this
                                layoutType &= (~RegisteredLayoutings);
 
-                               if (layoutType == LayoutingType.None)
+                               if (layoutType == LayoutingType.None) {
+                                       #if DEBUG_LOG
+                                       DbgLogger.EndEvent (DbgEvtType.GOLockLayouting);
+                                       #endif
                                        return;
+                               }
                                //dont set position for stretched item
                                if (Width == Measure.Stretched)
                                        layoutType &= (~LayoutingType.X);
@@ -1501,8 +1513,12 @@ namespace Crow
 //                             //prevent queueing same LayoutingType for this
                                layoutType &= (~RegisteredLayoutings);
 
-                               if (layoutType == LayoutingType.None)
+                               if (layoutType == LayoutingType.None) {
+                                       #if DEBUG_LOG
+                                       DbgLogger.EndEvent (DbgEvtType.GOLockLayouting);
+                                       #endif
                                        return;
+                               }
 
                                //enqueue LQI LayoutingTypes separately
                                if (layoutType.HasFlag (LayoutingType.Width))
@@ -1516,9 +1532,9 @@ namespace Crow
                                if (layoutType.HasFlag (LayoutingType.ArrangeChildren))
                                        IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this));
                        }
-#if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
-#endif
+                       #if DEBUG_LOG
+                       DbgLogger.EndEvent (DbgEvtType.GOLockLayouting);
+                       #endif
                }
 
                /// <summary> trigger dependant sizing component update </summary>
@@ -1695,7 +1711,7 @@ namespace Crow
                protected virtual void onDraw(Context gr)
                {
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GODraw, this);
+                       DbgLogger.StartEvent(DbgEvtType.GODraw, this);
                        #endif
 
                        Rectangle rBack = new Rectangle (Slot.Size);
@@ -1705,7 +1721,7 @@ namespace Crow
                        gr.Fill ();
 
                        #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                       DbgLogger.EndEvent (DbgEvtType.GODraw);
                        #endif
                }
 
@@ -1715,7 +1731,7 @@ namespace Crow
                protected virtual void RecreateCache ()
                {
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORecreateCache, this);
+                       DbgLogger.StartEvent (DbgEvtType.GORecreateCache, this);
                        #endif
 
                        /*if (bmp == null)
@@ -1734,12 +1750,12 @@ namespace Crow
                        IsDirty = false;
 
                        #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                       DbgLogger.EndEvent (DbgEvtType.GORecreateCache);
                        #endif
                }
                protected virtual void UpdateCache(Context ctx){
                        #if DEBUG_LOG
-                       DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOUpdateCacheAndPaintOnCTX, this);
+                       DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
                        #endif
 
                        Rectangle rb = Slot + Parent.ClientRectangle.Position;
@@ -1756,7 +1772,7 @@ namespace Crow
                        Clipping.Dispose ();
                        Clipping = new Region ();
                        #if DEBUG_LOG
-                       dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+                       DbgLogger.EndEvent (DbgEvtType.GOUpdateCache);
                        #endif
                }
                /// <summary> Chained painting routine on the parent context of the actual cached version
@@ -1764,7 +1780,7 @@ namespace Crow
                public virtual void Paint (ref Context ctx)
                {
 #if DEBUG_LOG
-                       DebugLog.AddEvent(DbgEvtType.GOPaint, this);
+                       DbgLogger.AddEvent(DbgEvtType.GOPaint, this);
 #endif
                        //TODO:this test should not be necessary
 
index 9e862e156dfed4e2af6b6a3a6147a8d5b6407409..1a0d5db2b9d95043742a3d6915b62ca2a7943a52 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Threading.Tasks;
 using Crow.Cairo;
 
 #if DEBUG_LOG
@@ -13,24 +14,118 @@ namespace Crow
 {
        public class DbgLogViewer : ScrollingObject
        {
-               public static Dictionary<DbgEvtType,Color> colors;
+               public static Dictionary<DbgEvtType, Color> colors;
 
-               public static Configuration colorsConf = new Configuration("dbgcolor.conf");
+               public static Configuration colorsConf = new Configuration ("dbgcolor.conf");//, Interface.GetStreamFromPath("#Crow.dbgcolor.conf"));
 
                #region debug viewer private classes
-               public class DbgData {
-                       public int objInstanceNum;
-                       public LayoutingType layout;
+               public class DbgLayoutEvent : DbgWidgetEvent
+               {
+                       public LayoutingType layouting;
                        public LayoutingQueueItem.Result result;
-
-                       public DbgData (int _obj) {
-                               objInstanceNum = _obj;
+                       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 class DbgWidgetEvent : DbgEvent
+               {
+                       public int widgetInstanceId;
+                       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.GOLock))
+                                               return Colors.DarkMagenta;
+                                       return Colors.White;
+                               }
                        }
                }
                public class DbgEvent {
                        public long begin, end;
+                       public int threadId;
                        public DbgEvtType type;
-                       public DbgData data = null;
+                       public DbgEvent parentEvent;
+                       public List<DbgEvent> events;
+                       public bool HasChildEvents => events != null && events.Count > 0;
+                       public long Duration => end - begin;
+
+                       public virtual Color Color {
+                               get {
+                                       switch (type) {
+                                       case DbgEvtType.IFaceLayouting:
+                                               return Colors.Yellow;
+                                       case DbgEvtType.IFaceClipping:
+                                               return Colors.DarkTurquoise;
+                                       case DbgEvtType.IFaceDrawing:
+                                               return Colors.MidnightBlue;
+                                       case DbgEvtType.IFaceUpdate:
+                                               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() {}
 
@@ -39,23 +134,40 @@ namespace Crow
                                        return null;
                                string[] tmp = str.Trim().Split(';');
 
-                               DbgEvent evt = new DbgEvent ();
-                               evt.begin = long.Parse (tmp [0]);
-                               evt.end = long.Parse (tmp [1]);
-                               evt.type = (DbgEvtType)Enum.Parse (typeof(DbgEvtType), tmp [2]);
-
-                               if (evt.type.HasFlag (DbgEvtType.GraphicObject)) {
-                                       evt.data = new DbgData (int.Parse (tmp [3]));
-                                       if (evt.type.HasFlag (DbgEvtType.GOLayouting)) {
-                                               evt.data.layout = (LayoutingType)Enum.Parse (typeof(LayoutingType), tmp [4]);
-                                               if (evt.type == DbgEvtType.GOProcessLayouting)
-                                                       evt.data.result = (LayoutingQueueItem.Result)Enum.Parse (typeof(LayoutingQueueItem.Result), tmp [5]);                                                                           
-                                       }
+                               DbgEvtType evtType = (DbgEvtType)Enum.Parse (typeof (DbgEvtType), tmp [3]);
+
+                               if (evtType.HasFlag (DbgEvtType.GraphicObject)) {
+                                       if (evtType.HasFlag (DbgEvtType.GOLayouting))
+                                               return new DbgLayoutEvent () {
+                                                       begin = long.Parse (tmp [0]),
+                                                       end = long.Parse (tmp [1]),
+                                                       threadId = int.Parse (tmp [2]),
+                                                       type = evtType,
+                                                       widgetInstanceId = 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
+                                               };
+                                       return new DbgWidgetEvent () {
+                                               begin = long.Parse (tmp [0]),
+                                               end = long.Parse (tmp [1]),
+                                               threadId = int.Parse (tmp [2]),
+                                               type = evtType,
+                                               widgetInstanceId = int.Parse (tmp [4]),
+                                       };
                                }
-                               return evt;
+                               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}:{type}";
                }
-               class DbgGo {
+               public class DbgGo {
                        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;
@@ -65,7 +177,7 @@ namespace Crow
                        public int yIndex;//index in parenting, the whole main graphic tree is one continuous suite
                        public int xLevel;//depth
 
-                       public List<DbgEvent> events = new List<DbgEvent>();
+                       public List<DbgEvent> events = new List<DbgEvent>();//flattened event list of this widget
 
                        public static DbgGo Parse (string str) {
                                DbgGo g = new DbgGo ();
@@ -96,20 +208,27 @@ namespace Crow
                        reloadColors ();
                }
                protected DbgLogViewer () : base(){}
-               public DbgLogViewer (Interface iface) : base(iface){}
+               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;
+               DbgGo curWidget;
+               DbgEvent curEvent;
 
-               List<DbgEvent> events;//global events
+               List<DbgEvent> events;
                List<DbgGo> objs;
 
+               public List<DbgEvent> Events => events;
+               public List<DbgGo> 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; }
@@ -118,7 +237,9 @@ namespace Crow
                                        return;
                                logFile = value;
 
+                               Console.WriteLine ("before load");
                                loadDebugFile ();
+                               Console.WriteLine ("after load");
 
                                NotifyValueChanged ("LogFile", logFile);
                                RegisterForGraphicUpdate ();
@@ -136,7 +257,7 @@ namespace Crow
                        }
                }
                public double YScale {
-                       get { return yScale; }
+                       get => yScale;
                        set {
                                if (yScale == value)
                                        return;
@@ -145,113 +266,6 @@ namespace Crow
                                RegisterForGraphicUpdate ();
                        }
                }
-
-
-               void storeEvent (DbgEvent evt) {
-                       if (evt.data == null)//global events
-                               events.Add (evt);
-                       else {
-                               DbgGo go = objs.Where (o => o.instanceNum == evt.data.objInstanceNum).FirstOrDefault ();
-                               if (go == null)
-                                       System.Diagnostics.Debug.WriteLine ("Unknown instance: " + evt.data.objInstanceNum);
-                               else
-                                       go.events.Add (evt);                                            
-                       }
-               }
-
-               void loadDebugFile() {
-                       if (!File.Exists (logFile))
-                               return;
-
-                       events = new List<DbgEvent>();
-                       objs = new List<DbgGo> ();
-                       minTicks = maxTicks = 0;
-                       leftMargin = topMargin = 0.0;
-
-                       using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) {
-                               using (Context gr = new Context (img)) {
-                                       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;
-                                                       DbgGo o = DbgGo.Parse (l);
-                                                       objs.Add (o);
-                                                       double nameWidth = gr.TextExtents (o.name).Width + 5.0 * o.xLevel;
-                                                       if (nameWidth > maxNameWidth)
-                                                               maxNameWidth = nameWidth;
-                                               }
-                                               if (!s.EndOfStream) {
-                                                       DbgEvent firstEvt = DbgEvent.Parse (s.ReadLine ());
-                                                       storeEvent (firstEvt);
-                                                       minTicks = firstEvt.begin;
-                                               }
-
-                                               if (!s.EndOfStream) {
-                                                       while (true) {
-                                                               DbgLogViewer.DbgEvent evt = DbgEvent.Parse (s.ReadLine ());
-                                                               storeEvent (evt);
-                                                               if (s.EndOfStream) {
-                                                                       maxTicks = evt.end;
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-                                       }
-
-                                       leftMargin = 2.5 + maxNameWidth;
-
-                                       topMargin = 2.0 * fe.Height;
-
-                                       updateVisibleLines ();
-                                       updateVisibleTicks ();
-                               }
-                       }
-
-               }
-               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 updateVisibleColumns(){
-                       visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance);
-                       NotifyValueChanged ("VisibleColumns", visibleColumns);
-                       updateMaxScrollX ();
-               }
-               void updateMaxScrollX () {
-                       MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns);
-                       if (buffer.longestLineCharCount > 0)
-                               NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount);                      
-               }*/
-
-               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);
-               }
-
-
                public override Font Font {
                        get { return base.Font; }
                        set {
@@ -266,15 +280,13 @@ namespace Crow
                        }
                }
                public override int ScrollY {
-                       get {
-                               return base.ScrollY;
-                       }
+                       get => base.ScrollY;
                        set {
                                base.ScrollY = value;
 
                                if (objs == null)
                                        return;
-                               
+
                                Rectangle cb = ClientRectangle;
                                cb.Left += (int)leftMargin;
                                cb.Width -= (int)leftMargin;
@@ -287,11 +299,90 @@ namespace Crow
                                        currentLine = (int)((double)(mousePos.Y - cb.Top) / fe.Height) + ScrollY;
 
                                NotifyValueChanged ("CurrentLine", currentLine);
+                       }
+               }
 
+               public DbgGo 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;
+                               curEvent = value;
+                               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.GraphicObject)) {
+                                       DbgWidgetEvent eW = evt as DbgWidgetEvent;
+                                       int lIdx = eW.widgetInstanceId - 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)
                {
@@ -316,58 +407,6 @@ namespace Crow
                                        break;
                                DbgGo g = objs [i + ScrollY];
 
-
-                               foreach (DbgEvent evt in g.events) {
-                                       
-
-                                       if (evt.end - minTicks <= ScrollX)
-                                               continue;
-                                       if (evt.begin - minTicks > ScrollX + visibleTicks)
-                                               break;
-
-                                       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;
-                                       //if (x + w > cb.Right)
-                                       //      continue;
-
-                                       Color c = Colors.Black;
-
-                                       if (evt.type == DbgEvtType.GOProcessLayouting) {
-                                               switch (evt.data.result) {
-                                               case LayoutingQueueItem.Result.Success:
-                                                       c = Crow.Colors.Green;
-                                                       break;
-                                               case LayoutingQueueItem.Result.Deleted:
-                                                       c = Crow.Colors.Red;
-                                                       break;
-                                               case LayoutingQueueItem.Result.Discarded:
-                                                       c = Crow.Colors.OrangeRed;
-                                                       break;
-                                               case LayoutingQueueItem.Result.Requeued:
-                                                       c = Crow.Colors.Orange;
-                                                       break;
-                                               }
-                                       } else if (evt.type.HasFlag (DbgEvtType.GOLock))
-                                               c = Colors.BlueViolet;
-                                       else if (colors.ContainsKey (evt.type))
-                                               c = colors [evt.type];
-                                       //else
-                                       //      System.Diagnostics.Debugger.Break ();
-                                       c = c.AdjustAlpha (0.2);
-                                       gr.SetSource (c);
-
-                                       gr.Rectangle (x, penY, w, fe.Height);
-                                       gr.Fill ();
-                               }
-
                                penY += fe.Height;
 
                                gr.SetSource (Crow.Colors.Jet);
@@ -383,14 +422,28 @@ namespace Crow
                                        Foreground.SetAsSource (gr);
 
                                gr.MoveTo (penX, penY - gr.FontExtents.Descent);
-                               gr.ShowText (g.name);
+                               gr.ShowText (g.name + g.instanceNum);
 
                                gr.SetSource (Crow.Colors.White);
                                gr.MoveTo (cb.X, penY - gr.FontExtents.Descent);
-                               gr.ShowText ((i+ ScrollY).ToString());
-
+                               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);
@@ -429,25 +482,14 @@ namespace Crow
                        gr.Stroke ();
 
                        //global events
-                       foreach (DbgEvent evt in events) {
+/*                     foreach (DbgEvent evt in events) {
                                if (evt.begin - minTicks <= ScrollX)
                                        continue;
                                double x = xScale * (evt.begin - minTicks - ScrollX) ;
                                x += leftMargin + cb.Left;
 
-                               gr.SetSource (Crow.Colors.Yellow);
-                               gr.MoveTo (x, penY);
-                               gr.LineTo (x, cb.Bottom);
-                               gr.Stroke ();
-                               string s = evt.type.ToString () [10].ToString ();
-                               Cairo.TextExtents te = gr.TextExtents (s);
-                               gr.Rectangle (x - 0.5 * te.Width , penY - te.Height, te.Width, te.Height);
-                               gr.Fill ();
-                               gr.MoveTo (x- 0.5 * te.Width, penY - gr.FontExtents.Descent);
-                               gr.SetSource (Crow.Colors.Jet);
-                               gr.ShowText (s);
 
-                       }
+                       }*/
 
                }
                public override void Paint (ref Cairo.Context ctx)
@@ -473,7 +515,8 @@ namespace Crow
                        ctx.Operator = Cairo.Operator.Add;
 
                        if (currentLine >= 0) {
-                               r = new Rectangle (cb.Left, (currentLine + 2 - ScrollY) * (int)fe.Height + cb.Top, cb.Width, (int)fe.Height);
+                               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);
@@ -481,13 +524,12 @@ namespace Crow
                                ctx.Fill ();
                        }
 
-                       if (selStart < 0) {
+                       if (selStart < 0 || selEnd < 0) {
                                ctx.Operator = Cairo.Operator.Over;
                                return;
                        }
                        double selStartX = (double)(selStart - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
-                       double selEndX = (selEnd >= 0) ? (double)(selEnd - ScrollX - minTicks) * xScale + leftMargin + cb.Left :
-                               (double)(currentTick - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
+                       double selEndX = (double)(selEnd - ScrollX - minTicks) * xScale + leftMargin + cb.Left;
 
                        if (selStartX < selEndX) {
                                ctxR.X = (int)selStartX;
@@ -518,33 +560,6 @@ namespace Crow
                        }
                }
 
-               Point mousePos;
-               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;
-
-               }
                public override void onMouseLeave (object sender, MouseMoveEventArgs e)
                {
                        base.onMouseLeave (sender, e);
@@ -554,10 +569,16 @@ namespace Crow
                public override void onMouseMove (object sender, MouseMoveEventArgs e)
                {
                        base.onMouseMove (sender, e);
+
+                       long lastTick = currentTick;
                        updateMouseLocalPos (e.Position);
 
-                       if (selStart >= 0 && IFace.IsDown (Glfw.MouseButton.Left))
+                       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);
@@ -567,19 +588,20 @@ namespace Crow
                {
                        base.onMouseDown (sender, e);
 
-                       selStart = currentTick;
-                       selEnd = -1;
+                       if (e.Button == Glfw.MouseButton.Left) {
+                               selStart = currentTick;
+                               selEnd = -1;
+                       }
 
                        RegisterForRedraw ();
                }
                public override void onMouseUp (object sender, MouseButtonEventArgs e)
                {
                        base.onMouseUp (sender, e);
-                       if (selStart == currentTick) {
-                               selStart = -1;
-                               selEnd = -1;
-                       }else
-                               selEnd = currentTick;
+
+                       selStart = -1;
+                       selEnd = -1;
+
                        RegisterForRedraw ();
                }
 
@@ -616,7 +638,148 @@ namespace Crow
                                selEnd = selStart = -1;
                        }
                }
+               async void loadDebugFile ()
+               {
+                       await loadDebugFileAsync ();
+               }
+
+
+
+               async Task loadDebugFileAsync ()
+               {
+                       if (!File.Exists (logFile))
+                               return;
+
+                       events = new List<DbgEvent> ();
+                       objs = new List<DbgGo> ();
+                       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;
+                                               DbgGo o = DbgGo.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.GraphicObject))
+                                                               objs [(evt as DbgWidgetEvent).widgetInstanceId].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;
+                       CurrentWidget = (currentLine < 0 || currentLine >= objs.Count) ? null : objs [currentLine];
+                       CurrentEvent = curWidget?.events.FirstOrDefault (e => e.begin <= currentTick && e.end >= currentTick);
+               }
                void zoom (long start, long end) {                                              
                        //Rectangle cb = ClientRectangle;
                        //cb.X += (int)leftMargin;
index 19c0137893ffcb15eddbe0f30f04a90b3fafb0dd..61ca14af512ea6f3387c2227cf4674bd6b3e8f2f 100644 (file)
@@ -8,6 +8,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Threading;
 
 #if DEBUG_LOG
 namespace Crow
@@ -19,17 +20,25 @@ namespace Crow
        [Flags]
        public enum DbgEvtType {
                ////9 nth bit set for iface event
-               IFace                                                   = 0x0100,
-               IFaceStartLayouting                             = 0x0101,
-               IFaceEndLayouting                               = 0x0102,
-               IFaceStartClipping                              = 0x0103,
-               IFaceEndClipping                                = 0x0104,
-               IFaceStartDrawing                               = 0x0105,
-               IFaceEndDrawing                                 = 0x0106,
-               IFaceUpdate                                             = 0x0107,
+               IFace                                                   = 0x10000,
+               IFaceFocus                                              = 0x20000,
+               GraphicObject                                   = 0x00100,
+               GOLayouting                                     = 0x00200,
+               Drawing                                                 = 0x00400,
+               GOLock                                                  = 0x00800,
+               IFaceLayouting                                  = IFace | 0x01,
+               IFaceClipping                                   = IFace | 0x02,
+               IFaceDrawing                                    = IFace | 0x03,
+               IFaceUpdate                                             = IFace | 0x04,
+               IFaceLoad                                               = IFace | 0x05,
+               IFaceInit                                               = IFace | 0x06,
+
+               HoverWidget                                             = IFaceFocus | 0x01,
+               FocusedWidget                                   = IFaceFocus | 0x02,
+               ActiveWidget                                    = IFaceFocus | 0x03,
+
                //10 nth bit set for graphic obj
-               GraphicObject                                   = 0x0100,
-               Warning                                                 = 0x4000,
+               Warning = 0x4000,
                Error                                                   = 0x8000,
                GOClassCreation                                 = GraphicObject | 0x01,
                GOInitialization                                = GraphicObject | 0x02,
@@ -38,16 +47,13 @@ namespace Crow
                GORegisterForGraphicUpdate              = GraphicObject | 0x05,
                GOEnqueueForRepaint                             = GraphicObject | 0x06,
                GONewDataSource                                 = GraphicObject | 0x07,
-               GOLayouting                                             = 0x0200,
-               Drawing                                                 = 0x0400,
-               GOLock                                                  = 0x0800,
                TemplatedGroup                                  = 0x1000,
                GORegisterLayouting                     = GraphicObject | GOLayouting | 0x01,
                GOProcessLayouting                              = GraphicObject | GOLayouting | 0x02,
                GOProcessLayoutingWithNoParent  = Warning | GraphicObject | GOLayouting | 0x01,
                GODraw                                                  = GraphicObject | Drawing | 0x01,
                GORecreateCache                                 = GraphicObject | Drawing | 0x02,
-               GOUpdateCacheAndPaintOnCTX              = GraphicObject | Drawing | 0x03,
+               GOUpdateCache           = GraphicObject | Drawing | 0x03,
                GOPaint                                                 = GraphicObject | Drawing | 0x04,
 
                GOLockUpdate                                    = GraphicObject | GOLock | 0x01,
@@ -55,60 +61,120 @@ namespace Crow
                GOLockRender                                    = GraphicObject | GOLock | 0x03,
                GOLockLayouting                                 = GraphicObject | GOLock | 0x04,
 
-               TGCancelLoadingThread                   = GraphicObject | TemplatedGroup | 0x01,
+               TGLoadingThread                                 = GraphicObject | TemplatedGroup | 0x01,
+               TGCancelLoadingThread                   = GraphicObject | TemplatedGroup | 0x02,
+
+               All = 0x0FFFFFFF
        }
 
-       /// <summary>
-       /// debug events as recorded, another class is used in the viewer
-       /// </summary>
-       public class DbgEvent {
-               public long begin, end;
-               public DbgEvtType type;
-               public object data = null;
-
-               public DbgEvent() {}
-                       
-               public DbgEvent(long timeStamp, DbgEvtType evt, object _data = null) {                  
-                       data = _data;
-                       type = evt;
-                       begin = timeStamp;
-                       end = timeStamp;
+
+
+       public static class DbgLogger
+       {
+               public static DbgEvtType IncludeEvents = DbgEvtType.All;
+               public static DbgEvtType DiscardEvents = DbgEvtType.IFaceFocus;
+
+               static bool logevt (DbgEvtType evtType)
+               {
+                       return (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) != 0;
                }
 
-               public override string ToString ()
+               /// <summary>
+               /// debug events as recorded, another class is used in the viewer
+               /// </summary>
+               public class DbgEvent
                {
-                       Widget go = data as Widget;
-                       if (go != null)
-                               return string.Format ("{0};{1};{2};{3}", begin, end, type, Widget.GraphicObjects.IndexOf(go).ToString());
-                       if (!(data is LayoutingQueueItem))
-                               return string.Format ("{0};{1};{2}", begin, end, type);
-                       LayoutingQueueItem lqi = (LayoutingQueueItem)data;
-                       if (type == DbgEvtType.GOProcessLayouting)
-                               return string.Format ("{0};{1};{2};{3};{4};{5}", begin, end, type, Widget.GraphicObjects.IndexOf(lqi.graphicObject).ToString(), lqi.LayoutType.ToString(), lqi.result.ToString());                      
-                       return string.Format ("{0};{1};{2};{3};{4}", begin, end, type, Widget.GraphicObjects.IndexOf(lqi.graphicObject).ToString(), lqi.LayoutType.ToString());
-                       
+                       public long begin, end;
+                       public DbgEvtType type;
+                       public object data = null;
+                       public int threadId;
+                       public List<DbgEvent> Events = new List<DbgEvent> ();
+
+                       public DbgEvent () { }
+
+                       public DbgEvent (long timeStamp, DbgEvtType evt, object _data = null)
+                       {
+                               data = _data;
+                               type = evt;
+                               begin = timeStamp;
+                               end = timeStamp;
+                               threadId = Thread.CurrentThread.ManagedThreadId;
+                       }
+
+                       public override string ToString ()
+                       {
+                               string tmp = $"{begin};{end};{threadId};{type}";
+                               if (type.HasFlag (DbgEvtType.GraphicObject)) {
+                                       if (type.HasFlag (DbgEvtType.GOLayouting)) {
+                                               LayoutingQueueItem lqi = (LayoutingQueueItem)data;
+                                               tmp += $";{Widget.GraphicObjects.IndexOf (lqi.graphicObject).ToString ()};{lqi.LayoutType}";
+                                               if (type == DbgEvtType.GOProcessLayouting)
+                                                       tmp += $";{lqi.result}";
+                                       } else
+                                               tmp += $";{Widget.GraphicObjects.IndexOf (data as Widget).ToString ()}";
+                               }
+                               return tmp;
+                       }
                }
-       }
 
-       public static class DebugLog
-       {
-               static Surface surf;
-               static Context ctx;
-
-               static Crow.Rectangle bounds = new Crow.Rectangle(0,0,8182,4096);
-               static double penX = 1.0;
-               static double ySpacing = 10.0;
-               static double xPenStart = 250.0;
-               static double xResolution = 0.001; //per tick
                public static Stopwatch chrono = Stopwatch.StartNew();
 
-               public static List<DbgEvent> events = new List<DbgEvent>();
-               public static DbgEvent currentEvent = null;
+               static List<DbgEvent> events = new List<DbgEvent>();
+               static Dictionary<int, Stack<DbgEvent>> startedEvents = new Dictionary<int, Stack<DbgEvent>> ();
+
+               static object logMutex = new object ();
+
+
+               static List<DbgEvent> curEventList =>
+                       startedEvents.ContainsKey(Thread.CurrentThread.ManagedThreadId) ?
+                       startedEvents[Thread.CurrentThread.ManagedThreadId].Count == 0 ? events : startedEvents[Thread.CurrentThread.ManagedThreadId].Peek ().Events : events;
 
+               public static DbgEvent StartEvent (DbgEvtType evtType, object data = null)
+               {
+                       if (!logevt (evtType))
+                               return null;
+                       lock (logMutex) {
+                               chrono.Stop ();
+                               DbgEvent evt = new DbgEvent (chrono.ElapsedTicks, evtType, data);
+                               curEventList.Add (evt);
+                               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.Count == 0)
+                                       curEventList.Remove (e);
+                               else
+                                       e.end = chrono.ElapsedTicks;
+                               chrono.Start ();
+                               return e;
+                       }
+               }
                public static DbgEvent AddEvent (DbgEvtType evtType, object data = null) {
-                       DbgEvent evt = new DbgEvent(chrono.ElapsedTicks, evtType, data);
-                       events.Add (evt);
-                       return evt;
+                       if (!logevt (evtType))
+                               return null;
+
+                       lock (logMutex) {
+                               chrono.Stop ();
+                               DbgEvent evt = new DbgEvent (chrono.ElapsedTicks, evtType, data);
+                               curEventList.Add (evt);
+                               chrono.Start ();
+                               return evt;
+                       }
                }
 
                static int y, level;
@@ -117,7 +183,6 @@ namespace Crow
                        if (go == null)
                                return;
 
-
                        go.yIndex = y++;
                        go.xLevel = level++;
 
@@ -133,30 +198,47 @@ namespace Crow
                        }
                        level--;                
                }
-
+               public static void Reset ()
+               {
+                       lock (logMutex) {
+                               startedEvents.Clear ();
+                               events.Clear ();
+                               chrono.Restart ();
+                       }
+               }
                public static void save(Interface iface) {
-                       y = 1;
-                       level = 0;
-
-                       foreach (Widget go in iface.GraphicTree) 
-                               parseTree (go);                 
-
-                       using (StreamWriter s = new StreamWriter("debug.log")){
-                               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 ("{0};{1};{2};{3}", i, g.GetType ().Name, g.yIndex, g.xLevel);      
+                       lock (logMutex) {
+                               y = 1;
+                               level = 0;
+
+                               foreach (Widget go in iface.GraphicTree)
+                                       parseTree (go);
+
+                               using (StreamWriter s = new StreamWriter ("debug.log")) {
+                                       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 ("{0};{1};{2};{3}", i, g.GetType ().Name, g.yIndex, g.xLevel);
+                                               }
                                        }
+                                       s.WriteLine ("[Events]");
+                                       saveEventList (s, events);
                                }
-                               s.WriteLine ("[Events]");
+                       }
+               }
 
-                               foreach (DbgEvent e in events)
-                                       if (e != null)
-                                               s.WriteLine (e.ToString ());
+               static void saveEventList (StreamWriter s, List<DbgEvent> events, int level = 0)
+               {
+                       foreach (DbgEvent e in events) {
+                               if (e == null)
+                                       continue;
+                               s.WriteLine (new string ('\t', level) + e.ToString ());
+                               saveEventList (s, e.Events, level + 1);
                        }
                }
+
        }
 }
 #endif
diff --git a/Images/screenshot4.png b/Images/screenshot4.png
new file mode 100644 (file)
index 0000000..8605e77
Binary files /dev/null and b/Images/screenshot4.png differ
index 83700273a70dd1fe2bb04236ef066ce6d519bec3..7610e9b6b5481a332e88d0c365f5f80c2f579624 100644 (file)
@@ -20,8 +20,7 @@
                        </HorizontalStack>
                        <HorizontalStack>
                                <Scroller Name="scroller1" Background="White"
-                                               Margin="2" ScrollY="{../scrollbar1.Value}"
-                                               ValueChanged="./_scroller_ValueChanged">
+                                               Margin="2" ScrollY="{../scrollbar1.Value}">
                                        <TextBox VerticalAlignment="Top"
                                                Text="{²Source}" Multiline="true" TextAlignment="TopLeft"
                                                Font="mono 10"/>
diff --git a/Samples/common/ui/Interfaces/Divers/colors.crow b/Samples/common/ui/Interfaces/Divers/colors.crow
new file mode 100644 (file)
index 0000000..ea46d0e
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<Window Width="80%" Height="90%">
+<ListBox Name="ColorList" Data="{TestList}" Margin="5">
+       <Template>
+               <Wrapper Name="ItemsContainer" Orientation="Horizontal"/>
+       </Template>
+       <ItemTemplate>
+               <Group Background="{}" Width="Fit" Height="Fit" >
+                       <Label Text="{}" TextAlignment="Center" Font="mono, 9" Foreground="Black" Left="2" Top="2" Margin="10" Width="100"/>
+                       <Label Text="{}" TextAlignment="Center" Font="mono, 9" Left="1" Top="1" Margin="10" Width="100"/>
+               </Group>
+       </ItemTemplate>
+
+</ListBox>
+</Window>
diff --git a/Samples/common/ui/Interfaces/Divers/dbglog.crow b/Samples/common/ui/Interfaces/Divers/dbglog.crow
new file mode 100644 (file)
index 0000000..02147b6
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<HorizontalStack>
+       <TreeView Width="20%" Data="{../dbv.Events}"> 
+               <ItemTemplate Data="events">
+                       <Expandable Caption="{type}" MouseDoubleClick="/onClickForExpand" CacheEnabled="true">
+                               <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"/>
+                                                               <Group Height="5">
+                                                                       <DbgEventWidget Event="{}" />
+                                                               </Group>
+                                                       </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="false" 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>
+               <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