  
//**************************************************************************/
// Copyright (c) 2008 Autodesk, Inc.
// All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
//
//**************************************************************************/
// DESCRIPTION:
// CREATED: October 2008
//**************************************************************************/

#ifndef __MUDBOXSDK_WIDGETS_H__
#define __MUDBOXSDK_WIDGETS_H__
#pragma once

// In order to create custom gui for your plugins, you need to install the Qt library. 
// Classes in this file are valid only when Qt is properly installed
#include <QtCore/QObject>
#include <QtCore/QFileInfo>
#include <QtGui/QWidget>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QCheckBox>
#include <QtGui/QPushButton>
#include <QtGui/QSlider>
#include <QtGui/QMouseEvent>
#include <QtGui/QSpinBox>
#include <QtGui/QComboBox>
#include <QtGui/QGroupBox>
#include <QtGui/QFrame>
#include <QtGui/QToolButton>

#if defined(JAMBUILD)
#include <Mudbox/mudbox.h>
#else
#include "mudbox.h"
#endif          

namespace mudbox
{
	class MBDLL_DECL AttributeSign : public QLabel
	{
		Q_OBJECT
		class AttributeWidget *m_pOwner;
		void mousePressEvent( QMouseEvent *pEvent );
		void dragEnterEvent( QDragEnterEvent *pEvent );
		void dropEvent( QDropEvent *pEvent );
		void SetImage( const QString &sFileName );

	public:
		AttributeSign( class AttributeWidget *pOwner );
		void UpdateImage( void );
	};

	class MBDLL_DECL AttributeWidget : public QWidget, public Node
	{
		Attribute *m_pAttribute;
		Node *m_pNode;
		int m_iNodeID;
		AttributeWatch m_cWatcher;
		QSize sizeHint( void ) const;
		bool m_bDestructed;	// HACK

	protected:
		void OnNodeEvent( const Attribute &cAttribute, NodeEventType eType );
		QLabel m_cLabel;
		float m_fLabelWidth;
		int m_iHeight;
		bool m_bLeftAlignedName;

	public:
		AttributeWidget( QWidget *pParent, int iWidth, Attribute *pAttribute );
		~AttributeWidget( void );
		bool Validate( void );
		virtual void Update( void ) {};
		virtual void MoveValue( int /*iStart*/, int /*iEnd*/ ) {};
		virtual void MoveContent( int iStart, int iEnd, bool bVisibleValue );
		virtual void ChangeWidth( int iWidth, bool bVisibleValue );
		inline Attribute *GetAttribute( void ) const { return m_pAttribute; };
		inline Node *GetNode( void ) const { return m_pNode; };
	};

	class MBDLL_DECL AttributeVectorbox : public AttributeWidget
	{
		Q_OBJECT

	protected:
		void Update( void );
		void MoveValue( int iStart, int iEnd );             
		QLineEdit m_cXBox, m_cYBox, m_cZBox;

	public:
		AttributeVectorbox( QWidget *pParent, int iWidth, avector *pAttribute );

	public slots:
		void OnChange( void );
	};

	/// A widget used to display and alter the value for a four dimensional vector attribute.
	class MBDLL_DECL AttributeVector4box : public AttributeWidget
	{
		Q_OBJECT

	protected:
		void Update( void );
		void MoveValue( int iStart, int iEnd );
		QLineEdit m_cXBox, m_cYBox, m_cZBox, m_cWBox;

	public:
		AttributeVector4box( QWidget *pParent, int iWidth, avector4 *pAttribute );

		public slots:
			void OnChange( void );
	};

	class MBDLL_DECL AttributeEditbox : public AttributeWidget
	{
		Q_OBJECT

	protected:
		void Update( void );
		void MoveValue( int iStart, int iEnd );
		QLineEdit m_cEditbox;

	public:
		AttributeEditbox( QWidget *pParent, int iWidth, Attribute *pAttribute );

	public slots:
		void OnChange( void );
	};

	/// A widget used to display and alter the value for an image attribute.
	class MBDLL_DECL AttributeImagebox : public AttributeWidget
	{
		Q_OBJECT
		void MoveValue( int iStart, int iEnd );
		void Update( void );
		void OnNodeEvent( const Attribute &cAttribute, NodeEventType eType );

		unsigned int m_iWidth;

	protected:
		QLabel m_cLabel;

	public:
		AttributeImagebox( QWidget *pParent, int iWidth, AttributePointer<Image> *pImage );
	};

	/// A widget which is used to display and alter the value for a bool attribute
	class MBDLL_DECL AttributeCheckbox : public AttributeWidget
	{
		Q_OBJECT
		bool m_bLock;
		void MoveValue( int iStart, int iEnd);
		void Update( void );

	protected:
		QCheckBox m_cCheckbox;

	public:
		AttributeCheckbox( QWidget *pParent, int iWidth, abool *pAttribute );

	public slots:
		void OnChange( int iState );
	};

	class MBDLL_DECL AttributeColorbox : public AttributeWidget
	{
		Q_OBJECT
		void MoveValue( int iStart, int iEnd );

	protected:
		void Update( void );

	public:
		AttributeColorbox( QWidget *pParent, int iWidth, acolor *pAttribute );

	public slots:
		void OnAboutToShowChooser(QColor* color);
		void OnColorChanged(const QColor&);

	public:
		static QWidget* CreateColorButton(const QColor& color, QWidget* parent, Attribute *pAttribute);
	};

	/// A widget which used to display and alter the value for a float range attribute.
	class MBDLL_DECL AttributeSliderbox : public AttributeEditbox
	{
		class Slider : public QSlider
		{
			void mouseDoubleClickEvent( QMouseEvent *pEvent )
			{
				if ( m_pOwner )
				{
					afloatr* pA = (afloatr *)m_pOwner->GetAttribute();
					if ( pEvent->button() == Qt::LeftButton )
						pA->SetMax( pA->Value() );
					if ( pEvent->button() == Qt::RightButton )
						pA->SetMin( pA->Value() );
					setValue( (int)(1000*(pA->Value()-pA->Min())/(pA->Max()-pA->Min())) );
				};
			};
		public:
			Slider( QWidget *pParent ) : QSlider( pParent ) { m_pOwner = 0; };
			AttributeSliderbox *m_pOwner;
		};
		Q_OBJECT
		bool m_bLock, m_bSliderLock;
		void MoveValue( int iStart, int iEnd );

	protected:
		void Update( void );
		Slider m_cSlider;

	public:
		AttributeSliderbox( QWidget *pParent, int iWidth, afloatr *pAttribute );

	public slots:
		void OnMove( int );
	};

	class MBDLL_DECL AttributeSpinbox : public AttributeWidget
	{
		struct SpinBox : public QSpinBox
		{
			SpinBox( QWidget *pParent, int iDigitCount ) : QSpinBox( pParent )
			{
				m_iDigitCount = iDigitCount;
			};
		private:
			QString textFromValue ( int v ) const
			{
				QString s = QString::number( v );
				while ( s.length() < m_iDigitCount )
					s = "0"+s;
				return s;
			};
			int m_iDigitCount;
		};
		Q_OBJECT
		void MoveValue( int iStart, int iEnd );

	protected:
		SpinBox m_cSpin;
		bool m_bLock;
		void Update( void );

	public:
		AttributeSpinbox( QWidget *pParent, int iWidth, aint *pAttribute, int iSpinWidth = 40, int iDigitCount = 1 );

	public slots:
		void OnChange( int );
	};

	/// A widget used to display and alter the value for an enum attribute.
	class MBDLL_DECL AttributeCombobox : public AttributeWidget
	{
		Q_OBJECT
		bool m_bLock;

	protected:
		void MoveValue( int iStart, int iEnd );
		void Update( void );
		QComboBox m_cCombo;

	public:
		AttributeCombobox( QWidget *pParent, int iWidth, aenum *pAttribute );

	public slots:
		void OnChange( int );	
	};

	/// A widget used to display and alter the value for a filename attribute.
	class MBDLL_DECL AttributeFilenamebox : public AttributeEditbox
	{
		Q_OBJECT
		void MoveValue( int iStart, int iEnd );

	protected:
		QPushButton m_cBrowseButton;

	public:
		AttributeFilenamebox( QWidget *pParent, int iWidth, afilename *pAttribute );

	public slots:
		void OnBrowse( void );
	};

	/// A widget which is used to display and alter the value for a texture attribu
	class MBDLL_DECL AttributeTextureFilenamebox : public AttributeFilenamebox
	{
		Q_OBJECT

	public:
		AttributeTextureFilenamebox( QWidget *pParent, int iWidth, afilename *pAttribute );

	public slots:
		void OnMenu( void );
		void OnSave( void );
	};

	class MBDLL_DECL AttributeEventbox : public AttributeWidget
	{
		Q_OBJECT
		void MoveContent( int iStart, int iEnd, bool bVisibleValue );

	protected:
		QPushButton m_cButton;

	public:
		AttributeEventbox( QWidget *pParent, int iWidth, EventGate *pAttribute );

	public slots:
		void OnAction( void );
	};

	/// A widget used to display and alter the value for a pointer attribute.
	class MBDLL_DECL AttributePointerbox : public AttributeWidget
	{
		Q_OBJECT
		bool m_bLock;
		bool m_bNullStringInserted;
		void MoveValue( int iStart, int iEnd );

	protected: QComboBox m_cCombo; const ClassDesc *m_pType; void Update( void );
	public: AttributePointerbox( QWidget *pParent, int iWidth, Attribute *pAttribute, const ClassDesc *pClass );
	public slots: void OnChange( int );
	};

	/// A widget used to display and alter the value for a bool collection attribute.
	class MBDLL_DECL AttributeCheckboxCollection : public AttributeWidget
	{
		Q_OBJECT
		QCheckBox *m_aCheckboxes[32];
		QWidget m_cValues;
		void MoveValue( int iStart, int iEnd );
		void Update( void );

	public:
		AttributeCheckboxCollection( QWidget *pParent, int iWidth, aboolc *pAttribute );

	public slots:
		void OnChange( int iState );
	};

	/// A widget which is used to display and alter the value for a bool attribute
	class MBDLL_DECL AttributeSliderWithCheckbox : public AttributeWidget
	{
		Q_OBJECT
		bool m_bLock;
		void Update( void );

	protected:
		QLabel *m_pLabel;
		QSlider *m_pSlider;
		QLineEdit *m_pEditBox;
		QGroupBox m_cGroupBox;

	public:
		AttributeSliderWithCheckbox( QWidget *pParent, int iWidth, acheckablefloat *pAttribute );

	public slots:
		void OnChange( void );
	};

	class MBDLL_DECL CPBox : public QWidget
	{
		Q_OBJECT
	public:
		CPBox( int iIndex, QWidget *pParent = 0, const char *sName = 0 );
		bool m_bSelected;
		int m_iIndex;

	protected:
		void contextMenuEvent( QContextMenuEvent *pEvent );
		void mousePressEvent( QMouseEvent *pEvent );
		QSize sizeHint( void ) const;
		void paintEvent( QPaintEvent *pEvent );
	};

	class MBDLL_DECL CurveEditor : public QFrame
	{
		Q_OBJECT
	public:
		CurveEditor( QWidget *pParent = 0, const char *sName = 0, bool bNurbs = false );
		void SelectCP( CPBox *pCP );
		void DeleteCP( void );
		void AddCP( float x, float y );
		void Init( void *pCurve = 0 );
		int m_iSnapDistance;
		static bool s_bSnap;
		bool m_bReadOnly, m_bNurbs;
		float m_fGridSizeX, m_fGridSizeY;
		void *m_pCurve;

	protected:
		QSize sizeHint( void ) const;
		void paintEvent( QPaintEvent *pe );
		void resizeEvent( QResizeEvent *pEvent );
		void mousePressEvent( QMouseEvent *pEvent );
		void mouseReleaseEvent( QMouseEvent *pEvent );
		void mouseMoveEvent( QMouseEvent *pEvent );
		void contextMenuEvent( QContextMenuEvent *pEvent );
	//	void mousePressEvent( QMouseEvent *pEvent );
		int CanvasToScreenX( float f );
		int CanvasToScreenY( float f );
		float ScreenToCanvasX( int i );
		float ScreenToCanvasY( int i );
		int m_iCanvasWidth, m_iCanvasHeight;
		CPBox *m_aBoxes[16];
		CPBox *m_pSelectedBox;
		class Vector m_vDragDistance;
	};

	class MBDLL_DECL AttributeCurveEditor : public AttributeWidget
	{
		Q_OBJECT

	protected:
		QPushButton *m_pStoreF;
		CurveEditor *m_pCurveEditor;
		bool eventFilter( QObject *pTarget, QEvent *pEvent );

	public:
		AttributeCurveEditor( QWidget *pParent, int iWidth, acurveptr *pAttribute );

	public slots:
		void OnChange( void );
		void Update( void );
	};

	class MBDLL_DECL AttributeStampConfigurationWidget : public AttributeWidget
	{
		Q_OBJECT

	protected:
		void UpdateImage( void );
        bool LoadImage(const QString &imgFileName);

        QImage        m_CachedImage;
        QString       m_CachedImageFileName;

		QGroupBox     m_cGroupBox;
		QLabel       *m_pPreviewImage;
		QGroupBox    *m_pRandomize;
		QToolButton  *m_pOrientToStroke; 
        QToolButton  *m_pRotateStamp; 
        QToolButton  *m_pFlipXStamp; 
        QToolButton  *m_pFlipYStamp;
		QSlider      *m_pRotateRandomize; 
        QSlider      *m_pPositionXRandomize; 
        QSlider      *m_pPositionYRandomize; 
        QSlider      *m_pScaleRandomize; 
        QSlider      *m_pStrengthRandomize;
		QCheckBox    *m_pFlipRandomize;
        QCheckBox    *m_pFlopRandomize;
		bool          m_bUpdating;

	public:
		AttributeStampConfigurationWidget( QWidget *pParent, int iWidth, astampcfg *pAttribute );

	public slots:
		void Update( void );
		void OnChange( void );
		void OnRotate( void );
	};
	
	
	/// \brief MirrorComboBox is a QComboBox that emits a signal when it loses keyboard focus.
	///
	/// This is useful when creating menus (such as the Mirror Mode menu found in the property
	/// window of several tools) that provide previews as the user scrolls through them.
	class MirrorComboBox : public QComboBox
	{
		Q_OBJECT
	public:
		/// Constructor (the same as QComboBox)
		MirrorComboBox(QWidget * parent = 0, const char * name = 0)
		:QComboBox(parent){ setObjectName(name); }
		
		/// Destructor
		~MirrorComboBox(){}
		
	signals:
		/// This signal is emitted when the MirrorComboBox loses keyboard focus.
		/// The value of its parameter is always 0.
		void departed(int);
		
	protected:
		/// This QWidget method is overridden here to emit the "departed" signal.
		void focusOutEvent ( QFocusEvent * )
		{
			emit departed(0);
		}
	};
	

	/// An attribute widget for setting the brush mirror mode
	class MBDLL_DECL AttributeMirrorConfigurationWidget : public AttributeWidget
	{
		Q_OBJECT
	public:
		/// Constructor
		AttributeMirrorConfigurationWidget( QWidget *pParent, int iWidth, amirrorcfg *pAttribute );

	protected:
		/// Prevents unnecessary window updates.
		bool m_bLock;
		/// Changes the position of the combobox
		void MoveValue( int iStart, int iEnd );
		/// Updates the widget values from the attribute
		void Update( void );
		/// The combo box to display mirror modes
		MirrorComboBox m_cCombo;
	public slots:
		/// This method is called when the user selects a new item in the combobox
		void OnChange( int );	
		/// This method is called when the user is scrolling through the menu choices,
		/// to display a preview of the mirroring axis.
		void ShowMirrorAxis( int );
	};
};

#endif
