00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #define GETTEXT_DOMAIN "wesnoth-lib"
00020
00021 #include "global.hpp"
00022
00023 #include "widgets/scrollbar.hpp"
00024 #include "image.hpp"
00025 #include "video.hpp"
00026
00027 #include <iostream>
00028
00029 namespace {
00030 const std::string scrollbar_top = "buttons/scrolltop.png";
00031 const std::string scrollbar_bottom = "buttons/scrollbottom.png";
00032 const std::string scrollbar_mid = "buttons/scrollmid.png";
00033
00034 const std::string scrollbar_top_hl = "buttons/scrolltop-active.png";
00035 const std::string scrollbar_bottom_hl = "buttons/scrollbottom-active.png";
00036 const std::string scrollbar_mid_hl = "buttons/scrollmid-active.png";
00037
00038 const std::string groove_top = "buttons/scrollgroove-top.png";
00039 const std::string groove_mid = "buttons/scrollgroove-mid.png";
00040 const std::string groove_bottom = "buttons/scrollgroove-bottom.png";
00041
00042 }
00043
00044 namespace gui {
00045
00046 scrollbar::scrollbar(CVideo &video)
00047 : widget(video)
00048 , mid_scaled_(NULL)
00049 , groove_scaled_(NULL)
00050 , uparrow_(video, "", button::TYPE_TURBO, "uparrow-button")
00051 , downarrow_(video, "", button::TYPE_TURBO, "downarrow-button")
00052 , state_(NORMAL)
00053 , minimum_grip_height_(0)
00054 , mousey_on_grip_(0)
00055 , grip_position_(0)
00056 , grip_height_(0)
00057 , old_position_(0)
00058 , full_height_(0)
00059 , scroll_rate_(1)
00060 {
00061 static const surface img(image::get_image(scrollbar_mid));
00062
00063 if (img != NULL) {
00064 set_width(img->w);
00065
00066 minimum_grip_height_ = 2 * img->h;
00067 }
00068 }
00069
00070 handler_vector scrollbar::handler_members()
00071 {
00072 handler_vector h;
00073 h.push_back(&uparrow_);
00074 h.push_back(&downarrow_);
00075 return h;
00076 }
00077
00078 void scrollbar::update_location(SDL_Rect const &rect)
00079 {
00080 int uh = uparrow_.height(), dh = downarrow_.height();
00081 uparrow_.set_location(rect.x, rect.y);
00082 downarrow_.set_location(rect.x, rect.y + rect.h - dh);
00083 SDL_Rect r = rect;
00084 r.y += uh;
00085 r.h -= uh + dh;
00086
00087 widget::update_location(r);
00088
00089 }
00090
00091 void scrollbar::hide(bool value)
00092 {
00093 widget::hide(value);
00094 uparrow_.hide(value);
00095 downarrow_.hide(value);
00096 }
00097
00098 unsigned scrollbar::get_position() const
00099 {
00100 return grip_position_;
00101 }
00102
00103 unsigned scrollbar::get_max_position() const
00104 {
00105 return full_height_ - grip_height_;
00106 }
00107
00108 void scrollbar::set_position(unsigned pos)
00109 {
00110 if (pos > full_height_ - grip_height_)
00111 pos = full_height_ - grip_height_;
00112 if (pos == grip_position_)
00113 return;
00114 grip_position_ = pos;
00115 uparrow_.enable(grip_position_ != 0);
00116 downarrow_.enable(grip_position_ < full_height_ - grip_height_);
00117 set_dirty();
00118 }
00119
00120 void scrollbar::adjust_position(unsigned pos)
00121 {
00122 if (pos < grip_position_)
00123 set_position(pos);
00124 else if (pos >= grip_position_ + grip_height_)
00125 set_position(pos - (grip_height_ - 1));
00126 }
00127
00128 void scrollbar::move_position(int dep)
00129 {
00130 int pos = grip_position_ + dep;
00131 if (pos > 0)
00132 set_position(pos);
00133 else
00134 set_position(0);
00135 }
00136
00137 void scrollbar::set_shown_size(unsigned h)
00138 {
00139 if (h > full_height_)
00140 h = full_height_;
00141 if (h == grip_height_)
00142 return;
00143 bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
00144 grip_height_ = h;
00145 if (at_bottom)
00146 grip_position_ = get_max_position();
00147 set_position(grip_position_);
00148 set_dirty(true);
00149 }
00150
00151 void scrollbar::set_full_size(unsigned h)
00152 {
00153 if (h == full_height_)
00154 return;
00155 bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
00156 full_height_ = h;
00157 if (at_bottom)
00158 grip_position_ = get_max_position();
00159 downarrow_.enable(grip_position_ < full_height_ - grip_height_);
00160 set_shown_size(grip_height_);
00161 set_position(grip_position_);
00162 set_dirty(true);
00163 }
00164
00165 void scrollbar::set_scroll_rate(unsigned r)
00166 {
00167 scroll_rate_ = r;
00168 }
00169
00170 bool scrollbar::is_valid_height(int height) const
00171 {
00172 int uh = uparrow_.height();
00173 int dh = downarrow_.height();
00174 if(uh + dh >= height) {
00175 return false;
00176 } else {
00177 return true;
00178 }
00179 }
00180
00181 void scrollbar::scroll_down()
00182 {
00183 move_position(scroll_rate_);
00184 }
00185
00186 void scrollbar::scroll_up()
00187 {
00188 move_position(-scroll_rate_);
00189 }
00190
00191 void scrollbar::process_event()
00192 {
00193 if (uparrow_.pressed())
00194 scroll_up();
00195
00196 if (downarrow_.pressed())
00197 scroll_down();
00198 }
00199
00200 SDL_Rect scrollbar::groove_area() const
00201 {
00202 SDL_Rect loc = location();
00203 int uh = uparrow_.height();
00204 int dh = downarrow_.height();
00205 if(uh + dh >= loc.h) {
00206 loc.h = 0;
00207 } else {
00208 loc.y += uh;
00209 loc.h -= uh + dh;
00210 }
00211 return loc;
00212 }
00213
00214 SDL_Rect scrollbar::grip_area() const
00215 {
00216 SDL_Rect const &loc = groove_area();
00217 if (full_height_ == grip_height_)
00218 return loc;
00219 int h = static_cast<int>(loc.h) * grip_height_ / full_height_;
00220 if (h < minimum_grip_height_)
00221 h = minimum_grip_height_;
00222 int y = loc.y + (static_cast<int>(loc.h) - h) * grip_position_ / (full_height_ - grip_height_);
00223 return create_rect(loc.x, y, loc.w, h);
00224 }
00225
00226 void scrollbar::draw_contents()
00227 {
00228 const surface mid_img(image::get_image(state_ != NORMAL ?
00229 scrollbar_mid_hl : scrollbar_mid));
00230 const surface bottom_img(image::get_image(state_ != NORMAL ?
00231 scrollbar_bottom_hl : scrollbar_bottom));
00232 const surface top_img(image::get_image(state_ != NORMAL ?
00233 scrollbar_top_hl : scrollbar_top));
00234
00235 const surface top_grv(image::get_image(groove_top));
00236 const surface mid_grv(image::get_image(groove_mid));
00237 const surface bottom_grv(image::get_image(groove_bottom));
00238
00239 if (mid_img == NULL || bottom_img == NULL || top_img == NULL
00240 || top_grv == NULL || bottom_grv == NULL || mid_grv == NULL) {
00241 std::cerr << "Failure to load scrollbar image.\n";
00242 return;
00243 }
00244
00245 SDL_Rect grip = grip_area();
00246 int mid_height = grip.h - top_img->h - bottom_img->h;
00247 if (mid_height <= 0) {
00248
00249
00250
00251 mid_height = 1;
00252 }
00253
00254 if(mid_scaled_.null() || mid_scaled_->h != mid_height) {
00255 mid_scaled_.assign(scale_surface(mid_img, mid_img->w, mid_height));
00256 }
00257
00258 SDL_Rect groove = groove_area();
00259 int groove_height = groove.h - top_grv->h - bottom_grv->h;
00260 if (groove_height <= 0) {
00261 groove_height = 1;
00262 }
00263
00264 if (groove_scaled_.null() || groove_scaled_->h != groove_height) {
00265 groove_scaled_.assign(scale_surface(mid_grv, mid_grv->w, groove_height));
00266 }
00267
00268 if (mid_scaled_.null() || groove_scaled_.null()) {
00269 std::cerr << "Failure during scrollbar image scale.\n";
00270 return;
00271 }
00272
00273 if (grip.h > groove.h) {
00274 std::cerr << "abort draw scrollbar: grip too large\n";
00275 return;
00276 }
00277
00278 surface const screen = video().getSurface();
00279
00280
00281 video().blit_surface(groove.x, groove.y, top_grv);
00282 video().blit_surface(groove.x, groove.y + top_grv->h, groove_scaled_);
00283 video().blit_surface(groove.x, groove.y + top_grv->h + groove_height, bottom_grv);
00284
00285
00286 video().blit_surface(grip.x, grip.y, top_img);
00287 video().blit_surface(grip.x, grip.y + top_img->h, mid_scaled_);
00288 video().blit_surface(grip.x, grip.y + top_img->h + mid_height, bottom_img);
00289
00290 update_rect(groove);
00291 }
00292
00293 void scrollbar::handle_event(const SDL_Event& event)
00294 {
00295 if (mouse_locked() || hidden())
00296 return;
00297
00298 STATE new_state = state_;
00299 SDL_Rect const &grip = grip_area();
00300 SDL_Rect const &groove = groove_area();
00301
00302
00303 switch (event.type) {
00304 case SDL_MOUSEBUTTONUP:
00305 {
00306 SDL_MouseButtonEvent const &e = event.button;
00307 bool on_grip = point_in_rect(e.x, e.y, grip);
00308 new_state = on_grip ? ACTIVE : NORMAL;
00309 break;
00310 }
00311 case SDL_MOUSEBUTTONDOWN:
00312 {
00313 SDL_MouseButtonEvent const &e = event.button;
00314 bool on_grip = point_in_rect(e.x, e.y, grip);
00315 bool on_groove = point_in_rect(e.x, e.y, groove);
00316 if (on_groove && e.button == SDL_BUTTON_WHEELDOWN) {
00317 move_position(scroll_rate_);
00318 } else if (on_groove && e.button == SDL_BUTTON_WHEELUP) {
00319 move_position(-scroll_rate_);
00320 } else if (on_grip && e.button == SDL_BUTTON_LEFT) {
00321 mousey_on_grip_ = e.y - grip.y;
00322 new_state = DRAGGED;
00323 } else if (on_groove && e.button == SDL_BUTTON_LEFT && groove.h != grip.h) {
00324 if (e.y < grip.y)
00325 move_position(-static_cast<int>(grip_height_));
00326 else
00327 move_position(grip_height_);
00328 } else if (on_groove && e.button == SDL_BUTTON_MIDDLE) {
00329 int y_dep = e.y - grip.y - grip.h/2;
00330 int dep = y_dep * int(full_height_ - grip_height_)/ int(groove.h - grip.h);
00331 move_position(dep);
00332 }
00333 break;
00334 }
00335 case SDL_MOUSEMOTION:
00336 {
00337 SDL_MouseMotionEvent const &e = event.motion;
00338 if (state_ == NORMAL || state_ == ACTIVE) {
00339 bool on_grip = point_in_rect(e.x, e.y, grip);
00340 new_state = on_grip ? ACTIVE : NORMAL;
00341 } else if (state_ == DRAGGED && groove.h != grip.h) {
00342 int y_dep = e.y - grip.y - mousey_on_grip_;
00343 int dep = y_dep * static_cast<int>(full_height_ - grip_height_) /
00344 static_cast<int>(groove.h - grip.h);
00345 move_position(dep);
00346 }
00347 break;
00348 }
00349 default:
00350 break;
00351 }
00352
00353 if ((new_state == NORMAL) ^ (state_ == NORMAL)) {
00354 set_dirty();
00355 mid_scaled_.assign(NULL);
00356 }
00357 state_ = new_state;
00358 }
00359
00360 }
00361