scrollbar.cpp

Go to the documentation of this file.
00001 /* $Id: scrollbar.cpp 23842 2008-02-16 08:47:16Z mordante $*/
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004                  2004 - 2008 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 //! @file widgets/scrollbar.cpp
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         // this is a bit rough maybe
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     //bg_register(r);
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         // For now, minimum size of the middle piece is 1.
00241         // This should never really be encountered, and if it is,
00242         // it's a symptom of a larger problem, I think.
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     // Draw scrollbar "groove"
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     // Draw scrollbar "grip"
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 } // end namespace gui
00352 

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