scrollbar.cpp

Go to the documentation of this file.
00001 /* $Id: scrollbar.cpp 26698 2008-05-18 14:25:08Z mordante $ */
00002 /*
00003    copyright (C) 2008 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 version 2
00008    or at your option any later version.
00009    this program is distributed in the hope that it will be useful,
00010    but without any warranty.
00011 
00012    see the copying file for more details.
00013 */
00014 
00015 #include "gui/widgets/scrollbar.hpp"
00016 
00017 #include "foreach.hpp"
00018 #include "gui/widgets/event_handler.hpp"
00019 #include "log.hpp"
00020 
00021 #include <cassert>
00022 
00023 
00024 #define DBG_G LOG_STREAM_INDENT(debug, gui)
00025 #define LOG_G LOG_STREAM_INDENT(info, gui)
00026 #define WRN_G LOG_STREAM_INDENT(warn, gui)
00027 #define ERR_G LOG_STREAM_INDENT(err, gui)
00028 
00029 #define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
00030 #define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
00031 #define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
00032 #define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
00033 
00034 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00035 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00036 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00037 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00038 
00039 #define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
00040 #define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
00041 #define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
00042 #define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
00043 
00044 
00045 namespace gui2 {
00046 
00047 void tscrollbar_::mouse_move(tevent_handler& event)
00048 {
00049     tpoint mouse = event.get_mouse();
00050     mouse.x -= get_x();
00051     mouse.y -= get_y();
00052 
00053     DBG_G_E << "Scrollbar: mouse move at " << mouse << ".\n";
00054 
00055     switch(state_) {
00056         case ENABLED :
00057             if(on_positioner(mouse)) {
00058                 set_state(FOCUSSED);
00059             }
00060 
00061             break;
00062         case DISABLED :
00063             // do nothing
00064             break;
00065 
00066         case PRESSED : {
00067                 const int distance = get_length_difference(mouse_, mouse);
00068                 mouse_ = mouse;
00069                 move_positioner(distance);
00070             }
00071             break; 
00072 
00073         case FOCUSSED :
00074             if(!on_positioner(mouse)) {
00075                 set_state(ENABLED);
00076             }
00077             break;
00078 
00079         default :
00080             assert(false);
00081     }
00082 }
00083 
00084 void tscrollbar_::mouse_leave(tevent_handler&)
00085 {
00086     if(state_ == FOCUSSED) {
00087         set_state(ENABLED);
00088     }
00089 }
00090 
00091 void tscrollbar_::mouse_left_button_down(tevent_handler& event)
00092 {
00093     tpoint mouse = event.get_mouse();
00094     mouse.x -= get_x();
00095     mouse.y -= get_y();
00096 
00097     DBG_G_E << "Scrollbar: mouse down at " << mouse << ".\n";
00098 
00099     if(on_positioner(mouse)) {
00100         mouse_ = mouse;
00101         event.mouse_capture();
00102         set_state(PRESSED);
00103     }
00104 }
00105 
00106 void tscrollbar_::mouse_left_button_up(tevent_handler& event)
00107 {
00108     tpoint mouse = event.get_mouse();
00109     mouse.x -= get_x();
00110     mouse.y -= get_y();
00111 
00112     DBG_G_E << "Scrollbar: mouse up at " << mouse << ".\n";
00113 
00114     if(state_ != PRESSED) {
00115         return;
00116     }
00117 
00118     event.mouse_capture(false);
00119 
00120     if(on_positioner(mouse)) {
00121         set_state(FOCUSSED);
00122     } else {
00123         set_state(ENABLED);
00124     }
00125 }
00126 
00127 void tscrollbar_::set_size(const SDL_Rect& rect)
00128 {
00129     // Inherited.
00130     tcontrol::set_size(rect);
00131 
00132     recalculate();
00133 }
00134 
00135 void tscrollbar_::set_item_position(const unsigned item_position)
00136 {
00137     // Set the value always execute since we update a part of the state.
00138     item_position_ = item_position + visible_items_ > item_count_ ? 
00139         item_count_ - visible_items_ : item_position;
00140 
00141     item_position_ = (item_position_ + step_size_ - 1) / step_size_;
00142 
00143     // Determine the pixel offset of the item position.
00144     positioner_offset_ = static_cast<unsigned>(item_position_ * pixels_per_step_);
00145 
00146     update_canvas();
00147 }
00148 
00149 void tscrollbar_::scroll(const tscroll scroll)
00150 {
00151     switch(scroll) {
00152         case BEGIN : 
00153             set_item_position(0);
00154             break;
00155 
00156         case ITEM_BACKWARDS :
00157             if(item_position_) {
00158                 set_item_position(item_position_ - 1);
00159             }
00160             break;
00161 
00162         case HALF_JUMP_BACKWARDS :
00163             set_item_position(item_position_ > (visible_items_ / 2) ? 
00164                 item_position_ - (visible_items_ / 2) : 0);
00165             break;
00166 
00167         case JUMP_BACKWARDS :
00168             set_item_position(item_position_ > visible_items_ ? 
00169                 item_position_ - visible_items_  : 0);
00170             break;
00171 
00172         case END :
00173             set_item_position(item_count_ - 1);
00174             break;
00175             
00176         case ITEM_FORWARD :
00177             set_item_position(item_position_ + 1);
00178             break;
00179 
00180         case HALF_JUMP_FORWARD :
00181             set_item_position(item_position_ +  (visible_items_ / 2));
00182             break;
00183 
00184         case JUMP_FORWARD :
00185             set_item_position(item_position_ +  visible_items_ );
00186             break;
00187 
00188         default :
00189             assert(false);
00190         }
00191 }
00192 
00193 void tscrollbar_::set_state(const tstate state)
00194 {
00195     if(state != state_) {
00196         state_ = state;
00197         set_dirty(true);
00198     }
00199 }
00200 
00201 //! Inherited from tcontrol.
00202 void tscrollbar_::load_config_extra()
00203 {
00204     // These values won't change so set them here.
00205     foreach(tcanvas& tmp, canvas()) {
00206         tmp.set_variable("offset_before", variant(offset_before()));
00207         tmp.set_variable("offset_after", variant(offset_after()));
00208     }
00209 }
00210 
00211 //! Updates the size of the scroll bar.
00212 void tscrollbar_::recalculate()
00213 {
00214     // We can be called before the size has been set up in that case we can't do
00215     // the proper recalcultion so stop before we die with an assert.
00216     if(!get_length()) {
00217         return;
00218     }
00219 
00220     // Get the available size for the slider to move.
00221     int available_length = 
00222         get_length() - offset_before() - minimum_positioner_length() - offset_after();
00223 
00224     assert(available_length > 0);
00225 
00226     // All visible.
00227     if(item_count_ <= visible_items_) {
00228         positioner_offset_ = offset_before();
00229         positioner_length_ = available_length + minimum_positioner_length();
00230         item_position_ = 0;
00231         update_canvas();
00232         return;
00233     }
00234 
00235     assert(step_size_);
00236     assert(visible_items_);
00237 
00238     const unsigned steps = (item_count_ + step_size_ - 1) / step_size_;
00239 
00240     if(steps < available_length) {
00241 
00242         // We can show them all.
00243         available_length += minimum_positioner_length();
00244 
00245         pixels_per_step_ = available_length / steps;
00246 
00247         positioner_length_ = static_cast<unsigned>(pixels_per_step_ * visible_items_) + available_length % steps;
00248 
00249     } else {
00250 
00251         // We'll skip some.
00252         WRN_G << "The scrollbar is too small for the"
00253             " number of items, movement might seem jerky.\n";
00254         
00255         pixels_per_step_ = available_length / steps;
00256         positioner_length_ = minimum_positioner_length();
00257     }
00258 
00259     set_item_position(item_position_);
00260 }
00261 
00262 void tscrollbar_::update_canvas() {
00263 
00264     foreach(tcanvas& tmp, canvas()) {
00265         tmp.set_variable("positioner_offset", variant(positioner_offset_));
00266         tmp.set_variable("positioner_length", variant(positioner_length_));
00267     }
00268     set_dirty();
00269 }
00270 
00271 void tscrollbar_::move_positioner(const int distance)
00272 {
00273     if(distance < 0 && -distance > positioner_offset_) {
00274         positioner_offset_ = 0;
00275     } else {
00276         positioner_offset_ += distance;
00277     }
00278     const unsigned length = get_length() - offset_before() - offset_after();
00279 
00280     if(positioner_offset_ + positioner_length_ > length) {
00281         positioner_offset_ = length - positioner_length_;
00282     }
00283 
00284     const unsigned position =
00285         static_cast<unsigned>(positioner_offset_ / pixels_per_step_); 
00286 
00287     if(position != item_position_) {
00288         item_position_ = position; 
00289 
00290         if(callback_positioner_move_) {
00291             callback_positioner_move_(this);
00292         }
00293     }
00294 
00295     update_canvas();
00296 }
00297 
00298 } // namespace gui2
00299 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs