//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: scrollscale.cpp,v 1.1.1.1 2003/10/29 10:06:27 wschweer Exp $
//  (C) Copyright 1999 Werner Schweer (ws@seh.de)
//=========================================================

#include <stdio.h>
#include <cmath>
#include <qslider.h>
#include <qscrollbar.h>
#include <qlayout.h>
#include <qtoolbutton.h>
#include <qtooltip.h>
#include <qlabel.h>

// #include "globals.h"
#include "scrollscale.h"
#include "icons.h"

//---------------------------------------------------------
//   setScale
//    "val" - slider value in range 0-1024
//---------------------------------------------------------

void ScrollScale::setScale(int val)
      {
      if (invers)
            val = 1024 - val;
      double min, max;
      if (scaleMin < 0)
            min = 1.0/(-scaleMin);
      else
            min = double(scaleMin);

      if (scaleMax < 0)
            max = 1.0/(-scaleMax);
      else
            max = double(scaleMax);

      double diff = max-min;
      double fkt  = double(val)/1024.0;
      double v = (pow(logbase, fkt)-1)/(logbase-1);
      double scale;
      if (invers)
            scale = max - v * diff;
      else
            scale = min + v * diff;

      if (scale < 1.0)
            scaleVal = -(int(1.0 / scale));
      else
            scaleVal = int(scale);
      if (scaleVal == -1)     // nur so
            scaleVal = 1;

#if 0
      if (scaleMax > scaleMin) {
            if (scale < scaleMin)
                  scale = scaleMin;
            else if (scale > scaleMax)
                  scale = scaleMax;
            }
      else {
            if (scale < scaleMax)
                  scale = scaleMax;
            else if (scale > scaleMin)
                  scale = scaleMin;
            }
#endif

      int sval = scroll->value();
      emit scaleChanged(scaleVal);
      if (!noScale)
            setRange(minVal, maxVal);
      setPos(sval);
      }

//---------------------------------------------------------
//   setMag
//---------------------------------------------------------

void ScrollScale::setMag(int cs)
      {
      scale->setValue(cs);
      setScale(cs);
      }

//---------------------------------------------------------
//   setRange
//    min,max  ticks
//---------------------------------------------------------

void ScrollScale::setRange(int min, int max)
      {
//      if ((min != minVal) && (max != maxVal))
//            return;
      minVal = min;
      maxVal = max;
      int i = (scroll->orientation() == Horizontal) ? width() : height();

      if (!noScale) {
            if (scaleVal < 1) {
                  min = minVal / (-scaleVal);
                  max = (maxVal-scaleVal-1) / (-scaleVal) - i;
                  }
            else {
                  min = minVal * scaleVal;
                  max = maxVal * scaleVal - i;
                  }
            }
      else
            max -= i;
      if (max < 0)
            max = 0;
      if (min < 0)
            min = 0;
      if (min > max)
            max = min;
      scroll->setRange(min, max);

      // qt doesn't check this...
      if (scroll->value() < min)
            scroll->setValue(min);
      if (scroll->value() > max)
      	scroll->setValue(max);
      scroll->setSteps(20, i);
      }

//---------------------------------------------------------
//   setPos
//    pos in pixel
//---------------------------------------------------------

void ScrollScale::setPos(int pos)
      {
      scroll->setValue(pos);
      }

//---------------------------------------------------------
//   resizeEvent
//---------------------------------------------------------

void ScrollScale::resizeEvent(QResizeEvent*)
      {
      setScale(scale->value());
      }

//---------------------------------------------------------
//   ScrollScale
//---------------------------------------------------------

ScrollScale::ScrollScale(int s1, int s2, int cs, int max_, Orientation o,
   QWidget* parent, int min_, bool inv, double bas)
   : QWidget(parent)
      {
      noScale     = false;
      _page        = 0;
      _pages       = 1;
      pageButtons = false;
      showMagFlag = true;
      scaleMin    = s1;
      scaleMax    = s2;
      minVal      = min_;
      maxVal      = max_;
      up          = 0;
      down        = 0;
      logbase     = bas;
      invers      = inv;

      double min, max;
      if (scaleMin < 0)
            min = 1.0/(-scaleMin);
      else
            min = double(scaleMin);

      if (scaleMax < 0)
            max = 1.0/(-scaleMax);
      else
            max = double(scaleMax);

      double cmag = (cs < 0) ? (1.0/(-cs)) : double(cs);
      double diff = max-min;

      //
      // search initial value for slider
      //
      int cur   = 512;
      int delta = 256;
      for (int i = 0; i < 8; ++i) {
            int tryVal   = invers ? 1025 - cur : cur;
            double fkt   = double(tryVal)/1024.0;
            double v     = (pow(logbase, fkt)-1)/(logbase-1);
            double scale = invers ? (max - v * diff) : (min + v * diff);
            if (scale == cmag)   // not very likely
                  break;
// printf("iteration %d invers:%d soll %f(cur:%d) - ist %f\n", i, invers, scale, cur, cmag);
            int dd = invers ? -delta : delta;
            cur += (scale < cmag) ? dd : -dd;
            delta/=2;
            }

      scale  = new QSlider(0, 1024, 1, cur, o, this);
      scroll = new QScrollBar(o, this);
      setScale(cur);

      if (o == Horizontal) {
            box = new QBoxLayout(this, QBoxLayout::LeftToRight);
//            scale->setFixedHeight(18);
//            scroll->setFixedHeight(18);
            scale->setMaximumWidth(70);
            scroll->setMinimumWidth(50);
            }
      else {
            box = new QBoxLayout(this, QBoxLayout::Down);
//            scale->setFixedWidth(18);
//            scroll->setFixedWidth(18);
            scroll->setMinimumHeight(50);
            scale->setMaximumHeight(70);
            }
      box->addWidget(scroll, 10);
      box->addWidget(scale, 5);
      connect(scale, SIGNAL(valueChanged(int)), SLOT(setScale(int)));
      connect(scale, SIGNAL(valueChanged(int)), SIGNAL(lscaleChanged(int)));
      connect(scroll, SIGNAL(valueChanged(int)), SIGNAL(scrollChanged(int)));
      }

//---------------------------------------------------------
//   setPageButtons
//---------------------------------------------------------

void ScrollScale::setPageButtons(bool flag)
      {
      if (flag == pageButtons)
            return;

      if (flag) {
            if (up == 0) {
                  up = new QToolButton(this);
                  up->setPixmap(*(upIcon));
                  down = new QToolButton(this);
                  down->setPixmap(*(downIcon));
                  pageNo = new QLabel(this);
                  QString s;
                  s.setNum(_page+1);
                  pageNo->setText(s);
                  QToolTip::add(down, tr("next page"));
                  QToolTip::add(up, tr("previous page"));
                  QToolTip::add(pageNo, tr("current page number"));
                  box->insertWidget(1, up);
                  box->insertWidget(2, down);
                  box->insertSpacing(3, 5);
                  box->insertWidget(4, pageNo);
                  box->insertSpacing(5, 5);
                  connect(up, SIGNAL(clicked()), SLOT(pageUp()));
                  connect(down, SIGNAL(clicked()), SLOT(pageDown()));
                  }
            up->show();
            down->show();
            pageNo->show();
            if (_page == (_pages-1))
                  down->setEnabled(false);
            if (_page == 0)
                  up->setEnabled(false);
            }
      else {
            up->hide();
            down->hide();
            }
      pageButtons = flag;
      }

//---------------------------------------------------------
//   showMag
//---------------------------------------------------------

void ScrollScale::showMag(bool flag)
      {
      showMagFlag = flag;
      if (flag)
            scale->show();
      else
            scale->hide();
      box->activate();
      }

//---------------------------------------------------------
//   setOffset
//    val in tick
//---------------------------------------------------------

void ScrollScale::setOffset(int val)
      {
      int i = (scroll->orientation() == Horizontal) ? width() : height();
      int pos, max;

      if (scaleVal < 1) {
            pos = (val-scaleVal/2) / (-scaleVal);
            max = (maxVal-scaleVal-1) / (-scaleVal) - i;
            }
      else {
            pos = val * scaleVal;
            max = maxVal * scaleVal - i;
            }
      if (pos > max) {
            int min;
            if (scaleVal < 1) {
                  maxVal  = (pos + width()) * (-scaleVal);
                  min = (minVal-scaleVal/2) / (-scaleVal);
                  max     = (maxVal-scaleVal/2) / (-scaleVal) - i;
                  }
            else {
                  maxVal  = (pos + width() + scaleVal/2)/scaleVal;
                  min = minVal * scaleVal;
                  max     = maxVal * scaleVal - i;
                  }

            if (max < 0)
                  max = 0;
            if (min < 0)
                  min = 0;
            if (min > max)
                  max = min;
            scroll->setRange(min, max);
            }
      setPos(pos);
      }

//---------------------------------------------------------
//   pageUp
//    goto previous page
//---------------------------------------------------------

void ScrollScale::pageUp()
      {
      if (_page) {
            --_page;
            emit newPage(_page);
            QString s;
            s.setNum(_page+1);
            pageNo->setText(s);
            if (_page == 0)
                  up->setEnabled(false);
            if (_page == (_pages-2))
                  down->setEnabled(true);
            }
      }

//---------------------------------------------------------
//   pageDown
//    goto next page
//---------------------------------------------------------

void ScrollScale::pageDown()
      {
      if (_page + 1 < _pages) {
            ++_page;
            emit newPage(_page);
            QString s;
            s.setNum(_page+1);
            pageNo->setText(s);
            if (_page == (_pages-1))
                  down->setEnabled(false);
            if (_page == 1)
                  up->setEnabled(true);
            }
      }

//---------------------------------------------------------
//   setPages
//---------------------------------------------------------

void ScrollScale::setPages(int n)
      {
      _pages = n;
      if (_page >= _pages) {
            _page = _pages-1;
            emit newPage(_page);
            QString s;
            s.setNum(_page+1);
            pageNo->setText(s);
            }
      up->setEnabled(_page);
      down->setEnabled(_page < (_pages-1));
      }

int ScrollScale::pos() const
      {
      return scroll->value();
      }

int ScrollScale::mag() const
      {
      return scale->value();
      }

