/***************************************************************************
                          qdialarc.cpp  -  description
                             -------------------
    begin                : Wed Aug 1 2001
    copyright            : (C) 2001 by 
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/


#include "qdialarc.h"

#include <tqpainter.h>
#include <math.h>
#include <stdlib.h>

#define qdegreesToRadians(n)  ((-(n))*M_PI*2/(360*16))

#define valToTQDegrees(n)      (int)(((n)-valMin)*angleLen/(valMax-valMin)+angleStart+0.5)


TQDialArc::TQDialArc(TQWidget *parent, const char *name ) : TQWidget(parent,name)
{
 val            = 0;
 valMin         = 0;
 valMax         = 100;
 valMinLimit       = (valMax+valMin)/2;
 valMaxLimit       = (valMax+valMin)/2;
 valMinLimitPercent= 0;
 valMaxLimitPercent= 0;
 angleStart     = 0;
 angleLen       = 360*16;
 fShowMarks     = false;
 fCalcParams    = true;
 colorMin       = TQt::green;
 colorMax       = TQt::red;
 arrowColor     = foregroundColor();
}

TQDialArc::~TQDialArc(){
}

void TQDialArc::setValue(double value)
{
 if(value>valMax) value= valMax;
 else if(value<valMin) value= valMin;
 if(val!=value) {
    TQPainter p(this);
    p.setPen(backgroundColor());
    drawArrow(&p,val);
    val= value;
    p.setPen(arrowColor);
    drawArrow(&p,val);
 }
}


void TQDialArc::setValueMin(double value)
{
 valMin= value;
 paramsChanged();
}


void TQDialArc::setValueMax(double value)
{
 valMax= value;
 paramsChanged();
}


void TQDialArc::setValueRanges(double min,double max)
{
 valMin= min;
 valMax= max;
 paramsChanged();
}


void TQDialArc::setValueLimitRanges (double min,double max)
{
 valMinLimit= min;
 valMaxLimit= max;
 update();
}

void TQDialArc::setAngle(int value)
{
 angleStart= value*16;
 paramsChanged();
}

void TQDialArc::setAngleLen(int value)
{
 angleLen= value*16;
 paramsChanged();
}


void TQDialArc::setAngles(int angle,int len)
{
 angleStart= angle*16;
 angleLen  = len*16;
 paramsChanged();
}

void TQDialArc::setColorMin(const TQColor &color)
{
 colorMin= color;
 update();
}

void TQDialArc::setColorMid(const TQColor &color)
{
 colorMid= color;
 update();
}


void TQDialArc::setColorMax(const TQColor &color)
{
 colorMax= color;
 update();
}

void TQDialArc::setColorRanges(const TQColor &min,const TQColor &mid,const TQColor &max)
{
 colorMin= min;
 colorMid= mid;
 colorMax= max;
 update();
}

void TQDialArc::setValueMinLimit(double value, int percent)
{
 valMinLimit= value;
 valMinLimitPercent= percent;
 update();
}

void TQDialArc::setValueMaxLimit(double value, int percent)
{
 valMaxLimit= value;
 valMaxLimitPercent= percent;
 update();
}

void TQDialArc::setValueMinLimitPercent(int value)
{
 valMinLimitPercent=value;
 update();
}

void TQDialArc::setValueMaxLimitPercent(int value)
{
 valMaxLimitPercent=value;
 update();
}


void TQDialArc::setShowMarks (bool flag)
{
 fShowMarks= flag;
 update();
}

void TQDialArc::setArrowColor(const TQColor &color)
{
 arrowColor= color;
}


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

void TQDialArc::resizeEvent( TQResizeEvent *)
{
 paramsChanged();
}

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


void TQDialArc::drawMarks(TQPainter *p,int l1,int l2)
{
int a;
double r,co,se;

 if(l1>l2) { a= l1; l1= l2; l2= a; }   // swap(l1,l2)

 a= (l1 / (360*16/32)) * (360*16/32);

 while(a<l1) a+= 360*16/32;
 while(a<=l2) {
   r = qdegreesToRadians(a);
   co= cos(r);
   se= sin(r);
   p->drawLine((int)(centerx+ co*(radius-1-radius/10)+0.5),
               (int)(centery+ se*(radius-1-radius/10)+0.5),
               (int)(centerx+ co*(radius-1) +0.5),
               (int)(centery+ se*(radius-1) +0.5) );
   a+= 360*16/32;
 }
}


void TQDialArc::drawArc(TQPainter *p,int l1,int l2,const TQColor &color)
{
 p->setPen(color);
 p->drawArc(centerx-radius,centery-radius,radius*2,radius*2, l1, l2-l1+1);
 if (fShowMarks) drawMarks(p,l1,l2);
}


void TQDialArc::drawArrow(TQPainter *p, double value)
{
double r= qdegreesToRadians(valToTQDegrees(value));

 p->drawLine(centerx,
            centery,
            (int)(centerx+ cos(r)*(radius-1-radius/4) +0.5),
            (int)(centery+ sin(r)*(radius-1-radius/4) +0.5)
            );
}

void TQDialArc::paintEvent ( TQPaintEvent *)
{
int l0,l1,l2,l3,l4,l5;
TQPainter p(this);

 if(fCalcParams) calcParams();

 l0= angleStart;
 l1= valToTQDegrees(valMinLimit);
 l2= valToTQDegrees(valMinLimit+(valMaxLimit-valMinLimit)*valMinLimitPercent/100);
 l3= valToTQDegrees(valMaxLimit-(valMaxLimit-valMinLimit)*valMaxLimitPercent/100);
 l4= valToTQDegrees(valMaxLimit);
 l5= angleStart+angleLen;

 drawArc(&p,l0,l1,colorMin);

 drawArc(&p,l1,l2, TQColor( (colorMin.red()  +colorMid.red()  )/2,
                           (colorMin.green()+colorMid.green())/2,
                           (colorMin.blue() +colorMid.blue() )/2  ) );

 drawArc(&p,l2,l3,colorMid);

 drawArc(&p,l3,l4, TQColor( (colorMax.red()  +colorMid.red()  )/2,
                           (colorMax.green()+colorMid.green())/2,
                           (colorMax.blue() +colorMid.blue() )/2  ) );
 drawArc(&p,l4,l5,colorMax);


 p.setPen(arrowColor);
 drawArrow(&p,val);
}


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

struct POINT2D { double x,y; };

static void calcAngleMin(double a, POINT2D &m)
{
double x= cos(a);
double y= sin(a);

  if(x<m.x) m.x= x;
  if(y<m.y) m.y= y;
}

static void calcAngleMax(double a, POINT2D &m)
{
double x= cos(a);
double y= sin(a);

  if(x>m.x) m.x= x;
  if(y>m.y) m.y= y;
}


static bool angleIsInRange(int a,int a1,int len)
{
int a2=a1+len;

  if(len>0) {
     if(a2>360*16) return a>=a1 || a<=(a2-360*16);
     else          return a>=a1 && a<=a2;
  } else {
     if(a2<0)      return a<=a1 || a>=(360*16+a2);
     else          return a>=a2 && a<=a1;
  }
}


void TQDialArc::calcParams()
{
double m,w,h;
POINT2D p1,p2,d,a;

 p1.x= p1.y= p2.x= p2.y=  0;
 //
 m= qdegreesToRadians(angleStart);
 calcAngleMin( m, p1);
 calcAngleMax( m, p2);
 m= qdegreesToRadians(angleStart+angleLen);
 calcAngleMin( m, p1);
 calcAngleMax( m, p2);
 //
 if(angleIsInRange(0     ,angleStart,angleLen)) calcAngleMax( 0       , p2);
 if(angleIsInRange(90*16 ,angleStart,angleLen)) calcAngleMin(-M_PI/2  , p1);
 if(angleIsInRange(180*16,angleStart,angleLen)) calcAngleMin(-M_PI    , p1);
 if(angleIsInRange(270*16,angleStart,angleLen)) calcAngleMax(-M_PI*3/2, p2);
 //
 d.x= p2.x - p1.x;
 d.y= p2.y - p1.y;
 //
 w= (double)width() -1;
 h= (double)height()-1;
 //
 if( d.x/d.y > w/h ) {
   m  = w / d.x;
   a.x= 0;
   a.y= (h - d.y * m)/2;
 } else {
   m  = h / d.y;
   a.x= (w - d.x * m)/2;
   a.y= 0;
 }
 radius =  (int) (m);
 centerx=  (int) ((-p1.x) *  m + a.x);
 centery=  (int) ((-p1.y) *  m + a.y);
 //
 fCalcParams= false;
}



void TQDialArc::paramsChanged()
{
 fCalcParams= true;
 update();
}

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

#include "qdialarc.moc"
