Updated scrollbar code

This commit is contained in:
KMJ 2004-03-02 03:34:08 +00:00
parent ba55645d2b
commit 121d0c4ca2
3 changed files with 108 additions and 80 deletions

View file

@ -48,15 +48,18 @@ menu::menu(display& disp, const std::vector<std::string>& items,
// The scrollbar height depends on the number of visible items versus
void menu::set_scrollbar_height()
{
int buttons_height = downarrow_.height() + uparrow_.height();
float pos_percent = (float)max_items_onscreen()/(float)items_.size();
scrollbar_height_ = (int)(pos_percent * items_height());
scrollbar_height_ = (int)(pos_percent * (height()-buttons_height));
int min_height = scrollbar_.get_minimum_grip_height();
if (scrollbar_height_ < min_height)
scrollbar_height_ = min_height;
if (scrollbar_height_ > items_height()) {
if (scrollbar_height_ > height()) {
std::cerr << "Strange. For some reason I want my scrollbar" <<
" to be larger than me!\n\n";
scrollbar_height_ = items_height();
scrollbar_height_ = height() - buttons_height;
}
scrollbar_.set_grip_height(scrollbar_height_);
@ -69,10 +72,6 @@ int menu::height() const
for(size_t i = 0; i != items_.size() && i != max_items_onscreen(); ++i) {
height_ += get_item_rect(i).h;
}
if(items_.size() > max_items_onscreen()) {
height_ += uparrow_.height() + downarrow_.height();
}
}
return height_;
@ -110,18 +109,17 @@ void menu::set_loc(int x, int y)
scrollbar_.enable(true);
int scr_width = scrollbar_.get_width();
// this seems to be the best configuration
int fudge = (uparrow_.width() - scr_width);
uparrow_.set_x(x_ + menu_width - fudge);
uparrow_.set_y(y_ );
downarrow_.set_x(x_+ menu_width - fudge);
downarrow_.set_y(y_ + items_end());
SDL_Rect scroll_rect = {x_ + menu_width, y_+uparrow_.height(),
scr_width, items_height()};
scr_width,
height()-downarrow_.height()-uparrow_.height()};
scrollbar_.set_location(scroll_rect);
set_scrollbar_height();
uparrow_.set_x(x_ + menu_width);
uparrow_.set_y(y_);
downarrow_.set_x(x_+ menu_width);
downarrow_.set_y(scrollbar_.location().y + scrollbar_.location().h);
}
}
@ -311,6 +309,7 @@ int menu::process(int x, int y, bool button,bool up_arrow,bool down_arrow,
static int last_scroll_position = 0;
bool scroll_in_use = false;
const int last_top_idx = items_.size() - max_items_onscreen();
int max_scroll_position = scrollbar_.location().h-scrollbar_height_;
if(show_scrollbar()) {
const bool up = uparrow_.process(x,y,button);
if(up && first_item_on_screen_ > 0) {
@ -331,14 +330,15 @@ int menu::process(int x, int y, bool button,bool up_arrow,bool down_arrow,
if (scroll_position != last_scroll_position) {
last_scroll_position = scroll_position;
if (scroll_position == 0) {
new_first_item = 0;
}
else if (scroll_position > items_height() - scrollbar_height_) {
else if (scroll_position > (max_scroll_position)) {
new_first_item = last_top_idx;
}
else {
new_first_item = scroll_position * last_top_idx /
(items_height() - scrollbar_height_);
max_scroll_position;
}
if (new_first_item != first_item_on_screen_) {
scroll_in_use = true;
@ -347,12 +347,32 @@ int menu::process(int x, int y, bool button,bool up_arrow,bool down_arrow,
drawn_ = false;
}
}
else {
int groove = scrollbar_.groove_clicked();
if (groove == -1) {
first_item_on_screen_ -= max_items_onscreen();
if (first_item_on_screen_ <= 0) {
first_item_on_screen_ = 0;
}
itemRects_.clear();
drawn_ = false;
}
else if (groove == 1) {
first_item_on_screen_ += max_items_onscreen();
if (first_item_on_screen_ > last_top_idx) {
first_item_on_screen_ = last_top_idx;
}
itemRects_.clear();
drawn_ = false;
}
}
}
if(!drawn_) {
if (!scroll_in_use && show_scrollbar()) {
int new_scrollpos = (first_item_on_screen_ *
(items_height() - scrollbar_height_)) / last_top_idx;
int new_scrollpos =
(first_item_on_screen_ * max_scroll_position)
/ last_top_idx;
scrollbar_.set_grip_position(new_scrollpos);
last_scroll_position = new_scrollpos;
}
@ -426,7 +446,7 @@ void menu::draw_item(int item)
}
if(buffer_.get() != NULL) {
const int ypos = items_start()+(item-first_item_on_screen_)*rect.h;
const int ypos = (item-first_item_on_screen_)*rect.h;
SDL_Rect srcrect = {0,ypos,rect.w,rect.h};
SDL_Rect dstrect = rect;
SDL_BlitSurface(buffer_,&srcrect,
@ -514,7 +534,7 @@ SDL_Rect menu::get_item_rect(int item) const
if(i != itemRects_.end())
return i->second;
int y = y_ + items_start();
int y = y_;
if(item != first_item_on_screen_) {
const SDL_Rect& prev = get_item_rect(item-1);
y = prev.y + prev.h;
@ -570,25 +590,4 @@ size_t menu::get_item_height(int item) const
return item_height_ = max_height;
}
int menu::items_start() const
{
if(show_scrollbar())
return uparrow_.height();
else
return 0;
}
int menu::items_end() const
{
if(show_scrollbar())
return height() - downarrow_.height();
else
return height();
}
int menu::items_height() const
{
return items_end() - items_start();
}
}

View file

@ -22,24 +22,29 @@ namespace {
const std::string scrollbar_top = "buttons/scrolltop.png";
const std::string scrollbar_bottom = "buttons/scrollbottom.png";
const std::string scrollbar_mid = "buttons/scrollmid.png";
const std::string scrollbar_top_hl = "buttons/scrolltop-active.png";
const std::string scrollbar_bottom_hl = "buttons/scrollbottom-active.png";
const std::string scrollbar_mid_hl = "buttons/scrollmid-active.png";
const std::string groove_top = "buttons/scrollgroove-top.png";
const std::string groove_mid = "buttons/scrollgroove-mid.png";
const std::string groove_bottom = "buttons/scrollgroove-bottom.png";
const int sb_width_pad = 2;
}
namespace gui {
scrollbar::scrollbar(display& d)
: widget(d), highlight_(false),
clicked_(false), dragging_(false), grip_position_(0), grip_height_(0),
enabled_(false), width_(0), minimum_grip_height_(0)
: widget(d), highlight_(false), clicked_(false), dragging_(false),
grip_position_(0), grip_height_(0), enabled_(false), width_(0),
minimum_grip_height_(0), groove_click_code_(0)
{
static const scoped_sdl_surface img(image::get_image(scrollbar_mid,
image::UNSCALED));
if (img != NULL) {
width_ = img->w + sb_width_pad*2;
width_ = img->w;
// this is a bit rough maybe
minimum_grip_height_ = 2 * img->h;
grip_height_ = minimum_grip_height_;
@ -112,12 +117,12 @@ void scrollbar::draw()
if (!enabled() || !dirty())
return;
const scoped_sdl_surface mid_img(image::get_image(scrollbar_mid,
image::UNSCALED));
const scoped_sdl_surface bottom_img(image::get_image(scrollbar_bottom,
image::UNSCALED));
const scoped_sdl_surface top_img(image::get_image(scrollbar_top,
image::UNSCALED));
const scoped_sdl_surface mid_img(image::get_image(highlight_ ?
scrollbar_mid_hl : scrollbar_mid, image::UNSCALED));
const scoped_sdl_surface bottom_img(image::get_image(highlight_ ?
scrollbar_bottom_hl : scrollbar_bottom, image::UNSCALED));
const scoped_sdl_surface top_img(image::get_image(highlight_ ?
scrollbar_top_hl : scrollbar_top, image::UNSCALED));
const scoped_sdl_surface top_grv(image::get_image(groove_top,
image::UNSCALED));
@ -142,11 +147,6 @@ void scrollbar::draw()
const scoped_sdl_surface mid_scaled(scale_surface_blended(mid_img,
mid_img->w, mid_height));
const scoped_sdl_surface highlighted(scale_surface_blended(
brighten_image(mid_img, 1.5),
mid_img->w, mid_height));
int groove_height = location().h - top_grv->h - bottom_grv->h;
if (groove_height <= 0) {
groove_height = 1;
@ -166,7 +166,7 @@ void scrollbar::draw()
bg_restore();
int xpos = location().x + sb_width_pad;
int xpos = location().x;
// draw scrollbar "groove"
disp().blit_surface(xpos, location().y, top_grv);
@ -176,10 +176,9 @@ void scrollbar::draw()
// draw scrollbar "grip"
SDL_Rect scrollbar = scroll_grip_area();
xpos = scrollbar.x + sb_width_pad;
xpos = scrollbar.x;
disp().blit_surface(xpos, scrollbar.y, top_img);
disp().blit_surface(xpos, scrollbar.y + top_img->h,
highlight_ ? highlighted : mid_scaled);
disp().blit_surface(xpos, scrollbar.y + top_img->h, mid_scaled);
disp().blit_surface(xpos, scrollbar.y + top_img->h + mid_height,
bottom_img);
@ -203,6 +202,11 @@ int scrollbar::get_grip_position() const
return grip_position_;
}
int scrollbar::groove_clicked() const
{
return groove_click_code_;
}
void scrollbar::process()
{
if (!enabled())
@ -217,10 +221,13 @@ void scrollbar::process()
set_location(rect);
const SDL_Rect& hit_area = scroll_grip_area();
const bool xrange = mousex > hit_area.x && mousex <= hit_area.x+hit_area.w;
const bool yrange = mousey > hit_area.y && mousey <= hit_area.y+hit_area.h;
const bool barx= mousex > hit_area.x && mousex <= hit_area.x+hit_area.w;
const bool gripy = mousey > hit_area.y && mousey <= hit_area.y+hit_area.h;
const bool bary = mousey > location().y &&
mousey <= location().y+location().h;
const bool on = xrange && yrange;
const bool on = barx && gripy;
bool start_dragging = (button && !clicked_ && on);
@ -237,27 +244,35 @@ void scrollbar::process()
set_dirty(true);
}
int new_position = grip_position_;
groove_click_code_ = 0;
if (dragging_) {
// mouse over grip & button down
int new_position = grip_position_;
highlight_ = true;
new_position = mousey - mousey_on_grip;
if (new_position < 0)
new_position = 0;
if (new_position > location().h - grip_height_)
new_position = location().h - grip_height_;
if (new_position != grip_position_) {
grip_position_ = new_position;
set_dirty(true);
}
}
else if (button && xrange) {
int button_position = mousey - location().y;
if (button_position != grip_position_)
new_position = button_position;
else if (button && barx && bary && (!clicked_)) {
if (mousey > hit_area.y + hit_area.h) {
// mouse on groove below grip & button down
groove_click_code_ = 1;
}
else {
// mouse on groove above grip & button down
groove_click_code_ = -1;
}
}
if (new_position < 0)
new_position = 0;
if (new_position > location().h - grip_height_)
new_position = location().h - grip_height_;
if (new_position != grip_position_) {
grip_position_ = new_position;
set_dirty(true);
}
clicked_ = button;
draw();

View file

@ -21,6 +21,10 @@
namespace gui{
/// class scrollbar implements a rather stupid scrollbar widget. It requires
/// some hand-holding from the widget using it. Many of these functions will
/// likely be removed (possibly replaced) at a later date, as the "widget"
/// class hierarchy is expanded
class scrollbar : public widget
{
public:
@ -85,6 +89,12 @@ public:
/// \return true if successful, false otherwise.
bool set_grip_height(int pos);
/// This function determines whether the user clicked on the scrollbar
/// groove, and whether it was above or below the grip
///
/// \return -1 if click was above, 1 if click was below, 0 otherwise
int groove_clicked() const;
protected:
using widget::bg_restore;
using widget::set_dirty;
@ -108,6 +118,10 @@ private:
int grip_height_;
int enabled_;
// -1 if user just clicked above the groove, 1 if they just clicked below
// 0 otherwise
int groove_click_code_;
};
}