예제 #1
0
    def NewDataAvailable(self, ticks):
        """
        Called by DataProducer for each tick captured or by panel to refresh
        graphs
        @param tick: PLC tick captured
        All other parameters are passed to refresh function
        """
        # If tick given
        if ticks is not None:
            tick = ticks[-1]

            # Save tick as start tick for range if data is still empty
            if len(self.Ticks) == 0:
                self.StartTick = ticks[0]

            # Add tick to list of ticks received
            self.Ticks = numpy.append(self.Ticks, ticks)

            # 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)

            # 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[-1] - self.Ticks[0] < self.CurrentRange:
                self.Force = True

            self.HasNewData = False
            self.RefreshView()

        else:
            DebugViewer.NewDataAvailable(self, ticks)
예제 #2
0
    def SetDataProducer(self, producer):
        """
        Set Data 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())
예제 #3
0
    def RefreshNewData(self):
        """
        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:
            self.HasNewData = False
            self.RefreshView()

        DebugViewer.RefreshNewData(self)
예제 #4
0
    def SubscribeAllDataConsumers(self):
        DebugViewer.SubscribeAllDataConsumers(self)

        if self.DataProducer is not None:
            if self.DataProducer is not None:
                self.SetTickTime(self.DataProducer.GetTicktime())

        self.ResetCursorTick()

        for panel in self.GraphicPanels[:]:
            panel.SubscribeAllDataConsumers()
            if panel.ItemsIsEmpty():
                if panel.HasCapture():
                    panel.ReleaseMouse()
                self.GraphicPanels.remove(panel)
                panel.Destroy()

        self.ResetVariableNameMask()
        self.RefreshGraphicsSizer()
        self.ForceRefresh()
예제 #5
0
 def RefreshNewData(self, *args, **kwargs):
     if self.HasNewData:
         self.HasNewData = False
         self.RefreshView()
     DebugViewer.RefreshNewData(self, *args, **kwargs)
예제 #6
0
    def __init__(self, parent, window):
        wx.Panel.__init__(self,
                          parent,
                          style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
        DebugViewer.__init__(self, None, False, False)

        main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
        main_sizer.AddGrowableCol(0)
        main_sizer.AddGrowableRow(1)

        filter_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.AddSizer(filter_sizer,
                            border=5,
                            flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)

        self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY)
        self.MessageFilter.Append(_("All"))
        levels = LogLevels[:3]
        levels.reverse()
        for level in levels:
            self.MessageFilter.Append(_(level))
        self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged,
                  self.MessageFilter)
        filter_sizer.AddWindow(self.MessageFilter,
                               1,
                               border=5,
                               flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)

        self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER)
        self.SearchMessage.ShowSearchButton(True)
        self.SearchMessage.ShowCancelButton(True)
        self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchMessageChanged,
                  self.SearchMessage)
        self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
                  self.OnSearchMessageSearchButtonClick, self.SearchMessage)
        self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN,
                  self.OnSearchMessageCancelButtonClick, self.SearchMessage)
        filter_sizer.AddWindow(self.SearchMessage,
                               3,
                               border=5,
                               flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)

        self.CleanButton = wx.lib.buttons.GenBitmapButton(
            self,
            bitmap=GetBitmap("Clean"),
            size=wx.Size(28, 28),
            style=wx.NO_BORDER)
        self.CleanButton.SetToolTipString(_("Clean log messages"))
        self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton)
        filter_sizer.AddWindow(self.CleanButton)

        message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
        message_panel_sizer.AddGrowableCol(0)
        message_panel_sizer.AddGrowableRow(0)
        main_sizer.AddSizer(message_panel_sizer,
                            border=5,
                            flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)

        self.MessagePanel = wx.Panel(self)
        if wx.Platform == '__WXMSW__':
            self.Font = wx.Font(8,
                                wx.SWISS,
                                wx.NORMAL,
                                wx.NORMAL,
                                faceName='Courier New')
        else:
            self.Font = wx.Font(10,
                                wx.SWISS,
                                wx.NORMAL,
                                wx.NORMAL,
                                faceName='Courier')
        self.MessagePanel.Bind(wx.EVT_LEFT_UP, self.OnMessagePanelLeftUp)
        self.MessagePanel.Bind(wx.EVT_RIGHT_UP, self.OnMessagePanelRightUp)
        self.MessagePanel.Bind(wx.EVT_LEFT_DCLICK,
                               self.OnMessagePanelLeftDCLick)
        self.MessagePanel.Bind(wx.EVT_MOTION, self.OnMessagePanelMotion)
        self.MessagePanel.Bind(wx.EVT_LEAVE_WINDOW,
                               self.OnMessagePanelLeaveWindow)
        self.MessagePanel.Bind(wx.EVT_MOUSEWHEEL,
                               self.OnMessagePanelMouseWheel)
        self.MessagePanel.Bind(wx.EVT_ERASE_BACKGROUND,
                               self.OnMessagePanelEraseBackground)
        self.MessagePanel.Bind(wx.EVT_PAINT, self.OnMessagePanelPaint)
        self.MessagePanel.Bind(wx.EVT_SIZE, self.OnMessagePanelResize)
        message_panel_sizer.AddWindow(self.MessagePanel, flag=wx.GROW)

        self.MessageScrollBar = LogScrollBar(self, wx.Size(16, -1))
        message_panel_sizer.AddWindow(self.MessageScrollBar, flag=wx.GROW)

        self.SetSizer(main_sizer)

        self.LeftButtons = []
        for label, callback in [
            ("+" + text, self.GenerateOnDurationButton(duration))
                for text, duration in CHANGE_TIMESTAMP_BUTTONS
        ]:
            self.LeftButtons.append(LogButton(label, callback))

        self.RightButtons = []
        for label, callback in [
            ("-" + text, self.GenerateOnDurationButton(-duration))
                for text, duration in CHANGE_TIMESTAMP_BUTTONS
        ]:
            self.RightButtons.append(LogButton(label, callback))

        self.MessageFilter.SetSelection(0)
        self.LogSource = None
        self.ResetLogMessages()
        self.ParentWindow = window

        self.LevelIcons = [GetBitmap("LOG_" + level) for level in LogLevels]
        self.LevelFilters = [range(i) for i in xrange(4, 0, -1)]
        self.CurrentFilter = self.LevelFilters[0]
        self.CurrentSearchValue = ""

        self.ScrollSpeed = 0.
        self.LastStartTime = None
        self.ScrollTimer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnScrollTimer, self.ScrollTimer)

        self.LastMousePos = None
        self.MessageToolTip = None
        self.MessageToolTipTimer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnMessageToolTipTimer,
                  self.MessageToolTipTimer)
예제 #7
0
    def __init__(self, parent, producer, window):
        """
        Constructor
        @param parent: Reference to the parent wx.Window
        @param producer: Object receiving debug value and dispatching them to
        consumers
        @param window: Reference to Beremiz frame
        """
        wx.Panel.__init__(self, parent, style=wx.SP_3D | wx.TAB_TRAVERSAL)

        # List of values possible for graph range
        # Format is [(time_in_plain_text, value_in_nanosecond),...]
        self.RANGE_VALUES = [(_("%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)]

        # 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
        self.HasNewData = False

        # Variable storing flag indicating that refresh has been forced, and
        # that next time refresh is possible, it will be done even if no new
        # data is available
        self.Force = False

        self.SetBackgroundColour(wx.WHITE)

        main_sizer = wx.BoxSizer(wx.VERTICAL)

        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 = []

        self.GraphicPanels = []

        graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(graphics_button_sizer, border=5, flag=wx.GROW | wx.ALL)

        range_label = wx.StaticText(self, label=_('Range:'))
        graphics_button_sizer.Add(range_label, flag=wx.ALIGN_CENTER_VERTICAL)

        self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY)
        self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange)
        graphics_button_sizer.Add(self.CanvasRange,
                                  1,
                                  border=5,
                                  flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL)

        self.CanvasRange.Clear()
        default_range_idx = 0
        for idx, (text, _value) in enumerate(self.RANGE_VALUES):
            self.CanvasRange.Append(text)
            if _value == 1000000000:
                default_range_idx = idx
        self.CanvasRange.SetSelection(default_range_idx)

        for name, bitmap, help in [("CurrentButton", "current",
                                    _("Go to current value")),
                                   ("LoadButton", "open", _("load vars")),
                                   ("SaveButton", "save", _("save vars")),
                                   ("ExportGraphButton", "export_graph",
                                    _("Export graph values to clipboard"))]:
            button = wx.lib.buttons.GenBitmapButton(self,
                                                    bitmap=GetBitmap(bitmap),
                                                    size=wx.Size(28, 28),
                                                    style=wx.NO_BORDER)
            button.SetToolTip(help)
            setattr(self, name, button)
            self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button)
            graphics_button_sizer.Add(button, border=5, flag=wx.LEFT)

        self.CanvasPosition = wx.ScrollBar(self,
                                           size=wx.Size(0, 16),
                                           style=wx.SB_HORIZONTAL)
        self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK,
                                 self.OnPositionChanging, self.CanvasPosition)
        self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, self.OnPositionChanging,
                                 self.CanvasPosition)
        self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN,
                                 self.OnPositionChanging, self.CanvasPosition)
        self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, self.OnPositionChanging,
                                 self.CanvasPosition)
        self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN,
                                 self.OnPositionChanging, self.CanvasPosition)
        main_sizer.Add(self.CanvasPosition,
                       border=5,
                       flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM)

        self.TickSizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(self.TickSizer, border=5, flag=wx.ALL | wx.GROW)

        self.TickLabel = wx.StaticText(self)
        self.TickSizer.Add(self.TickLabel, border=5, flag=wx.RIGHT)

        self.MaskLabel = wx.TextCtrl(self,
                                     style=wx.TE_READONLY | wx.TE_CENTER
                                     | wx.NO_BORDER)
        self.TickSizer.Add(self.MaskLabel,
                           1,
                           border=5,
                           flag=wx.RIGHT | wx.GROW)

        self.TickTimeLabel = wx.StaticText(self)
        self.TickSizer.Add(self.TickTimeLabel)

        self.GraphicsWindow = wx.ScrolledWindow(self,
                                                style=wx.HSCROLL | wx.VSCROLL)
        self.GraphicsWindow.SetBackgroundColour(wx.WHITE)
        self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self))
        self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint)
        self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize)
        self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL,
                                 self.OnGraphicsWindowMouseWheel)

        main_sizer.Add(self.GraphicsWindow, 1, flag=wx.GROW)

        self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL)
        self.GraphicsWindow.SetSizer(self.GraphicsSizer)

        DebugViewer.__init__(self, producer, True)

        self.SetSizer(main_sizer)
        self.SetTickTime()
예제 #8
0
    def __init__(self, parent, window):
        wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        DebugViewer.__init__(self, None, False, False)

        main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
        main_sizer.AddGrowableCol(0)
        main_sizer.AddGrowableRow(1)

        filter_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)

        self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY)
        self.MessageFilter.Append(_("All"))
        levels = LogLevels[:3]
        levels.reverse()
        for level in levels:
            self.MessageFilter.Append(_(level))
        self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged, self.MessageFilter)
        filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)

        self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER)
        self.SearchMessage.ShowSearchButton(True)
        self.SearchMessage.ShowCancelButton(True)
        self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchMessageChanged, self.SearchMessage)
        self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
              self.OnSearchMessageSearchButtonClick, self.SearchMessage)
        self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN,
              self.OnSearchMessageCancelButtonClick, self.SearchMessage)
        filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)

        self.CleanButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("Clean"),
              size=wx.Size(28, 28), style=wx.NO_BORDER)
        self.CleanButton.SetToolTipString(_("Clean log messages"))
        self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton)
        filter_sizer.AddWindow(self.CleanButton)

        message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
        message_panel_sizer.AddGrowableCol(0)
        message_panel_sizer.AddGrowableRow(0)
        main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)

        self.MessagePanel = wx.Panel(self)
        if wx.Platform == '__WXMSW__':
            self.Font = wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier New')
        else:
            self.Font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier')
        self.MessagePanel.Bind(wx.EVT_LEFT_UP, self.OnMessagePanelLeftUp)
        self.MessagePanel.Bind(wx.EVT_RIGHT_UP, self.OnMessagePanelRightUp)
        self.MessagePanel.Bind(wx.EVT_LEFT_DCLICK, self.OnMessagePanelLeftDCLick)
        self.MessagePanel.Bind(wx.EVT_MOTION, self.OnMessagePanelMotion)
        self.MessagePanel.Bind(wx.EVT_LEAVE_WINDOW, self.OnMessagePanelLeaveWindow)
        self.MessagePanel.Bind(wx.EVT_MOUSEWHEEL, self.OnMessagePanelMouseWheel)
        self.MessagePanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnMessagePanelEraseBackground)
        self.MessagePanel.Bind(wx.EVT_PAINT, self.OnMessagePanelPaint)
        self.MessagePanel.Bind(wx.EVT_SIZE, self.OnMessagePanelResize)
        message_panel_sizer.AddWindow(self.MessagePanel, flag=wx.GROW)

        self.MessageScrollBar = LogScrollBar(self, wx.Size(16, -1))
        message_panel_sizer.AddWindow(self.MessageScrollBar, flag=wx.GROW)

        self.SetSizer(main_sizer)

        self.LeftButtons = []
        for label, callback in [("+" + text, self.GenerateOnDurationButton(duration))
                                for text, duration in CHANGE_TIMESTAMP_BUTTONS]:
            self.LeftButtons.append(LogButton(label, callback))

        self.RightButtons = []
        for label, callback in [("-" + text, self.GenerateOnDurationButton(-duration))
                                for text, duration in CHANGE_TIMESTAMP_BUTTONS]:
            self.RightButtons.append(LogButton(label, callback))

        self.MessageFilter.SetSelection(0)
        self.LogSource = None
        self.ResetLogMessages()
        self.ParentWindow = window

        self.LevelIcons = [GetBitmap("LOG_" + level) for level in LogLevels]
        self.LevelFilters = [range(i) for i in xrange(4, 0, -1)]
        self.CurrentFilter = self.LevelFilters[0]
        self.CurrentSearchValue = ""

        self.ScrollSpeed = 0.
        self.LastStartTime = None
        self.ScrollTimer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnScrollTimer, self.ScrollTimer)

        self.LastMousePos = None
        self.MessageToolTip = None
        self.MessageToolTipTimer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.OnMessageToolTipTimer, self.MessageToolTipTimer)
예제 #9
0
 def __init__(self, parent, producer, window):
     """
     Constructor
     @param parent: Reference to the parent wx.Window
     @param producer: Object receiving debug value and dispatching them to
     consumers
     @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
     self.HasNewData = False
     
     # Variable storing flag indicating that refresh has been forced, and
     # that next time refresh is possible, it will be done even if no new
     # data is available
     self.Force = False
     
     self.SetBackgroundColour(wx.WHITE)
     
     main_sizer = wx.BoxSizer(wx.VERTICAL)
     
     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 = []
     
     self.GraphicPanels = []
     
     graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
     main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL)
     
     range_label = wx.StaticText(self, label=_('Range:'))
     graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL)
     
     self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY)
     self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange)
     graphics_button_sizer.AddWindow(self.CanvasRange, 1, 
           border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
     
     self.CanvasRange.Clear()
     default_range_idx = 0
     for idx, (text, value) in enumerate(RANGE_VALUES):
         self.CanvasRange.Append(text)
         if text == "1s":
             default_range_idx = idx
     self.CanvasRange.SetSelection(default_range_idx)
     
     for name, bitmap, help in [
         ("CurrentButton", "current", _("Go to current value")),
         ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]:
         button = wx.lib.buttons.GenBitmapButton(self, 
               bitmap=GetBitmap(bitmap), 
               size=wx.Size(28, 28), style=wx.NO_BORDER)
         button.SetToolTipString(help)
         setattr(self, name, button)
         self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button)
         graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
     
     self.CanvasPosition = wx.ScrollBar(self, 
           size=wx.Size(0, 16), style=wx.SB_HORIZONTAL)
     self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, 
           self.OnPositionChanging, self.CanvasPosition)
     self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, 
           self.OnPositionChanging, self.CanvasPosition)
     self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN, 
           self.OnPositionChanging, self.CanvasPosition)
     self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, 
           self.OnPositionChanging, self.CanvasPosition)
     self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, 
           self.OnPositionChanging, self.CanvasPosition)
     main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
     
     self.TickSizer = wx.BoxSizer(wx.HORIZONTAL)
     main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL|wx.GROW)
     
     self.TickLabel = wx.StaticText(self)
     self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT)
     
     self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY|wx.TE_CENTER|wx.NO_BORDER)
     self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT|wx.GROW)
     
     self.TickTimeLabel = wx.StaticText(self)
     self.TickSizer.AddWindow(self.TickTimeLabel)
     
     self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL)
     self.GraphicsWindow.SetBackgroundColour(wx.WHITE)
     self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self))
     self.GraphicsWindow.Bind(wx.EVT_ERASE_BACKGROUND, self.OnGraphicsWindowEraseBackground)
     self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint)
     self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize)
     self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel)
     
     main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW)
     
     self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL)
     self.GraphicsWindow.SetSizer(self.GraphicsSizer)
 
     DebugViewer.__init__(self, producer, True)
     
     self.SetSizer(main_sizer)