/*	TTreeView.h
 *
 *		This defines the way a project view works. This provides the
 *	interface.
 */

/**********************************************************************

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

**********************************************************************/

#ifndef PandaWave_TTREEVIEW
#define PandaWave_TTREEVIEW

#include <XConfig.h>
#include <XCollection.h>
#include <XDragDrop.h>
#include <XView.h>

/************************************************************************/
/*																		*/
/*	Events																*/
/*																		*/
/************************************************************************/

/*	TreeEventRecord
 *
 *		The tree event record
 */

struct TreeEventRecord {
	uint32						child;
	uint32						ev_flags;
};

/*	KEventTreeClick
 *
 *		An item was clicked on and selected
 */

#define KEventTreeClick			'TCLK'

/*	KEventTreeDClick
 *
 *		An item was double-clicked on
 */

#define KEventTreeDoubleClick	'TDCK'

/*	KEventTreeOpen
 *
 *		An item with 'defer children' was opened
 */

#define KEventTreeOpen			'TOPN'

/*	KEventTreeStartDrag
 *
 *		This is sent when a drag/drop process is started. This should
 *	return 0 if this item should not be dragged.
 */

#define KEventTreeStartDrag		'TSDR'

/*	TreeDragRecord
 *
 *		What is sent when I start dragging
 */

struct TreeDragRecord {
	class TTreeView				*tree;
	uint32						dragID;
};

/*	KEventTreeCanDrop
 *
 *		Sent when first entered; this indicates if I can even accept
 *	objects of this type. Only the 'tree' and 'dropID' fields are
 *	filled in.
 */

#define KEventTreeCanDrop		'TCDP'

/*	KEventTreeDoDrop
 *
 *		When an object is dropped, this is sent to indicate the object
 *	has been dropped. All fields filled in.
 *
 *		This should return 1 if the drop was accepted.
 */

#define KEventTreeDoDrop		'TDDP'

/*	KEventTreeDropHere
 *
 *		While an object is dragged, this message is sent up to determine
 *	*where* an object can be dropped in the tree. This is sent with the
 *	parent object's ID and the sibling ID where this thing may be
 *	dropped. Return 0 if the object <<cannot>> be dropped here. (If
 *	the message is ignored, it's assumed to be a '1'--that is, that
 *	this object can be dropped anywhere.
 *
 *		Note that the 'len' and 'data' fields are not filled in on
 *	the TreeDropRecord object
 */

#define KEventTreeDropHere		'THER'

/*	KDragFlavorTreeView
 *  
 *		The flavor used by the table for drag/drop.
 */
#define KDragFlavorTreeView		'TBDP'
 

/*	TreeDropRecord
 *
 *		Drag/drop record; this is how the drag/drop state is sent
 *	upwards.
 */

struct TreeDropRecord {
	class TTreeView				*tree;
	long						dropID;
	uint32						parent;
	uint32						child;
	long						modifiers;
	long						len;
	void						*data;
};

/************************************************************************/
/*																		*/
/*	Structures															*/
/*																		*/
/************************************************************************/

/*	TableEntryRecord
 *
 *		How a table entry is stored internally
 */

struct TableEntryRecord {
	struct TableEntryRecord		*next;
	struct TableEntryRecord		*child;
	struct TableEntryRecord		*parent;
	struct TableEntryRecord		*nextSelected;
	struct TableEntryRecord		*prevSelected;
	class TTreeView				*owner;

	bool						fOpen;
	bool						fChildDefer;
	bool						fSelected;

	short						icon;
	uint32						strHandle;
	uint32						dataHandle;
	
	bool						fInternDrag;
	long						dragID;
	uint32						dragData;
	XPoint						dragSize;
};

/*	TableDrawRecord
 *
 *		How I keep track of what is currently open and closed...
 */

struct TableDrawRecord {
	TableEntryRecord			*entry;
	short						inset;
};

/************************************************************************/
/*																		*/
/*	Class Declaration													*/
/*																		*/
/************************************************************************/

/*	TTreeView
 *
 *		the project view object for displaying the contents of this thing
 */

class TTreeView : public XGView, public XGDropper {
	public:
								TTreeView(XGView *, XGArgStream &);
		virtual					~TTreeView();
		
		enum {
			kClassID = 'Tree'
		};
				
		/*
		 *	Event overrides
		 */
		
		void					DoDrawView(XRect);
		void					DoActivate(bool);
		void					DoSizeView();
		bool					DoMouseDown(XPoint,short);
		
		/*
		 *	Drag and drop interface
		 */
		
		bool					Accept(long, long, long);
		bool					Drop(XPoint, long, long, long, void *, long);
		void					Enter(XPoint, long, bool);
		void					Leave(void);
		void					Track(XPoint, long);

		
		/*
		 *	Interface
		 */
		 
		void					DisableDrawing();
		void					EnableDrawing();
		
		uint32					AppendItem(uint32 parent,
										uint32 after,
										const char *ptr,
										sint16 icon = 0);
		void					AppendDefer(uint32 parent);
		
		void					DeleteItem(uint32 item);
		void					DeleteAll(void);
		
		short					GetNumItems(uint32 parent);
		uint32					GetItemHandle(uint32 parent, short index);
		void					GetItemData(uint32 item, char *ptr, uint32 len);
		void					SetItemData(uint32 item, char *ptr);
		sint16					GetItemIcon(uint32 item);
		uint32					GetItemParent(uint32 item);

		void					OpenItem(uint32 parent, bool);
		bool					IsItemOpen(uint32 item);
		
		uint32					GetExtraData(uint32 item, void *ptr, uint32 len);
		uint32					SetExtraData(uint32 item, void *ptr, uint32 len);
		
		uint32					GetDragSource(uint32 item, long *dragid, void *ptr, uint32 len);
		uint32					SetDragSource(uint32 item, long dragid, void *ptr, uint32 len, bool intern = false);
		
		XPoint					GetDragSize(uint32 item);
		void					SetDragSize(uint32 item, XPoint size);
		
		void					SortChildrenOf( uint32 parent );
		
		
		/*
		 *	Selection interface
		 */
		
		uint32					GetFirstSelected()
									{ return (uint32)fSelection; }
		uint32					GetNextSelected( uint32 item )
									{ return item ? (uint32)((TableEntryRecord *)item)->nextSelected : 0; }
		void					SetSelection(uint32 item)
									{ ClearSelection(); SetSelected( item, true ); }
		void					ClearSelection();
		void					SetSelected(uint32 item, bool select);
		bool					IsSelected( uint32 item )
									{ return ((TableEntryRecord *)item)->fSelected; }
		uint32					GetSelectionCount()
									{ return fSelectedCount; }
		
		/*
		 *	Events
		 */
		
		DECLAREDISPATCH
		long					DoKeyEvent(long, void *);
	protected:
		/*
		 *	Display support
		 */
		
		virtual void			RedrawItem(XGDraw &, TableEntryRecord *item);

		virtual void			DrawItem(XGDraw &, XRect &, bool, uint32 data);
		virtual void			DrawItemIcon(XGDraw &, XRect &, sint16);
		virtual void			DrawDropIcon(XGDraw &, XRect &, bool);
		
		void					DeselectChildren( TableEntryRecord *item );

	private:
		void					Update();
		void					Recompute();
		void					RecalcScroll();
		
		void					AppendEntry(XGDraw &, short, TableEntryRecord *);
		void					DeleteEntry(TableEntryRecord *tentry);
		
		bool					FindDropPoint(XPoint where);
		void					ClearDropPoint();
		void					DrawDropPoint(XGDraw &, XPoint);
		
		static int				CompareItems( const void *a, const void *b );
		
		long					fWidth;
		long					fLength;
		XGCollection			fData;
		XGHandle				fDrawList;
		
		long					fDropID;
		XPoint					fDropPos;
		uint32					fDropParent;
		uint32					fDropChild;
		
		short					fUpIcon;
		short					fDownIcon;
		
		bool					fDrawFlag;
		bool					fUpdateFlag;
		TableEntryRecord		*fRoot;
		TableEntryRecord		*fSelection;
		int						fSelectedCount;
};

#endif
