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