/***************************************************************************
 *   Copyright (C) 2003-2005 by David Saxton                               *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "canvasitemparts.h"
#include "cells.h"
#include "cnitem.h"
#include "icndocument.h"

#include <tqpainter.h>


//BEGIN Class GuiPart
GuiPart::GuiPart( CNItem *parent, const TQRect & r, TQCanvas * canvas )
	: TQObject(parent),
	TQCanvasRectangle( r, canvas ),
	m_angleDegrees(0),
	p_parent(parent),
	b_pointsAdded(false),
	m_originalRect(r)
{
	connect( parent, TQT_SIGNAL(movedBy(double, double )), this, TQT_SLOT(slotMoveBy(double, double )) );
	setZ( parent->z() + 0.5 );
}


GuiPart::~GuiPart()
{
	hide();
}


void GuiPart::setAngleDegrees( int angleDegrees )
{
	m_angleDegrees = angleDegrees;
	posChanged();
	if (canvas())
		canvas()->setChanged( boundingRect() );
}


void GuiPart::setGuiPartSize( int width, int height )
{
	updateConnectorPoints(false);
	setSize( width, height );
	posChanged();
}


void GuiPart::initPainter( TQPainter &p )
{
	if ( (m_angleDegrees%180) == 0 )
		return;
	
	p.translate( int(x()+(width()/2)), int(y()+(height()/2)) );
	p.rotate(m_angleDegrees);
	p.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) );
}


void GuiPart::deinitPainter( TQPainter &p )
{
	if ( (m_angleDegrees%180) == 0 )
		return;
	
	p.translate( int(x()+(width()/2)), int(y()+(height()/2)) );
	p.rotate(-m_angleDegrees);
	p.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) );
}


void GuiPart::slotMoveBy( double dx, double dy )
{
	if ( dx==0 && dy==0 )
		return;
	
	moveBy( dx, dy );
	posChanged();
}


void GuiPart::updateConnectorPoints( bool add )
{
	ICNDocument *icnd = dynamic_cast<ICNDocument*>(p_parent->itemDocument());
	if ( !icnd)
		return;
	
	Cells * cells = icnd->cells();
	if (!cells)
		return;
	
	if ( add == b_pointsAdded )
		return;
	
	b_pointsAdded = add;
	
	int mult = add ? 1 : -1;
	int sx = int(x()/8);
	int sy = int(y()/8);
	int ex = int((x()+width())/8);
	int ey = int((y()+height())/8);
	
	for ( int x=sx; x<=ex; ++x )
	{
		for ( int y=sy; y<=ey; ++y )
		{
			if ( icnd->isValidCellReference( x, y ) )
				(*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item/2;
		}
	}
}


TQRect GuiPart::drawRect()
{
	TQRect dr = rect();
	if ( m_angleDegrees%180 != 0 )
	{
		TQWMatrix m;
		m.translate( int(x()+(width()/2)), int(y()+(height()/2)) );
	
		if ( (m_angleDegrees%180) != 0 )
			m.rotate(-m_angleDegrees);
		
		m.translate( -int(x()+(width()/2)), -int(y()+(height()/2)) );
		
		dr = m.mapRect(dr);
	}
	return dr;
}
//END Class GuiPart



//BEGIN Class Text
Text::Text( const TQString &text, CNItem *parent, const TQRect & r, TQCanvas * canvas, int flags )
	: GuiPart( parent, r, canvas )
{
	m_flags = flags;
	setText(text);
}


Text::~Text()
{
}


bool Text::setText( const TQString & text )
{
	if ( m_text == text )
		return false;
	
	updateConnectorPoints(false);
	
	m_text = text;
	return true;
}


void Text::setFlags( int flags )
{
	updateConnectorPoints( false );
	m_flags = flags;
}


void Text::drawShape( TQPainter & p )
{
	initPainter(p);
	p.setFont( p_parent->font() );
	p.drawText( drawRect(), m_flags, m_text );
	deinitPainter(p);
}


TQRect Text::recommendedRect() const
{
	return TQFontMetrics( p_parent->font() ).boundingRect( m_originalRect.x(), m_originalRect.y(), m_originalRect.width(), m_originalRect.height(), m_flags, m_text );
}
//END Class Text



//BEGIN Class Widget
Widget::Widget( const TQString & id, CNItem * parent, const TQRect & r, TQCanvas * canvas )
	: GuiPart( parent, r, canvas )
{
	m_id = id;
	show();
}

Widget::~Widget()
{
}


int Widget::rtti() const
{
	return ItemDocument::RTTI::Widget;
}


void Widget::setEnabled( bool enabled )
{
	widget()->setEnabled(enabled);
}


void Widget::posChanged()
{
	// Swap around the width / height if we are rotated at a non-half way around
	if ( m_angleDegrees%90 != 0 )
		widget()->setFixedSize( TQSize( height(), width() ) );
	else
		widget()->setFixedSize( size() );
	
	widget()->move( int(x()), int(y()) );
}


void Widget::drawShape( TQPainter &p )
{
// 	initPainter(p);
	p.drawPixmap( int(x()), int(y()), TQPixmap::grabWidget( widget() ) );
// 	deinitPainter(p);
}
//END Class Widget


//BEGIN Class ToolButton
ToolButton::ToolButton( TQWidget *parent )
	: TQToolButton(parent)
{
	m_angleDegrees = 0;
	if ( TQFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size
		m_font.setPixelSize(12);
}


void ToolButton::drawButtonLabel( TQPainter * p )
{
	if ( m_angleDegrees % 180 == 0 || text().isEmpty() )
	{
		TQToolButton::drawButtonLabel(p);
		return;
	}
	
	double dx = size().width()/2;
	double dy = size().height()/2;
	
	p->translate( dx, dy );
	p->rotate( m_angleDegrees );
	p->translate( -dx, -dy );
	
	p->translate( -dy+dx, 0 );
	
	int m = width() > height() ? width() : height();
	
	p->setPen( TQt::black );
	p->drawText( isDown()?1:0, isDown()?1:0, m, m, TQt::AlignVCenter | TQt::AlignHCenter, text() );
	
	p->translate( dy-dx, 0 );
	
	p->translate( dx, dy );
	p->rotate( -m_angleDegrees );
	p->translate( -dx, -dy );
}
//END Class ToolButton


//BEGIN Class Button
Button::Button( const TQString & id, CNItem * parent, bool isToggle, const TQRect & r, TQCanvas * canvas )
	: Widget( id, parent, r, canvas )
{
	b_isToggle = isToggle;
	m_button = new ToolButton(0l);
	m_button->setUsesTextLabel(false);
	m_button->setToggleButton(b_isToggle);
	connect( m_button, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotStateChanged()) );
	connect( m_button, TQT_SIGNAL(released()), this, TQT_SLOT(slotStateChanged()) );
	posChanged();
}


Button::~Button()
{
	delete m_button;
}


void Button::setToggle( bool toggle )
{
	if ( b_isToggle == toggle )
		return;
	
	if (b_isToggle)
	{
		// We must first untoggle it, else it'll be forever stuck...
		setState(false);
	}
	
	b_isToggle = toggle;
	m_button->setToggleButton(b_isToggle);
}


void Button::posChanged()
{
	Widget::posChanged();
	m_button->setAngleDegrees(m_angleDegrees);
}

void Button::slotStateChanged()
{
	parent()->buttonStateChanged( id(), m_button->isDown() || m_button->isOn() );
}
TQWidget* Button::widget() const
{
	return m_button;
}
void Button::setPixmap( const TQPixmap &p )
{
	m_button->setPixmap(p);
}
void Button::setState( bool state )
{
	if ( this->state() == state )
		return;
	
	if ( isToggle() )
		m_button->setOn(state);
	else
		m_button->setDown(state);
	
	slotStateChanged();
}
bool Button::state() const
{
	if ( isToggle() )
		return m_button->state();
	else
		return m_button->isDown();
}


TQRect Button::recommendedRect() const
{
	TQSize sizeHint = m_button->sizeHint();
	if ( sizeHint.width() < m_originalRect.width() )
		sizeHint.setWidth( m_originalRect.width() );
	
	// Hmm...for now, lets just keep the recomended rect the same height as the original rect
	sizeHint.setHeight( m_originalRect.height() );
	
	int hdw = (sizeHint.width() - m_originalRect.width())/2;
	int hdh = (sizeHint.height() - m_originalRect.height())/2;
	
	return TQRect( m_originalRect.x()-hdw, m_originalRect.y()-hdh, sizeHint.width(), sizeHint.height() );
}


void Button::setText( const TQString &text )
{
	if ( m_button->text() == text )
		return;
	
	updateConnectorPoints(false);
	
	m_button->setUsesTextLabel(true);
	m_button->setText(text);
	m_button->setTextLabel(text);
	canvas()->setChanged( rect() );
	p_parent->updateAttachedPositioning();
}


void Button::mousePressEvent( TQMouseEvent *e )
{
	if ( !m_button->isEnabled() )
		return;
	
	TQMouseEvent event( TQEvent::MouseButtonPress, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_button->mousePressEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}


void Button::mouseReleaseEvent( TQMouseEvent *e )
{
	TQMouseEvent event( TQEvent::MouseButtonRelease, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_button->mouseReleaseEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}


void Button::enterEvent()
{
	m_button->enterEvent();
// 	m_button->setFocus();
// 	bool hasFocus = m_button->hasFocus();
// 	m_button->setAutoRaise(true);
// 	m_button->setOn(true);
}

void Button::leaveEvent()
{
	m_button->leaveEvent();
// 	m_button->clearFocus();
// 	bool hasFocus = m_button->hasFocus();
// 	m_button->setAutoRaise(false);
// 	m_button->setOn(false);
}
//END Class Button


//BEGIN Class SliderWidget
SliderWidget::SliderWidget( TQWidget *parent )
	: TQSlider(parent)
{
	setWFlags(WNoAutoErase|WRepaintNoErase);
}
//END Class SliderWidget


//BEGIN Class Slider
Slider::Slider( const TQString & id, CNItem * parent, const TQRect & r, TQCanvas * canvas )
	: Widget( id, parent, r, canvas )
{
	m_orientation = Qt::Vertical;
	m_slider = new SliderWidget(0l);
	m_slider->setPaletteBackgroundColor(TQt::white);
	m_slider->setPaletteForegroundColor(TQt::white);
	m_slider->setEraseColor(TQt::white);
	m_slider->setBackgroundMode( TQt::NoBackground );
	connect( m_slider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotValueChanged(int)) );
	posChanged();
}


Slider::~Slider()
{
	delete m_slider;
}


TQWidget* Slider::widget() const
{
	return m_slider;
}


int Slider::value() const
{
	return m_slider->value();
}

void Slider::setValue( int value )
{
	m_slider->setValue(value);
}

 
void Slider::mousePressEvent( TQMouseEvent *e )
{
	TQMouseEvent event( TQEvent::MouseButtonPress, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_slider->mousePressEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}

void Slider::mouseReleaseEvent( TQMouseEvent *e )
{
	TQMouseEvent event( TQEvent::MouseButtonRelease, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_slider->mouseReleaseEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}

void Slider::mouseDoubleClickEvent ( TQMouseEvent *e )
{
	TQMouseEvent event( TQEvent::MouseButtonDblClick, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_slider->mouseDoubleClickEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}

void Slider::mouseMoveEvent( TQMouseEvent *e )
{
	TQMouseEvent event( TQEvent::MouseMove, e->pos()-TQPoint(int(x()),int(y())), e->button(), e->state() );
	m_slider->mouseMoveEvent(&event);
	if (event.isAccepted())
		e->accept();
}

void Slider::wheelEvent( TQWheelEvent *e )
{
	TQWheelEvent event( e->pos()-TQPoint(int(x()),int(y())), e->delta(), e->state(), e->orientation() );
	m_slider->wheelEvent(&event);
	if (event.isAccepted())
		e->accept();
	canvas()->setChanged( rect() );
}

void Slider::enterEvent()
{
	m_slider->enterEvent();
}

void Slider::leaveEvent()
{
	m_slider->leaveEvent();
}

void Slider::slotValueChanged( int value )
{
	parent()->itemDocument()->setModified(true);
	parent()->sliderValueChanged(id(),value);
}

void Slider::setOrientation( Qt::Orientation o )
{
	m_orientation = o;
	posChanged();
}

void Slider::posChanged()
{
	Widget::posChanged();
	
	if ( m_orientation == Qt::Vertical )
		m_slider->setOrientation( (m_angleDegrees%180 == 0) ? Qt::Vertical : Qt::Horizontal );
	
	else
		m_slider->setOrientation( (m_angleDegrees%180 == 0) ? Qt::Horizontal : Qt::Vertical );
}
//END Class Slider


#include "canvasitemparts.moc"
