cwidget
0.5.16
|
00001 // subtree.h (this is -*-c++-*-) 00002 // 00003 // Copyright 1999-2003, 2005 Daniel Burrows 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 2 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; see the file COPYING. If not, write to 00017 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 // Boston, MA 02111-1307, USA. 00019 // 00020 // Subtrees for trees. 00021 00022 #ifndef SUBTREE_H 00023 #define SUBTREE_H 00024 00025 #include <list> 00026 #include "treeitem.h" 00027 #include "tree.h" 00028 00029 #include <cwidget/config/keybindings.h> 00030 00031 namespace cwidget 00032 { 00033 namespace widgets 00034 { 00035 template<class childtype, class default_sorter=tag_sort_policy> 00036 class subtree:virtual public treeitem 00037 // A tree-item which can contain other tree items. Still abstract -- the 00038 // display routines have to be filled in, and you may want to add more behavior 00039 // on keypresses -- but we're getting there :) 00040 { 00041 protected: 00042 00043 typedef std::list<childtype *> child_list; 00044 typedef typename std::list<childtype *>::iterator child_iterator; 00045 00046 class levelref:public tree_levelref 00047 { 00048 child_iterator realitem; 00049 00050 child_list *parent_list; 00051 public: 00052 levelref(const levelref &x) 00053 :tree_levelref(x), realitem(x.realitem), parent_list(x.parent_list) {} 00054 levelref(const child_iterator &_realitem, child_list *_parent_list) 00055 :realitem(_realitem), parent_list(_parent_list) 00056 { 00057 } 00058 00059 treeitem *get_item() {eassert(realitem!=parent_list->end()); return *realitem;} 00060 virtual void advance_next() {++realitem;} 00061 virtual void return_prev() {--realitem;} 00062 bool is_begin() {return realitem==parent_list->begin();} 00063 bool is_end() {return realitem==parent_list->end();} 00064 levelref *clone() const {return new levelref(*this);} 00065 }; 00066 00067 private: 00068 bool expanded; 00069 00070 child_list children; 00071 00072 protected: 00073 child_iterator get_children_begin() {return children.begin();} 00074 child_iterator get_children_end() {return children.end();} 00075 00076 public: 00077 typedef treeiterator iterator; 00078 typedef default_sorter default_sort; 00079 00080 subtree(bool _expanded):treeitem(),expanded(_expanded) {} 00081 00082 bool get_expanded() {return expanded;} 00083 00084 void expand() {expanded=true;} 00085 00086 void expand_all() 00087 { 00088 expanded=true; 00089 for(child_iterator i=children.begin(); i!=children.end(); i++) 00090 (*i)->expand_all(); 00091 } 00092 00093 void collapse_all() 00094 { 00095 expanded=false; 00096 for(child_iterator i=children.begin(); i!=children.end(); i++) 00097 (*i)->collapse_all(); 00098 } 00099 00100 void paint(tree *win, int y, bool hierarchical, 00101 const std::wstring &str, int depth_shift=2) 00102 { 00103 int width, height; 00104 int basex=hierarchical?depth_shift*get_depth():0; 00105 win->getmaxyx(height,width); 00106 00107 win->move(y,0); 00108 00109 int x=0; 00110 while(x<basex && x<width) 00111 { 00112 win->add_wch(L' '); 00113 x+=wcwidth(L' '); 00114 } 00115 00116 if(basex>width) 00117 return; 00118 00119 const wchar_t *ws; 00120 if(hierarchical) 00121 ws=get_expanded()?L"--\\ ":L"--- "; 00122 else 00123 ws=L"-> "; 00124 00125 while(*ws!=0 && x<width) 00126 { 00127 win->add_wch(*ws); 00128 x+=wcwidth(*ws); 00129 ++ws; 00130 } 00131 00132 if(x>=width) 00133 return; 00134 00135 size_t i=0; 00136 while(i<str.size() && x<width) 00137 { 00138 wchar_t ch=str[i]; 00139 00140 win->add_wch(ch); 00141 x+=wcwidth(ch); 00142 ++i; 00143 } 00144 00145 while(x<width) 00146 { 00147 win->add_wch(L' '); 00148 x+=wcwidth(L' '); 00149 } 00150 } 00151 00152 void set_depth(int _depth) 00153 { 00154 for(child_iterator i=children.begin(); i!=children.end(); i++) 00155 (*i)->set_depth(_depth+1); 00156 00157 treeitem::set_depth(_depth); 00158 } 00159 00160 void add_child(childtype *newchild) 00161 { 00162 newchild->set_depth(get_depth()+1); 00163 00164 children.push_back(newchild); 00165 } 00166 00167 // Adds a new child item at an unspecified location -- you should call sort() 00168 // after adding children or the tree will have an undetermined order. (yes, 00169 // you can deduce the real order. Don't.) 00170 void sort(sortpolicy &sort_method) 00171 { 00172 for(child_iterator i=children.begin(); i!=children.end(); i++) 00173 (*i)->sort(sort_method); 00174 00175 children.sort(sortpolicy_wrapper(sort_method)); 00176 } 00177 00178 void sort() 00179 { 00180 default_sort sorter; 00181 sort(sorter); 00182 } 00183 00184 virtual bool dispatch_key(const config::key &k, tree *owner) 00185 { 00186 if(tree::bindings->key_matches(k, "ToggleExpanded")) 00187 { 00188 expanded=!expanded; 00189 return true; 00190 } 00191 else if(tree::bindings->key_matches(k, "ExpandTree")) 00192 { 00193 if(!expanded) 00194 { 00195 expanded=true; 00196 return true; 00197 } 00198 else 00199 return false; 00200 } 00201 else if(tree::bindings->key_matches(k, "CollapseTree")) 00202 { 00203 if(expanded) 00204 { 00205 expanded=false; 00206 return true; 00207 } else 00208 return false; 00209 } 00210 else if(tree::bindings->key_matches(k, "ExpandAll")) 00211 { 00212 expand_all(); 00213 return true; 00214 } 00215 else if(tree::bindings->key_matches(k, "CollapseAll")) 00216 { 00217 collapse_all(); 00218 return true; 00219 } 00220 return false; 00221 } 00222 // The default action is to expand or shrink the tree when Enter is pressed. 00223 // FIXME: should I use '+' and '-' here? That would appear to conflict with 00224 // the other keybindings I need. Hm. 00225 00226 virtual void dispatch_mouse(short id, int x, mmask_t bstate, tree *owner) 00227 { 00228 if(bstate & (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | 00229 BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED | 00230 BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | 00231 BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED)) 00232 expanded=!expanded; 00233 } 00234 00235 virtual levelref *begin() {return new levelref(children.begin(), &children);} 00236 virtual levelref *end() {return new levelref(children.end(), &children);} 00237 00238 bool has_visible_children() {return expanded && children.size()>0;} 00239 bool has_children() {return children.size()>0;} 00240 00241 virtual ~subtree() 00242 { 00243 child_iterator i,j; 00244 for(i=children.begin(); i!=children.end(); i=j) 00245 { 00246 j=i; 00247 j++; 00248 delete *i; 00249 } 00250 } 00251 }; 00252 00253 class subtree_generic:public subtree<treeitem> 00254 { 00255 public: 00256 subtree_generic(int _expanded):subtree<treeitem>(_expanded) {} 00257 }; 00258 } 00259 } 00260 00261 #endif