1 #include "scrollbar.h"
2 
3 #include "core/calc.h"
4 #include "core/image.h"
5 #include "core/image_group.h"
6 #include "graphics/image.h"
7 #include "graphics/image_button.h"
8 
9 #define SCROLL_BUTTON_HEIGHT 26
10 #define SCROLL_BUTTON_WIDTH 39
11 #define SCROLL_DOT_SIZE 25
12 #define TOTAL_BUTTON_HEIGHT (2 * SCROLL_BUTTON_HEIGHT + SCROLL_DOT_SIZE)
13 
14 static void text_scroll(int is_down, int num_lines);
15 
16 static image_button image_button_scroll_up = {
17     0, 0, SCROLL_BUTTON_WIDTH, SCROLL_BUTTON_HEIGHT, IB_SCROLL,
18     GROUP_OK_CANCEL_SCROLL_BUTTONS, 8, text_scroll, button_none, 0, 1, 1
19 };
20 static image_button image_button_scroll_down = {
21     0, 0, SCROLL_BUTTON_WIDTH, SCROLL_BUTTON_HEIGHT, IB_SCROLL,
22     GROUP_OK_CANCEL_SCROLL_BUTTONS, 12, text_scroll, button_none, 1, 1, 1
23 };
24 
25 static scrollbar_type *current;
26 
scrollbar_init(scrollbar_type * scrollbar,int scroll_position,int max_scroll_position)27 void scrollbar_init(scrollbar_type *scrollbar, int scroll_position, int max_scroll_position)
28 {
29     if (max_scroll_position < 0) {
30         max_scroll_position = 0;
31     }
32     scrollbar->scroll_position = calc_bound(scroll_position, 0, max_scroll_position);
33     scrollbar->max_scroll_position = max_scroll_position;
34     scrollbar->is_dragging_scroll = 0;
35 }
36 
scrollbar_reset(scrollbar_type * scrollbar,int scroll_position)37 void scrollbar_reset(scrollbar_type *scrollbar, int scroll_position)
38 {
39     scrollbar->scroll_position = scroll_position;
40     scrollbar->is_dragging_scroll = 0;
41 }
42 
scrollbar_update_max(scrollbar_type * scrollbar,int max_scroll_position)43 void scrollbar_update_max(scrollbar_type *scrollbar, int max_scroll_position)
44 {
45     if (max_scroll_position < 0) {
46         max_scroll_position = 0;
47     }
48     scrollbar->max_scroll_position = max_scroll_position;
49     if (scrollbar->scroll_position > max_scroll_position) {
50         scrollbar->scroll_position = max_scroll_position;
51     }
52 }
53 
scrollbar_draw(scrollbar_type * scrollbar)54 void scrollbar_draw(scrollbar_type *scrollbar)
55 {
56     if (scrollbar->max_scroll_position > 0 || scrollbar->always_visible) {
57         image_buttons_draw(scrollbar->x, scrollbar->y, &image_button_scroll_up, 1);
58         image_buttons_draw(scrollbar->x, scrollbar->y + scrollbar->height - SCROLL_BUTTON_HEIGHT,
59             &image_button_scroll_down, 1);
60 
61         int pct;
62         if (scrollbar->scroll_position <= 0) {
63             pct = 0;
64         } else if (scrollbar->scroll_position >= scrollbar->max_scroll_position) {
65             pct = 100;
66         } else {
67             pct = calc_percentage(scrollbar->scroll_position, scrollbar->max_scroll_position);
68         }
69         int offset = calc_adjust_with_percentage(
70             scrollbar->height - TOTAL_BUTTON_HEIGHT - 2 * scrollbar->dot_padding, pct);
71         if (scrollbar->is_dragging_scroll) {
72             offset = scrollbar->scroll_position_drag;
73         }
74         image_draw(image_group(GROUP_PANEL_BUTTON) + 39,
75             scrollbar->x + (SCROLL_BUTTON_WIDTH - SCROLL_DOT_SIZE) / 2,
76             scrollbar->y + offset + SCROLL_BUTTON_HEIGHT + scrollbar->dot_padding);
77     }
78 }
79 
handle_scrollbar_dot(scrollbar_type * scrollbar,const mouse * m)80 static int handle_scrollbar_dot(scrollbar_type *scrollbar, const mouse *m)
81 {
82     if (scrollbar->max_scroll_position <= 0 || !m->left.is_down) {
83         return 0;
84     }
85     int track_height = scrollbar->height - TOTAL_BUTTON_HEIGHT - 2 * scrollbar->dot_padding;
86     if (m->x < scrollbar->x || m->x >= scrollbar->x + SCROLL_BUTTON_WIDTH) {
87         return 0;
88     }
89     if (m->y < scrollbar->y + SCROLL_BUTTON_HEIGHT + scrollbar->dot_padding ||
90         m->y > scrollbar->y + scrollbar->height - SCROLL_BUTTON_HEIGHT - scrollbar->dot_padding) {
91         return 0;
92     }
93     int dot_offset = m->y - scrollbar->y - SCROLL_DOT_SIZE/2 - SCROLL_BUTTON_HEIGHT;
94     if (dot_offset < 0) {
95         dot_offset = 0;
96     }
97     if (dot_offset > track_height) {
98         dot_offset = track_height;
99     }
100     int pct_scrolled = calc_percentage(dot_offset, track_height);
101     scrollbar->scroll_position = calc_adjust_with_percentage(
102         scrollbar->max_scroll_position, pct_scrolled);
103     scrollbar->is_dragging_scroll = 1;
104     scrollbar->scroll_position_drag = dot_offset;
105     if (scrollbar->scroll_position_drag < 0) {
106         scrollbar->scroll_position_drag = 0;
107     }
108     if (scrollbar->on_scroll_callback) {
109         scrollbar->on_scroll_callback();
110     }
111     return 1;
112 }
113 
scrollbar_handle_mouse(scrollbar_type * scrollbar,const mouse * m)114 int scrollbar_handle_mouse(scrollbar_type *scrollbar, const mouse *m)
115 {
116     if (scrollbar->max_scroll_position <= 0) {
117         return 0;
118     }
119     current = scrollbar;
120     if (m->scrolled == SCROLL_DOWN) {
121         text_scroll(1, 3);
122     } else if (m->scrolled == SCROLL_UP) {
123         text_scroll(0, 3);
124     }
125 
126     if (image_buttons_handle_mouse(m,
127         scrollbar->x, scrollbar->y, &image_button_scroll_up, 1, 0)) {
128         return 1;
129     }
130     if (image_buttons_handle_mouse(m,
131         scrollbar->x, scrollbar->y + scrollbar->height - SCROLL_BUTTON_HEIGHT,
132         &image_button_scroll_down, 1, 0)) {
133         return 1;
134     }
135     return handle_scrollbar_dot(scrollbar, m);
136 }
137 
text_scroll(int is_down,int num_lines)138 static void text_scroll(int is_down, int num_lines)
139 {
140     scrollbar_type *scrollbar = current;
141     if (is_down) {
142         scrollbar->scroll_position += num_lines;
143         if (scrollbar->scroll_position > scrollbar->max_scroll_position) {
144             scrollbar->scroll_position = scrollbar->max_scroll_position;
145         }
146     } else {
147         scrollbar->scroll_position -= num_lines;
148         if (scrollbar->scroll_position < 0) {
149             scrollbar->scroll_position = 0;
150         }
151     }
152     scrollbar->is_dragging_scroll = 0;
153     if (scrollbar->on_scroll_callback) {
154         scrollbar->on_scroll_callback();
155     }
156 }
157