00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017
00018 #include "gui/widgets/tree_view_node.hpp"
00019
00020 #include "gettext.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 #include "gui/widgets/toggle_button.hpp"
00023 #include "gui/widgets/toggle_panel.hpp"
00024 #include "gui/widgets/tree_view.hpp"
00025
00026 #include <boost/bind.hpp>
00027
00028 #define LOG_SCOPE_HEADER \
00029 get_control_type() + " [" + tree_view().id() + "] " + __func__
00030 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00031
00032 namespace gui2 {
00033
00034 ttree_view_node::ttree_view_node(const std::string& id
00035 , const std::vector<tnode_definition>& node_definitions
00036 , ttree_view_node* parent_node
00037 , ttree_view& parent_tree_view
00038 , const std::map<std::string /* widget id */, string_map>& data)
00039 : twidget()
00040 , parent_node_(parent_node)
00041 , tree_view_(parent_tree_view)
00042 , grid_()
00043 , children_()
00044 , node_definitions_(node_definitions)
00045 , icon_(NULL)
00046 , label_(NULL)
00047 {
00048 grid_.set_parent(this);
00049 set_parent(&parent_tree_view);
00050 if(id != "root") {
00051 foreach(const tnode_definition& node_definition, node_definitions_) {
00052 if(node_definition.id == id) {
00053 node_definition.builder->build(&grid_);
00054 init_grid(&grid_, data);
00055
00056 icon_ = find_widget<ttoggle_button>(
00057 &grid_
00058 , "tree_view_node_icon"
00059 , false
00060 , false);
00061
00062 if(icon_) {
00063 icon_->set_visible(twidget::HIDDEN);
00064 icon_->connect_signal<event::LEFT_BUTTON_CLICK>(
00065 boost::bind(&ttree_view_node::
00066 signal_handler_left_button_click
00067 , this, _2));
00068
00069 }
00070
00071 if(parent_node_ && parent_node_->icon_) {
00072 parent_node_->icon_->set_visible(twidget::VISIBLE);
00073 }
00074
00075 twidget& widget = find_widget<twidget>(
00076 &grid_
00077 , "tree_view_node_label"
00078 , false);
00079
00080 label_ = dynamic_cast<tselectable_*>(&widget);
00081 if(label_) {
00082 widget.connect_signal<event::LEFT_BUTTON_CLICK>(
00083 boost::bind(&ttree_view_node::
00084 signal_handler_label_left_button_click
00085 , this, _2, _3, _4)
00086 , event::tdispatcher::front_child);
00087 widget.connect_signal<event::LEFT_BUTTON_CLICK>(
00088 boost::bind(&ttree_view_node::
00089 signal_handler_label_left_button_click
00090 , this, _2, _3, _4)
00091 , event::tdispatcher::front_pre_child);
00092
00093 if(!tree_view().selected_item_) {
00094 tree_view().selected_item_ = this;
00095 label_->set_value(true);
00096 }
00097 }
00098
00099 return;
00100 }
00101 }
00102
00103 VALIDATE(false, _("Unknown builder id for tree view node."));
00104 }
00105 }
00106
00107 ttree_view_node::~ttree_view_node()
00108 {
00109 if( tree_view().selected_item_ == this) {
00110 tree_view().selected_item_ = NULL;
00111 }
00112 }
00113
00114 ttree_view_node& ttree_view_node::add_child(
00115 const std::string& id
00116 , const std::map<std::string /* widget id */, string_map>& data
00117 , const int index)
00118 {
00119
00120 boost::ptr_vector<ttree_view_node>::iterator itor = children_.end();
00121
00122 if(static_cast<size_t>(index) < children_.size()) {
00123 itor = children_.begin() + index;
00124 }
00125
00126 itor = children_.insert(itor, new ttree_view_node(
00127 id
00128 , node_definitions_
00129 , this
00130 , tree_view()
00131 , data));
00132
00133 if(is_folded() || is_root_node()) {
00134 return *itor;
00135 }
00136
00137 if(tree_view().get_size() == tpoint(0, 0)) {
00138 return *itor;
00139 }
00140
00141 assert(tree_view().content_grid());
00142 const int current_width = tree_view().content_grid()->get_width();
00143
00144
00145 tpoint best_size = itor->get_best_size();
00146 best_size.x += get_indention_level() * tree_view().indention_step_size_;
00147 const unsigned width_modification = best_size.x > current_width
00148 ? best_size.x - current_width
00149 : 0;
00150
00151
00152 const int height_modification = best_size.y;
00153 assert(height_modification > 0);
00154
00155
00156 tree_view().resize_content(width_modification, height_modification);
00157
00158 return *itor;
00159 }
00160
00161 unsigned ttree_view_node::get_indention_level() const
00162 {
00163 unsigned level = 0;
00164
00165 const ttree_view_node* node = this;
00166 while(!node->is_root_node()) {
00167 node = &node->parent_node();
00168 ++level;
00169 }
00170
00171 return level;
00172 }
00173
00174 ttree_view_node& ttree_view_node::parent_node()
00175 {
00176 assert(!is_root_node());
00177 return *parent_node_;
00178 }
00179
00180 const ttree_view_node& ttree_view_node::parent_node() const
00181 {
00182 assert(!is_root_node());
00183 return *parent_node_;
00184 }
00185
00186 ttree_view& ttree_view_node::tree_view()
00187 {
00188 return tree_view_;
00189 }
00190
00191 const ttree_view& ttree_view_node::tree_view() const
00192 {
00193 return tree_view_;
00194 }
00195
00196 bool ttree_view_node::is_folded() const
00197 {
00198 return icon_ && icon_->get_value();
00199 }
00200 #if 0
00201 void ttree_view_node::fold(const bool )
00202 {
00203
00204
00205 }
00206
00207 void ttree_view_node::unfold(const texpand_mode )
00208 {
00209
00210
00211 }
00212 #endif
00213
00214 void ttree_view_node::clear()
00215 {
00216
00217 int height_reduction = 0;
00218
00219 if(!is_folded()) {
00220 foreach(const ttree_view_node& node, children_) {
00221 height_reduction += node.get_current_size().y;
00222 }
00223 }
00224
00225 children_.clear();
00226
00227 if(height_reduction == 0) {
00228 return;
00229 }
00230
00231 tree_view().resize_content(0, -height_reduction);
00232 }
00233
00234 struct ttree_view_node_implementation
00235 {
00236 private:
00237
00238 template<class W, class It>
00239 static W* find_at_aux(
00240 It begin
00241 , It end
00242 , const tpoint& coordinate
00243 , const bool must_be_active)
00244 {
00245 for(It it = begin; it != end; ++it) {
00246 if(W* widget = it->find_at(coordinate, must_be_active)) {
00247 return widget;
00248 }
00249 }
00250 return NULL;
00251 }
00252
00253 public:
00254
00255 template<class W>
00256 static W* find_at(
00257 typename utils::tconst_clone<ttree_view_node, W>::reference
00258 tree_view_node
00259 , const tpoint& coordinate, const bool must_be_active)
00260 {
00261 if(W* widget =
00262 tree_view_node.grid_.find_at(coordinate, must_be_active)) {
00263
00264 return widget;
00265 }
00266
00267 if(tree_view_node.is_folded()) {
00268 return NULL;
00269 }
00270
00271 typedef typename utils::tconst_clone<ttree_view_node, W>::type thack;
00272 return find_at_aux<W>(tree_view_node.children_.begin(),
00273 tree_view_node.children_.end(),
00274 coordinate, must_be_active);
00275 }
00276 };
00277
00278 twidget* ttree_view_node::find_at(
00279 const tpoint& coordinate
00280 , const bool must_be_active)
00281 {
00282 return ttree_view_node_implementation::find_at<twidget>(
00283 *this, coordinate, must_be_active);
00284 }
00285
00286 const twidget* ttree_view_node::find_at(
00287 const tpoint& coordinate
00288 , const bool must_be_active) const
00289 {
00290 return ttree_view_node_implementation::find_at<const twidget>(
00291 *this, coordinate, must_be_active);
00292 }
00293
00294 void ttree_view_node::impl_populate_dirty_list(twindow& caller
00295 , const std::vector<twidget*>& call_stack)
00296 {
00297 std::vector<twidget*> child_call_stack = call_stack;
00298 grid_.populate_dirty_list(caller, child_call_stack);
00299
00300 if(is_folded()) {
00301 return;
00302 }
00303
00304 foreach(ttree_view_node& node, children_) {
00305 std::vector<twidget*> child_call_stack = call_stack;
00306 node.impl_populate_dirty_list(caller, child_call_stack);
00307 }
00308 }
00309
00310 tpoint ttree_view_node::calculate_best_size() const
00311 {
00312 return calculate_best_size(-1, tree_view().indention_step_size_);
00313 }
00314
00315 tpoint ttree_view_node::get_current_size() const
00316 {
00317 if(parent_node_ && parent_node_->is_folded()) {
00318 return tpoint(0, 0);
00319 }
00320
00321 tpoint size = get_folded_size();
00322 if(is_folded()) {
00323 return size;
00324 }
00325
00326 for(boost::ptr_vector<ttree_view_node>::const_iterator itor =
00327 children_.begin (); itor != children_.end (); ++itor) {
00328
00329 const ttree_view_node& node = *itor;
00330
00331 if(node.grid_.get_visible() == twidget::INVISIBLE) {
00332 continue;
00333 }
00334
00335 tpoint node_size = node.get_current_size();
00336
00337 size.y += node_size.y;
00338 size.x = std::max(size.x, node_size.x);
00339 }
00340
00341 return size;
00342 }
00343
00344 tpoint ttree_view_node::get_folded_size() const
00345 {
00346 tpoint size = grid_.get_size();
00347 if(get_indention_level() > 1) {
00348 size.x += (get_indention_level() - 1) * tree_view().indention_step_size_;
00349 }
00350 return size;
00351 }
00352
00353 tpoint ttree_view_node::get_unfolded_size() const
00354 {
00355 tpoint size = grid_.get_best_size();
00356 if(get_indention_level() > 1) {
00357 size.x += (get_indention_level() - 1) * tree_view().indention_step_size_;
00358 }
00359
00360 for(boost::ptr_vector<ttree_view_node>::const_iterator itor =
00361 children_.begin (); itor != children_.end (); ++itor) {
00362
00363 const ttree_view_node& node = *itor;
00364
00365 if(node.grid_.get_visible() == twidget::INVISIBLE) {
00366 continue;
00367 }
00368
00369 tpoint node_size = node.get_unfolded_size();
00370
00371 size.y += node_size.y;
00372 size.x = std::max(size.x, node_size.x);
00373 }
00374
00375 return size;
00376 }
00377
00378 tpoint ttree_view_node::calculate_best_size(const int indention_level
00379 , const unsigned indention_step_size) const
00380 {
00381 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00382
00383 tpoint best_size = grid_.get_best_size();
00384 if(indention_level > 0) {
00385 best_size.x += indention_level * indention_step_size;
00386 }
00387
00388 if(is_folded()) {
00389
00390 DBG_GUI_L << LOG_HEADER
00391 << " Folded grid return own best size " << best_size << ".\n";
00392 return best_size;
00393 }
00394
00395 DBG_GUI_L << LOG_HEADER << " own grid best size " << best_size << ".\n";
00396
00397 for(boost::ptr_vector<ttree_view_node>::const_iterator itor =
00398 children_.begin (); itor != children_.end (); ++itor) {
00399
00400 const ttree_view_node& node = *itor;
00401
00402 if(node.grid_.get_visible() == twidget::INVISIBLE) {
00403 continue;
00404 }
00405
00406 const tpoint node_size = node.calculate_best_size(indention_level + 1,
00407 indention_step_size);
00408
00409 best_size.y += node_size.y;
00410 best_size.x = std::max(best_size.x, node_size.x);
00411 }
00412
00413 DBG_GUI_L << LOG_HEADER << " result " << best_size << ".\n";
00414 return best_size;
00415 }
00416
00417 void ttree_view_node::set_origin(const tpoint& origin)
00418 {
00419
00420 twidget::set_origin(origin);
00421
00422
00423 place(tree_view().indention_step_size_, origin, get_size().x);
00424 }
00425
00426 void ttree_view_node::place(const tpoint& origin, const tpoint& size)
00427 {
00428
00429 twidget::place(origin, size);
00430
00431 tree_view().layout_children(true);
00432 }
00433
00434 unsigned ttree_view_node::place(
00435 const unsigned indention_step_size
00436 , tpoint origin
00437 , unsigned width)
00438 {
00439 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00440 DBG_GUI_L << LOG_HEADER << " origin " << origin << ".\n";
00441
00442 const unsigned offset = origin.y;
00443 tpoint best_size = grid_.get_best_size();
00444 best_size.x = width;
00445 grid_.place(origin, best_size);
00446
00447 if(!is_root_node()) {
00448 origin.x += indention_step_size;
00449 width -= indention_step_size;
00450 }
00451 origin.y += best_size.y;
00452
00453 if(is_folded()) {
00454 DBG_GUI_L << LOG_HEADER << " folded node done.\n";
00455 return origin.y - offset;
00456 }
00457
00458 DBG_GUI_L << LOG_HEADER << " set children.\n";
00459 foreach(ttree_view_node& node, children_) {
00460 origin.y += node.place(indention_step_size, origin, width);
00461 }
00462
00463
00464 twidget::set_size(tpoint(width, origin.y - offset));
00465
00466 DBG_GUI_L << LOG_HEADER << " result " << ( origin.y - offset) << ".\n";
00467 return origin.y - offset;
00468 }
00469
00470 void ttree_view_node::set_visible_area(const SDL_Rect& area)
00471 {
00472 log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00473 DBG_GUI_L << LOG_HEADER << " area " << area << ".\n";
00474 grid_.set_visible_area(area);
00475
00476 if(is_folded()) {
00477 DBG_GUI_L << LOG_HEADER << " folded node done.\n";
00478 return;
00479 }
00480
00481 foreach(ttree_view_node& node, children_) {
00482 node.set_visible_area(area);
00483 }
00484 }
00485
00486 void ttree_view_node::impl_draw_children(surface& frame_buffer)
00487 {
00488 grid_.draw_children(frame_buffer);
00489
00490 if(is_folded()) {
00491 return;
00492 }
00493
00494 foreach(ttree_view_node& node, children_) {
00495 node.impl_draw_children(frame_buffer);
00496 }
00497 }
00498
00499 void ttree_view_node::impl_draw_children(
00500 surface& frame_buffer
00501 , int x_offset
00502 , int y_offset)
00503 {
00504 grid_.draw_children(frame_buffer, x_offset, y_offset);
00505
00506 if(is_folded()) {
00507 return;
00508 }
00509
00510 foreach(ttree_view_node& node, children_) {
00511 node.impl_draw_children(frame_buffer, x_offset, y_offset);
00512 }
00513 }
00514
00515 void ttree_view_node::signal_handler_left_button_click(
00516 const event::tevent event)
00517 {
00518 DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 if(is_folded()) {
00529
00530
00531 const tpoint current_size(get_current_size().x, get_unfolded_size().y);
00532 const tpoint new_size = get_folded_size();
00533
00534 int width_modification = new_size.x - current_size.x;
00535 if(width_modification < 0) {
00536 width_modification = 0;
00537 }
00538
00539 const int height_modification = new_size.y - current_size.y;
00540 assert(height_modification <= 0);
00541
00542 tree_view().resize_content(width_modification, height_modification);
00543 } else {
00544
00545
00546 const tpoint current_size(get_current_size().x, get_folded_size().y);
00547 const tpoint new_size = get_unfolded_size();
00548
00549 int width_modification = new_size.x - current_size.x;
00550 if(width_modification < 0) {
00551 width_modification = 0;
00552 }
00553
00554 const int height_modification = new_size.y - current_size.y;
00555 assert(height_modification >= 0);
00556
00557 tree_view().resize_content(width_modification, height_modification);
00558 }
00559 }
00560
00561 void ttree_view_node::signal_handler_label_left_button_click(
00562 const event::tevent event
00563 , bool& handled
00564 , bool& halt)
00565 {
00566 DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00567
00568 assert(label_);
00569
00570
00571
00572
00573 if(label_->get_value()) {
00574
00575 halt = handled = true;
00576 } else {
00577
00578 if(tree_view().selected_item_ && tree_view().selected_item_->label_) {
00579 tree_view().selected_item_->label_->set_value(false);
00580 }
00581
00582 tree_view().selected_item_ = this;
00583
00584 if(tree_view().selection_change_callback_) {
00585 tree_view().selection_change_callback_();
00586 }
00587 }
00588 }
00589
00590 void ttree_view_node::init_grid(tgrid* grid
00591 , const std::map<std::string /* widget id */, string_map>& data)
00592 {
00593 assert(grid);
00594
00595 for(unsigned row = 0; row < grid->get_rows(); ++row) {
00596 for(unsigned col = 0; col < grid->get_cols(); ++col) {
00597 twidget* widget = grid->widget(row, col);
00598 assert(widget);
00599
00600 tgrid* child_grid = dynamic_cast<tgrid*>(widget);
00601
00602 ttoggle_panel* panel = dynamic_cast<ttoggle_panel*>(widget);
00603 tcontrol* ctrl = dynamic_cast<tcontrol*>(widget);
00604
00605 if(panel) {
00606 panel->set_child_members(data);
00607 } else if(child_grid) {
00608 init_grid(child_grid, data);
00609 } else if(ctrl) {
00610 std::map<std::string, string_map>::const_iterator itor =
00611 data.find(ctrl->id());
00612
00613 if(itor == data.end()) {
00614 itor = data.find("");
00615 }
00616 if(itor != data.end()) {
00617 ctrl->set_members(itor->second);
00618 }
00619
00620 } else {
00621
00622
00623
00624 }
00625 }
00626 }
00627
00628 }
00629
00630 const std::string& ttree_view_node::get_control_type() const
00631 {
00632 static const std::string type = "tree_view_node";
00633 return type;
00634 }
00635
00636 }
00637