gui/widgets/tree_view_node.cpp

Go to the documentation of this file.
00001 /* $Id: tree_view_node.cpp 54259 2012-05-20 14:00:17Z mordante $ */
00002 /*
00003    Copyright (C) 2010 - 2012 by Mark de Wever <koraq@xs4all.nl>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
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() &&*/ 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     // Calculate width modification.
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     // Calculate height modification.
00152     const int height_modification = best_size.y;
00153     assert(height_modification > 0);
00154 
00155     // Request new size.
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 /*recursive*/)
00202 {
00203     // FIXME set state
00204 
00205 }
00206 
00207 void ttree_view_node::unfold(const texpand_mode /*mode*/)
00208 {
00209     // FIXME set state
00210 
00211 }
00212 #endif
00213 
00214 void ttree_view_node::clear()
00215 {
00216     /** @todo Also try to find the optimal width. */
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     // Inherited.
00420     twidget::set_origin(origin);
00421 
00422     // Using layout_children seems to fail.
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     // Inherited.
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     // Inherited.
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      * @todo Rewrite this sizing code for the folding/unfolding.
00522      *
00523      * The code works but feels rather hacky, so better move back to the
00524      * drawingboard for 1.9.
00525      */
00526 
00527     // is_folded() returns the new state.
00528     if(is_folded()) {
00529 
00530         // From unfolded to folded.
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         // From folded to unfolded.
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     // We only snoop on the event so normally don't touch the handled, else if
00571     // we snoop in preexcept when halting.
00572 
00573     if(label_->get_value()) {
00574         // Forbid deselecting
00575         halt = handled = true;
00576     } else {
00577         // Deselect current item
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 //          ttoggle_button* btn = dynamic_cast<ttoggle_button*>(widget);
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 //              ctrl->set_members(data);
00620             } else {
00621 
00622 //              ERROR_LOG("Widget type '"
00623 //                      << typeid(*widget).name() << "'.");
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 } // namespace gui2
00637 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:00 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs