//**************************************************************************
//*                     This file is part of the                           *
//*                MMC - Mpxplay Multimedia Commander                      *
//*                   The source code of MMC is                            *
//*        (C) copyright 1998-2018 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  This program 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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
////function: audio and video mixer control dialog window (switches, sliders)

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_AVMIX NULL //stdout
#define DISPQT_DEBUG_AMIXER stdout
#define DISPQT_DEBUGOUT_EVENT stdout

#include <QtGui>
#include <QtWidgets>
#include <QtWinExtras/QtWinExtras>
#include "disp_qt.h"
#include "moc_avmixer.h"
#include "moc_mainwindow.h"
#include "moc_video_qt.h"

extern "C" {
 extern struct mainvars mvps;
 extern keyconfig kb[];
}

DispQtAVMixerDialog::DispQtAVMixerDialog(MainWindow *main_window, QWidget *parent) : QDialog(parent, Qt::Tool)
{
	this->main_window = main_window;
	this->mixer_widget = new DispQtAVMixerWidget(main_window, this);
	this->mixer_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
	this->mixer_widget->setMaximumSize(2048, 1024);
	this->setFocusPolicy(Qt::ClickFocus);
	this->setFocus();
	if(main_window->mainwin_is_translucent_enabled())
		this->avdialog_config_style_apply(true);
	this->setWindowTitle("A/V mixer control");
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(this->mixer_widget, 1);
	setLayout(mainLayout);
	connect(this, SIGNAL(signal_avdialog_config_style_apply(bool)), this, SLOT(avdialog_config_style_apply(bool)));
	connect(this, SIGNAL(signal_avdialog_set_avformat(bool)), this, SLOT(avdialog_set_avformat(bool)));
	connect(this, SIGNAL(signal_avdialog_sliders_reload(bool)), this, SLOT(avdialog_sliders_reload(bool)));
	this->show();
}

DispQtAVMixerDialog::~DispQtAVMixerDialog()
{
	emit this->main_window->signal_mixer_dialog_close();
	this->close();
}

bool DispQtAVMixerDialog::event(QEvent *event)
{
	bool cursor_hide = false;
	switch(event->type()){
		case QEvent::Enter: break;
		case QEvent::Leave: cursor_hide = true; break;
		default: goto err_out_event;
	}
	if(this->main_window->mainwin_is_on_video() && this->main_window->qt_video_player)
		this->main_window->qt_video_player->video_mouse_cursor_show(cursor_hide);

err_out_event:
	return QDialog::event(event);
}

void DispQtAVMixerDialog::closeEvent(QCloseEvent *e)
{
	emit this->main_window->signal_mixer_dialog_close();
	QDialog::closeEvent(e);
}

void DispQtAVMixerDialog::avdialog_config_style_apply(bool lucent_enable)
{
	if(lucent_enable){
		QtWin::extendFrameIntoClientArea(this, -1, -1, -1, -1);
		setAttribute(Qt::WA_TranslucentBackground, true);
		setAttribute(Qt::WA_NoSystemBackground, false);
		setStyleSheet("QDialog { background: transparent }");
	} else {
		setAttribute(Qt::WA_TranslucentBackground, false);
		setStyleSheet(QString());
	}
	emit this->mixer_widget->signal_avmixer_config_style_apply(lucent_enable);
}

void DispQtAVMixerDialog::avdialog_set_avformat(bool video)
{
	emit this->mixer_widget->signal_avmixer_set_avformat(video);
}

void DispQtAVMixerDialog::avdialog_sliders_reload(bool volume_only)
{
	emit this->mixer_widget->signal_avmixer_sliders_reload(volume_only);
}

//-------------------------------------------------------------------------------------------

DispQtAVMixerWidget::DispQtAVMixerWidget(MainWindow *main_window, QWidget *parent) : QTabWidget(parent)
{
    this->main_window = main_window;
	this->setMinimumSize(100, 126);  // FIXME: hack, else parent doesn't know the real widget size
	this->setMaximumSize(600, 126);  // FIXME: has no effect in mainwin with AlignCentral
	setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
	this->setFocusPolicy(Qt::NoFocus);
	this->audio_mixer = new DispQtAMixer(main_window, this);
	this->video_mixer = new DispQtVMixer(main_window, this);
	this->addTab(this->audio_mixer, "Audio");
	this->addTab(this->video_mixer, "Video");
	this->setTabPosition(QTabWidget::East);
	if(main_window->mainwin_is_translucent_enabled()){
        setAttribute(Qt::WA_TranslucentBackground, true);
        setAttribute(Qt::WA_NoSystemBackground, true);
        //setStyleSheet("QWidget {background: transparent; color:white} QWidget:disabled { background: transparent; color:gray}");
		//setStyleSheet("background: transparent; color:white");
        /*setStyleSheet("QWidget { background: rgb( 255, 255, 25, 20% )}"
        		"QTabWidget::pane { background: rgb( 255, 255, 25, 20% )} QTabWidget::tab-bar { background: rgb( 255, 255, 25, 20% )}"
        		"QTabBar::tab { background: rgb( 255, 255, 25, 20% )}"
        );*/
	}
	setDocumentMode(true);
	mpxplay_debugf(DISPQT_DEBUG_AVMIX, "w:%d h:%d", this->width(), this->height());
	connect(this, SIGNAL(signal_avmixer_config_style_apply(bool)), this, SLOT(avmixer_config_style_apply(bool)));
	connect(this, SIGNAL(signal_avmixer_set_avformat(bool)), this, SLOT(avmixer_set_avformat(bool)));
	connect(this, SIGNAL(signal_avmixer_sliders_reload(bool)), this, SLOT(avmixer_sliders_reload(bool)));

	this->avmixer_set_avformat((main_window->qt_video_player && (main_window->qt_video_player->video_duration_ms() > 0))? true : false);
}

void DispQtAVMixerWidget::keyPressEvent(QKeyEvent *event)
{
	this->main_window->handle_keypressevent(event);
}

void DispQtAVMixerWidget::avmixer_config_style_apply(bool lucent_enable)
{
	this->audio_mixer->amixer_config_style_apply(lucent_enable);
	this->video_mixer->vmixer_config_style_apply(lucent_enable);
}

void DispQtAVMixerWidget::avmixer_set_avformat(bool video)
{
	this->audio_mixer->amixer_set_avformat(video);
	this->video_mixer->vmixer_sliders_reinit();
}

void DispQtAVMixerWidget::avmixer_sliders_reload(bool volume_only)
{
	this->audio_mixer->amixer_sliders_reload(volume_only);
}

//-------------------------------------------------------------------------------------------

static const struct amixer_info_s amixer_slider_configs[AMIXER_SLIDER_NUM] = {
 {"Speed",    "MIX_SPEED",    400, DISPQT_AMIXER_FLAG_VIDEOTOO },
 {"Surround", "MIX_SURROUND",   0, 0 },
 {"Bass",     "MIX_TONE_BASS",  0, 0 },
 {"Treble",   "MIX_TONE_TREBLE",0, 0 },
 {"Balance",  "MIX_BALANCE",    0, 0 },
 {"Volume",   "MIX_VOLUME",   100, DISPQT_AMIXER_FLAG_VIDEOTOO }
};

#define DISPQT_AMIXER_SLIDERCFG_VOLUME ((sizeof(amixer_slider_configs) / sizeof(struct amixer_info_s)) - 1)

#define DISPQT_AMIXER_BUTTON_WIDTH 55

DispQtAMixer::DispQtAMixer(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	this->main_window = main_window;
	this->setFocusPolicy(Qt::NoFocus);
	setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
	QHBoxLayout *amixer_layout = new QHBoxLayout;
	amixer_layout->setMargin(0);
	amixer_layout->setSpacing(5);
	for(int i = 0; i < AMIXER_SLIDER_NUM; i++) {
		this->amixer_sliders[i] = new DispQtAmixerSliders(main_window, this, &amixer_slider_configs[i]);
		amixer_layout->addWidget(this->amixer_sliders[i], 1);
	}

	QWidget *button_widget = new QWidget(this);
	button_widget->setFocusPolicy(Qt::NoFocus);
	QVBoxLayout *button_layout = new QVBoxLayout;
	button_layout->setContentsMargins(0, 0, 10, 0);
	button_layout->setSpacing(0);
	this->button_expand = new QPushButton("Expand", this);
	this->button_expand->setToolTip("Loud(ness) on/off ('|', shift-'\\')");
	this->button_expand->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_expand->setCheckable(true);
	this->button_expand->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_expand);
	this->button_reset = new QPushButton("Reset", this);
	this->button_reset->setToolTip("Set all to center (ctrl-'V')");
	this->button_reset->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_reset->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_reset);
	this->button_mute = new QPushButton("Mute", this);
	this->button_mute->setToolTip("Reduced (25%) volume on/off (ctrl-'M')");
	this->button_mute->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_mute->setCheckable(true);
	this->button_mute->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_mute);
	this->button_autovol = new QPushButton("AutoVol", this);
	this->button_autovol->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_autovol->setToolTip("Slow auto volume correction on/off ('V')");
	this->button_autovol->setCheckable(true);
	this->button_autovol->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_autovol);
	this->button_cf_enable = new QPushButton("CrosFade", this);
	this->button_cf_enable->setToolTip("Crossfade on/off ('C')");
	this->button_cf_enable->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_cf_enable->setCheckable(true);
	this->button_cf_enable->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_cf_enable);

	QWidget *btn_cf_widget = new QWidget;
	btn_cf_widget->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	QHBoxLayout *btn_cf_layout = new QHBoxLayout;
	btn_cf_layout->setMargin(0);
	btn_cf_layout->setSpacing(0);
	this->button_cf_fout = new QPushButton("fOut", this);
	this->button_cf_fout->setToolTip("Crossfade fade-out on/off ('F')");
	this->button_cf_fout->setFixedSize(30,DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_cf_fout->setCheckable(true);
	this->button_cf_fout->setFocusPolicy(Qt::NoFocus);
	btn_cf_layout->addWidget(this->button_cf_fout);
	this->button_cf_fin = new QPushButton("fIn", this);
	this->button_cf_fin->setToolTip("Crossfade fade-in on/off ('F')");
	this->button_cf_fin->setFixedSize(24,DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_cf_fin->setCheckable(true);
	this->button_cf_fin->setFocusPolicy(Qt::NoFocus);
	btn_cf_layout->addWidget(this->button_cf_fin);
	btn_cf_widget->setLayout(btn_cf_layout);

	button_layout->addWidget(btn_cf_widget);

	this->amixer_buttons_reload();

	button_widget->setLayout(button_layout);
	amixer_layout->addWidget(button_widget, 0, (Qt::AlignVCenter | Qt::AlignLeft));
	this->setLayout(amixer_layout);

	connect(this->button_expand, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_loudness(bool)));
	connect(this->button_reset, SIGNAL(pressed()), this, SLOT(amixer_sliders_set_center()));
	connect(this->button_mute, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_mute(bool)));
	connect(this->button_autovol, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_autovol(bool)));
	connect(this->button_cf_enable, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_crossfade(bool)));
	connect(this->button_cf_fout, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_cf_fadeout(bool)));
	connect(this->button_cf_fin, SIGNAL(clicked(bool)), this, SLOT(amixer_switch_cf_fadein(bool)));
}

void DispQtAMixer::keyPressEvent(QKeyEvent *event)
{
	this->main_window->handle_keypressevent(event);
}

void DispQtAMixer::amixer_config_style_apply(bool lucent_enable)
{
	for(int i = 0; i < AMIXER_SLIDER_NUM; i++)
		this->amixer_sliders[i]->avslider_config_style_apply(lucent_enable);
}

void DispQtAMixer::amixer_set_avformat(bool video)
{
	for(int i = 0; i < AMIXER_SLIDER_NUM; i++){
		const struct amixer_info_s *cfg = &amixer_slider_configs[i];
		this->amixer_sliders[i]->avslider_set_avformat(cfg, video);
	}
	this->button_expand->setDisabled(video);
	this->button_mute->setDisabled(video);
	this->button_autovol->setDisabled(video);
	this->button_cf_enable->setDisabled(video);
	this->button_cf_fout->setDisabled(video);
	this->button_cf_fin->setDisabled(video);
	if(video)
		this->amixer_switch_crossfade(false); // FIXME: other solution?
}

void DispQtAMixer::amixer_buttons_reload(void)
{
	this->button_expand->setChecked(MIXER_getvalue((char *)"MIX_TONE_LOUDNESS")? true : false);
	this->button_mute->setChecked(MIXER_getvalue((char *)"MIX_MUTE")? true : false);
	this->button_autovol->setChecked(MIXER_getvalue((char *)"MIX_AUTOVOLUME")? true : false);
	struct crossfade_info *cfi = mvps.cfi;
	this->button_cf_enable->setChecked((cfi->usecrossfade)? true : false);
	this->button_cf_fout->setChecked((cfi->crossfadetype & CFT_FADEOUT)? true : false);
	this->button_cf_fin->setChecked((cfi->crossfadetype & CFT_FADEIN)? true : false);
}

void DispQtAMixer::amixer_sliders_reload(bool volume_only)
{
	if(volume_only) {
		this->amixer_sliders[DISPQT_AMIXER_SLIDERCFG_VOLUME]->slider_reload_value();
		this->amixer_sliders[DISPQT_AMIXER_SLIDERCFG_VOLUME]->spinbox_reload_value();
	} else {
		for(int i = 0; i < AMIXER_SLIDER_NUM; i++) {
			this->amixer_sliders[i]->slider_reload_value();
			this->amixer_sliders[i]->spinbox_reload_value();
		}
		this->amixer_buttons_reload();
	}
}

void DispQtAMixer::amixer_switch_loudness(bool enable)
{
	MIXER_setfunction(mvps.fr_primary->mpi, (char *)"MIX_TONE_LOUDNESS", MIXER_SETMODE_ABSOLUTE, (int)enable);
	this->amixer_sliders_reload(false);
}

void DispQtAMixer::amixer_sliders_set_center(void)
{
	for(int i = 0; i < AMIXER_SLIDER_NUM; i++)
		this->amixer_sliders[i]->slider_set_center();
	this->button_expand->setChecked(false);
	if(this->button_expand->isEnabled()){
		MIXER_setfunction(mvps.fr_primary->mpi, (char *)"MIX_TONE_LOUDNESS", MIXER_SETMODE_RESET, 0);
		MIXER_setfunction(mvps.fr_primary->mpi, (char *)"MIX_LIMITER", MIXER_SETMODE_RESET, 0);
	}
}

void DispQtAMixer::amixer_switch_mute(bool enable)
{
	MIXER_setfunction(mvps.fr_primary->mpi, (char *)"MIX_MUTE", MIXER_SETMODE_ABSOLUTE, ((enable)? MPXPLAY_AUMIXER_MUTE_SWITCH_SIGN : 0));
}

void DispQtAMixer::amixer_switch_autovol(bool enable)
{
	MIXER_setfunction(mvps.fr_primary->mpi, (char *)"MIX_AUTOVOLUME", MIXER_SETMODE_ABSOLUTE, (int)enable);
}

void DispQtAMixer::amixer_switch_crossfade(bool enable)
{
	if(mvps.cfi->usecrossfade != (unsigned int)enable)
		pds_pushkey(kb[56].c); // !!!
}

void DispQtAMixer::amixer_switch_cf_fadeout(bool enable)
{
	struct crossfade_info *cfi = mvps.cfi;
	if(enable)
		funcbit_enable(cfi->crossfadetype, CFT_FADEOUT);
	else
		funcbit_disable(cfi->crossfadetype, CFT_FADEOUT);
}

void DispQtAMixer::amixer_switch_cf_fadein(bool enable)
{
	struct crossfade_info *cfi = mvps.cfi;
	if(enable)
		funcbit_enable(cfi->crossfadetype, CFT_FADEIN);
	else
		funcbit_disable(cfi->crossfadetype, CFT_FADEIN);
}

//-------------------------------------------------------------------------------------

#define DISPQT_AMIXER_SLIDER_MIN      ((int)0)
#define DISPQT_AMIXER_SLIDER_CENTER   ((int)100)
#define DISPQT_AMIXER_SLIDER_MAX      ((int)200)

DispQtAmixerSliders::DispQtAmixerSliders(MainWindow *main_window, QWidget *parent, const struct amixer_info_s *slider_info) : QWidget(parent)
{
	setFocusPolicy(Qt::NoFocus);
	this->amixer_name = slider_info->amixer_name;
	this->mixfunc = MIXER_getfunction((char *)this->amixer_name);
	if(!this->mixfunc)
		return;
	this->value_max = this->mixfunc->var_max;
	QVBoxLayout *slider_layout = new QVBoxLayout;
	slider_layout->setMargin(0);
	slider_layout->setSpacing(0);
	this->slider_label = new QLabel(QString::fromUtf8(slider_info->slider_name));
	this->avmix_slider = new DispQtmixerSlider(this);
	this->avmix_slider->setRange(DISPQT_AMIXER_SLIDER_MIN, DISPQT_AMIXER_SLIDER_MAX);
	this->avmix_slider->setValue(this->amixer_cv_mixerval_to_sliderval());
	this->avmix_slider->setSingleStep(this->mixfunc->var_step);
	this->avmix_slider->setTickInterval(15);
	this->avmix_slider->setTickPosition(QSlider::TicksBothSides);
	this->avmix_slider->setTracking(true);
	this->amix_spinbox = new QSpinBox;
	this->amix_spinbox->setRange(this->mixfunc->var_min, this->mixfunc->var_max);
	this->amix_spinbox->setSingleStep(this->mixfunc->var_step);
	this->amix_spinbox->setAlignment(Qt::AlignRight);
	//this->amix_spinbox->setAccelerated(true);
	if(main_window->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_EMBEDD_AVMIXER) {
		this->avmix_slider->setFocusPolicy(Qt::NoFocus);
		this->amix_spinbox->setFocusPolicy(Qt::NoFocus);
	}
	this->spinbox_reload_value();
	if(main_window->mainwin_is_translucent_enabled())
		this->avslider_config_style_apply(true);
	slider_layout->addWidget(this->slider_label, 0, Qt::AlignHCenter);
	slider_layout->addWidget(this->avmix_slider, 1, Qt::AlignHCenter);
	slider_layout->addWidget(this->amix_spinbox, 0, Qt::AlignHCenter);
	this->setLayout(slider_layout);
	connect(this->avmix_slider, SIGNAL(valueChanged(int)), this, SLOT(slider_change_handler(int)));
	connect(this->amix_spinbox, SIGNAL(valueChanged(int)), this, SLOT(spinbox_change_handler(int)));
}

void DispQtAmixerSliders::avslider_config_style_apply(bool lucent_enable)
{
	if(lucent_enable) {
		this->setStyleSheet("QWidget { background: transparent; color:white} QWidget:disabled { background: transparent; color:gray}");
		//this->slider_label->setStyleSheet("QLabel { background: transparent; color:white} QLabel:disabled { background: transparent; color:gray}");
		//this->amix_spinbox->setStyleSheet("QSpinBox { background: transparent; color:white} QSpinBox:disabled { background: transparent; color:gray}");
		/*this->setStyleSheet(
		 "QSlider::groove:vertical {background: black; position: absolute;left: 4px; right: 4px;width: 4px;}"
		 "QSlider::handle:vertical { height: 8px; background: white; margin: 0 -6px; width: 12px; border: 1px solid gray; border-radius:2px}"
		 "QSlider::add-page:vertical { background: white;}"
		 "QSlider::sub-page:vertical { background: gray; }");*/
	} else {
		this->setStyleSheet(QString());
		//this->slider_label->setStyleSheet(QString());
		//this->amix_spinbox->setStyleSheet(QString());
	}
}

void DispQtAmixerSliders::avslider_set_avformat(const struct amixer_info_s *cfg, bool video)
{
	this->setDisabled((video && !(cfg->flags & DISPQT_AMIXER_FLAG_VIDEOTOO))? true : false);
	this->value_max = (video && (cfg->flags & DISPQT_AMIXER_FLAG_VIDEOTOO))? cfg->video_limit : this->mixfunc->var_max;
	this->amix_spinbox->setMaximum(this->value_max);
	this->avmix_slider->mixerslider_setmaxval(amixer_cv_calc_mixerval_to_sliderval(this->value_max)); // !!! hack for volume control only
}

void DispQtAmixerSliders::slider_change_handler(int newval)
{
	this->amixer_cv_sliderval_to_mixerval(newval);
	this->spinbox_reload_value();
}

void DispQtAmixerSliders::spinbox_change_handler(int newval)
{
	int oldval = MIXER_getvalue((char *)this->amixer_name), center = this->mixfunc->var_center, step = this->mixfunc->var_step;
	if(((oldval < center) && (oldval > (center - step)) && (newval > center) && (newval < (center + step))) || ((oldval > center) && (oldval < (center + step)) && (newval < center) && (newval > (center - step)))) {
		MIXER_setfunction(mvps.fr_primary->mpi, (char *)this->amixer_name, MIXER_SETMODE_RESET, 0);
		this->spinbox_reload_value();
	} else
		MIXER_setfunction(mvps.fr_primary->mpi, (char *)this->amixer_name, MIXER_SETMODE_ABSOLUTE, newval);
	this->slider_reload_value();
}

int DispQtAmixerSliders::amixer_cv_calc_mixerval_to_sliderval(int value)
{
	int sliderval, center = this->mixfunc->var_center, minval = this->mixfunc->var_min, maxval = this->value_max;
	if(value > maxval)
		value = maxval;
	if(value == center)
		sliderval = DISPQT_AMIXER_SLIDER_CENTER;
	else if(value < center)
		sliderval = (DISPQT_AMIXER_SLIDER_CENTER - DISPQT_AMIXER_SLIDER_MIN ) * (value - minval ) / (center - minval) + DISPQT_AMIXER_SLIDER_MIN;
	else
		sliderval = (DISPQT_AMIXER_SLIDER_MAX - DISPQT_AMIXER_SLIDER_CENTER ) * (value - center) / (maxval - center) + DISPQT_AMIXER_SLIDER_CENTER;
	return sliderval;
}

int DispQtAmixerSliders::amixer_cv_mixerval_to_sliderval(void)
{
	return this->amixer_cv_calc_mixerval_to_sliderval(MIXER_getvalue((char *)this->amixer_name));
}

void DispQtAmixerSliders::amixer_cv_sliderval_to_mixerval(int sliderval)
{
	int mixerval, center = this->mixfunc->var_center, minval = this->mixfunc->var_min, maxval = this->value_max;
	if(sliderval == DISPQT_AMIXER_SLIDER_CENTER)
		mixerval = center;
	else if(sliderval < DISPQT_AMIXER_SLIDER_CENTER)
		mixerval = (center - minval) * (sliderval - DISPQT_AMIXER_SLIDER_MIN) / (DISPQT_AMIXER_SLIDER_CENTER - DISPQT_AMIXER_SLIDER_MIN ) + minval;
	else
		mixerval = (maxval - center) * (sliderval - DISPQT_AMIXER_SLIDER_CENTER) / (DISPQT_AMIXER_SLIDER_MAX - DISPQT_AMIXER_SLIDER_CENTER ) + center;
	MIXER_setfunction(mvps.fr_primary->mpi, (char *)this->amixer_name, MIXER_SETMODE_ABSOLUTE, mixerval);
	//mpxplay_debugf(DISPQT_DEBUG_AMIXER, "%s m:%d c:%d x:%d sv:%d mv:%d", this->amixer_name, this->mixfunc->var_min, this->mixfunc->var_center, this->mixfunc->var_max, sliderval, mixerval);
}

void DispQtAmixerSliders::slider_set_center(void)
{
	if(!this->isEnabled())
		return;
	MIXER_setfunction(mvps.fr_primary->mpi, (char *)this->amixer_name, MIXER_SETMODE_RESET, 0);
	this->slider_reload_value();
	this->spinbox_reload_value();
}

void DispQtAmixerSliders::slider_reload_value(void)
{
	int value = amixer_cv_mixerval_to_sliderval();
	disconnect(this->avmix_slider, SIGNAL(valueChanged(int)), this, SLOT(slider_change_handler(int)));
	this->avmix_slider->setSliderPosition(value);
	connect(this->avmix_slider, SIGNAL(valueChanged(int)), this, SLOT(slider_change_handler(int)));
	//mpxplay_debugf(DISPQT_DEBUG_AMIXER, "S %s m:%d c:%d x:%d v:%d", this->amixer_name, this->mixfunc->var_min, this->mixfunc->var_center, this->mixfunc->var_max, value);
}

void DispQtAmixerSliders::spinbox_reload_value(void)
{
	int value = MIXER_getvalue((char *)this->amixer_name);
	disconnect(this->amix_spinbox, SIGNAL(valueChanged(int)), this, SLOT(spinbox_change_handler(int)));
	this->amix_spinbox->setValue(value);
	connect(this->amix_spinbox, SIGNAL(valueChanged(int)), this, SLOT(spinbox_change_handler(int)));
	//mpxplay_debugf(DISPQT_DEBUG_AMIXER, "B %s m:%d c:%d x:%d v:%d", this->amixer_name, this->mixfunc->var_min, this->mixfunc->var_center, this->mixfunc->var_max, value);
}

//-------------------------------------------------------------------------------------------
DispQtmixerSlider::DispQtmixerSlider(QWidget *parent) : QSlider(Qt::Vertical, parent)
{
	this->max_value = DISPQT_AMIXER_SLIDER_MAX;
}

void DispQtmixerSlider::mixerslider_setmaxval(int max_val)
{
	this->max_value = max_val;
}

void DispQtmixerSlider::wheelEvent(QWheelEvent* event)
{
	int val = this->value(), step = event->delta() * this->pageStep() / DISPQT_MOUSE_WHEEL_SCALE, center = (this->minimum() + this->maximum()) / 2;
	//mpxplay_debugf(DISPQT_DEBUG_AMIXER, "val: %d step:%d center:%d min:%d max:%d", val, step, center, this->minimum(), this->maximum());
	if(((val < center) && ((val + step) > center)) || ((val > center) && ((val + step) < center))) {
		this->setValue(center);
		emit valueChanged(center);
		event->accept();
	} else if((val + step) > this->max_value) {
		this->setValue(this->max_value);
		emit valueChanged(this->max_value);
		event->accept();
	} else
		QSlider::wheelEvent(event);
}

//-------------------------------------------------------------------------------------------
static const char *dispqt_vmixer_slider_names[VMIXER_SLIDER_NUM] = {"Brightness", "Contrast", "Saturation", "Hue"}; // !!! shall match with DISPQT_VIDEO_VMIXERTYPE_ order
static const int dispqt_vmixer_expand_values[VMIXER_SLIDER_NUM] = {6, 12, 10, 0};  // !!! shall match with DISPQT_VIDEO_VMIXERTYPE_ order

DispQtVMixer::DispQtVMixer(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	int i;
	this->main_window = main_window;
	this->setFocusPolicy(Qt::NoFocus);

	for(i = 0; i < VMIXER_SLIDER_NUM; i++)
		this->vmixer_sliders[i] = new DispQtVmixerSliders(main_window, this, i, dispqt_vmixer_slider_names[i]);

	QHBoxLayout *vmixer_layout = new QHBoxLayout;
	vmixer_layout->setMargin(2);
	vmixer_layout->setSpacing(5);
	for(int i = 0; i < VMIXER_SLIDER_NUM; i++)
		vmixer_layout->addWidget(this->vmixer_sliders[i], 1);

	QWidget *button_widget = new QWidget;
	QVBoxLayout *button_layout = new QVBoxLayout;

	this->button_expand = new QPushButton("Expand");
	this->button_expand->setToolTip("Increase dynamic");
	this->button_expand->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_expand->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_expand);

	this->button_reset = new QPushButton("Reset");
	this->button_reset->setToolTip("Set all to center");
	this->button_reset->setFixedSize(DISPQT_AMIXER_BUTTON_WIDTH, DISPQT_AVMIXER_BUTTON_HEIGHT);
	this->button_reset->setFocusPolicy(Qt::NoFocus);
	button_layout->addWidget(this->button_reset);

	button_widget->setLayout(button_layout);
	vmixer_layout->addWidget(button_widget, 0, (Qt::AlignVCenter | Qt::AlignLeft));
	this->setLayout(vmixer_layout);

	connect(this->button_expand, SIGNAL(pressed()), this, SLOT(vmixer_set_expand()));
	connect(this->button_reset, SIGNAL(pressed()), this, SLOT(vmixer_set_center()));
}

void DispQtVMixer::vmixer_config_style_apply(bool lucent_enable)
{
	for(int i = 0; i < VMIXER_SLIDER_NUM; i++)
		this->vmixer_sliders[i]->slider_config_style_apply(lucent_enable);
}

void DispQtVMixer::vmixer_sliders_reinit(void)
{
	for(int i = 0; i < VMIXER_SLIDER_NUM; i++)
		this->vmixer_sliders[i]->slider_reinit();
}

void DispQtVMixer::vmixer_set_center(void)
{
	DispQtVideoFrameFilter *frame_filter;
	if(!this->main_window->qt_video_player)
		return;
	frame_filter = this->main_window->qt_video_player->video_frame_filter_eq_process;
	if(!frame_filter)
		return;
	frame_filter->resetVideoFilterValues(DISPQT_VIDEOFRAMEFILTER_PROCESSTYPE_VMIXERSLIDER);
	for(int i = 0; i < VMIXER_SLIDER_NUM; i++)
		this->vmixer_sliders[i]->slider_set_value(DISPQT_VMIXER_VALUE_CENTER);
}

void DispQtVMixer::vmixer_set_expand(void)
{
	DispQtVideoFrameFilter *frame_filter = this->main_window->qt_video_player->video_frame_filter_eq_process;
	bool do_expand = false;
	int i;

	for(i = 0; i < VMIXER_SLIDER_NUM; i++)
	{
		if(frame_filter->getVideoFilterValue(i) != dispqt_vmixer_expand_values[i])
		{
			do_expand = true;
			break;
		}
	}

	if(do_expand)
	{
		for(i = 0; i < VMIXER_SLIDER_NUM; i++)
		{
			this->vmixer_sliders[i]->slider_set_value(dispqt_vmixer_expand_values[i]);
		}
	}
	else
	{
		vmixer_set_center();
	}
}

//--------------------------------------------------------------------------------

DispQtVmixerSliders::DispQtVmixerSliders(MainWindow *mainwindow, QWidget *parent, int vmixerindex, const char *name) : QWidget(parent)
{
	this->setFocusPolicy(Qt::NoFocus);
	this->main_window = mainwindow;
	this->vmixer_index = vmixerindex;
	QVBoxLayout *slider_layout = new QVBoxLayout;
	slider_layout->setMargin(0);
	slider_layout->setSpacing(0);
	this->slider_label = new QLabel(QString::fromUtf8(name));
	this->avmix_slider = new DispQtmixerSlider(this);
	this->avmix_slider->setRange(DISPQT_VMIXER_VALUE_MIN, DISPQT_VMIXER_VALUE_MAX);
	this->avmix_slider->setSingleStep(2);
	this->avmix_slider->setTickInterval(15);
	this->avmix_slider->setTickPosition(QSlider::TicksBothSides);
	this->avmix_slider->setTracking(true);
	this->avmix_spinbox = new QSpinBox;
	this->avmix_spinbox->setRange(DISPQT_VMIXER_VALUE_MIN, DISPQT_VMIXER_VALUE_MAX);
	this->avmix_spinbox->setSingleStep(1);
	this->avmix_spinbox->setAlignment(Qt::AlignRight);
	if(main_window->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_EMBEDD_AVMIXER) {
		this->avmix_slider->setFocusPolicy(Qt::NoFocus);
		this->avmix_spinbox->setFocusPolicy(Qt::NoFocus);
	}
	if(main_window->mainwin_is_translucent_enabled())
		this->slider_config_style_apply(true);
	slider_layout->addWidget(this->slider_label, 0, Qt::AlignHCenter);
	slider_layout->addWidget(this->avmix_slider, 1, Qt::AlignHCenter);
	slider_layout->addWidget(this->avmix_spinbox, 0, Qt::AlignHCenter);
	this->setLayout(slider_layout);
	connect(this->avmix_slider, SIGNAL(valueChanged(int)), this->avmix_spinbox, SLOT(setValue(int)));
	connect(this->avmix_spinbox, SIGNAL(valueChanged(int)), this->avmix_slider, SLOT(setValue(int)));
	connect(this->avmix_spinbox, SIGNAL(valueChanged(int)), this, SLOT(slider_value_change_handler(int)));
}

void DispQtVmixerSliders::slider_config_style_apply(bool lucent_enable)
{
	if(lucent_enable)
		this->setStyleSheet("QWidget { background: transparent; color:white} QWidget:disabled { background: transparent; color:gray}");
	else
		this->setStyleSheet(QString());
}

void DispQtVmixerSliders::slider_reinit(void)
{
	int value = DISPQT_VMIXER_VALUE_CENTER;
	if(this->main_window->qt_video_player)
	{
		DispQtVideoFrameFilter *frame_filter = this->main_window->qt_video_player->video_frame_filter_eq_process;
		if(frame_filter)
		{
			value = frame_filter->getVideoFilterValue(this->vmixer_index);
			frame_filter->setVideoFilterValue(this->vmixer_index, value);
		}
	}
	this->avmix_slider->setValue(value);
}

void DispQtVmixerSliders::slider_set_value(int value)
{
	this->avmix_slider->setValue(value);
}

void DispQtVmixerSliders::slider_value_change_handler(int newValue)
{
	DispQtVideoFrameFilter *frame_filter;
	if(!this->main_window->qt_video_player)
		return;
	frame_filter = this->main_window->qt_video_player->video_frame_filter_eq_process;
	if(!frame_filter)
		return;
	frame_filter->setVideoFilterValue(this->vmixer_index, newValue);
	mpxplay_debugf(DISPQT_DEBUGOUT_EVENT, "slider_value_change_handler nv:%d", newValue);
}
