gui/widgets/list.cpp

Go to the documentation of this file.
00001 /* $Id: list.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
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 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00017 
00018 #define GETTEXT_DOMAIN "wesnoth-lib"
00019 
00020 #include "gui/widgets/list.hpp"
00021 
00022 #include "foreach.hpp"
00023 #include "gui/auxiliary/log.hpp"
00024 #include "gui/auxiliary/widget_definition/listbox.hpp"
00025 #include "gui/auxiliary/window_builder/listbox.hpp"
00026 #include "gui/widgets/selectable.hpp"
00027 #include "gui/widgets/settings.hpp"
00028 #include "gui/widgets/window.hpp"
00029 
00030 #include <boost/bind.hpp>
00031 
00032 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
00033 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00034 
00035 namespace gui2 {
00036 
00037 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00038 REGISTER_WIDGET(listbox)
00039 #endif
00040 
00041 tlist::tlist(const bool has_minimum
00042         , const bool has_maximum
00043         , const tgenerator_::tplacement placement
00044         , const bool select
00045         , const tbuilder_grid_const_ptr list_builder)
00046     : tcontainer_(2) // FIXME magic number
00047     , state_(ENABLED)
00048     , generator_(NULL)
00049     , list_builder_(list_builder)
00050     , need_layout_(false)
00051 {
00052     assert(list_builder);
00053 
00054     generator_ = tgenerator_::build(
00055             has_minimum, has_maximum, placement, select);
00056     assert(generator_);
00057 
00058     connect_signal<event::LEFT_BUTTON_DOWN>(
00059               boost::bind(
00060                     &tlist::signal_handler_left_button_down
00061                   , this
00062                   , _2)
00063             , event::tdispatcher::back_pre_child);
00064 
00065     connect_signal<event::SDL_KEY_DOWN>(
00066             boost::bind(
00067                 &tlist::signal_handler_sdl_key_down
00068                 , this
00069                 , _2
00070                 , _3
00071                 , _5
00072                 , _6));
00073 
00074     connect_signal<event::SDL_KEY_DOWN>(
00075               boost::bind(
00076                 &tlist::signal_handler_sdl_key_down
00077                 , this
00078                 , _2
00079                 , _3
00080                 , _5
00081                 , _6)
00082             , event::tdispatcher::back_pre_child);
00083 }
00084 
00085 void tlist::add_row(const string_map& item, const int index)
00086 {
00087     std::map<std::string, string_map> data;
00088 
00089     data.insert(std::make_pair("", item));
00090     add_row(data, index);
00091 }
00092 
00093 void tlist::add_row(
00094           const std::map<std::string /* widget id */, string_map>& data
00095         , const int index)
00096 {
00097     assert(generator_);
00098     tgrid& grid =
00099             generator_->create_item(index, list_builder_, data, NULL);
00100 
00101     tselectable_* selectable =
00102             find_widget<tselectable_>(&grid, "_toggle", false, false);
00103 
00104     if(selectable) {
00105         dynamic_cast<twidget&>(*selectable).
00106             connect_signal<event::LEFT_BUTTON_CLICK>(
00107                   boost::bind(
00108                         &tlist::signal_handler_pre_child_left_button_click
00109                       , this
00110                       , &grid
00111                       , _2
00112                       , _3
00113                       , _4)
00114                 , event::tdispatcher::back_pre_child);
00115 
00116         // Post widget for panel.
00117         dynamic_cast<twidget&>(*selectable).
00118             connect_signal<event::LEFT_BUTTON_CLICK>(
00119                   boost::bind(
00120                         &tlist::signal_handler_left_button_click
00121                       , this
00122                       , &grid
00123                       , _2)
00124                 , event::tdispatcher::back_post_child);
00125 
00126         // Post widget for button and widgets on the panel.
00127         dynamic_cast<twidget&>(*selectable).
00128             connect_signal<event::LEFT_BUTTON_CLICK>(
00129                   boost::bind(
00130                         &tlist::signal_handler_left_button_click
00131                       , this
00132                       , &grid
00133                       , _2)
00134                 , event::tdispatcher::back_child);
00135     }
00136 }
00137 
00138 void tlist::append_rows(const std::vector<string_map>& items)
00139 {
00140     foreach(const string_map& item, items) {
00141         add_row(item);
00142     }
00143 }
00144 
00145 void tlist::remove_row(const unsigned row, unsigned count)
00146 {
00147     assert(generator_);
00148 
00149     if(row >= get_item_count()) {
00150         return;
00151     }
00152 
00153     if(!count || count > get_item_count()) {
00154         count = get_item_count();
00155     }
00156 
00157     unsigned height_reduced = 0;
00158     for(; count; --count) {
00159         if(generator_->item(row).get_visible() != INVISIBLE) {
00160             height_reduced += generator_->item(row).get_height();
00161         }
00162         generator_->delete_item(row);
00163     }
00164 
00165     if(height_reduced != 0) {
00166 //      resize_content(0, -height_reduced);
00167     }
00168 }
00169 
00170 void tlist::clear()
00171 {
00172     // Due to the removing from the linked group, don't use
00173     // generator_->clear() directly.
00174     remove_row(0, 0);
00175 }
00176 
00177 unsigned tlist::get_item_count() const
00178 {
00179     assert(generator_);
00180     return generator_->get_item_count();
00181 }
00182 
00183 void tlist::set_row_active(const unsigned row, const bool active)
00184 {
00185     assert(generator_);
00186     generator_->item(row).set_active(active);
00187 }
00188 
00189 void tlist::set_row_shown(const unsigned row, const bool shown)
00190 {
00191     assert(generator_);
00192 
00193     twindow *window = get_window();
00194     assert(window);
00195 
00196     const int selected_row = get_selected_row();
00197 
00198     bool resize_needed;
00199     {
00200         twindow::tinvalidate_layout_blocker invalidate_layout_blocker(*window);
00201 
00202         generator_->set_item_shown(row, shown);
00203         generator_->place(generator_->get_origin()
00204                 , generator_->calculate_best_size());
00205 //      resize_needed = !content_resize_request();
00206     }
00207 
00208     if(resize_needed) {
00209         window->invalidate_layout();
00210     } else {
00211 //      grid().set_visible_area(content_visible_area());
00212         set_dirty();
00213     }
00214 
00215     if(selected_row != get_selected_row()) {
00216         fire(event::NOTIFY_MODIFIED, *this, NULL);
00217     }
00218 }
00219 
00220 void tlist::set_row_shown(const std::vector<bool>& shown)
00221 {
00222     assert(generator_);
00223     assert(shown.size() == get_item_count());
00224 
00225     twindow *window = get_window();
00226     assert(window);
00227 
00228     const int selected_row = get_selected_row();
00229 
00230     bool resize_needed;
00231     {
00232         twindow::tinvalidate_layout_blocker invalidate_layout_blocker(*window);
00233 
00234         for(size_t i = 0; i < shown.size(); ++i) {
00235             generator_->set_item_shown(i, shown[i]);
00236         }
00237         generator_->place(generator_->get_origin()
00238                 , generator_->calculate_best_size());
00239 //      resize_needed = !content_resize_request();
00240     }
00241 
00242     if(resize_needed) {
00243         window->invalidate_layout();
00244     } else {
00245 //      content_grid_->set_visible_area(content_visible_area());
00246         set_dirty();
00247     }
00248 
00249     if(selected_row != get_selected_row()) {
00250         fire(event::NOTIFY_MODIFIED, *this, NULL);
00251     }
00252 }
00253 
00254 const tgrid* tlist::get_row_grid(const unsigned row) const
00255 {
00256     assert(generator_);
00257     // rename this function and can we return a reference??
00258     return &generator_->item(row);
00259 }
00260 
00261 tgrid* tlist::get_row_grid(const unsigned row)
00262 {
00263     assert(generator_);
00264     return &generator_->item(row);
00265 }
00266 
00267 bool tlist::select_row(const unsigned row, const bool select)
00268 {
00269     assert(generator_);
00270 
00271     generator_->select_item(row, select);
00272 
00273     return true; // FIXME test what result should have been!!!
00274 }
00275 
00276 int tlist::get_selected_row() const
00277 {
00278     assert(generator_);
00279 
00280     return generator_->get_selected_item();
00281 }
00282 
00283 void tlist::place(const tpoint& origin, const tpoint& size)
00284 {
00285     // Inherited.
00286     tcontainer_::place(origin, size);
00287 
00288     /**
00289      * @todo Work-around to set the selected item visible again.
00290      *
00291      * At the moment the listes and dialogs in general are resized a lot as
00292      * work-around for sizing. So this function makes the selected item in view
00293      * again. It doesn't work great in all cases but the proper fix is to avoid
00294      * resizing dialogs a lot. Need more work later on.
00295      */
00296     const int selected_item = generator_->get_selected_item();
00297     if(selected_item != -1) {
00298 /*
00299         const SDL_Rect& visible = content_visible_area();
00300         SDL_Rect rect = generator_->item(selected_item).get_rect();
00301 
00302         rect.x = visible.x;
00303         rect.w = visible.w;
00304 
00305         show_content_rect(rect);
00306 */
00307     }
00308 }
00309 #if 0
00310 void tlist::resize_content(
00311           const int width_modification
00312         , const int height_modification)
00313 {
00314     DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size()
00315             << " width_modification " << width_modification
00316             << " height_modification " << height_modification
00317             << ".\n";
00318 
00319     if(content_resize_request(width_modification, height_modification)) {
00320 
00321         // Calculate new size.
00322         tpoint size = content_grid()->get_size();
00323         size.x += width_modification;
00324         size.y += height_modification;
00325 
00326         // Set new size.
00327         content_grid()->set_size(size);
00328 
00329         // Set status.
00330         need_layout_ = true;
00331         // If the content grows assume it "overwrites" the old content.
00332         if(width_modification < 0 || height_modification < 0) {
00333             set_dirty();
00334         }
00335         DBG_GUI_L << LOG_HEADER << " succeeded.\n";
00336     } else {
00337         DBG_GUI_L << LOG_HEADER << " failed.\n";
00338     }
00339 }
00340 #endif
00341 
00342 void tlist::init()
00343 {
00344     init_grid(cast<tlistbox_definition::tresolution>(config()).grid);
00345 
00346     set_single_child(
00347               find_widget<tgrid>(&grid(), "_list_grid", false)
00348             , generator_);
00349 
00350     /*
00351      * These items should be managed by the new listbox class.
00352      * So make them invisible for now.
00353      */
00354     tgrid* g = find_widget<tgrid>(&grid(), "_header_grid", false, false);
00355     if(g) g->set_visible(twidget::INVISIBLE);
00356 
00357     g = find_widget<tgrid>(&grid(), "_footer_grid", false, false);
00358     if(g) g->set_visible(twidget::INVISIBLE);
00359 
00360     g = find_widget<tgrid>(&grid(), "_vertical_scrollbar_grid", false, false);
00361     if(g) g->set_visible(twidget::INVISIBLE);
00362 
00363     g = find_widget<tgrid>(&grid(), "_horizontal_scrollbar_grid", false, false);
00364     if(g) g->set_visible(twidget::INVISIBLE);
00365 
00366 }
00367 
00368 void tlist::layout_children(const bool force)
00369 {
00370     if(need_layout_ || force) {
00371         grid().place(grid().get_origin(), grid().get_size());
00372 
00373 /*
00374         grid().set_visible_area(content_visible_area_);
00375 */
00376         need_layout_ = false;
00377         set_dirty();
00378     }
00379 }
00380 
00381 const std::string& tlist::get_control_type() const
00382 {
00383     static const std::string type = "list";
00384     return type;
00385 }
00386 
00387 void tlist::signal_handler_left_button_down(const event::tevent event)
00388 {
00389     DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00390 
00391     assert(get_window());
00392     get_window()->keyboard_capture(this);
00393 }
00394 
00395 void tlist::signal_handler_pre_child_left_button_click(
00396           tgrid* grid
00397         , const event::tevent event
00398         , bool& handled
00399         , bool& halt)
00400 {
00401     DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00402 
00403     assert(grid);
00404     assert(generator_);
00405 
00406     for(size_t i = 0; i < generator_->get_item_count(); ++i) {
00407         if(&generator_->item(i) == grid) {
00408 
00409             /**
00410              * @todo Here we should check whether the panel can be toggled.
00411              *
00412              * NO set halt + handled
00413              * YES do nothing
00414              *
00415              * Then a post to the widget, which if done sets the proper state
00416              * in the list.
00417              *
00418              * For now we simply assume an item can only be selected and not
00419              * deselected (which is true at the moment).
00420              */
00421             if(generator_->is_selected(i)) {
00422                 halt = true;
00423                 handled = true;
00424             }
00425             return;
00426         }
00427     }
00428     assert(false);
00429 }
00430 
00431 void tlist::signal_handler_left_button_click(
00432           tgrid* grid
00433         , const event::tevent event)
00434 {
00435     DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00436     assert(grid);
00437     assert(generator_);
00438 
00439     /** @todo Test the proper state to set. */
00440     for(size_t i = 0; i < generator_->get_item_count(); ++i) {
00441         if(&generator_->item(i) == grid) {
00442             generator_->select_item(i);
00443             fire(event::NOTIFY_MODIFIED, *this, NULL);
00444         }
00445     }
00446 }
00447 
00448 void tlist::signal_handler_sdl_key_down(const event::tevent event
00449         , bool& handled
00450         , const SDLKey key
00451         , SDLMod modifier)
00452 {
00453     DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
00454 
00455     if(handled) {
00456         return;
00457     }
00458 
00459     switch(key) {
00460         case SDLK_UP :
00461             generator_->handle_key_up_arrow(modifier, handled);
00462             break;
00463         case SDLK_DOWN :
00464             generator_->handle_key_down_arrow(modifier, handled);
00465             break;
00466         case SDLK_LEFT :
00467             generator_->handle_key_left_arrow(modifier, handled);
00468             break;
00469         case SDLK_RIGHT :
00470             generator_->handle_key_right_arrow(modifier, handled);
00471             break;
00472         default : ;
00473             /* Do nothing. */
00474     }
00475     if(handled) {
00476         fire(event::NOTIFY_MODIFIED, *this, NULL);
00477     }
00478 }
00479 
00480 } // namespace gui2
00481 
00482 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

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