Atrinik Client  4.0
scrollbar.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 
35 static SDL_Color scrollbar_color_bg;
37 static SDL_Color scrollbar_color_fg;
39 static SDL_Color scrollbar_color_highlight;
40 
45 {
46  if (!text_color_parse("000000", &scrollbar_color_bg) ||
47  !text_color_parse("b5a584", &scrollbar_color_fg) ||
49  log_error("Failed to parse scrollbar color");
50  }
51 }
52 
66 static void scrollbar_element_init(scrollbar_element *elem, int x, int y, int w, int h)
67 {
68  elem->x = x;
69  elem->y = y;
70  elem->w = w;
71  elem->h = h;
72 }
73 
75 static void scrollbar_element_render_background(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
76 {
77  (void) elem;
78  (void) horizontal;
79  SDL_FillRect(surface, box, SDL_MapRGB(surface->format, scrollbar_color_bg.r, scrollbar_color_bg.g, scrollbar_color_bg.b));
81 }
82 
84 static void scrollbar_element_render_arrow_up(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
85 {
86  SDL_Color *color = &scrollbar_color_fg;
87 
88  /* If highlighted, use the highlight color. */
89  if (elem->highlight) {
91  }
92 
93  border_create_sdl_color(surface, box, 1, color);
94 
95  /* Create the arrow. */
96  if (horizontal) {
97  lineRGBA(surface, box->x + 2, box->y + box->h / 2, box->x + box->w - 3, box->y + box->h / 2, color->r, color->g, color->b, 255);
98  lineRGBA(surface, box->x + 2, box->y + box->h / 2, box->x + box->w / 2, box->y + 2, color->r, color->g, color->b, 255);
99  lineRGBA(surface, box->x + 2, box->y + box->h / 2, box->x + box->w / 2, box->y + box->h - 2 - 1, color->r, color->g, color->b, 255);
100  } else {
101  lineRGBA(surface, box->x + box->w / 2, box->y + 2, box->x + box->w / 2, box->y + box->h - 3, color->r, color->g, color->b, 255);
102  lineRGBA(surface, box->x + box->w / 2, box->y + 2, box->x + 2, box->y + box->h / 2, color->r, color->g, color->b, 255);
103  lineRGBA(surface, box->x + box->w / 2, box->y + 2, box->x + box->w - 2 - 1, box->y + box->h / 2, color->r, color->g, color->b, 255);
104  }
105 }
106 
108 static void scrollbar_element_render_arrow_down(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
109 {
110  SDL_Color *color = &scrollbar_color_fg;
111 
112  /* If highlighted, use the highlight color. */
113  if (elem->highlight) {
114  color = &scrollbar_color_highlight;
115  }
116 
117  border_create_sdl_color(surface, box, 1, color);
118 
119  /* Create the arrow. */
120  if (horizontal) {
121  lineRGBA(surface, box->x + box->w - 3, box->y + box->h / 2, box->x + 2, box->y + box->h / 2, color->r, color->g, color->b, 255);
122  lineRGBA(surface, box->x + box->w - 3, box->y + box->h / 2, box->x + box->w / 2, box->y + 2, color->r, color->g, color->b, 255);
123  lineRGBA(surface, box->x + box->w - 3, box->y + box->h / 2, box->x + box->w / 2, box->y + box->h - 3, color->r, color->g, color->b, 255);
124  } else {
125  lineRGBA(surface, box->x + box->w / 2, box->y + box->h - 3, box->x + box->w / 2, box->y + 2, color->r, color->g, color->b, 255);
126  lineRGBA(surface, box->x + box->w / 2, box->y + box->h - 3, box->x + 2, box->y + box->h / 2, color->r, color->g, color->b, 255);
127  lineRGBA(surface, box->x + box->w / 2, box->y + box->h - 3, box->x + box->w - 2 - 1, box->y + box->h / 2, color->r, color->g, color->b, 255);
128  }
129 }
130 
132 static void scrollbar_element_render_slider(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
133 {
134  (void) horizontal;
135 
136  SDL_FillRect(surface, box, SDL_MapRGB(surface->format, scrollbar_color_fg.r, scrollbar_color_fg.g, scrollbar_color_fg.b));
137 
138  /* If highlighted, create highlighted border around the edges of the
139  * slider. */
140  if (elem->highlight) {
142  }
143 }
144 
159 {
160  SDL_Rect box;
161 
162  box.x = scrollbar->x + elem->x;
163  box.y = scrollbar->y + elem->y;
164  box.w = elem->w;
165  box.h = elem->h;
166 
167  if (mx >= box.x && mx < box.x + box.w && my >= box.y && my < box.y + box.h) {
168  elem->highlight = 1;
169  } else {
170  elem->highlight = 0;
171  }
172 
173  return elem->highlight;
174 }
175 
185 static void scrollbar_element_render(scrollbar_struct *scrollbar, scrollbar_element *elem, SDL_Surface *surface)
186 {
187  SDL_Rect box;
188 
189  box.x = scrollbar->x + elem->x;
190  box.y = scrollbar->y + elem->y;
191  box.w = elem->w;
192  box.h = elem->h;
193 
194  /* Make sure the element should still be highlighted. */
195  if (elem->highlight) {
196  int mx, my;
197 
198  SDL_GetMouseState(&mx, &my);
199 
200  mx -= scrollbar->px;
201  my -= scrollbar->py;
202 
203  scrollbar_element_highlight_check(scrollbar, elem, mx, my);
204  }
205 
206  elem->render_func(surface, &box, elem, scrollbar->background.w > scrollbar->background.h);
207 }
208 
219 {
220  /* Dragging the slider, do not allow clicking anything. */
221  if (scrollbar->dragging) {
222  return 0;
223  }
224 
225  if (scrollbar->arrow_up.highlight) {
226  /* Mouse over the up arrow. */
227  if (!test) {
228  scrollbar_scroll_adjust(scrollbar, -scrollbar->arrow_adjust);
229  }
230 
231  return 1;
232  } else if (scrollbar->arrow_down.highlight) {
233  /* Mouse over the down arrow. */
234  if (!test) {
235  scrollbar_scroll_adjust(scrollbar, scrollbar->arrow_adjust);
236  }
237 
238  return 1;
239  } else if (scrollbar->background.highlight && scrollbar->scroll_direction != SCROLL_DIRECTION_NONE) {
240  /* Mouse over the background and there's a known scroll direction. */
241 
242  if (scrollbar->scroll_direction == SCROLL_DIRECTION_UP) {
243  if (!test) {
244  scrollbar_scroll_adjust(scrollbar, -scrollbar->max_lines);
245  }
246 
247  return 1;
248  } else if (scrollbar->scroll_direction == SCROLL_DIRECTION_DOWN) {
249  if (!test) {
250  scrollbar_scroll_adjust(scrollbar, scrollbar->max_lines);
251  }
252 
253  return 1;
254  }
255  }
256 
257  return 0;
258 }
259 
268 {
269  if (scrollbar_click_scroll(scrollbar, 1) && SDL_GetMouseState(NULL, NULL) == SDL_BUTTON_LEFT) {
270  return 1;
271  }
272 
273  return 0;
274 }
275 
284 {
285  if (scrollbar->background.w > scrollbar->background.h) {
286  return scrollbar->background.h + 1;
287  } else {
288  return 2;
289  }
290 }
291 
300 {
301  if (scrollbar->background.w > scrollbar->background.h) {
302  return 2;
303  } else {
304  return scrollbar->background.w + 1;
305  }
306 }
307 
316 {
317  if (scrollbar->background.w > scrollbar->background.h) {
318  return scrollbar->background.w - (scrollbar->background.h + 1) * 2;
319  } else {
320  return scrollbar->background.w - 2 * 2;
321  }
322 }
323 
332 {
333  if (scrollbar->background.w > scrollbar->background.h) {
334  return scrollbar->background.h - 2 * 2;
335  } else {
336  return scrollbar->background.h - (scrollbar->background.w + 1) * 2;
337  }
338 }
339 
350 void scrollbar_create(scrollbar_struct *scrollbar, int w, int h, uint32_t *scroll_offset, uint32_t *num_lines, uint32_t max_lines)
351 {
352  memset(scrollbar, 0, sizeof(*scrollbar));
353 
354  scrollbar->scroll_offset = scroll_offset;
355  scrollbar->num_lines = num_lines;
356  scrollbar->max_lines = max_lines;
357  scrollbar->arrow_adjust = 1;
358 
359  /* Initialize the elements. */
360  scrollbar_element_init(&scrollbar->background, 0, 0, w, h);
362 
363  if (w > h) {
364  scrollbar_element_init(&scrollbar->arrow_up, 0, 0, h, h);
365  scrollbar_element_init(&scrollbar->arrow_down, w - h, 0, h, h);
366  } else {
367  scrollbar_element_init(&scrollbar->arrow_up, 0, 0, w, w);
368  scrollbar_element_init(&scrollbar->arrow_down, 0, h - w, w, w);
369  }
370 
375 }
376 
383 {
384  memset(info, 0, sizeof(*info));
385 }
386 
398 {
399  /* Make sure the scroll offset is in a valid range. */
400  if (scroll < SCROLL_TOP(scrollbar)) {
401  scroll = SCROLL_TOP(scrollbar);
402  } else if ((uint32_t) scroll > SCROLL_BOTTOM(scrollbar)) {
403  scroll = (int) SCROLL_BOTTOM(scrollbar);
404  }
405 
406  /* If the scroll offset changed, update it and set the redraw flag,
407  * if possible. */
408  if ((uint32_t) scroll != *scrollbar->scroll_offset) {
409  *scrollbar->scroll_offset = scroll;
410 
411  if (scrollbar->redraw) {
412  *scrollbar->redraw = 1;
413  }
414  }
415 }
416 
428 {
429  scrollbar_scroll_to(scrollbar, *scrollbar->scroll_offset + adjust);
430 }
431 
443 void scrollbar_show(scrollbar_struct *scrollbar, SDL_Surface *surface, int x, int y)
444 {
445  int horizontal;
446 
447  scrollbar->x = x;
448  scrollbar->y = y;
449 
450  horizontal = scrollbar->background.w > scrollbar->background.h;
451 
452  /* If the scroll direction is set but the left mouse button is no
453  * longer being held, clear the scroll direction. */
454  if (scrollbar->scroll_direction != SCROLL_DIRECTION_NONE && SDL_GetMouseState(NULL, NULL) != SDL_BUTTON_LEFT) {
456  }
457 
458  /* Handle click repeating. */
459  if (SDL_GetMouseState(NULL, NULL) == SDL_BUTTON_LEFT && SDL_GetTicks() - scrollbar->click_ticks > scrollbar->click_repeat_ticks) {
460  if (scrollbar_click_scroll(scrollbar, 0)) {
461  scrollbar->click_ticks = SDL_GetTicks();
462  scrollbar->click_repeat_ticks = 35;
463  }
464  }
465 
466  /* Calculate slider height and y offset if necessary. */
467  if (*scrollbar->num_lines > scrollbar->max_lines) {
468  int scroll;
469 
470  scroll = scrollbar->max_lines + *scrollbar->scroll_offset;
471 
472  if (horizontal) {
473  scrollbar->slider.w = scrollbar_slider_width(scrollbar) * scrollbar->max_lines / *scrollbar->num_lines;
474  scrollbar->slider.x = ((scroll - scrollbar->max_lines) * scrollbar_slider_width(scrollbar)) / *scrollbar->num_lines;
475 
476  if (scrollbar->slider.w < 1) {
477  scrollbar->slider.w = 1;
478  }
479 
480  if (scroll - scrollbar->max_lines > 0 && scrollbar->slider.x + scrollbar->slider.w < scrollbar_slider_width(scrollbar)) {
481  scrollbar->slider.x++;
482  }
483  } else {
484  scrollbar->slider.h = scrollbar_slider_height(scrollbar) * scrollbar->max_lines / *scrollbar->num_lines;
485  scrollbar->slider.y = ((scroll - scrollbar->max_lines) * scrollbar_slider_height(scrollbar)) / *scrollbar->num_lines;
486 
487  if (scrollbar->slider.h < 1) {
488  scrollbar->slider.h = 1;
489  }
490 
491  if (scroll - scrollbar->max_lines > 0 && scrollbar->slider.y + scrollbar->slider.h < scrollbar_slider_height(scrollbar)) {
492  scrollbar->slider.y++;
493  }
494  }
495  } else {
496  /* Not necessary to calculate, so full slider height. */
497 
498  if (horizontal) {
499  scrollbar->slider.w = scrollbar_slider_width(scrollbar);
500  scrollbar->slider.x = 0;
501  } else {
502  scrollbar->slider.h = scrollbar_slider_height(scrollbar);
503  scrollbar->slider.y = 0;
504  }
505  }
506 
507  if (horizontal) {
508  scrollbar->slider.x += scrollbar_slider_startx(scrollbar);
509  } else {
510  scrollbar->slider.y += scrollbar_slider_starty(scrollbar);
511  }
512 
513  /* Render the elements. */
514  scrollbar_element_render(scrollbar, &scrollbar->background, surface);
515  scrollbar_element_render(scrollbar, &scrollbar->arrow_up, surface);
516  scrollbar_element_render(scrollbar, &scrollbar->arrow_down, surface);
517  scrollbar_element_render(scrollbar, &scrollbar->slider, surface);
518 }
519 
530 {
531  if (event->type == SDL_MOUSEMOTION) {
532  /* If dragging but the left mouse button is no longer being held,
533  * quit dragging the slider. */
534  if (scrollbar->dragging && !(SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT)) {
535  scrollbar->dragging = 0;
536  }
537 
538  /* Try dragging the scrollbar. */
539  if (scrollbar->dragging) {
540  int slider_pos;
541  uint32_t scroll_offset;
542 
543  if (scrollbar->background.w > scrollbar->background.h) {
544  slider_pos = event->motion.x - scrollbar->px - scrollbar->old_slider_pos;
545 
546  if (slider_pos > scrollbar_slider_width(scrollbar) - scrollbar->slider.w) {
547  slider_pos = scrollbar_slider_width(scrollbar) - scrollbar->slider.w;
548  } else if (slider_pos < 0) {
549  slider_pos = 0;
550  }
551 
552  scroll_offset = MIN(*scrollbar->num_lines - scrollbar->max_lines, MAX(0, slider_pos) * *scrollbar->num_lines / scrollbar_slider_width(scrollbar));
553  } else {
554  slider_pos = event->motion.y - scrollbar->py - scrollbar->old_slider_pos;
555 
556  if (slider_pos > scrollbar_slider_height(scrollbar) - scrollbar->slider.h) {
557  slider_pos = scrollbar_slider_height(scrollbar) - scrollbar->slider.h;
558  } else if (slider_pos < 0) {
559  slider_pos = 0;
560  }
561 
562  scroll_offset = MIN(*scrollbar->num_lines - scrollbar->max_lines, MAX(0, slider_pos) * *scrollbar->num_lines / scrollbar_slider_height(scrollbar));
563  }
564 
565  /* Redraw if the scroll offset changed. */
566  if (scroll_offset != *scrollbar->scroll_offset) {
567  *scrollbar->scroll_offset = scroll_offset;
568 
569  if (scrollbar->redraw) {
570  *scrollbar->redraw = 1;
571  }
572  }
573 
574  return 1;
575  } else if (scrollbar_element_highlight_check(scrollbar, &scrollbar->arrow_up, event->motion.x - scrollbar->px, event->motion.y - scrollbar->py)) {
576  return 1;
577  } else if (scrollbar_element_highlight_check(scrollbar, &scrollbar->arrow_down, event->motion.x - scrollbar->px, event->motion.y - scrollbar->py)) {
578  return 1;
579  } else if (scrollbar_element_highlight_check(scrollbar, &scrollbar->slider, event->motion.x - scrollbar->px, event->motion.y - scrollbar->py)) {
580  return 1;
581  } else if (scrollbar_element_highlight_check(scrollbar, &scrollbar->background, event->motion.x - scrollbar->px, event->motion.y - scrollbar->py)) {
582  return 1;
583  }
584  } else if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT) {
585  /* Start dragging the slider. */
586  if (scrollbar->slider.highlight) {
587  if (scrollbar->background.w > scrollbar->background.h) {
588  scrollbar->old_slider_pos = event->motion.x - scrollbar->px - scrollbar->slider.x + scrollbar_slider_startx(scrollbar);
589  } else {
590  scrollbar->old_slider_pos = event->motion.y - scrollbar->py - scrollbar->slider.y + scrollbar_slider_starty(scrollbar);
591  }
592 
593  scrollbar->dragging = 1;
594  return 1;
595  } else if (scrollbar->background.highlight) {
596  /* Set scroll direction if clicked on the background. */
597 
598  if (scrollbar->background.w > scrollbar->background.h) {
599  if (event->motion.x - scrollbar->px < scrollbar->x + scrollbar->slider.x) {
601  } else if (event->motion.x - scrollbar->px > scrollbar->x + scrollbar->slider.x + scrollbar->slider.w) {
603  }
604  } else {
605  if (event->motion.y - scrollbar->py < scrollbar->y + scrollbar->slider.y) {
607  } else if (event->motion.y - scrollbar->py > scrollbar->y + scrollbar->slider.y + scrollbar->slider.h) {
609  }
610  }
611  }
612 
613  if (scrollbar_click_scroll(scrollbar, 0)) {
614  scrollbar->click_ticks = SDL_GetTicks();
615  scrollbar->click_repeat_ticks = 400;
616  return 1;
617  }
618  }
619 
620  return 0;
621 }
622 
631 {
632  return scrollbar->background.w;
633 }
scrollbar_element slider
Definition: scrollbar.h:126
void scrollbar_scroll_to(scrollbar_struct *scrollbar, int scroll)
Definition: scrollbar.c:397
static SDL_Color scrollbar_color_bg
Definition: scrollbar.c:35
void scrollbar_init()
Definition: scrollbar.c:44
int text_color_parse(const char *color_notation, SDL_Color *color)
Definition: text.c:603
static scrollbar_struct scrollbar
Definition: book.c:50
uint8_t highlight
Definition: scrollbar.h:50
static int scrollbar_element_highlight_check(scrollbar_struct *scrollbar, scrollbar_element *elem, int mx, int my)
Definition: scrollbar.c:158
static void scrollbar_element_init(scrollbar_element *elem, int x, int y, int w, int h)
Definition: scrollbar.c:66
uint8_t dragging
Definition: scrollbar.h:105
static SDL_Color scrollbar_color_highlight
Definition: scrollbar.c:39
static int scrollbar_slider_starty(scrollbar_struct *scrollbar)
Definition: scrollbar.c:299
static int scrollbar_slider_width(scrollbar_struct *scrollbar)
Definition: scrollbar.c:315
static void scrollbar_element_render_arrow_down(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
Definition: scrollbar.c:108
int scrollbar_need_redraw(scrollbar_struct *scrollbar)
Definition: scrollbar.c:267
uint32_t * num_lines
Definition: scrollbar.h:74
#define SCROLL_BOTTOM(_scrollbar)
Definition: scrollbar.h:157
static int scrollbar_click_scroll(scrollbar_struct *scrollbar, int test)
Definition: scrollbar.c:218
static void scrollbar_element_render(scrollbar_struct *scrollbar, scrollbar_element *elem, SDL_Surface *surface)
Definition: scrollbar.c:185
scrollbar_element arrow_up
Definition: scrollbar.h:120
uint32_t max_lines
Definition: scrollbar.h:77
#define SCROLL_DIRECTION_NONE
Definition: scrollbar.h:149
void scrollbar_show(scrollbar_struct *scrollbar, SDL_Surface *surface, int x, int y)
Definition: scrollbar.c:443
scrollbar_element background
Definition: scrollbar.h:117
void scrollbar_info_create(scrollbar_info_struct *info)
Definition: scrollbar.c:382
static void scrollbar_element_render_background(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
Definition: scrollbar.c:75
uint32_t * scroll_offset
Definition: scrollbar.h:71
scrollbar_element arrow_down
Definition: scrollbar.h:123
#define SCROLL_DIRECTION_DOWN
Definition: scrollbar.h:153
static SDL_Color scrollbar_color_fg
Definition: scrollbar.c:37
int scrollbar_get_width(scrollbar_struct *scrollbar)
Definition: scrollbar.c:630
static void scrollbar_element_render_slider(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
Definition: scrollbar.c:132
void scrollbar_scroll_adjust(scrollbar_struct *scrollbar, int adjust)
Definition: scrollbar.c:427
void scrollbar_create(scrollbar_struct *scrollbar, int w, int h, uint32_t *scroll_offset, uint32_t *num_lines, uint32_t max_lines)
Definition: scrollbar.c:350
uint32_t click_ticks
Definition: scrollbar.h:108
static void scrollbar_element_render_arrow_up(SDL_Surface *surface, SDL_Rect *box, scrollbar_element *elem, uint8_t horizontal)
Definition: scrollbar.c:84
uint8_t * redraw
Definition: scrollbar.h:87
#define SCROLL_DIRECTION_UP
Definition: scrollbar.h:151
int scrollbar_event(scrollbar_struct *scrollbar, SDL_Event *event)
Definition: scrollbar.c:529
uint32_t click_repeat_ticks
Definition: scrollbar.h:111
void(* render_func)(SDL_Surface *surface, SDL_Rect *box, struct scrollbar_element *element, uint8_t horizontal)
Definition: scrollbar.h:63
static int scrollbar_slider_startx(scrollbar_struct *scrollbar)
Definition: scrollbar.c:283
void border_create_sdl_color(SDL_Surface *surface, SDL_Rect *coords, int thickness, SDL_Color *color)
Definition: sprite.c:1306
static int scrollbar_slider_height(scrollbar_struct *scrollbar)
Definition: scrollbar.c:331
#define SCROLL_TOP(_scrollbar)
Definition: scrollbar.h:159