The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
scrollbar.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  2004 - 2015 by Guillaume Melquiond <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /** @file */
17 
18 #define GETTEXT_DOMAIN "wesnoth-lib"
19 
20 #include "global.hpp"
21 
22 #include "widgets/scrollbar.hpp"
23 #include "image.hpp"
24 #include "sdl/rect.hpp"
25 #include "video.hpp"
26 
27 #include <iostream>
28 
29 namespace {
30  const std::string scrollbar_top = "buttons/scrollbars_large/scrolltop.png";
31  const std::string scrollbar_bottom = "buttons/scrollbars_large/scrollbottom.png";
32  const std::string scrollbar_mid = "buttons/scrollbars_large/scrollmid.png";
33 
34  const std::string scrollbar_top_hl = "buttons/scrollbars_large/scrolltop-active.png";
35  const std::string scrollbar_bottom_hl = "buttons/scrollbars_large/scrollbottom-active.png";
36  const std::string scrollbar_mid_hl = "buttons/scrollbars_large/scrollmid-active.png";
37 
38  const std::string scrollbar_top_pressed = "buttons/scrollbars_large/scrolltop-pressed.png";
39  const std::string scrollbar_bottom_pressed = "buttons/scrollbars_large/scrollbottom-pressed.png";
40  const std::string scrollbar_mid_pressed = "buttons/scrollbars_large/scrollmid-pressed.png";
41 
42  const std::string groove_top = "buttons/scrollbars_large/scrollgroove-top.png";
43  const std::string groove_mid = "buttons/scrollbars_large/scrollgroove-mid.png";
44  const std::string groove_bottom = "buttons/scrollbars_large/scrollgroove-bottom.png";
45 
46 }
47 
48 namespace gui {
49 
51  : widget(video)
52  , mid_scaled_(nullptr)
53  , groove_scaled_(nullptr)
54  , uparrow_(video, "", button::TYPE_TURBO, "button_square/button_square_25"
55  , gui::button::DEFAULT_SPACE, true,"icons/arrows/arrows_ornate_up_25")
56  , downarrow_(video, "", button::TYPE_TURBO, "button_square/button_square_25"
57  , gui::button::DEFAULT_SPACE, true,"icons/arrows/arrows_ornate_down_25")
58  , state_(NORMAL)
59  , minimum_grip_height_(0)
60  , mousey_on_grip_(0)
61  , grip_position_(0)
62  , grip_height_(0)
63  , full_height_(0)
64  , scroll_rate_(1)
65 {
66  uparrow_.enable(false);
67  downarrow_.enable(false);
68 
69  static const surface img(image::get_image(scrollbar_mid));
70 
71  if (img != nullptr) {
72  set_width(img->w);
73  // this is a bit rough maybe
74  minimum_grip_height_ = 2 * img->h;
75  }
76 }
77 
79 {
81  h.push_back(&uparrow_);
82  h.push_back(&downarrow_);
83  return h;
84 }
85 
86 void scrollbar::update_location(SDL_Rect const &rect)
87 {
88  int uh = uparrow_.height(), dh = downarrow_.height();
89  uparrow_.set_location(rect.x, rect.y);
90  downarrow_.set_location(rect.x, rect.y + rect.h - dh);
91  SDL_Rect r = rect;
92  r.y += uh;
93  r.h -= uh + dh;
94 
96  //TODO comment or remove
97  //bg_register(r);
98 }
99 
101 {
102  widget::hide(value);
103  uparrow_.hide(value);
104  downarrow_.hide(value);
105 }
106 
107 unsigned scrollbar::get_position() const
108 {
109  return grip_position_;
110 }
111 
113 {
114  return full_height_ - grip_height_;
115 }
116 
118 {
119  if (pos > full_height_ - grip_height_)
120  pos = full_height_ - grip_height_;
121  if (pos == grip_position_)
122  return;
125  downarrow_.enable(grip_position_ < full_height_ - grip_height_);
126  set_dirty();
127 }
128 
130 {
131  if (pos < grip_position_)
132  set_position(pos);
133  else if (pos >= grip_position_ + grip_height_)
134  set_position(pos - (grip_height_ - 1));
135 }
136 
138 {
139  int pos = grip_position_ + dep;
140  if (pos > 0)
141  set_position(pos);
142  else
143  set_position(0);
144 }
145 
147 {
148  if (h > full_height_)
149  h = full_height_;
150  if (h == grip_height_)
151  return;
152  bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
153  grip_height_ = h;
154  if (at_bottom)
157  set_dirty(true);
158 }
159 
161 {
162  if (h == full_height_)
163  return;
164  bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
165  full_height_ = h;
166  if (at_bottom)
171  set_dirty(true);
172 }
173 
175 {
176  scroll_rate_ = r;
177 }
178 
180 {
181  int uh = uparrow_.height();
182  int dh = downarrow_.height();
183  if(uh + dh >= height) {
184  return false;
185  } else {
186  return true;
187  }
188 }
189 
191 {
193 }
194 
196 {
198 }
199 
201 {
202  if (uparrow_.pressed())
203  scroll_up();
204 
205  if (downarrow_.pressed())
206  scroll_down();
207 }
208 
209 SDL_Rect scrollbar::groove_area() const
210 {
211  SDL_Rect loc = location();
212  int uh = uparrow_.height();
213  int dh = downarrow_.height();
214  if(uh + dh >= loc.h) {
215  loc.h = 0;
216  } else {
217  loc.y += uh;
218  loc.h -= uh + dh;
219  }
220  return loc;
221 }
222 
223 SDL_Rect scrollbar::grip_area() const
224 {
225  SDL_Rect const &loc = groove_area();
226  if (full_height_ == grip_height_)
227  return loc;
228  int h = static_cast<int>(loc.h) * grip_height_ / full_height_;
229  if (h < minimum_grip_height_)
231  int y = loc.y + (static_cast<int>(loc.h) - h) * grip_position_ / (full_height_ - grip_height_);
232  return sdl::create_rect(loc.x, y, loc.w, h);
233 }
234 
236 {
237  surface mid_img;
238  surface bottom_img;
239  surface top_img;
240 
241  switch (state_) {
242 
243  case NORMAL:
244  top_img.assign(image::get_image(scrollbar_top));
245  mid_img.assign(image::get_image(scrollbar_mid));
246  bottom_img.assign(image::get_image(scrollbar_bottom));
247  break;
248 
249  case ACTIVE:
250  top_img.assign(image::get_image(scrollbar_top_hl));
251  mid_img.assign(image::get_image(scrollbar_mid_hl));
252  bottom_img.assign(image::get_image(scrollbar_bottom_hl));
253  break;
254 
255  case DRAGGED:
256  top_img.assign(image::get_image(scrollbar_top_pressed));
257  mid_img.assign(image::get_image(scrollbar_mid_pressed));
258  bottom_img.assign(image::get_image(scrollbar_bottom_pressed));
259  break;
260 
261  case UNINIT:
262  default:
263  break;
264  }
265 
266  const surface top_grv(image::get_image(groove_top));
267  const surface mid_grv(image::get_image(groove_mid));
268  const surface bottom_grv(image::get_image(groove_bottom));
269 
270  if (mid_img == nullptr || bottom_img == nullptr || top_img == nullptr
271  || top_grv == nullptr || bottom_grv == nullptr || mid_grv == nullptr) {
272  std::cerr << "Failure to load scrollbar image.\n";
273  return;
274  }
275 
276  SDL_Rect grip = grip_area();
277  int mid_height = grip.h - top_img->h - bottom_img->h;
278  if (mid_height <= 0) {
279  // For now, minimum size of the middle piece is 1.
280  // This should never really be encountered, and if it is,
281  // it's a symptom of a larger problem, I think.
282  mid_height = 1;
283  }
284 
285  if(mid_scaled_.null() || mid_scaled_->h != mid_height) {
286  mid_scaled_.assign(scale_surface(mid_img, mid_img->w, mid_height));
287  }
288 
289  SDL_Rect groove = groove_area();
290  int groove_height = groove.h - top_grv->h - bottom_grv->h;
291  if (groove_height <= 0) {
292  groove_height = 1;
293  }
294 
295  if (groove_scaled_.null() || groove_scaled_->h != groove_height) {
296  groove_scaled_.assign(scale_surface(mid_grv, mid_grv->w, groove_height));
297  }
298 
299  if (mid_scaled_.null() || groove_scaled_.null()) {
300  std::cerr << "Failure during scrollbar image scale.\n";
301  return;
302  }
303 
304  if (grip.h > groove.h) {
305  std::cerr << "abort draw scrollbar: grip too large\n";
306  return;
307  }
308 
309  // Draw scrollbar "groove"
310  video().blit_surface(groove.x, groove.y, top_grv);
311  video().blit_surface(groove.x, groove.y + top_grv->h, groove_scaled_);
312  video().blit_surface(groove.x, groove.y + top_grv->h + groove_height, bottom_grv);
313 
314  // Draw scrollbar "grip"
315  video().blit_surface(grip.x, grip.y, top_img);
316  video().blit_surface(grip.x, grip.y + top_img->h, mid_scaled_);
317  video().blit_surface(grip.x, grip.y + top_img->h + mid_height, bottom_img);
318 
319  update_rect(groove);
320 }
321 
322 void scrollbar::handle_event(const SDL_Event& event)
323 {
325 
326  if (mouse_locked() || hidden())
327  return;
328 
329  STATE new_state = state_;
330  SDL_Rect const &grip = grip_area();
331  SDL_Rect const &groove = groove_area();
332 
333 
334  switch (event.type) {
335  case SDL_MOUSEBUTTONUP:
336  {
337  SDL_MouseButtonEvent const &e = event.button;
338  bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
339  new_state = on_grip ? ACTIVE : NORMAL;
340  break;
341  }
342  case SDL_MOUSEBUTTONDOWN:
343  {
344  SDL_MouseButtonEvent const &e = event.button;
345  bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
346  bool on_groove = sdl::point_in_rect(e.x, e.y, groove);
347  if (on_grip && e.button == SDL_BUTTON_LEFT) {
348  mousey_on_grip_ = e.y - grip.y;
349  new_state = DRAGGED;
350  } else if (on_groove && e.button == SDL_BUTTON_LEFT && groove.h != grip.h) {
351  if (e.y < grip.y)
352  move_position(-static_cast<int>(grip_height_));
353  else
355  } else if (on_groove && e.button == SDL_BUTTON_MIDDLE) {
356  int y_dep = e.y - grip.y - grip.h/2;
357  int dep = y_dep * int(full_height_ - grip_height_)/ (groove.h - grip.h);
358  move_position(dep);
359  }
360  break;
361  }
362  case SDL_MOUSEMOTION:
363  {
364  SDL_MouseMotionEvent const &e = event.motion;
365  if (state_ == NORMAL || state_ == ACTIVE) {
366  bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
367  new_state = on_grip ? ACTIVE : NORMAL;
368  } else if (state_ == DRAGGED && groove.h != grip.h) {
369  int y_dep = e.y - grip.y - mousey_on_grip_;
370  int dep = y_dep * static_cast<int>(full_height_ - grip_height_) / (groove.h - grip.h);
371  move_position(dep);
372  }
373  break;
374  }
375  case SDL_MOUSEWHEEL:
376  {
377  const SDL_MouseWheelEvent& e = event.wheel;
378  int x, y;
379  SDL_GetMouseState(&x, &y);
380  bool on_groove = sdl::point_in_rect(x, y, groove);
381  if (on_groove && e.y < 0) {
383  } else if (on_groove && e.y > 0) {
385  }
386  break;
387  }
388  default:
389  break;
390  }
391 
392 
393  if (new_state != state_) {
394  set_dirty();
395  mid_scaled_.assign(nullptr);
396  state_ = new_state;
397  }
398 }
399 
400 } // end namespace gui
401 
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
bool null() const
Definition: utils.hpp:104
std::vector< events::sdl_handler * > sdl_handler_vector
Definition: events.hpp:163
int pos
Definition: formula.cpp:800
virtual void handle_event(const SDL_Event &event)
Definition: scrollbar.cpp:322
virtual void update_location(SDL_Rect const &rect)
Definition: widget.cpp:99
Definition: video.hpp:58
virtual void enable(bool new_val=true)
Definition: button.cpp:386
button downarrow_
Definition: scrollbar.hpp:92
surface groove_scaled_
Definition: scrollbar.hpp:90
int minimum_grip_height_
Definition: scrollbar.hpp:97
unsigned int full_height_
Definition: scrollbar.hpp:99
CVideo & video() const
Definition: widget.hpp:83
General purpose widgets.
bool is_valid_height(int height) const
Return true if the scrollbar has a valid size.
Definition: scrollbar.cpp:179
void set_width(int w)
Definition: widget.cpp:119
virtual void process_event()
Definition: scrollbar.cpp:200
#define h
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
SDL_Rect groove_area() const
Definition: scrollbar.cpp:209
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Definition: video.cpp:290
button uparrow_
Definition: scrollbar.hpp:92
-file util.hpp
void scroll_down()
Scrolls down one step.
Definition: scrollbar.cpp:190
bool hidden() const
Definition: widget.cpp:198
SDL_Rect grip_area() const
Definition: scrollbar.cpp:223
void set_dirty(bool dirty=true)
Definition: widget.cpp:217
virtual void hide(bool value=true)
Definition: widget.cpp:162
GLsizei const GLfloat * value
Definition: glew.h:1817
virtual void hide(bool value=true)
Definition: scrollbar.cpp:100
bool pressed()
Definition: button.cpp:770
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
void set_position(unsigned pos)
Manually update the scrollbar.
Definition: scrollbar.cpp:117
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:47
unsigned int grip_height_
Definition: scrollbar.hpp:99
virtual void update_location(SDL_Rect const &rect)
Definition: scrollbar.cpp:86
void adjust_position(unsigned pos)
Ensure the viewport contains the position.
Definition: scrollbar.cpp:129
virtual void draw_contents()
Definition: scrollbar.cpp:235
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
virtual sdl_handler_vector handler_members()
Definition: scrollbar.cpp:78
void scroll_up()
Scrolls up one step.
Definition: scrollbar.cpp:195
GLint GLint GLint GLint GLint GLint GLsizei GLsizei height
Definition: glew.h:1220
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
unsigned get_max_position() const
Definition: scrollbar.cpp:112
Contains the SDL_Rect helper code.
void set_shown_size(unsigned h)
Set the relative size of the grip.
Definition: scrollbar.cpp:146
cl_event event
Definition: glew.h:3070
surface mid_scaled_
Definition: scrollbar.hpp:90
GLint GLvoid * img
Definition: glew.h:1353
bool mouse_locked() const
Definition: widget.cpp:72
void assign(const surface &o)
Definition: utils.hpp:83
virtual void set_location(SDL_Rect const &rect)
Definition: widget.cpp:85
scrollbar(CVideo &video)
Create a scrollbar.
Definition: scrollbar.cpp:50
void set_full_size(unsigned h)
Set the relative size of the scrollbar.
Definition: scrollbar.cpp:160
void set_scroll_rate(unsigned r)
Set scroll rate.
Definition: scrollbar.cpp:174
#define e
virtual void handle_event(SDL_Event const &)
Definition: widget.cpp:345
unsigned int grip_position_
Definition: scrollbar.hpp:99
SDL_Rect const & location() const
Definition: widget.cpp:144
void move_position(int dep)
Move the scrollbar.
Definition: scrollbar.cpp:137
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
GLsizei const GLcharARB ** string
Definition: glew.h:4503
int height() const
Definition: widget.cpp:139
unsigned get_position() const
Determine where the scrollbar is.
Definition: scrollbar.cpp:107