/****************************************************************************
** FrameObject class
**
** Created: Tue Feb 02 22:06:51 2004
**      by: Varol Okan using Kate
**
** This class is the encapsulation of the FrameObject.
**
** A FrameObject is a visible frame on a DVD menu.  
**
****************************************************************************/
#include <qpainter.h>
#include <qwmatrix.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qlineedit.h>

#include "messagebox.h"
#include "global.h"
#include "xml_dvd.h"
#include "menuobject.h"
#include "frameobject.h"
#include "dialogframe.h"
#include "dialogmatrix.h"
#include "structuretoolbar.h"

FrameObject::FrameObject (QWidget *pParent)
	: MenuObject (pParent)
{
	m_qsObjectType = QString ( FRAME_OBJECT );
	m_colorFrame   = QColor  ( START_FRAME_COLOR );
	m_iFrameWidth  = 4;
	m_iFrameJoin   = Qt::MiterJoin;
	m_iFrameStyle  = Qt::SolidLine;
}

FrameObject::~FrameObject ()
{

}

void FrameObject::setFrameWidth(int iFrameWidth)
{
	m_iFrameWidth = iFrameWidth;
}

void FrameObject::setFrameJoin(int iFrameJoin)
{
	m_iFrameJoin = iFrameJoin;
}

void FrameObject::setFrameStyle(int iFrameStyle)
{
	m_iFrameStyle = iFrameStyle;
}

void FrameObject::replaceColor(QColor theColor, QColor oldColor)
{
	if (color () == oldColor)
		setFrameColor (theColor);
}

void FrameObject::setFrameColor(QColor colorFrame)
{
  m_colorFrame = colorFrame;
}

int FrameObject::width ()
{
	return m_iFrameWidth;
}

QColor FrameObject::color ()
{
	return m_colorFrame;
}

int FrameObject::style ()
{
	return m_iFrameStyle;
}

int FrameObject::join ()
{
	return m_iFrameJoin;
}

void FrameObject::drawContents (QPainter *painter)
{
        if ( m_pShadow && ! m_bDrawRect )
	     m_pShadow->drawContents ( painter );
	QWMatrix theMatrix;
	// Here we calculate the center point of gravity (rotation)
	QPoint centerPos;
	centerPos.setX (rect().x() + (int)((float)rect().width () / 2.0));
	centerPos.setY (rect().y() + (int)((float)rect().height() / 2.0));
	// Here we define the cenetered rect.
	QRect theRect ((int)-(rect().width()/ 2.0), (int)-(rect().height()/2.0), rect().width(), rect().height());

	QPen thePen (m_colorFrame, m_iFrameWidth, (Qt::PenStyle)m_iFrameStyle, Qt::FlatCap, (Qt::PenJoinStyle)m_iFrameJoin);
	// Set the PEN
	painter->setPen(thePen);
	// and make sure no Brush is used ...
	painter->setBrush(Qt::NoBrush);

	// First we translate to the appropriate location,
	theMatrix.translate ((double)centerPos.x(), (double)centerPos.y());

	//. then we apply the other modifications ...
	theMatrix.scale  (modifiers()->fScaleX, modifiers()->fScaleY);
	theMatrix.rotate (modifiers()->fRotate);
	theMatrix.shear  (modifiers()->fShearX, modifiers()->fShearY);
	
	// Here we draw the rect that encompasses the button (think of rotated)
	m_boundingRect = theMatrix.mapRect(theRect);
	if (m_bDrawRect)
	  drawActiveFrame ( painter );

	painter->setWorldMatrix(theMatrix);

	painter->drawRect(theRect);
	theMatrix.reset();
	painter->setWorldMatrix(theMatrix);
}

void FrameObject::drawContents (QPainter *pPainter, int iRenderFrameNumber, int)
{
	// Next is to set the AnimationAttributes
	for (uint t=0;t<m_listAnimationAttributes.count();t++)
		m_listAnimationAttributes[t]->setValue (iRenderFrameNumber);

	drawContents (pPainter);
}

bool FrameObject::mousePressEvent (QMouseEvent *pEvent)
{
	m_currentMousePos = pEvent->pos();
	if (pEvent->button() == Qt::RightButton)	{
		QPoint globalPos = pEvent->globalPos();
		return createContextMenu ( globalPos );
	}
	else
		m_bDrawRect = true;
	return false;
}

bool FrameObject::mouseReleaseEvent (QMouseEvent *)
{
	m_bDrawRect = false;
	emit (signalUpdatePixmap());
	emit (signalUpdateStructure());
	return false;
}

bool FrameObject::mouseDoubleClickEvent (QMouseEvent *)
{
	QString qsAnimation;
	DialogFrame frameDialog (m_pParent);
	frameDialog.initMe(this);
	if (frameDialog.exec() == QDialog::Rejected)
		return false;
	setFrameWidth(frameDialog.frameWidth ());
	setFrameStyle(frameDialog.style());
	setFrameJoin (frameDialog.join ());
	qsAnimation = frameDialog.animation ();
	setAnimation ( qsAnimation );
	if (color() != frameDialog.color())	{
		// This emit signal is only caught when in ButtonDialog and the Selected, or Highlighted mask 
		// was changed (I.e. This Object is in one of those two frames).
		// Otherwise the signal is ignored.
		emit (signalMaskColorChanged(frameDialog.color(), color()));
		// P.s. replaceColor (QColor, QColor) of all ButtonObjects will be called, inclusive this object)
	}
	setFrameColor(frameDialog.color());
	int x, y, width, height;
	x      = frameDialog.m_pEditX->text().toInt();
	y      = frameDialog.m_pEditY->text().toInt();
	width  = frameDialog.m_pEditWidth->text().toInt();
	height = frameDialog.m_pEditHeight->text().toInt();
	QRect newRect (x, y, width, height);
	setRect (newRect);
	emit (signalUpdatePixmap());
	return false;
}

bool FrameObject::readProjectFile  (QDomNode &theNode)
{
	// Okay, here we retain the stored data from the xml file.
	QDomElement theElement = theNode.toElement();
	QDomAttr attribute;

	attribute = theElement.attributeNode ( FRAME_OBJECT_COLOR );
	if (!attribute.isNull())
		m_colorFrame = QColor(attribute.value());

	attribute = theElement.attributeNode ( FRAME_OBJECT_WIDTH );
	if (!attribute.isNull())
		m_iFrameWidth = attribute.value().toInt();

	attribute = theElement.attributeNode ( FRAME_OBJECT_STYLE);
	if (!attribute.isNull())
		m_iFrameStyle = attribute.value().toInt();

	attribute = theElement.attributeNode ( FRAME_OBJECT_JOIN );
	if (!attribute.isNull())
		m_iFrameJoin = attribute.value().toInt();

	MenuObject::readProjectFile( theNode );
	return true;
}

// <...>
// <FrameObject Color="#00FF00" Width="2" Style="1" Join="2">
//    <MenuObject>
//        <Modifiers>
//        </Modifiers>
//    </MenuObect>
// </FrameObject>
bool FrameObject::writeProjectFile (QDomElement &theElement)
{
	// First check if this node holds any information at all ...
//printf ("FrameObject::writeProjectFile <%s><%s>\n",(const char *)theElement.tagName(), (const char *)name());
	QDomDocument xmlDoc = theElement.ownerDocument();
	QDomElement frameNode = xmlDoc.createElement( FRAME_OBJECT );	// <FrameObject>
	// Here we set the attributes of the <dvdauthor> tag
	if (m_iFrameWidth != 4)
		frameNode.setAttribute( FRAME_OBJECT_WIDTH, m_iFrameWidth );
	if (m_colorFrame != QColor (START_FRAME_COLOR))
		frameNode.setAttribute( FRAME_OBJECT_COLOR, m_colorFrame.name() );
	if (m_iFrameStyle != (int)Qt::SolidLine)
		frameNode.setAttribute( FRAME_OBJECT_STYLE, m_iFrameStyle );
	if (m_iFrameJoin != (int)Qt::MiterJoin)
		frameNode.setAttribute( FRAME_OBJECT_JOIN,  m_iFrameJoin );

	theElement.appendChild( frameNode );
	// And here we write the base class ...
	return MenuObject::writeProjectFile( frameNode );
}

bool FrameObject::createContextMenu (QPoint globalPos)
{
        QString qsShadow;
        QPoint globalPos2 = globalPos;
	QPopupMenu *pStackMenu = new QPopupMenu(m_pParent);
	pStackMenu->insertItem ( tr ("Cut") , this, SLOT ( slotCut  ( ) ) );
	pStackMenu->insertItem ( tr ("Copy"), this, SLOT ( slotCopy ( ) ) );
	pStackMenu->insertSeparator();
	pStackMenu->insertItem ( tr ("To Front")  , this, SLOT(slotToFront ( ) ) );
	pStackMenu->insertItem ( tr ("To Back")   , this, SLOT(slotToBack  ( ) ) );
	globalPos.setY ( globalPos.y ( ) - 25 );
	globalPos.setX ( globalPos.x ( ) - pStackMenu->sizeHint ( ).width ( ) ); // -100);
	pStackMenu->popup(globalPos, 1);

	qsShadow = tr ( "Add Shadow ..." );
	if ( shadow ( ) )
 	   qsShadow = tr ( "Edit Shadow ..." );

	if (m_pContextMenu)
		delete m_pContextMenu;
	m_pContextMenu = new QPopupMenu(m_pParent);
	m_pContextMenu->insertItem ( tr ("Edit ...")  , this, SLOT(slotEdit       ( ) ) );
	m_pContextMenu->insertItem ( tr ("Matrix ..."), this, SLOT(slotMatrix     ( ) ) );
	m_pContextMenu->insertItem ( tr ("Delete")    , this, SLOT(slotDelete     ( ) ) );
	m_pContextMenu->insertSeparator();
	m_pContextMenu->insertItem ( qsShadow          , this, SLOT(slotAddShadow ( ) ) );
	m_pContextMenu->insertItem ( tr ("Add Text")   , this, SLOT(slotAddText   ( ) ) );
	m_pContextMenu->insertItem ( tr ("Add Image")  , this, SLOT(slotAddImage  ( ) ) );
	m_pContextMenu->insertItem ( tr ("Add Movie")  , this, SLOT(slotAddMovie  ( ) ) );
	m_pContextMenu->insertSeparator();
	m_pContextMenu->insertItem ( tr ("Define as Button") , this, SLOT(slotDefineAsButton()));
	m_pContextMenu->exec(globalPos2, 4);

	delete pStackMenu;
	if (m_pContextMenu)
		delete m_pContextMenu;
	m_pContextMenu = NULL;
	// Here we mark that the user called a menu item thus we don't want the
	// base classes to continue with the mouse event
//	if (iReturn != -1)
		return true;
}

void FrameObject::createStructure (QListViewItem *pParentItem)
{
	StructureItem *pFrameItem;
	StructureItem *pModifierItem;

	QString qsName ( tr("Frame (%1, %2, %3, %4)").
			 arg ( rect ( ).x      ( ) ).arg ( rect ( ).y      ( ) ).
			 arg ( rect ( ).width  ( ) ).arg ( rect ( ).height ( ) ) );
	//arg(m_colorFrame.red  ()).
	//arg(m_colorFrame.green()).
	//arg(m_colorFrame.blue ()));
	setName (qsName);

	qsName  = tr("Frame Object");
	QString qsInfo = QString ("%1 - (%2, %3, %4 %5)").arg ( width ( ) ).
	  arg ( rect ( ).x      ( ) ).arg ( rect ( ).y      ( ) ).
	  arg ( rect ( ).width  ( ) ).arg ( rect ( ).height ( ) );

	pFrameItem = new StructureItem(this, pParentItem, qsName, qsInfo);
	pFrameItem->setExpandable (TRUE);

	// And finally we create the modifiers info ...
	if ( !((m_modifiers.fRotate == 0.0) && (m_modifiers.fShearX == 0.0) && (m_modifiers.fShearY == 0.0) &&
		   (m_modifiers.fZoom   == 1.0) && (m_modifiers.fScaleX == 1.0) && (m_modifiers.fScaleY == 1.0)) )	{
	  pModifierItem = new StructureItem(this, pFrameItem, tr ("Modifiers"), NULL);
		pFrameItem->setExpandable (TRUE);

		new StructureItem(this, pModifierItem, tr ("Shear (x, y)"),
			QString ("%1, %2").arg(m_modifiers.fShearX).arg(m_modifiers.fShearY));
		new StructureItem(this, pModifierItem, tr ("Zoom"),
			QString ("%1").arg(m_modifiers.fZoom));
		new StructureItem(this, pModifierItem, tr ("Rotate"),
			tr ("%1 deg").arg(m_modifiers.fRotate));
	}
	if ( m_pShadow )
	     m_pShadow->createStructure ( pFrameItem );

	new StructureItem(this, pFrameItem, tr ("Frame Color"),
		tr ("color(%1, %2, %3)").
			arg(m_colorFrame.red()).
			arg(m_colorFrame.green()).
			arg(m_colorFrame.blue()));

	new StructureItem(this, pFrameItem, tr ("Frame Width"), QString ("%1").arg (width()));

	new StructureItem(this, pFrameItem, tr ("Geometry"),
		QString ("%1, %2, %3, %4").
		arg(rect().x()).arg(rect().y()).arg(rect().width()).arg(rect().height()));
}

void FrameObject::slotEdit()
{
	mouseDoubleClickEvent(NULL);
}

void FrameObject::slotMatrix()
{
	DialogMatrix *pDialog = new DialogMatrix(MenuObject::parent());
	pDialog->initMe(this);
	pDialog->show();
}

void FrameObject::slotAddText()
{
	MessageBox::warning (NULL, tr ("Not Implemented yet."), tr("Not Implemented yet."),
		QMessageBox::Ok ,  QMessageBox::Cancel);
}

void FrameObject::slotAddImage()
{
	MessageBox::warning (NULL, tr("Not Implemented yet."), tr("Not Implemented yet."),
		QMessageBox::Ok ,  QMessageBox::Cancel);
}

void FrameObject::slotAddMovie()
{
	MessageBox::warning (NULL, tr("Not Implemented yet."), tr("Not Implemented yet."),
		QMessageBox::Ok ,  QMessageBox::Cancel);
}

void FrameObject::slotDefineAsButton()
{
	emit (signalDefineAsButton(this));
}

MenuObject *FrameObject::clone ( QWidget *pParent )
{
  if ( !pParent )
    pParent = MenuObject::parent ( );

  FrameObject *pNewObject = new FrameObject ( pParent );
  pNewObject->setFrameWidth(width());
  pNewObject->setFrameStyle(style());
  pNewObject->setFrameJoin (join ());
  pNewObject->setFrameColor(color());
  
  // The following two are not really needed, since we get those
  // informations solely from the Normal State - objects ...
  pNewObject->setRect( rect ( ) );
  pNewObject->setModifiers ( *modifiers ( ) );
  
  MenuObject *pShadow = shadow ( );
  if ( pShadow )
    pShadow = pShadow->clone ( pNewObject, pParent );
  pNewObject->setShadow      (  pShadow   );
  
  return pNewObject;
}

AnimationAttribute *FrameObject::getSpecificAttributes (long iMaxNumberOfFrames, QString qsProperty)
{
	AnimationAttribute *pAnimAttr = NULL;
	if (qsProperty == "color.red")	{
		FunctionCallback<QColor> *callMeBack = new FunctionCallback<QColor>(m_colorFrame, TYPE_COLOR_RED);
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_colorFrame.red(), callMeBack);
	}
	else if (qsProperty == "color.green")	{
		FunctionCallback<QColor> *callMeBack = new FunctionCallback<QColor>(m_colorFrame, TYPE_COLOR_GREEN);
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_colorFrame.green(), callMeBack);
	}
	else if (qsProperty == "color.blue")	{
		FunctionCallback<QColor> *callMeBack = new FunctionCallback<QColor>(m_colorFrame, TYPE_COLOR_BLUE);
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_colorFrame.blue(), callMeBack);
	}
	else if (qsProperty == "frameWidth")
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_iFrameWidth, &m_iFrameWidth);
	else if (qsProperty == "frameStyle")
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_iFrameStyle, &m_iFrameStyle);
	else if (qsProperty == "frameJoin")
		pAnimAttr = new AnimationAttribute (iMaxNumberOfFrames, qsProperty, m_iFrameJoin, &m_iFrameJoin);
	return pAnimAttr;
}

