
How to use the option tree control
==================================


0. Create a control of any kind (static text is fine) in your dialog
   box and give it an ID, say, 101.

   This is NOT our control. Instead, our control will initialize its
   position and size as the same as this control.



1. #include "opttree.h" and put "opttree.cpp" in your prj.




2. Declare a member for the control obj:


class CDlgTest:public CDialog  
{
   COptTree *otc;

   public:

   CDlgTest():CDialog("dlgtest")
   {
      otc = 0;
   }
  ~CDlgTest();

   BOOL OnInitDialog();
};


3. Create the control obj, the nodes and build up the trees in OnInitDialog():


BOOL CDlgTest::OnInitDialog()
{
   COptNode *p;                                    /* the root of the 1st tree */
   COptNode *r;                                    /* the root of the 2nd tree */
   COptNode *q;                                             /* for scratch use */

   CDialog::OnInitDialog();

   otc = new OptTree(this);                 /* create the control obj (no wnd) */

   p = new COptNode("Software Products", 0, 1);        /* create the root node */

   p->begappendkid();                                   /* put 3 kids under it */
   {
      q = new COptNode("Lotus 123 for Windows", 0, 0, 1);    /* create 1st kid */
      p->appendkid(q);                                               /* add it */

      q = new COptNode("Microsoft Word",        0, 1, 1);           /* 2nd kid */
      p->appendkid(q);

      q = new COptNode("Visual C++",            0, 1, 1);           /* 3rd kid */
      p->appendkid(q);
   }
   p->endappendkid();                /* finish adding kids. this tree is ready */

   r = new COptNode("Meals", 0, 1);                    /* prepare the 2nd tree */
   r->begappendkid();                                      /* add 2 kids to it */
   {
      q = new COptNode("KFC",       0, 1, 1);
      r->appendkid(q);

      q = new COptNode("Pizza Hut", 0, 1, 1);
      r->appendkid(q);
   }
   r->endappendkid();                                    /* finish adding kids */

   otc->begappendroot();                     /* add the 2 trees to the control */
   otc->appendroot(p);                                             /* 1st tree */
   otc->appendroot(r);                                             /* 2nd tree */
   otc->endappendroot();       /* finish. the ctrl can take care of itself now */

   otc->create(102, 101);/* base its size & pos on ctrl 101. its own id is 102 */
   return 1;
}


5. Delete nodes when the dialog is close:


CDlgTest::~CDlgTest();
{
   otc->freeallnodes();

   delete otc;
} 


Class Reference
===============

1. COptNode


This is the class for the nodes in the control.


class COptNode
{
   public:

   int i;                                   /* sequential index in the control */
   int isxcl;                                  /* is exclusive among siblings? */
   int isexp;                          /* is it expanded? meaningless for leaf */
   int chkstr;                /* real check state. calc from kids for a branch */
   int chksti;                /* ideal check state, equal to chkstr for a leaf */
   int enable;                     /* 0 -- disabled  1 -- enabled  2 -- hidden */
   int ischkchg;                           /* is the real check state changed? */
   char txt[40];                               /* maximum 40 char for the name */
   COptNode *dad;                                                  /* dad node */
   COptNode *last;                                             /* last sibling */
   COptNode *next;                                             /* next sibling */
   COptNodeList kids;                                             /* kid nodes */

   /* constructor for leaf nodes                                     */
   /* txt    --- the name of the node. displayed in the listbox      */
   /* isxcl  --- if this node is exclusive or not. if it is, when it */
   /*            is selected, all its siblings will be deselected    */
   /* chksti --- ideal check state of the node.                      */
   /*            0 -- cleared                                        */
   /*            1 -- checked                                        */
   /* enable --- 0 -- the node is disabled (normal checkbox)         */
   /*            1 -- the node is enabled  (gray checkbox)           */
   /*            2 -- hidden (no checkbox at all)                    */
   COptNode(char txt[], int isxcl, int chksti, int enable);


   /* constructor for branch nodes                                   */
   /* txt    --- the name of the node. displayed in the listbox      */
   /* isxcl  --- if this node is exclusive or not. if it is, when it */
   /*            is selected, all its siblings will be deselected    */
   /* isexp  --- if this node is expanded at startup                 */
   COptNode(char txt[], int isxcl, int isexp);

   /* return the no of kids under this node */
   int getnokids();


   /* return the i'th kid under this node */
   COptNode *getkid(int i);


   /* append a kid to this node. begappendkid() must be called before */
   int appendkid(COptNode *p);


   /* begin appending kids to this node */
   void begappendkid();


   /* finish appending kids to this node */
   void endappendkid();

};



2. COptTree


This is the class for control. Note that it is not really a tree. It is a control
containing possibly more than one trees.


class COptTree:public CWnd
{
   enum
   {
      gap1 = 3, gap2 = 25
   };

   int h;                                           /* the height of each item */
   int tidx;                                                      /* top index */
   int hoff;        /* when listbox is horizontally scrolled, it is the offset */
   int hext;                                                    /* horz extent */
   int noshown;                                     /* total no of nodes shown */
   int isindinv;          /* invalidate individual nodes when triggering check */
   int isshowdot;                 /* show a dot as a leaf node's expand button */
   CFont *fo;                                                        /* helv 9 */
   COptNode *tp;                                                   /* top node */
   COptNode *sel;                                 /* the selected node, if any */
   COptNodeList roots;              /* every root starts a tree in the control */

   public:

   /* parent    --- the parent window                                          */
   /* id        --- the ID of the listbox. The listbox must be unsorted, fixed */
   /*               owner-drawn, not having strings                            */
   /* isshowdot --- true  -- draw a dot as the expand button for leaf nodes    */
   /*               false -- don't draw expand buttons of any form for leaf    */
   /*                        nodes. don't even leave space for them            */
   /* isindinv  --- true  -- invalidate individual nodes when checking or      */
   /*                        clearing the nodes                                */
   /*               false -- invalidate the whole control when checking or     */
   /*                        clearing the nodes                                */
   COptTree(CWnd *parent, int isshowdot = 1, int isindinv = 0);

  ~COptTree();


   /* check if p is selected */
   int chksel(COptNode *p);


   /* append another tree to the control. before calling this begappendroot() */
   /* must be called                                                          */
   /* p --- the root of the tree                                              */
   /* return: true  -- ok                                                     */
   /*         false -- error                                                  */
   int appendroot(COptNode *p);


   /* create the window element                                           */
   /* id    --- the id of the control                                     */
   /* posid --- the id of another control whose pos & size will be copied */
   void create(int id, int posid);


   /* delete all nodes in the ctrl */
   void freeallnodes();


   /* begin appending roots to the control */
   void begappendroot();


   /* finish appending roots to the control */
   void endappendroot();


   /* try set the check state of the node           */
   /* p      --- the node to be set                 */
   /* chksti --- the ideal check state of the node  */
   /* isback --- go back to update ancestors or not */
   void trychk(COptNode *p, int chksti, int isback = 1);


   /* select the node */
   void trigsel(COptNode *p);


   /* toggle the check state of the node */
   void trigchk(COptNode *p);


   /* toggle the expand/collapse state of the node */
   void trigexp(COptNode *p);


   /* invalidate the part of the control corresponding to the node */
   /* for future redraw                                            */
   void invalidate(COptNode *p);


   /* given the sequential index, return the node */
   COptNode *i2n(int i);


   /* get the currently selected node. return 0 if none is selected */
   COptNode *getsel();


   /* get the first node in the control */
   COptNode *getfrst();


   /* get the last node of p in a depth first search manner */
   COptNode *getlast(COptNode *p);


   /* get the next node of p in a depth first search manner */
   COptNode *getnext(COptNode *p);


   /* get the last sibling of p in a depth first search manner */
   /* if p is a root in the control, it will return the root   */
   /* next to p                                                */
   COptNode *getlastsibling(COptNode *p);


   /* get the next sibling of p in a depth first search manner */
   /* if p is a root in the control, it will return the root   */
   /* next to p                                                */
   COptNode *getnextsibling(COptNode *p);



   protected:

   /* three notification functions. if you want to catch the notification */
   /* you should derive your own class from COptTree and define the       */
   /* notification functions                                              */

   /* p is just selected */
   virtual void notifyselchg(COptNode *p)

   /* check state of p has changed */
   virtual void notifychkchg(COptNode *p)

   /* check state of some nodes have changed and all have been notified on */
   virtual void notifychkchgend()
};


Sample Code
===========

Check with ottest.cpp for a working example on how to use the control.

