    001package org.vishia.gral.swt;
    002
    003
    004
    005import java.util.List;
    006
    007import org.eclipse.swt.SWT;
    008import org.eclipse.swt.events.FocusEvent;
    009import org.eclipse.swt.events.FocusListener;
    010import org.eclipse.swt.events.PaintEvent;
    011import org.eclipse.swt.events.PaintListener;
    012import org.eclipse.swt.graphics.Color;
    013import org.eclipse.swt.graphics.GC;
    014import org.eclipse.swt.graphics.Image;
    015import org.eclipse.swt.graphics.Point;
    016import org.eclipse.swt.widgets.Canvas;
    017import org.eclipse.swt.widgets.Composite;
    018import org.vishia.gral.base.GralCurveView;
    019import org.vishia.gral.base.GralMng;
    020import org.vishia.gral.base.GralPos;
    021import org.vishia.gral.base.GralWidget;
    022import org.vishia.gral.ifc.GralColor;
    023import org.vishia.gral.ifc.GralRectangle;
    024import org.vishia.util.Assert;
    025import org.vishia.util.Debugutil;
    026
    027
    028
    029
    030public class SwtCurveView extends GralCurveView.GraphicImplAccess
    031{
    032
    033  /**Version, history and license.
    034   * <ul>
    035   * <li>2016-07-03 Hartmut chg: Now derived from {@link GralCurveView.GraphicImplAccess} adequate to the  new concept:
    036   *   An implementing widget is derived from its derived class of {@link GralWidget.ImplAccess}. Therefore only that base class implements the GralWidgetImpl_ifc.
    037   * <li>2014-02-03 Hartmut new: {@link CommonCurve#bFreeze}: freeze as common property of more as one GralCurveView. Constructor argument.
    038   * <li>2013-05-19 Hartmut new: Usage of the common {@link SwtGralMouseListener} and
    039   *   implementation of the special functionality in the superclass {@link GralCurveView.GralCurveViewMouseAction}.
    040   * <li>2012-08-11 Hartmut now grid with  timestamps
    041   * <li>2012-03-25 Hartmut improved zoom
    042   * <li>2012-03-17 Hartmut some improvements in paint routine.
    043   * <li>2012-02-26 Hartmut A lot of details, see {@link GralCurveView}
    044   * <li>2012-02-21 Hartmut Now the CurveView works in the new environment. Some adjustments necessary yet.
    045   * <li>2011-06-00 Hartmut New concept of GralWidget etc and new Configuration concept
    046   *   with {@link org.vishia.gral.cfg.GralCfgBuilder}. The old GuiDialogZbnfControlled.class
    047   *   was not use nevermore. But the CurveView was not adapted for that.
    048   * <li>2010-03-00 Hartmut The curve view was development as basic feature.
    049   * </ul>
    050   * <br><br>
    051   * <b>Copyright/Copyleft</b>:
    052   * For this source the LGPL Lesser General Public License,
    053   * published by the Free Software Foundation is valid.
    054   * It means:
    055   * <ol>
    056   * <li> You can use this source without any restriction for any desired purpose.
    057   * <li> You can redistribute copies of this source to everybody.
    058   * <li> Every user of this source, also the user of redistribute copies
    059   *    with or without payment, must accept this license for further using.
    060   * <li> But the LPGL is not appropriate for a whole software product,
    061   *    if this source is only a part of them. It means, the user
    062   *    must publish this part of source,
    063   *    but doesn't need to publish the whole source of the own product.
    064   * <li> You can study and modify (improve) this source
    065   *    for own using or for redistribution, but you have to license the
    066   *    modified sources likewise under this LGPL Lesser General Public License.
    067   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
    068   * </ol>
    069   * If you intent to use this source without publishing its usage, you can get
    070   * a second license subscribing a special contract with the author.
    071   *
    072   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
    073   *
    074   */
    075  @SuppressWarnings("hiding")
    076  public final static int version = 20120317;
    077
    078  private final CurveView curveSwt;
    079
    080  private final Image cursorStore1, cursorStore2;
    081
    082
    083
    084  protected Color gridColor, gridColorStrong;
    085
    086  protected final Color colorCursor, colorBack;
    087
    088
    089
    090  public SwtCurveView(GralCurveView widgg, SwtMng mng) //String sName, GralPos pos, SwtMng mng, int nrofXvalues, GralCurveView.CommonCurve common)
    091  {
    092    super(widgg);
    093    //super(sName, mng.mng, nrofXvalues, common);
    094    mouseListenerCurve = new SwtGralMouseListener.MouseListenerGralAction();
    095
    096    GralRectangle bounds = mng.calcWidgetPosAndSize(widgg.pos(), 800, 600);
    097    Composite panelSwt = (Composite)widgg.pos().panel.getWidgetImplementation();
    098    curveSwt = this.new CurveView(panelSwt, bounds.dx, bounds.dy, widgg.maxNrofXValues);
    099    curveSwt.setData(this);
    100    curveSwt.setSize(bounds.dx, bounds.dy);
    101    curveSwt.setBounds(bounds.x, bounds.y, bounds.dx, bounds.dy);
    102    //mng.setBounds_(curveSwt); //, dyGrid, dxGrid);
    103    curveSwt.setGridVertical(10, 5);   //10 data-points per grid line, 50 data-points per strong line.
    104    curveSwt.setGridHorizontal(50.0F, 5);  //10%-divisions, with 5 sub-divisions
    105    cursorStore1 = new Image(panelSwt.getDisplay(), 1, 2000);
    106    cursorStore2 = new Image(panelSwt.getDisplay(), 1, 2000);
    107
    108    gridColor = new Color(curveSwt.getDisplay(), 192, 255, 255);
    109    gridColorStrong = new Color(curveSwt.getDisplay(), 128, 255, 255);
    110    colorCursor = new Color(curveSwt.getDisplay(), 64, 64, 64);
    111    colorBack = new Color(curveSwt.getDisplay(), 0xff, 0xff, 0xff);
    112    widgg.initMenuContext();
    113  }
    114
    115
    116  @Override public void repaintGthread(){
    117    int chg = dyda().getChanged();  //impl.getChanged();
    118    int acknChg = 0;
    119    if((chg & chgVisible)!=0){
    120      acknChg |= chgVisible;
    121      curveSwt.setVisible(true);
    122      setFocusGThread();
    123    }
    124    if((chg & chgInvisible)!=0){
    125      acknChg |= chgInvisible;
    126      curveSwt.setVisible(false);
    127    }
    128    dyda().acknChanged(acknChg);
    129    curveSwt.redraw();
    130  }
    131
    132
    133
    134
    135  /**Draws one track using the {@link ixDataShown} indices to the data.
    136   * @param g graphic context from SWT
    137   * @param size of the panel in pixel
    138   * @param track data
    139   * @param iTrack Index of track, only used for debugging or test outputs.
    140   * @param ixixDataLast The end index in {@link ixDataShown} for this presentation.
    141   */
    142  private void drawTrack(GC g, Point size, GralCurveView.Track track, int iTrack, int ixixDataLast){
    143    int ixixiData = 0;
    144    //float pixelFromRight = 0;
    145    int xp2 = size.x -1;
    146    int xp1 = xp2;
    147    int ixData2 = super.ixDataShown[ixixiData];
    148    int nrofPixel4Data = super.nrofPixel4data[ixixiData];
    149    int ixData = ixData2;
    150    int ixD = (ixData >> widgg.shIxiData) & widgg.mIxiData; //real index in data
    151    //
    152    float yFactor = size.y / -10.0F / track.scale.yScale;  //y-scaling
    153    float y0Pix = (1.0F - track.scale.y0Line/100.0F) * size.y; //y0-line
    154    float yF = track.values[ixD];
    155    int time2 = widgg.timeValues[ixD];
    156    int time1;
    157    int yp9 = (int)( (yF - track.scale.yOffset) * yFactor + y0Pix);
    158    int yp2 = yp9;  //right value
    159    int yp1; //left value
    160    int ixData1;
    161    Color lineColor = track.lineColor !=null ? (Color)widgg.gralMng().impl.getColorImpl(track.lineColor) : ((SwtProperties)widgg.gralMng().propertiesGui).colorBackground;
    162    if(iTrack == 0){
    163      //System.out.println("SwtCurveView-drawTrack-start(y0Pix=" + y0Pix + ", yFactor=" + yFactor + ", y=" + yF + ")");
    164    }
    165    //
    166    while( ixixiData < ixixDataLast){ //for all gotten ixData
    167      ixixiData += nrofPixel4Data +1;
    168      ixData1 = super.ixDataShown[ixixiData];
    169      //ixData1 = ixDataShown[(int)pixelFromRight];
    170
    171      xp1 -= nrofPixel4Data +1;
    172      if(ixData != ixData1) {
    173        int yp1min = Integer.MAX_VALUE, yp1max = Integer.MIN_VALUE;
    174        int nrofYp = 0;
    175        yp1 = 0;
    176        do{ //all values per 1 pixel
    177          ixData -= widgg.adIxData;
    178          ixD = (ixData >> widgg.shIxiData) & widgg.mIxiData;
    179          int yp11;
    180          //if(ixData == ixDataDraw){
    181          if(ixixiData >= ixixDataLast){
    182              yp11 = track.ypixLast;
    183          } else {
    184            yF = track.values[ixD];
    185            time1 = widgg.timeValues[ixD];
    186            int dTime = time2 - time1;
    187            //pixelFromRight += dTime * pixel7time;
    188            yp11 = (int)( (yF - track.scale.yOffset) * yFactor + y0Pix);
    189          }
    190          yp1 += yp11;  //build middle value or init first.
    191          if(ixData != ixData1){  //more as one value on the same xp
    192            if(yp1min > yp11){ yp1min = yp11; }
    193            if(yp1max < yp11){ yp1max = yp11; }
    194          }
    195          nrofYp +=1;
    196        } while(ixData != ixData1); // iData != ixDrawValues); //all values per 1 pixel
    197        g.setForeground(lineColor);
    198        g.setLineWidth(track.lineWidth);
    199        if(nrofYp > 1){ //more as one value on the same xp
    200          g.drawLine(xp1, yp1min, xp1, yp1max);  //draw vertical line to show range.
    201          yp1 = yp1 / nrofYp;
    202        }
    203        g.drawLine(xp2, yp2, xp1, yp1);
    204        if(iTrack == 0){
    205          //System.out.println("SwtCurveView-drawTrack(" + xp2 + "+" + (xp1 - xp2) + ", " + yp2 + "+" + (yp1 - yp2) + ")");
    206        }
    207        xp2 = xp1; //next xp from right to left.
    208        yp2 = yp1;
    209        nrofPixel4Data = super.nrofPixel4data[ixixiData];
    210        ixData2 = ixData1;
    211      } else {
    212      }
    213    } //while(iData != ixDrawValues);
    214    track.ypixLast = yp9;
    215
    216  }
    217
    218
    219
    220  /**Shifts the left draw area to left because only a right part of the curve should be drawn.
    221   * It is to save calculation time
    222   */
    223  private int drawShiftAreaToLeft(GC g, Point size, int xView, int dxView, int yView, int dyView, int xViewPart, int timeDiff){
    224    final int xp0;
    225    testHelp.ctRedrawBecauseNewData +=1;
    226    //
    227    //calculate the number of x-pixel to shift in graphic to left and the width of the range to paint new:
    228    //
    229    //Shift the graphic if the reason of redraw is only increment samples
    230    //and the number the values are shifted at least by that number, which is mapped to 1 pixel.
    231    if(xViewPart >0 && xViewPart < size.x){
    232      super.timeCaryOverNewValue = (int)(timeDiff - xViewPart * widgg.timeorg.timePerPixel);
    233      super.xViewLastF -= xViewPart;
    234      if(xView != 0){
    235        //TODO what is if only a part of control is shown
    236        stop();
    237      }
    238      xp0 = xView + dxView - xViewPart;
    239      if(super.xpCursor1 >= 0){ //xViewPart){  //only if the cursor is in the shifted area:
    240        //restore graphic under cursor
    241        g.drawImage(cursorStore1, size.x - super.xpCursor1, 0);
    242        //System.out.println("cursor1 " + xpCursor1);
    243      }
    244      if(super.xpCursor2 >= 0){ //xViewPart){  //only if the cursor is in the shifted area:
    245        //restore graphic under cursor
    246        g.drawImage(cursorStore2, size.x - super.xpCursor2, 0);
    247        //System.out.println("cursor2 " + xpCursor2);
    248      }
    249      g.copyArea(xView + xViewPart, yView, dxView - xViewPart , dyView -5, xView, yView, false);
    250      //
    251      widgg.timeorg.pixelWrittenAfterStrongDiv += xViewPart;
    252
    253      //System.out.println("SwtCurveView - draw - shift graphic;" + xViewPart);
    254      //System.arraycopy(ixDataShown, 0, ixDataShown, xViewPart, size.x - xViewPart);
    255      testHelp.ctRedrawPart +=1;
    256    } else if(xViewPart >=size.x){
    257      //too many new values. Show all
    258      xViewPart = size.x;
    259      xp0 = 0;
    260      testHelp.ctRedrawAllShift +=1;
    261      super.xViewLastF = 0.0F;
    262    } else { //xViewPart <=0
    263      //don't paint.
    264      //System.out.println("SwtCurveView - draw - don't shift graphic;" + xViewPart);
    265      xViewPart = 0;
    266      xp0 = size.x;
    267    }
    268    return xp0;
    269  }
    270
    271
    272
    273  /**Draws the curves.
    274   * @param g
    275   * @param size
    276   * @param xView
    277   * @param dxView
    278   * @param yView
    279   * @param dyView
    280   * @param ixDataRight
    281   * @param xViewPart
    282   * @param timeDiff
    283   * @param xp0
    284   */
    285  private void drawRightOrAll(GC g, Point size, int xView, int dxView, int yView, int dyView
    286      , int ixDataRight, int xViewPart, int timeDiff, int xp0, boolean bPaintAll){
    287    g.setBackground(colorBack);
    288    //fill, clear the area either from 0 to end or from size.x - xView to end,
    289    g.fillRectangle(xp0, yView, xViewPart, dyView);  //fill the current background area
    290    { //draw horizontal grid
    291      float yG = dyView / super.gridDistanceX;
    292      int yS = super.gridStrongPeriodX;
    293      /*TODO
    294      while(yGridF < dyView){
    295        int yGrid = (int)yGridF;
    296        if(--yS1 <=0){
    297          yS1 = yS; g.setForeground(gridColorStrong);
    298        } else { g.setForeground(gridColor);
    299        }
    300        g.drawLine(xViewLast, yGrid, dxView, yGrid);
    301        yGridF += yG;
    302      }
    303      */
    304    }
    305    //
    306    //prepare indices of data. Fills {@link #ixDataShown}
    307    int ixixDataLast = super.prepareIndicesDataForDrawing(ixDataRight, xViewPart, timeDiff, bPaintAll);
    308    //
    309    //write time divisions:
    310    g.setForeground(gridColor);
    311    g.setLineWidth(1);
    312    g.setLineStyle(SWT.LINE_DOT);
    313    for(int ii=1; ii <=9; ++ii){  //draw the horizontal grid
    314      int y = (int)(size.y /10.0f * ii);
    315      g.drawLine(size.x - xViewPart, y, size.x, y);
    316
    317    }
    318    //
    319    int ixPixelTimeDiv =-1;
    320    int xPixelTimeDiv1;                     //draw the vertical fine grid, the time divisions
    321    while((xPixelTimeDiv1 = widgg.timeorg.xPixelTimeDivFine[++ixPixelTimeDiv]) >=0) {
    322      g.drawLine(size.x - xPixelTimeDiv1, 0, size.x - xPixelTimeDiv1, size.y);
    323      //System.out.println("draw " + xPixelTimeDiv);
    324    }
    325    g.setForeground(gridColorStrong);
    326    g.setLineWidth(1);
    327    ixPixelTimeDiv =-1;                     //draw the vertical grid, strong lines.
    328    while((xPixelTimeDiv1 = widgg.timeorg.xPixelTimeDiv[++ixPixelTimeDiv]) >=0) {
    329      g.drawLine(size.x - xPixelTimeDiv1, 0, size.x - xPixelTimeDiv1, size.y);
    330      if(xPixelTimeDiv1 > 30){
    331        g.setForeground((Color)widgg.gralMng().impl.getColorImpl(GralColor.getColor("bk")));
    332        g.drawText(widgg.timeorg.sTimeAbsDiv[ixPixelTimeDiv], size.x - 6 - xPixelTimeDiv1, size.y - 25);
    333        g.setForeground(gridColorStrong);
    334        widgg.timeorg.pixelWrittenAfterStrongDiv = Integer.MIN_VALUE;
    335      }
    336      //System.out.println("draw " + xPixelTimeDiv);
    337    }
    338    //write all tracks.
    339    g.setLineStyle(SWT.LINE_SOLID);
    340    int iTrack = 0;
    341    List<GralCurveView.Track> listTracks1 = widgg.listTracks; //Atomic access, iterate in local referenced list.
    342    for(GralCurveView.Track track: listTracks1){
    343      //draw line per track
    344      if(track.showSelected !=0) {
    345        drawTrack(g, size, track, iTrack, ixixDataLast);
    346      }
    347      iTrack +=1;
    348    } //for listlines
    349    super.ixDataDraw = ixDataRight;
    350    //
    351    if(widgg.timeorg.pixelWrittenAfterStrongDiv > 30){
    352      g.drawText(widgg.timeorg.sTimeAbsDiv[0], size.x - 6 - widgg.timeorg.pixelWrittenAfterStrongDiv, size.y - 25);
    353      widgg.timeorg.pixelWrittenAfterStrongDiv = Integer.MIN_VALUE;
    354    }
    355    //set the cursors
    356    if(super.xpCursor1New >=0){
    357      super.xpCursor1 = super.xpCursor1New;
    358      super.xpCursor1New = -1;
    359    }
    360    if(super.xpCursor2New >=0){
    361      super.xpCursor2 = super.xpCursor2New;
    362      super.xpCursor2New = -1;
    363    }
    364    if(super.xpCursor1 >=0){
    365      int xpCursor = size.x - super.xpCursor1;
    366      g.copyArea(cursorStore1, xpCursor, 0);
    367      g.setForeground(colorCursor);
    368      g.setLineWidth(1);
    369      g.drawLine(xpCursor, 0, xpCursor, size.y);
    370    }
    371    if(super.xpCursor2 >=0){
    372      int xpCursor = size.x - super.xpCursor2;
    373      g.copyArea(cursorStore2, xpCursor, 0);
    374      //if(xViewPart >= size.x){
    375        g.setForeground(colorCursor);
    376        g.setLineWidth(1);
    377        g.drawLine(xpCursor, 0, xpCursor, size.y);
    378      //}
    379    }
    380
    381  }
    382
    383
    384
    385  /**This routine overrides
    386   * @see org.eclipse.swt.widgets.Canvas#drawBackground(org.eclipse.swt.graphics.GC, int, int, int, int)
    387   * It is called in this class in {@link #paintListener} in the {@link PaintListener#paintControl(PaintEvent)} method.
    388   * It draws the whole content.
    389   * <br><br>
    390   * Because of saving calculation time there will be drawn only a small peace on right side of the area
    391   * with the new data normally. The rest inclusive grid lines, curves, text is moved to left. But if the whole
    392   * window should be refreshed, the whole widget is drawn newly.
    393   *
    394   */
    395  protected void drawBackground(GC g, Point size, int xView, int yView, int dxView, int dyView) {
    396    //NOTE: forces stack overflow because calling of this routine recursively: super.paint(g);
    397    try{
    398      boolean redrawBecauseNewData1, redrawAll;
    399      synchronized(this){
    400        redrawBecauseNewData1 = super.redrawBecauseNewData;
    401        redrawAll = super.bRedrawAll;
    402        if(!redrawBecauseNewData1){
    403          Debugutil.stop();
    404        }
    405        super.bRedrawAll = false;  //it is done
    406        super.redrawBecauseNewData = false;  //it is done.
    407      }
    408      //
    409      //detect how many new data are given. Because the data are written in another thread,
    410      //the number of data, the write index are accessed only one time from this
    411      //Note that ixDataShowRight is set by ixDataWr if the curve is running.
    412      int ixDataRight = super.ixDataShowRight;
    413      super.pixelOrg.xPixelCurve = size.x;
    414      super.pixelOrg.yPixelCurve = size.y;
    415      @SuppressWarnings("hiding")
    416      GralCurveView.TimeOrganisation timeorg = widgg.timeorg;
    417      timeorg.timePerPixel = (float)timeorg.timeSpread / (size.x +1); //nr of time units per pixel.
    418      timeorg.pixel7time = (float)(size.x +1) / timeorg.timeSpread; //nr of pixel per time unit.
    419      int xViewPart = -1;   //nr of new pixel if only a part is drawn
    420      final int xp0;  //left point to draw.
    421      final int timeDiff; //time for new values.
    422      testHelp.xView =xView; testHelp.yView =yView; testHelp.dxView =dxView; testHelp.dyView =dyView;
    423      //
    424      final boolean bPaintAll;
    425      if(!widgg.common.bFreeze && !super.bPaintAllCmd && !redrawAll ) { //redrawBecauseNewData1) {
    426        //paint only a part of the curve to save calculation time.
    427        //The curve will be shifted to left.
    428        //
    429        bPaintAll = false;
    430        if(ixDataRight != super.ixDataDraw){
    431          widgg.testStopWr = true;
    432          stop();
    433        }
    434        int timeLast = widgg.timeValues[(super.ixDataDraw >> widgg.shIxiData) & widgg.mIxiData];
    435        int timeNow = widgg.timeValues[(ixDataRight >> widgg.shIxiData) & widgg.mIxiData];
    436        timeDiff = timeNow - timeLast + super.timeCaryOverNewValue;  //0 if nothing was written.
    437        xViewPart = (int)(timeorg.pixel7time * timeDiff + 0.0f);
    438        if(xViewPart > size.x){
    439          xViewPart = size.x;   //for example if no data were received in the past, then timeDiff is hi.
    440        }
    441        xp0 = drawShiftAreaToLeft(g, size, xView, dxView, yView, dyView, xViewPart, timeDiff);
    442      } else { //paintall
    443        bPaintAll = true;
    444        timeorg.calc();
    445        //System.out.println("SwtCurveView - paintall;" + bFreeze + bPaintAllCmd + redrawBecauseNewData1);
    446        xViewPart = size.x;
    447        super.timeCaryOverNewValue = 0;
    448        timeDiff = (int)(timeorg.timePerPixel * xViewPart);
    449        xp0 = 0;
    450        super.bPaintAllCmd = false; //accepted, done
    451        testHelp.ctRedrawAll +=1;
    452        //xViewLast = 0;
    453        super.xViewLastF = 0.0F;
    454        super.nrofDataShift.set(0);
    455      }
    456      widgg.newSamples = 0;  //next call of setSample will cause only draw of less area.
    457
    458      //draw grid and 0-lines:
    459      if(xViewPart >0) { //only if anything is to draw
    460        //only if a new point should be drawn.
    461        try{Thread.sleep(2);} catch(InterruptedException exc){}
    462        drawRightOrAll(g, size, xView, dxView, yView, dyView, ixDataRight, xViewPart, timeDiff, xp0, bPaintAll);
    463
    464      } else { //xViewPart == 0
    465        //This is is normal case if a new value in data has a too less new timestamp.
    466        //It can't be shown. Await the next values. Any value will be have a more newer timestamp
    467        //with a great-enough time difference to show it.
    468        super.nrofValuesLessViewPart +=1;
    469        //System.out.println("SwtCurveView - xViewPart=0");
    470      }
    471      if(widgg.nrofValues >0){  //don't work if no data are stored.
    472        int ixDataShow2 = ((widgg.ixDataWr - super.ixDataDraw)  >> widgg.shIxiData) & widgg.mIxiData;  //index of data which are shown right
    473        int ixDataShow1 = ((widgg.ixDataWr - super.ixDataShown[size.x])  >> widgg.shIxiData) & widgg.mIxiData; //index of data which are shown left
    474        float ixDataRel2 = (float)ixDataShow2 / widgg.maxNrofXValues;  //value 0..1 which range of buffer is shown
    475        float ixDataRel1 = (float)ixDataShow1 / widgg.maxNrofXValues;
    476        int iPixRange2 = size.x - (int)(size.x * ixDataRel2);  //Position shown range right in pixel
    477        int iPixRange1 = size.x - (int)(size.x * ixDataRel1);  //left
    478        //int ixDWr = (ixDataWr >> shIxiData) & mIxiData;
    479        //System.out.println("SwtCurveView.spread; " + ixDataRel1 + ".." + ixDataRel2);
    480        g.setLineWidth(5);
    481        g.setForeground((Color)widgg.gralMng().impl.getColorImpl(GralColor.getColor("ye")));
    482        g.drawLine(0, size.y -3, iPixRange1, size.y -3);  //left not shown range.
    483        g.drawLine(iPixRange2, size.y -3, size.x, size.y -3);  //right non shown range.
    484        g.setForeground((Color)widgg.gralMng().impl.getColorImpl(GralColor.getColor("dgr")));
    485        //g.setAlpha(128);
    486        g.drawLine(iPixRange1, size.y -3, iPixRange2, size.y -3);  //shown range
    487      }
    488    } catch(Exception exc){
    489      CharSequence sError = Assert.exceptionInfo("SwtCurveView.draw - exception", exc, 0, 20, true);
    490      System.err.append(sError);
    491    }
    492    //g.drawString(""+xShift+ ":"+ xViewLast + ":" + nrofDataShift.get(), 200, dyView-28);
    493    //g.drawString("xx", 200, dyView-16);
    494    super.focusChanged = false; //paint only last area by next paint event without focus event.
    495    widgg.testStopWr = false;
    496  }
    497
    498
    499
    500  private class CurveView extends Canvas
    501  {
    502
    503    //private final CurveView widgSwt;
    504
    505    //final Canvas canvas;
    506
    507    //private final Color[] lineColors;
    508
    509
    510    public CurveView(Composite parent, int xPixel, int yPixel, int nrofXvalues){
    511      super(parent, org.eclipse.swt.SWT.NO_SCROLL|org.eclipse.swt.SWT.NO_BACKGROUND);
    512      setData("Control", this);
    513      setSize(xPixel, yPixel);  //the size may be changed later by drag the window.
    514      //this.xPixel = xPixel;
    515      //this.yPixel = yPixel;
    516      //lineColors = new Color[nrofTracks];
    517      Color defaultColor = new Color(getDisplay(), 255,0,0);
    518      addPaintListener(paintListener);
    519      addFocusListener(focusListener);
    520      addMouseListener(mouseListenerCurve);
    521      //addMouseListener(mouseLeftButtonListener);
    522      //addMouseMoveListener(mouseMoveListener);
    523      //widgSwt = this;
    524    }
    525
    526
    527
    528
    529    public void setGridVertical(int dataPointsBetweenGridLines, int periodStrongLine){
    530      SwtCurveView.this.gridDistanceY = dataPointsBetweenGridLines;
    531      SwtCurveView.this.gridStrongPeriodY = periodStrongLine;
    532      widgg.gridDistanceStrongY = dataPointsBetweenGridLines * periodStrongLine;
    533    }
    534
    535
    536    /**Set distance for horizontal grid lines.
    537     * @param percentY percent of y-view for grid lines. For example 50.0: divide y-axis in 50 steps.
    538     * @param periodStrongLine period for strong lines For example 5, any 5. line is stroke.
    539     */
    540    public void setGridHorizontal(float percentY, int periodStrongLine){
    541      SwtCurveView.this.gridDistanceX = percentY;
    542      SwtCurveView.this.gridStrongPeriodX = periodStrongLine;
    543    }
    544
    545
    546
    547    public void redrawData(){
    548      SwtCurveView.this.redrawBecauseNewData = true;
    549      redraw();
    550    }
    551
    552
    553
    554
    555
    556
    557
    558    PaintListener paintListener = new PaintListener()
    559    {
    560
    561      @Override public void paintControl(PaintEvent e) {
    562        GC gc = e.gc;
    563        drawBackground(e.gc, e.x, e.y, e.width, e.height);
    564      }
    565
    566    };
    567
    568
    569
    570    FocusListener focusListener = new FocusListener()
    571    { @Override public void focusGained(FocusEvent e) {
    572      SwtCurveView.this.focusChanged = true;
    573      }
    574
    575      @Override public void focusLost(FocusEvent e) {
    576        SwtCurveView.this.focusChanged = true;
    577      }
    578    };
    579
    580
    581    /**This routine overrides
    582     * @see org.eclipse.swt.widgets.Canvas#drawBackground(org.eclipse.swt.graphics.GC, int, int, int, int)
    583     * It is called in this class in {@link #paintListener} in the {@link PaintListener#paintControl(PaintEvent)} method.
    584     * It draws the whole content.
    585     * <br><br>
    586     * Because of saving calculation time there will be drawn only a small peace on right side of the area
    587     * with the new data normally. The rest inclusive grid lines, curves, text is moved to left. But if the whole
    588     * window should be refreshed, the whole widget is drawn newly.
    589     *
    590     */
    591    @Override public void drawBackground(GC g, int xView, int yView, int dxView, int dyView) {
    592      //NOTE: forces stack overflow because calling of this routine recursively: super.paint(g);
    593      SwtCurveView.this.drawBackground(g, getSize(), xView, yView, dxView, dyView);
    594    }
    595  }
    596
    597
    598  /**This class is only used to store values to inspect. The Inspector is a tool which works with
    599   * reflection and with it internal variable can be visited in runtime. See {@link org.vishia.inspectorTarget.Inspector}.
    600   */
    601  @SuppressWarnings("unused")
    602  private static class TestHelp{
    603    /**Counts any redraw action for complete redraw, to see how often.  */
    604    int ctRedrawAll;
    605    /**Counts any redraw action for complete redraw because nrof shift>100, to see how often.  */
    606    int ctRedrawAllShift;
    607
    608    /**Counts any redraw action for partial redraw, to see how often.  */
    609    int ctRedrawPart;
    610
    611    /**Ct if redraw only because new data. */
    612    int ctRedrawBecauseNewData;
    613
    614    /**Coordinates while redraw. {@link CurveView#drawBackground(GC, int, int, int, int)}. */
    615    int xView, yView, dxView, dyView;
    616  }
    617  TestHelp testHelp = new TestHelp();
    618
    619
    620  final SwtGralMouseListener.MouseListenerGralAction mouseListenerCurve;
    621
    622
    623  void stop(){}
    624
    625
    626  @Override
    627  public boolean setFocusGThread()
    628  {
    629    // TODO Auto-generated method stub
    630    return false;
    631  }
    632
    633
    634  @Override
    635  public void setVisibleGThread(boolean bVisible)
    636  {
    637    // TODO Auto-generated method stub
    638
    639  }
    640
    641
    642  @Override
    643  public void removeWidgetImplementation()
    644  {
    645    // TODO Auto-generated method stub
    646
    647  }
    648
    649
    650  @Override public Object getWidgetImplementation(){ return curveSwt; }
    651
    652
    653  @Override
    654  public void setBoundsPixel(int x, int y, int dx, int dy)
    655  {
    656    // TODO Auto-generated method stub
    657
    658  }
    659
    660
    661  @Override
    662  public GralRectangle getPixelPositionSize()
    663  {
    664    // TODO Auto-generated method stub
    665    return null;
    666  }
    667
    668
    669  @Override
    670  public boolean remove()
    671  {
    672    // TODO Auto-generated method stub
    673    return false;
    674  }
    675
    676}