//**************************************************************************
//*                     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: open small dialog windows, conversion between display/textwin.c and QT GUI

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_OUTPUT stdout
#define DISPQT_DEBUGOUT_ITEMS stdout

#include <QApplication>
#include <QtGui>
#include <QtWidgets>
#include <QLineEdit>
#include <QLabel>
#include "disp_qt.h"
#include "moc_textwin.h"
#include "moc_mainwindow.h"
#include "display/display.h"
#include "display/textwin.h"
#include "newfunc/newfunc.h"

extern "C" {
 extern struct mainvars mvps;
 extern unsigned int playcontrol, refdisp, desktopmode, preloadinfo;
}

extern MainWindow *dispqt_window_ptr;

DispQtTextwinGenerate::DispQtTextwinGenerate(MainWindow *mainwindow, QWidget *parent) : QObject(parent)
{
	this->main_window = mainwindow;
	this->parent_widget = parent;
	this->dialog_open_counter = 0;
	connect(this, SIGNAL(signal_textwinopen(textwin_window_t *)), SLOT(textwin_open(textwin_window_t *)));
	connect(this, SIGNAL(signal_textwindelete(textwin_window_t *)), SLOT(textwin_delete(textwin_window_t *)));
	connect(this, SIGNAL(signal_textwinupdate(struct dispqt_textwin_config_s *)), SLOT(textwin_update(struct dispqt_textwin_config_s *)));
}

void DispQtTextwinGenerate::textwin_open(textwin_window_t *tw)
{
    DispQtTextwinDialog *dialog_p;
	if(!tw)
		return;
	this->main_window->video_fullscreen_mainwin_opacity_disable(true);
	if(tw->dialog_ptr) {
	    this->dialog_open_decrement();
	    dialog_p = (DispQtTextwinDialog *) tw->dialog_ptr;
		delete dialog_p;
		tw->dialog_ptr = NULL;
	}
	dialog_p = new DispQtTextwinDialog(this->main_window, this->parent_widget, tw);
	if(dialog_p){
	    tw->dialog_ptr = (void *)dialog_p;
	    this->dialog_open_increment();
	    this->main_window->releaseMouse();
	}
	mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DispQtTextwinGenerate::textwin_open tw:%8.8X i:%d dp:%8.8X", (unsigned int)tw, (tw)? (unsigned int)tw->nb_items : 0, (tw)? (unsigned int)tw->dialog_ptr : 0);
}

void DispQtTextwinGenerate::textwin_delete(textwin_window_t *tw)  // called from other places
{
    mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DispQtTextwinGenerate::textwin_delete tw:%8.8X i:%d dp:%8.8X", (unsigned int)tw, (tw)? (unsigned int)tw->nb_items : 0, (tw)? (unsigned int)tw->dialog_ptr : 0);
    if(!tw)
        return;
    if(!tw->dialog_ptr){
        display_textwin_terminate_window((void *)tw);
        mpxplay_dispqt_mainthread_callback_init((void *)display_textwin_close_window, (void *)tw, 0);
        return;
    }
	DispQtTextwinDialog *dialog_p = (DispQtTextwinDialog *) tw->dialog_ptr;
	tw->dialog_ptr = NULL;
	this->dialog_open_decrement();
	dialog_p->releaseMouse();
	delete dialog_p;
    mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DispQtTextwinGenerate::textwin_delete END");
}

void DispQtTextwinGenerate::textwin_update(struct dispqt_textwin_config_s *dtc)
{
	if(!dtc)
		return;
	textwin_window_t *tw = (textwin_window_t *)dtc->tw_update;
	if(!tw || !tw->dialog_ptr) {
		pds_free(dtc->msg);
		pds_free(dtc);
		return;
	}
	DispQtTextwinDialog *dialog_p = (DispQtTextwinDialog *) tw->dialog_ptr;
	dialog_p->textwindialog_update_itemwidget(dtc);
}

bool DispQtTextwinGenerate::is_dialog_open(void)
{
    bool retval;
    this->mutex_counter.tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
    retval = (this->dialog_open_counter > 0)? true : false;
    this->mutex_counter.unlock();
    return retval;
}

void DispQtTextwinGenerate::dialog_open_increment(void)
{
    this->mutex_counter.tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
    this->dialog_open_counter++;
    this->mutex_counter.unlock();
}

void DispQtTextwinGenerate::dialog_open_decrement(void)
{
    this->mutex_counter.tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
    if(this->dialog_open_counter > 0) this->dialog_open_counter--;
    this->mutex_counter.unlock();
}

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

DispQtTextwinDialog::DispQtTextwinDialog(MainWindow *mainwindow, QWidget *parent, textwin_window_t *tw) : QDialog(parent)
{
	QString qs;
	QBoxLayout *btn_lay = NULL;
	QGridLayout *gdl = NULL;
	int font_size;
	if(!tw)
		return;
	this->main_window = mainwindow;
	this->parent_widget = parent;
	this->tw_data = tw;
	this->first_button = NULL;

	if(this->main_window->gui_config->font_text_name[DISPQT_FONTTEXTID_DIALOG]){
		this->font_dialog.fromString(QString::fromUtf8(this->main_window->gui_config->font_text_name[DISPQT_FONTTEXTID_DIALOG]));
		this->setFont(this->font_dialog);
	}
	font_size = this->font().pointSize();
	this->setFocus();
	this->setFocusPolicy(Qt::StrongFocus);
	this->setModal(true);

	this->setMinimumSize(DISPQT_TEXTWIN_WINSIZE_MIN_X * font_size, DISPQT_TEXTWIN_WINSIZE_MIN_Y * font_size);

	layout = new QGridLayout;
	//layout->setMargin(0);
	gdl = new QGridLayout;
	//gdl->setMargin(0);
	layout->addLayout(gdl, 0, 0);

	int lastx = 0, lasty = -1, btn_counter = 0;
	textwin_item_t *it = tw->item_first;
	for(int i = 0; i < tw->nb_items; i++, it++) {
		Qt::Alignment qt_it_align = Qt::AlignLeft;
		QWidget *qw = NULL;
		if(!it->data)
			continue;
		switch(it->flags & TEXTWIN_FLAGS_MSG_ALIGN) {
			case TEXTWIN_FLAG_MSGCENTERALIGN: qt_it_align = Qt::AlignCenter; break;
			//case TEXTWIN_FLAG_MSGLEFTALIGN: qt_align = Qt::AlignLeft; break;
			case TEXTWIN_FLAG_MSGRIGHTALIGN: qt_it_align = Qt::AlignRight; break;
		}
		switch(it->type){
			case TEXTWIN_LINETYPE_MSG_STATIC:
			case TEXTWIN_LINETYPE_MSG_ALLOCATED: {
				qs = QString::fromUtf8((char *)it->data); // , it->xsize); TODO: check
				if(qs.size() <= 0)
					break;
				QLabel *ql = new QLabel;
				ql->setText(qs);
				mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "m: x:%d s:%s ", it->xsize, (char *)it->data);
				qw = ql; }
				break;
			case TEXTWIN_LINETYPE_MSG_TABLE:
				this->gdl_table = gdl;
				textwindialog_msg_table_draw(gdl, lasty, it, qt_it_align, false, (char *)it->data);
				break;
			case TEXTWIN_LINETYPE_MSG_LIST: {
				struct textwin_listlines_t *tl = (struct textwin_listlines_t *)it->data;
				DispQtTextwinListSelect *table = new DispQtTextwinListSelect(tl->nb_entries, 1, tl->line_selector_varptr, this);
				table->verticalHeader()->setDefaultSectionSize(font_size + 7);
				for(int i = 0; i < tl->nb_entries; i++)
					table->setItem(i, 0, new QTableWidgetItem(QString::fromUtf8(tl->listentries[i])));
				if(tl->line_selector_varptr)
					table->selectRow(*(tl->line_selector_varptr));
				qw = table; }
				break;
			case TEXTWIN_LINETYPE_MSG_EDIT: {
				struct textwin_editline_t *tel = (struct textwin_editline_t *)it->data;
				qs = QString::fromUtf8(tel->srcstr);
				QLineEdit *qe = new QLineEdit;
				qe->setText(qs);
				qe->setMaxLength(tel->maxdatalen - 1);
				qe->setCursorPosition(tel->line_data_pos);
				if(tel->flags & TEXTWIN_EDITFLAG_HIDDENTYPE)
					qe->setEchoMode(QLineEdit::Password);
				qe->setFixedWidth(it->xsize * font_size);
				//if(tel->flags & TEXTWIN_EDITFLAG_OVERWRITE) // FIXME: ??? everywhere
					qe->setSelection(0, tel->line_data_len);
				mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "e: x:%d s:%s ", it->xsize, tel->srcstr);
				qw = qe; }
				break;
			case TEXTWIN_LINETYPE_BUTTON: {
				DispQtTextwinButton *qp = new DispQtTextwinButton(this, tw, it);
				if(!it->widget_ptr)
					break;
				if(!btn_lay) {   // FIXME: mixed vertical and horizontal buttons (no such one yet)
					if(it->flags & TEXTWIN_FLAG_VERTICALBUTTONS) {
						btn_lay = new QVBoxLayout;
						layout->addLayout(btn_lay, it->ypos, it->xpos);
					} else {
						btn_lay = new QHBoxLayout;
						layout->addLayout(btn_lay, it->ypos, 0);
					}
				}
				btn_lay->addWidget(qp, 0);//, qt_align);
				if(!this->first_button)
					this->first_button = qp;
				if(i == tw->item_selected)
					qp->setFocus(Qt::OtherFocusReason); }
				break;
			case TEXTWIN_LINETYPE_SWITCH: {
				struct textwin_switchline_t *tsl = (struct textwin_switchline_t *)it->data;
				qs = QString::fromUtf8(tsl->switchtext);
				QCheckBox *qc = new QCheckBox;
				qc->setText(qs);
				qc->setCheckable(true);
				bool setc = (((*(tsl->switchvar)) & tsl->switchbit)? true:false);
				qc->setChecked(setc);
				qw = qc; }
				break;
			case TEXTWIN_LINETYPE_PROGRESSBAR: {
				struct textwin_progressbar_t *tp = (struct textwin_progressbar_t *)it->data;
				QProgressBar *pb = new QProgressBar;
				pb->setOrientation((tp->flags & TEXTWIN_ITEM_PROGRESSBAR_FLAG_VERTICAL)? Qt::Vertical : Qt::Horizontal);
				pb->setTextDirection((tp->flags & TEXTWIN_ITEM_PROGRESSBAR_FLAG_BOTTOMTOTOP)? QProgressBar::BottomToTop : QProgressBar::TopToBottom);
				pb->setTextVisible((tp->flags & TEXTWIN_ITEM_PROGRESSBAR_FLAG_SHOWPTEXT)? true : false);
				pb->setRange(tp->minval, tp->maxval);
				pb->setValue(tp->value);
				qw = pb; }
				break;
			case TEXTWIN_LINETYPE_SEPARATOR: // FIXME: ???
				break;
		}
		if(!qw)
			continue;
		int y = it->ypos, x = it->xpos, save_ly = lasty;
		if(y < 0) {
			y = ++lasty;
			lastx = 0;
		} else if(y != lasty) {
			lasty = y;
			lastx = 0;
		} else
			lastx++;
		if((save_ly != lasty) && (lasty > 0)) { // FIXME: better logic
			gdl = new QGridLayout;
			//gdl->setMargin(0);
			layout->addLayout(gdl, lasty, 0);
		}
		gdl->addWidget(qw, lasty, lastx, qt_it_align);
		if(i == tw->item_selected) {
			qw->setFocus(Qt::OtherFocusReason);
			this->setFocusProxy(qw);
		}
		it->widget_ptr = (void *)qw;
		//mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "it x:%d y:%d itx:%d ity:%d twy:%d d:%s", lastx, lasty, it->xpos, it->ypos, tw->item_pos_y, ((qs.size()>0)? qs.toLatin1().data():"..."));
	}

	setLayout(layout);
	QString title = QString::fromUtf8(tw->headtext);
	setWindowTitle(title);
	show();
}

void DispQtTextwinDialog::textwindialog_close_event(void)
{
    textwin_window_t *tw = this->tw_data;
    if(tw){
        display_textwin_terminate_window((void *)tw);
        mpxplay_dispqt_mainthread_callback_init((void *)display_textwin_terminate_window, (void *)tw, 0);
    }
    this->main_window->video_fullscreen_mainwin_opacity_disable(false);
}

DispQtTextwinDialog::~DispQtTextwinDialog()
{
    mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DispQtTextwinDialog ~DispQtTextwinDialog");
    this->textwindialog_close_event();
}

void DispQtTextwinDialog::closeEvent(QCloseEvent *event)
{
    mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DispQtTextwinDialog closeEvent");
    if(this->main_window->dialog_handler)
        this->main_window->dialog_handler->dialog_open_decrement();  // FIXME: multiply dialog handling? (no such one yet)
    this->textwindialog_close_event();
    QDialog::closeEvent(event);
}

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

static unsigned int dispqttextwin_keyPressEvent_check(QKeyEvent *event, textwin_window_t *tw, QMutex *mutex_tw)
{
	if(!tw)
		return 0;
	unsigned long keycode = mpxplay_dispqt_mainwindow_keypress_convert(event);
	unsigned int extkey = PDS_KEYCODE_GET_EXTKEY(keycode);
	//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "e: %4.4X", extkey);
	if(!tw->nb_buttons) // !!! (same in console)
		return extkey;
	mutex_tw->tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
	textwin_item_t *it = tw->item_first;
	for(int i = 0; i < tw->nb_items; i++, it++) {
		if(!it->data || (it->type != TEXTWIN_LINETYPE_BUTTON))
			continue;
		struct display_textwin_button_t *btn = (struct display_textwin_button_t *)it->data;
		if(btn->extkey != extkey)
			continue;
		mutex_tw->unlock();
		return extkey;
	}
	mutex_tw->unlock();
	//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "e: QDialog");
	return 0;
}

static void dispqttextwin_mainthread_execute_button(struct dispqt_textwin_execfunc_t *dte)
{
	if(!dte)
		return;
	if(!(dte->flags & TEXTWIN_FLAG_DONTCLOSE) && (dte->nb_buttons || (dte->flags & TEXTWIN_FLAG_KEYCLOSEMSG)))
	    display_textwin_closewindow_items(dte->tw);
	if(dte->flags & TEXTWIN_FLAG_CONFIRM)
		display_textwin_execute_window_confirm(dte->extkey, dte->buttonhandlerfunc, dte->buttonhandlerdata);
	else if(dte->buttonhandlerfunc)
		((buttonhand_func_t)dte->buttonhandlerfunc)(dte->buttonhandlerdata, dte->extkey);
	pds_free(dte);
}

static void dispqttextwin_execfunc_call(textwin_window_t *tw, unsigned int extkey, QMutex *mutex_dte)
{
	if(!tw)
		return;
	struct dispqt_textwin_execfunc_t *dte = (struct dispqt_textwin_execfunc_t *)pds_malloc(sizeof(struct dispqt_textwin_execfunc_t));
	mutex_dte->tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
	dte->tw = tw;
	dte->buttonhandlerfunc = tw->buttonhandlerfunc;
	dte->buttonhandlerdata = tw->buttonhandlerdata;
	dte->extkey = extkey;
	dte->flags = tw->flags;
	dte->nb_buttons = tw->nb_buttons;
	mutex_dte->unlock();
	mpxplay_dispqt_mainthread_callback_init((void *)dispqttextwin_mainthread_execute_button, dte, 0);
}
//---------------------------------------------------------------------------------------------------------

void DispQtTextwinDialog::keyPressEvent(QKeyEvent *event)
{
	unsigned int extkey = dispqttextwin_keyPressEvent_check(event, this->tw_data, &this->mutex_tw);
	if(extkey) {
		if(extkey != KEY_ESC)
			textwindialog_save_modifications();
		dispqttextwin_execfunc_call(this->tw_data, extkey, &this->mutex_dte);
	} else
		QDialog::keyPressEvent(event);
}

/*bool DispQtTextwinDialog::eventFilter(QObject *o, QEvent *e)
{
	if ( e->type() == QEvent::KeyPress ){
		QKeyEvent* k = (QKeyEvent *)e;
		this->keyPressEvent(k);
		return TRUE;
	}
	return FALSE;
}*/

void DispQtTextwinDialog::textwindialog_msg_table_draw(QGridLayout *gdl, int &lasty, textwin_item_t *it, Qt::Alignment qt_it_align, bool update, char *upd_msg)
{
	QString qs;
	int widget_index;

	if(update) {
		if(!gdl)
			return;
		widget_index = gdl->indexOf((QWidget *)it->widget_ptr);
		//mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "len:%d wi: %d", len, widget_index);
		if(widget_index < 0)
			return;
	}

	unsigned int len = pds_strlen(upd_msg);
	if(!len)
		return;

	char *strbuf = (char *)pds_malloc(len + 4);
	if(!strbuf)
		return;
	memcpy(strbuf, upd_msg, len + 1);

	char *rowp = (char *)strbuf;
	do{
		char *nextrow = pds_strchr(rowp, '\n'), *colp; // new row
		unsigned int colnum = 0;
		if(nextrow)
			*nextrow++ = 0;
		colp = rowp;
		++lasty;
		do{
			Qt::Alignment qt_align;
			char *nextcol = pds_strchr(colp, '\t'); // new col
			if(nextcol)
				*nextcol++ = 0;
			switch(*colp) {
				case '\r': colp++; qt_align = Qt::AlignRight; break;  // right alignment (not left!)
				case '\f': colp++; qt_align = Qt::AlignCenter; break; // center alignment (aka form feed)
				default: qt_align = qt_it_align; break;  // use it/tw alignment
			}
			qs = QString::fromUtf8(colp);
			if(qs.size() > 0) {
				if(update) {
					QLayoutItem *qa = gdl->itemAt(widget_index++);
					if(qa) {
						QLabel *ql = (QLabel *)qa->widget();
						if(ql)
							ql->setText(qs);
						//mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, " ql:%8.8X ", (unsigned long)ql);
					}
				} else {
					QLabel *ql = new QLabel;
					ql->setText(qs);
					gdl->addWidget(ql, lasty, colnum, qt_align);
					if(!it->widget_ptr)
						it->widget_ptr = ql;
				}
			}
			colnum++;
			colp = nextcol;
			//mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "y:%d c:%d wi:%d",lasty, colnum, widget_index);
		}while(colp);
		rowp = nextrow;
	}while(rowp);
	pds_free(strbuf);
}

void DispQtTextwinDialog::textwindialog_update_itemwidget(struct dispqt_textwin_config_s *dtc)
{
	if(!dtc)
		return;
	struct textwin_window_t *tw = (struct textwin_window_t *)dtc->tw_update;
	textwin_item_t *it;
	if(!tw || (dtc->itemnum >= tw->nb_items))
		goto err_out_upd;
	it = tw->item_first + dtc->itemnum;
	switch(dtc->cfg_type){
		case DISPQT_TEXTWIN_CFGTYPE_UPDMSG:
		    switch(it->type) {
		    	case TEXTWIN_LINETYPE_MSG_STATIC:
		    	case TEXTWIN_LINETYPE_MSG_ALLOCATED: {
		    		QLabel *ql = (QLabel *)it->widget_ptr;
		    		if(!ql)
		    			break;
		    		ql->setText(QString::fromUtf8(dtc->msg));
		    		}
		    		break;
		    	case TEXTWIN_LINETYPE_MSG_TABLE: {
		    		Qt::Alignment qt_it_align = Qt::AlignLeft;
		    		switch(it->flags & TEXTWIN_FLAGS_MSG_ALIGN) {
		    			case TEXTWIN_FLAG_MSGCENTERALIGN: qt_it_align = Qt::AlignCenter; break;
		    			case TEXTWIN_FLAG_MSGRIGHTALIGN: qt_it_align = Qt::AlignRight; break;
		    		}
		    		textwindialog_msg_table_draw(this->gdl_table, it->ypos, it, qt_it_align, true, dtc->msg); // FIXME: multiply tables / gdl_table (no such one yet)
		    		}
		    		break;
			}
			break;
		case DISPQT_TEXTWIN_CFGTYPE_UPDVAL:
			switch(it->type){
	    		case TEXTWIN_LINETYPE_PROGRESSBAR:
	    			{ QProgressBar *pb = (QProgressBar *)it->widget_ptr;
	    			if(!pb)
	    				break;
	    			pb->setValue(dtc->value);
	    			}
	    			break;
			}
			break;
		case DISPQT_TEXTWIN_CFGTYPE_UPDHEAD:
			setWindowTitle(QString::fromUtf8(dtc->msg));
			break;
	}

err_out_upd:
	if(dtc->msg)
		pds_free(dtc->msg);
	pds_free(dtc);
}

void DispQtTextwinDialog::textwindialog_save_modifications(void)
{
	textwin_window_t *tw = this->tw_data;
	if(!tw)
		return;
	this->mutex_tw.tryLock(DISPQT_TEXTWIN_MUTEX_TIMEOUT);
	textwin_item_t *it = tw->item_first;
	for(int i = 0; i < tw->nb_items; i++, it++) {
		if(!it->data || !it->widget_ptr)
			continue;
		switch(it->type){
			case TEXTWIN_LINETYPE_MSG_EDIT: {
				struct textwin_editline_t *tel = (struct textwin_editline_t *)it->data;
				if(!tel->strbuf)
					break;
				QLineEdit *qe = (QLineEdit *)it->widget_ptr;
				QString qs = qe->text();
				int len = min(qs.size(), tel->maxdatalen);
				if(len > 0)
					memcpy(tel->strbuf, qs.utf16(), len * sizeof(mpxp_wchar_t));
				else
					len = 0;
				tel->strbuf[len] = 0;
				mpxplay_debugf(DISPQT_DEBUGOUT_ITEMS, "i:%2d l:%d t:\"%s\"", i, len, qs.toUtf8().data());
				break; }
			case TEXTWIN_LINETYPE_SWITCH: {
				struct textwin_switchline_t *tsl = ((struct textwin_switchline_t *)it->data);
				QCheckBox *qc = (QCheckBox *)it->widget_ptr;
				if(qc->isChecked())
					funcbit_enable(*(tsl->switchvar), tsl->switchbit);
				else
					funcbit_disable(*(tsl->switchvar), tsl->switchbit);
				break; }
		}
	}
	this->mutex_tw.unlock();
}

/*connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)),
  SLOT(focusChanged(QWidget*,QWidget*)));

void MyDialog::focusChanged(QWidget*, QWidget* to)
{
  if (!isAncestorOf(to))
  {
    QWidget* widget(qobject_cast<QWidget*>(children().front()));

    widget->setFocus(Qt::OtherFocusReason);

    QKeyEvent event(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);

    qApp->sendEvent(widget, &event);
  }
  // else do nothing
}*/

/*bool DispQtTextwinDialog::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::FocusIn) {
        //setStyleSheet("background-color: #FFFFCC;");
    } else if (event->type() == QEvent::FocusOut) {
    	this->setFocus();
        //setStyleSheet(m_originalStyleSheet);
    }

    return QObject::eventFilter(object, event);
}*/

/*void DispQtTextwinDialog::focusOutEvent(QFocusEvent * event)
{
	this->setFocus();
	//close();
}*/

//-------------------------------------------------------------------------------------------
DispQtTextwinButton::DispQtTextwinButton(QWidget *parent, textwin_window_t *tw, textwin_item_t *it) : QPushButton(parent)
{
	struct display_textwin_button_t *btn = (struct display_textwin_button_t *)it->data;
	char *p, stmp[128];
	QString qs;

	this->parent_widget = parent;
	this->tw_data = tw;
	this->button_keycode = btn->extkey;

	pds_strncpy(stmp, btn->text, sizeof(stmp));
	stmp[sizeof(stmp) - 1] = 0;
	p = &stmp[0];
	while(*p) {
		if(*p == '[' || *p == ']') // remove brackets from button text
			*p = ' ';
		p++;
	}
	pds_strcutspc(stmp);

	qs = QString::fromUtf8(stmp);
	if(qs.size() > 0) { // visible button
		it->widget_ptr = (void *)this;
		this->setText(qs);
		this->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
	} else {
		this->setVisible(false);
		this->setEnabled(false);
	}

	connect(this, SIGNAL(clicked(bool)), this, SLOT(textwin_button_handler(bool)));
	//connect(this, SIGNAL(pressed()), this, SLOT(textwin_button_handler()));
}

void DispQtTextwinButton::keyPressEvent(QKeyEvent *event)
{
	unsigned int extkey = dispqttextwin_keyPressEvent_check(event, this->tw_data, &this->mutex_tw);
	if(extkey){
		if(extkey != KEY_ESC)
			((DispQtTextwinDialog *)this->parent_widget)->textwindialog_save_modifications();
		if((extkey != KEY_ENTER1) && (extkey != KEY_ENTER2)) {
			dispqttextwin_execfunc_call(this->tw_data, extkey, &this->mutex_dte);
			return;
		}
	}
	QPushButton::keyPressEvent(event);
}

void DispQtTextwinButton::textwin_button_handler(bool checked)
{
	((DispQtTextwinDialog *)this->parent_widget)->textwindialog_save_modifications();
	dispqttextwin_execfunc_call(this->tw_data, this->button_keycode, &this->mutex_dte);
}

//-------------------------------------------------------------------------------------------
DispQtTextwinListSelect::DispQtTextwinListSelect(int rows, int columns, unsigned int *lineselector_varptr, QWidget *parent) : QTableWidget(rows, columns, parent)
{
	this->parent_dialog = (DispQtTextwinDialog *)parent;
	this->line_selector_varptr = lineselector_varptr;
	this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch );
	this->horizontalHeader()->hide();
	this->verticalHeader()->hide();
	this->setShowGrid(false);
	this->setSelectionBehavior(QAbstractItemView::SelectRows);
	this->setSelectionMode(QAbstractItemView::SingleSelection);
	this->setEditTriggers(QTableWidget::NoEditTriggers);
	this->setTabKeyNavigation(false);
	connect(this,SIGNAL(itemSelectionChanged()),this,SLOT(textwinlist_select_changed()));
	connect(this,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(doubleClickedSlot(QModelIndex)));
}

void DispQtTextwinListSelect::textwinlist_select_changed()
{
	if(this->line_selector_varptr)
		*(this->line_selector_varptr) = this->currentRow();
}

void DispQtTextwinListSelect::doubleClickedSlot(QModelIndex index)
{
	if(this->line_selector_varptr)
		*(this->line_selector_varptr) = index.row();
	if(this->parent_dialog) {
		DispQtTextwinButton *btn = this->parent_dialog->textwindialog_first_button();
		if(btn)
			emit btn->clicked(false);
		//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "double end lsv:%d r:%d btn:%8.8X", *(this->line_selector_varptr), index.row(), (unsigned long)btn);
	}
}

//-------------------------------------------------------------------------------------------
unsigned int display_textwin_draw_window_items(textwin_window_t *tw)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->dialog_handler || !tw)
		return 0;
	emit dispqt_window_ptr->dialog_handler->signal_textwinopen(tw);
	return 1;
}

void display_textwin_closewindow_items(void *tw_p)
{
	textwin_window_t *tw = (textwin_window_t *)tw_p;
	mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "display_textwin_closewindow_items func:%8.8X tw:%8.8X i:%d dp:%8.8X", (int)&display_textwin_closewindow_items, (unsigned int)tw, (tw)? (unsigned int)tw->nb_items : 0, (tw)? (unsigned int)tw->dialog_ptr : 0);
	if(!tw)
		return;
	display_textwin_reset_window(tw_p);  // FIXME: hack for editlines
	if(dispqt_window_ptr && dispqt_window_ptr->mainwin_initialized && dispqt_window_ptr->dialog_handler)
		emit dispqt_window_ptr->dialog_handler->signal_textwindelete(tw);
	else {
	    display_textwin_terminate_window(tw_p);
		display_textwin_close_window(tw_p);
	}
}

void display_textwin_draw_window_headtext(void *tw_update, char *headtext)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->dialog_handler || !tw_update || !headtext)
		return;
	struct dispqt_textwin_config_s *dtc = (struct dispqt_textwin_config_s *)pds_calloc(1, sizeof(struct dispqt_textwin_config_s));
	if(!dtc)
		return;
	dtc->msg = (char *)pds_malloc(strlen(headtext) + 1);
	if(!dtc->msg) {
		pds_free(dtc);
		return;
	}
	strcpy(dtc->msg, headtext);
	dtc->tw_update = tw_update;
	dtc->cfg_type = DISPQT_TEXTWIN_CFGTYPE_UPDHEAD;
	emit dispqt_window_ptr->dialog_handler->signal_textwinupdate(dtc);
}

void display_textwin_update_msg(void *tw_update, int itemnum, char *msg)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->dialog_handler || !tw_update || !msg)
		return;
	struct dispqt_textwin_config_s *dtc = (struct dispqt_textwin_config_s *)pds_calloc(1, sizeof(struct dispqt_textwin_config_s));
	if(!dtc)
		return;
	dtc->msg = (char *)pds_malloc(strlen(msg) + 1);
	if(!dtc->msg) {
		pds_free(dtc);
		return;
	}
	strcpy(dtc->msg, msg);
	dtc->tw_update = tw_update;
	dtc->itemnum = itemnum;
	dtc->cfg_type = DISPQT_TEXTWIN_CFGTYPE_UPDMSG;
	emit dispqt_window_ptr->dialog_handler->signal_textwinupdate(dtc);
}

void display_textwin_update_value(void *tw_update, int itemnum, int value)
{
	if(!dispqt_window_ptr || !dispqt_window_ptr->mainwin_initialized || !dispqt_window_ptr->dialog_handler || !tw_update)
		return;
	struct dispqt_textwin_config_s *dtc = (struct dispqt_textwin_config_s *)pds_malloc(sizeof(struct dispqt_textwin_config_s));
	if(!dtc)
		return;
	dtc->tw_update = tw_update;
	dtc->itemnum = itemnum;
	dtc->msg = NULL;
	dtc->value = value;
	dtc->cfg_type = DISPQT_TEXTWIN_CFGTYPE_UPDVAL;
	emit dispqt_window_ptr->dialog_handler->signal_textwinupdate(dtc);
}
