00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "treebox.hpp"
00035 #include "data/config.hpp"
00036 #include "platform/font.hpp"
00037 #include "platform/lowlevel.hpp"
00038
00039 namespace gsgl
00040 {
00041
00042 using namespace data;
00043 using namespace platform;
00044
00045 namespace framework
00046 {
00047
00048 static config_variable<int> PLUS_WIDTH(L"framework/treebox/plus_width", 8);
00049
00050
00051 class treebox_plus
00052 : public widget
00053 {
00054 treebox_node *parent_node;
00055 public:
00056 treebox_plus(treebox_node *parent, const color & fg, const color & bg);
00057 virtual ~treebox_plus();
00058
00059 virtual void draw();
00060 virtual bool handle_event(const SDL_Event &);
00061 };
00062
00063
00064 treebox_plus::treebox_plus(treebox_node *parent, const color & fg, const color & bg)
00065 : widget(parent, 0, 0, 0, 0, fg, bg), parent_node(parent)
00066 {
00067
00068 }
00069
00070
00071 treebox_plus::~treebox_plus()
00072 {
00073
00074 }
00075
00076
00077 void treebox_plus::draw()
00078 {
00079 if (parent_node->get_tree_nodes().size())
00080 {
00081 get_foreground().set();
00082 glLineWidth(3.0f);
00083
00084 glBegin(GL_LINES);
00085
00086 glVertex2i(get_x(), get_y() + get_h()/2);
00087 glVertex2i(get_x() + get_w(), get_y() + get_h()/2);
00088
00089 if (!parent_node->get_expanded())
00090 {
00091 glVertex2i(get_x() + get_w()/2, get_y() + get_h()/2 - PLUS_WIDTH/2);
00092 glVertex2i(get_x() + get_w()/2, get_y() + get_h()/2 + PLUS_WIDTH/2);
00093 }
00094
00095 glEnd();
00096 }
00097 }
00098
00099
00100 bool treebox_plus::handle_event(const SDL_Event & e)
00101 {
00102 if (e.type == SDL_MOUSEBUTTONUP)
00103 {
00104 if (parent_node->get_children().size())
00105 parent_node->get_expanded() = !parent_node->get_expanded();
00106 return true;
00107 }
00108 return false;
00109 }
00110
00111
00112
00113 treebox_node::treebox_node(treebox *parent_treebox, treebox_node *parent_node, const color & fg, const color & bg, const string & text, void *user_data)
00114 : widget(parent_treebox, 0, 0, 0, 0, fg, bg), parent_treebox(parent_treebox), parent_node(parent_node), plus_widget(0), text_widget(0), expanded(false), indent(0), user_data(user_data)
00115 {
00116
00117
00118 if (parent_treebox && !parent_node)
00119 parent_treebox->get_tree_nodes().append(this);
00120 if (parent_node)
00121 parent_node->get_tree_nodes().append(this);
00122
00123 plus_widget = new treebox_plus(this, fg, bg);
00124 text_widget = new textbox(this, 0, 0, 0, 0, fg, bg,
00125 parent_treebox->get_text_font()->get_face(),
00126 parent_treebox->get_text_font()->get_size());
00127 text_widget->get_text() = text;
00128 }
00129
00130
00131 treebox_node::~treebox_node()
00132 {
00133
00134
00135 }
00136
00137
00138 void treebox_node::clear_tree_nodes()
00139 {
00140 for (list<treebox_node *>::iterator i = tree_nodes.iter(); i.is_valid(); ++i)
00141 {
00142 (*i)->clear_tree_nodes();
00143 parent_treebox->remove_child(*i);
00144 delete *i;
00145 }
00146
00147 tree_nodes.clear();
00148 }
00149
00150
00151 void treebox_node::draw()
00152 {
00153 plus_widget->get_x() = 0;
00154 plus_widget->get_y() = 0;
00155 plus_widget->get_w() = PLUS_WIDTH;
00156 plus_widget->get_h() = get_h();
00157
00158 text_widget->get_x() = PLUS_WIDTH;
00159 text_widget->get_y() = 0;
00160 text_widget->get_w() = get_w() - PLUS_WIDTH;
00161 text_widget->get_h() = get_h();
00162
00163 if (this == parent_treebox->get_selected_node())
00164 {
00165 glDisable(GL_BLEND);
00166 get_foreground().set();
00167 glLineWidth(1.0f);
00168
00169 glBegin(GL_LINE_STRIP);
00170 glVertex2i(PLUS_WIDTH, 0);
00171 glVertex2i(get_w(), 0);
00172 glVertex2i(get_w(), get_h());
00173 glVertex2i(PLUS_WIDTH, get_h());
00174 glVertex2i(PLUS_WIDTH, 0);
00175 glEnd();
00176 }
00177 }
00178
00179
00180 bool treebox_node::handle_event(const SDL_Event & e)
00181 {
00182 if (e.type == SDL_MOUSEBUTTONDOWN)
00183 {
00184 if (button_down_here(e.button.button))
00185 {
00186 parent_treebox->get_selected_node() = this;
00187 }
00188
00189
00190 }
00191
00192 return false;
00193 }
00194
00195
00196
00197 static config_variable<int> SCROLL_WIDTH(L"framework/treebox/scroll_width", 16);
00198
00199
00200 treebox::treebox(widget *parent, int x, int y, int w, int h, const color & fg, const color & bg, const string & font_face, const int font_size)
00201 : widget(parent, x, y, w, h, fg, bg), text_font(0), side_scroll(0), selected_node(0)
00202 {
00203 text_font = new font(font_face, font_size, fg);
00204 side_scroll = new scrollbar(this, w-SCROLL_WIDTH, 0, SCROLL_WIDTH, h, fg, bg);
00205 side_scroll->set_flags(WIDGET_INVISIBLE, true);
00206 }
00207
00208
00209 treebox::~treebox()
00210 {
00211 delete text_font;
00212 }
00213
00214
00215 void treebox::clear_tree_nodes()
00216 {
00217 simple_array<treebox_node *> nodes_to_remove;
00218
00219 for (list<treebox_node *>::iterator i = tree_nodes.iter(); i.is_valid(); ++i)
00220 {
00221 treebox_node *n = *i;
00222 n->clear_tree_nodes();
00223 nodes_to_remove.append(n);
00224 }
00225
00226 for (simple_array<treebox_node *>::iterator i = nodes_to_remove.iter(); i.is_valid(); ++i)
00227 {
00228 treebox_node *n = *i;
00229 remove_child(n);
00230 delete n;
00231 }
00232
00233 tree_nodes.clear();
00234 }
00235
00236
00237 void treebox::draw()
00238 {
00239 const int list_item_height = text_font->get_size() * 4 / 3;
00240
00241
00242 nodes_to_draw.clear();
00243
00244 for (list<treebox_node *>::iterator n = tree_nodes.iter(); n.is_valid(); ++n)
00245 {
00246 mark_expanded_nodes(*n, true, 0);
00247 }
00248
00249
00250 side_scroll->get_min() = 0;
00251 side_scroll->get_max() = nodes_to_draw.size();
00252 side_scroll->get_extent() = min_val(get_h() / list_item_height, nodes_to_draw.size());
00253
00254
00255 bool draw_scroll_bar = nodes_to_draw.size() > side_scroll->get_extent();
00256 int start_index = side_scroll->get_pos();
00257 int num_to_draw = draw_scroll_bar ? side_scroll->get_extent() : nodes_to_draw.size();
00258
00259
00260 for (int i = 0; i < nodes_to_draw.size(); ++i)
00261 {
00262 if (i < start_index || i > start_index+num_to_draw)
00263 {
00264 nodes_to_draw[i]->set_flags(WIDGET_INVISIBLE, true);
00265 }
00266 else
00267 {
00268 treebox_node *n = nodes_to_draw[i];
00269
00270 n->set_flags(WIDGET_INVISIBLE, false);
00271 n->get_x() = get_x() + n->get_indent() * PLUS_WIDTH;
00272 n->get_y() = get_y() + get_h() - (list_item_height * (1 + i - start_index));
00273 n->get_w() = get_w() - (n->get_indent()*PLUS_WIDTH + (draw_scroll_bar ? SCROLL_WIDTH : 0));
00274 n->get_h() = list_item_height;
00275 }
00276 }
00277
00278
00279 }
00280
00281
00282 void treebox::mark_expanded_nodes(treebox_node *n, bool visible, int indent)
00283 {
00284 if (visible)
00285 nodes_to_draw.append(n);
00286
00287 n->set_flags(WIDGET_INVISIBLE, !visible);
00288 n->get_indent() = indent;
00289
00290 for (list<treebox_node *>::iterator child = n->get_tree_nodes().iter(); child.is_valid(); ++child)
00291 {
00292 mark_expanded_nodes(*child, visible && n->get_expanded(), indent+1);
00293 }
00294 }
00295
00296 }
00297
00298 }