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/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
00044
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 }
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
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
00165
00166
00167
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
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
00194 vertical_scrollbar_grid_->set_visible(twidget::VISIBLE);
00195
00196 const tpoint scrollbar_size = vertical_scrollbar_grid_->get_best_size();
00197
00198
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
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
00237
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
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
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
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
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
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
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
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
00356 tcontainer_::place(origin, size);
00357
00358
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
00373 set_scrollbar_mode(vertical_scrollbar_grid_, vertical_scrollbar_,
00374 vertical_scrollbar_mode_,
00375 content_grid_->get_height(),
00376 content_->get_height());
00377
00378
00379 set_scrollbar_mode(horizontal_scrollbar_grid_, horizontal_scrollbar_,
00380 horizontal_scrollbar_mode_,
00381 content_grid_->get_width(),
00382 content_->get_width());
00383
00384
00385 set_scrollbar_button_status();
00386
00387
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
00395 tcontainer_::set_origin(origin);
00396
00397
00398 assert(content_ && content_grid_);
00399
00400 const tpoint content_origin = content_->get_origin();
00401
00402 content_grid_->set_origin(content_origin);
00403
00404
00405 content_grid_->set_visible_area(content_visible_area_);
00406 }
00407
00408 void tscrollbar_container::set_visible_area(const SDL_Rect& area)
00409 {
00410
00411 tcontainer_::set_visible_area(area);
00412
00413
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
00458
00459
00460
00461
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
00563
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
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
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
00694 typedef std::pair<std::string, tscrollbar_::tscroll> hack;
00695 foreach(const hack& item, scroll_lookup()) {
00696
00697
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
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
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
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
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
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
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
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
00807
00808
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
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
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
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
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
00848 scrollbar_moved();
00849 }
00850
00851 void tscrollbar_container::set_scrollbar_button_status()
00852 {
00853 if(true) {
00854
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
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
00875 vertical_scrollbar_->set_active(
00876 !vertical_scrollbar_->all_items_visible());
00877 }
00878
00879 if(true) {
00880
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
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
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 , 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 , 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 , 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 , 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 , 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 , 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 , 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 , 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
01015 assert(content_ && content_grid_);
01016 assert(vertical_scrollbar_ && horizontal_scrollbar_);
01017
01018
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
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
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 }
01157