//**************************************************************************
//*                     This file is part of the                           *
//*                MMC - Mpxplay Multimedia Commander                      *
//*                   The source code of MMC is                            *
//*        (C) copyright 1998-2014 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: QT GUI API for Mpxplay

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_MIXER NULL //stdout
#define DISPQT_DEBUG_INIT stdout
#define DISPQT_DEBUG_OUTPUT stdout
#define DISPQT_DEBUGOUT_FFMPEG stdout

#include <QApplication>
#include <QtGui>
#include <QLCDNumber>
#include <Qcolor>
#include "disp_qt.h"
#include "moc_mainwindow.h"
#include "moc_config.h"
#include "moc_driveline.h"
#include "moc_editor.h"
#include "moc_seekbar.h"
#include "moc_video_qt.h"
#include "mpxplay.h"
#include "display/display.h"
#include "playlist/playlist.h"
#include "newfunc/newfunc.h"

extern "C" {
 extern struct mainvars mvps;
 extern unsigned int playcontrol, refdisp, desktopmode, preloadinfo, mpxplay_signal_events, timemode;
 extern enum mpxplay_video_player_types mpxplay_config_videoplayer_type;
}

static int  dispqt_main_calculate_timepos_ms(struct mpxpframe_s *frp);
static void refresh_display(struct mainvars *mvp);

// config_ini.cpp
extern void mpxplay_dispqt_configini_save_to_file(void);
static unsigned int lockid3window;

MainWindow *dispqt_window_ptr = NULL;

int mpxplay_dispqt_main_start(int argc, char *argv[])
{
	funcbit_smp_int32_put(refdisp, 0);

	Q_INIT_RESOURCE(mpxplay_qt_qrc);

	QApplication app(argc, argv);

	app.setApplicationName("Mpxplay");
	app.setOrganizationName("PDSoft");
	app.setOrganizationDomain("mpxplay.sourceforge.net");

	mpxplay_dispqt_configini_init();
	mpxplay_dispqt_configini_load_from_file();

#ifdef MPXPLAY_LINK_QTAV
    QtAV::Widgets::registerRenderers(); // FIXME: ???
#endif
	dispqt_window_ptr = new MainWindow();
	dispqt_window_ptr->setWindowTitle(QString::fromUtf8("MMC - Mpxplay Multimedia Commander v" DISPQT_MMC_VERSION_STRING));

	dispqt_window_ptr->show();

	//QObject::connect(&app, SIGNAL(aboutToQuit()), window, SLOT(exit_handler()));
	//QObject::connect(&app, SIGNAL(commitDataRequest()), window, SLOT(exit_handler_commit()), Qt::DirectConnection);

	refdisp |= RDT_INIT_FULL|RDT_OPTIONS;//|RDT_HEADER|RDT_ID3INFO|RDT_EDITOR;
	dispqt_window_ptr->mainwin_initialized = true;
	funcbit_enable(mpxplay_signal_events, MPXPLAY_SIGNALTYPE_GUIREADY);

	app.exec();

	mpxplay_dispqt_main_clean();
	mpxplay_dispqt_configini_save_to_file();

	mpxplay_debugf(DISPQT_DEBUG_INIT, "WINDOW CLOSE frp:%8.8X mpi:%8.8X", (unsigned long)mvps.frp0, (unsigned long)mvps.frp0->mpi);

	return 0;
}

void mpxplay_dispqt_main_close(void)
{
	MainWindow *winptr = dispqt_window_ptr;
	mpxplay_dispqt_main_clean();
	if(winptr)
		winptr->CloseWindowTriggeredfromExternal();
}

void mpxplay_dispqt_main_clean(void)
{
	if(dispqt_window_ptr)
		dispqt_window_ptr->mainwin_initialized = false;
	funcbit_disable(mpxplay_signal_events, MPXPLAY_SIGNALTYPE_GUIREADY);
	mpxplay_timer_deletefunc((void *)&refresh_display, NULL);
	mpxplay_timer_deletefunc((void *)&refresh_desktop, NULL);
}

void mpxplay_dispqt_video_waitfor_init(void)
{
	int counter = 200; // ca. 4 secs
	do{
		if(dispqt_window_ptr)
			if(dispqt_window_ptr->mainwin_initialized)
				break;
		pds_threads_sleep(20);
	}while(--counter);
	counter = 200;
	do{
		if(!refdisp)
			break;
		refresh_desktop(&mvps);
		pds_threads_sleep(20);
	}while(--counter);
	mpxplay_debugf(DISPQT_DEBUG_INIT, "INIT c:%d rd:%8.8X", counter, refdisp);
}

void mpxplay_display_init(struct mainvars *mvp)
{
	struct playlist_side_info *psi=mvp->psi0;
	unsigned int i;
	if(dispqt_window_ptr)
		dispqt_window_ptr->analtabdelay = (mvp->aui->card_controlbits&AUINFOS_CARDCNTRLBIT_DOUBLEDMA)? 7:3;
	for(i = 0; i < mvp->editorside_all_tabs; i++, psi++)
		psi->editor_from = psi->firstentry;
	mpxplay_timer_addfunc((void *)&refresh_display,mvp,MPXPLAY_TIMERTYPE_REPEAT,mpxplay_timer_secs_to_counternum(1)/DISPLAY_REFRESH_FPS);
	mpxplay_timer_addfunc((void *)&refresh_desktop,mvp,MPXPLAY_TIMERTYPE_REPEAT,1);
}

void mpxplay_display_close(struct mainvars *mvp){}

static void dtp_reset_editor(struct mainvars *mvp)
{
	unsigned int i;
	struct playlist_side_info *psi = mvp->psi0;
	for(i = 0; i < mvp->editorside_all_tabs; i++, psi++)
		psi->editor_from_prev = NULL;
}

void display_editorside_reset(struct playlist_side_info *psi)
{
	psi->editor_from_prev = NULL;
}

//------------------------------------------------------------------------
void mpxplay_dispqt_mainthread_callback_init(void *func, void *passinfo, unsigned long cb_flags)
{
	unsigned long tflag = MPXPLAY_TIMERTYPE_WAKEUP;
	if(cb_flags & DISPQT_CB_FLAG_MULTYCALL)
		tflag |= MPXPLAY_TIMERFLAG_MULTIPLY;
	if(cb_flags & DISPQT_CB_FLAG_MVPDATA)
		tflag |= MPXPLAY_TIMERFLAG_MVPDATA;
	mpxplay_timer_addfunc(func, passinfo, tflag, 0);
}

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

void mpxplay_dispqt_mouse_loadini(mpxini_line_t *,struct mpxini_part_t *){}
void mpxplay_dispqt_mouse_init(void){}
void mpxplay_dispqt_mouse_close(void){}

//------------------------------------------------------------------------
void mpxplay_dispqt_driveselect_popup(unsigned int sidenum)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || (sidenum >= PLAYLIST_MAX_SIDES))
		return;
	if(!dispqt_window_ptr->PlaylistEditor || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor->editor_drive_line[sidenum])
		return;
	if(!dispqt_window_ptr->PlaylistEditor->editor_drive_line[sidenum]->drive_combobox)
		return;
	emit dispqt_window_ptr->PlaylistEditor->editor_drive_line[sidenum]->drive_combobox->signal_show_popup();
}

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

unsigned int mpxplay_dispqt_video_open(void *handler_id, char *utf8_filename)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return 0;
	dispqt_window_ptr->qt_video_player->video_request_open(handler_id, utf8_filename);
	return (unsigned int)dispqt_window_ptr->qt_video_player->video_wait_for_open();
}

unsigned int mpxplay_dispqt_video_close(void *handler_id)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return 0;
	dispqt_window_ptr->qt_video_player->video_request_close(handler_id);
	return (unsigned int)dispqt_window_ptr->qt_video_player->video_wait_for_close();
}

void mpxplay_dispqt_video_play(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_play((playcontrol & (PLAYC_RUNNING | PLAYC_STARTFLAG))? true : false);
}

void mpxplay_dispqt_video_pause(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_pause();
}

mpxp_int64_t mpxplay_dispqt_video_duration_ms(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return -1;
	return (mpxp_int64_t)dispqt_window_ptr->qt_video_player->video_duration_ms();
}

void mpxplay_dispqt_video_seek_ms(mpxp_int64_t newpos_ms)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_seek_ms((qint64)newpos_ms);
}

mpxp_int64_t mpxplay_dispqt_video_tell_ms(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return -1;
	return (mpxp_int64_t)dispqt_window_ptr->qt_video_player->video_tell_ms();
}

void mpxplay_dispqt_video_switch_fullscreen(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_switch_fullscreen();
}

void mpxplay_dispqt_video_set_speed(int speed1000)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_set_speed(speed1000);
}

void mpxplay_dispqt_video_set_volume(int vol)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_audio_set_volume(vol);
}

void mpxplay_dispqt_video_signal_stop(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->qt_video_player || !(dispqt_window_ptr->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO))
		return;
	emit dispqt_window_ptr->qt_video_player->signal_video_event_stop();
}

//----------------------------------------------------------------------
static void dispqt_media_title_create(char *sout, unsigned int bufsize, struct playlist_entry_info *pei, bool aktfile, char *pre_str)
{
	if(!pei) {
		snprintf(sout, bufsize, "%s none", pre_str);
		return;
	}

	char **id3ip = &pei->id3info[0];
	char stmp[128];

	if(!aktfile) {
		unsigned long timesec = (playlist_entry_get_timemsec(pei) + 500) / 1000;
		if(timesec >= 3600)
			snprintf(stmp, sizeof(stmp), "  (%d:%2.2d:%2.2d)", (timesec/3600), (timesec%3600)/60, (timesec%3600)%60);
		else
			snprintf(stmp, sizeof(stmp), "  (%d:%2.2d)", (timesec/60) , (timesec%60));
	} else
		stmp[0] = 0;

	if(id3ip[I3I_ARTIST] || id3ip[I3I_TITLE]) {
		snprintf(sout, bufsize, "%s%s  -  %s%s", pre_str, (id3ip[I3I_ARTIST])? id3ip[I3I_ARTIST] : "", (id3ip[I3I_TITLE])? id3ip[I3I_TITLE] : "", stmp);
	} else {
		char *shortfname = pds_getfilename_from_fullname(pei->filename);
		if(!shortfname)
			shortfname = pei->filename;
		snprintf(sout, bufsize, "%s%s%s", pre_str, shortfname, stmp);
	}
}

static void mpxplay_dispqt_media_set_currfileinfo(struct mainvars *mvp)
{
	struct playlist_side_info *psip = mvp->psip;
	struct playlist_entry_info *pei;
	struct dispqt_currfileinfo_s *cur;
	char stmp[128];
	if(!psip)
		return;
	cur = (struct dispqt_currfileinfo_s *)calloc(1, sizeof(struct dispqt_currfileinfo_s));
	if(!cur)
		return;
	cur->currtimelen = mvp->fr_primary->timesec * 1000;
	if(!cur->currtimelen)
		cur->currtimelen = 100;
	cur->allsongnum = psip->lastentry - psip->firstsong + 1;
	cur->currsongnum = playlist_getsongcounter(mvp);
	snprintf(stmp, sizeof(stmp), " %2d / %d      ", cur->currsongnum, cur->allsongnum);
	dispqt_media_title_create(cur->curr_title, sizeof(cur->curr_title), mvp->pei0, true, stmp);
	pei = mvp->aktfilenum;
	if(!playlist_editlist_entry_skip(psip, &pei, -1) || (pei < psip->firstsong) || (pei > psip->lastentry))
		pei = NULL;
	dispqt_media_title_create(cur->prev_title, sizeof(cur->prev_title), pei, false, (char *)"Prev:   ");
	if(mvp->newfilenum)
		pei = mvp->newfilenum;
	else {
		pei = mvp->aktfilenum;
		if((pei < psip->firstsong) || (pei > psip->lastentry))
			pei = psip->firstsong - 1;
		if(!playlist_editlist_entry_skip(psip, &pei, +1) || (pei < psip->firstsong) || (pei > psip->lastentry))
			pei = NULL;
	}
	dispqt_media_title_create(cur->next_title, sizeof(cur->next_title), pei, false, (char *)"Next:   ");
	if(dispqt_window_ptr){
		int ctime = dispqt_main_calculate_timepos_ms(mvp->fr_primary);
		if(ctime < 0)
			ctime = 0;
		emit dispqt_window_ptr->signal_media_set_currfileinfos(cur);
		emit dispqt_window_ptr->signal_media_set_timepos(ctime);
	}
}

static void mpxplay_dispqt_media_set_timepos(int timepos_ms)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;
	emit dispqt_window_ptr->signal_media_set_timepos(timepos_ms);
}

void mpxplay_dispqt_avmixer_set_avformat(unsigned int extfile)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;
	emit dispqt_window_ptr->signal_avmixer_set_avformat((extfile)? true : false); // !!! extfile means video file
}

static void mpxplay_dispqt_amixer_sliders_reload(bool volume_only)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;
	emit dispqt_window_ptr->signal_avmixer_sliders_reload(volume_only);
}

//----------------------------------------------------------------------
unsigned long volnum[DISPLAY_ANALISER_MAXDELAY][2];
unsigned long analtab[DISPLAY_ANALISER_MAXDELAY][DISPLAY_ANALISER_BANDNUM];

static int dispqt_main_calculate_timepos_ms(struct mpxpframe_s *frp)
{
	int ctime;
	if(frp && (frp->frameNum >= frp->index_start) && frp->index_len)
	{
		int cframe, index_pos = frp->frameNum - frp->index_start;
		ctime = 0;
		/*switch(timemode){
			case 0: cframe = index_pos; break;
			case 1: cframe = frp->index_len-index_pos; break;
			case 2: cframe = index_pos; ctime = playlist_fulltime_getelapsed(mvp,0); break;
			case 3: cframe = frp->index_len-index_pos;
					if(mvp->psip->fulltimesec)
						ctime = mvp->psip->fulltimesec-playlist_fulltime_getelapsed(mvp,0) - frp->timesec;
					break;
		   default: cframe = index_pos;
					break;
		}
		if(cframe < 0)
			cframe=0;*/
		cframe = index_pos;

		ctime *= 1000;
		ctime += (long)(1000.0 * (float)cframe * (float)frp->timesec / (float)frp->index_len);
	}else{
		ctime = -1;
	}
	return ctime;

}

static void refresh_display(struct mainvars *mvp)
{
	int ctime = dispqt_main_calculate_timepos_ms(mvp->fr_primary);
	if(ctime >= 0)
		mpxplay_dispqt_media_set_timepos(ctime);
}

static void display_fileinfos(struct mainvars *mvp)
{
	struct playlist_entry_info *pei;
	char **id3ip, souttext[256];

	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;

	pei = mvp->pei0;
	id3ip = &pei->id3info[0];

	if(id3ip[I3I_ARTIST] || id3ip[I3I_TITLE]){
		snprintf(souttext, sizeof(souttext), "MMC %s - %s : %s ", DISPQT_MMC_VERSION_STRING,
		(id3ip[I3I_ARTIST])? id3ip[I3I_ARTIST] : "", (id3ip[I3I_TITLE])? id3ip[I3I_TITLE] : "");
	}else{
		char *shortfname = pds_getfilename_from_fullname(pei->filename);
		if(!shortfname)
			shortfname = pei->filename;
		snprintf(souttext, sizeof(souttext), "MMC %s - %s ", DISPQT_MMC_VERSION_STRING, shortfname);
	}
	dispqt_window_ptr->setWindowTitle(QString::fromUtf8(souttext));
}

static int dispqt_editor_refresh_tabinfos(struct mainvars *mvp)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return DISPQT_ERROR_EDITORTABLE_UNINIT;
	if(!(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR))
		return DISPQT_ERROR_EDITORTABLE_NOTEXISTS;
	return mpxplay_dispqt_editor_tab_headers_refresh_create(mvp, dispqt_window_ptr->PlaylistEditor);
}

void refresh_desktop(struct mainvars *mvp)
{
	if(!refdisp || !dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;

	if(refdisp&RDT_INIT_FULL){
		if(refdisp&RDT_RESET_EDIT)
			dtp_reset_editor(mvp);
		funcbit_disable(refdisp, RDT_INIT_FULL);
	}

	if(refdisp&RDT_HEADER){
		struct mpxplay_audioout_info_s *aui = mvp->aui;
		if(aui && aui->card_bytespersign && aui->freq_card){
			int ad = (DISPLAY_REFRESH_FPS * (int)aui->card_dmasize) / ((int)aui->card_bytespersign * (int)aui->freq_card);
			if(ad < 1)
				ad = 1;
			else if(ad >= DISPLAY_ANALISER_MAXDELAY)
				ad = DISPLAY_ANALISER_MAXDELAY-1;
			if(dispqt_window_ptr)
				dispqt_window_ptr->analtabdelay = ad;
		}

		funcbit_disable(refdisp, RDT_HEADER);
		display_fileinfos(mvp);
		if(!(refdisp & (RDT_BROWSER | RDT_ID3INFO)))
			mpxplay_dispqt_media_set_currfileinfo(mvp);
	}
	if(refdisp&RDT_ID3INFO){
		funcbit_disable(refdisp, RDT_ID3INFO);
		if(!(refdisp & RDT_BROWSER))
			mpxplay_dispqt_media_set_currfileinfo(mvp);
	}
	if(refdisp&RDT_BROWSER){
		funcbit_disable(refdisp, RDT_BROWSER);
		mpxplay_dispqt_media_set_currfileinfo(mvp);
		playlist_fulltime_getelapsed(mvp,1);
	}

	if(refdisp&RDT_TABINFOS)
	{
		if(dispqt_editor_refresh_tabinfos(mvp) != DISPQT_ERROR_EDITORTABLE_BUSY)
			funcbit_disable(refdisp, RDT_TABINFOS);
	}
	else if(refdisp&RDT_EDITOR)  // FIXME: else
	{
		funcbit_disable(refdisp, RDT_EDITOR);
		draweditor(mvp);
	}

	if(refdisp&RDT_VOL){
		funcbit_disable(refdisp, RDT_VOL);
		mpxplay_dispqt_amixer_sliders_reload(true);
	}
	if(refdisp&RDT_OPTIONS){
		funcbit_disable(refdisp, RDT_OPTIONS);
		mpxplay_dispqt_amixer_sliders_reload(false);
	}
}

static void dispqt_editor_chkfile_disp(struct playlist_side_info *psi, int editor_rows)
{
	if(psi->editor_from_prev != psi->editor_from){
		psi->editor_from_prev = psi->editor_from;
		if(preloadinfo == PLI_DISPLOAD) {
			struct playlist_entry_info *pei_lastline = playlist_editlist_entry_seek(psi, psi->editor_from, editor_rows, SEEK_CUR);
			playlist_chkfile_start_disp(psi, psi->editor_from, pei_lastline);
			mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "dispload er:%d f:%d e:%d", editor_rows, (unsigned long)(psi->editor_from - psi->firstentry), (unsigned long)(pei_lastline - psi->firstentry));
		}
	}
}

static int dispqt_editor_table_refresh(struct playlist_side_info *psi, unsigned int full_tab)
{
	int retcode = DISPQT_ERROR_EDITORTABLE_ARGS;
	PlaylistEditorWidget *pew;

	if(!psi || (psi->sidenum >= PLAYLIST_MAX_SIDES))
		return retcode;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return DISPQT_ERROR_EDITORTABLE_UNINIT;
	if(!(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !(dispqt_window_ptr->gui_config->editor_flags & (1 << psi->sidenum))) // side is not enabled
		return DISPQT_ERROR_EDITORTABLE_NOTEXISTS;
	if((psi->tabnum != psi->mvp->editorsides_selected_tab[psi->sidenum]))
		return retcode;
	pew = dispqt_window_ptr->PlaylistEditor;
	if(!pew)
		return DISPQT_ERROR_EDITORTABLE_MISSING;

	if(full_tab) {
		pew = dispqt_window_ptr->PlaylistEditor;
		if(!pew)
			return DISPQT_ERROR_EDITORTABLE_MISSING;
		int editor_rows = pew->editortable_line_count(psi);
		if(!psi->editor_from_prev) // RDT_RESET_EDIT
			mpxplay_display_center_editorhighline(psi, 0);
		dispqt_editor_chkfile_disp(psi, editor_rows);
	}

	retcode = pew->table_refresh_create(psi);
	switch(retcode)
	{
		case DISPQT_ERROR_OK: break;
		case DISPQT_ERROR_EDITORTABLE_MISSING: psi->editor_from = psi->firstentry; // FIXME: ???
		default: return retcode;
	}

	return DISPQT_ERROR_OK;
}

void draweditor(struct mainvars *mvp)
{
	int side, tabnum;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->PlaylistEditor || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR))
		return;
	for(side = 0; side < PLAYLIST_MAX_SIDES; side++) {
		for(tabnum = 0; (tabnum < mvp->editorsides_num_tabs[side]) && dispqt_window_ptr && dispqt_window_ptr->PlaylistEditor; tabnum++) {
			struct playlist_side_info *psi = playlist_editlist_tabpsi_get(mvp, side, tabnum);
			int retcode = dispqt_editor_table_refresh(psi, 1);
			switch(retcode) {
				case DISPQT_ERROR_EDITORTABLE_MISSING:
				case DISPQT_ERROR_EDITORTABLE_BUSY   : refdisp |= RDT_EDITOR; break;
				default: break;
			}
		}
	}
}

void display_draw_editor_oneline(struct playlist_side_info *psi, struct playlist_entry_info *pei, int lineposy)
{
	if((psi->editloadtype&PLL_FILTERED) && (pei->infobits&PEIF_FILTEROUT))
		return;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->PlaylistEditor || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR))
		return;
	int editor_rows = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	if((pei < psi->editor_from) || (pei > playlist_editlist_entry_seek(psi, psi->editor_from, editor_rows, SEEK_CUR)))
		return;
	if(dispqt_editor_table_refresh(psi, 0) == DISPQT_ERROR_EDITORTABLE_BUSY) // FIXME: a faster way
		refdisp |= RDT_EDITOR;
	//pet->line_update(psi, pei);  //
}

unsigned int mpxplay_display_editorside_scroll(struct playlist_side_info *psi, int scroll_lines, int whence, unsigned int check_page)
{
	if(!psi || !dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor)
	 	return 0;
	int editor_lines = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	int listlines = (psi->editloadtype & PLL_FILTERED)? psi->filtered_files : ((psi->lastentry - psi->firstentry) + 1);
	int remainlines = listlines - editor_lines;
	struct playlist_entry_info *newfrom, *nf;
	editor_lines--;

	if((editor_lines <= 1) || (remainlines <= 0))
		return 0;

	switch(whence){
		case SEEK_SET:newfrom = psi->firstentry; break;
		case SEEK_CUR:newfrom = psi->editor_from; break;
		case SEEK_END:newfrom = psi->lastentry; break;
	}
	newfrom = playlist_editlist_entry_seek(psi, newfrom, scroll_lines, whence);
	if(check_page) {
		nf = playlist_editlist_entry_seek(psi, newfrom, -editor_lines, SEEK_END);
		if(newfrom > nf)
			newfrom = nf;
		nf = playlist_editlist_entry_seek(psi, newfrom, 0, SEEK_SET);
		if(newfrom < nf)
			newfrom = nf;
	}
	psi->editor_from = newfrom;
	refdisp|=RDT_EDITOR;
	return 1;
}

void mpxplay_display_editorside_move(struct mainvars *mvp,struct playlist_entry_info *ehls)
{
	struct playlist_side_info *psi = mvp->psie;
	int diff = playlist_editlist_entry_diff(psi, psi->editorhighline, ehls);
	if(mpxplay_display_editorside_scroll(psi, diff, SEEK_CUR, 1))
		playlist_editorhighline_set_nocenter(psi, ehls);
}

#define MDCE_VISIBLE_LINES 4 // give a high value to keep the cursor on the middle of editorside

void mpxplay_display_center_editorhighline(struct playlist_side_info *psi,unsigned int visible_lines)
{
	unsigned int listlines;
	int editor_lines;
	struct playlist_entry_info *newfrom, *nf;

	if(psi->sidenum >= PLAYLIST_MAX_SIDES)
		return;

	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor)
		return;

	editor_lines = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	if(editor_lines <= 1){
		newfrom = psi->editorhighline;
		goto err_out_mdce;
	}

	if(psi->editloadtype&PLL_FILTERED)
		listlines = psi->filtered_files;
	else
		listlines = (psi->lastentry-psi->firstentry) + 1;

	if(listlines <= editor_lines){
		newfrom = playlist_editlist_entry_seek(psi,psi->firstentry,0,SEEK_SET);
		goto err_out_mdce;
	}

	if(desktopmode&DTM_EDIT_MDCE_DISABLE){
		if(!(psi->editloadtype&PLL_FILTERED))
			return;
		visible_lines = 1;
	}

	if(!visible_lines)
		visible_lines = MDCE_VISIBLE_LINES;

	editor_lines--;

	if(editor_lines < (visible_lines*2)){
		newfrom = playlist_editlist_entry_seek(psi,psi->editorhighline,-(editor_lines/2),SEEK_CUR);
	}else{
		newfrom = playlist_editlist_entry_seek(psi,psi->editorhighline,-visible_lines,SEEK_CUR);
		if(psi->editor_from <= newfrom){
			newfrom = playlist_editlist_entry_seek(psi,psi->editorhighline,(-editor_lines+visible_lines),SEEK_CUR);
			if(psi->editor_from >= newfrom)
				newfrom = psi->editor_from;
		}
	}

	nf = playlist_editlist_entry_seek(psi,newfrom,(-editor_lines),SEEK_END);
	if(newfrom > nf)
		newfrom = nf;
	nf = playlist_editlist_entry_seek(psi,psi->firstentry,0,SEEK_SET);
	if(newfrom < nf)
		newfrom = nf;

err_out_mdce:
	if(psi->editor_from != newfrom) {
		psi->editor_from = newfrom;
		refdisp |= RDT_EDITOR;
	} else if(psi == psi->mvp->psie) {
		if(dispqt_window_ptr->PlaylistEditor)
			dispqt_window_ptr->PlaylistEditor->line_select_request(psi, psi->editorhighline);
	}
}

void mpxplay_display_editor_pageup(struct playlist_side_info *psi)
{
	PlaylistEditorTable *pet;
	if(!psi || !dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor)
		return;
	int editor_rows = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	playlist_editorhighline_seek(psi, (-editor_rows), SEEK_CUR);
}

void mpxplay_display_editor_pagedown(struct playlist_side_info *psi)
{
	PlaylistEditorTable *pet;
	if(!psi || !dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor)
		return;
	int editor_rows = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	playlist_editorhighline_seek(psi, editor_rows, SEEK_CUR);
}

int mpxplay_display_editor_getlinenums(struct playlist_side_info *psi)
{
	PlaylistEditorTable *pet;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !(dispqt_window_ptr->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_EDITOR) || !dispqt_window_ptr->PlaylistEditor)
		return 127;
	int editor_rows = dispqt_window_ptr->PlaylistEditor->editortable_line_count(psi);
	if(editor_rows <= 0)
		editor_rows = 127;
	return editor_rows;
}

void mpxplay_display_editor_addfiles_dialog_open(void)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->PlaylistEditor)
		return;
	emit dispqt_window_ptr->signal_action_file_openfiles();
}

//-----------------------------------------------------------------------------------------------
void display_message(unsigned int linepos, unsigned int blink, char *msg) // FIXME: blinking?
{
	static char msg0[256];
	char strtmp[512];

	if(lockid3window >= 2)
		return;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;
	lockid3window = 1;

	if(!linepos) {
		dispqt_window_ptr->mainwin_statusbar_msg_send(msg);
		pds_strncpy(msg0, msg, sizeof(msg0) - 4);
		msg0[sizeof(msg0) - 4] = 0;
	} else {
		int len = pds_strncpy(strtmp, msg0, sizeof(strtmp) - 4);
		pds_strncpy(&strtmp[len], msg, (sizeof(strtmp) - 4 - len));
		strtmp[sizeof(strtmp) - 4] = 0;
		dispqt_window_ptr->mainwin_statusbar_msg_send(strtmp);
	}

	funcbit_enable(mpxplay_signal_events, MPXPLAY_SIGNALTYPE_DISPMESSAGE);
	funcbit_disable(mpxplay_signal_events, MPXPLAY_SIGNALTYPE_CLEARMESSAGE); //
}

void clear_message(void)
{
	if(lockid3window >= 2)
		return;
	lockid3window = 0;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized)
		return;
	if(!dispqt_window_ptr->mainwin_statusbar_msg_send((char *)"Ready"))
		mpxplay_timer_addfunc((void *)clear_message, NULL, MPXPLAY_TIMERTYPE_WAKEUP, mpxplay_timer_secs_to_counternum(1));
	else
		funcbit_enable(mpxplay_signal_events, MPXPLAY_SIGNALTYPE_CLEARMESSAGE);
}

void display_clear_timed_message(void)
{
	if(lockid3window >= 3)
		return;
	lockid3window = 0;
	clear_message();
	mpxplay_timer_deletefunc((void *)display_clear_timed_message, NULL);
}

void display_timed_message(char *message)
{
	char line0[256];

	if(lockid3window>2)
		return;
	lockid3window=0;

	if(pds_strchr(message,'\n')){
	    char *line1;
	    pds_strncpy(line0, message, sizeof(line0));
	    line0[sizeof(line0) - 1] = 0;
	    line1 = pds_strchr(line0,'\n');
	    if(line1)
	        *line1 = ' ';
	    message = &line0[0];
	}
	display_message(0, 0, message);

	mpxplay_timer_addfunc((void *)display_clear_timed_message, NULL, MPXPLAY_TIMERTYPE_WAKEUP, mpxplay_timer_secs_to_counternum(DISPLAY_MESSAGE_TIME));
	lockid3window=2;
}

void display_static_message(unsigned int linepos,unsigned int blink,char *msg)
{
	lockid3window = 0;
	display_message(linepos, blink, msg);
	lockid3window = 3;
	mpxplay_timer_deletefunc((void *)display_clear_timed_message, NULL);
}

void clear_static_message(void)
{
	lockid3window = 0;
	clear_message();
}

void display_warning_message(char *message)
{
	display_message(0, 0, message);
}

#include "help_text.h"
void display_help_window(void)
{
	display_textwin_openwindow_keymessage(0,(char *)(" Help - keyboard controls "), (char *)keycontrols_help_text);
}

void clear_volnum(void){}
void display_bufpos_int08(struct mainvars *mvp){}
void draw_browserbox(struct mainvars *,struct playlist_entry_info *){}
unsigned int display_editor_resize_x(struct mainvars *,int direction){return 0;}
void display_editor_resize_y(struct mainvars *mvp,int direction){}

//doesn't work
/*void mpxplay_dispqt_system_opendefaultapplication(char *filename_utf8)
{
	QDesktopServices::openUrl(QUrl(QString::fromUtf8(filename_utf8)));
	//QDesktopServices::openUrl(QUrl("file:///home/fstigre/fileName.pdf"));  // for QT
}*/

#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
int mpxplay_dispqt_ffmpegvideo_configcbk_check(unsigned int cfgcmd)
{
	if(mpxplay_config_videoplayer_type != MPXPLAY_VIDEOPLAYERTYPE_FFMPEG)
		return DISPQT_ERROR_EDITORTABLE_ARGS;
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->qt_video_player || !dispqt_window_ptr->qt_video_player->video_get_widgetptr())
		return DISPQT_ERROR_EDITORTABLE_UNINIT;
	return DISPQT_ERROR_OK;
}

int mpxplay_dispqt_ffmpegvideo_config_callback(unsigned int cfgcmd, mpxplay_infile_callback_t *cbk_func, void *passdata)
{
	int retcode = mpxplay_dispqt_ffmpegvideo_configcbk_check(cfgcmd);
	if(retcode == DISPQT_ERROR_OK)
	{
		retcode = dispqt_window_ptr->qt_video_player->video_ffmpeg_configcallback_create(cfgcmd, cbk_func, passdata);
		if((retcode == DISPQT_ERROR_OK) && (cfgcmd == MPXPLAY_INFILE_CBKCFG_SRVFFMV_REFRESH_CALLBACK) && (playcontrol & PLAYC_RUNNING))
			mpxplay_dispqt_video_play();
	}
	//mpxplay_debugf(DISPQT_DEBUGOUT_FFMPEG, "mpxplay_dispqt_ffmpegvideo_config_callback cmd:%8.8X cbk:%8.8X p:%8.8X", cfgcmd, (unsigned long)cbk_func, (unsigned long)passdata);
	return retcode;
}

#else

int mpxplay_dispqt_ffmpegvideo_configcbk_check(unsigned int cfgcmd)
{
	return -1;
}

int mpxplay_dispqt_ffmpegvideo_config_callback(unsigned int cfgcmd, mpxplay_infile_callback_t *cbk_func, void *passdata)
{
	return -1;
}

#endif

