00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00130 tcontrol::set_size(rect);
00131
00132 recalculate();
00133 }
00134
00135 void tscrollbar_::set_item_position(const unsigned item_position)
00136 {
00137
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
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
00202 void tscrollbar_::load_config_extra()
00203 {
00204
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
00212 void tscrollbar_::recalculate()
00213 {
00214
00215
00216 if(!get_length()) {
00217 return;
00218 }
00219
00220
00221 int available_length =
00222 get_length() - offset_before() - minimum_positioner_length() - offset_after();
00223
00224 assert(available_length > 0);
00225
00226
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
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
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 }
00299