예제 #1
0
class PathPage(parentpage):
    def __init__(self, parent):
        super(PathPage, self).__init__(parent, 'Select New Storage Dir')
        if guihelper.IsMSWindows():
            shell = client.Dispatch("WScript.Shell")
            self.defaultdir = os.path.join(shell.SpecialFolders("MyDocuments"),
                                           'Phones')
        else:
            self.defaultdir = os.path.expanduser('~/Phones')

    def GetMyControls(self):
        vbs = wx.BoxSizer(wx.VERTICAL)
        vbs.Add(wx.StaticText(self, -1, 'Storage Dir:'), 0, wx.EXPAND | wx.ALL,
                5)
        self.path = ExpandoTextCtrl(self, -1, '', style=wx.TE_READONLY)
        self.path.SetBackgroundColour(self.GetBackgroundColour())
        vbs.Add(self.path, 0, wx.EXPAND | wx.ALL, 5)
        btn = wx.Button(self, -1, 'Browse')
        wx.EVT_BUTTON(self, btn.GetId(), self.OnBrowse)
        vbs.Add(btn, 0, wx.ALL, 5)
        return vbs

    def ok(self):
        return bool(self.path.GetValue())

    def get(self, data):
        data['path'] = self.path.GetValue()

    def set(self, data):
        path = data.get('path', '')
        if not path:
            path = os.path.join(self.defaultdir, data.get('name', ''))
        self.path.SetValue(path)

    def OnBrowse(self, _):
        with guihelper.WXDialogWrapper(
                wx.DirDialog(self,
                             defaultPath=self.path.GetLabel(),
                             style=wx.DD_NEW_DIR_BUTTON),
                True) as (dlg, retcode):
            if retcode == wx.ID_OK:
                self.path.SetValue(dlg.GetPath())
예제 #2
0
    def addRow(self, row, rowLabel=None):
        """Add one row of info, either header (col names) or normal data

        Adds items sequentially; FlexGridSizer moves to next row automatically
        """
        labelBox = wx.BoxSizer(wx.HORIZONTAL)
        if not rowLabel:
            if sys.platform == 'darwin':
                self.SetWindowVariant(variant=wx.WINDOW_VARIANT_SMALL)
            label = _translate('cond %s:') % str(row + 1 -
                                                 int(self.hasHeader)).zfill(2)
            rowLabel = wx.StaticText(self, -1, label=label)
            rowLabel.SetForegroundColour(darkgrey)
            if sys.platform == 'darwin':
                self.SetWindowVariant(variant=wx.WINDOW_VARIANT_NORMAL)
        labelBox.Add(rowLabel, 1, flag=wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM)
        self.sizer.Add(labelBox, 1, flag=wx.ALIGN_CENTER)
        lastRow = []
        for col in range(self.cols):
            # get the item, as unicode for display purposes:
            if len(str(self.grid[row][col])):  # want 0, for example
                item = str(self.grid[row][col])
            else:
                item = u''
            # make a textbox:
            field = ExpandoTextCtrl(self,
                                    -1,
                                    item,
                                    size=(self.colSizes[col], 20))
            field.Bind(EVT_ETC_LAYOUT_NEEDED, self.onNeedsResize)
            field.SetMaxHeight(100)  # ~ 5 lines
            if self.hasHeader and row == 0:
                # add a default column name (header) if none provided
                header = self.grid[0]
                if item.strip() == '':
                    c = col
                    while self.colName(c) in header:
                        c += 1
                    field.SetValue(self.colName(c))
                field.SetForegroundColour(darkblue)  # dark blue
                # or (self.parent and
                if not valid_var_re.match(field.GetValue()):
                    # self.parent.exp.namespace.exists(field.GetValue()) ):
                    # was always red when preview .xlsx file -- in
                    # namespace already is fine
                    if self.fixed:
                        field.SetForegroundColour("Red")
                field.SetToolTip(
                    wx.ToolTip(
                        _translate(
                            'Should be legal as a variable name (alphanumeric)'
                        )))
                field.Bind(wx.EVT_TEXT, self.checkName)
            elif self.fixed:
                field.SetForegroundColour(darkgrey)
                field.SetBackgroundColour(white)

            # warn about whitespace unless will be auto-removed. invisible,
            # probably spurious:
            if (self.fixed or not self.clean) and item != item.strip():
                field.SetForegroundColour('Red')
                # also used in show():
                self.warning = _translate('extra white-space')
                field.SetToolTip(wx.ToolTip(self.warning))
            if self.fixed:
                field.Disable()
            lastRow.append(field)
            self.sizer.Add(field, 1)
        self.inputFields.append(lastRow)
        if self.hasHeader and row == 0:
            self.header = lastRow
예제 #3
0
class TestFrame(wx.Frame):
    def __init__(self, parent, log):
        wx.Frame.__init__(self, parent, title="Test ExpandoTextCtrl")
        self.log = log
        self.pnl = p = wx.Panel(self)
        self.eom = ExpandoTextCtrl(
            p, size=(250, -1), value="This control will expand as you type")
        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.eom)

        # create some buttons and sizers to use in testing some
        # features and also the layout
        vBtnSizer = wx.BoxSizer(wx.VERTICAL)

        btn = wx.Button(p, -1, "Set MaxHeight")
        self.Bind(wx.EVT_BUTTON, self.OnSetMaxHeight, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        btn = wx.Button(p, -1, "Set Font")
        self.Bind(wx.EVT_BUTTON, self.OnSetFont, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        btn = wx.Button(p, -1, "Write Text")
        self.Bind(wx.EVT_BUTTON, self.OnWriteText, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        btn = wx.Button(p, -1, "Append Text")
        self.Bind(wx.EVT_BUTTON, self.OnAppendText, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        btn = wx.Button(p, -1, "Set Value")
        self.Bind(wx.EVT_BUTTON, self.OnSetValue, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        btn = wx.Button(p, -1, "Get Value")
        self.Bind(wx.EVT_BUTTON, self.OnGetValue, btn)
        vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)

        for x in range(3):
            btn = wx.Button(p, -1, " ")
            vBtnSizer.Add(btn, 0, wx.ALL | wx.EXPAND, 5)
            self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn)

        hBtnSizer = wx.BoxSizer(wx.HORIZONTAL)
        for x in range(3):
            btn = wx.Button(p, -1, " ")
            hBtnSizer.Add(btn, 0, wx.ALL, 5)
            self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn)

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        col1 = wx.BoxSizer(wx.VERTICAL)
        col1.Add(self.eom, 0, wx.ALL, 10)
        col1.Add(hBtnSizer)
        sizer.Add(col1)
        sizer.Add(vBtnSizer)
        p.SetSizer(sizer)

        # Put the panel in a sizer for the frame so we can use self.Fit()
        frameSizer = wx.BoxSizer()
        frameSizer.Add(p, 1, wx.EXPAND)
        self.SetSizer(frameSizer)

        self.Fit()

    def OnRefit(self, evt):
        # The Expando control will redo the layout of the
        # sizer it belongs to, but sometimes this may not be
        # enough, so it will send us this event so we can do any
        # other layout adjustments needed.  In this case we'll
        # just resize the frame to fit the new needs of the sizer.
        self.Fit()

    def OnSetMaxHeight(self, evt):
        mh = self.eom.GetMaxHeight()
        dlg = wx.NumberEntryDialog(self, "", "Enter new max height:",
                                   "MaxHeight", mh, -1, 1000)
        if dlg.ShowModal() == wx.ID_OK:
            self.eom.SetMaxHeight(dlg.GetValue())
        dlg.Destroy()

    def OnSetFont(self, evt):
        dlg = wx.FontDialog(self, wx.FontData())
        dlg.GetFontData().SetInitialFont(self.eom.GetFont())
        if dlg.ShowModal() == wx.ID_OK:
            self.eom.SetFont(dlg.GetFontData().GetChosenFont())
        dlg.Destroy()

    def OnWriteText(self, evt):
        self.eom.WriteText("\nThis is a test...  Only a test.  If this had "
                           "been a real emergency you would have seen the "
                           "quick brown fox jump over the lazy dog.\n")

    def OnAppendText(self, evt):
        self.eom.AppendText("\nAppended text.")

    def OnSetValue(self, evt):
        self.eom.SetValue("A new value.")

    def OnGetValue(self, evt):
        self.log.write("-----------------\n" + self.eom.GetValue())

    def OnOtherBtn(self, evt):
        # just for testing...
        #print(self.eom.numLines)
        self.eom._adjustCtrl()
예제 #4
0
class _PlotCanvas(_PlotCanvas_Base):
    def __init__(self, dock, parent, Real_Time=False):
        _PlotCanvas_Base.__init__(self, dock, parent, Real_Time)
        #print 'REAL_TIME ??',Real_Time,self.Real_Time
        self.parent = parent

        # some initial values  SHOULD NOT BE HERE !!
        self.grid_x = 10
        self.grid_y = 10

        # *************************************************************
        # popup menus
        # *************************************************************
        pre = [
            _(0, 'Remove Cursors'),
            _(0, 'Memo Visible'),
            _(0, 'Move Memo Here'),
            _(0, 'Copy to Clipboard'), '-',
            _(0, 'Linear Expansion'),
            _(0, 'Not Transparent'),
            _(0, 'Transparency 200'),
            _(0, 'Transparency 150'),
            _(0, 'Transparency 100'),
            _(0, 'Transparency 50')
        ]
        self.Popup_Menu = My_Popup_Menu(self._OnPopupItemSelected,
                                        None,
                                        pre=pre)
        self.Transparancy = 0

        # At this point we can do all actions that really draw !!
        # call OnSize, to make sure the dc-buffer is initialized.
        self.Set_Canvas(self.BG_Color, self.Grid_Color)
        self._On_Size(None)

    # *****************************************************************
    # *****************************************************************
    def _On_Show_Popup(self, event):
        self.Popup_Menu.SetChecked(1, self.Memo_Extra)
        self.Popup_Menu.SetChecked(4, self.Linear_Interpolation)
        for i in range(5):
            self.Popup_Menu.SetChecked(5 + i, self.Transparancy == i)

        self.Hit_Pos = self.ScreenToClient(event.GetPosition())
        self.PopupMenu(self.Popup_Menu, pos=self.Hit_Pos)

    # *****************************************************************
    # *****************************************************************
    def _OnPopupItemSelected(self, event):
        ID = event.Int

        if ID == 0:
            self._Draw_Cursor(0, -1)
            self._Draw_Cursor(1, -1)

        elif ID == 1:
            if not (self.Memo_Extra):
                self.Memo_Extra = ExpandoTextCtrl(self,
                                                  size=(100, -1),
                                                  pos=self.Hit_Pos,
                                                  value=self.Memo_Extra_Text)
            else:
                #print 'YTRFGJKOP',self.Hit_Pos,event.GetId(),self.Memo_Extra.GetId()
                self.Memo_Extra_Text = self.Memo_Extra.GetValue()
                self.Memo_Extra.Destroy()
                self.Memo_Extra = None

        elif ID == 2:
            if not (self.Memo_Extra):
                self.Memo_Extra = ExpandoTextCtrl(self,
                                                  size=(100, -1),
                                                  pos=self.Hit_Pos,
                                                  value=self.Memo_Extra_Text)
            else:
                self.Memo_Extra.SetPosition(self.Hit_Pos)

        elif ID == 3:
            import SendKeys
            SendKeys.SendKeys('%{PRTSC}')

        elif ID == 4:
            self.Linear_Interpolation = not (self.Linear_Interpolation)
            self.Set_Data(self.Data)  # _Redraw_Data ()
            #self._Redraw()

        elif ID in range(5, 10):
            self.Transparancy = ID - 5
            val = 5 + 50 * (5 - self.Transparancy)
            self.TopFrame.SetTransparent(val)

    # *****************************************************************
    # Draw "LEFT" measurement cursor
    # *****************************************************************
    def _On_Mouse_Left(self, event):
        x, y = event.GetPosition()
        self._Draw_Cursor(0, x, y)

    # *****************************************************************
    # Dragging of the measurement cursors
    # *****************************************************************
    def _On_Mouse_Move(self, event):
        if event.LeftIsDown():
            self._On_Mouse_Left(event)
        elif event.MiddleIsDown():
            self._On_Mouse_Middle(event)

    # *****************************************************************
    # Draw "RIGHT" measurement cursor
    # *****************************************************************
    def _On_Mouse_Middle(self, event):
        x, y = event.GetPosition()
        self._Draw_Cursor(1, x, y)

    # *****************************************************************
    # *****************************************************************
    def _On_Size(self, event):
        for chan in range(len(self.gain)):
            self._Correct_Gain(chan)
        self._Redraw_Screen()

    # *****************************************************************
    # adds a new signal-channel to the plot canvas
    # *****************************************************************
    def Add_Channel(self):
        self.curves.append(_Channel(self.Buf_max))
        self.gain.append(1)
        self.offset.append(0)
        self.cal1.append(None)
        self.cal2.append(None)
        self.name.append('Signal')

    # *****************************************************************
    # Convenience function that returns the number of displayed signals
    # *****************************************************************
    def Get_NCurve(self):
        return len(self.curves)

    # *****************************************************************
    # Let the main program change one or more parameters of the _Channel
    # *****************************************************************
    def Set_Channel(self,
                    chan,
                    base_gain=1.0,
                    base_offset=0,
                    name='Signal',
                    cal1=None,
                    cal2=None,
                    delay=None,
                    color=None):
        # if curves don't exists here, create them
        while self.Get_NCurve() <= chan:
            self.Add_Channel()
        self.name[chan] = name
        self.cal1[chan] = cal1
        self.cal2[chan] = cal2
        self.gain[chan] = base_gain
        self.offset[chan] = base_offset
        self._Correct_Gain(chan, delay, color)
        self._Redraw_Screen()

    # *****************************************************************
    # Called by the timer, to refresh the label values,
    # and by measurement cursors
    # *****************************************************************
    def Get_DataSet(self, from_end):
        #v3print ( 'Scope.Get_DataSet: self.curves =', self.curves )
        if not self.curves: return
        """
    self.old_Cursor = [ -1, -1 ]
    if self.oldx < 0 :
      # Display of realtime signals
      p = ( self.Buf_wp - 1 ) % self.Buf_max
    else:
      # display of measurement cursor
      p = self.Buf_rp - ( self.Dp - self.oldx ) % self.Size [0]
    """
        # Display of realtime signals
        if self.Real_Time:
            p = (self.Buf_wp - 1 - from_end) % self.Buf_max
        else:
            p = from_end
        data = []
        for chan, curve in enumerate(self.curves):
            #v3print ( 'Scope.Get_DataSet: chan/ curve =', chan, curve )
            #data.append ( self.gain [ chan ] * curve.Buf [ p ] + \
            #              self.offset [ chan ])
            gain = self.parent.Signal_Gain[chan]
            if gain:
                offset = self.parent.Signal_Offset[chan]
                data.append(gain * curve.Buf[p] + offset)
            else:
                data.append(curve.Buf[p])
        #v3print ( 'Data', data )
        return data

    # *****************************************************************
    # *****************************************************************
    def _Correct_Gain(self, chan, delay=None, color=None):
        cal1 = self.cal1[chan]
        cal2 = self.cal2[chan]
        self.base_gain = self.gain[chan]
        self.base_offset = self.offset[chan]
        if (cal1 != None) and (cal2 != None) and (cal1 != cal2):
            w1 = self.GetClientSize()[1]
            w2 = 0
            gain2 = 1.0 * (w2 - w1) / (cal2 - cal1)
            offset2 = 1.0 * (cal2 * w1 - cal1 * w2) / (cal2 - cal1)
            gain = gain2 * self.base_gain,
            offset = gain2 * self.base_offset + offset2
        else:
            gain = self.base_gain
            offset = self.base_offset
        self.curves[chan]._Set_Channel(gain, offset, delay, color)

    # *****************************************************************
    # *****************************************************************
    def Set_Data(self, data=None):
        """
    Sets all the data in none Real-Time mode.
    Is also called in Real-Time mode,
      on resize and history cursor movement.
      In that case data is None,
      because Real-Time data is stored in the curves themself,
      and this function should do nothing.
    """
        if data == None:
            if self.Real_Time:
                return
            try:
                a = self.Data
            except:
                return
        else:
            self.Data = data
        #v3print ( 'Normal Scope, set data', self.Data.shape )

        # M = the number of available channels
        # N = the number of samples in one channel
        M, N = self.Data.shape
        if N < 2:
            return

        # if delivered number of signals too large,
        # create new channels
        Ncurves = len(self.curves)
        if M > Ncurves: M = Ncurves
        #while len ( self.curves ) < M :
        #  self.Add_Channel ( )

        #print 'Set_Data',N, self.Size[0],self.curves
        if N >= self.Size[0]:
            N_Average = 1 + N / self.Size[0]
            MaxI = (N / N_Average)  #* N_Average
            for i, curve in enumerate(self.curves[:M]):
                for ii in range(MaxI):
                    curve.Buf[ii] = 0
                    for ai in range(N_Average):
                        curve.Buf[ii] += self.Data[i, ii * N_Average + ai]
                    curve.Buf[ii] /= N_Average
        else:
            N_Average = self.Size[0] / N
            MaxI = (N - 1) * N_Average
            if self.Linear_Interpolation:
                N_Afloat = 1.0 * N_Average
                for i, curve in enumerate(self.curves[:M]):
                    # we don't use the last element
                    for ii in range(N - 1):
                        delta = (self.Data[i, ii + 1] -
                                 self.Data[i, ii]) / N_Afloat
                        for ai in range(N_Average):
                            curve.Buf [ ii * N_Average + ai ] = \
                              self.Data [ i, ii ] + ai * delta

            else:
                for i, curve in enumerate(self.curves[:M]):
                    for ii in range(N):
                        for ai in range(N_Average):
                            curve.Buf[ii * N_Average + ai] = self.Data[i, ii]

        # and draw it
        self.Dp = MaxI
        self._Redraw_Screen()

    # *****************************************************************
    # Adds MANY dataset to the history buffer
    # data must be a 2-dimensional array
    # *****************************************************************
    def Append_Data(self, data):
        #print 'HHH',type(data),data,data.shape,len ( self.curves )
        # M = the number of available channels
        # N = the number of samples in one channel
        #if data.ndim == 1 :
        #  M = 1
        #  N = data.shape[0]
        #else:
        M, N = data.shape
        if self.Buf_wp + N >= self.Buf_max:
            N1 = self.Buf_max - self.Buf_wp
            N2 = N - N1
        else:
            N1 = N
            N2 = 0

        # if delivered number of signals too large,
        # create new channels
        Ncurves = len(self.curves)
        if M > Ncurves: M = Ncurves
        #while len ( self.curves ) < M :
        #  self.Add_Channel ( )

        #print N,N1,N2,M,self.Buf_wp,self.Buf_max
        # Here just process the number of available channels (M)
        for i, curve in enumerate(self.curves[:M]):
            if len(curve.Delayed) > 0:
                curve.Delayed = r_[curve.Delayed[N1:], data[i][:N1]]
                curve.Buf[self.Buf_wp:self.Buf_wp + N1] = curve.Delayed[:N1]
            else:
                curve.Buf[self.Buf_wp:self.Buf_wp + N1] = data[i][:N1]
            """
      if i == 0 :
        self.Delayed = r_ [ self.Delayed [N1:], data [i][:N1]]
        curve.Buf [ self.Buf_wp : self.Buf_wp + N1 ] = self.Delayed [:N1]
      else :
        curve.Buf [ self.Buf_wp : self.Buf_wp + N1 ] = data [i][:N1]
      """
            #print 'EEEEEEEERRRRREEEEOOOORRRR',len(curve.Buf[:N2]),N-N1,curve.Buf.shape,data.shape
            #print N2,self.Buf_max,curve.Buf.shape,curve.Buf [:N2].shape,data [i][ N1 : N ].shape
            curve.Buf[:N2] = data[i][N1:N]

        self.Buf_wp += N
        self.Buf_wp %= self.Buf_max

        # *****************************************************************
        # notify the display update timer, that there's new data available
        # *****************************************************************
        ## self.My_Parent.New_Data = True
        self.Draw_Curves()

    # *****************************************************************
    # Redraw the signals and the grid, when the window is resized
    # *****************************************************************
    def _Redraw_Screen(self):
        # The Buffer init is done here, to make sure the buffer is always
        # the same size as the Window
        self.Size = self.GetClientSize()
        #print '_Redraw_Screen, get size',self.Size
        if self.Size[0] * self.Size[1] <= 0:
            return

        # Make new offscreen bitmap: this bitmap will always have the
        # current drawing in it, so it can be used to save the image to
        # a file, or whatever.
        self._Buffer = wx.Bitmap(*self.Size)

        # remove measurement cursors (must be done before creating dc)
        #self._Draw_Cursor ( 0, -1 )
        #self._Draw_Cursor ( 1, -1 )
        # don't use _Draw_Cursor, because then a lot of flicker will result
        for C in [0, 1]:
            if self.old_Cursor[C] >= 0:
                self.old_CMemo[C].Destroy()
                self.old_CMemo[C] = None
                self.CMemo_Labels = [[], []]
                self.old_Cursor[C] = -1

        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
        dc.SetBrush(self.Brush)

        # draw the grid
        self.grid_x = 1.0 * self.Size[0] / XDIV
        self.grid_y = 1.0 * self.Size[1] / YDIV
        self.erase_th = int(0.5 * self.grid_x)
        for xi in range(XDIV):
            self._Draw_Grid_Block(dc, xi)
            self.Erase_Block[xi] = False

        self.Draw_Curves(True)
        #dc.EndDrawing()
        # Refresh must be called to garantee a correct visible image
        self.Refresh()

    # *****************************************************************
    # Draws a chunk of newly received data to the display,
    # can also Redraw the complete signal, in case of resize
    # *****************************************************************
    def Draw_Curves(self, Redraw=False):
        #print 'Draw_Curves: Redraw, RealTime =', Redraw, self.Real_Time
        if not (self.curves): return

        # Clipping doesn't make much sense !!
        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
        dc.SetBrush(self.Brush)

        # In case not realtime, simply draw from the start
        if not (self.Real_Time):
            #print 'Block-1'
            N = self.Dp
            x11 = 0
            xbuf = 0
            for curve in self.curves:
                curve._Draw(dc, N, x11, xbuf)
            return

        #if self.grid_x < 1 : return
        #print 'redraw,',Redraw
        if Redraw:  # in case of a total redraw
            #print 'OOOO',self.Dp,self.grid_x, Redraw
            if self.grid_x < 1: self.grid_x = 10

            x22 = self.Dp
            n = self.Dp % int(self.grid_x)
            N = self.Size[0] - (self.grid_x - n)
            if n > self.erase_th:
                N = N - self.grid_x
            # Be sure everything is integer !!
            N = int(N)
            x11 = (x22 - N) % self.Size[0]
            xbuf = (self.Buf_rp - N) % self.Buf_max
            #print 'Block-2',self.Dp,N,x11,x22,xbuf,self.Buf_wp,self.Buf_rp

        else:  # in case of normal draw of small chunks
            x11 = self.Dp
            N = (self.Buf_wp - self.Buf_rp) % self.Buf_max
            # Be sure everything is integer !!
            N = int(N)
            x22 = (x11 + N) % self.Size[0]
            xbuf = self.Buf_rp
            #print 'Block-3',self.Dp,N,x11,x22,xbuf,self.Buf_wp,self.Buf_rp

        x1, x1r = divmod(x11, int(self.grid_x))
        x2, x2r = divmod(x22, int(self.grid_x))
        x1_next = (x1 + 1) % XDIV
        if not ( self.Erase_Block [ x1_next ] ) and \
           ( ( x1r > self.erase_th ) or ( x2r > self.erase_th ) or ( x1 != x2 ) ) :
            self._Draw_Grid_Block(dc, x1_next)

        # draw curves, here wrapping around display end is done,
        # curve._Draw does the wrapping around the history buffer
        if x11 <= x22:
            for curve in self.curves:
                curve._Draw(dc, N, x11, xbuf)
        else:
            for curve in self.curves:
                curve._Draw(dc, self.Size[0] - x11, x11, xbuf)
                curve._Draw(dc, x22, 0,
                            (xbuf + self.Size[0] - x11) % self.Buf_max)

        if not (Redraw):
            self.Buf_rp = (self.Buf_wp - 1) % self.Buf_max
            self.Dp = (self.Dp + N - 1) % self.Size[0]

        #dc.EndDrawing()

    # *****************************************************************
    # Draws a vertical grid block (and thereby erasing the signals)
    # over 1 X-division.
    # *****************************************************************
    def _Draw_Grid_Block(self, dc, xi):
        dc.SetPen(wx.Pen(self.Grid_Color, 1))
        rectangles = []
        # we need to do this so complex to be sure the blocks will overlap
        # and thus getting a 1-width line !!
        xi = xi % XDIV
        x = int(round(xi * self.grid_x))
        w = int(round((xi + 1) * self.grid_x + 1)) - x
        for i in range(YDIV):
            y = int(round(i * self.grid_y))
            h = int(round((i + 1) * self.grid_y + 1)) - y
            if y + h > self.Size[1]:
                h = self.Size[1] - y
            rectangles.append((x, y, w, h))

        dc.DrawRectangleList(rectangles)
        self.Erase_Block[xi] = True
        self.Erase_Block[(xi + 1) % XDIV] = False

    # *****************************************************************
    # Draws a measurement cursor at position x,
    # a previous cursor is first removed.
    # Removing all cursors can be done by specifying a negative value for x
    # *****************************************************************
    def _Draw_Cursor(self, C, x, y=None):
        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
        #dc.SetLogicalFunction ( wx.XOR )
        dc.SetLogicalFunction(wx.INVERT)
        dc.SetPen(wx.Pen((0, 0, 0), 2, wx.SOLID))
        #dc.SetPen ( wx.Pen ( (255,255,255), 2, wx.SOLID ))

        if self.old_Cursor[C] >= 0:
            dc.DrawLine(self.old_Cursor[C], 0, self.old_Cursor[C],
                        self.Size[1])

        if x >= 0:
            dc.DrawLine(x, 0, x, self.Size[1])

            # calculate the position in the history array
            if self.Real_Time:
                from_end = self.Dp - x
                if x > self.Dp:
                    from_end += self.Size[0]
            else:
                from_end = x
                if x >= self.Dp:
                    from_end = self.Dp - 1
            data = self.Get_DataSet(from_end)

            N = len(self.curves)
            if not (self.old_CMemo[C]):
                self.old_CMemo[C] = wx.Panel(self)
                self.old_CMemo[C].SetBackgroundColour(self.BG_Color)

                Sizer = wx.BoxSizer(wx.VERTICAL)
                self.old_CMemo[C].SetSizer(Sizer)
                for i in range(N):
                    label = wx.StaticText(self.old_CMemo[C])
                    self.CMemo_Labels[C].append(label)
                    label.SetForegroundColour(self.curves[i].Pen.GetColour())
                    Sizer.Add(label, 0, wx.EXPAND)

                # now add 2 extra memos for samp and time measurement
                for i in range(2):
                    label = wx.StaticText(self.old_CMemo[C])
                    self.CMemo_Labels[C].append(label)
                    label.SetForegroundColour(wx.BLACK)
                    Sizer.Add(label, 0, wx.EXPAND)

            # now put in the actual measurement values
            # and determine the max width on the flight
            dc = wx.ScreenDC()
            w = 0
            for chan in range(N):
                value = self.gain[chan] * data[chan] + self.offset[chan]
                line = nice_number(value)
                line = self.name[chan] + ' =' + line
                w = max(w, dc.GetTextExtent(line)[0])
                #v3print ( 'Label', chan, value, line, w )
                self.CMemo_Labels[C][chan].SetLabel(line)

            # ***********************************************************
            # ***********************************************************
            # are there 2 cursors ?
            if (C == 0) and self.old_CMemo[1]:
                x2 = self.old_Cursor[1]
            elif (C == 1) and self.old_CMemo[0]:
                x2 = self.old_Cursor[0]
            else:
                x2 = None

            delta = None

            # ***********************************************************
            # LEFT cursor is always absolute
            # ***********************************************************
            if C == 0:
                line = 'Time =' + str(1.0 * x / 100)
                w = max(w, dc.GetTextExtent(line)[0])
                self.CMemo_Labels[C][N].SetLabel(line)
                line = 'NSamp =' + str(x)
                w = max(w, dc.GetTextExtent(line)[0])
                self.CMemo_Labels[C][N + 1].SetLabel(line)

                if x2:  # if also RIGHT cursor available, adapt it
                    dx = x2 - x
                    delta = '-'
                else:
                    delta = None

            # ***********************************************************
            # RIGHT cursor is absolute if there's no LEFT cursor
            # ***********************************************************
            else:  # this is the RIGHT cursor
                if x2:
                    dx = x - x2
                    delta = '-'
                else:  # if other cursor not available
                    dx = x
                    delta = ''

            if delta != None:
                line = delta + 'Time =' + str(1.0 * dx / 100)
                w = max(w, dc.GetTextExtent(line)[0])
                self.CMemo_Labels[1][N].SetLabel(line)
                line = delta + 'NSamp =' + str(dx)
                w = max(w, dc.GetTextExtent(line)[0])
                self.CMemo_Labels[1][N + 1].SetLabel(line)

            # Print mean and std over the selected period
            if x2 == None: x2 = 0
            if x > x2:
                x1 = x2
                x2 = x
            else:
                x1 = x
            if (x1 >= 0):
                data = []
                for i in range(x1, x2):
                    from_end = i
                    if i >= self.Dp:
                        from_end = self.Dp - 1
                    data.append(self.Get_DataSet(from_end))
                data = asarray(data).astype(int)
                import numpy
                print('mean / std = ',
                      numpy.mean(data, 0).round().astype(int),
                      numpy.std(data, 0).round().astype(int))

            # ***********************************************************
            # draw the values on the left for the left cursor (if possible)
            # to the right for the right cursor
            # ***********************************************************
            if Platform_Windows:
                w -= 17
            if ( ( C == 0 ) and ( x > w ) ) or \
               ( ( C == 1 ) and ( (x+w) > self.Size[0] )) :
                self.old_CMemo[C].SetPosition((x - w - 2, y + 5))
            else:
                self.old_CMemo[C].SetPosition((x + 2, y + 5))
            self.old_CMemo[C].Refresh()
            #if x2:
            N += 2
            self.old_CMemo[C].SetSize((w, N * 13))
            #self.old_CMemo[C].SendSizeEvent ()

        # ***********************************************************
        # remove this cursor
        # ***********************************************************
        else:
            if self.old_CMemo[C]:
                self.old_CMemo[C].Destroy()
                self.old_CMemo[C] = None
                self.CMemo_Labels = [[], []]

        #dc.EndDrawing()
        self.old_Cursor[C] = x
        self.Dock.SetFocus()