// strip.c - Dynalink for drawing stripcharts (up to 20 at the moment,
// change ss[] and recompile if more needed !).
//
// This is meant to be compiled with Quick C for Windows version 1.0
// (the makefile will not work with other make utilities)
//

// THIS IS OUTDATED
//
// LINKING: Add the following to the IMPORTS section of your module definition file:
//  Setmaxvalstrip = STRIP.2
//  Labelstrip     = STRIP.3
//  Setupstrip     = STRIP.4
//  Strip          = STRIP.5

// USAGE: Doing the Setup: for every stripchart:
//   1. Call: Setmaxvalstrip(HDC theHDC,int aSlotIn_ss,int maximumValue);
//   2. Call: Setupstrip(HDC theHDC,int sameSlotIn_ss,int left,int top,int right,int bottom);
//   3. Call: Labelstrip(HDC theHDC,int sameSlotIn_ss,LPSTR yourLabelString);
//
// Plotting a value:
//   Call: Strip(HDC theHDC,theSlotIn_ss,int theValueToPlot); for every new value
//
// END OF THIS IS OUTDATED

// As you can see, I later prefered to do it with function StripChart only!

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include "strip.h"

//typedef struct stripstruct {
//  int start_x;
//  int end_x;
//  int start_y;
//  int end_y;
//  int valrange;
//  int maxval;
//  int do_init;
//} stripstruct;
//
//static stripstruct ss[20]; // For up to nine charts, just change this if you want more

typedef struct StripChartStruct_tag {
  int xs, xe;           // The real xs and xe
  int ys, ye;           // The real ys and ye
  int x1, y1;           // Initial point on line drawn.
  int x2, y2;           // Terminating point on line drawn.
  int position;         // Tracks current plotting position.
  int old_position;     // Last plotting position.
  int tic_counter;      // Counts interval between tic marks.
  int tic_location[9];  // y locations of tic marks.
  int tic_cnt;          // The # of tic marks to make.
  int old_value;        // Old value to plot.
  int new_value;        // New value to plot.
  long value;           // The value to plot
  int ticAbst;          // Room from one tickmark to next (vertical)
} StripChartStruct;

static StripChartStruct SS[20];


int FAR PASCAL _WEP(int idExit)
{
  return 1;
}


//void FAR PASCAL Setmaxvalstrip(HDC hDC,int chartID,int maxval)
//{
//  ss[chartID].maxval=maxval;
//}

//void FAR PASCAL Setupstrip(HDC hDC,int chartID,int sx,int sy,int ex,int ey)
//{
//  static HPEN hLGreyPen;
//  static HPEN hDarkGreyPen;
//  static HPEN hBackUpPen;
//
//  // Setup global plotinfo structure, strip() uses this info
//  ss[chartID].start_x=sx+2;
//  ss[chartID].start_y=sy+1;
//  ss[chartID].end_x=ex-2;
//  ss[chartID].end_y=ey;
//  ss[chartID].valrange=ey-sy-2;
//  ss[chartID].do_init=1;         // reset plot positions
//
//  // Draw box
//  hLGreyPen=CreatePen(PS_SOLID,1,RGB(225,225,225));
//  hDarkGreyPen=CreatePen(PS_SOLID,1,RGB(128,128,128));
//
//  hBackUpPen=SelectObject(hDC,hDarkGreyPen);
//  MoveTo(hDC,sx+1,ey);
//  LineTo(hDC,sx+1,sy);
//  LineTo(hDC,ex,sy);
//  SelectObject(hDC,hLGreyPen);
//  MoveTo(hDC,ex,sy);
//  LineTo(hDC,ex,ey);
//  LineTo(hDC,sx,ey);
//
//  SelectObject(hDC,hBackUpPen);  // Back in black
//  DeleteObject(hDarkGreyPen);
//  DeleteObject(hLGreyPen);
//}

//void FAR PASCAL labelstrip(HDC hDC,int chartID,LPSTR label)
//{
//  TextOut(hDC,ss[chartID].start_x-10,ss[chartID].start_y+ss[chartID].valrange/2,label,_fstrlen(label));
//}

//void FAR PASCAL strip(HDC hDC,int chartID,int value)
//{
//  static HPEN hBackUpPen;
//  static HPEN hLGreyPen;
//  static float floated;
//  static int initialrun[20]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
//  static int position[20];
//  static int old_position[20];
//  static old_value[20];
//  static float valdiv[20];
//
//  hLGreyPen=CreatePen(PS_SOLID,1,RGB(192,192,192));
//
//  if (ss[chartID].do_init)
//  {
//    initialrun[chartID]=1;
//    ss[chartID].do_init=0;
//  }
//
//  floated=(float)value;
//
//  if (initialrun[chartID])
//  {
//    position[chartID]=ss[chartID].start_x+1;                                   // Set X start
//    valdiv[chartID]=((float)ss[chartID].maxval)/((float)ss[chartID].valrange); // transformation
//    old_value[chartID]=ss[chartID].end_y;                            // Start from zero position
//    initialrun[chartID]=0;
//  }
//
//  old_position[chartID]=position[chartID];
//
//  if (position[chartID]++ == ss[chartID].end_x)
//  {
//    hBackUpPen=SelectObject(hDC,hLGreyPen); // Have to delete old bar
//    MoveTo(hDC,position[chartID],ss[chartID].start_y);
//    LineTo(hDC,position[chartID],ss[chartID].end_y);
//    SelectObject(hDC,hBackUpPen);                           // Back in black
//    position[chartID]=ss[chartID].start_x;
//    old_position[chartID]=ss[chartID].start_x;              // Old position only imagination
//  }
//
//  MoveTo(hDC,position[chartID]+1,ss[chartID].start_y);      // Draw bar
//  LineTo(hDC,position[chartID]+1,ss[chartID].end_y);
//  hBackUpPen=SelectObject(hDC,hLGreyPen);   // Delete old bar
//  MoveTo(hDC,old_position[chartID]+1,ss[chartID].start_y);
//  LineTo(hDC,old_position[chartID]+1,ss[chartID].end_y);    // Back in black
//  SelectObject(hDC,hBackUpPen);
//
//  // Transpose value to displayable range
//  floated/=valdiv[chartID];
//  value=(int)floated;
//  value=ss[chartID].valrange-value;                // Make bottom zero instead of top
//  value+=ss[chartID].start_y;                      // Move to zero line
//
//  // Connect old point and new point
//  MoveTo(hDC,old_position[chartID],old_value[chartID]);
//  LineTo(hDC,position[chartID],value);
//
//  old_value[chartID]=value;
//
//  DeleteObject(hLGreyPen);
//}



// This is the stripchart function, in brackets the situations when a value is needed

void FAR PASCAL StripChart(HDC hdc,          // A handle to a device context (always)
                           int ID,           // Chart Identifier (0 to 19)
                           int wxs,          // Wanted left (if SETUP)
                           int wys,          // Wanted top  (if SETUP)
                           int wxe,          // Wanted right (if SETUP)
                           int wye,          // Wanted bottom (if SETUP)
                           double datum,     // Data Item to plot (if PLOT)
                           double theMax,    // Maximum displayable value (if SETUP)
                           STRIPTYPE doWhat, // SETUP or PLOT or SHUTDOWN
                           LPSTR label)      // The label
{
  static HPEN hBackUpPen;      // Holds the pen originally bound to the HDC
  static HPEN hLGreyPen;       // The pen matching the background color
  RECT kasten;

  // Initialize the y locations of tic marks
  if (doWhat == SETUP)
  {
    // Die gewünschten Eckpunkte werden bei Bedarf etwas korrigiert, um
    // leichter beschriften zu können
    SS[ID].ys=wys;
    SS[ID].ye=wye;  // The real ye depends not only on the wanted ye (wye)
    SS[ID].xs=wxs;
    SS[ID].xe=wxe;  // The real xe depends not only on the wanted xe (wxe)

    // Mach die Höhe zu einem Vielfachen von 10, erleichtert Ticks und Beschriftung
    while((SS[ID].ye-SS[ID].ys) % 10)
      SS[ID].ye--;

    // Mach die Breite zu einem Vielfachen von 10, erleichtert Ticks und Beschriftung
    while((SS[ID].xe-SS[ID].xs) % 5)
      SS[ID].xe--;

    // Lösche den Hintergrund
    kasten.left=SS[ID].xs;
    kasten.top=SS[ID].ys;
    kasten.right=SS[ID].xe;
    kasten.bottom=SS[ID].ye+1;
    FillRect(hdc,(LPRECT)&kasten,GetStockObject(WHITE_BRUSH));

    hLGreyPen=CreatePen(PS_SOLID,1,RGB(192,192,192));

    SS[ID].tic_cnt=9; // Alway make 10 horizontal strip bands

    SS[ID].ticAbst=(SS[ID].ye-SS[ID].ys)/10;

    {
      int run;

      for(run=0;run < 9;run++)
        SS[ID].tic_location[run]=SS[ID].ys+SS[ID].ticAbst+(run*SS[ID].ticAbst);
    }
    // Box in the plotting region (use 3d routine later !!)

    // Left side
    SS[ID].x1=SS[ID].xs-1;
    SS[ID].x2=SS[ID].x1;
    SS[ID].y1=SS[ID].ys;
    SS[ID].y2=SS[ID].ye+1;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    // Top side
    SS[ID].x1=SS[ID].xs-1;
    SS[ID].x2=SS[ID].xe+1;
    SS[ID].y1=SS[ID].ys-1;
    SS[ID].y2=SS[ID].y1;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    hBackUpPen=SelectObject(hdc,hLGreyPen);

    // Right side
    SS[ID].x1=SS[ID].xe+1;
    SS[ID].x2=SS[ID].x1;
    SS[ID].y1=SS[ID].ys;
    SS[ID].y2=SS[ID].ye+1;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    // Bottom side
    SS[ID].x1=SS[ID].xs-1;
    SS[ID].x2=SS[ID].xe+1;
    SS[ID].y1=SS[ID].ye+1;
    SS[ID].y2=SS[ID].y1;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    SelectObject(hdc,hBackUpPen);
    DeleteObject(hLGreyPen);

    // 3d frame
    hBackUpPen=SelectObject(hdc,GetStockObject(WHITE_PEN));

    // Right side
    SS[ID].x1=SS[ID].xe+2;
    SS[ID].x2=SS[ID].x1;
    SS[ID].y1=SS[ID].ys-1;
    SS[ID].y2=SS[ID].ye+3;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    // Bottom side
    SS[ID].x1=SS[ID].xs-1;
    SS[ID].x2=SS[ID].xe+2;
    SS[ID].y1=SS[ID].ye+2;
    SS[ID].y2=SS[ID].y1;
    MoveTo(hdc,SS[ID].x1,SS[ID].y1);
    LineTo(hdc,SS[ID].x2,SS[ID].y2);

    SelectObject(hdc,hBackUpPen);

    { // Add the label to the left of the StripChart
      WORD prevAlign;
      int prevBk;

      prevBk=SetBkMode(hdc,TRANSPARENT);
      prevAlign=SetTextAlign(hdc,TA_RIGHT|TA_BASELINE);
      // Draw label
      TextOut(hdc,SS[ID].xs-15,(SS[ID].ye-SS[ID].ys)/2+SS[ID].ys,label,_fstrlen(label));
      // Restore previous alignment
      SetBkMode(hdc,prevBk);
      SetTextAlign(hdc,prevAlign);
    }

    // Draw the initial tracking bar which scans left to right across the screen.
    SS[ID].position=SS[ID].xs;
    MoveTo(hdc,SS[ID].position+1,SS[ID].ys);
    LineTo(hdc,SS[ID].position+1,SS[ID].ye);

    SS[ID].tic_counter=0;
  }
  else if (doWhat == PLOT)
  {
    // Get the new point to plot
    SS[ID].value=(long)datum;
    SS[ID].value=(SS[ID].value*(long)(SS[ID].ye-SS[ID].ys+1))/(long)theMax;
    SS[ID].new_value=SS[ID].ye-(int)SS[ID].value;

    if(SS[ID].new_value < SS[ID].ys)
      SS[ID].new_value=SS[ID].ys;

    // Check to see if we've come back to the beginning
    if(SS[ID].position == SS[ID].xs)
      SS[ID].old_value=SS[ID].new_value;

    // Update the tracking bar.  First draw new bar, then remove old bar.
    // The order is important; this helps reduce unsightly flicker.

    SS[ID].old_position=SS[ID].position;

    if(SS[ID].position++ == SS[ID].xe)
    {
      SS[ID].position=SS[ID].xs;
      SS[ID].old_position=SS[ID].xs-1;
    }

    // Drawing new bar, but leave alone right edge
    if (SS[ID].position+1 != SS[ID].xe+1)
    {
      MoveTo(hdc,SS[ID].position+1,SS[ID].ys);
      LineTo(hdc,SS[ID].position+1,SS[ID].ye+1);  // Added the +1, now it works
    }

    // Removing old bar
    hBackUpPen=SelectObject(hdc,GetStockObject(WHITE_PEN)); // Have to delete old bar
    MoveTo(hdc,SS[ID].old_position+1,SS[ID].ys);
    LineTo(hdc,SS[ID].old_position+1,SS[ID].ye+1);  // Added the +1, now it works
    SelectObject(hdc,hBackUpPen);

    // Plot the A/D values by drawing a line from last value read to the new value.

    // Draw tic marks if necessary
    if(++SS[ID].tic_counter == 5)
    {
      int run;

      SS[ID].tic_counter=0;

      for(run=0;run < SS[ID].tic_cnt;run++)
        SetPixel(hdc,SS[ID].old_position,SS[ID].tic_location[run],RGB(192,192,192));
    }

    if(SS[ID].position == SS[ID].xs)
      SS[ID].old_position=SS[ID].xs;

    MoveTo(hdc,SS[ID].old_position,SS[ID].old_value);
    LineTo(hdc,SS[ID].position,SS[ID].new_value);

    // Draw tic marks if necessary
    //if(++SS[ID].tic_counter == 5)
    //{
    //  int run;
    //
    //  SS[ID].tic_counter=0;
    //
    //  for(run=0;run < SS[ID].tic_cnt;run++)
    //    SetPixel(hdc,SS[ID].old_position,SS[ID].tic_location[run],RGB(192,192,192));
    //}

    // We've plotted the point, now it's the old point
    SS[ID].old_value=SS[ID].new_value;
  }
  else if (doWhat == SHUTDOWN)
  {
    // Delted earlier, nothing left to do, perfect !
    //DeleteObject(hLGreyPen);
  }
}

