//**************************************************************************
//*                     This file is part of the                           *
//*                MMC - Mpxplay Multimedia Commander                      *
//*                   The source code of MMC is                            *
//*        (C) copyright 1998-2015 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: menu -> configure

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_OUTPUT stdout

#include <QtGui>
#include <QtWidgets>
#include <QLineEdit>
#include <QLabel>
#include <QFontDialog>
#include "disp_qt.h"
#include "moc_config.h"
#include "moc_mainwindow.h"
#include "moc_video_qt.h"
#include "control/cntfuncs.h"
#include "display/display.h"

#define DISPQT_CONFIG_TOOLTIP_DURATION 15000

extern "C" {
 extern unsigned long displaymode, desktopmode, desktopmod_player, desktopmod_commander;
 extern unsigned long playcontrol, playrand, playreplay, su_startupenabled, mpxplay_programcontrol;
 extern unsigned long mpxplay_playlistcontrol, mpxplay_playlistcontrol_mpxpini, loadid3tag, loadid3tag_mpxpini;
 extern unsigned long preloadinfo, preloadinfo_mpxpini, mpxplay_sortcontrol, outmode, outmode_mpxpini;
 extern unsigned long mpxplay_progtimebegin,mpxplay_playtimestart,mpxplay_progtimelen,mpxplay_progtimeexit;
 extern unsigned long intsoundconfig,refdisp;
 extern char mpxplay_extrafiletypes_config[MPXINI_MAX_CHARDATA_LEN];
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
 extern char mpxplay_config_video_preffered_audiotypes[MPXINI_MAX_CHARDATA_LEN];
 extern char mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_NUM][MPXINI_MAX_CHARDATA_LEN];
#endif
 extern struct mpxplay_audioout_info_s au_infos;
 extern struct mainvars mvps;
 extern keyconfig kb[];
}

static int dispqtconfig_content_row_selected;

DispQtConfigWindow::DispQtConfigWindow(MainWindow *main_window, QWidget *parent) : QDialog(parent)
{
	main_window->video_fullscreen_mainwin_opacity_disable(true);

	this->main_window = main_window;
	this->parent_widget = parent;
	this->setMinimumWidth(200);
	this->setMaximumWidth(404);

	contentsWidget = new QListWidget;
	contentsWidget->setViewMode(QListView::ListMode);
	//contentsWidget->setIconSize(QSize(48, 42));
	contentsWidget->setMovement(QListView::Static);
	contentsWidget->setMaximumWidth(64);

	pagesWidget = new QStackedWidget;
	this->configpage_mainwin = new DispQtConfigpageMainwin(main_window, this);
	pagesWidget->addWidget(this->configpage_mainwin);
	this->configpage_display = new DispQtConfigpageDisplay(main_window, this);
	pagesWidget->addWidget(this->configpage_display);
	this->configpage_color = new DispQtConfigpageColor(main_window, this);
	pagesWidget->addWidget(this->configpage_color);
	this->configpage_font = new DispQtConfigpageFont(main_window, this);
	pagesWidget->addWidget(this->configpage_font);
	this->configpage_opacity = new DispQtConfigpageOpacity(main_window, this);
	pagesWidget->addWidget(this->configpage_opacity);
	this->configpage_playlist = new DispQtConfigpagePlayList(main_window, this);
	pagesWidget->addWidget(this->configpage_playlist);
	this->configpage_playcontrol = new DispQtConfigpagePlayControl(main_window, this);
	pagesWidget->addWidget(this->configpage_playcontrol);
	this->configpage_program = new DispQtConfigpageProgram(main_window, this);
	pagesWidget->addWidget(this->configpage_program);
	this->configpage_audio = new DispQtConfigpageAudio(main_window, this);
	pagesWidget->addWidget(this->configpage_audio);
	this->configpage_video = new DispQtConfigpageVideo(main_window, this);
	pagesWidget->addWidget(this->configpage_video);

	QPushButton *button_ok = new QPushButton(tr("OK"));
	QPushButton *button_cancel = new QPushButton(tr("Cancel"));
	QPushButton *button_apply = new QPushButton(tr("Apply"));

	config_create_listlines();
	contentsWidget->setCurrentRow(dispqtconfig_content_row_selected);

	connect(button_ok, SIGNAL(clicked()), this, SLOT(config_ok_close()));
	connect(button_cancel, SIGNAL(clicked()), this, SLOT(close()));
	connect(button_apply, SIGNAL(clicked()), this, SLOT(config_apply()));

	QHBoxLayout *horizontalLayout = new QHBoxLayout;
	QWidget *horizontal_widget = new QWidget(this);
	horizontalLayout->addWidget(contentsWidget);
	horizontalLayout->addWidget(pagesWidget, 1);
	horizontal_widget->setLayout(horizontalLayout);

	QHBoxLayout *buttonsLayout = new QHBoxLayout;
	QWidget *buttons_widget = new QWidget(this);
	buttonsLayout->addStretch(1);
	buttonsLayout->addWidget(button_ok);
	buttonsLayout->addWidget(button_cancel);
	buttonsLayout->addWidget(button_apply);
	buttons_widget->setLayout(buttonsLayout);

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(horizontal_widget);
	mainLayout->addWidget(buttons_widget);
	mainLayout->setContentsMargins(0,5,0,0);
	setLayout(mainLayout);

	setWindowTitle(tr("Configure MMC"));
	show();
}

void DispQtConfigWindow::closeEvent(QCloseEvent *e)
{
	this->main_window->video_fullscreen_mainwin_opacity_disable(false);
	QDialog::closeEvent(e);
}

void DispQtConfigWindow::keyPressEvent(QKeyEvent *event)
{
	if(event->key() == Qt::Key_Escape)
		this->main_window->video_fullscreen_mainwin_opacity_disable(false);
	QDialog::keyPressEvent(event);
}

static const char *config_menu_list_names[] = {"Layout", "Display", " Color", " Font", " Opacity", "List", "Play", "Program", "Audio", "Video"};

#define DISPQT_CONFIGMENU_NB_ELEMS (sizeof(config_menu_list_names) / sizeof(config_menu_list_names[0]))

void DispQtConfigWindow::config_create_listlines()
{
	for(int i = 0; i < DISPQT_CONFIGMENU_NB_ELEMS; i++) {
		QListWidgetItem *button = new QListWidgetItem(contentsWidget);
		//button->setIcon(QIcon(":/images/query.png"));
		button->setText(QString::fromUtf8(config_menu_list_names[i]));
		button->setTextAlignment(Qt::AlignLeft);
		button->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
	}

	connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
}

void DispQtConfigWindow::changePage(QListWidgetItem *current, QListWidgetItem *previous)
{
	if (!current)
		current = previous;
	dispqtconfig_content_row_selected = contentsWidget->row(current);
	pagesWidget->setCurrentIndex(dispqtconfig_content_row_selected);
}

void DispQtConfigWindow::config_apply()
{
	this->configpage_mainwin->configpage_mainwin_applyall();
	this->configpage_display->configpage_display_applyall();
	this->configpage_color->configpage_color_applyall();
	this->configpage_font->configpage_font_applyall();
	this->configpage_opacity->configpage_opacity_applyall();
	this->configpage_playlist->configpage_playlist_applyall();
	this->configpage_playcontrol->configpage_playcontrol_applyall();
	this->configpage_program->configpage_program_applyall();
	this->configpage_audio->configpage_audio_applyall();
	this->configpage_video->configpage_video_applyall();
	emit this->main_window->signal_config_apply();
	//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "fontedit: \"%s\"", this->main_window->fonttext_editor.toLatin1().data());
}

void DispQtConfigWindow::config_ok_close()
{
	this->config_apply();
	this->close();
}

//--------------------------------------------------------------------------------------
DispQtConfigpageCheckboxGroup::DispQtConfigpageCheckboxGroup(MainWindow *main_window, QWidget *parent, const struct configpage_chkbox_s *p_chkbox_config, int nb_config) : QVBoxLayout(parent)
{
	if(!p_chkbox_config || (nb_config <= 0))
		return;
	this->chkbox_config = p_chkbox_config;
	this->nb_of_chkboxconfig = nb_config;

	this->chkbox_widgets = new QCheckBox *[nb_config];
	if(!this->chkbox_widgets)
		return;

	this->setContentsMargins(3,0,3,3);
	this->setSpacing(5);

	for(int i = 0; i < nb_config; i++, p_chkbox_config++) {
		unsigned long *varptr = p_chkbox_config->chkvar;
		if(varptr) {
			this->chkbox_widgets[i] = new QCheckBox;
			this->chkbox_widgets[i]->setText(QString::fromUtf8(p_chkbox_config->name));
			if(p_chkbox_config->chkbit) {
				this->chkbox_widgets[i]->setCheckable(true);
				bool setc = (*(p_chkbox_config->chkvar) & p_chkbox_config->chkbit)? true:false;
				this->chkbox_widgets[i]->setChecked(setc);
			} else
				this->chkbox_widgets[i]->setDisabled(true);
			this->chkbox_widgets[i]->setToolTip(QString::fromUtf8(p_chkbox_config->tooltip));
			this->chkbox_widgets[i]->setToolTipDuration(DISPQT_CONFIG_TOOLTIP_DURATION);
			this->addWidget(this->chkbox_widgets[i]);
		} else {
			QLabel *label = new QLabel(QString::fromUtf8(p_chkbox_config->name));
			this->addWidget(label);
			this->chkbox_widgets[i] = NULL;
		}
	}
}

DispQtConfigpageCheckboxGroup::~DispQtConfigpageCheckboxGroup()
{
	if(this->chkbox_widgets)
		delete this->chkbox_widgets;
}

void DispQtConfigpageCheckboxGroup::checkboxgroup_applyall(void)
{
	for(int i = 0; i < this->nb_of_chkboxconfig; i++) {
		unsigned long *varptr = this->chkbox_config[i].chkvar;
		if(!varptr)
			continue;
		if(!this->chkbox_widgets[i]->isCheckable())
			continue;
		unsigned long chkbit = this->chkbox_config[i].chkbit;
		if(this->chkbox_widgets[i]->isChecked())
			funcbit_enable(*varptr, chkbit);
		else
			funcbit_disable(*varptr, chkbit);
	}
}

DispQtConfigpageCheckboxGroupbox::DispQtConfigpageCheckboxGroupbox(MainWindow *main_window, QWidget *parent, QString box_title, const struct configpage_chkbox_s *p_chkbox_config, int nb_config) : QGroupBox(box_title, parent)
{
	this->checkbox_group = new DispQtConfigpageCheckboxGroup(main_window, parent, p_chkbox_config, nb_config);
	this->checkbox_group->setMargin(3);
	this->setLayout(this->checkbox_group);
}

DispQtConfigpageCheckboxGroupbox::~DispQtConfigpageCheckboxGroupbox()
{
	if(this->checkbox_group)
		delete this->checkbox_group;
	this->close();
}

void DispQtConfigpageCheckboxGroupbox::checkboxgroup_applyall(void)
{
	if(this->checkbox_group)
		this->checkbox_group->checkboxgroup_applyall();
}

//--------------------------------------------------------------------------------------
DispQtConfigpageSpinboxGroupbox::DispQtConfigpageSpinboxGroupbox(MainWindow *main_window, QWidget *parent, QString box_title, const struct configpage_spinbox_s *p_spinbox_config, int nb_config) : QGroupBox(box_title, parent)
{
	if(!p_spinbox_config || (nb_config <= 0))
		return;
	this->spinbox_config = p_spinbox_config;
	this->nb_of_spinboxconfig = nb_config;

	this->spinbox_widgets = new QSpinBox *[nb_config];
	if(!this->spinbox_widgets)
		return;

	QGridLayout *boxlayout = new QGridLayout;
	boxlayout->setMargin(3);
	boxlayout->setSpacing(0);
	boxlayout->setColumnStretch(0, 10);
	boxlayout->setColumnStretch(1, 1);

	for(int i = 0; i < nb_config; i++) {
		QLabel *spin_text = new QLabel(QString::fromUtf8(p_spinbox_config[i].name));
		boxlayout->addWidget(spin_text, i, 0);
		unsigned long *varptr = p_spinbox_config[i].var_ptr;
		if(varptr) {
			this->spinbox_widgets[i] = new QSpinBox;
			this->spinbox_widgets[i]->setAlignment(Qt::AlignRight);
			this->spinbox_widgets[i]->setAccelerated(true);
			this->spinbox_widgets[i]->setRange(p_spinbox_config[i].val_min, p_spinbox_config[i].val_max);
			this->spinbox_widgets[i]->setValue(*varptr);
			boxlayout->addWidget(this->spinbox_widgets[i], i , 1);
		} else {
			this->spinbox_widgets[i] = NULL;
		}
	}

	this->setLayout(boxlayout);
}

DispQtConfigpageSpinboxGroupbox::~DispQtConfigpageSpinboxGroupbox()
{
	if(this->spinbox_widgets)
		delete this->spinbox_widgets;
	this->close();
}

void DispQtConfigpageSpinboxGroupbox::spinboxgroup_applyall(void)
{
	for(int i = 0; i < this->nb_of_spinboxconfig; i++) {
		unsigned long *varptr = this->spinbox_config[i].var_ptr;
		if(!varptr || !this->spinbox_widgets[i])
			continue;
		*varptr = this->spinbox_widgets[i]->value();
	}
}

//--------------------------------------------------------------------------------------
DispQtConfigpageEditlineGroup::DispQtConfigpageEditlineGroup(MainWindow *main_window, QWidget *parent, const struct configpage_editline_s *p_editline_config, int nb_config) : QGridLayout(parent)
{
	QString qs;

	if(!p_editline_config || (nb_config <= 0))
		return;
	this->editline_config = p_editline_config;
	this->nb_of_editlineconfig = nb_config;

	this->lineedits = new QLineEdit *[nb_config];
	if(!this->lineedits)
		return;

	this->setMargin(3);
	this->setSpacing(0);
	this->setColumnStretch(0, (nb_config == 1)? 1 : 10);  // FIXME: hack
	this->setColumnStretch(1, 1);

	for(int i = 0; i < nb_config; i++) {
		char *name = (char *)p_editline_config[i].name;
		if(!name)
			name = (char *)" ";
		QLabel *label = new QLabel(QString::fromUtf8(name));
		this->addWidget(label, i, 0);
		QLineEdit *qe = new QLineEdit;
		this->lineedits[i] = qe;
		qe->setText(QString::fromUtf8(p_editline_config[i].var_ptr));
		qe->setMaxLength(p_editline_config->var_size - 1);
		this->addWidget(qe, i, 1);
		qe->setToolTip(QString::fromUtf8(p_editline_config[i].tooltip));
		qe->setToolTipDuration(DISPQT_CONFIG_TOOLTIP_DURATION);
		mpxplay_debugf(DISPQT_DEBUG_OUTPUT,"qe: %d \"%s\" %d \"%s\"", qe->text().length(), qe->text().toUtf8().data(),pds_strlen(p_editline_config[i].var_ptr),p_editline_config[i].var_ptr);
	}
}

DispQtConfigpageEditlineGroup::~DispQtConfigpageEditlineGroup()
{
	if(this->lineedits)
		delete this->lineedits;
}

void DispQtConfigpageEditlineGroup::editlinegroup_applyall(void)
{
	for(int i = 0; i < this->nb_of_editlineconfig; i++) {
		char *varptr = this->editline_config[i].var_ptr;
		if(!varptr)
			continue;
		char *data = this->lineedits[i]->text().toUtf8().data();
		if(data){
			pds_strncpy(varptr, data, MPXINI_MAX_CHARDATA_LEN - 1);
			pds_strcutspc(varptr);
		}
	}
}

DispQtConfigpageEditlineGroupbox::DispQtConfigpageEditlineGroupbox(MainWindow *main_window, QWidget *parent, QString box_title, const struct configpage_editline_s *editline_config, int nb_config) : QGroupBox(box_title, parent)
{
	this->editline_group = new DispQtConfigpageEditlineGroup(main_window, parent, editline_config, nb_config);
	this->setLayout(this->editline_group);
}

DispQtConfigpageEditlineGroupbox::~DispQtConfigpageEditlineGroupbox()
{
	if(this->editline_group)
		delete this->editline_group;
	this->close();
}

void DispQtConfigpageEditlineGroupbox::editlinegroupbox_applyall(void)
{
	if(this->editline_group)
		this->editline_group->editlinegroup_applyall();
}

//--------------------------------------------------------------------------------------
DispQtConfigpageComboboxGroup::DispQtConfigpageComboboxGroup(MainWindow *main_window, QWidget *parent, const struct configpage_comboboxline_s *p_comboboxline_configs, unsigned int nb_configs) : QGridLayout(parent)
{
	unsigned int selected_item;
	this->comboboxgroup_config = p_comboboxline_configs;
	this->nb_of_comboboxconfig = nb_configs;

	this->combobox = new QComboBox *[nb_configs];
	if(!this->combobox)
		return;

	this->setContentsMargins(3,0,3,3);
	this->setSpacing(2);

	for(int c = 0; c < nb_configs; c++, p_comboboxline_configs++) {
		QLabel *label = new QLabel(QString::fromUtf8(p_comboboxline_configs->title));
		label->setToolTip(QString::fromUtf8(p_comboboxline_configs->tooltip));
		label->setToolTipDuration(DISPQT_CONFIG_TOOLTIP_DURATION);
		this->addWidget(label, c, 0);
		this->combobox[c] = new QComboBox;
		for(int i = 0; i < p_comboboxline_configs->nb_values; i++) {
			this->combobox[c]->addItem(QString::fromUtf8(p_comboboxline_configs->data_description[i]));
			if(p_comboboxline_configs->datatype & ARG_NUM) {
				if(p_comboboxline_configs->data_var && (*((unsigned long *)p_comboboxline_configs->data_var) == pds_atol((char *)p_comboboxline_configs->data_values[i])))
					selected_item = i;
			} else if(p_comboboxline_configs->datatype & ARG_CHAR) {
				char strtmp[MPXINI_MAX_CHARDATA_LEN];
				pds_strncpy(strtmp, *((char **)p_comboboxline_configs->data_var), MPXINI_MAX_CHARDATA_LEN);
				strtmp[MPXINI_MAX_CHARDATA_LEN - 1] = 0;
				pds_strcutspc(strtmp);
				mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "char \"%s\" \"%s\"", strtmp, (char *)p_comboboxline_configs->data_values[i]);
				if(pds_stricmp(strtmp, (char *)p_comboboxline_configs->data_values[i]) == 0)
					selected_item = i;
			}
		}
		this->combobox[c]->setCurrentIndex(selected_item);
		this->addWidget(this->combobox[c], c, 1);
	}
}

DispQtConfigpageComboboxGroup::~DispQtConfigpageComboboxGroup()
{
	if(this->combobox)
		for(int c = 0; c < this->nb_of_comboboxconfig; c++)
			delete this->combobox[c];
}

void DispQtConfigpageComboboxGroup::comboboxgroup_applyall(void)
{
	struct configpage_comboboxline_s *comboboxline_config = (struct configpage_comboboxline_s *)this->comboboxgroup_config;
	for(int c = 0; c < this->nb_of_comboboxconfig; c++, comboboxline_config++) {
		int selected_item = this->combobox[c]->currentIndex();
		if(selected_item >= comboboxline_config->nb_values || !comboboxline_config->data_var || !comboboxline_config->data_values[selected_item])
			return;
		if(comboboxline_config->datatype & ARG_NUM)
			*((unsigned long *)comboboxline_config->data_var) = pds_atol((char *)comboboxline_config->data_values[selected_item]);
		else if(comboboxline_config->datatype & ARG_CHAR) {
			if(comboboxline_config->datatype & ARG_POINTER)
				*(char **)comboboxline_config->data_var = (char *)comboboxline_config->data_values[selected_item];
			else {
				pds_strncpy((char *)comboboxline_config->data_var, (char *)comboboxline_config->data_values[selected_item], MPXINI_MAX_CHARDATA_LEN);
				((char *)comboboxline_config->data_var)[MPXINI_MAX_CHARDATA_LEN - 1] = 0;
			}
		}
	}
}

DispQtConfigpageComboboxGroupbox::DispQtConfigpageComboboxGroupbox(MainWindow *main_window, QWidget *parent, QString title, const struct configpage_comboboxline_s *p_comboboxline_configs, unsigned int nb_configs) : QGroupBox(title, parent)
{
	this->combobox_group = new DispQtConfigpageComboboxGroup(main_window, parent, p_comboboxline_configs, nb_configs);
	this->setLayout(this->combobox_group);
}

DispQtConfigpageComboboxGroupbox::~DispQtConfigpageComboboxGroupbox()
{
	if(this->combobox_group)
		delete this->combobox_group;
	this->close();
}

void DispQtConfigpageComboboxGroupbox::comboboxgroupbox_applyall(void)
{
	if(this->combobox_group)
		this->combobox_group->comboboxgroup_applyall();
}

//======================================================================================

static struct configpage_chkbox_s mainwin_layout_normal_checkboxes[] = {
	{"Show video window (*)",     &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_VIDEO },
	{"Show seekbar",              &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_SEEKBAR },
	{"Show toolbar / buttons",    &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_TOOLBAR },
	{"Embedd AV mixer",           &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_EMBEDD_AVMIXER },
	{"Show playlist editor (*)",  &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR },
	{"Show status line",          &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_STATUSLINE },
	{"Translucent (Win7 / Aero)", &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_TRANSLUCENT },
	{"Always on top",             &mmc_config.mainwin_control, DISPQT_CONFIG_MAINWINCTRL_ALWAYS_ON_TOP },
	{" (*) cannot disable both widget, only by video control", NULL, 0 }
};

#define DISPQT_CONFIGPAGE_MAINWIN_NORMAL_CHKBOX_MAX (sizeof(mainwin_layout_normal_checkboxes) / sizeof(struct configpage_chkbox_s))

static struct configpage_chkbox_s mainwin_layout_transparent_checkboxes[] = {
	{"Hide menu",              &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_HIDE_MENU },
	{"Show video window",      &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_VIDEO },
	{"Show seekbar",           &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_SEEKBAR },
	{"Show toolbar / buttons", &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_TOOLBAR },
	{"Show playlist editor",   &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR },
	{"Show status line",       &mmc_config.transparent_control, DISPQT_CONFIG_MAINWINCTRL_SHOW_STATUSLINE },
//	{"Frameless window",       &mmc_config.transparent_control, DISPQT_CONFIG_TRANSCTRL_DESKTOPTRANS_FRAMELESS },  // doesn't work
	{"Maximize mainwin auto",  &mmc_config.transparent_control, DISPQT_CONFIG_TRANSCTRL_DESKTOPTRANS_AUTOMAXI },
	{"From transparency to fullvideo", &mmc_config.transparent_control, DISPQT_CONFIG_TRANSCTRL_EXIT_TO_FULLVIDEO },
	{"Restore at program start",&mmc_config.transparent_control, DISPQT_CONFIG_TRANSCTRL_DESKTOPTRANS_RESTORE }
};

#define DISPQT_CONFIGPAGE_MAINWIN_TRANSPARENT_CHKBOX_MAX (sizeof(mainwin_layout_transparent_checkboxes) / sizeof(struct configpage_chkbox_s))

DispQtConfigpageMainwin::DispQtConfigpageMainwin(MainWindow *main_window, QWidget *parent) : QTabWidget(parent)
{
	QWidget *mainwin_tab_widget_normal = new QWidget(this);
	QWidget *mainwin_tab_widget_transparent = new QWidget(this);
	QVBoxLayout *mainwin_tab_layout_normal = new QVBoxLayout;
	QVBoxLayout *mainwin_tab_layout_transparent = new QVBoxLayout;

	this->groupchkboxes_mainwin_normal_layout = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Main window layout / widgets", mainwin_layout_normal_checkboxes, DISPQT_CONFIGPAGE_MAINWIN_NORMAL_CHKBOX_MAX);
	this->groupchkboxes_mainwin_transparent_layout = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Main window layout in transparent desktop mode", mainwin_layout_transparent_checkboxes, DISPQT_CONFIGPAGE_MAINWIN_TRANSPARENT_CHKBOX_MAX);

	mainwin_tab_layout_normal->setContentsMargins(0,5,0,0);
	mainwin_tab_layout_normal->addWidget(this->groupchkboxes_mainwin_normal_layout);
	mainwin_tab_layout_normal->addStretch(1);
	mainwin_tab_widget_normal->setLayout(mainwin_tab_layout_normal);

	mainwin_tab_layout_transparent->setContentsMargins(0,5,0,0);
	mainwin_tab_layout_transparent->addWidget(this->groupchkboxes_mainwin_transparent_layout);
	mainwin_tab_layout_transparent->addStretch(1);
	mainwin_tab_widget_transparent->setLayout(mainwin_tab_layout_transparent);

	this->addTab(mainwin_tab_widget_normal, "Normal");
	this->addTab(mainwin_tab_widget_transparent, "Transparent");
	this->setDocumentMode(true);
}

void DispQtConfigpageMainwin::configpage_mainwin_applyall(void)
{
	this->groupchkboxes_mainwin_normal_layout->checkboxgroup_applyall();
	this->groupchkboxes_mainwin_transparent_layout->checkboxgroup_applyall();
}

//--------------------------------------------------------------------------------------
static struct configpage_chkbox_s display_editor_checkboxes[] = {
	{"Horizontal layout",     &desktopmode, DTM_EDIT_VERTICAL, "Vertical playlist editor border" },
	{"Show left panel",       &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_SHOWPANEL_LEFT, "Show left/up panel (side 0)" },
	{"Show right panel",      &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_SHOWPANEL_RIGHT, "Show right/down panel (side 1)" },
	{"Show drive control bar",&mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_SHOW_DRIVELINE, "Drive select, drive info, directory navigation buttons" },
	{"Show drives in dirs",   &desktopmode, DTM_EDIT_DRIVES, "Add drive labels and names to the\ntop of directories in the playlist editor\n(switch to another drive like subdir)\n(requires ctrl-'R' or dir change to take effect)" },
	{"Show all files in dirs",&desktopmode, DTM_EDIT_ALLFILES, "Show all files (not only the supported a/v files)\nin the current player/commander mode\n(requires ctrl-'R' or directory change)"},
	{"File infos in tooltip", &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_TOOLTIP_FILEINFOS, "Show file infos in tooltip by mouse cursor\nover playlist editor entries" },
	{"Manual column widths",  &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_COLUMNS_MANUALSIZE, "Disable auto width correction for editor columns" },
	{"Disable scrollbar",     &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_DISABLE_SCROLLBAR, "Never show editor list scrollbar" },
	{"Shift entry by mouse",  &desktopmode, DTM_EDIT_MOUSESONGSHIFT, "Drag and move playlist entries by mouse\n(else move complete list)" }
};

#define DISPQT_CONFIGPAGE_DISPLAY_EDITOR_CHKBOX_MAX (sizeof(display_editor_checkboxes) / sizeof(struct configpage_chkbox_s))

DispQtConfigpageDisplay::DispQtConfigpageDisplay(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	this->main_window = main_window;
	this->groupchkboxes_editor = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Editor settings", display_editor_checkboxes, DISPQT_CONFIGPAGE_DISPLAY_EDITOR_CHKBOX_MAX);

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(0);
	mainLayout->addWidget(this->groupchkboxes_editor);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpageDisplay::configpage_display_applyall(void)
{
	unsigned long editor_flags_old = this->main_window->gui_config->editor_flags;
	unsigned int desktopmod_old = desktopmode;
	this->groupchkboxes_editor->checkboxgroup_applyall();
	if(displaymode&DISP_DESKTOPMODEC)
		desktopmod_commander=desktopmode;
	else
		desktopmod_player=desktopmode;
	if( ((desktopmode & DTM_EDIT_VERTICAL) != (desktopmod_old & DTM_EDIT_VERTICAL))
	 || ((this->main_window->gui_config->editor_flags &DISPQT_CONFIG_EDITORFLAG_SHOWPANELS_ALL) != (editor_flags_old & DISPQT_CONFIG_EDITORFLAG_SHOWPANELS_ALL))
	 || ((this->main_window->gui_config->editor_flags &DISPQT_CONFIG_EDITORFLAG_SHOW_DRIVELINE) != (editor_flags_old & DISPQT_CONFIG_EDITORFLAG_SHOW_DRIVELINE)) )
		funcbit_enable(refdisp, RDT_TABINFOS);
	if((this->main_window->gui_config->editor_flags &DISPQT_CONFIG_EDITORFLAG_TOOLTIP_FILEINFOS) != (editor_flags_old & DISPQT_CONFIG_EDITORFLAG_TOOLTIP_FILEINFOS))
		funcbit_enable(refdisp, (RDT_EDITOR | RDT_RESET_EDIT));
}

//--------------------------------------------------------------------------------------
DispQtConfigpageColorCfgline::DispQtConfigpageColorCfgline(QWidget *parent, QString line_text, char **colortext_ptr) : QWidget(parent)
{
	this->color_text_ptr = colortext_ptr;
	this->label_colorname = new QLabel;
	this->label_colorbar = new QLabel;

	this->label_colorname->setText(line_text);
	this->label_colorbar->setMinimumWidth(60);
	if(*colortext_ptr) {
		QString qs = QString::fromUtf8(*colortext_ptr);
		this->color_selected.setNamedColor(qs);
		this->label_colorbar->setText(qs);
		this->label_colorbar->setPalette(QPalette(this->color_selected));
	}
	int frameStyle = QFrame::Sunken | QFrame::Panel;
	this->label_colorbar->setFrameStyle(frameStyle);
	this->label_colorbar->setMinimumWidth(100);
	this->label_colorbar->setMaximumHeight(20);
	this->label_colorbar->setAutoFillBackground(true);

	QPushButton *qb = new QPushButton;
	qb->setText(">>");
	qb->setMaximumWidth(25);
	connect(qb, SIGNAL(clicked()), this, SLOT(colorcfgline_getcolor()));

	QHBoxLayout *layout = new QHBoxLayout;
	layout->addWidget(this->label_colorname, 1);
	layout->addWidget(this->label_colorbar, 0);
	layout->addWidget(qb, 0);
	layout->addStretch(0);
	layout->setMargin(0);
	layout->setSpacing(1);
	setLayout(layout);
}

void DispQtConfigpageColorCfgline::colorcfgline_getcolor()
{
	QColor qc;
	if(this->color_selected.isValid())
		qc = this->color_selected;
	else {
		QString qs = QString::fromUtf8(*this->color_text_ptr);
		if(qs.size() > 0)
			qc.setNamedColor(qs);
		else
			qc = Qt::white;
	}
	this->color_selected = QColorDialog::getColor(qc, this);
	if (!this->color_selected.isValid())
		return;
	this->label_colorbar->setText(this->color_selected.name());
	this->label_colorbar->setPalette(QPalette(this->color_selected));
	this->label_colorbar->setAutoFillBackground(true);
}

void DispQtConfigpageColorCfgline::colorcfgline_apply()
{
	if(!this->color_selected.isValid())
		return;
	QString qs = this->color_selected.name();
	QByteArray utf8 = qs.toUtf8();
	int len = utf8.size();
	if(len <= 0)
		return;
	if(*this->color_text_ptr)
		delete *this->color_text_ptr;
	*this->color_text_ptr = new char[len + 4];
	if(*this->color_text_ptr) {
		memcpy(*this->color_text_ptr, utf8.data(), len);
		(*this->color_text_ptr)[len] = 0;
	}
}

static const char *colorcfgline_names[DISPQT_COLORTEXTID_EDITOR_MAX] = { // !!! must match with dispt_colortext_editor_ids
 "Font base (not playtab)", "Background", "Background 2", "Cursor background", "Mark / selected font",
 "Currsong font (on playtab)", "Nextsong font (on playtab)", "Played font (on playtab)", "Not played font (on playtab)"
};

DispQtConfigpageColor::DispQtConfigpageColor(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	QGroupBox *colorGroup = new QGroupBox(tr("Editor colors"));
	QVBoxLayout *colorLayout = new QVBoxLayout;
	colorLayout->setMargin(3);
	colorLayout->setSpacing(5);

	for(int i = 0; i < DISPQT_COLORTEXTID_EDITOR_MAX; i++){
		this->colorcfgline[i] = new DispQtConfigpageColorCfgline(this, colorcfgline_names[i], &main_window->gui_config->color_text_name[i]);
		colorLayout->addWidget(this->colorcfgline[i]);
	}

	colorGroup->setLayout(colorLayout);

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(0);
	mainLayout->addWidget(colorGroup);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpageColor::configpage_color_applyall(void)
{
	for(int i = 0; i < DISPQT_COLORTEXTID_EDITOR_MAX; i++)
		this->colorcfgline[i]->colorcfgline_apply();
}

//-------------------------------------------------------------------------------
DispQtConfigpageFontBox::DispQtConfigpageFontBox(QWidget *parent, QString box_text, char **fonttext_ptr) : QGroupBox(parent)
{
	this->setTitle(box_text);
	this->font_text_ptr = fonttext_ptr;
    QHBoxLayout *fontbox_layout = new QHBoxLayout;
    fontbox_layout->setMargin(2);
    int frameStyle = QFrame::Sunken | QFrame::Panel;
    this->font_label = new QLabel;
    this->font_label->setFrameStyle(frameStyle);
    this->font_label->setMinimumWidth(180);
    this->font_label->setText(*fonttext_ptr);
    this->font_selected.fromString(*fonttext_ptr);
    this->font_label->setFont(this->font_selected);
    QPushButton *button_font = new QPushButton(tr("Change font"));
    fontbox_layout->addWidget(button_font, 0);
    fontbox_layout->addWidget(this->font_label, 1);
    this->setLayout(fontbox_layout);
    connect(button_font, SIGNAL(clicked()), this, SLOT(pagefontbox_getfont()));
}

void DispQtConfigpageFontBox::pagefontbox_getfont()
{
    bool ok = false;
    this->font_selected.fromString(QString::fromUtf8(*this->font_text_ptr));
    QFont font = QFontDialog::getFont(&ok, this->font_selected, this);
    if (!ok)
    	return;
    this->font_label->setText(font.toString());
    this->font_label->setFont(font);
    this->font_selected = font;
    //mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "fontbox key     : \"%s\"", qf.key().toLatin1().data());
    //mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "fontbox tostring: \"%s\"", qf.toString().toLatin1().data());
}

void DispQtConfigpageFontBox::pagefontbox_apply()
{
	if(this->font_selected.family().size() <= 0)
		return;
    QString qs = this->font_selected.toString();
    QByteArray utf8 = qs.toUtf8();
    int len = utf8.size();
    if(len <= 0)
    	return;
    if(*this->font_text_ptr)
    	delete *this->font_text_ptr;
    *this->font_text_ptr = new char[len + 4];
    if(*this->font_text_ptr) {
    	memcpy(*this->font_text_ptr, utf8.data(), len);
    	(*this->font_text_ptr)[len] = 0;
    }
}

static const char *fontbox_names[DISPQT_FONTTEXTID_MAX] = {
		"Playlist font", "Main window font", "Dialog box font", "Video subtitle font" // !!! must match with enum dispt_fonttext_ids
};

DispQtConfigpageFont::DispQtConfigpageFont(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->setMargin(0);
    for(int i = 0; i < DISPQT_FONTTEXTID_MAX; i++){
    	this->fontcfgbox[i] = new DispQtConfigpageFontBox(this, tr(fontbox_names[i]), &main_window->gui_config->font_text_name[i]);
    	mainLayout->addWidget(this->fontcfgbox[i]);
    }
    mainLayout->addStretch(1);
    setLayout(mainLayout);
}

void DispQtConfigpageFont::configpage_font_applyall(void)
{
	for(int i = 0; i < DISPQT_FONTTEXTID_MAX; i++)
	    this->fontcfgbox[i]->pagefontbox_apply();
}

//--------------------------------------------------------------------------------------
static struct configpage_spinbox_s mainwin_opacity_spinboxes[] = {
	{"Base / General", &mmc_config.mainwin_opacity_general, DISPQT_CONFIG_MAINWIN_OPACITY_GENERAL_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_GENERAL_MAX},
	{"Inactive base",  &mmc_config.mainwin_opacity_inactive, DISPQT_CONFIG_MAINWIN_OPACITY_GENERAL_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_GENERAL_MAX},
	{"Show on video",  &mmc_config.mainwin_opacity_onvideo_show, DISPQT_CONFIG_MAINWIN_OPACITY_ONVIDEO_SHOW_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_ONVIDEO_SHOW_MAX},
	{"Hide on video",  &mmc_config.mainwin_opacity_onvideo_hide, DISPQT_CONFIG_MAINWIN_OPACITY_ONVIDEO_HIDE_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_ONVIDEO_HIDE_MAX},
	{"Transparent desktop", &mmc_config.mainwin_opacity_transparent, DISPQT_CONFIG_MAINWIN_OPACITY_TRANSPARENT_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_TRANSPARENT_MAX}
};

static struct configpage_spinbox_s mainwin_opacity_time_spinboxes[] = {
	{"Fade in time", &mmc_config.mainwin_opacity_fadein_time, DISPQT_CONFIG_MAINWIN_OPACITY_FADEIN_TIMEMS_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_FADEIN_TIMEMS_MAX},
	{"Keep showing (by editkeys)", &mmc_config.mainwin_opacity_showkeep_time, DISPQT_CONFIG_MAINWIN_OPACITY_SHOWKEEP_TIMEMS_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_SHOWKEEP_TIMEMS_MAX},
	{"Fade out time", &mmc_config.mainwin_opacity_fadeout_time, DISPQT_CONFIG_MAINWIN_OPACITY_FADEOUT_TIMEMS_MIN, DISPQT_CONFIG_MAINWIN_OPACITY_FADEOUT_TIMEMS_MAX}
};

static struct configpage_chkbox_s display_editor_translucent_checkboxes[] = {
	{"Translucent in window",&mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INWINDOW, "Translucent main window in normal window mode\n(has effect only Win7 with Aero enabled)" },
	{"Translucent on video", &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_ONVIDEO, "Translucent main window over video"},
	{"Translucent inactive", &mmc_config.editor_flags, DISPQT_CONFIG_EDITORFLAG_TRANSLUCENT_INACTIVE, "Translucent main window losing focus\n(clicking to an other program in Windows)" }
};

#define DISPQT_CONFIGPAGE_MAINWIN_OPACITY_SPINBOX_MAX (sizeof(mainwin_opacity_spinboxes) / sizeof(struct configpage_spinbox_s))
#define DISPQT_CONFIGPAGE_MAINWIN_OPACITY_TIME_SPINBOX_MAX (sizeof(mainwin_opacity_time_spinboxes) / sizeof(struct configpage_spinbox_s))
#define DISPQT_CONFIGPAGE_DISPLAY_ETCHKBOX_MAX (sizeof(display_editor_translucent_checkboxes) / sizeof(struct configpage_chkbox_s))

DispQtConfigpageOpacity::DispQtConfigpageOpacity(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	this->groupspinboxes_mainwin_opacity = new DispQtConfigpageSpinboxGroupbox(main_window, this, "Main window opacity / transparency levels (%)", mainwin_opacity_spinboxes, DISPQT_CONFIGPAGE_MAINWIN_OPACITY_SPINBOX_MAX);
	this->groupspinboxes_mainwin_opacity_time = new DispQtConfigpageSpinboxGroupbox(main_window, this, "Main window transparency on video timeout (msec)", mainwin_opacity_time_spinboxes, DISPQT_CONFIGPAGE_MAINWIN_OPACITY_TIME_SPINBOX_MAX);
	this->groupchkboxes_editor_translucent = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Editor translucent settings", display_editor_translucent_checkboxes, DISPQT_CONFIGPAGE_DISPLAY_ETCHKBOX_MAX);

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(0);
	mainLayout->addWidget(this->groupspinboxes_mainwin_opacity);
	mainLayout->addWidget(this->groupspinboxes_mainwin_opacity_time);
	mainLayout->addWidget(this->groupchkboxes_editor_translucent);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpageOpacity::configpage_opacity_applyall(void)
{
	this->groupspinboxes_mainwin_opacity->spinboxgroup_applyall();
	this->groupspinboxes_mainwin_opacity_time->spinboxgroup_applyall();
	this->groupchkboxes_editor_translucent->checkboxgroup_applyall();
}

//----------------------------------------------------------------------------------------------
static struct configpage_chkbox_s playlist_playlistcontrol_checkboxes[] = {
	{"Disable playlist warnings", &mpxplay_playlistcontrol, MPXPLAY_PLAYLISTC_NOLISTWARNINGS, "Disable playlist related warning dialogs" },
	{"Open input songs in its dirs", &mpxplay_playlistcontrol, MPXPLAY_PLAYLISTC_DIRBROWSER2, "Command-line input files (songs,lists) are opened in their directory,\nnot loaded as a playlist (equal to -db2 option)" },
	{"Use local ID3 lists", &mpxplay_playlistcontrol, MPXPLAY_PLAYLISTC_ID3LIST_LOCAL, "Artist:Title infos are loaded from a local ID3 info list too,\nnamed !FILES by default (equal to -il option)" },
	{"Non-filtered ID3 search", &mpxplay_playlistcontrol, MPXPLAY_PLAYLISTC_NONFILT_SEARCH, "Using ID3-search function (alt-letters), non-matching entries\nare keeped in the list (but skiped at up/down arrows)" }
};

static struct configpage_chkbox_s playlist_loadid3tag_checkboxes[] = {
	{"Use cue/extm3u/id3list", &loadid3tag, ID3LOADMODE_LIST, "ID3 tags are loaded from extended (with artist:title info) playlists (too)" },
	{"Load tags from audiofiles", &loadid3tag, ID3LOADMODE_FILE, "ID3 tags are loaded from audio files (too)" },
	{"Create ID3 from filename", &loadid3tag, ID3LOADMODE_CLFN, "ID3 tags are created from proper (lfn) filenames\nand parent directory names (too)\nArtist - Album (Date) \\ NN. [Artist -] Title.mp3"},
	{"Prefer playlist-tags", &loadid3tag, ID3LOADMODE_PREFER_LIST, "Prefer extended list and lfn based tags\nagainst audiofile tags.\nTitle info from http is still updated,\nartist (channel name) is not." },
	{"Load from lowlevel devices", &loadid3tag, ID3LOADMODE_LOWLEVEL, "Load Artist (channel) and Title infos\nfrom the low level devices (http,ice)" }
};

static const char *config_playlist_preloadinfo_data_values[] = {"0","1","2","3","4"};
static const char *config_playlist_preloadinfo_data_description[] = {"Don't preload meta infos (-inl)", "Load at program start", "Load parallel with playing (-ipl)", "Load only displayed entries (-idl)", "Load highlighted (under cursor) (-ihl)"};

static struct configpage_comboboxline_s playlist_preloadinfo_combobox_lines[] = {
{
	"Preload mode: ", ARG_NUM, (void *)&preloadinfo, (sizeof(config_playlist_preloadinfo_data_values) / sizeof(char *)),
	&config_playlist_preloadinfo_data_values[0], &config_playlist_preloadinfo_data_description[0], "Playlist entry informations load timing\n(requires ctrl-'R' after change)"
} };

static struct configpage_chkbox_s playlist_preloadinfo_checkboxes[] = {
	{"Preload from slow devices too (ftp,http)", &loadid3tag, ID3LOADMODE_SLOWACCESS, "By default, ftp and http entries are not pre-checked,\nmedia informations are loaded at playing only"}
};

static struct configpage_chkbox_s playlist_sortcontrol_checkboxes[] = {
	{"Sort dirs/lists too by date or name", &mpxplay_sortcontrol, PLAYLIST_SORTCONTROL_CMD_DIR, "If enabled, directories and playlists are also sorted\nif Artist, Filename, Ext or Filedate order is selected\n(else sorted only by filename in ascending order)" },
	{"Disable auto descending order (len,size,date)", &mpxplay_sortcontrol, PLAYLIST_SORTCONTROL_NOAUTODESC, "By default, song-len, filesize and filedate\nhave initially descending order when selected" },
	{"Don't keep playlists on top of dir (needs ctrl-'R')", &mpxplay_sortcontrol, PLAYLIST_SORTCONTROL_NOLISTTOP, "By default, playlist filenames are\nalways placed at the top of directory" }
};

#define DISPQT_CONFIGPAGE_PLAYLIST_PLAYLISTCONTROL_CHKBOX_MAX (sizeof(playlist_playlistcontrol_checkboxes) / sizeof(struct configpage_chkbox_s))
#define DISPQT_CONFIGPAGE_PLAYLIST_LOADID3TAG_CHKBOX_MAX (sizeof(playlist_loadid3tag_checkboxes) / sizeof(struct configpage_chkbox_s))
#define DISPQT_CONFIGPAGE_PLAYLIST_PRELOADINFO_COMBOX_MAX (sizeof(playlist_preloadinfo_combobox_lines) / sizeof(struct configpage_comboboxline_s))
#define DISPQT_CONFIGPAGE_PLAYLIST_PRELOADINFO_CHKBOX_MAX (sizeof(playlist_preloadinfo_checkboxes) / sizeof(struct configpage_chkbox_s))
#define DISPQT_CONFIGPAGE_PLAYLIST_SORTCONTROL_CHKBOX_MAX (sizeof(playlist_sortcontrol_checkboxes) / sizeof(struct configpage_chkbox_s))

DispQtConfigpagePlayList::DispQtConfigpagePlayList(MainWindow *main_window, QWidget *parent) : QWidget(parent)
{
	QVBoxLayout *mainLayout = new QVBoxLayout;
	QWidget *widget_control_loadid3 = new QWidget(this);
	QHBoxLayout *layout_control_loadid3 = new QHBoxLayout;
	QGroupBox *groupbox_preloadinfo = new QGroupBox;
	QVBoxLayout *layout_preloadinfo = new QVBoxLayout;
	QWidget *widget_preloadinfo_comboxes = new QWidget(this);
	QWidget *widget_preloadinfo_checkboxes = new QWidget(this);

	this->groupchkboxes_playlistcontrol = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Playlist control", playlist_playlistcontrol_checkboxes, DISPQT_CONFIGPAGE_PLAYLIST_PLAYLISTCONTROL_CHKBOX_MAX);
	this->groupchkboxes_loadid3tag = new DispQtConfigpageCheckboxGroupbox(main_window, this, "ID3 load types", playlist_loadid3tag_checkboxes, DISPQT_CONFIGPAGE_PLAYLIST_LOADID3TAG_CHKBOX_MAX);
	this->groupcomboxes_preloadinfo = new DispQtConfigpageComboboxGroup(main_window, this, &playlist_preloadinfo_combobox_lines[0], DISPQT_CONFIGPAGE_PLAYLIST_PRELOADINFO_COMBOX_MAX);
	this->groupchkboxes_preloadinfo = new DispQtConfigpageCheckboxGroup(main_window, this, playlist_preloadinfo_checkboxes, DISPQT_CONFIGPAGE_PLAYLIST_PRELOADINFO_CHKBOX_MAX);
	this->groupchkboxes_sortcontrol = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Sort control", playlist_sortcontrol_checkboxes, DISPQT_CONFIGPAGE_PLAYLIST_SORTCONTROL_CHKBOX_MAX);

	layout_control_loadid3->setMargin(0);
	layout_control_loadid3->addWidget(this->groupchkboxes_playlistcontrol);
	layout_control_loadid3->addWidget(this->groupchkboxes_loadid3tag);
	layout_control_loadid3->addStretch(1);
	widget_control_loadid3->setLayout(layout_control_loadid3);

	groupbox_preloadinfo->setTitle("ID3 / metadata preload mode");
	layout_preloadinfo->setMargin(0);
	layout_preloadinfo->setSpacing(2);
	layout_preloadinfo->addStretch(1);
	widget_preloadinfo_comboxes->setLayout(this->groupcomboxes_preloadinfo);
	layout_preloadinfo->addWidget(widget_preloadinfo_comboxes);
	widget_preloadinfo_checkboxes->setLayout(this->groupchkboxes_preloadinfo);
	layout_preloadinfo->addWidget(widget_preloadinfo_checkboxes);
	groupbox_preloadinfo->setLayout(layout_preloadinfo);

	mainLayout->setMargin(0);
	mainLayout->addWidget(widget_control_loadid3);
	mainLayout->addWidget(groupbox_preloadinfo);
	mainLayout->addWidget(this->groupchkboxes_sortcontrol);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpagePlayList::configpage_playlist_applyall(void)
{
	this->groupchkboxes_playlistcontrol->checkboxgroup_applyall();
	mpxplay_playlistcontrol_mpxpini = mpxplay_playlistcontrol;
	this->groupchkboxes_loadid3tag->checkboxgroup_applyall();
	this->groupcomboxes_preloadinfo->comboboxgroup_applyall();
	this->groupchkboxes_preloadinfo->checkboxgroup_applyall();
	loadid3tag_mpxpini = loadid3tag;
	preloadinfo_mpxpini = preloadinfo;
	this->groupchkboxes_sortcontrol->checkboxgroup_applyall();
}

//----------------------------------------------------------------------------------------------
static struct configpage_chkbox_s config_play_control_checkboxes[] = {
	{"Play random/shuffle",    &playrand, 1, "Play media files randomly from playlist\n(skip forward = random, skip back = step on randomly played files backward)" },
	{"Replay/repeat song",     &playreplay, REPLAY_SONG, "Repeat/replay current song only (endlessly)" },
	{"Replay/repeat list",     &playreplay, REPLAY_LIST, "Repeat/replay all playlist entries"},
	{"Exit at end of list",    &playcontrol, PLAYC_EXITENDLIST, "Except if directory has no media files" },
	{"Pause before each song", &playcontrol, PLAYC_PAUSEALL, "Auto pause at each song" },
	{"Pause at next song",     &playcontrol, PLAYC_PAUSENEXT, "Pause playing at the begin of next song"},
	{"Disable auto program skip", &playcontrol, PLAYC_NOAUTOPRGSKIP, "Don't skip (DVB/TS) program automatically\n(if the current/selected program lost)"},
	{"Highlight scan from half",  &playcontrol, PLAYC_HSSTARTPOSHALF, "Start position of the highlight scan is\nthe half/center position of the file.\nThis option is usefull for video files.\n(\"Start timepos\" is ignored in this case)"}
};

#define DISPQT_CONFIGPAGE_PLAY_CONTROL_CHKBOX_MAX (sizeof(config_play_control_checkboxes) / sizeof(struct configpage_chkbox_s))

static struct configpage_chkbox_s config_play_startup_checkboxes[] = {
	{"Save play position",     &su_startupenabled, MPXPLAY_STARTUP_FLAG_SAVE, "Save play position at exit" },
	{"Restore play position",  &su_startupenabled, MPXPLAY_STARTUP_FLAG_LOAD, "Restore play positon at program start" },
	{"Restore all tabs/sides", &su_startupenabled, MPXPLAY_STARTUP_FLAG_2SIDES },
	{"Start playing auto",     &su_startupenabled, MPXPLAY_STARTUP_FLAG_RESDIR, "Start playing audio at program start" },
	{"Save at every new song", &su_startupenabled, MPXPLAY_STARTUP_FLAG_NEWFILE, "Save play position at every track / song change\n(requires program restart to take effect)" }
};

#define DISPQT_CONFIGPAGE_PLAY_STARTUP_CHKBOX_MAX (sizeof(config_play_startup_checkboxes) / sizeof(struct configpage_chkbox_s))

static struct configpage_editline_s config_play_hilitescan_editlines[] = {
	{"Start timepos", &mpxplay_highlitescan_starttime[0], sizeof(mpxplay_highlitescan_starttime), "Song start position of hi-lite scan in MM:SS\n(note: you cannot set zero value for this,\nbut you can use 00:00.01 setting)"},
	{"Duration", &mpxplay_highlitescan_timecount[0], sizeof(mpxplay_highlitescan_timecount), "Duration of hi-lite scan at each song in MM:SS\n(note: you cannot set zero value for this,\nminimum 00:01)"}
};

#define DISPQT_CONFIGPAGE_PLAY_HILITESCAN_EDITLINE_MAX (sizeof(config_play_hilitescan_editlines) / sizeof(struct configpage_editline_s))

DispQtConfigpagePlayControl::DispQtConfigpagePlayControl(MainWindow *main_window, QWidget *parent)
{
	QWidget *widget_playcontrol = new QWidget(this);
	QWidget *widget_startup_hs = new QWidget(this);
	QVBoxLayout *mainLayout = new QVBoxLayout;
	QHBoxLayout *layout_control = new QHBoxLayout;
	QVBoxLayout *layout_startup_hs = new QVBoxLayout;

	this->groupchkboxes_playcontrol = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Play control", config_play_control_checkboxes, DISPQT_CONFIGPAGE_PLAY_CONTROL_CHKBOX_MAX);
	this->groupchkboxes_startup = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Startup control", config_play_startup_checkboxes, DISPQT_CONFIGPAGE_PLAY_STARTUP_CHKBOX_MAX);
	this->groupeditlines_hilitescan = new DispQtConfigpageEditlineGroupbox(main_window, this, "Highlight scan", config_play_hilitescan_editlines, DISPQT_CONFIGPAGE_PLAY_HILITESCAN_EDITLINE_MAX);

	layout_startup_hs->setMargin(0);
	layout_startup_hs->addWidget(this->groupchkboxes_startup);
	layout_startup_hs->addWidget(this->groupeditlines_hilitescan);
	layout_startup_hs->addStretch(1);
	widget_startup_hs->setLayout(layout_startup_hs);

	layout_control->setMargin(0);
	layout_control->addWidget(this->groupchkboxes_playcontrol);
	layout_control->addWidget(widget_startup_hs);
	layout_control->addStretch(1);
	widget_playcontrol->setLayout(layout_control);

	mainLayout->setMargin(0);
	mainLayout->addWidget(widget_playcontrol);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpagePlayControl::configpage_playcontrol_applyall(void)
{
	this->groupchkboxes_playcontrol->checkboxgroup_applyall();
	this->groupchkboxes_startup->checkboxgroup_applyall();
	this->groupeditlines_hilitescan->editlinegroupbox_applyall();
}

//----------------------------------------------------------------------------------------------
static struct configpage_chkbox_s config_program_control_checkboxes[] = {
	{"Confirm exit (at ESC and F10)", &mpxplay_programcontrol, MPXPLAY_PROGRAMC_CONFIRMEXIT, "Show a confirm dialog/window at exit" },
	{"Shutdown system at exit !",     &mpxplay_programcontrol, MPXPLAY_PROGRAMC_SHUTDOWNATX, "Switch off machine at exit\n(except exiting with F10 key)"},
	{"Extended filetype detection",   &mpxplay_programcontrol, MPXPLAY_PROGRAMC_AUTODETECTALWAYS, "By default, file types are detected by extension only.\nThis option helps if the file format doesn't match with the extension." },
	{"Call system app for unknown",   &mpxplay_programcontrol, MPXPLAY_PROGRAMC_SYSTEMAPPOPEN_UNKNOWN, "Call the default system application for the unknown filetypes\n(like doc or pdf files), at pressing the enter key." },
	{"Call system app for all files", &mpxplay_programcontrol, MPXPLAY_PROGRAMC_SYSTEMAPPOPEN_ALLFILES, "Call the default system application for all filetypes at pressing the enter key.\nInside A/V playing still can be controlled by ctrl-enter and skip keys." }
#ifdef MPXPLAY_USE_SMP
    ,{"Disable multi CPU core usage",  &mpxplay_programcontrol, MPXPLAY_PROGRAMC_DISABLE_SMP, "Enabling this switch, all threads will run on the same (1st) CPU core,\nelse only Mpxplay's threads (main timed functions and decoder thread)\nrun on the same core (Qt GUI and video playing are separated).\n(requires program restart to take effect)" }
#endif
	,{"Separated read thread (TSR mode)", &intsoundconfig, INTSOUND_TSR, "The file reading thread is separated from the other (main cycle) functions.\nThis option is for testing purposes only.\n(requires program restart to take effect)" }
};

static struct configpage_editline_s config_program_extrafiletypes_editline[] = {
    {"File extension list", &mpxplay_extrafiletypes_config[0], sizeof(mpxplay_extrafiletypes_config), "Loaded / displayed extra file types in player mode\nExtension list is separated by ',' ( MP?,EXT2,EXT3,ETC* ) (wildcards are supported)\n(requires ctrl-'R' or dir change and \"Extended filetype detection\" to take effect)"}
};

static char config_program_executetime_strtmp_startpos[16], config_program_executetime_strtmp_duration[16], config_program_executetime_strtmp_exittime[16];

static struct configpage_editline_s config_program_executetime_editlines[] = {
	{"Playstart timepos", &config_program_executetime_strtmp_startpos[0], sizeof(config_program_executetime_strtmp_startpos), "Start playing at HH:MM:SS"},
	{"Duration", &config_program_executetime_strtmp_duration[0], sizeof(config_program_executetime_strtmp_duration), "Playing time-len in HH:MM:SS\n(exit from the program after 'start/current time + duration')"},
	{"Exit timepos", &config_program_executetime_strtmp_exittime[0], sizeof(config_program_executetime_strtmp_exittime), "Exit from the program at HH:MM:SS\nIf Duration and Exit timepos are also set,\nthen the earlier (less) matters."}
};

#define DISPQT_CONFIGPAGE_PROGRAM_CONTROL_CHKBOX_MAX (sizeof(config_program_control_checkboxes) / sizeof(struct configpage_chkbox_s))
#define DISPQT_CONFIGPAGE_PROGRAM_EXECUTETIME_EDITLINE_MAX (sizeof(config_program_executetime_editlines) / sizeof(struct configpage_editline_s))
#define DISPQT_CONFIGPAGE_EXTRAFILETYPES_EDITLINE_MAX (sizeof(config_program_extrafiletypes_editline) / sizeof(struct configpage_editline_s))

DispQtConfigpageProgram::DispQtConfigpageProgram(MainWindow *main_window, QWidget *parent)
{
	unsigned long hextime;

	mpxplay_playtimestart+= mpxplay_progtimebegin;
	if(mpxplay_playtimestart > 24*3600)
		mpxplay_playtimestart -= 24*3600;
	hextime = PDS_SECONDS_TO_HEXTIME(mpxplay_playtimestart);
	pds_hextime_to_strtime(hextime, config_program_executetime_strtmp_startpos, sizeof(config_program_executetime_strtmp_startpos));

	if(mpxplay_progtimelen > mpxplay_playtimestart)
		mpxplay_progtimelen -= mpxplay_playtimestart;
	hextime = PDS_SECONDS_TO_HEXTIME(mpxplay_progtimelen);
	pds_hextime_to_strtime(hextime, config_program_executetime_strtmp_duration, sizeof(config_program_executetime_strtmp_duration));

	mpxplay_progtimeexit = mpxplay_progtimebegin + mpxplay_progtimelen;
	if(mpxplay_progtimeexit > 24*3600)
		mpxplay_progtimeexit -= 24*3600;
	hextime = PDS_SECONDS_TO_HEXTIME(mpxplay_progtimeexit);
	pds_hextime_to_strtime(hextime, config_program_executetime_strtmp_exittime, sizeof(config_program_executetime_strtmp_exittime));

	this->groupchkboxes_programcontrol = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Program control", config_program_control_checkboxes, DISPQT_CONFIGPAGE_PROGRAM_CONTROL_CHKBOX_MAX);
	this->groupeditlines_extrafiletypes = new DispQtConfigpageEditlineGroupbox(main_window, this, "Loaded extra filetypes", config_program_extrafiletypes_editline, DISPQT_CONFIGPAGE_EXTRAFILETYPES_EDITLINE_MAX);
	this->groupeditlines_executetime = new DispQtConfigpageEditlineGroupbox(main_window, this, "Program execution times", config_program_executetime_editlines, DISPQT_CONFIGPAGE_PROGRAM_EXECUTETIME_EDITLINE_MAX);

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(0);
	mainLayout->addWidget(this->groupchkboxes_programcontrol);
	mainLayout->addWidget(this->groupeditlines_extrafiletypes);
	mainLayout->addWidget(this->groupeditlines_executetime);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

void DispQtConfigpageProgram::configpage_program_applyall(void)
{
	this->groupchkboxes_programcontrol->checkboxgroup_applyall();
	this->groupeditlines_extrafiletypes->editlinegroupbox_applyall();
	this->groupeditlines_executetime->editlinegroupbox_applyall();
	mpxplay_playtimestart=pds_strtime_to_hextime(config_program_executetime_strtmp_startpos,1);
	mpxplay_playtimestart=PDS_HEXTIME_TO_SECONDS(mpxplay_playtimestart);
	mpxplay_progtimelen=pds_strtime_to_hextime(config_program_executetime_strtmp_duration,1);
	mpxplay_progtimelen=PDS_HEXTIME_TO_SECONDS(mpxplay_progtimelen);
	mpxplay_progtimeexit=pds_strtime_to_hextime(config_program_executetime_strtmp_exittime,1);
	mpxplay_progtimeexit=PDS_HEXTIME_TO_SECONDS(mpxplay_progtimeexit);
	mpxplay_control_start_progexectime();
	mpxplay_control_extrafiletypes_slice();
}

//----------------------------------------------------------------------------------------------
static unsigned long config_audio_control_swapchan, config_audio_soundcard_bits;

static struct configpage_chkbox_s config_audio_control_checkboxes[] = {
	{"Swap channels ( L <-> R )", &config_audio_control_swapchan, 1, "Reverse stereo" },
	{"Enable limiter", &MIXER_controlbits, MIXER_CONTROLBIT_LIMITER, "Fast auto volume reductor\n(to avoid audio distortions)" },
	{"High-res speed control", &MIXER_controlbits, MIXER_CONTROLBIT_SPEED1000, "x10 resolution for audio speed\n(requires program restart to take effect)" },
	{"Disable decoder tone (MPX)", &MIXER_controlbits, MIXER_CONTROLBIT_DISABLE_DECODERTONE, "Use mixer tone (high-/low-pass filters) for MPX files too" }
//	{"Disable mixer tone (non-MP3)", &MIXER_controlbits, MIXER_CONTROLBIT_DISABLE_MIXERTONE, "Don't use mixer tone" }
};

static struct configpage_spinbox_s config_audio_loudness_values_spinboxes[] = {
	{"Volume",   &MIXER_loudness_val_volume,    0, 700},
	{"Surround", &MIXER_loudness_val_surround, 10, 300},
	{"Bass",     &MIXER_loudness_val_bass,      0, 200},
	{"Treble",   &MIXER_loudness_val_treble,    0, 200}
};

#define DISPQT_CONFIGPAGE_AUDIO_CONTROL_CHKBOX_MAX (sizeof(config_audio_control_checkboxes) / sizeof(struct configpage_chkbox_s))
#define DISPQT_CONFIGPAGE_AUDIO_LOUDNESS_SPINBOX_MAX (sizeof(config_audio_loudness_values_spinboxes) / sizeof(struct configpage_spinbox_s))

#define DISPQT_CONFIGPAGE_AUDIO_OUTPUT_FLOAT32_SIGN 33
#define DISPQT_CONFIGPAGE_AUDIO_OUTMODE_CHECKFLAGS (OUTMODE_CONTROL_FILE_FLOATOUT)

static const char *config_audio_output_sndcardname_data_values[]      = {"AUTO","WDS","WIN","NUL"};
static const char *config_audio_output_sndcardname_data_description[] = {"Autodetect","Directsound","Wave mapper","Null output"};

static const char *config_audio_output_sndcardfreq_data_values[]      = {"0","8000","11025","16000","22050","32000","44100","48000","96000","192000"};
static const char *config_audio_output_sndcardfreq_data_description[] = {"As input","8000 Hz","11025 Hz","16000 Hz","22050 Hz","32000 Hz","44100 Hz","48000 Hz","96000 Hz","192000 Hz"};

static const char *config_audio_output_sndcardbits_data_values[]      = {"0","8","16","24","32","33"}; // DISPQT_CONFIGPAGE_AUDIO_OUTPUT_FLOAT32_SIGN
static const char *config_audio_output_sndcardbits_data_description[] = {"Default (16)", "8 bits", "16 bits", "24 bits", "32 bits", "32-float"};

static const char *config_audio_output_sndcardchans_data_values[]      = {"0","1","2","3","4","5","6","7","8"};
static const char *config_audio_output_sndcardchans_data_description[] = {"Default (2)", "Mono", "Stereo", "2.1 chans", "4.0 chans", "5.0 chans", "5.1 chans", "7.0 chans", "7.1 chans"};

static struct configpage_comboboxline_s config_audio_output_soundcard_combobox_group[] = { {
	"Device      ", ARG_CHAR|ARG_POINTER, (void *)&au_infos.card_selectname, (sizeof(config_audio_output_sndcardname_data_values) / sizeof(char *)),
	&config_audio_output_sndcardname_data_values[0], &config_audio_output_sndcardname_data_description[0],
	"Primary driver is Directsound\n(usually requires program restart for proper change)"
},{
	"Frequency   ", ARG_NUM, (void *)&au_infos.freq_set, (sizeof(config_audio_output_sndcardfreq_data_values) / sizeof(char *)),
	&config_audio_output_sndcardfreq_data_values[0], &config_audio_output_sndcardfreq_data_description[0],
	"By default, output frequency equals with the freq of input file\n(note: Directsound doesn't accept freqs bellow 44100Hz)"
},{
	"Bits        ", ARG_NUM, (void *)&config_audio_soundcard_bits, (sizeof(config_audio_output_sndcardbits_data_values) / sizeof(char *)),
	&config_audio_output_sndcardbits_data_values[0], &config_audio_output_sndcardbits_data_description[0],
	"Output bit (dynamic) resolution"
},{
	"Channels    ", ARG_NUM, (void *)&au_infos.chan_set, (sizeof(config_audio_output_sndcardchans_data_values) / sizeof(char *)),
	&config_audio_output_sndcardchans_data_values[0], &config_audio_output_sndcardchans_data_description[0],
	"Channel mapping of Directsound device.\nNot all devices support all channel variations\n(sound can stop in this case)"
} };

static struct configpage_chkbox_s config_audio_output_soundcard_checkboxes[] = {
	{"Double buffer", &outmode, OUTMODE_CONTROL_SNDCARD_DDMA, "Less gaps in playing with higher latency\n(32k -> 64k)" },
	{" ",NULL,0,NULL},
	{" ",NULL,0,NULL},
	{" ",NULL,0,NULL}
};

#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
static struct configpage_editline_s config_video_preferaudio_editlines[] = {
	{"Preferred audio types", &mpxplay_config_video_preffered_audiotypes[0], sizeof(mpxplay_config_video_preffered_audiotypes), "Select preferred audio format(s),\nin case of multiply streams in the container,\nseparate by ',' (like AC3,DTS,MP3,AAC,Vorbis)\nNote1: wildcards are supported (like MP?,AAC*)\nNote2: audio language setting has higher priority\n(but combined with this list)"}
};
#endif

#define DISPQT_CONFIGPAGE_AUDIO_OUTPUT_SOUNDCARD_COMBOX_MAX (sizeof(config_audio_output_soundcard_combobox_group) / sizeof(struct configpage_comboboxline_s))
#define DISPQT_CONFIGPAGE_AUDIO_OUTPUT_SOUNDCARD_CHKBOX_MAX (sizeof(config_audio_output_soundcard_checkboxes) / sizeof(struct configpage_chkbox_s))
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
#define DISPQT_CONFIGPAGE_VIDEO_PREFERAUDIOS_EDITLINE_MAX (sizeof(config_video_preferaudio_editlines) / sizeof(struct configpage_editline_s))
#endif

DispQtConfigpageAudio::DispQtConfigpageAudio(MainWindow *main_window, QWidget *parent) :  QTabWidget(parent)
{
	QWidget *audio_tab_widget_input = new QWidget(this);
	QVBoxLayout *audio_tab_layout_input = new QVBoxLayout;

#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	this->groupeditlines_audio_format_priority = new DispQtConfigpageEditlineGroupbox(main_window, this, "Audio stream priority", config_video_preferaudio_editlines, DISPQT_CONFIGPAGE_VIDEO_PREFERAUDIOS_EDITLINE_MAX);
#endif

	audio_tab_layout_input->setContentsMargins(0,5,0,0);
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	audio_tab_layout_input->addWidget(this->groupeditlines_audio_format_priority);
#endif
	audio_tab_layout_input->addStretch(1);
	audio_tab_widget_input->setLayout(audio_tab_layout_input);

	//----------------------------------------------------------------------------------------------------------------
	QWidget *audio_tab_widget_mixer = new QWidget(this);
	QWidget *widget_mixer_control = new QWidget(this);
	QVBoxLayout *audio_tab_layout_mixer = new QVBoxLayout;
	QHBoxLayout *layout_mixer_control = new QHBoxLayout;

	config_audio_control_swapchan = MIXER_var_swapchan;

	this->groupchkboxes_audio = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Audio control", config_audio_control_checkboxes, DISPQT_CONFIGPAGE_AUDIO_CONTROL_CHKBOX_MAX);
	this->groupspinboxes_loudness = new DispQtConfigpageSpinboxGroupbox(main_window, this, "Expand / Loudness", config_audio_loudness_values_spinboxes, DISPQT_CONFIGPAGE_AUDIO_LOUDNESS_SPINBOX_MAX);

	layout_mixer_control->setMargin(0);
	layout_mixer_control->addWidget(this->groupchkboxes_audio);
	layout_mixer_control->addWidget(this->groupspinboxes_loudness);
	widget_mixer_control->setLayout(layout_mixer_control);

	audio_tab_layout_mixer->setContentsMargins(0,5,0,0);
	audio_tab_layout_mixer->addWidget(widget_mixer_control);
	audio_tab_layout_mixer->addStretch(1);
	audio_tab_widget_mixer->setLayout(audio_tab_layout_mixer);

	//----------------------------------------------------------------------------------------------------------------
	QWidget *audio_tab_widget_output = new QWidget(this);
	QWidget *widget_output_control = new QWidget(this);
	QVBoxLayout *audio_tab_layout_output = new QVBoxLayout;
	QHBoxLayout *layout_output_control = new QHBoxLayout;

	if(funcbit_test(outmode, OUTMODE_CONTROL_FILE_FLOATOUT))
		config_audio_soundcard_bits = DISPQT_CONFIGPAGE_AUDIO_OUTPUT_FLOAT32_SIGN;
	else
		config_audio_soundcard_bits = au_infos.bits_set;

	this->groupcomboxes_soundcard = new DispQtConfigpageComboboxGroupbox(main_window, this, "Audio output config", &config_audio_output_soundcard_combobox_group[0], DISPQT_CONFIGPAGE_AUDIO_OUTPUT_SOUNDCARD_COMBOX_MAX);
	this->groupchkboxes_soundcard = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Audio output control", config_audio_output_soundcard_checkboxes, DISPQT_CONFIGPAGE_AUDIO_OUTPUT_SOUNDCARD_CHKBOX_MAX);

	layout_output_control->setMargin(0);
	layout_output_control->addWidget(this->groupcomboxes_soundcard);
	layout_output_control->addWidget(this->groupchkboxes_soundcard);
	widget_output_control->setLayout(layout_output_control);

	audio_tab_layout_output->setContentsMargins(0,5,0,0);
	audio_tab_layout_output->addWidget(widget_output_control);
	audio_tab_layout_output->addStretch(1);
	audio_tab_widget_output->setLayout(audio_tab_layout_output);

	//----------------------------------------------------------------------------------------------------------------
	this->addTab(audio_tab_widget_input, "Audio input");
	this->addTab(audio_tab_widget_mixer, "Audio mixer");
	this->addTab(audio_tab_widget_output,"Audio output");

	this->setDocumentMode(true);
}

void DispQtConfigpageAudio::configpage_audio_applyall(void)
{
	int freq_old = au_infos.freq_set, bits_old = au_infos.bits_set, chan_old = au_infos.chan_set;
	unsigned long mixer_controlbits_old = MIXER_controlbits, outmode_old = outmode;
	char cardname_old[16];

	pds_strncpy(cardname_old, au_infos.card_selectname, sizeof(cardname_old));
	cardname_old[sizeof(cardname_old) - 1] = 0;

	this->groupchkboxes_audio->checkboxgroup_applyall();
	this->groupspinboxes_loudness->spinboxgroup_applyall();
	this->groupcomboxes_soundcard->comboboxgroupbox_applyall();
	this->groupchkboxes_soundcard->checkboxgroup_applyall();
	this->groupeditlines_audio_format_priority->editlinegroupbox_applyall();

	mpxplay_control_extrafiletypes_slice();

	if(config_audio_control_swapchan != MIXER_var_swapchan)
		pds_pushkey(kb[76].c); // !!!

	if(config_audio_soundcard_bits == DISPQT_CONFIGPAGE_AUDIO_OUTPUT_FLOAT32_SIGN) {
		funcbit_enable(outmode, OUTMODE_CONTROL_FILE_FLOATOUT);
		au_infos.bits_set = 0;
	} else {
		funcbit_disable(outmode, OUTMODE_CONTROL_FILE_FLOATOUT);
		au_infos.bits_set = config_audio_soundcard_bits;
	}

	if(((outmode_old & OUTMODE_CONTROL_SNDCARD_DDMA) != (outmode & OUTMODE_CONTROL_SNDCARD_DDMA)) || (pds_strlicmp(cardname_old, au_infos.card_selectname) != 0)){
	    if(playcontrol & PLAYC_RUNNING)
	        funcbit_enable(playcontrol, PLAYC_STARTNEXT);
	    if(outmode & OUTMODE_CONTROL_SNDCARD_DDMA)
	    	funcbit_enable(au_infos.card_controlbits, AUINFOS_CARDCNTRLBIT_DOUBLEDMA);
	    else
	    	funcbit_disable(au_infos.card_controlbits, AUINFOS_CARDCNTRLBIT_DOUBLEDMA);
	    AU_close(&au_infos);
	    AU_init(&au_infos);
        funcbit_enable(au_infos.card_controlbits, AUINFOS_CARDCNTRLBIT_UPDATEFREQ);
        mvps.adone = ADONE_REOPEN;
	}

    if((freq_old != au_infos.freq_set) || (bits_old != au_infos.bits_set) || (chan_old != au_infos.chan_set) || ((outmode_old & DISPQT_CONFIGPAGE_AUDIO_OUTMODE_CHECKFLAGS) != (outmode & DISPQT_CONFIGPAGE_AUDIO_OUTMODE_CHECKFLAGS))){
        funcbit_enable(au_infos.card_controlbits, AUINFOS_CARDCNTRLBIT_UPDATEFREQ);
        mvps.adone = ADONE_REOPEN;
    }

    if(mixer_controlbits_old != MIXER_controlbits)
        mvps.adone = ADONE_REOPEN;

	outmode_mpxpini = outmode;
}

//----------------------------------------------------------------------------------------------
static const char *config_video_decodertype_data_values[] = {
	"0",  // MPXPLAY_VIDEOPLAYERTYPE_NONE
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	"1",  // MPXPLAY_VIDEOPLAYERTYPE_FFMPEG
#endif
#ifdef MPXPLAY_LINK_QTMEDIA
	"5",  // MPXPLAY_VIDEOPLAYERTYPE_QTMEDIA
#endif
#ifdef MPXPLAY_LINK_QTAV
	"9"   // MPXPLAY_VIDEOPLAYERTYPE_QTAV
#endif
};

static const char *config_video_decodertype_description[] = {
	"None (audio only)",
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	"FFMpeg (internal)",
#endif
#ifdef MPXPLAY_LINK_QTMEDIA
	"QtMedia (DShow)",
#endif
#ifdef MPXPLAY_LINK_QTAV
	"QtAV (test)"
#endif
};

//-------
static const char *config_video_renderertype_data_values[] = {
	"0",  // DISPQT_VIDEORENDERTYPE_WIDGET
#ifdef MPXPLAY_WIN32
//	"1",  // DISPQT_VIDEORENDERTYPE_EVR
#endif
};

static const char *config_video_renderertype_description[] = {
	"Widget (Qt/OpenGL)",
#ifdef MPXPLAY_WIN32
//	"Windows EVR",
#endif
};

//-------
static const char *config_video_windowedartype_data_values[] = {
	"0",  // DISPQT_VIDEOWINDOWEDARTYPE_EQFULLSCREEN
	"1",  // DISPQT_VIDEOWINDOWEDARTYPE_VIDEO
	"2",  // DISPQT_VIDEOWINDOWEDARTYPE_FILL
};

static const char *config_video_windowedartype_description[] = {
	"Equal to fullscreen setting",
	"Use the video aspect ratio",
	"Fill window (no aspect ratio)"
};

#if 0
//-------
static const char *config_video_audiovisualizationtype_data_values[] = {
	"0",  // DISPQT_AUDIOVISUALIZATIONTYPE_NONE
//	"1",  // DISPQT_AUDIOVISUALIZATIONTYPE_SPECTRUMANALIZER
};

static const char *config_video_audiovisualizationtype_description[] = {
	"None (blank video window)",
//	"Spectrum analizer",
};
#endif

//-------
static struct configpage_comboboxline_s config_video_decoder_config_combobox_group[] = {
{
	"Decoder type: ", ARG_NUM, (void *)&mmc_config.selected_videoplayer_type, (sizeof(config_video_decodertype_data_values) / sizeof(char *)),
	&config_video_decodertype_data_values[0], &config_video_decodertype_description[0],
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	"FFMpeg means built-in decoders (no external codec required)"
#endif
#if defined(MPXPLAY_LINK_ORIGINAL_FFMPEG) && defined(MPXPLAY_LINK_QTMEDIA)
	",\n"
#endif
#ifdef MPXPLAY_LINK_QTMEDIA
	"QtMedia requires Windows DirectShow filters and decoders (like Haali Media splitter and FFDShow)"
#endif
#if defined(MPXPLAY_LINK_ORIGINAL_FFMPEG) && defined(MPXPLAY_LINK_QTMEDIA)
	"\n(for correct change it usually requires program restart)"
#endif
},
{
	"Renderer type: ", ARG_NUM, (void *)&mmc_config.video_renderer_type, (sizeof(config_video_renderertype_data_values) / sizeof(char *)),
	&config_video_renderertype_data_values[0], &config_video_renderertype_description[0],
	"Widget renderer is an sw-synchronised video output, using a simle QWidget"
#ifdef MPXPLAY_WIN32
//	"\nEnhanced video renderer gives a gapless, hw based picture displaying"
#endif
},
{
	"Windowed aspect ratio: ", ARG_NUM, (void *)&mmc_config.video_windowed_ar_type, (sizeof(config_video_windowedartype_data_values) / sizeof(char *)),
	&config_video_windowedartype_data_values[0], &config_video_windowedartype_description[0],
	"Ascpect ratio in Windowed (non-fullscreen) mode\n"
	"can follow the AR setting of fullscreen mode\n"
	"(configured in the video surface context menu)\n"
	"or uses the video AR, or fully fills the window"
}
#if 0 // not implemented yet
,
{
	"Audiovisualization type: ", ARG_NUM, (void *)&mmc_config.video_audiovisualization_type, (sizeof(config_video_audiovisualizationtype_data_values) / sizeof(char *)),
	&config_video_audiovisualizationtype_data_values[0], &config_video_audiovisualizationtype_description[0],
	"Video window effect at audio playing"
}
#endif
};

#define DISPQT_CONFIGPAGE_VIDEO_DECODER_SELECT_COMBOX_MAX (sizeof(config_video_decoder_config_combobox_group) / sizeof(struct configpage_comboboxline_s))

static struct configpage_chkbox_s config_video_surface_control_checkboxes[] = {
	{"Enable bottom control bar",       &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_ENABLE_CONTROLBAR, "Popup bottom control bar by mouse pointer" },
	{"Show main window on video",       &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_SHOW_MAINWIN_ON_VIDEO, "Show main MMC window over the video surface\n(popup by mouse pointer or editkeys)" },
	{"Auto hide main window on video",  &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_AUTO_HIDE_MAINWIN, "Hide main window over video with fade-out\nafter the configured time-out" },
	{"Popup main window by editkeys",   &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_POPUP_MAINWIN_BY_KEYS, "Show main window over video,\nif an editor key is pressed (like up/down arrows)" },
	{"Fullscreen video at play-start",  &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_PLAYSTART_FULLSCREEN, "Switch to fullscreen video mode,\nstarting the video playing with the enter key" },
	{"Always set fullscreen to videos", &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_ALWAYS_FULLSCREEN, "Always switch to fullscreen video, when a new video file starts\n(else only pressing enter key)" },
	{"Exit fullscreen at play-stop",    &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_EXIT_FULLSCREEN_AT_STOP, "Exit from fullscreen video when playing has finished" },
	{"Pause at ESC from fullscreen",    &mmc_config.video_control, DISPQT_CONFIG_VIDEOCTRL_FULLSCREEN_ESC_PAUSE, "Pressing ESC key in fullscreen video mode,\nthe playing pauses"}
};

#define DISPQT_CONFIGPAGE_VIDEO_CONTROL_CHKBOX_MAX (sizeof(config_video_surface_control_checkboxes) / sizeof(struct configpage_chkbox_s))

#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
static struct configpage_editline_s config_video_language_editlines[] = {
	{"Audio stream language", &mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_AUDIO][0], sizeof(mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_AUDIO]), "Select preferred audio stream language\nby a 2-3 chars language code, like ENG or HUN"},
	{"Subtitle language",     &mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_SUBTITLE][0], sizeof(mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_SUBTITLE]), "Select preferred subtitle language\nby a 2-3 chars language code, like ENG or HUN\nNote: if preferred audio stream has found\nand audio language equals with subtitle,\nonly a forced subtitle is used automatically"},
	{"Video stream language", &mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_VIDEO][0], sizeof(mpxplay_config_video_preferred_language[MPXPLAY_STREAMTYPEINDEX_VIDEO]), "Select preferred video stream\nby a 2-3 chars language code, like ENG or HUN (can be empty)"}
};
#define DISPQT_CONFIGPAGE_VIDEO_LANGUAGES_EDITLINE_MAX (sizeof(config_video_language_editlines) / sizeof(struct configpage_editline_s))
#endif

#ifdef MPXPLAY_LINK_DXVA
static struct configpage_chkbox_s config_video_player_control_checkboxes[] = {
	{"Enable HW (DXVA) decoding",  &mmc_config.selected_videoplayer_control, MPXPLAY_CONFIG_VIDEOPLAYERCONTROL_USEHWDECODING,  "Enable HW (DXVA) decoding for MPEG2, H264, VC1, HEVC, VP9\n(note: this setting is hardware dependant, it can be worse on some systems)" },
	{"Disable HW decoding for SD", &mmc_config.selected_videoplayer_control, MPXPLAY_CONFIG_VIDEOPLAYERCONTROL_DISABLESDHWDEC, "Disable HW decoding for SD content\n(720x540 or lower resolution)" },
	{"Disable auto skip frame",    &mmc_config.selected_videoplayer_control, MPXPLAY_CONFIG_VIDEOPLAYERCONTROL_DISABLESKIPFRAME, "Disable automatic video frame skip\n(at large video delay / slow decoding)\n(disabling of frame skip can cause GUI freeze)" },
};
#define DISPQT_CONFIGPAGE_VIDEO_PLAYERCONTROL_CHKBOX_MAX (sizeof(config_video_player_control_checkboxes) / sizeof(struct configpage_chkbox_s))
#endif

#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
static struct configpage_editline_s config_video_config_custom_editlines[] = {
	{"Aspect ratio", &mmc_config.video_ar_custom[0],   sizeof(mmc_config.video_ar_custom), "Custom video aspect ratio in N:D format\n(integer numbers only)"},
	{"Source crop",  &mmc_config.video_crop_custom[0], sizeof(mmc_config.video_crop_custom), "Custom source video crop ratio in N:D format\n(integer numbers only)"},
	{"Zoom ratio",   &mmc_config.video_zoom_custom[0], sizeof(mmc_config.video_zoom_custom), "Custom video zoom ratio in N:D format\n(integer numbers only)"}
};
#define DISPQT_CONFIGPAGE_VIDEO_CONFIG_CUSTOM_EDITLINE_MAX (sizeof(config_video_config_custom_editlines) / sizeof(struct configpage_editline_s))
#endif

DispQtConfigpageVideo::DispQtConfigpageVideo(MainWindow *main_window, QWidget *parent) : QTabWidget(parent)
{
	this->main_window = main_window;
	QWidget *video_tab_widget_control = new QWidget(this);
	QWidget *video_tab_widget_config = new QWidget(this);
	QVBoxLayout *video_tab_layout_control = new QVBoxLayout;
	QVBoxLayout *video_tab_layout_config = new QVBoxLayout;

	this->groupchkboxes_video_surface_control = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Video surface control", config_video_surface_control_checkboxes, DISPQT_CONFIGPAGE_VIDEO_CONTROL_CHKBOX_MAX);
	this->groupcomboxes_video_config = new DispQtConfigpageComboboxGroupbox(main_window, this, "Video config", &config_video_decoder_config_combobox_group[0], DISPQT_CONFIGPAGE_VIDEO_DECODER_SELECT_COMBOX_MAX);
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	this->groupeditlines_video_languages = new DispQtConfigpageEditlineGroupbox(main_window, this, "Preferred languages selection", config_video_language_editlines, DISPQT_CONFIGPAGE_VIDEO_LANGUAGES_EDITLINE_MAX);
	this->groupeditlines_video_cfg_custom = new DispQtConfigpageEditlineGroupbox(main_window, this, "Custom picture settings (for video context menu)", config_video_config_custom_editlines, DISPQT_CONFIGPAGE_VIDEO_CONFIG_CUSTOM_EDITLINE_MAX);
#endif
#ifdef MPXPLAY_LINK_DXVA
	this->groupchkboxes_video_player_control = new DispQtConfigpageCheckboxGroupbox(main_window, this, "Video player control", config_video_player_control_checkboxes, DISPQT_CONFIGPAGE_VIDEO_PLAYERCONTROL_CHKBOX_MAX);
#endif

	video_tab_layout_control->setContentsMargins(0,5,0,0);
	video_tab_layout_control->addWidget(this->groupchkboxes_video_surface_control);
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	video_tab_layout_control->addWidget(this->groupeditlines_video_languages);
#endif
	video_tab_layout_control->addStretch(1);
	video_tab_widget_control->setLayout(video_tab_layout_control);

	video_tab_layout_config->setContentsMargins(0,5,0,0);
	video_tab_layout_config->addWidget(this->groupcomboxes_video_config);
#ifdef MPXPLAY_LINK_DXVA
	video_tab_layout_config->addWidget(this->groupchkboxes_video_player_control);
#endif
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	video_tab_layout_config->addWidget(this->groupeditlines_video_cfg_custom);
#endif
	video_tab_layout_config->addStretch(1);
	video_tab_widget_config->setLayout(video_tab_layout_config);

	this->addTab(video_tab_widget_control, "Video control");
	this->addTab(video_tab_widget_config, "Video config");
	this->setDocumentMode(true);
}

void DispQtConfigpageVideo::configpage_video_applyall(void)
{
	unsigned long w_ar_type = mmc_config.video_windowed_ar_type;
	this->groupchkboxes_video_surface_control->checkboxgroup_applyall();
	this->groupcomboxes_video_config->comboboxgroupbox_applyall();       // TODO: some changes has no immediate effect (ie: windowed ar type)
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	this->groupeditlines_video_languages->editlinegroupbox_applyall();
	this->groupeditlines_video_cfg_custom->editlinegroupbox_applyall();  // TODO: changes has no immediate effect (if custom is already selected)
#endif
#ifdef MPXPLAY_LINK_DXVA
	this->groupchkboxes_video_player_control->checkboxgroup_applyall();
#endif
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	if((mmc_config.video_windowed_ar_type != w_ar_type) && this->main_window->qt_video_player)
		emit this->main_window->qt_video_player->signal_video_surface_resize_refresh();
#endif
}
