controls/DebugVariablePanel/DebugVariablePanel.py
branchsvghmi
changeset 3257 095c73591b7e
parent 2593 62c5c3589769
child 2742 5f7445b582d4
equal deleted inserted replaced
3256:8d1cc99a8f54 3257:095c73591b7e
    24 
    24 
    25 
    25 
    26 from __future__ import absolute_import
    26 from __future__ import absolute_import
    27 from __future__ import division
    27 from __future__ import division
    28 from functools import reduce
    28 from functools import reduce
    29 import numpy
    29 import numpy as np
    30 
    30 
    31 import wx
    31 import wx
    32 import wx.lib.buttons
    32 import wx.lib.buttons
    33 
    33 
    34 
    34 
    41 from util.BitmapLibrary import GetBitmap
    41 from util.BitmapLibrary import GetBitmap
    42 
    42 
    43 from controls.DebugVariablePanel.DebugVariableItem import DebugVariableItem
    43 from controls.DebugVariablePanel.DebugVariableItem import DebugVariableItem
    44 from controls.DebugVariablePanel.DebugVariableTextViewer import DebugVariableTextViewer
    44 from controls.DebugVariablePanel.DebugVariableTextViewer import DebugVariableTextViewer
    45 from controls.DebugVariablePanel.DebugVariableGraphicViewer import *
    45 from controls.DebugVariablePanel.DebugVariableGraphicViewer import *
       
    46 from controls.DebugVariablePanel.RingBuffer import RingBuffer
    46 
    47 
    47 
    48 
    48 MILLISECOND = 1000000        # Number of nanosecond in a millisecond
    49 MILLISECOND = 1000000        # Number of nanosecond in a millisecond
    49 SECOND = 1000 * MILLISECOND  # Number of nanosecond in a second
    50 SECOND = 1000 * MILLISECOND  # Number of nanosecond in a second
    50 MINUTE = 60 * SECOND         # Number of nanosecond in a minute
    51 MINUTE = 60 * SECOND         # Number of nanosecond in a minute
   203 
   204 
   204         self.SetBackgroundColour(wx.WHITE)
   205         self.SetBackgroundColour(wx.WHITE)
   205 
   206 
   206         main_sizer = wx.BoxSizer(wx.VERTICAL)
   207         main_sizer = wx.BoxSizer(wx.VERTICAL)
   207 
   208 
   208         self.Ticks = numpy.array([])  # List of tick received
   209         self.Ticks = RingBuffer()  # List of tick received
   209         self.StartTick = 0            # Tick starting range of data displayed
   210         self.StartTick = 0            # Tick starting range of data displayed
   210         self.Fixed = False            # Flag that range of data is fixed
   211         self.Fixed = False            # Flag that range of data is fixed
   211         self.CursorTick = None        # Tick of cursor for displaying values
   212         self.CursorTick = None        # Tick of cursor for displaying values
   212 
   213 
   213         self.DraggingAxesPanel = None
   214         self.DraggingAxesPanel = None
   342         # If tick given
   343         # If tick given
   343         if ticks is not None:
   344         if ticks is not None:
   344             tick = ticks[-1]
   345             tick = ticks[-1]
   345 
   346 
   346             # Save tick as start tick for range if data is still empty
   347             # Save tick as start tick for range if data is still empty
   347             if len(self.Ticks) == 0:
   348             if self.Ticks.count == 0:
   348                 self.StartTick = ticks[0]
   349                 self.StartTick = ticks[0]
   349 
   350 
   350             # Add tick to list of ticks received
   351             # Add tick to list of ticks received
   351             self.Ticks = numpy.append(self.Ticks, ticks)
   352             self.Ticks.append(ticks)
   352 
   353 
   353             # Update start tick for range if range follow ticks received
   354             # Update start tick for range if range follow ticks received
   354             if not self.Fixed or tick < self.StartTick + self.CurrentRange:
   355             if not self.Fixed or tick < self.StartTick + self.CurrentRange:
   355                 self.StartTick = max(self.StartTick, tick - self.CurrentRange)
   356                 self.StartTick = max(self.StartTick, tick - self.CurrentRange)
   356 
   357 
   357             # Force refresh if graph is fixed because range of data received
   358             # Force refresh if graph is fixed because range of data received
   358             # is too small to fill data range selected
   359             # is too small to fill data range selected
   359             if self.Fixed and \
   360             if self.Fixed and \
   360                self.Ticks[-1] - self.Ticks[0] < self.CurrentRange:
   361                self.Ticks.view[-1] - self.Ticks.view[0] < self.CurrentRange:
   361                 self.Force = True
   362                 self.Force = True
   362 
   363 
   363             self.HasNewData = False
   364             self.HasNewData = False
   364             self.RefreshView()
   365             self.RefreshView()
   365 
   366 
   383         self.Fixed = cursor_tick is not None
   384         self.Fixed = cursor_tick is not None
   384         self.UpdateCursorTick()
   385         self.UpdateCursorTick()
   385 
   386 
   386     def MoveCursorTick(self, move):
   387     def MoveCursorTick(self, move):
   387         if self.CursorTick is not None:
   388         if self.CursorTick is not None:
   388             cursor_tick = max(self.Ticks[0],
   389             cursor_tick = max(self.Ticks.view[0],
   389                               min(self.CursorTick + move, self.Ticks[-1]))
   390                               min(self.CursorTick + move, self.Ticks.view[-1]))
   390             cursor_tick_idx = numpy.argmin(numpy.abs(self.Ticks - cursor_tick))
   391             cursor_tick_idx = np.searchsorted(self.Ticks.view, cursor_tick)
   391             if self.Ticks[cursor_tick_idx] == self.CursorTick:
   392             if self.Ticks.view[cursor_tick_idx] == self.CursorTick:
   392                 cursor_tick_idx = max(0,
   393                 cursor_tick_idx = max(0,
   393                                       min(cursor_tick_idx + abs(move) // move,
   394                                       min(cursor_tick_idx + abs(move) // move,
   394                                           len(self.Ticks) - 1))
   395                                           self.Ticks.count - 1))
   395             self.CursorTick = self.Ticks[cursor_tick_idx]
   396             self.CursorTick = self.Ticks.view[cursor_tick_idx]
   396             self.StartTick = max(
   397             self.StartTick = max(
   397                 self.Ticks[numpy.argmin(
   398                 self.Ticks.view[np.searchsorted(self.Ticks.view,  self.CursorTick + self.CurrentRange)],
   398                     numpy.abs(self.Ticks - self.CursorTick + self.CurrentRange))],
       
   399                 min(self.StartTick, self.CursorTick))
   399                 min(self.StartTick, self.CursorTick))
   400             self.RefreshCanvasPosition()
   400             self.RefreshCanvasPosition()
   401             self.UpdateCursorTick()
   401             self.UpdateCursorTick()
   402 
   402 
   403     def ResetCursorTick(self):
   403     def ResetCursorTick(self):
   545             else:
   545             else:
   546                 panel.RefreshViewer()
   546                 panel.RefreshViewer()
   547 
   547 
   548         if self.CursorTick is not None:
   548         if self.CursorTick is not None:
   549             tick = self.CursorTick
   549             tick = self.CursorTick
   550         elif len(self.Ticks) > 0:
   550         elif self.Ticks.count > 0:
   551             tick = self.Ticks[-1]
   551             tick = self.Ticks.view[-1]
   552         else:
   552         else:
   553             tick = None
   553             tick = None
   554         if tick is not None:
   554         if tick is not None:
   555             self.TickLabel.SetLabel(label=_("Tick: %d") % tick)
   555             self.TickLabel.SetLabel(label=_("Tick: %d") % tick)
   556             tick_duration = int(tick * self.Ticktime)
   556             tick_duration = int(tick * self.Ticktime)
   602         self.GraphicPanels = []
   602         self.GraphicPanels = []
   603         self.ResetVariableNameMask()
   603         self.ResetVariableNameMask()
   604         self.RefreshGraphicsSizer()
   604         self.RefreshGraphicsSizer()
   605 
   605 
   606     def SetCanvasPosition(self, tick):
   606     def SetCanvasPosition(self, tick):
   607         tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange))
   607         tick = max(self.Ticks.view[0], min(tick, self.Ticks.view[-1] - self.CurrentRange))
   608         self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))]
   608         self.StartTick = self.Ticks.view[np.searchsorted(self.Ticks.view, tick)]
   609         self.Fixed = True
   609         self.Fixed = True
   610         self.RefreshCanvasPosition()
   610         self.RefreshCanvasPosition()
   611         self.ForceRefresh()
   611         self.ForceRefresh()
   612 
   612 
   613     def RefreshCanvasPosition(self):
   613     def RefreshCanvasPosition(self):
   614         if len(self.Ticks) > 0:
   614         if len(self.Ticks.view) > 0:
   615             pos = int(self.StartTick - self.Ticks[0])
   615             pos = int(self.StartTick - self.Ticks.view[0])
   616             range = int(self.Ticks[-1] - self.Ticks[0])
   616             range = int(self.Ticks.view[-1] - self.Ticks.view[0])
   617         else:
   617         else:
   618             pos = 0
   618             pos = 0
   619             range = 0
   619             range = 0
   620         self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange)
   620         self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange)
   621 
   621 
   624         current_range_idx = self.CanvasRange.GetSelection()
   624         current_range_idx = self.CanvasRange.GetSelection()
   625         new_range_idx = max(0, min(current_range_idx + dir, len(self.RANGE_VALUES) - 1))
   625         new_range_idx = max(0, min(current_range_idx + dir, len(self.RANGE_VALUES) - 1))
   626         if new_range_idx != current_range_idx:
   626         if new_range_idx != current_range_idx:
   627             self.CanvasRange.SetSelection(new_range_idx)
   627             self.CanvasRange.SetSelection(new_range_idx)
   628             self.CurrentRange = self.RANGE_VALUES[new_range_idx][1] / self.Ticktime
   628             self.CurrentRange = self.RANGE_VALUES[new_range_idx][1] / self.Ticktime
   629             if len(self.Ticks) > 0:
   629             if self.Ticks.count > 0:
   630                 if tick is None:
   630                 if tick is None:
   631                     tick = self.StartTick + self.CurrentRange / 2.
   631                     tick = self.StartTick + self.CurrentRange / 2.
   632                 new_start_tick = min(tick - (tick - self.StartTick) * self.CurrentRange / current_range,
   632                 new_start_tick = min(tick - (tick - self.StartTick) * self.CurrentRange / current_range,
   633                                      self.Ticks[-1] - self.CurrentRange)
   633                                      self.Ticks.view[-1] - self.CurrentRange)
   634                 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))]
   634                 self.StartTick = self.Ticks.view[np.searchsorted(self.Ticks.view, - new_start_tick)]
   635                 self.Fixed = new_start_tick < self.Ticks[-1] - self.CurrentRange
   635                 self.Fixed = new_start_tick < self.Ticks.view[-1] - self.CurrentRange
   636             self.ForceRefresh()
   636             self.ForceRefresh()
   637 
   637 
   638     def RefreshRange(self):
   638     def RefreshRange(self):
   639         if len(self.Ticks) > 0:
   639         if self.Ticks.count > 0:
   640             if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange:
   640             if self.Fixed and self.Ticks.view[-1] - self.Ticks.view[0] < self.CurrentRange:
   641                 self.Fixed = False
   641                 self.Fixed = False
   642             if self.Fixed:
   642             if self.Fixed:
   643                 self.StartTick = min(self.StartTick, self.Ticks[-1] - self.CurrentRange)
   643                 self.StartTick = min(self.StartTick, self.Ticks.view[-1] - self.CurrentRange)
   644             else:
   644             else:
   645                 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
   645                 self.StartTick = max(self.Ticks.view[0], self.Ticks.view[-1] - self.CurrentRange)
   646         self.ForceRefresh()
   646         self.ForceRefresh()
   647 
   647 
   648     def OnRangeChanged(self, event):
   648     def OnRangeChanged(self, event):
   649         try:
   649         try:
   650             self.CurrentRange = self.RANGE_VALUES[self.CanvasRange.GetSelection()][1] // self.Ticktime
   650             self.CurrentRange = self.RANGE_VALUES[self.CanvasRange.GetSelection()][1] // self.Ticktime
   652             self.CanvasRange.SetValue(str(self.CurrentRange))
   652             self.CanvasRange.SetValue(str(self.CurrentRange))
   653         wx.CallAfter(self.RefreshRange)
   653         wx.CallAfter(self.RefreshRange)
   654         event.Skip()
   654         event.Skip()
   655 
   655 
   656     def OnCurrentButton(self, event):
   656     def OnCurrentButton(self, event):
   657         if len(self.Ticks) > 0:
   657         if self.Ticks.count > 0:
   658             self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
   658             self.StartTick = max(self.Ticks.view[0], self.Ticks.view[-1] - self.CurrentRange)
   659             self.ResetCursorTick()
   659             self.ResetCursorTick()
   660         event.Skip()
   660         event.Skip()
   661 
   661 
   662     def CopyDataToClipboard(self, variables):
   662     def CopyDataToClipboard(self, variables):
   663         text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables])
   663         text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables])
   693                      if item.IsNumVariable()]
   693                      if item.IsNumVariable()]
   694         wx.CallAfter(self.CopyDataToClipboard, variables)
   694         wx.CallAfter(self.CopyDataToClipboard, variables)
   695         event.Skip()
   695         event.Skip()
   696 
   696 
   697     def OnPositionChanging(self, event):
   697     def OnPositionChanging(self, event):
   698         if len(self.Ticks) > 0:
   698         if self.Ticks.count > 0:
   699             self.StartTick = self.Ticks[0] + event.GetPosition()
   699             self.StartTick = self.Ticks.view[0] + event.GetPosition()
   700             self.Fixed = True
   700             self.Fixed = True
   701             self.ForceRefresh()
   701             self.ForceRefresh()
   702         event.Skip()
   702         event.Skip()
   703 
   703 
   704     def GetRange(self):
   704     def GetRange(self):
   906             panel.Destroy()
   906             panel.Destroy()
   907         self.RefreshGraphicsSizer()
   907         self.RefreshGraphicsSizer()
   908         self.ForceRefresh()
   908         self.ForceRefresh()
   909 
   909 
   910     def ResetGraphicsValues(self):
   910     def ResetGraphicsValues(self):
   911         self.Ticks = numpy.array([])
   911         self.Ticks = RingBuffer()
   912         self.StartTick = 0
   912         self.StartTick = 0
   913         for panel in self.GraphicPanels:
   913         for panel in self.GraphicPanels:
   914             panel.ResetItemsData()
   914             panel.ResetItemsData()
   915         self.ResetCursorTick()
   915         self.ResetCursorTick()
   916 
   916