--- a/controls/DebugVariablePanel/DebugVariableGraphicPanel.py Mon Jun 03 17:29:03 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableGraphicPanel.py Mon Jun 03 22:09:01 2013 +0200
@@ -41,21 +41,86 @@
from DebugVariableTextViewer import DebugVariableTextViewer
from DebugVariableGraphicViewer import *
+MILLISECOND = 1000000 # Number of nanosecond in a millisecond +SECOND = 1000 * MILLISECOND # Number of nanosecond in a second +MINUTE = 60 * SECOND # Number of nanosecond in a minute +HOUR = 60 * MINUTE # Number of nanosecond in a hour +DAY = 24 * HOUR # Number of nanosecond in a day +# List of values possible for graph range +# Format is [(time_in_plain_text, value_in_nanosecond),...] + [("%dms" % i, i * MILLISECOND) for i in (10, 20, 50, 100, 200, 500)] + \ + [("%ds" % i, i * SECOND) for i in (1, 2, 5, 10, 20, 30)] + \ + [("%dm" % i, i * MINUTE) for i in (1, 2, 5, 10, 20, 30)] + \ + [("%dh" % i, i * HOUR) for i in (1, 2, 3, 6, 12, 24)] +# Scrollbar increment in pixel + return [(xp if xp == yp else "*") + for xp, yp in zip(x, y)] +def NextTick(variables): + for item, data in variables: + else min(next_tick, data[0][0])) +#------------------------------------------------------------------------------- +# Debug Variable Graphic Panel Drop Target +#------------------------------------------------------------------------------- +Class that implements a custom drop target class for Debug Variable Graphic class DebugVariableDropTarget(wx.TextDropTarget):
- def __init__(self, parent):
+ def __init__(self, window): + @param window: Reference to the Debug Variable Panel wx.TextDropTarget.__init__(self)
- self.ParentWindow = parent
+ self.ParentWindow = window + # Remove reference to Debug Variable Panel def OnDragOver(self, x, y, d):
+ Function called when mouse is dragged over Drop Target + @param x: X coordinate of mouse pointer + @param y: Y coordinate of mouse pointer + @param d: Suggested default for return value + # Signal Debug Variable Panel to refresh highlight giving mouse position self.ParentWindow.RefreshHighlight(x, y)
return wx.TextDropTarget.OnDragOver(self, x, y, d)
def OnDropText(self, x, y, data):
+ Function called when mouse is released in Drop Target + @param x: X coordinate of mouse pointer + @param y: Y coordinate of mouse pointer + @param data: Text associated to drag'n drop + # Check that data is valid regarding DebugVariablePanel if not isinstance(values, TupleType):
@@ -64,80 +129,87 @@
message = _("Invalid value \"%s\" for debug variable")%data
+ # Display message if data is invalid wx.CallAfter(self.ShowMessage, message)
+ # Data contain a reference to a variable to debug elif values[1] == "debug":
+ # Drag'n Drop is an internal is an internal move inside Debug if len(values) > 2 and values[2] == "move":
self.ParentWindow.MoveValue(values[0])
+ # Drag'n Drop was initiated by another control of Beremiz self.ParentWindow.InsertValue(values[0], force=True)
+ Function called when mouse is leave Drop Target + # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight()
return wx.TextDropTarget.OnLeave(self)
def ShowMessage(self, message):
+ Show error message in Error Dialog + @param message: Error message to display dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
-SECOND = 1000 * MILLISECOND
-ZOOM_VALUES = map(lambda x:("x %.1f" % x, x), [math.sqrt(2) ** i for i in xrange(8)])
- [("%dms" % i, i * MILLISECOND) for i in (10, 20, 50, 100, 200, 500)] + \
- [("%ds" % i, i * SECOND) for i in (1, 2, 5, 10, 20, 30)] + \
- [("%dm" % i, i * MINUTE) for i in (1, 2, 5, 10, 20, 30)] + \
- [("%dh" % i, i * HOUR) for i in (1, 2, 3, 6, 12, 24)]
- for xp, yp in zip(x, y):
+#------------------------------------------------------------------------------- +# Debug Variable Graphic Panel Class +#------------------------------------------------------------------------------- -def NextTick(variables):
- for item, data in variables:
- next_tick = min(next_tick, data[0][0])
+Class that implements a Viewer that display variable values as a graphs class DebugVariableGraphicPanel(wx.Panel, DebugViewer):
def __init__(self, parent, producer, window):
+ @param parent: Reference to the parent wx.Window + @param producer: Object receiving debug value and dispatching them to + @param window: Reference to Beremiz frame wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL)
+ # Save Reference to Beremiz frame self.ParentWindow = window
+ # Variable storing flag indicating that variable displayed in table + # received new value and then table need to be refreshed + # Variable storing flag indicating that refresh has been forced, and + # that next time refresh is possible, it will be done even if no new self.SetBackgroundColour(wx.WHITE)
main_sizer = wx.BoxSizer(wx.VERTICAL)
- self.Ticks = numpy.array([])
+ self.Ticks = numpy.array([]) # List of tick received + self.StartTick = 0 # Tick starting range of data displayed + self.Fixed = False # Flag that range of data is fixed + self.CursorTick = None # Tick of cursor for displaying values self.DraggingAxesPanel = None
self.DraggingAxesBoundingBox = None
self.DraggingAxesMousePos = None
self.VetoScrollEvent = False
self.VariableNameMask = []
@@ -215,40 +287,78 @@
self.SetSizer(main_sizer)
- DebugViewer.__del__(self)
def SetTickTime(self, ticktime=0):
+ Set Ticktime for calculate data range according to time range selected + @param ticktime: Ticktime to apply to range (default: 0) + # Set ticktime to millisecond if undefined self.Ticktime = MILLISECOND
+ # Calculate range to apply to data self.CurrentRange = RANGE_VALUES[
self.CanvasRange.GetSelection()][1] / self.Ticktime
def SetDataProducer(self, producer):
+ @param producer: Data Producer DebugViewer.SetDataProducer(self, producer)
+ # Set ticktime if data producer is available if self.DataProducer is not None:
self.SetTickTime(self.DataProducer.GetTicktime())
def RefreshNewData(self, *args, **kwargs):
+ Called to refresh Panel according to values received by variables + Can receive any parameters (not used here) + # Refresh graphs if new data is available or refresh is forced if self.HasNewData or self.Force:
DebugViewer.RefreshNewData(self, *args, **kwargs)
def NewDataAvailable(self, tick, *args, **kwargs):
+ Called by DataProducer for each tick captured or by panel to refresh + @param tick: PLC tick captured + All other parameters are passed to refresh function + # Save tick as start tick for range if data is still empty + # Add tick to list of ticks received self.Ticks = numpy.append(self.Ticks, [tick])
+ # Update start tick for range if range follow ticks received if not self.Fixed or tick < self.StartTick + self.CurrentRange:
self.StartTick = max(self.StartTick, tick - self.CurrentRange)
- if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange:
+ # Force refresh if graph is fixed because range of data received + # is too small to fill data range selected + self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: DebugViewer.NewDataAvailable(self, tick, *args, **kwargs)
+ Called to force refresh of graphs wx.CallAfter(self.NewDataAvailable, None, True)
@@ -668,6 +778,7 @@
panel.SetCanvasSize(source_size.width, source_size.height)
if self.CursorTick is not None:
panel.SetCursorTick(self.CursorTick)
panel = DebugVariableTextViewer(self.GraphicsWindow, self, [item])
@@ -676,9 +787,10 @@
if source_panel.ItemsIsEmpty():
if source_panel.HasCapture():
source_panel.ReleaseMouse()
+ if isinstance(source_panel, DebugVariableGraphicViewer): self.GraphicPanels.remove(source_panel)
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
@@ -716,8 +828,9 @@
if source_panel.ItemsIsEmpty():
if source_panel.HasCapture():
source_panel.ReleaseMouse()
+ if isinstance(source_panel, DebugVariableGraphicViewer): self.GraphicPanels.remove(source_panel)
elif (merge_type != graph_type and len(target_panel.Items) == 2):
target_panel.RemoveItem(source_item)
@@ -745,14 +858,16 @@
source_panel.ClearItems()
+ if isinstance(source_panel, DebugVariableGraphicViewer): self.GraphicPanels.remove(source_panel)
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
source_panel.RemoveItem(item)
if source_panel.ItemsIsEmpty():
+ if isinstance(source_panel, DebugVariableGraphicViewer): self.GraphicPanels.remove(source_panel)
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
--- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Jun 03 17:29:03 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Jun 03 22:09:01 2013 +0200
@@ -58,23 +58,13 @@
-def OrthogonalDataAndRange(item, start_tick, end_tick):
- data = item.GetData(start_tick, end_tick)
- min_value, max_value = item.GetValueRange()
- if min_value is not None and max_value is not None:
- center = (min_value + max_value) / 2.
- range = max(1.0, max_value - min_value)
- return data, center - range * 0.55, center + range * 0.55
#-------------------------------------------------------------------------------
# Debug Variable Graphic Viewer Drop Target
#-------------------------------------------------------------------------------
-Class that implements a custom drop target class for Debug Variable Graphic Viewer
+Class that implements a custom drop target class for Debug Variable Graphic class DebugVariableGraphicDropTarget(wx.TextDropTarget):
@@ -112,7 +102,7 @@
def OnDropText(self, x, y, data):
- Function called when mouse is dragged over Drop Target
+ Function called when mouse is released in Drop Target @param x: X coordinate of mouse pointer
@param y: Y coordinate of mouse pointer
@param data: Text associated to drag'n drop
@@ -1095,8 +1085,8 @@
start_tick = max(start_tick, min_start_tick)
end_tick = max(end_tick, min_start_tick)
items = self.ItemsDict.values()
- x_data, x_min, x_max = OrthogonalDataAndRange(items[0], start_tick, end_tick)
- y_data, y_min, y_max = OrthogonalDataAndRange(items[1], start_tick, end_tick)
+ x_data, x_min, x_max = items[0].OrthogonalDataAndRange(start_tick, end_tick) + y_data, y_min, y_max = items[1].OrthogonalDataAndRange(start_tick, end_tick) if self.CursorTick is not None:
x_cursor, x_forced = items[0].GetValue(self.CursorTick, raw=True)
y_cursor, y_forced = items[1].GetValue(self.CursorTick, raw=True)
@@ -1133,7 +1123,7 @@
while len(self.Axes.lines) > 0:
- z_data, z_min, z_max = OrthogonalDataAndRange(items[2], start_tick, end_tick)
+ z_data, z_min, z_max = items[2].OrthogonalDataAndRange(start_tick, end_tick) if self.CursorTick is not None:
z_cursor, z_forced = items[2].GetValue(self.CursorTick, raw=True)
if x_data is not None and y_data is not None and z_data is not None: