gui/widgets/scrollbar_container.cpp

Go to the documentation of this file.
00001 /* $Id: scrollbar_container.cpp 54007 2012-04-28 19:16:10Z mordante $ */
00002 /*
00003    Copyright (C) 2008 - 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/scrollbar_container_private.hpp"
00019 
00020 #include "foreach.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 #include "gui/auxiliary/layout_exception.hpp"
00023 #include "gui/widgets/clickable.hpp"
00024 #include "gui/widgets/spacer.hpp"
00025 #include "gui/widgets/window.hpp"
00026 
00027 #include <boost/bind.hpp>
00028 
00029 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
00030 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00031 
00032 namespace gui2 {
00033 
00034 namespace {
00035 
00036 static const std::string button_up_names[] = {
00037     "_begin", "_line_up", "_half_page_up", "_page_up" };
00038 
00039 static const std::string button_down_names[] = {
00040     "_end", "_line_down", "_half_page_down", "_page_down" };
00041 
00042 /**
00043  * Returns a map with the names of all buttons and the scrollbar jump they're
00044  * supposed to execute.
00045  */
00046 const std::map<std::string, tscrollbar_::tscroll>& scroll_lookup()
00047 {
00048     static std::map<std::string, tscrollbar_::tscroll> lookup;
00049     if(lookup.empty()) {
00050         lookup["_begin"] = tscrollbar_::BEGIN;
00051         lookup["_line_up"] = tscrollbar_::ITEM_BACKWARDS;
00052         lookup["_half_page_up"] = tscrollbar_::HALF_JUMP_BACKWARDS;
00053         lookup["_page_up"] = tscrollbar_::JUMP_BACKWARDS;
00054 
00055         lookup["_end"] = tscrollbar_::END;
00056         lookup["_line_down"] = tscrollbar_::ITEM_FORWARD;
00057         lookup["_half_page_down"] = tscrollbar_::HALF_JUMP_FORWARD;
00058         lookup["_page_down"] = tscrollbar_::JUMP_FORWARD;
00059     }
00060 
00061     return lookup;
00062 }
00063 
00064 } // namespace
00065 
00066 tscrollbar_container::tscrollbar_container(const unsigned canvas_count)
00067     : tcontainer_(canvas_count)
00068     , state_(ENABLED)
00069     , vertical_scrollbar_mode_(auto_visible_first_run)
00070     , horizontal_scrollbar_mode_(auto_visible_first_run)
00071     , vertical_scrollbar_grid_(NULL)
00072     , horizontal_scrollbar_grid_(NULL)
00073     , vertical_scrollbar_(NULL)
00074     , horizontal_scrollbar_(NULL)
00075     , content_grid_(NULL)
00076     , content_(NULL)
00077     , content_visible_area_()
00078 {
00079     connect_signal<event::SDL_KEY_DOWN>(boost::bind(
00080             &tscrollbar_container::signal_handler_sdl_key_down
00081                 , this, _2, _3, _5, _6));
00082 
00083 
00084     connect_signal<event::SDL_WHEEL_UP>(
00085             boost::bind(
00086                   &tscrollbar_container::signal_handler_sdl_wheel_up
00087                 , this
00088                 , _2
00089                 , _3)
00090             , event::tdispatcher::back_post_child);
00091 
00092     connect_signal<event::SDL_WHEEL_DOWN>(
00093             boost::bind(
00094                 &tscrollbar_container::signal_handler_sdl_wheel_down
00095                 , this
00096                 , _2
00097                 , _3)
00098             , event::tdispatcher::back_post_child);
00099 
00100     connect_signal<event::SDL_WHEEL_LEFT>(
00101             boost::bind(
00102                 &tscrollbar_container::signal_handler_sdl_wheel_left
00103                 , this
00104                 , _2
00105                 , _3)
00106             , event::tdispatcher::back_post_child);
00107 
00108     connect_signal<event::SDL_WHEEL_RIGHT>(
00109             boost::bind(
00110                 &tscrollbar_container::signal_handler_sdl_wheel_right
00111                 , this
00112                 , _2
00113                 , _3)
00114             , event::tdispatcher::back_post_child);
00115 }
00116 
00117 void tscrollbar_container::layout_init(const bool full_initialization)
00118 {
00119     // Inherited.
00120     tcontainer_::layout_init(full_initialization);
00121 
00122     if(full_initialization) {
00123 
00124         assert(vertical_scrollbar_grid_);
00125         switch(vertical_scrollbar_mode_) {
00126             case always_visible :
00127                 vertical_scrollbar_grid_->set_visible(twidget::VISIBLE);
00128                 break;
00129 
00130             case auto_visible :
00131                 vertical_scrollbar_grid_->set_visible(twidget::HIDDEN);
00132                 break;
00133 
00134             default :
00135                 vertical_scrollbar_grid_->set_visible(twidget::INVISIBLE);
00136         }
00137 
00138         assert(horizontal_scrollbar_grid_);
00139         switch(horizontal_scrollbar_mode_) {
00140             case always_visible :
00141                 horizontal_scrollbar_grid_->set_visible(twidget::VISIBLE);
00142                 break;
00143 
00144             case auto_visible :
00145                 horizontal_scrollbar_grid_->set_visible(twidget::HIDDEN);
00146                 break;
00147 
00148             default :
00149                 horizontal_scrollbar_grid_->set_visible(twidget::INVISIBLE);
00150         }
00151     }
00152 
00153     assert(content_grid_);
00154     content_grid_->layout_init(full_initialization);
00155 }
00156 
00157 void tscrollbar_container::request_reduce_height(
00158         const unsigned maximum_height)
00159 {
00160     DBG_GUI_L << LOG_HEADER
00161             << " requested height " << maximum_height
00162             << ".\n";
00163     /*
00164      * First ask the content to reduce it's height. This seems to work for now,
00165      * but maybe some sizing hints will be required later.
00166      */
00167     /** @todo Evaluate whether sizing hints are required. */
00168     assert(content_grid_);
00169     const unsigned offset = horizontal_scrollbar_grid_
00170             && horizontal_scrollbar_grid_->get_visible() != twidget::INVISIBLE
00171                 ?  horizontal_scrollbar_grid_->get_best_size().y
00172                 : 0;
00173     content_grid_->request_reduce_height(maximum_height - offset);
00174 
00175     // Did we manage to achieve the wanted size?
00176     tpoint size = get_best_size();
00177     if(static_cast<unsigned>(size.y) <= maximum_height) {
00178         DBG_GUI_L << LOG_HEADER
00179                 << " child honoured request, height " << size.y
00180                 << ".\n";
00181         return;
00182     }
00183 
00184     if(vertical_scrollbar_mode_ == always_invisible) {
00185         DBG_GUI_L << LOG_HEADER << " request failed due to scrollbar mode.\n";
00186         return;
00187     }
00188 
00189     assert(vertical_scrollbar_grid_);
00190     const bool resized =
00191         vertical_scrollbar_grid_->get_visible() == twidget::INVISIBLE;
00192 
00193     // Always set the bar visible, is a nop is already visible.
00194     vertical_scrollbar_grid_->set_visible(twidget::VISIBLE);
00195 
00196     const tpoint scrollbar_size = vertical_scrollbar_grid_->get_best_size();
00197 
00198     // If showing the scrollbar increased the height, hide and abort.
00199     if(resized && scrollbar_size.y > size.y) {
00200         vertical_scrollbar_grid_->set_visible(twidget::INVISIBLE);
00201         DBG_GUI_L << LOG_HEADER
00202                 << " request failed, showing the scrollbar"
00203                 << " increased the height to " << scrollbar_size.y
00204                 << ".\n";
00205         return;
00206     }
00207 
00208     if(maximum_height > static_cast<unsigned>(scrollbar_size.y)) {
00209         size.y = maximum_height;
00210     } else {
00211         size.y = scrollbar_size.y;
00212     }
00213 
00214     // FIXME adjust for the step size of the scrollbar
00215 
00216     set_layout_size(size);
00217     DBG_GUI_L << LOG_HEADER
00218             << " resize resulted in " << size.y
00219             << ".\n";
00220 
00221     if(resized) {
00222         DBG_GUI_L << LOG_HEADER
00223                 << " resize modified the width, throw notification.\n";
00224 
00225         throw tlayout_exception_width_modified();
00226     }
00227 }
00228 
00229 void tscrollbar_container::request_reduce_width(
00230         const unsigned maximum_width)
00231 {
00232     DBG_GUI_L << LOG_HEADER
00233             << " requested width " << maximum_width
00234             << ".\n";
00235 
00236     // First ask our content, it might be able to wrap which looks better as
00237     // a scrollbar.
00238     assert(content_grid_);
00239     const unsigned offset = vertical_scrollbar_grid_
00240             && vertical_scrollbar_grid_->get_visible() != twidget::INVISIBLE
00241                 ?  vertical_scrollbar_grid_->get_best_size().x
00242                 : 0;
00243     content_grid_->request_reduce_width(maximum_width - offset);
00244 
00245     // Did we manage to achieve the wanted size?
00246     tpoint size = get_best_size();
00247     if(static_cast<unsigned>(size.x) <= maximum_width) {
00248         DBG_GUI_L << LOG_HEADER
00249                 << " child honoured request, width " << size.x
00250                 << ".\n";
00251         return;
00252     }
00253 
00254     if(horizontal_scrollbar_mode_ == always_invisible) {
00255         DBG_GUI_L << LOG_HEADER << " request failed due to scrollbar mode.\n";
00256         return;
00257     }
00258 
00259     // Always set the bar visible, is a nop when it's already visible.
00260     assert(horizontal_scrollbar_grid_);
00261     horizontal_scrollbar_grid_->set_visible(twidget::VISIBLE);
00262     size = get_best_size();
00263 
00264     const tpoint scrollbar_size = horizontal_scrollbar_grid_->get_best_size();
00265 
00266     // If showing the scrollbar increased the width, hide and abort.
00267     if(horizontal_scrollbar_mode_ == auto_visible_first_run
00268             && scrollbar_size.x > size.x) {
00269 
00270         horizontal_scrollbar_grid_->set_visible(twidget::INVISIBLE);
00271         DBG_GUI_L << LOG_HEADER
00272                 << " request failed, showing the scrollbar"
00273                 << " increased the width to " << scrollbar_size.x
00274                 << ".\n";
00275         return;
00276     }
00277 
00278     if(maximum_width > static_cast<unsigned>(scrollbar_size.x)) {
00279         size.x = maximum_width;
00280     } else {
00281         size.x = scrollbar_size.x;
00282     }
00283 
00284     // FIXME adjust for the step size of the scrollbar
00285 
00286     set_layout_size(size);
00287     DBG_GUI_L << LOG_HEADER
00288             << " resize resulted in " << size.x
00289             << ".\n";
00290 }
00291 
00292 tpoint tscrollbar_container::calculate_best_size() const
00293 {
00294     log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
00295 
00296     /***** get vertical scrollbar size *****/
00297     const tpoint vertical_scrollbar =
00298             vertical_scrollbar_grid_->get_visible() == twidget::INVISIBLE
00299             ? tpoint(0, 0)
00300             : vertical_scrollbar_grid_->get_best_size();
00301 
00302     /***** get horizontal scrollbar size *****/
00303     const tpoint horizontal_scrollbar =
00304             horizontal_scrollbar_grid_->get_visible() == twidget::INVISIBLE
00305             ? tpoint(0, 0)
00306             : horizontal_scrollbar_grid_->get_best_size();
00307 
00308     /***** get content size *****/
00309     assert(content_grid_);
00310     const tpoint content = content_grid_->get_best_size();
00311 
00312     const tpoint result(
00313             vertical_scrollbar.x +
00314                 std::max(horizontal_scrollbar.x, content.x),
00315             horizontal_scrollbar.y +
00316                 std::max(vertical_scrollbar.y,  content.y));
00317 
00318     DBG_GUI_L << LOG_HEADER
00319             << " vertical_scrollbar " << vertical_scrollbar
00320             << " horizontal_scrollbar " << horizontal_scrollbar
00321             << " content " << content
00322             << " result " << result
00323             << ".\n";
00324 
00325     return result;
00326 }
00327 
00328 static void set_scrollbar_mode(tgrid* scrollbar_grid, tscrollbar_* scrollbar,
00329         tscrollbar_container::tscrollbar_mode& scrollbar_mode,
00330         const unsigned items, const unsigned visible_items)
00331 {
00332     assert(scrollbar_grid && scrollbar);
00333 
00334     if(scrollbar_mode == tscrollbar_container::always_invisible) {
00335         scrollbar_grid->set_visible(twidget::INVISIBLE);
00336         return;
00337     }
00338 
00339     scrollbar->set_item_count(items);
00340     scrollbar->set_item_position(0);
00341     scrollbar->set_visible_items(visible_items);
00342 
00343     if(scrollbar_mode == tscrollbar_container::auto_visible) {
00344 
00345         const bool scrollbar_needed = items > visible_items;
00346 
00347         scrollbar_grid->set_visible(scrollbar_needed
00348                 ? twidget::VISIBLE
00349                 : twidget::HIDDEN);
00350     }
00351 }
00352 
00353 void tscrollbar_container::place(const tpoint& origin, const tpoint& size)
00354 {
00355     // Inherited.
00356     tcontainer_::place(origin, size);
00357 
00358     // Set content size
00359     assert(content_ && content_grid_);
00360 
00361     const tpoint content_origin = content_->get_origin();
00362 
00363     const tpoint best_size = content_grid_->get_best_size();
00364     const tpoint content_size(content_->get_width(), content_->get_height());
00365 
00366     const tpoint content_grid_size(
00367             std::max(best_size.x, content_size.x),
00368             std::max(best_size.y, content_size.y));
00369 
00370     set_content_size(content_origin, content_grid_size);
00371 
00372     // Set vertical scrollbar
00373     set_scrollbar_mode(vertical_scrollbar_grid_, vertical_scrollbar_,
00374             vertical_scrollbar_mode_,
00375             content_grid_->get_height(),
00376             content_->get_height());
00377 
00378     // Set horizontal scrollbar
00379     set_scrollbar_mode(horizontal_scrollbar_grid_, horizontal_scrollbar_,
00380             horizontal_scrollbar_mode_,
00381             content_grid_->get_width(),
00382             content_->get_width());
00383 
00384     // Update the buttons.
00385     set_scrollbar_button_status();
00386 
00387     // Now set the visible part of the content.
00388     content_visible_area_ = content_->get_rect();
00389     content_grid_->set_visible_area(content_visible_area_);
00390 }
00391 
00392 void tscrollbar_container::set_origin(const tpoint& origin)
00393 {
00394     // Inherited.
00395     tcontainer_::set_origin(origin);
00396 
00397     // Set content size
00398     assert(content_ && content_grid_);
00399 
00400     const tpoint content_origin = content_->get_origin();
00401 
00402     content_grid_->set_origin(content_origin);
00403 
00404     // Changing the origin also invalidates the visible area.
00405     content_grid_->set_visible_area(content_visible_area_);
00406 }
00407 
00408 void tscrollbar_container::set_visible_area(const SDL_Rect& area)
00409 {
00410     // Inherited.
00411     tcontainer_::set_visible_area(area);
00412 
00413     // Now get the visible part of the content.
00414     content_visible_area_ = intersect_rects(area, content_->get_rect());
00415 
00416     content_grid_->set_visible_area(content_visible_area_);
00417 }
00418 
00419 twidget* tscrollbar_container::find_at(
00420         const tpoint& coordinate, const bool must_be_active)
00421 {
00422     return tscrollbar_container_implementation
00423             ::find_at<twidget>(*this, coordinate, must_be_active);
00424 }
00425 
00426 const twidget* tscrollbar_container::find_at(const tpoint& coordinate,
00427         const bool must_be_active) const
00428 {
00429     return tscrollbar_container_implementation
00430             ::find_at<const twidget>(*this, coordinate, must_be_active);
00431 }
00432 
00433 twidget* tscrollbar_container::find(
00434         const std::string& id, const bool must_be_active)
00435 {
00436     return tscrollbar_container_implementation
00437             ::find<twidget>(*this, id, must_be_active);
00438 }
00439 
00440 const twidget* tscrollbar_container::find(
00441             const std::string& id, const bool must_be_active) const
00442 {
00443     return tscrollbar_container_implementation
00444             ::find<const twidget>(*this, id, must_be_active);
00445 }
00446 
00447 bool tscrollbar_container::disable_click_dismiss() const
00448 {
00449     assert(content_grid_);
00450     return tcontainer_::disable_click_dismiss()
00451             || content_grid_->disable_click_dismiss();
00452 }
00453 
00454 bool tscrollbar_container::content_resize_request(const bool force_sizing)
00455 {
00456     /**
00457      * @todo Try to handle auto_visible_first_run here as well.
00458      *
00459      * Handling it here makes the code a bit more complex but allows to not
00460      * reserve space for scrollbars, which will look nicer in the MP lobby.
00461      * But the extra complexity is no 1.8 material.
00462      */
00463 
00464     assert(content_ && content_grid_);
00465 
00466     tpoint best_size = content_grid_->recalculate_best_size();
00467     tpoint size = content_->get_size();
00468 
00469     DBG_GUI_L << LOG_HEADER
00470             << " wanted size " << best_size
00471             << " available size " << size
00472             << ".\n";
00473 
00474     if(size == tpoint(0, 0)) {
00475         DBG_GUI_L << LOG_HEADER
00476                 << " initial setup not done, bailing out.\n";
00477         return false;
00478     }
00479 
00480     if(best_size.x <= size.x && best_size.y <= size.y) {
00481         const tpoint content_size = content_grid_->get_size();
00482         if(content_size.x > size.x || content_size.y > size.y) {
00483             DBG_GUI_L << LOG_HEADER << " will fit, only needs a resize.\n";
00484             goto resize;
00485         }
00486         if(force_sizing) {
00487             DBG_GUI_L << LOG_HEADER << " fits, but resize forced.\n";
00488             goto resize;
00489         }
00490         DBG_GUI_L << LOG_HEADER << " fits, nothing to do.\n";
00491         return true;
00492     }
00493 
00494     if(best_size.x > size.x) {
00495         DBG_GUI_L << LOG_HEADER << " content too wide.\n";
00496         if(horizontal_scrollbar_mode_ == always_invisible
00497                 || (horizontal_scrollbar_mode_ == auto_visible_first_run
00498                     && horizontal_scrollbar_grid_->get_visible()
00499                         == twidget::INVISIBLE)) {
00500 
00501             DBG_GUI_L << LOG_HEADER
00502                     << " can't use horizontal scrollbar, ask window.\n";
00503             twindow* window = get_window();
00504             assert(window);
00505             window->invalidate_layout();
00506             return false;
00507         }
00508     }
00509 
00510     if(best_size.y > size.y) {
00511         DBG_GUI_L << LOG_HEADER << " content too high.\n";
00512         if(vertical_scrollbar_mode_ == always_invisible
00513                 || (vertical_scrollbar_mode_ == auto_visible_first_run
00514                     && vertical_scrollbar_grid_->get_visible()
00515                         == twidget::INVISIBLE)) {
00516 
00517             DBG_GUI_L << LOG_HEADER
00518                     << " can't use vertical scrollbar, ask window.\n";
00519             twindow* window = get_window();
00520             assert(window);
00521             window->invalidate_layout();
00522             return false;
00523         }
00524     }
00525 
00526 resize:
00527     DBG_GUI_L << LOG_HEADER << " handle resizing.\n";
00528     place(get_origin(), get_size());
00529     return true;
00530 }
00531 
00532 bool tscrollbar_container::content_resize_request(
00533           const int width_modification
00534         , const int height_modification)
00535 {
00536     DBG_GUI_L << LOG_HEADER
00537             << " wanted width modification " << width_modification
00538             << " wanted height modification " << height_modification
00539             << ".\n";
00540 
00541     if(get_size() == tpoint(0, 0)) {
00542         DBG_GUI_L << LOG_HEADER
00543                 << " initial setup not done, bailing out.\n";
00544         return false;
00545     }
00546 
00547     twindow* window = get_window();
00548     assert(window);
00549     if(window->get_need_layout()) {
00550         DBG_GUI_L << LOG_HEADER
00551                 << " window already needs a layout phase, bailing out.\n";
00552         return false;
00553     }
00554 
00555     assert(content_ && content_grid_);
00556 
00557     const bool result = content_resize_width(width_modification)
00558             && content_resize_height(height_modification);
00559 
00560     if(result) {
00561         /*
00562          * The subroutines set the new size of the scrollbar but don't
00563          * update the button status.
00564          */
00565         set_scrollbar_button_status();
00566     }
00567 
00568     DBG_GUI_L << LOG_HEADER << " result " << result << ".\n";
00569     return result;
00570 }
00571 
00572 bool tscrollbar_container::content_resize_width(const int width_modification)
00573 {
00574     if(width_modification == 0) {
00575         return true;
00576     }
00577 
00578     const int new_width = content_grid_->get_width() + width_modification;
00579     DBG_GUI_L << LOG_HEADER
00580             << " current width " << content_grid_->get_width()
00581             << " wanted width " << new_width;
00582 
00583     assert(new_width > 0);
00584 
00585     if(static_cast<unsigned>(new_width) <= content_->get_width()) {
00586         DBG_GUI_L << " width fits in container, test height.\n";
00587         set_scrollbar_mode(horizontal_scrollbar_grid_
00588                 , horizontal_scrollbar_
00589                 , horizontal_scrollbar_mode_
00590                 , new_width
00591                 , content_->get_width());
00592         return true;
00593     }
00594 
00595     assert(horizontal_scrollbar_ && horizontal_scrollbar_grid_);
00596     if(horizontal_scrollbar_mode_ == always_invisible
00597             || (horizontal_scrollbar_mode_ == auto_visible_first_run
00598                 && horizontal_scrollbar_grid_->get_visible()
00599                     == twidget::INVISIBLE)) {
00600 
00601         DBG_GUI_L << " can't use horizontal scrollbar, ask window.\n";
00602         twindow* window = get_window();
00603         assert(window);
00604         window->invalidate_layout();
00605         return false;
00606     }
00607 
00608     DBG_GUI_L << " use the horizontal scrollbar, test height.\n";
00609     set_scrollbar_mode(horizontal_scrollbar_grid_
00610             , horizontal_scrollbar_
00611             , horizontal_scrollbar_mode_
00612             , new_width
00613             , content_->get_width());
00614 
00615     return true;
00616 }
00617 
00618 bool tscrollbar_container::content_resize_height(const int height_modification)
00619 {
00620     if(height_modification == 0) {
00621         return true;
00622     }
00623 
00624     const int new_height =
00625             content_grid_->get_height() + height_modification;
00626 
00627     DBG_GUI_L << LOG_HEADER
00628             << " current height " << content_grid_->get_height()
00629             << " wanted height " << new_height;
00630 
00631     assert(new_height > 0);
00632 
00633     if(static_cast<unsigned>(new_height) <= content_->get_height()) {
00634         DBG_GUI_L << " height in container, resize allowed.\n";
00635         set_scrollbar_mode(vertical_scrollbar_grid_
00636                 , vertical_scrollbar_
00637                 , vertical_scrollbar_mode_
00638                 , new_height
00639                 , content_->get_height());
00640         return true;
00641     }
00642 
00643     assert(vertical_scrollbar_ && vertical_scrollbar_grid_);
00644     if(vertical_scrollbar_mode_ == always_invisible
00645             || (vertical_scrollbar_mode_ == auto_visible_first_run
00646                 && vertical_scrollbar_grid_->get_visible()
00647                     == twidget::INVISIBLE)) {
00648 
00649         DBG_GUI_L << " can't use vertical scrollbar, ask window.\n";
00650         twindow* window = get_window();
00651         assert(window);
00652         window->invalidate_layout();
00653         return false;
00654     }
00655 
00656     DBG_GUI_L << " use the vertical scrollbar, resize allowed.\n";
00657     set_scrollbar_mode(vertical_scrollbar_grid_
00658             , vertical_scrollbar_
00659             , vertical_scrollbar_mode_
00660             , new_height
00661             , content_->get_height());
00662 
00663     return true;
00664 }
00665 
00666 void tscrollbar_container::finalize_setup()
00667 {
00668     /***** Setup vertical scrollbar *****/
00669 
00670     vertical_scrollbar_grid_ =
00671         find_widget<tgrid>(this, "_vertical_scrollbar_grid", false, true);
00672 
00673     vertical_scrollbar_ = find_widget<tscrollbar_>(
00674             vertical_scrollbar_grid_, "_vertical_scrollbar", false, true);
00675 
00676     connect_signal_notify_modified(*vertical_scrollbar_
00677             , boost::bind(
00678                   &tscrollbar_container::vertical_scrollbar_moved
00679                 , this));
00680 
00681     /***** Setup horizontal scrollbar *****/
00682     horizontal_scrollbar_grid_ =
00683         find_widget<tgrid>(this, "_horizontal_scrollbar_grid", false, true);
00684 
00685     horizontal_scrollbar_ = find_widget<tscrollbar_>(
00686             horizontal_scrollbar_grid_, "_horizontal_scrollbar", false, true);
00687 
00688     connect_signal_notify_modified(*horizontal_scrollbar_
00689             , boost::bind(
00690                   &tscrollbar_container::horizontal_scrollbar_moved
00691                 , this));
00692 
00693     /***** Setup the scrollbar buttons *****/
00694     typedef std::pair<std::string, tscrollbar_::tscroll> hack;
00695     foreach(const hack& item, scroll_lookup()) {
00696 
00697         // Vertical.
00698         tclickable_* button = find_widget<tclickable_>(
00699                 vertical_scrollbar_grid_, item.first, false, false);
00700 
00701         if(button) {
00702             button->connect_click_handler(boost::bind(
00703                       &tscrollbar_container::scroll_vertical_scrollbar
00704                     , this
00705                     , item.second));
00706         }
00707 
00708         // Horizontal.
00709         button = find_widget<tclickable_>(
00710                 horizontal_scrollbar_grid_, item.first, false, false);
00711 
00712         if(button) {
00713             button->connect_click_handler(boost::bind(
00714                       &tscrollbar_container::scroll_horizontal_scrollbar
00715                     , this
00716                     , item.second));
00717         }
00718     }
00719 
00720     /***** Setup the content *****/
00721     content_ = new tspacer();
00722     content_->set_definition("default");
00723 
00724     content_grid_ = dynamic_cast<tgrid*>(
00725             grid().swap_child("_content_grid", content_, true));
00726     assert(content_grid_);
00727 
00728     content_grid_->set_parent(this);
00729 
00730     /***** Let our subclasses initialize themselves. *****/
00731     finalize_subclass();
00732 }
00733 
00734 void tscrollbar_container::
00735 		set_vertical_scrollbar_mode(const tscrollbar_mode scrollbar_mode)
00736 {
00737     if(vertical_scrollbar_mode_ != scrollbar_mode) {
00738         vertical_scrollbar_mode_ = scrollbar_mode;
00739     }
00740 }
00741 
00742 void tscrollbar_container::
00743 		set_horizontal_scrollbar_mode(const tscrollbar_mode scrollbar_mode)
00744 {
00745     if(horizontal_scrollbar_mode_ != scrollbar_mode) {
00746         horizontal_scrollbar_mode_ = scrollbar_mode;
00747     }
00748 }
00749 
00750 void tscrollbar_container::impl_draw_children(surface& frame_buffer)
00751 {
00752     assert(get_visible() == twidget::VISIBLE
00753             && content_grid_->get_visible() == twidget::VISIBLE);
00754 
00755     // Inherited.
00756     tcontainer_::impl_draw_children(frame_buffer);
00757 
00758     content_grid_->draw_children(frame_buffer);
00759 }
00760 
00761 void tscrollbar_container::impl_draw_children(
00762           surface& frame_buffer
00763         , int x_offset
00764         , int y_offset)
00765 {
00766     assert(get_visible() == twidget::VISIBLE
00767             && content_grid_->get_visible() == twidget::VISIBLE);
00768 
00769     // Inherited.
00770     tcontainer_::impl_draw_children(frame_buffer, x_offset, y_offset);
00771 
00772     content_grid_->draw_children(frame_buffer, x_offset, y_offset);
00773 }
00774 
00775 void tscrollbar_container::layout_children()
00776 {
00777     // Inherited.
00778     tcontainer_::layout_children();
00779 
00780     assert(content_grid_);
00781     content_grid_->layout_children();
00782 }
00783 
00784 void tscrollbar_container::child_populate_dirty_list(twindow& caller,
00785         const std::vector<twidget*>& call_stack)
00786 {
00787     // Inherited.
00788     tcontainer_::child_populate_dirty_list(caller, call_stack);
00789 
00790     assert(content_grid_);
00791     std::vector<twidget*> child_call_stack(call_stack);
00792     content_grid_->populate_dirty_list(caller, child_call_stack);
00793 }
00794 
00795 void tscrollbar_container::set_content_size(
00796         const tpoint& origin, const tpoint& size)
00797 {
00798     content_grid_->place(origin, size);
00799 }
00800 
00801 void tscrollbar_container::show_content_rect(const SDL_Rect& rect)
00802 {
00803     assert(content_);
00804     assert(horizontal_scrollbar_ && vertical_scrollbar_);
00805 
00806     // Set the bottom right location first if it doesn't fit the top left
00807     // will look good. First calculate the left and top position depending on
00808     // the current position.
00809 
00810     const int left_position = horizontal_scrollbar_->get_item_position()
00811             + (rect.x - content_->get_x());
00812     const int top_position = vertical_scrollbar_->get_item_position()
00813             + (rect.y - content_->get_y());
00814 
00815     // bottom.
00816     const int wanted_bottom = rect.y + rect.h;
00817     const int current_bottom = content_->get_y() + content_->get_height();
00818     int distance = wanted_bottom - current_bottom;
00819     if(distance > 0) {
00820         vertical_scrollbar_->set_item_position(
00821                 vertical_scrollbar_->get_item_position() + distance);
00822     }
00823 
00824     // right.
00825     const int wanted_right = rect.x + rect.w;
00826     const int current_right = content_->get_x() + content_->get_width();
00827     distance = wanted_right - current_right;
00828     if(distance > 0) {
00829         horizontal_scrollbar_->set_item_position(
00830                 horizontal_scrollbar_->get_item_position() + distance);
00831     }
00832 
00833     // top.
00834     if(top_position < static_cast<int>(
00835                 vertical_scrollbar_->get_item_position())) {
00836 
00837         vertical_scrollbar_->set_item_position(top_position);
00838     }
00839 
00840     // left.
00841     if(left_position < static_cast<int>(
00842                 horizontal_scrollbar_->get_item_position())) {
00843 
00844         horizontal_scrollbar_->set_item_position(left_position);
00845     }
00846 
00847     // Update.
00848     scrollbar_moved();
00849 }
00850 
00851 void tscrollbar_container::set_scrollbar_button_status()
00852 {
00853     if(true) { /** @todo scrollbar visibility. */
00854         /***** set scroll up button status *****/
00855         foreach(const std::string& name, button_up_names) {
00856             tcontrol* button = find_widget<tcontrol>(
00857                     vertical_scrollbar_grid_, name, false, false);
00858 
00859             if(button) {
00860                 button->set_active(!vertical_scrollbar_->at_begin());
00861             }
00862         }
00863 
00864         /***** set scroll down status *****/
00865         foreach(const std::string& name, button_down_names) {
00866             tcontrol* button = find_widget<tcontrol>(
00867                     vertical_scrollbar_grid_, name, false, false);
00868 
00869             if(button) {
00870                 button->set_active(!vertical_scrollbar_->at_end());
00871             }
00872         }
00873 
00874         /***** Set the status if the scrollbars *****/
00875         vertical_scrollbar_->set_active(
00876                 !vertical_scrollbar_->all_items_visible());
00877     }
00878 
00879     if(true) { /** @todo scrollbar visibility. */
00880         /***** Set scroll left button status *****/
00881         foreach(const std::string& name, button_up_names) {
00882             tcontrol* button = find_widget<tcontrol>(
00883                     horizontal_scrollbar_grid_, name, false, false);
00884 
00885             if(button) {
00886                 button->set_active(!horizontal_scrollbar_->at_begin());
00887             }
00888         }
00889 
00890         /***** Set scroll right button status *****/
00891         foreach(const std::string& name, button_down_names) {
00892             tcontrol* button = find_widget<tcontrol>(
00893                     horizontal_scrollbar_grid_, name, false, false);
00894 
00895             if(button) {
00896                 button->set_active(!horizontal_scrollbar_->at_end());
00897             }
00898         }
00899 
00900         /***** Set the status if the scrollbars *****/
00901         horizontal_scrollbar_->set_active(
00902                 !horizontal_scrollbar_->all_items_visible());
00903     }
00904 }
00905 
00906 void tscrollbar_container::scroll_vertical_scrollbar(
00907         const tscrollbar_::tscroll scroll)
00908 {
00909     assert(vertical_scrollbar_);
00910 
00911     vertical_scrollbar_->scroll(scroll);
00912     scrollbar_moved();
00913 }
00914 
00915 void tscrollbar_container::scroll_horizontal_scrollbar(
00916         const tscrollbar_::tscroll scroll)
00917 {
00918     assert(horizontal_scrollbar_);
00919 
00920     horizontal_scrollbar_->scroll(scroll);
00921     scrollbar_moved();
00922 }
00923 
00924 void tscrollbar_container::handle_key_home(SDLMod /*modifier*/, bool& handled)
00925 {
00926     assert(vertical_scrollbar_ && horizontal_scrollbar_);
00927 
00928     vertical_scrollbar_->scroll(tscrollbar_::BEGIN);
00929     horizontal_scrollbar_->scroll(tscrollbar_::BEGIN);
00930     scrollbar_moved();
00931 
00932     handled = true;
00933 }
00934 
00935 void tscrollbar_container::handle_key_end(SDLMod /*modifier*/, bool& handled)
00936 {
00937     assert(vertical_scrollbar_);
00938 
00939     vertical_scrollbar_->scroll(tscrollbar_::END);
00940     scrollbar_moved();
00941 
00942     handled = true;
00943 }
00944 
00945 void tscrollbar_container::
00946 		handle_key_page_up(SDLMod /*modifier*/, bool& handled)
00947 {
00948     assert(vertical_scrollbar_);
00949 
00950     vertical_scrollbar_->scroll(tscrollbar_::JUMP_BACKWARDS);
00951     scrollbar_moved();
00952 
00953     handled = true;
00954 }
00955 
00956 void tscrollbar_container::
00957 		handle_key_page_down(SDLMod /*modifier*/, bool& handled)
00958 
00959 {
00960     assert(vertical_scrollbar_);
00961 
00962     vertical_scrollbar_->scroll(tscrollbar_::JUMP_FORWARD);
00963     scrollbar_moved();
00964 
00965     handled = true;
00966 }
00967 
00968 void tscrollbar_container::
00969 		handle_key_up_arrow(SDLMod /*modifier*/, bool& handled)
00970 {
00971     assert(vertical_scrollbar_);
00972 
00973     vertical_scrollbar_->scroll(tscrollbar_::ITEM_BACKWARDS);
00974     scrollbar_moved();
00975 
00976     handled = true;
00977 }
00978 
00979 void tscrollbar_container::
00980 		handle_key_down_arrow( SDLMod /*modifier*/, bool& handled)
00981 {
00982     assert(vertical_scrollbar_);
00983 
00984     vertical_scrollbar_->scroll(tscrollbar_::ITEM_FORWARD);
00985     scrollbar_moved();
00986 
00987     handled = true;
00988 }
00989 
00990 void tscrollbar_container
00991 		::handle_key_left_arrow(SDLMod /*modifier*/, bool& handled)
00992 {
00993     assert(horizontal_scrollbar_);
00994 
00995     horizontal_scrollbar_->scroll(tscrollbar_::ITEM_BACKWARDS);
00996     scrollbar_moved();
00997 
00998     handled = true;
00999 }
01000 
01001 void tscrollbar_container
01002 		::handle_key_right_arrow(SDLMod /*modifier*/, bool& handled)
01003 {
01004     assert(horizontal_scrollbar_);
01005 
01006     horizontal_scrollbar_->scroll(tscrollbar_::ITEM_FORWARD);
01007     scrollbar_moved();
01008 
01009     handled = true;
01010 }
01011 
01012 void tscrollbar_container::scrollbar_moved()
01013 {
01014     // Init.
01015     assert(content_ && content_grid_);
01016     assert(vertical_scrollbar_ && horizontal_scrollbar_);
01017 
01018     /*** Update the content location. ***/
01019     const int x_offset = horizontal_scrollbar_mode_ == always_invisible
01020             ? 0
01021             : horizontal_scrollbar_->get_item_position() *
01022               horizontal_scrollbar_->get_step_size();
01023 
01024     const int y_offset = vertical_scrollbar_mode_ == always_invisible
01025             ? 0
01026             : vertical_scrollbar_->get_item_position() *
01027               vertical_scrollbar_->get_step_size();
01028 
01029     const tpoint content_origin = tpoint(
01030             content_->get_x() - x_offset,
01031             content_->get_y() - y_offset);
01032 
01033     content_grid_->set_origin(content_origin);
01034     content_grid_->set_visible_area(content_visible_area_);
01035     content_grid_->set_dirty();
01036 
01037     // Update scrollbar.
01038     set_scrollbar_button_status();
01039 }
01040 
01041 const std::string& tscrollbar_container::get_control_type() const
01042 {
01043     static const std::string type = "scrollbar_container";
01044     return type;
01045 }
01046 
01047 void tscrollbar_container::signal_handler_sdl_key_down(
01048         const event::tevent event
01049         , bool& handled
01050         , const SDLKey key
01051         , SDLMod modifier)
01052 {
01053     DBG_GUI_E << LOG_HEADER << event << ".\n";
01054 
01055     switch(key) {
01056         case SDLK_HOME :
01057             handle_key_home(modifier, handled);
01058             break;
01059 
01060         case SDLK_END :
01061             handle_key_end(modifier, handled);
01062             break;
01063 
01064 
01065         case SDLK_PAGEUP :
01066             handle_key_page_up(modifier, handled);
01067             break;
01068 
01069         case SDLK_PAGEDOWN :
01070             handle_key_page_down(modifier, handled);
01071             break;
01072 
01073 
01074         case SDLK_UP :
01075             handle_key_up_arrow(modifier, handled);
01076             break;
01077 
01078         case SDLK_DOWN :
01079             handle_key_down_arrow(modifier, handled);
01080             break;
01081 
01082         case SDLK_LEFT :
01083             handle_key_left_arrow(modifier, handled);
01084             break;
01085 
01086         case SDLK_RIGHT :
01087             handle_key_right_arrow(modifier, handled);
01088             break;
01089         default:
01090             /* ignore */
01091             break;
01092         }
01093 }
01094 
01095 void tscrollbar_container::signal_handler_sdl_wheel_up(
01096           const event::tevent event
01097         , bool& handled)
01098 {
01099     DBG_GUI_E << LOG_HEADER << event << ".\n";
01100 
01101     assert(vertical_scrollbar_grid_ && vertical_scrollbar_);
01102 
01103     if(vertical_scrollbar_grid_->get_visible() == twidget::VISIBLE) {
01104         vertical_scrollbar_->scroll(tscrollbar_::HALF_JUMP_BACKWARDS);
01105         scrollbar_moved();
01106         handled = true;
01107     }
01108 }
01109 
01110 void tscrollbar_container::signal_handler_sdl_wheel_down(
01111           const event::tevent event
01112         , bool& handled)
01113 {
01114     DBG_GUI_E << LOG_HEADER << event << ".\n";
01115 
01116     assert(vertical_scrollbar_grid_ && vertical_scrollbar_);
01117 
01118     if(vertical_scrollbar_grid_->get_visible() == twidget::VISIBLE) {
01119         vertical_scrollbar_->scroll(tscrollbar_::HALF_JUMP_FORWARD);
01120         scrollbar_moved();
01121         handled = true;
01122     }
01123 }
01124 
01125 void tscrollbar_container::signal_handler_sdl_wheel_left(
01126           const event::tevent event
01127         , bool& handled)
01128 {
01129     DBG_GUI_E << LOG_HEADER << event << ".\n";
01130 
01131     assert(horizontal_scrollbar_grid_ && horizontal_scrollbar_);
01132 
01133     if(horizontal_scrollbar_grid_->get_visible() == twidget::VISIBLE) {
01134         horizontal_scrollbar_->scroll(tscrollbar_::HALF_JUMP_BACKWARDS);
01135         scrollbar_moved();
01136         handled = true;
01137     }
01138 }
01139 
01140 void tscrollbar_container::signal_handler_sdl_wheel_right(
01141           const event::tevent event
01142         , bool& handled)
01143 {
01144     DBG_GUI_E << LOG_HEADER << event << ".\n";
01145 
01146     assert(horizontal_scrollbar_grid_ && horizontal_scrollbar_);
01147 
01148     if(horizontal_scrollbar_grid_->get_visible() == twidget::VISIBLE) {
01149         horizontal_scrollbar_->scroll(tscrollbar_::HALF_JUMP_FORWARD);
01150         scrollbar_moved();
01151         handled = true;
01152     }
01153 
01154 }
01155 
01156 } // namespace gui2
01157 
 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