/* This file is part of the KDE project
  Copyright (c) 1999 Matthias Elter (me@kde.org)

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

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "koColorSlider.h"

#include <tqpainter.h>
#include <tqcursor.h>
#include <tqpen.h>

#include <kdebug.h>
#include <kpixmapeffect.h>

KoColorFrame::KoColorFrame(TQWidget *parent):
TQFrame(parent)
{
  setFrameStyle(Panel | Sunken);
  setBackgroundMode(NoBackground);

  /* default values */
  mC1 = TQColor(0, 0, 0);
  mC2 = TQColor(255, 255, 255);

  mColorChanged = false;
  mPixChanged = false;
  mDragging = false;
}

const TQColor KoColorFrame::colorAt(const TQPoint &p)
{
  if(mPixChanged)
  {
    mImage = mPixmap.convertToImage();
    mPixChanged = false;
  }

  if(p.x() >= mPixmap.width() || p.y() >= mPixmap.height())
    return TQColor(255,255,255);

  return TQColor(mImage.pixel(p.x(), p.y()));
}

void KoColorFrame::slotSetColor1(const TQColor &c)
{
  mC1 = c;
  mColorChanged = true;
  mPixChanged = true;
  repaint();
}

void KoColorFrame::slotSetColor2(const TQColor &c)
{
  mC2 = c;
  mColorChanged = true;
  repaint();
}

void KoColorFrame::drawContents(TQPainter *p)
{
  TQRect r = contentsRect();

  if((mPixmap.size() != r.size()) || mColorChanged)
  {
    mPixmap.resize(r.width() + 1, r.height() + 1);
    KPixmapEffect::gradient(mPixmap, mC1, mC2, KPixmapEffect::HorizontalGradient);
    mColorChanged = false;
    mPixChanged = true;
  }

  p->drawPixmap(r.left(), r.top(), mPixmap);
}

void KoColorFrame::mousePressEvent(TQMouseEvent *e)
{
  if(e->button() & TQt::LeftButton)
  {
    emit clicked(e->pos());

    mDragging = true;
    TQPoint pos = TQPoint(e->pos().x() - contentsRect().left(), e->pos().y() - contentsRect().top());

    if(pos.x() < 0)
      pos.setX(0);
    else if(pos.x() >= contentsRect().width())
      pos.setX(contentsRect().width()-1);

    if(pos.y() < 0)
      pos.setY(0);
    else if(pos.y() >= contentsRect().height())
      pos.setY(contentsRect().height()-1);

    TQColor c = colorAt(pos);
    emit colorSelected(c);
  }
  else
    TQFrame::mousePressEvent(e);
}

void KoColorFrame::mouseReleaseEvent(TQMouseEvent *e)
{
  if(e->button() & TQt::LeftButton)
    mDragging = false;
  else
    TQFrame::mouseReleaseEvent(e);
}

void KoColorFrame::mouseMoveEvent(TQMouseEvent *e)
{
  if(mDragging)
  {
    bool set = false;
    int x = e->pos().x();
    int y = e->pos().y();

    int left = contentsRect().left();
    int right = contentsRect().left() + contentsRect().width();
    int top = contentsRect().top();
    int bottom =  contentsRect().top() + contentsRect().height();

    if(x < left)
    {
      x = left;
      set = true;
    }
    else if(x > right)
    {
      x = right;
      set = true;
    }
    if(y < top)
    {
      y = top;
      set = true;
    }
    else if(y > bottom)
    {
      y = bottom;
      set = true;
    }

//    if(set)
//      TQCursor::setPos(mapToGlobal(TQPoint(x,y)));

    TQPoint pos = TQPoint(x - contentsRect().left(), y - contentsRect().top());

    TQColor c = colorAt(pos);
    emit colorSelected(c);
  }
  else
    TQFrame::mouseMoveEvent(e);
}

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

KoSliderWidget::KoSliderWidget(TQWidget *parent):
TQWidget(parent)
{
  mDragging = false;
  setFixedHeight(6);
  setFixedWidth(11);
}

void KoSliderWidget::paintEvent(TQPaintEvent *)
{
  TQPainter p;
  TQPen pen(black, 1);
  p.begin(this);

  p.setPen(pen);
  p.drawLine(0, 5, 5, 0);
  p.drawLine(10, 5, 5, 0);
  p.drawLine(0, 5, 10, 5);
  p.end();
}

void KoSliderWidget::mousePressEvent(TQMouseEvent *e)
{
  if(e->button() & TQt::LeftButton)
  {
    mPos = e->pos();
    mDragging = true;
  }
  else
    TQWidget::mousePressEvent(e);
}

void KoSliderWidget::mouseReleaseEvent(TQMouseEvent *e)
{
  if(e->button() & TQt::LeftButton)
    mDragging = false;
  else
    TQWidget::mouseReleaseEvent(e);
}

void KoSliderWidget::mouseMoveEvent(TQMouseEvent *e)
{
  if(mDragging)
  {
    TQWidget *p = parentWidget();

    if(!p)
      return;

    TQPoint newPos = p->mapFromGlobal(TQCursor::pos()) - mPos;

    /* don't drag vertically */
    newPos.setY(pos().y());

    if(newPos.x() < 0)
      newPos.setX(0);
    if(newPos.x() > p->width() - width())
      newPos.setX(p->width() - width());

    move(newPos);
    emit positionChanged(newPos.x());
  }
  else
    TQWidget::mouseMoveEvent(e);
}

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

KoColorSlider::KoColorSlider(TQWidget *parent):
TQWidget(parent)
{
  mColorFrame = new KoColorFrame(this);
  mSlider = new KoSliderWidget(this);

  mMin = 0;
  mMax = 255;
  mValue = 0;

  connect(mSlider, TQ_SIGNAL(positionChanged(int)), this, TQ_SLOT(slotSliderMoved(int)));
  connect(mColorFrame, TQ_SIGNAL(clicked(const TQPoint &)), this, TQ_SLOT(slotFrameClicked(const TQPoint &)));
}

KoColorSlider::~KoColorSlider()
{
  delete mColorFrame;
  delete mSlider;
}

int KoColorSlider::minValue()
{
  return mMin;
}

int KoColorSlider::maxValue()
{
  return mMax;
}

void KoColorSlider::slotSetRange(int min, int max)
{
  if(min >= max)
    return;

  mMin = min;
  mMax = max;
}

void KoColorSlider::resizeEvent(TQResizeEvent *e)
{
  TQWidget::resizeEvent(e);
  // m_pSlider->width()/2 * 2 seems stupid but is not because for example
  // m_pSlider->width() == 11 I get 10.
  mColorFrame->setGeometry(mSlider->width() / 2, 0, width() - mSlider->width() / 2 * 2, height() - mSlider->height());
  slotSetValue(mValue);
}

void KoColorSlider::slotSetColor1(const TQColor &c)
{
  mColorFrame->slotSetColor1(c);
}

void KoColorSlider::slotSetColor2(const TQColor &c)
{
  mColorFrame->slotSetColor2(c);
}

void KoColorSlider::slotSetValue(int value)
{
  if(value < mMin)
    value = mMin;
  if(value > mMax)
    value = mMax;

  mValue = value;

  int range = mMax - mMin;
  float v = value;
  if(mMin < 0)
    v += -mMin;

  float factor = v / range;
  int x = static_cast<int>(factor * mColorFrame->contentsRect().width());

  mSlider->move(TQPoint(x, height() - mSlider->height()));
}

void KoColorSlider::slotSliderMoved(int x)
{
  if(x < 0)
    x = 0;
  if(x > mColorFrame->contentsRect().width())
    x = mColorFrame->contentsRect().width();

  float factor = x;
  factor /= mColorFrame->contentsRect().width();
  int range = mMax - mMin;

  mValue = static_cast<int>(factor * range);

  emit valueChanged(mValue);
  emit colorSelected(mColorFrame->colorAt(TQPoint(x, mColorFrame->contentsRect().height()/2)));
}

void KoColorSlider::slotFrameClicked(const TQPoint &p)
{
  TQPoint local = mColorFrame->mapToParent(p);
  TQPoint pos = TQPoint(local.x() - mSlider->width() / 2, height() - mSlider->height());

  if(pos.x() < 0)
    pos.setX(0);
  else if(pos.x() > width() - mSlider->width())
    pos.setX(width() - mSlider->width());

  mSlider->move(pos);
  slotSliderMoved(pos.x());
}

void KoColorSlider::mousePressEvent(TQMouseEvent *e)
{
  if(e->button() & TQt::LeftButton)
  {
    TQPoint pos = TQPoint(e->pos().x() - mSlider->width() / 2, height() - mSlider->height());

    if(pos.x() < 0)
      pos.setX(0);
    else if(pos.x() > width() - mSlider->width())
      pos.setX(width() - mSlider->width());

    mSlider->move(pos);
    slotSliderMoved(pos.x());
  }
  else
    TQWidget::mousePressEvent(e);
}

#include "koColorSlider.moc"
