widgets/scrollbar.cpp

Go to the documentation of this file.
00001 /* $Id: scrollbar.cpp 52533 2012-01-07 02:35:17Z shadowmaster $*/
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004                  2004 - 2012 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 as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY.
00013 
00014    See the COPYING file for more details.
00015 */
00016 
00017 /** @file */
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         // this is a bit rough maybe
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     //bg_register(r);
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         // For now, minimum size of the middle piece is 1.
00249         // This should never really be encountered, and if it is,
00250         // it's a symptom of a larger problem, I think.
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     // Draw scrollbar "groove"
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     // Draw scrollbar "grip"
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 } // end namespace gui
00361 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:59 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs