#include <QPainter>
#include "qad_types.h"
#include "slider.h"
#include "ui_slider.h"


SHSSlider::SHSSlider(QWidget * parent): QFrame(parent), ui(new Ui::SHSSlider) {
	ui->setupUi(this);
	ui->bar->installEventFilter(this);
	ui->qt_pbZero->hide();
	pval = val_ = min_ = 0.;
	max_ = 255.;
	prec = 1;
	app_scale = 1.;
	m_titleSize = 0.5;
	frac_digits = 0;
	id_click = id_set = -1;
	m_showDecInc = m_showMinMax = true;
	hasZero = m_readOnly = m_titleInsideBar = m_noFrame = false;
	style_ = From0;
	updateCaption();
}


SHSSlider::~SHSSlider() {
	delete ui;
}


QSize SHSSlider::minimumButtonSize() const {
	return ui->qt_pbDec->minimumSize();
}


int SHSSlider::spacing() const {
	return ui->horizontalLayout->spacing();
}


bool SHSSlider::event(QEvent * e) {
	if (e->type() == QEvent::FontChange || e->type() == QEvent::Polish) {
		ui->bar->setMinimumSize(preferredIconSize(2., this));
		app_scale = appScale(this);
	}
	return QFrame::event(e);
}


void SHSSlider::setSpacing(int value) {
	ui->horizontalLayout->setSpacing(value);
}


void SHSSlider::setMinimum(double min) {
	min_ = qRound(min / prec) * prec;
	if (val_ < min_) setValue(min_);
	hasZero = min_ * max_ < 0;
	ui->qt_pbZero->setVisible(hasZero && !m_readOnly);
	ui->qt_pbMin->setText(QString::number(min_));
	ui->bar->update();
}


void SHSSlider::setMaximum(double max) {
	max_ = qRound(max / prec) * prec;
	if (val_ > max_) setValue(max_);
	hasZero = min_ * max_ < 0;
	ui->qt_pbZero->setVisible(hasZero && !m_readOnly);
	ui->qt_pbMax->setText(QString::number(max_));
	ui->bar->update();
}


void SHSSlider::setValue(double val) {
	val_ = qRound(val / prec) * prec;
	if (val_ < min_) val_ = min_;
	if (val_ > max_) val_ = max_;
	if (pval == val_) return;
	pval = val_;
	updateCaption();
	ui->bar->update();
}


void SHSSlider::setMinimumButtonSize(const QSize & sz) {
	ui->qt_pbDec->setMinimumSize(sz);
	ui->qt_pbInc->setMinimumSize(sz);
	ui->qt_pbMax->setMinimumSize(sz);
	ui->qt_pbMin->setMinimumSize(sz);
	ui->qt_pbZero->setMinimumSize(sz);
}


void SHSSlider::setPrecision(double precision) {
	if (precision == 0.) return;
	prec = qAbs(precision);
	min_ = qRound(min_ / prec) * prec;
	max_ = qRound(max_ / prec) * prec;
	double p = prec - floor(prec);
	frac_digits = 0;
	while (p > 1.E-6 && frac_digits < 8) {
		p *= 10;
		p = p - floor(p);
		++frac_digits;
	}
	setValue(val_);
	ui->qt_pbDec->setText("-" + QString::number(prec));
	ui->qt_pbInc->setText("+" + QString::number(prec));
	ui->qt_pbMin->setText(QString::number(min_));
	ui->qt_pbMax->setText(QString::number(max_));
}


bool SHSSlider::eventFilter(QObject * o, QEvent * e) {
	int w = ui->bar->width();
	if (w <= 0) return QObject::eventFilter(o, e);
	QPoint mp;
	QMouseEvent * me = ((QMouseEvent * )e);
	switch (e->type()) {
	case QEvent::Paint:
		drawBar();
		break;
	case QEvent::MouseButtonPress:
	case QEvent::MouseMove:
		if (m_readOnly) break;
		if (isEnabled()) {
			if (me->buttons() != Qt::NoButton) {
				mp = me->pos();
				setValue((max_ - min_) * (float(mp.x()) / w) + min_);
			}
			return true;
		}
	case QEvent::MouseButtonRelease:
		if (m_readOnly) break;
		return true;
	default: break;
	};
	return QObject::eventFilter(o, e);
}


void SHSSlider::updateCaption() {
	double cval = value();
	title_cur = QString(title_).replace("%v", QString::number(cval, 'f', frac_digits));
	if (titleInsideBar()) {
		ui->labelTitle->setText(QString());
		update();
	} else
		ui->labelTitle->setText(title_cur);
	ui->widgetTitle->setHidden(ui->labelTitle->text().isEmpty());
	emit valueChanged(cval);
	emit valueChanged((int)cval);
	emit valueChangedID(id_click, cval);
	emit valueChangedID(id_click, (int)cval);
}


void SHSSlider::drawBar() {
	QRectF rct(ui->bar->rect()), vr;
	float range = max_ - min_;
	if (rct.isEmpty() || (qAbs(range) < 1.E-6)) return;
	float vz = -min_ / range, vv = (val_ - min_) / range;
	bool dz = false;
	switch (style_) {
	case From0:
		if (min_ >= 0. && max_ >= 0.)
			vr.setRect(0, 0, rct.width() * vv, rct.height());
		else {
			if (min_ <= 0. && max_ <= 0.)
				vr.setRect(rct.width() * vv, 0, rct.width() * (1.f - vv), rct.height());
			else {
				dz = true;
				float mmin = qAbs(min_ / range), mmax = qAbs(max_ / range);
				if (val_ >= 0) vr.setRect(rct.width() * mmin, 0, rct.width() * mmax * (val_ / max_), rct.height());
				else vr.setRect(rct.width() * mmin * (1.f - val_ / min_), 0, rct.width() * mmin * (val_ / min_), rct.height());
			}
		}
		break;
	case MinToValue:
		vr.setRect(0, 0, rct.width() * vv, rct.height());
		break;
	case MaxToValue:
		vr.setRect(rct.width() * vv, 0, rct.width() * (1.f - vv), rct.height());
		break;
	default: break;
	}
	float radius = 5. * app_scale;
	QPainter p(ui->bar);
	p.setRenderHint(QPainter::Antialiasing);
	
	p.setPen(Qt::NoPen);
	p.setBrush(palette().brush(QPalette::Normal, QPalette::Highlight));
	p.drawRoundedRect(vr, radius, radius);
	
	p.setPen(palette().color(QPalette::Dark));
	p.setBrush(Qt::NoBrush);
	if (dz) p.drawLine(vz * rct.width(), 0, vz * rct.width(), rct.height());
	p.drawRoundedRect(rct, radius, radius);

	if (titleInsideBar()) {
		QRectF trect(0, 0, rct.width(), rct.height());
		float dmin = qMin(trect.width(), trect.height());
		trect = enlargedRect(trect, 0., 0., -dmin * (1. - titleSize()) / 2.);
		QFont fnt = p.font();
		fnt.setPixelSize(trect.height());
		p.setFont(fnt);
		p.setPen(palette().color(QPalette::Normal, QPalette::Text));
		p.drawText(trect, Qt::AlignCenter, title_cur);
		p.setClipping(true);
		p.setClipRect(vr.toRect());
		p.setPen(palette().color(QPalette::Normal, QPalette::HighlightedText));
		p.drawText(trect, Qt::AlignCenter, title_cur);
	}
}


void SHSSlider::setReadOnly(bool yes) {
	m_readOnly = yes;
	ui->qt_pbDec->setHidden(yes);
	ui->qt_pbInc->setHidden(yes);
	ui->qt_pbZero->setHidden(yes || !hasZero);
}


void SHSSlider::setShowMinMax(bool yes) {
	m_showMinMax = yes;
	ui->qt_pbMin->setVisible(yes);
	ui->qt_pbMax->setVisible(yes);
}


void SHSSlider::setShowDecInc(bool yes) {
	m_showDecInc = yes;
	ui->qt_pbDec->setVisible(yes);
	ui->qt_pbInc->setVisible(yes);
}


void SHSSlider::setNoFrame(bool yes) {
	m_noFrame = yes;
	setFrameShape(m_noFrame ? QFrame::NoFrame : QFrame::StyledPanel);
	int m = m_noFrame ? 0 : 4;
	layout()->setContentsMargins(m, m, m, m);
}
