/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:		$Id: widgeteditor.h,v 1.21 2001/03/14 13:48:11 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas (alex@soften.ktu.lt)
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifndef __WIDGETVIEW_G__
#define __WIDGETVIEW_G__

#include "wx/pmf/pm.h"

#include "dmcmn.h"

#include "XObject.h"
#include "ui_lookrenderer.h"
#include "res_templ.h"
#include "res_doc.h"
#include "eq_solver.h"

#include "wx/hash.h"
#include "wx/listbox.h"
#include "wx/choice.h"

class XCollection;
class XGenericEditorHandler;
class XCommandManager;
class MyXCommandMgr;

class wxDMNodePropertyPanel;

class WidgetDocument;
class WidgetView;

class WidgetNode;
class WidgetGlyph;

// solver specialized for quick lookup of variables as 
// properties of the given attribute-group

class WidgetEqSolver : public EqSolver
{
public:
	WidgetEqSolver();

	void Init( wxDMAttrGroupInfo* pGroup, void* pGroupData, 
			   const wxString& uiType, WidgetResTemplate* pTempl );

	// overriden method of EqSovler
	virtual EqSolverVar* FindVar( const wxString& name );

protected:
	EqSolverVar* GetVarForValue( const wxString& value );

protected:
	wxDMAttrGroupInfo* mpGroup;
	WidgetResTemplate* mpTempl;
	void*			   mpGroupData;
	EqSolverVar		   mVarsRibbon[5]; // "round-ribbon"
	size_t			   mCurVarIdx;
	wxString		   mUIType;
};

class WidgetDocument : public ResItemDocumentBase
{
public:
	WidgetDocument();
	~WidgetDocument();

	// overriden methods of wxPMDocument
	virtual bool CanHaveFile();
	virtual bool SavePMDocument();
	virtual bool LoadPMDocument();

	// used for previewing the result
	virtual bool SaveResToTempFile( const wxString& fname );

	virtual bool IsModified() const;
	virtual void Modify(bool modify);

	// overriden methods of ResItemDocumentBase

	void SetRootNode( wxDMNode* pRoot );
	wxDMNode* GetRootNode();

	WidgetResTemplate* GetTemplateForNode( wxDMNode& node );

	// other methods

	virtual WidgetNode* InsertWidgetByCode( int code, 
											WidgetNode* pTarget, 
											const XPoint& pos,
											int zOrder );

	virtual bool FindInsertionPoint( XPoint& pos, WidgetNode*& pTarget );
	wxUILookInfo* FindLookForNode( WidgetNode& node );

	ResTemplateManager& GetTemplateManager();
	wxUILookRenderer& GetRenderer();
	WidgetEqSolver& GetEqSolver();

	const wxString& GetUIType();
	void SetUIType( const wxString& uiType );

	static void LockUndoBuffer( bool lock );

	virtual void MarkUsedId( const wxString& id );
	virtual void MarkUnusedId( const wxString& id );
	virtual wxString GenerateUniqueId( WidgetNode& forNode );

	wxDMCommandProcessor& GetCmdProcessor() { return *mpDMCmdProcessor; }

	DECLARE_DYNAMIC_CLASS( WidgetDocument )

protected:

	friend class WidgetView;
	friend class WidgetInsertionEditor;

	void DoExtractBounds( Record& rec, wxRect& bounds );
	bool LoadNodesRecursively( Record& rec, Record* pExtraPropsRec,
							   WidgetNode* pParent, 
							   ResTemplateManager& mgr, 
							   bool isLinked = FALSE, 
							   wxRect* pBounds = NULL );

	bool StoreNodesRecursively( WidgetNode* pNode, Record& rec,
							    ResTemplateManager& mgr );
protected:
	wxDMCommandProcessor*   mpDMCmdProcessor;
	WidgetNode*				mpRootNode;
	Record*					mpRecord;
	wxUILookRenderer*		mpRenderer;
	WidgetEqSolver			mSolver;
	static bool				mUBufferLocked;
	wxString				mUIType; // type of UI, in which currently edited
									 // scene is rendered

	wxPoint					mInsertionOfs;

	wxHashTable				mIdsHash;

};


class WidgetView : public wxPMView, public wxDMListener
{
public:
	WidgetView();
	~WidgetView();

	XCollection& GetScene();

	virtual void SetDialogsUnits( bool on );
	virtual bool UseDialogUnits();

	WidgetGlyph& GetGlyphForNode( wxDMNode& node );	
	WidgetGlyph* FindGlyphForNode( wxDMNode& node );

	WidgetNode& GetRootNode();
	virtual void RelayoutScene();

	ResTemplateManager& GetTemplateManager();

	virtual void RemoveGlyphsForNode( WidgetNode& node );
	virtual void CreateGlyphsForNode( WidgetNode& node );

	virtual void RecreateScene();

	WidgetDocument& GetWidgetDoc();

	enum GRID_TYPES
	{
		GRID_NONE,
		GRID_LINES,
		GRID_DOTS,
		GRID_DOTS_3D,
		GRID_LAST_TYPE = GRID_DOTS_3D
	};

	virtual void SetGridType( int type );
	virtual int GetGridType();
	wxSize& GetGridSpacinig();
	wxSize& GetSnapSpacing();

	// units<->pixels conversion routines

	void AdjustRectToGrid( XRect& rect, WidgetGlyph& forGlyph );
	int AdjustToSnappingX( int units );
	int AdjustToSnappingY( int units );
	int PixelsToUnits( int pixels );
	int UnitsToPixels( int units );
	void GetTopLevelWidgetOrigin( int* x, int* y );
	double GetVerticalPixelsPerUnitRatio();
	double GetHorizontalPixelsPerUnitRatio();
	void PixelRectToUnitRect( XRect& pixelRect, XRect& unitRect );
	void UnitRectToPixelRect( XRect& unitRect, XRect& pixelRect );

	// overriden method of wxDocument
	virtual void OnUpdate(wxView* sender, wxObject* hint);
	virtual void OnActivateView(bool activate, wxView *activeView, wxView *deactiveView);

	// overriden method wxView and wxPMView
	virtual bool OnCreate(wxDocument* doc, long flags);

	// overriden method of wxPMService
	virtual wxPMMergableMenuChain* GetMergableMenuChain();

	// overriden notifications of wxDMListener

	virtual void OnNodeRemoved( wxDMNode& node );
	virtual void OnNodeAdded( wxDMNode& node );
	virtual void OnNodeChanged( wxDMNode& node );
	virtual void OnNodeOrderChanged( wxDMNode& node );
	virtual void OnPointerChanged( wxDMNode* pFromPtr, wxDMNode* pToPtr );
	virtual void OnNodeReplaced( wxDMNode& node, wxDMNode& withNode );
	
	virtual void OnFocusChanged( wxDMNode& node );
	virtual void OnFocusRemoved();

	virtual void OnSelectionSet( DMNodeListT& nodes );
	virtual void OnNodeAddedToSelection( wxDMNode& node );
	virtual void OnNodeDeselected( wxDMNode& node );

	virtual void FindInsertionTarget( const XPoint& pos, WidgetNode*& pTarget, 
									  int& orderNo, WidgetNode* pNodeToExclude );

	virtual void OnUpdateFinished();

	/*** event handlers ***/

	enum COMMAND_IDS
	{
		ID_SET_UI_TYPE = 300,
		ID_SET_UNITS,
		ID_SET_SIZER,
		ID_GRID_SETTINGS,
		ID_INSERT_WIDGET,
		ID_PREVIEW,
		ID_RELOAD_WIDGET_LOOKS,
		ID_AUTOSELECT,
		ID_SHOW_SIZERS,

		// any-tiem related operations
		ID_INSERT_LINKED_ITEM,
		ID_ESTABLISH_AS_LINK,

		// sizer-item related operations
		ID_SELECT_PARENT,
		ID_MOVE_FORWARD,
		ID_MOVE_BACKWARD,
		ID_INC_BORDER,
		ID_DEC_BORDER,
		ID_ALIGN_LEFT,
		ID_ALIGN_RIGHT,
		ID_ALIGN_CENTER,
		ID_EXPAND,

		ID_INSERT_WIDGET_IDS_START = 400,
		ID_INSERT_WIDGET_IDS_END   = 499
	};

	void OnEditorCommandsRange( wxCommandEvent& event );
	void OnInsertWidgetCommandsRange( wxCommandEvent& event );

	void OnSetUIType( wxCommandEvent& event );
	void OnSetUnits( wxCommandEvent& event );
	void OnSetSizer( wxCommandEvent& event );
	void OnGridSettings( wxCommandEvent& event );
	void OnInsertWidget( wxCommandEvent& event );
	void OnPreview( wxCommandEvent& event );
	void OnReloadWigetLooks( wxCommandEvent& event );
	void OnShowSizers( wxCommandEvent& event );

	// any-tiem related operations

	void OnInsertLinkedItem( wxCommandEvent& event );
	void OnEstablishAsLink( wxCommandEvent& event );

	// sizer-item related operations

	void OnItemSelectParent( wxCommandEvent& event );
	void OnItemMoveForward( wxCommandEvent& event );
	void OnItemMoveBackward( wxCommandEvent& event );
	void OnItemIncBorder( wxCommandEvent& event );
	void OnItemDecBorder( wxCommandEvent& event );
	void OnItemAlignLeft( wxCommandEvent& event );
	void OnItemAlignCenter( wxCommandEvent& event );
	void OnItemAlignRight( wxCommandEvent& event );
	void OnItemExpand( wxCommandEvent& event );

	// window-commands

	void OnKeyDown( wxKeyEvent& event );

	virtual bool SizersShown();
	virtual WidgetNode* FindFocus();

	DECLARE_DYNAMIC_CLASS( WidgetView )
	DECLARE_EVENT_TABLE()

	friend class MultiFaceGlyphBase;

protected:
	virtual void AssignPropertiesToGlyph( WidgetGlyph& glyph, WidgetNode& fromNode );
	virtual WidgetGlyph* CreateGlyphForNode( WidgetNode& node );
	virtual void ReorderAllGlyphs();
	virtual void RefreshScene();
	virtual void AddGlyphRefsRecursive( XObjListT& toLst, wxDMNode& node );
	virtual void CreateGlyphsRecursive( XObjListT& toLst, wxDMNode& node );
	virtual void InvalidateLooks();
	virtual void RecreateMenuChains();

protected:
	XCollection*			mpScene;
	XGenericEditorHandler*	mpEditorHandler;
	MyXCommandMgr*			mpXCmdMgr;
	WidgetNode*				mpRootNode;

	static wxDMClipboard*   mpClipboard;
	wxHashTable				mGlyphHash; // maps "WidgetNode"s to corresponding "WidgetGlyphs"

	bool					mUseDialogUnits; // default: false (is autodetected
											 // when loading resource)

	bool					mSizersShown;

	wxSize 					mSnapSpacing;
	wxSize 					mGridSpacing;
	int						mGridType;

	wxCommandInfo*			mpWidgetMenus;
	wxPMMergableMenuChain*  mpMenuChains;

	wxDMNodePropertyPanel*  mpPropPane;

};

class WidgetNode : public wxDMCompositeNode
{
public:
	WidgetNode();
	~WidgetNode();

	// overriden methods of wxDMNode

	virtual size_t GetGroupCount();
	virtual wxDMAttrGroupInfo* GetAttrGroupInfo( size_t index );
	virtual void* GetAttrGroupData( size_t index );
	virtual void* GetAttrGroupData( wxDMAttrGroupInfo* pForGroup );
	virtual wxString GetDisplayName();

	virtual wxDMNode* Clone( bool uniqueCopy, bool cloneChildren = TRUE );
	virtual void AssignData( wxDMNode* pCopy, bool uniqueCopy, bool cloneChildren );

	virtual void OnStartEdit();
	virtual void OnFinishEdit();

	virtual bool IsLinked();
	virtual void SetIsLinked( bool isLinked );

	virtual bool CanHaveChildren();

	// other methods

	virtual const XDim GetPreferredSize();
	virtual XRect GetLimitingBounds();

	void SetView( WidgetView* pView );
	const wxString& GetWidgetClass();
	WidgetResTemplate& GetTemplate();

	virtual void RecalcPreferredSize( wxDC& dc );
	virtual void SetPreferredSize( const XDim& size );

	XRect& GetBounds();
	void SetBounds( const XRect& rect, wxDC& dc );

	virtual wxColour& GetBgColor();
	virtual wxColour& GetFgColor();
	virtual wxFont& GetFont();
	virtual void CreateFont();
	virtual bool IsDefaultValue( const wxString& prop );
	virtual void CreateBgColor();
	virtual void CreateFgColor();

	virtual void InvalidateLooksRecursive();

	virtual wxColour GetColourPropByName( const wxString& prop, const wxColour& defaultVal );

	// overridables 
	virtual void DoLayoutChildren( wxDC& dc );
	virtual void AddExtraPropertiesToChild( WidgetNode* pChild );

	bool HasExtraProperties();
						
	virtual void ExtractBoundsInfo();
	virtual void StoreBoundsInfo();

	// convenience methods
	virtual wxString GetNodeAttrValue( const wxString& name );
	virtual wxString GetNodeExtraAttrValue( const wxString& name );
	virtual void SetNodeAttrValue( const wxString& name, const wxString& value );
	virtual void SetNodeExtraAttrValue( const wxString& name, const wxString& value );

	// overriden notifications of wxDMNode which are send to parent-widget nodes, 
	// It is currently used for setting up and removing parent-specific 
	// extra properties for the given child

	virtual void OnChildInserted( wxDMNode* pNode );
	virtual void OnChildRemoved( wxDMNode* pNode );

	DECLARE_DYNAMIC_CLASS( WidgetNode )

public: /* protected really */
	enum 
	{
		WIDGET_PROPERTIES_GROUP = 0,
		EXTRA_PROPERTIES_GROUP	= 1,

		MAX_PROPERTY_GROUPS = 2
	};

	ResGroupData mAttribGroups[MAX_PROPERTY_GROUPS];

	WidgetResTemplate* mpTempl;
	WidgetView* mpView;

	XRect    mBounds;   // always in pixels
	XDim	 mPrefSize; // preferred size

	wxColour mBgColor;
	wxColour mFgColor;
	wxFont   mFont;

	bool	 mIsLinked;
};

class WidgetGlyph : public XObject
{
public:
	WidgetGlyph();
	~WidgetGlyph();

	void SetNode( WidgetNode* pNode );
	void SetLookInfo( wxUILookInfo* pInfo );
	wxUILookInfo* GetLookInfo();

	// overriden methods of XObject

	void Draw( wxDC& canvas);
	virtual bool Contains( const XPoint& point );

	virtual void SetBounds( const XRect& bounds );
	virtual void SetBoundsSilent( const XRect& bounds );
	virtual XRect GetBounds();
	virtual XRect GetLimitingBounds();

	virtual bool OnStartEdit();
	virtual bool OnFinishEdit();

	virtual WidgetGlyph* GetParentGlyph();

	virtual void ToGlyphRect( XRect& rect );
	virtual void ToNodeRect( XRect& rect, bool useParent = TRUE );

	// other methods

	virtual void DrawGrid( wxDC& dc );

	virtual void InvalidateLook();

	virtual WidgetNode& GetNode();

	virtual XObject* GetSurroundingObject();

	virtual void RegenerateLookBitmap();

	// overridables

	// returns TRUE by default
	virtual bool IsVisibleChild( size_t childNo );

	DECLARE_DYNAMIC_CLASS( WidgetGlyph )

protected:
	virtual void GetLimitingRectInUnits( XRect& r );

protected:
	wxUILookInfo* mpLookInfo;
	wxBitmap*     mpBmp;

	WidgetNode*	  mpNode;
	XRect		  mPixBounds; // always in pixels (indirectly maps to mpNode->mBounds)
};

// just delegates all important events to DM-command manager

class MyXCommandMgr : public XCommandManager
{
public:
	MyXCommandMgr( wxDMCommandProcessor* pDMCmdProcessor, 
				   XCollection* pScene,
				   WidgetView* pView );

	virtual void NotifyWillChange( XObject* pObj = 0 );
	virtual void NotifyWillRemove( XObject* pObj = 0 );
	virtual void NotifyAdded( XObject* pObj = 0 );

	virtual void StartBatch();
	virtual void FinishBatch();

	// user-level commands

	virtual bool CanUndo();
	virtual bool CanRedo();
	virtual bool CanPaste();
	virtual bool CanDelete();

	virtual void Undo();
	virtual void Redo();
	virtual void Delete();

	virtual void Copy( XCollection*  pScene );
	virtual void Paste( XCollection* pScene );

	void SetCommandProcessor( wxDMCommandProcessor* pProc );

protected:
	wxDMCommandProcessor* mpMgr;
	WidgetView* mpView;
};

class MyXCollection : public XCollection
{
public:
	MyXCollection( WidgetView* pView );

	// overriden methods of XObject

	virtual void NotifyWillChange( XObject* pObj = NULL );
	virtual void NotifyWillRemove( XObject* pObj = NULL );
	virtual void NotifyAdded( XObject* pObj = NULL );

	// overriden methods of XCollection
	virtual void SetFocus( XObject* pFocus, bool refreshNow = TRUE );
	virtual void SetSelection( XObjListT& newSelection, bool refreshNow = TRUE );
	virtual void ResetSelection();
	virtual void SelectAll();
	virtual void DeleteSelection();

	virtual void BringSelectionToFront();
	virtual void SendSelectionBack();

protected:
	void DoSetSelection( XObjListT& lst );

protected:
	WidgetView* mpView;
	bool mReqsLocked;
};

class wxMyDMPasteHandler : public wxDMPasteHandler
{
public:
	virtual void HandleNodePasting( wxDMNode* pNode, wxDMNode* pToNode, int depth );
};

class WidgetInsertionEditor : public XEditor
{
public:
	WidgetInsertionEditor( WidgetView* pView, int widgetCode );
	WidgetInsertionEditor( WidgetView* pView, const wxString& itemId );

	~WidgetInsertionEditor();

	virtual bool OnMouseDown( const XPoint& pos );
	virtual bool OnRightClick( const XPoint& pos );

	virtual bool OnMouseMove( const XPoint& pos );

	void CancelCreation();

protected:
	void DetachFromScene();

protected:
	int mWigetCode;
	WidgetView* mpView;
	XEditor* mpPrevEditor;
	wxString mItemId;
};

class GridSettingsDialog : public wxDialog
{
public:
	GridSettingsDialog( wxWindow* pParent, 
						int gridType,
						const wxSize& gridSpacing,
						const wxSize& snapSpacing );

	int GetGridType();
	wxSize& GetGridSpacinig();
	wxSize& GetSnapSpacing();

	void OnDblClick( wxCommandEvent& event );

	enum CTL_IDS
	{
		ID_GRIT_TYPES = 200
	};

	void OnOk( wxCommandEvent& event );

	DECLARE_EVENT_TABLE()

protected:
	wxListBox* mpTypes;
	wxChoice*  mpGridSpacing;
	wxChoice*  mpSnapSpacing;

	int mGridType;
	wxSize mGridSpacing;
	wxSize mSnapSpacing;
};

class SizerNodeBase : public WidgetNode
{
public:
	static void GetLayoutProps( WidgetNode& node, int& option, int& flag, int& border );
	
	DECLARE_CLASS( SizerNodeBase )
};

class MultiFaceNodeBase : public WidgetNode
{
public:
	MultiFaceNodeBase();

	// overriden methods of WidgetNode
	virtual void DoLayoutChildren( wxDC& dc );

	virtual void OnChildInserted( wxDMNode* pNode );
	virtual void OnChildRemoved( wxDMNode* pNode );
	virtual void OnChildChanged( wxDMNode* pNode );

	DECLARE_CLASS( MultiFaceNodeBase )

protected:
	virtual void DoUpdateGlyphForNode( wxDMNode* pChild );
};

class MultiFaceGlyphBase : public WidgetGlyph
{
public:
	MultiFaceGlyphBase();

	// overriden methods of WidgetGlyph

	virtual bool IsVisibleChild( size_t childNo );

	// overridables for the derived classes
	virtual void RecalcFaceGeometry( wxDC& dc );
	virtual void SetVisibleFace( int faceIndex );
	
	size_t GetVisibleFace();
	
	DECLARE_CLASS( MultiFaceGlyphBase )

protected:
	size_t mVisibleFace;
};

#endif // __WIDGETVIEW_G__
