/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CTreeView.h  -  description
                             -------------------
    begin                : June 21 2003
    copyright            : (C) 2002-2006 by Alexey Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library is distributed in the hope that it will be useful, but 
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CTREECONTROL_H__
#define __CTREECONTROL_H__

#include <FL/Fl_Widget.h>
#include <sptk3/CLayoutClient.h>
#include <sptk3/CScroll.h>
#include <sptk3/CGroup.h>

#include <string>
#include <vector>

namespace sptk {

   /// @addtogroup gui GUI Classes
   /// @{

	class CTreeControl;

   /// @brief Tree widget item.
   ///
   /// A group widget with the extra information about item pixmaps
   /// and current state.
	class CTreeItem : public CGroup {
		friend class CTreeControl;

		int            m_itemHeight;  ///< Returns the height of the item text
		int            m_indent;      ///< The width of the indent zone
		int            m_labelWidth;  ///< The width of the label computed by fl_measure
		int            m_labelHeight; ///< The height of the label computed by fl_measure

	protected:
		Fl_Image      *m_openedImage; ///< The image for the open state
		Fl_Image      *m_closedImage; ///< The image for the closed state
		bool           m_opened;      ///< The item's state
		CTreeControl  *m_tree;        ///< The tree control
		std::string    m_caption;     ///< The tree item caption

   /** Adds a child item to the item using the path. The required path items are created automatically. 
    * This methos is used internally only.
    * @param pathFolders const std::vector<std::string>&, the path to the new child item relatively to the item
    * @param offset unsigned, the offset in pathFolders where the path starts 
    * @param openedImage Fl_Image, the image for the opened folder
    * @param closedImage Fl_Image, the image for the closed folder
    * @param itemImage Fl_Image, the image for the child item
    * @param data void *, the user data or ID attached to the item
    * @returns the new child item
    */
		CTreeItem *addPathOffset(const std::vector<std::string>& pathFolders,unsigned offset,Fl_Image *openedImage,Fl_Image *closedImage,Fl_Image *itemImage=0L,void *data=0L);

	public:   
   /** Constructor. If the closedImage parameter is omitted the openedImage is used instead.
    * @param label const char *, the item label
    * @param openedImage Fl_Image, the image for the opened state
    * @param closedImage Fl_Image, the image for the closed state
    * @param data void *, the user data or ID attached to the item
    */
		CTreeItem(const char *label,Fl_Image *openedImage=0L,Fl_Image *closedImage=0L,void *data=0L);

   /** Adds a child item to the item. If the closedImage parameter is omitted the openedImage is used instead.
    * @param label const char *, the item label
    * @param openedImage Fl_Image, the image for the opened state
    * @param closedImage Fl_Image, the image for the closed state
    * @param data void *, the user data or ID attached to the item
    * @returns the new child item
    */
		CTreeItem *addItem(const char *label,Fl_Image *openedImage,Fl_Image *closedImage=0L,void *data=0L);

   /** Adds a child item to the item using the path. The required path items are created automatically. 
    * @param path const std::vector<std::string>&, the path to the new child item relatively to the item
    * @param openedImage Fl_Image, the image for the opened folder
    * @param closedImage Fl_Image, the image for the closed folder
    * @param itemImage Fl_Image, the image for the child item
    * @param data void *, the user data or ID attached to the item
    * @returns the new child item
    */
		CTreeItem *addPath(const std::vector<std::string>& path,Fl_Image *openedImage,Fl_Image *closedImage,Fl_Image *itemImage=0L,void *data=0L);

   /** Adds a child item to the item using the path. The required path items are created automatically. 
    * The default images are used for the folders in the path.
    * @param path const std::vector<std::string>&, the path to the new child item relatively to the item
    * @param itemImage Fl_Image, the image for the child item
    * @param data void *, the user data or ID attached to the item
    * @returns the new child item
    */
		CTreeItem *addPath(const std::vector<std::string>& path,Fl_Image *itemImage=0L,void *data=0L);

      /// Sets the item's caption
      /// @param lbl const char *, the new item caption
		void label(const char *lbl);

      /// Returns the item's caption
		const char * label() const { return m_caption.c_str(); }

      /// Removes all the child items of the item 
		void clear();

      /// Finds an item among the child items
      /// @returns the child item (if found) or NULL
		CTreeItem *findItem(const char *label) const;

      /// Finds an item by the item user data in the whole tree
      /// @param data void *, user data to find
      /// @returns the child item (if found) or NULL
		CTreeItem *findData(const void *data) const;

      /// Removes an item from the child items.
      /// Only the intermediate children are considered
      /// @param item CTreeItem *, item to remove
		void removeItem(CTreeItem *item);

      /// Returns the parent item
      /// @returns the parent item or NULL (for the root item)
		CTreeItem *parentItem() const;

      /// Returns the tree control this item belongs to
		CTreeControl *tree() const { return m_tree; }

      /// Moves the immediate child before another immediate child
      /// If beforeItem is 0L then moves to the end of the children
      /// @param item CTreeItem *, the item to move
      /// @param beforeItem CTreeItem *, the item to insert before
		void moveItem(CTreeItem *item,CTreeItem *beforeItem=0L);

      /// Moves the immediate child up or down in the list of items
      /// @param item CTreeItem *, the item to move
      /// @param direction int, the direction to move. -1 to move up, 1 to move down
		void moveItem(CTreeItem *item,int direction);

      /// Shows or hides all the child items. Changes the item state accordingly. 
      /// @param vc bool, show(true) or hide(false) children
		void visibleChildren(bool vc);

      /// Shows all the child items. Changes the item state accordingly.
		void open()         { visibleChildren(true); }

      /// Hides all the child items. Changes the item state accordingly. 
		void close()        { visibleChildren(false); }

      /// Reports the item state - opened or closed.
      /// @returns item state, true if opened
		bool opened() const { return m_opened; }

      /// Sets image(s) for the item
      /// @param openedImage Fl_Image *, the image for the opened state
      /// @param closedImage Fl_Image *, the image for the closed state
		void setImage(Fl_Image *openedImage,Fl_Image *closedImage=0L) {
			m_openedImage = openedImage;
			m_closedImage = closedImage;
		}

      /// The event handle function. Internal. See Fl_Widget for details.
      /// @param event int, event type.
      /// @returns true if event was processed.
		int handle(int event);

      /// The draw function. Internal. See Fl_Widget for details.
		virtual void draw();

      /// Computes the preferred size of the item based on the font of the parent widget, 
      /// the image size, and the text (label) of the item.
		virtual void preferredSize(int& w,int& h);

      /// Resizes item and sub items
		void resize(int xx,int yy,int ww,int hh);
	};

   /// @brief Tree widget. 
   ///
   /// Designed to be used inside
   /// CTreeView widget, but also can be used by itself. It's missing for data connection
   /// support of CTreeView, though.
	class CTreeControl : public CScroll {
		friend class CTreeItem;
	private:
		CTreeItem  *m_selected;    ///< The selected item
		CTreeItem  *m_root;        ///< The root item 
	protected:
		bool        m_tabPressed;  ///< Internal flag to temporarely block tree items focus acceptance

	public:
		/// The constructor. 
		/// @param label const char *, the widget's label
		/// @param layoutSize int, size of widget in layout. See CLayoutClient for details
		/// @param align CLayoutAlign, widget align in the layout
		CTreeControl(const char *label,int layoutSize=50,CLayoutAlign align=SP_ALIGN_TOP);

		/// Adds a child item to the root item. If the closedImage parameter is omitted the openedImage is used instead.
		/// @param label const char *, the item label
		/// @param openedImage Fl_Image, the image for the opened state
		/// @param closedImage Fl_Image, the image for the closed state
		/// @param data void *, the user data or ID attached to the item
		/// @returns the new child item
		CTreeItem *addItem(const char *label,Fl_Image *openedImage=0L,Fl_Image *closedImage=0L,void *data=0L);

      /// Adds a child item to the root item using the path. The required path items are created automatically. 
		/// Path elements are separated with '/'. The default images are used for the folders in the path.
		/// @param path const std::vector<std::string>&, the path to the new child item
		/// @param openedImage Fl_Image, the image for the folders in opened state
		/// @param closedImage Fl_Image, the image for the folders in closed state
		/// @param itemImage Fl_Image, the image for the child item
		/// @param data void *, the user data or ID attached to the item
		/// @returns the new child item
		CTreeItem *addPath(const std::vector<std::string>& path,Fl_Image *openedImage,Fl_Image *closedImage,Fl_Image *itemImage=0L,void *data=0L);

   /** Adds a child item to the root item using the path. The required path items are created automatically. 
    * Path elements are separated with '/'. The default images are used for the folders in the path.
    * @param path const std::vector<std::string>&, the path to the new child item
    * @param itemImage Fl_Image, the image for the child item
    * @param data void *, the user data or ID attached to the item
    * @returns the new child item
    */
		CTreeItem *addPath(const std::vector<std::string>& path,Fl_Image *itemImage=0L,void *data=0L);

		/// Finds an item by the item label in the whole tree
		/// @param item const char *, item label to find
		/// @returns the child item (if found) or NULL
		CTreeItem *findItem(const char *item) const;

		/// Finds an item by the item user data in the whole tree
		/// @param data void *, user data to find
		/// @returns the child item (if found) or NULL
		CTreeItem *findData(const void *data) const;

		/// Removes all the items in the tree. 
		virtual void clear() { m_selected = 0L; m_root->clear(); }

		/// Moves the item in the tree. 
		/// @param item CTreeItem *, item to insert
		/// @param beforeItem CTreeItem *, item before the insert point. If 0L - it's moved to the very last position in parent item list of items.
		void moveItem(CTreeItem *item,CTreeItem *beforeItem=0L);

		/// Removes all the item and underlying structure from the tree. 
		/// @param item CTreeItem *, item to remove
		void removeItem(CTreeItem *item);

		/// Reports the currently selected item. 
		/// @returns the selected item.
		CTreeItem *selected() const { return m_selected; }

		/// Selects the item. Only one item in the tree may be selected.
		/// @param item CTreeItem, item to select
		void select(CTreeItem *item);

		/// Makes the item visible if it's outside the visible area.
      /// @param item CTreeItem, item to make visible
		void makeVisible(CTreeItem *item);

      /// Special handle() function.
      /// @param event int, an FLTK event
      /// @returns true, if event was processed
		int handle(int event);
	};	
   /// @}
}
#endif
