IDE: Fixed variable traces graphs RingBuffers. Removed an apparently useless wxCallAfter in trend graph that was leading to pydeadobject exception on wxGTK when double-clicking.
--- a/controls/DebugVariablePanel/DebugVariableItem.py Mon Jun 14 16:48:39 2021 +0200
+++ b/controls/DebugVariablePanel/DebugVariableItem.py Wed Jun 16 12:15:02 2021 +0200
@@ -384,7 +384,7 @@
ticks = self.Data.view[:, 0]
# Get nearest data from tick
- idx = np.searchsorted(ticks, tick)
+ idx = min(np.searchsorted(ticks, tick), self.Data.count - 1)
# Adjust data index according to constraint
if adjust < 0 and ticks[idx] > tick and idx > 0 or \
--- a/controls/DebugVariablePanel/DebugVariablePanel.py Mon Jun 14 16:48:39 2021 +0200
+++ b/controls/DebugVariablePanel/DebugVariablePanel.py Wed Jun 16 12:15:02 2021 +0200
@@ -357,9 +357,13 @@
# Force refresh if graph is fixed because range of data received
# is too small to fill data range selected
- if self.Fixed and \
- self.Ticks.view[-1] - self.Ticks.view[0] < self.CurrentRange:
- self.Force = True
+ if self.Fixed :
+ if self.Ticks.view[-1] - self.Ticks.view[0] < self.CurrentRange:
+ self.Force = True
+ if self.Ticks.view[0] > self.StartTick:
+ self.StartTick = self.Ticks.view[0]
+ self.Force = True
+
self.HasNewData = False
self.RefreshView()
@@ -388,14 +392,14 @@
if self.CursorTick is not None:
cursor_tick = max(self.Ticks.view[0],
min(self.CursorTick + move, self.Ticks.view[-1]))
- cursor_tick_idx = np.searchsorted(self.Ticks.view, cursor_tick)
+ cursor_tick_idx = min(np.searchsorted(self.Ticks.view, cursor_tick), self.Ticks.count - 1)
if self.Ticks.view[cursor_tick_idx] == self.CursorTick:
cursor_tick_idx = max(0,
min(cursor_tick_idx + abs(move) // move,
self.Ticks.count - 1))
self.CursorTick = self.Ticks.view[cursor_tick_idx]
self.StartTick = max(
- self.Ticks.view[np.searchsorted(self.Ticks.view, self.CursorTick + self.CurrentRange)],
+ self.Ticks.view[min(np.searchsorted(self.Ticks.view, self.CursorTick - self.CurrentRange), self.Ticks.count - 1)],
min(self.StartTick, self.CursorTick))
self.RefreshCanvasPosition()
self.UpdateCursorTick()
@@ -605,7 +609,7 @@
def SetCanvasPosition(self, tick):
tick = max(self.Ticks.view[0], min(tick, self.Ticks.view[-1] - self.CurrentRange))
- self.StartTick = self.Ticks.view[np.searchsorted(self.Ticks.view, tick)]
+ self.StartTick = self.Ticks.view[min(np.searchsorted(self.Ticks.view, tick), self.Ticks.count - 1)]
self.Fixed = True
self.RefreshCanvasPosition()
self.ForceRefresh()
@@ -631,7 +635,7 @@
tick = self.StartTick + self.CurrentRange / 2.
new_start_tick = min(tick - (tick - self.StartTick) * self.CurrentRange / current_range,
self.Ticks.view[-1] - self.CurrentRange)
- self.StartTick = self.Ticks.view[np.searchsorted(self.Ticks.view, - new_start_tick)]
+ self.StartTick = self.Ticks.view[min(np.searchsorted(self.Ticks.view, new_start_tick), self.Ticks.count - 1)]
self.Fixed = new_start_tick < self.Ticks.view[-1] - self.CurrentRange
self.ForceRefresh()
--- a/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Jun 14 16:48:39 2021 +0200
+++ b/controls/DebugVariablePanel/DebugVariableTextViewer.py Wed Jun 16 12:15:02 2021 +0200
@@ -270,7 +270,7 @@
"""
# Execute callback on button under mouse pointer if it exists
x, y = event.GetPosition()
- wx.CallAfter(self.HandleButton, x, y)
+ self.HandleButton(x, y)
event.Skip()
def OnLeftDClick(self, event):
--- a/controls/DebugVariablePanel/RingBuffer.py Mon Jun 14 16:48:39 2021 +0200
+++ b/controls/DebugVariablePanel/RingBuffer.py Wed Jun 16 12:15:02 2021 +0200
@@ -12,36 +12,32 @@
class RingBuffer(object):
- def __init__(self, width=None, size=65536, padding=None):
+ def __init__(self, width=None, size=131072, padding=None):
self.size = size
self.padding = size if padding is None else padding
shape = (self.size+self.padding,)
if width :
shape += (width,)
self.buffer = np.zeros(shape)
- self.counter = 0
- self.full = False
+ self.cursor = 0
def append(self, data):
"""this is an O(n) operation"""
- data = data[-self.padding:]
+ data = data[-self.size:]
n = len(data)
- if self.remaining < n: self.compact()
- self.buffer[self.counter+self.size:][:n] = data
- self.counter += n
+ if self.size + self.padding - self.cursor < n:
+ self.compact()
+ self.buffer[self.cursor:][:n] = data
+ self.cursor += n
@property
def count(self):
- return self.counter if not self.full else self.size
-
- @property
- def remaining(self):
- return self.padding-self.counter
+ return min(self.size, self.cursor)
@property
def view(self):
"""this is always an O(1) operation"""
- return self.buffer[self.counter:][:self.size]
+ return self.buffer[max(0, self.cursor - self.size):][:self.count]
def compact(self):
"""
@@ -49,7 +45,6 @@
and this cost is amortized over the whole padding space
"""
print 'compacting'
- self.buffer[:self.size] = self.view
- self.counter = 0
- self.full = True
+ self.buffer[:self.count] = self.view
+ self.cursor -= self.size