/***************************************************************************
 *   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.                                   *
 ***************************************************************************/

#ifndef CANVASITEMPARTS_H
#define CANVASITEMPARTS_H

#include <tqcanvas.h>
#include <tqguardedptr.h>
#include <tqslider.h>
#include <tqtoolbutton.h>

class Cells;
class CIWidgetMgr;
class CNItem;
class SliderWidget;
class ToolButton;
class TQString;

class GuiPart : public TQObject, public TQCanvasRectangle
{
	TQ_OBJECT
  
	public:
		/**
		 * Create a GuiPart. Control the position using setGuiPartSize, instead
		 * of calling TQCanvasRectangle::setSize. This allows GuiPart to know
		 * when its size has been changed
		 */
		GuiPart( CNItem *parent, const TQRect & r, TQCanvas * canvas );
		virtual ~GuiPart();
		
		virtual TQRect recommendedRect() const { return m_originalRect; }
		void setOriginalRect( const TQRect & r ) { m_originalRect = r; }
		
		virtual void updateConnectorPoints( bool add );
		
		/**
		 * Set the angle that the GuiPart draws itself (if the GuiPart chooses
		 * to use it by calling initPainter and deinitPainter from drawShape).
		 * Note that this doesn't affect the rectangle position that the
		 * GuiPart is in. The rotation is taken to be about the center of the
		 * rectangle.
		 */
		void setAngleDegrees( int angleDegrees );
		/**
		 * Control the size. Call this instead of TQCanvasRectangle::setSize. In
		 * turn, this function will notify subclasses via posChanged();
		 */
		void setGuiPartSize( int width, int height );
		/**
		 * Returns the rectangle to draw in to compensate for rotation of
		 * the TQPainter
		 */
		TQRect drawRect();
		
		int angleDegrees() const { return m_angleDegrees; }
		CNItem *parent() const { return p_parent; }
	
	protected:
		/**
		 * Called when the size or angle changes
		 */
		virtual void posChanged() {;}
		/**
		 * Rotate / etc the painter. You must call deinitPainter after
		 * calling this function.
		 */
		void initPainter( TQPainter & p );
		/**
		 * Complement function to initPainter - restores painter to normal
		 * transform
		 */
		void deinitPainter( TQPainter & p );
		int m_angleDegrees;
		CNItem *p_parent;
		bool b_pointsAdded;
		TQRect m_originalRect;
		
	private slots:
		void slotMoveBy( double dx, double dy );
};


/**
@short Stores internal information about text associated with CNItem
@author David Saxton
*/
class Text : public GuiPart
{
	TQ_OBJECT
  
	public:
		Text( const TQString &text, CNItem *parent, const TQRect & r, TQCanvas * canvas, int flags = TQt::AlignHCenter | TQt::AlignVCenter );
		~Text();
		
		/**
		 * Set the text, returning true if the size of this Text on the canvas
		 * has changed.
		 */
		bool setText( const TQString & text );
		virtual TQRect recommendedRect() const;
		virtual void drawShape ( TQPainter & p );
		/**
		 * The text flags (see TQPainter::drawText) - TQt::AlignmentFlags and
		 * TQt::TextFlags OR'd together.
		 */
		int flags() const { return m_flags; }
		/**
		 * @see flags
		 */
		void setFlags( int flags );
		
	protected:
		TQString m_text;
		int m_flags;
};
typedef TQMap<TQString, TQGuardedPtr<Text> > TextMap;


/**
@short Base class for embedding TQt Widgets into the canvas
@author David Saxton
*/
class Widget : public GuiPart
{
	public:
		Widget( const TQString & id, CNItem *parent, const TQRect & r, TQCanvas * canvas );
		~Widget();
		
		virtual int rtti() const;
		
		virtual TQWidget *widget() const = 0;
		TQString id() const { return m_id; }
		
		/**
		 * Set the widget enabled/disabled
		 */
		void setEnabled( bool enabled );
		
		virtual void enterEvent() {};
		virtual void leaveEvent() {};
		
		/**
		 * Mouse was pressed. pos is given relative to CNItem position.
		 */
		virtual void mousePressEvent( TQMouseEvent *e ) { Q_UNUSED(e); }
		/**
		 * Mouse was released. pos is given relative to CNItem position.
		 */
		virtual void mouseReleaseEvent( TQMouseEvent *e ) { Q_UNUSED(e); }
		/**
		 * Mouse was double clicked. pos is given relative to CNItem position.
		 */
		virtual void mouseDoubleClickEvent( TQMouseEvent *e ) { Q_UNUSED(e); }
		/**
		 * Mouse was moved. pos is given relative to CNItem position.
		 */
		virtual void mouseMoveEvent( TQMouseEvent *e ) { Q_UNUSED(e); }
		/**
		 * Mouse was scrolled. pos is given relative to CNItem position.
		 */
		virtual void wheelEvent( TQWheelEvent *e ) { Q_UNUSED(e); }
		
		virtual void drawShape( TQPainter &p );
	
	protected:
		virtual void posChanged();
		TQString m_id;
};


class ToolButton : public TQToolButton
{
	public:
		ToolButton( TQWidget* parent );
		
		virtual void mousePressEvent( TQMouseEvent *e ) { TQToolButton::mousePressEvent(e); }
		virtual void mouseReleaseEvent( TQMouseEvent *e ) { TQToolButton::mouseReleaseEvent(e); }
		virtual void mouseDoubleClickEvent ( TQMouseEvent *e ) { TQToolButton::mouseDoubleClickEvent(e); }
		virtual void mouseMoveEvent( TQMouseEvent *e ) { TQToolButton::mouseMoveEvent(e); }
		virtual void wheelEvent( TQWheelEvent *e ) { TQToolButton::wheelEvent(e); }
		virtual void enterEvent() { TQToolButton::enterEvent(0l); }
		virtual void leaveEvent() { TQToolButton::leaveEvent(0l); }
		
		void setAngleDegrees( int angleDegrees ) { m_angleDegrees = angleDegrees; }
		
	protected:
		virtual void drawButtonLabel( TQPainter * p );
		
		int m_angleDegrees;
		TQFont m_font;
};


/**
@short Stores internal information about button associated with CNItem
@author David Saxton
*/
class Button : public Widget
{
	TQ_OBJECT
  
	public:
		Button( const TQString & id, CNItem *parent, bool isToggle, const TQRect & r, TQCanvas * canvas );
		~Button();
		
		virtual void mousePressEvent( TQMouseEvent *e );
		virtual void mouseReleaseEvent( TQMouseEvent *e );
		virtual void enterEvent();
		virtual void leaveEvent();
		
		/**
		 * Set the text displayed inside the button
		 */
		void setText( const TQString &text );
		void setToggle( bool toggle );
		bool isToggle() const { return b_isToggle; }
		virtual TQWidget *widget() const;
		bool state() const;
		void setPixmap( const TQPixmap & );
		void setState( bool state );
		virtual TQRect recommendedRect() const;
		
	protected:
		virtual void posChanged();
		
	private slots:
		void slotStateChanged();
		
	private:
		bool b_isToggle; // i.e. whether it should be depressed when the mouse is released
		ToolButton *m_button;
};
	
	
class SliderWidget : public TQSlider
{
	public:
		SliderWidget( TQWidget* parent );
	
		virtual void mousePressEvent( TQMouseEvent *e ) { TQSlider::mousePressEvent(e); }
		virtual void mouseReleaseEvent( TQMouseEvent *e ) { TQSlider::mouseReleaseEvent(e); }
		virtual void mouseDoubleClickEvent ( TQMouseEvent *e ) { TQSlider::mouseDoubleClickEvent(e); }
		virtual void mouseMoveEvent( TQMouseEvent *e ) { TQSlider::mouseMoveEvent(e); }
		virtual void wheelEvent( TQWheelEvent *e ) { TQSlider::wheelEvent(e); }
		virtual void enterEvent() { TQSlider::enterEvent((TQEvent*)0l); }
		virtual void leaveEvent() { TQSlider::leaveEvent((TQEvent*)0l); }
};
	
	
/**
@short Stores internal information about a TQSlider associated with CNItem
@author David Saxton
*/
class Slider : public Widget
{
	TQ_OBJECT
  
	public:
		Slider( const TQString & id, CNItem *parent, const TQRect & r, TQCanvas * canvas );
		~Slider();
		
		virtual void mousePressEvent( TQMouseEvent *e );
		virtual void mouseReleaseEvent( TQMouseEvent *e );
		virtual void mouseDoubleClickEvent ( TQMouseEvent *e );
		virtual void mouseMoveEvent( TQMouseEvent *e );
		virtual void wheelEvent( TQWheelEvent *e );
		virtual void enterEvent();
		virtual void leaveEvent();
		
		virtual TQWidget *widget() const;
		int value() const;
		void setValue( int value );
		void setOrientation( TQt::Orientation o );
		
	protected:
		virtual void posChanged();
		
	private slots:
		void slotValueChanged( int value );
		
	private:
		SliderWidget *m_slider;
		TQt::Orientation m_orientation;
};
	
#endif
	
