wmi

git clone git://oldgit.suckless.org/wmi/
Log | Files | Refs | LICENSE

container.h (6625B)


      1 // Copyright (c) 2003 - 2009 Anselm R Garbe <anselm@garbe.us>
      2 // See LICENSE for license details.
      3 
      4 #ifndef __CONTAINER_H
      5 #define __CONTAINER_H
      6 
      7 #include "kernel.h"
      8 #include "util.h" // also includes wmi.h
      9 
     10 /**
     11  * A Container object keeps a parent reference and may contain a list of
     12  * child objects.
     13  *
     14  * A Container is a class template that creates an object that contains a list
     15  * of other objects and also keeps a reference to a parent object.
     16  * A container can be configured with for stacked tabbing at compile time.
     17  *
     18  * @param P the parent class
     19  * @param LT the child list class
     20  * @param LTI the iterator class for the child list 
     21  * @param T the child class 
     22  */
     23 template <class P, class LT, class LTI, class T>
     24     class Container
     25 {
     26 public:
     27 
     28     /**
     29      * Constructs a container with a parent and a focused child. 
     30      *
     31      * @param parent the original parent. 
     32      * @param child the original focused child which is optional.
     33      */
     34     Container(P *parent, T *child = 0) {
     35         parent_ = parent;
     36         child_ = child;
     37     };
     38 
     39     /**
     40      * The destructor.
     41      *
     42      * When the destructor is destoryed it will also destroys 
     43      * all of the children in the container.
     44      */
     45     ~Container() {
     46         Util::destroy<LT, LTI, T *>
     47                  (&childs_, childs_.begin(), childs_.end());
     48     };
     49 
     50     /**
     51      * Checks if the child is contained in this container.
     52      *
     53      * @param child the child to search for.
     54      */
     55     bool contains(T *child) {
     56         return Util::contains<LT, LTI, T>(&childs_, child);
     57     };
     58 
     59     /** 
     60      * Get the number of children in this container.
     61      *
     62      * @return the the number of children
     63      */
     64     unsigned int size() {
     65         return childs_.size();
     66     };
     67 
     68     /**
     69      * Get the list iterator to the first child.
     70      *
     71      * @return the list iterator to first child. 
     72      */
     73     LTI begin() {
     74         return childs_.begin();
     75     };
     76 
     77     /** 
     78      * Get the list iterator to end of child list. 
     79      *
     80      * @return the list iterator to the last child.
     81      */
     82     LTI end() {
     83         return childs_.end();
     84     };
     85 
     86     /** 
     87      * Get the parent that the container is attached to. 
     88      *
     89      * @return the parent.
     90      */
     91     P *attached() const {
     92         return parent_;
     93     };
     94 
     95     /** 
     96      * Attach the container to a new parent. 
     97      *
     98      * @param parent the parent. 
     99      */
    100     void setAttached(P *parent) {
    101         parent_ = parent;
    102     };
    103 
    104     /** 
    105      * Get the currently focused child in the container. 
    106      *
    107      * @return the focused child, if any.
    108      */
    109     T *focused() const {
    110         return child_;
    111     };
    112 
    113     /** 
    114      * Gives a child focus. 
    115      *
    116      * In normal mode the child simply receives focus.  In stacked
    117      * tabbing mode the currently focused child will be placed at
    118      * the end of the list and the newly focused child will be placed
    119      * at the front.
    120      *
    121      * @param child the child to receive focus.
    122      */
    123     void focus(T *child) {
    124         if (child && KERNEL->isStackedTabbing()) {
    125             if (childs_.size()) {
    126                 T *foc = childs_.front();
    127                 if (foc != child) {
    128                     childs_.remove(foc);
    129                     childs_.push_back(foc);
    130                 }
    131             }
    132             childs_.remove(child);
    133             childs_.push_front(child);
    134         }
    135         child_ = child;
    136     };
    137 
    138     /** 
    139      * Attaches a child to the container. 
    140      *
    141      * This attaches a new child to the container.
    142      * When a child is attached it receives focus.
    143      * <code>attach()</code> will not add a duplicate child to the container.
    144      *
    145      * @param child the child to attach.
    146      */
    147     void attach(T *child) {
    148         if (child && !contains(child)) {
    149             childs_.push_back(child);
    150             focus(child);
    151         }
    152     };
    153 
    154     /** 
    155      * Detach a child from the container.
    156      *
    157      * Detaches the child from the container.  If the child being detached
    158      * currently has focus then the focus will switch to the previous child.
    159      * If this was the last child left in the container than there will be no
    160      * child with focus. 
    161      *
    162      * @param child the child to detach.
    163      * @return the current child with focus.
    164      */
    165     T *detach(T *child) {
    166 
    167         if (child_ == child) {
    168             // cycle to prev child
    169             focus(prev());
    170         }
    171         childs_.remove(child);
    172 
    173         if (childs_.size() < 1) {
    174             child_ = 0;
    175         }
    176         return child_;
    177     };
    178 
    179     /**
    180      * Get the previous child in the list.
    181      *
    182      * In stacked tabbing mode this is the last child.  In regular
    183      * mode this is the child before the currently focused child.
    184      *
    185      * @return the previous child.
    186      */
    187     T *prev() {
    188 
    189         if (childs_.size() < 1) {
    190             return 0;
    191         }
    192         else if (childs_.size() < 2) {
    193             return child_;
    194         }
    195 
    196         if (KERNEL->isStackedTabbing()) {
    197             return childs_.back();
    198         }
    199         else {
    200             for (LTI it = childs_.begin();
    201                     it != childs_.end(); it++)
    202             {
    203                 if (child_ == *it) {
    204                     if (it != childs_.begin()) {
    205                         it--;
    206                         return *it;
    207                     }
    208                     else {
    209                         break;
    210                     }
    211                 }
    212             }
    213             return childs_.back();
    214         }
    215     }
    216 
    217 
    218     /**
    219      * Get the next child in the list.
    220      *
    221      * In stacked tabbing mode this is the second child in the list.
    222      * In regular mode it is the child after the currently focused child.
    223      *
    224      * @return the next child.
    225      */
    226     T *next() {
    227         if (childs_.size() < 1) {
    228             return 0;
    229         }
    230         else if (childs_.size() < 2) {
    231             return child_;
    232         }
    233 
    234         if (KERNEL->isStackedTabbing()) {
    235             LTI it = childs_.begin();
    236             it++;
    237             return *it;
    238         }
    239         else {
    240             for (LTI it = childs_.begin();
    241                     it != childs_.end(); it++)
    242             {
    243                 if (child_ == *it) {
    244                     it++;
    245                     if (it != childs_.end()) {
    246                         return *it;
    247                     }
    248                     else {
    249                         break;
    250                     }
    251                 }
    252             }
    253             return childs_.front();
    254         }
    255     };
    256 
    257     /** Used for direct manipulation, use with care! */
    258     LT *childs() {
    259         return &childs_;
    260     }
    261 
    262 
    263 private:
    264 
    265     P *parent_;
    266     T *child_;
    267     LT childs_;
    268 };
    269 
    270 #endif // __CONTAINER_H