reflowable text box
[fanfix.git] / src / jexer / THScroller.java
1 /**
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
9 *
10 * Copyright (C) 2015 Kevin Lamonte
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31 package jexer;
32
33 import jexer.bits.CellAttributes;
34 import jexer.bits.GraphicsChars;
35 import jexer.event.TMouseEvent;
36
37 /**
38 * THScroller implements a simple horizontal scroll bar.
39 */
40 public final class THScroller extends TWidget {
41
42 /**
43 * Value that corresponds to being on the left edge of the scroll bar.
44 */
45 private int leftValue = 0;
46
47 /**
48 * Get the value that corresponds to being on the left edge of the scroll
49 * bar.
50 *
51 * @return the scroll value
52 */
53 public int getLeftValue() {
54 return leftValue;
55 }
56
57 /**
58 * Set the value that corresponds to being on the left edge of the
59 * scroll bar.
60 *
61 * @param leftValue the new scroll value
62 */
63 public void setLeftValue(final int leftValue) {
64 this.leftValue = leftValue;
65 }
66
67 /**
68 * Value that corresponds to being on the right edge of the scroll bar.
69 */
70 private int rightValue = 100;
71
72 /**
73 * Get the value that corresponds to being on the right edge of the
74 * scroll bar.
75 *
76 * @return the scroll value
77 */
78 public int getRightValue() {
79 return rightValue;
80 }
81
82 /**
83 * Set the value that corresponds to being on the right edge of the
84 * scroll bar.
85 *
86 * @param rightValue the new scroll value
87 */
88 public void setRightValue(final int rightValue) {
89 this.rightValue = rightValue;
90 }
91
92 /**
93 * Current value of the scroll.
94 */
95 private int value = 0;
96
97 /**
98 * Get current value of the scroll.
99 *
100 * @return the scroll value
101 */
102 public int getValue() {
103 return value;
104 }
105
106 /**
107 * Set current value of the scroll.
108 *
109 * @param value the new scroll value
110 */
111 public void setValue(final int value) {
112 this.value = value;
113 }
114
115 /**
116 * The increment for clicking on an arrow.
117 */
118 private int smallChange = 1;
119
120 /**
121 * Set the increment for clicking on an arrow.
122 *
123 * @param smallChange the new increment value
124 */
125 public void setSmallChange(final int smallChange) {
126 this.smallChange = smallChange;
127 }
128
129 /**
130 * The increment for clicking in the bar between the box and an arrow.
131 */
132 private int bigChange = 20;
133
134 /**
135 * Set the increment for clicking in the bar between the box and an
136 * arrow.
137 *
138 * @param bigChange the new increment value
139 */
140 public void setBigChange(final int bigChange) {
141 this.bigChange = bigChange;
142 }
143
144 /**
145 * When true, the user is dragging the scroll box.
146 */
147 private boolean inScroll = false;
148
149 /**
150 * Public constructor.
151 *
152 * @param parent parent widget
153 * @param x column relative to parent
154 * @param y row relative to parent
155 * @param width height of scroll bar
156 */
157 public THScroller(final TWidget parent, final int x, final int y,
158 final int width) {
159
160 // Set parent and window
161 super(parent);
162
163 setX(x);
164 setY(y);
165 setHeight(1);
166 setWidth(width);
167 }
168
169 /**
170 * Compute the position of the scroll box (a.k.a. grip, thumb).
171 *
172 * @return Y position of the box, between 1 and width - 2
173 */
174 private int boxPosition() {
175 return (getWidth() - 3) * (value - leftValue) / (rightValue - leftValue) + 1;
176 }
177
178 /**
179 * Draw a horizontal scroll bar.
180 */
181 @Override
182 public void draw() {
183 CellAttributes arrowColor = getTheme().getColor("tscroller.arrows");
184 CellAttributes barColor = getTheme().getColor("tscroller.bar");
185 getScreen().putCharXY(0, 0, GraphicsChars.CP437[0x11], arrowColor);
186 getScreen().putCharXY(getWidth() - 1, 0, GraphicsChars.CP437[0x10],
187 arrowColor);
188
189 // Place the box
190 if (rightValue > leftValue) {
191 getScreen().hLineXY(1, 0, getWidth() - 2, GraphicsChars.CP437[0xB1],
192 barColor);
193 getScreen().putCharXY(boxPosition(), 0, GraphicsChars.BOX,
194 arrowColor);
195 } else {
196 getScreen().hLineXY(1, 0, getWidth() - 2, GraphicsChars.HATCH,
197 barColor);
198 }
199
200 }
201
202 /**
203 * Perform a small step change left.
204 */
205 public void decrement() {
206 if (leftValue == rightValue) {
207 return;
208 }
209 value -= smallChange;
210 if (value < leftValue) {
211 value = leftValue;
212 }
213 }
214
215 /**
216 * Perform a small step change right.
217 */
218 public void increment() {
219 if (leftValue == rightValue) {
220 return;
221 }
222 value += smallChange;
223 if (value > rightValue) {
224 value = rightValue;
225 }
226 }
227
228 /**
229 * Handle mouse button releases.
230 *
231 * @param mouse mouse button release event
232 */
233 @Override
234 public void onMouseUp(final TMouseEvent mouse) {
235
236 if (inScroll) {
237 inScroll = false;
238 return;
239 }
240
241 if (rightValue == leftValue) {
242 return;
243 }
244
245 if ((mouse.getX() == 0)
246 && (mouse.getY() == 0)
247 ) {
248 // Clicked on the left arrow
249 decrement();
250 return;
251 }
252
253 if ((mouse.getY() == 0)
254 && (mouse.getX() == getWidth() - 1)
255 ) {
256 // Clicked on the right arrow
257 increment();
258 return;
259 }
260
261 if ((mouse.getY() == 0)
262 && (mouse.getX() > 0)
263 && (mouse.getX() < boxPosition())
264 ) {
265 // Clicked between the left arrow and the box
266 value -= bigChange;
267 if (value < leftValue) {
268 value = leftValue;
269 }
270 return;
271 }
272
273 if ((mouse.getY() == 0)
274 && (mouse.getX() > boxPosition())
275 && (mouse.getX() < getWidth() - 1)
276 ) {
277 // Clicked between the box and the right arrow
278 value += bigChange;
279 if (value > rightValue) {
280 value = rightValue;
281 }
282 return;
283 }
284 }
285
286 /**
287 * Handle mouse movement events.
288 *
289 * @param mouse mouse motion event
290 */
291 @Override
292 public void onMouseMotion(final TMouseEvent mouse) {
293
294 if (rightValue == leftValue) {
295 inScroll = false;
296 return;
297 }
298
299 if ((mouse.getMouse1())
300 && (inScroll)
301 && (mouse.getX() > 0)
302 && (mouse.getX() < getWidth() - 1)
303 ) {
304 // Recompute value based on new box position
305 value = (rightValue - leftValue) * (mouse.getX()) / (getWidth() - 3) + leftValue;
306 return;
307 }
308 inScroll = false;
309 }
310
311 /**
312 * Handle mouse button press events.
313 *
314 * @param mouse mouse button press event
315 */
316 @Override
317 public void onMouseDown(final TMouseEvent mouse) {
318 if (rightValue == leftValue) {
319 inScroll = false;
320 return;
321 }
322
323 if ((mouse.getY() == 0)
324 && (mouse.getX() == boxPosition())
325 ) {
326 inScroll = true;
327 return;
328 }
329
330 }
331
332 }