/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CTreeView.h  -  description
                             -------------------
    begin                : June 21 2003
    copyright            : (C) 2002-2005 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>

class CTreeControl;

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

/// @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
