static char BarGuage_id[] = "$Header: BarGuage.cc,v 1.3 97/03/20 12:28:46 oreilly Exp $";


/*
$Log:	BarGuage.cc,v $
Revision 1.3  97/03/20  12:28:46  12:28:46  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.2  96/10/28  09:11:50  09:11:50  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.1  96/07/22  10:41:47  10:41:47  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Vk/VkMeter.h>
#include "BarGuage.h"

XtResource BarGuage::_resources[] = 
{
  {
    "barGuageForeground",
    XtCForeground,
    XtRPixel,
    sizeof(Pixel),
    XtOffset(BarGuage *, _foreground),
    XmRString, 
    "lightgray"
  },

  {
    "barGuageBackground",
    XtCBackground,
    XtRPixel,
    sizeof(Pixel),
    XtOffset(BarGuage *, _background),
    XmRString, 
    "white"
  },

  {
    "barGuageTicColor",
    XtCForeground,
    XtRPixel,
    sizeof(Pixel),
    XtOffset(BarGuage *, _ticColor),
    XmRString, 
    "black"
  }

};


BarGuage::BarGuage(const char *name, Widget parent,
		   float minValue, float maxValue, 
		   Boolean addTickMarks, Side tickSide, 
		   const char *valueFormat)
  : VkComponent(name)
{  
  _baseWidget = XtCreateWidget(name, xmFormWidgetClass, parent, NULL, 0);
  installDestroyHandler();
  getResources(_resources, XtNumber(_resources));

  Widget meterMgr = 
    XtCreateWidget(name, xmFormWidgetClass, _baseWidget, NULL, 0);

  tickMarks = 0;
  
  if (setRange(minValue, maxValue) == -1)
    return;
  
  _meter = new VkMeter("meter", meterMgr);
  _meter->setOrientation(XmVERTICAL);

  if (addTickMarks)
  {
    Boolean labelsToLeft;
    if (tickSide == Left)
      labelsToLeft = True;
    else
      labelsToLeft = False;
    
    tickMarks = new VkTickMarks("tickMarks", meterMgr, labelsToLeft);
    int majorInterval = (int )((maxValue - minValue) / 10 + 0.5);
    int minorInterval = majorInterval / 2;
    
    tickMarks->setScale((int )minValue, (int )maxValue, 
			majorInterval, minorInterval);

    int topMargin = 0;
    int bottomMargin = 0;
    tickMarks->setMargin(topMargin, bottomMargin);
    
    if (tickSide == Left)
    {
      XtVaSetValues(_meter->baseWidget(),
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNrightAttachment, XmATTACH_FORM,		
		    XmNbottomAttachment, XmATTACH_FORM,		
		    NULL);

      XtVaSetValues(tickMarks->baseWidget(),
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNleftAttachment, XmATTACH_FORM,
		    XmNrightAttachment, XmATTACH_WIDGET,
		    XmNrightWidget, _meter->baseWidget(),
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);
    }
    else
    {
      XtVaSetValues(tickMarks->baseWidget(),
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNrightAttachment, XmATTACH_FORM,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);

      XtVaSetValues(_meter->baseWidget(),
		    XmNtopAttachment, XmATTACH_FORM,
		    XmNleftAttachment, XmATTACH_FORM,
		    XmNbottomAttachment, XmATTACH_FORM,		
		    XmNrightAttachment, XmATTACH_WIDGET,
		    XmNrightWidget, tickMarks->baseWidget(),
		    NULL);

    }
    _meter->show();
    tickMarks->show();
  }
  else
  {
    XtVaSetValues(_meter->baseWidget(),
		  XmNtopAttachment, XmATTACH_FORM,
		  XmNleftAttachment, XmATTACH_FORM,
		  XmNrightAttachment, XmATTACH_FORM,		
		  XmNbottomAttachment, XmATTACH_FORM,		
		  NULL);

    tickMarks = NULL;
    _meter->show();
  }

  if (valueFormat && strlen(valueFormat))
  {
    _valueText = new DynamicLabel("valueText", _baseWidget, 
				  XmALIGNMENT_BEGINNING);

    XtVaSetValues(_valueText->baseWidget(),
		  XmNbottomAttachment, XmATTACH_FORM,
		  XmNleftAttachment, XmATTACH_FORM,
		  XmNrightAttachment, XmATTACH_FORM,
		  XmNtopAttachment, XmATTACH_WIDGET, // New
		  XmNtopWidget, meterMgr,            // New
		  NULL);		  

    _valueText->show();
    
    _valueFormat = strdup(valueFormat);

    XtVaSetValues(meterMgr, 
		  XmNtopAttachment, XmATTACH_FORM,
		  XmNleftAttachment, XmATTACH_FORM,
		  XmNrightAttachment, XmATTACH_FORM,
		  XmNbottomAttachment, XmATTACH_POSITION,
		  XmNbottomPosition, 80,
		  NULL);
  }
  else
  {
    _valueText = NULL;
    _valueFormat = NULL;

    XtVaSetValues(meterMgr, 
		  XmNtopAttachment, XmATTACH_FORM,
		  XmNleftAttachment, XmATTACH_FORM,
		  XmNrightAttachment, XmATTACH_FORM,
		  XmNbottomAttachment, XmATTACH_FORM,
		  NULL);
  }
  
  XtManageChild(meterMgr);
  
  _ticThickness = 5;
  _barThickness = 10;


  // Set value so meter appears
  set(_minValue);
}


int BarGuage::set(float value)
{
  char errorBuf[errorMsgSize];
  
  if (value < _minValue || value > _maxValue)
  {
    sprintf(errorBuf, "value %.1f out of range", value); 
    setError(errorBuf);
    if (value < _minValue)
      value = _minValue;
    else
      value = _maxValue;
  }
  _value = value;
  
  _meter->reset(_range, _barThickness);

  if (_sameSign)
  {
    if (_maxValue < 0.)
    {
      _meter->add(intValue(value - _minValue), _barThickness, _background);
      _meter->add(intValue(_maxValue - value), _barThickness, _foreground);
    }
    else
    {
      _meter->add(intValue(value - _minValue), _barThickness, _foreground);
      _meter->add(intValue(_maxValue - value), _barThickness, _background);
    }
  }
  else
  {
    if (value < 0.)
    {
      _meter->add(intValue(value) - intValue(_minValue), _barThickness, 
		  _background);
      _meter->add(intValue(0.) - intValue(value), 
		  _barThickness, _foreground);
      _meter->add(_ticThickness, _barThickness, _ticColor);
      _meter->add(intValue(_maxValue) - intValue(0.), _barThickness, 
		  _background);
    }
    else
    {
      _meter->add(intValue(0.), _barThickness, _background);
      _meter->add(_ticThickness, _barThickness, _ticColor);
      _meter->add(intValue(value) - intValue(0.), 
		  _barThickness, _foreground);
      _meter->add(intValue(_maxValue) - intValue(value), _barThickness, 
		  _background);
    }
  }
  _meter->update();  

  if (_valueText)
  {
    char buf[100];
    sprintf(buf, _valueFormat, value);
    _valueText->setText(buf);
  }
  
  return 0;
}


int BarGuage::setRange(float minValue, float maxValue)
{
  if (minValue >= maxValue)
  {
    setError("minValue must be less than maxValue");
    return -1;
  }
  
  _minValue = minValue;
  _maxValue = maxValue;
  _imax = 500;
  _slope = _imax / (maxValue - minValue);
  _yIntercept = -1. * _slope * minValue;

  if (minValue < 0. && maxValue >= 0.)
  {
    _sameSign = False;
    _range = intValue(maxValue) - intValue(minValue) + _ticThickness;
  }
  else
  {
    _sameSign = True;
    _range = intValue(maxValue) - intValue(minValue);
  }  

  if (tickMarks)
  {
    int majorInterval = (int )((maxValue - minValue) / 10 + 0.5);
    int minorInterval = majorInterval / 2;
    
    tickMarks->setScale((int )minValue, (int )maxValue, 
			majorInterval, minorInterval);
  }

  return 0;
}


void BarGuage::setColors(Pixel barColor, Pixel background)
{
  _foreground = barColor;
  _background = background;
  set(_value);
}


void BarGuage::setBarWidth(int width)
{
  XtVaSetValues(_meter->baseWidget(), XmNwidth, width, NULL);
  _meter->setResizePolicy(XmRESIZE_NONE);
  
  XtVaSetValues(baseWidget(), XmNresizePolicy, XmRESIZE_NONE, NULL);
}


void BarGuage::setBarHeight(int height)
{
  XtVaSetValues(baseWidget(), XmNheight, height, NULL);
}


int BarGuage::intValue(float value)
{
  return (int )((_slope * value + _yIntercept) + 0.5); 
}
