Updated scrollbar code
This commit is contained in:
parent
ba55645d2b
commit
121d0c4ca2
3 changed files with 108 additions and 80 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue