/**************************************************************************/
/* svgafft --  Spectrum Analyzer                                          */
/*                                                                        */ 
/* bar class implementation                                               */
/**************************************************************************/

/**************************************************************************

    Copyright (C) 1995 Andrew Veliath

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


***************************************************************************/

// $Id: bars.cc,v 0.6 1995/01/28 19:00:40 root Exp $             

#include "bars.h"
#include "defaults.h"
#include "colors.h"
#include <vgagl.h>

// global defaults home file (from defaults.h)

/*******************************************************************/
/* BarGraph base class methods */

/*******************************************************************/
BarGraph::BarGraph() 
{ 
  x=5; y=5; 
  w=gConfig.BarWidth.val; 
  oldvalue=1;
  value=1; 
  height=50; 
  clipvalue=height; 
  clipnum=clipvalue; 
}


/*******************************************************************/
BarGraph::BarGraph(int X, int Y, int W, int Value, int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value; 
  oldvalue=value; 
  height=Height; 
}


/*******************************************************************/
void BarGraph::Label(const char *Label)
{
  strcpy(label, Label);
}


/*******************************************************************/
virtual void BarGraph::DrawLabel()
{
  if (*label) {
    int len=strlen(label);
    if (len<=3) 
      gl_write(x-13+w/2, y+7, label);
    else if (len<=4) 
      gl_write(x-20+w/2, y+7, label);
    else gl_write(x-15+w/2, y+7, label);
  }
      
}


/*******************************************************************/
virtual void BarGraph::DrawTick(int height, int color)
{
    gl_line(x, y+2, x, y+height+2, color);
}


/*******************************************************************/
virtual void BarGraph::AdjustVals()
{
}


/*******************************************************************/
virtual void BarGraph::SetProx(int X, int Y, int W)
{
  x=X;
  if (Y>0) y=Y;
  if (W!=0) w=W;
}


/*******************************************************************/
virtual void BarGraph::SetClipValue(int value)
{ 
  clipvalue=clipnum=value-1;
}

/*******************************************************************/
virtual int BarGraph::GetClipValue(void) 
{ 
  return clipvalue; 
}

/*******************************************************************/
virtual void BarGraph::SetValue(int Value) 
{ 
  oldvalue=value;
  value=Value < clipvalue ? Value : clipvalue; 
  if (value<0) value=0;
}


/*******************************************************************/
void BarGraph::Update(void) 
{
  int delta=value-oldvalue;
  if (delta>0) { 
    gl_fillbox(x, y-value+1, w, delta, 
	       gConfig.BarColor.val);
    if (value>=clipnum) gl_fillbox(x, y-clipvalue+1, w, 3,
				   gConfig.BarClipColor.val);
  }
  else if (delta<0) {
    gl_fillbox(x, y-oldvalue+1, w, -delta, gConfig.BarClear.val);
  }
  oldvalue=value;
}


/*******************************************************************/
/* BarGraph derived class methods */
/*******************************************************************/

/*******************************************************************/
/* Segmented Bar Graph methods */
/*******************************************************************/

/*******************************************************************/
SegmentedBarGraph::SegmentedBarGraph(int X, int Y, 
				     int W, int Value, 
				     int SegHeight, int SegSpace,
				     int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value; 
  oldvalue=value; 
  height=Height;
  if (segHeight==0) {
    segHeight=gConfig.SegHeight.val; 
    segSpace=gConfig.SegSpace.val; 
  }  
  divider=segSpace+segHeight;
}

/*******************************************************************/
void SegmentedBarGraph::DrawTick(int height, int color)
{
    gl_line(x, y+2+segHeight, x, y+height+2+segHeight, color);
}


/*******************************************************************/
void SegmentedBarGraph::DrawLabel()
{
  if (*label) {
    int len=strlen(label);
    if (len<=3) 
      gl_write(x-13+w/2, y+7+segHeight, label);
    else if (len<=4) 
      gl_write(x-20+w/2, y+7+segHeight, label);
    else gl_write(x-15+w/2, y+7+segHeight, label);
  }
      
}


/*******************************************************************/
void SegmentedBarGraph::SetProx(int X, int Y, int W)
{
  x=X;
  if (Y>0) y=Y-segHeight;
  if (W!=0) w=W;
}


/*******************************************************************/
inline void SegmentedBarGraph::DrawSegment(int num, int color)
{
  gl_fillbox(x, y-num*divider,
	     w, segHeight, color);
}


/*******************************************************************/
inline void SegmentedBarGraph::SegmentOn(int num)
{
 

  gl_fillbox(x, y-num*divider,
	     w, segHeight, 
	     (num<medbarval) ? gConfig.BarColor.val : 
	     (num<highbarval) ? gConfig.MedBarColor.val :
	     gConfig.HighBarColor.val);
}


/*******************************************************************/
inline void SegmentedBarGraph::SegmentOff(int num)
{
  gl_fillbox(x, y-num*divider,
	     w, segHeight, gConfig.BarClear.val);
}

/*******************************************************************/
inline void SegmentedBarGraph::ShowPeak(int num)
{
  gl_fillbox(x, y-num*divider,
	     w, segHeight, gConfig.PeakColor.val);
}


/*******************************************************************/
inline void SegmentedBarGraph::ShowClip(int num)
{
  gl_fillbox(x, y-num*divider,
	     w, segHeight, gConfig.BarClipColor.val);
}


/*******************************************************************/
void SegmentedBarGraph::AdjustVals()
{
  medbarval=(int) ((float) gConfig.MedBarVal.val / 100.0 * (float) clipnum);
  highbarval=(int) ((float) gConfig.HighBarVal.val / 100.0 * (float) clipnum);
}


/*******************************************************************/
void SegmentedBarGraph::SetClipValue(int value)
{ 
  clipvalue=value; 
  clipnum=clipvalue/divider-1;
}


/*******************************************************************/
void SegmentedBarGraph::SetValue(int Value) 
{
  oldvalue=value; 
  value=Value<clipvalue ?
    Value/divider:clipnum;
  if (value<0) value=0;
}


/*******************************************************************/
void SegmentedBarGraph::Update(void) 
{
  int delta=value-oldvalue;
  register int i;

  if (delta>0) {
    for (i=oldvalue; i<=value; i++) 
      if (i < clipnum) SegmentOn(i);
      else ShowClip(i);
  }
  else if (delta<0) {
    for (i=oldvalue; i>=value; i--) 
      SegmentOff(i);
  }
  oldvalue=value;
}


/*******************************************************************/
/* One-Segment Bar Graph Implementation */
/*******************************************************************/

/*******************************************************************/
SegmentBarGraph::SegmentBarGraph(int X, int Y, 
				 int W, int Value, 
				 int SegHeight, int SegSpace,
				 int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value;     
  oldvalue=value; 
  height=Height; 
  if (segHeight==0) {
    segHeight=gConfig.SegHeight.val; 
    segSpace=gConfig.SegSpace.val; 
  }
  divider=segSpace+segHeight;
}


/*******************************************************************/
void SegmentBarGraph::SetClipValue(int value)
{ 
  clipvalue=value; 
  clipnum=clipvalue/divider-1;
}


/*******************************************************************/
void SegmentBarGraph::SetValue(int Value) 
{
  oldvalue=value; 
  value=Value/divider;
  if (value>clipnum) value=clipnum;
  if (value<0) value=0;
}


/*******************************************************************/
void SegmentBarGraph::Update(void)
{
  SegmentOff(oldvalue);
  if (value!=oldvalue) oldvalue=value;
  if (value < clipnum) SegmentOn(value);
  else ShowClip(value);
}


/*******************************************************************/
/* Peak-Drop Bar Graph Implementation */
/*******************************************************************/

/*******************************************************************/
PeakDropSegmentedBarGraph::PeakDropSegmentedBarGraph
(int X, int Y, 
 int W, int Value, 
 int SegHeight, int SegSpace,
 int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value;  
  oldvalue=value; 
  height=Height; 
  if (segHeight==0) {
    segHeight=gConfig.SegHeight.val; 
    segSpace=gConfig.SegSpace.val; 
  }
  peak=gConfig.PeakDisappearValue.val;
  divider=segSpace+segHeight;
}


/*******************************************************************/
void PeakDropSegmentedBarGraph::SetValue(int Value) 
{ 
  oldvalue=value; 
  value=Value < clipvalue ?
    Value/divider:clipnum;
  if (value<0) value=0;
}


/*******************************************************************/
void PeakDropSegmentedBarGraph::Update(void)
{
  int delta=value-oldvalue;
  register int i;

  /* take care of the peak */
  peak=value>peak?value:peak;
  if (peak>=gConfig.PeakDisappearValue.val) {
    if (peak>value) {
      SegmentOff(peak--);
      if (peak!=value) {
	if (peak>gConfig.PeakDisappearValue.val) 
	  ShowPeak(peak);
	else SegmentOff(peak);
      }
    } else 
      if (peak<value)
	SegmentOn(peak);
  }

  
  if (delta>0) {
    for (i=oldvalue; i<=value; i++) 
      if (i < clipnum) 
	SegmentOn(i);
      else 
	ShowClip(i);
  }
  else if (delta<0) {
    for (i=oldvalue; i>=value; i--) 
      SegmentOff(i);
  }

  oldvalue=value;
}


/*******************************************************************/
/* One Segment Peak-Drop Bar Graph Implementation */
/*******************************************************************/

/*******************************************************************/
PeakDropSegmentBarGraph::PeakDropSegmentBarGraph
(int X, int Y, 
 int W, int Value, 
 int SegHeight, int SegSpace,
 int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value; 
  oldvalue=value; 
  height=Height; 
  if (segHeight==0) {
    segHeight=gConfig.SegHeight.val; 
    segSpace=gConfig.SegSpace.val; 
  }
  divider=segSpace+segHeight;
}


/*******************************************************************/
void PeakDropSegmentBarGraph::SetClipValue(int value)
{ 
  clipvalue=value; 
  clipnum=clipvalue/divider-2;
}


/*******************************************************************/
void PeakDropSegmentBarGraph::SetValue(int Value) 
{
  oldvalue=value; 
  value=Value/divider;
  if (value>clipnum) value=clipnum;
  if (value<0) value=0;
}

/*******************************************************************/
void PeakDropSegmentBarGraph::Update(void)
{
  /* peak segment */
  if (peak<value)
    SegmentOff(peak);
  peak=value > peak ? value : peak;
  if (peak >= gConfig.PeakDisappearValue.val) {
    if (peak > value) {
      SegmentOff(peak--);
      if (peak != value) {
	if (peak > gConfig.PeakDisappearValue.val) 
	  ShowPeak(peak);
	else SegmentOff(peak);
      }
    }
  }

  SegmentOff(oldvalue);
  if (value!=oldvalue) oldvalue=value;
  if (value < clipnum) SegmentOn(value);
  else ShowClip(clipnum);
}


/*******************************************************************/
/* Fading Segment Bar Graph Implementation */
/*******************************************************************/

static unsigned char _FadeColors[MAXNUMFADECOLS];

/*******************************************************************/
FadeSegmentBarGraph::FadeSegmentBarGraph(int X, int Y, 
					 int W, int Value, 
					 int SegHeight, int SegSpace,
					 int Height)
{ 
  x=X; y=Y; 
  w=W; 
  value=Value;     
  oldvalue=value; 
  height=Height; 
  if (segHeight==0) {
    segHeight=gConfig.SegHeight.val; 
    segSpace=gConfig.SegSpace.val; 
  }
  divider=segSpace+segHeight;

  num=gConfig.FadeSteps.val; // number of faders
  if (num>MAXNUMFADECOLS) num=MAXNUMFADECOLS;
  vals=new int[num];

  for (current=0; current<num; current++)
    vals[current]=0;
  current=0;
  peak=0;

  FadeArray(Color(FFADE_R, FFADE_G, FFADE_B),
	    Color(IFADE_R, IFADE_G, IFADE_B),
	    _FadeColors, num);
}


/*******************************************************************/
void FadeSegmentBarGraph::SetClipValue(int value)
{ 
  clipvalue=value; 
  clipnum=clipvalue/divider-2;
}


/*******************************************************************/
void FadeSegmentBarGraph::SetValue(int Value) 
{
  current=(current+1) % num;
  peak=vals[current];
  vals[current]=Value/divider;
  if (vals[current]>clipnum) vals[current]=clipnum;
  if (vals[current]<0) vals[current]=0;
}


/*******************************************************************/
void FadeSegmentBarGraph::Update(void)
{
  DrawSegment(peak, 0);  
  for (register int i=0, j=current; i<num; i++, ++j%=num) 
    DrawSegment(vals[j], _FadeColors[i]);
}


/*******************************************************************/












