
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. Create the control obj:


class TDlgTest:public TDialog
{
   TOptTree *otc;

   public:

   TDlgTest(TWindow *parent, TResID id);

};


TDlgTest::TDlgTest(TWindow *parent, TResID id)::TDialog(parent, id)
{
   otc = new OptTree(this);                 /* create the control obj (no wnd) */
   ......
}


3. Create the nodes and build up the trees:


TDlgTest::TDlgTest(TWindow *parent, TResID id)::TDialog(parent, id)
{
   TOptNode *p;                                    /* the root of the 1st tree */
   TOptNode *r;                                    /* the root of the 2nd tree */
   TOptNode *q;                                             /* for scratch use */

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

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

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

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

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

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

      q = new TOptNode("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 */
}


4. Create the window element in SetupWindow():


void TDlgTest::SetupWindow()
{
   TDialog::SetupWindow();

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




5. Delete nodes when the dialog is close:


void TDlgTest::CleanupWindow()
{
   otc->freeallnodes();

   TDialog::CleanupWindow();
}


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

1. TOptNode


This is the class for the nodes in the control.


class TOptNode
{
   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 */
   TOptNode *dad;                                                  /* dad node */
   TOptNode *last;                                             /* last sibling */
   TOptNode *next;                                             /* next sibling */
   TOptNodeList 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)                    */
   TOptNode(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                 */
   TOptNode(char txt[], int isxcl, int isexp);

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


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


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


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


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

};



2. TOptTree


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 TOptTree:public TWindow
{
   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 */
   TFont *fo;                                                        /* helv 9 */
   TOptNode *tp;                                                   /* top node */
   TOptNode *sel;                                 /* the selected node, if any */
   TOptNodeList 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                                */
   TOptTree(TWindow *parent, int isshowdot = 1, int isindinv = 0);

  ~TOptTree();


   /* check if p is selected */
   int chksel(TOptNode *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(TOptNode *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(TOptNode *p, int chksti, int isback = 1);


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


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


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


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


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


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


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


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


   /* get the next node of p in a depth first search manner */
   TOptNode *getnext(TOptNode *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                                                */
   TOptNode *getlastsibling(TOptNode *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                                                */
   TOptNode *getnextsibling(TOptNode *p);



   protected:

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

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

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

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


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

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

