Merge branch 'subtree'
[fanfix.git] / src / jexer / THScroller.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer;
30
31 import jexer.bits.CellAttributes;
32 import jexer.bits.GraphicsChars;
33 import jexer.event.TMouseEvent;
34
35 /**
36 * THScroller implements a simple horizontal scroll bar.
37 */
38 public class THScroller extends TWidget {
39
40 // ------------------------------------------------------------------------
41 // Variables --------------------------------------------------------------
42 // ------------------------------------------------------------------------
43
44 /**
45 * Value that corresponds to being on the left edge of the scroll bar.
46 */
47 private int leftValue = 0;
48
49 /**
50 * Value that corresponds to being on the right edge of the scroll bar.
51 */
52 private int rightValue = 100;
53
54 /**
55 * Current value of the scroll.
56 */
57 private int value = 0;
58
59 /**
60 * The increment for clicking on an arrow.
61 */
62 private int smallChange = 1;
63
64 /**
65 * The increment for clicking in the bar between the box and an arrow.
66 */
67 private int bigChange = 20;
68
69 /**
70 * When true, the user is dragging the scroll box.
71 */
72 private boolean inScroll = false;
73
74 // ------------------------------------------------------------------------
75 // Constructors -----------------------------------------------------------
76 // ------------------------------------------------------------------------
77
78 /**
79 * Public constructor.
80 *
81 * @param parent parent widget
82 * @param x column relative to parent
83 * @param y row relative to parent
84 * @param width height of scroll bar
85 */
86 public THScroller(final TWidget parent, final int x, final int y,
87 final int width) {
88
89 // Set parent and window
90 super(parent, x, y, width, 1);
91 }
92
93 // ------------------------------------------------------------------------
94 // Event handlers ---------------------------------------------------------
95 // ------------------------------------------------------------------------
96
97 /**
98 * Handle mouse button releases.
99 *
100 * @param mouse mouse button release event
101 */
102 @Override
103 public void onMouseUp(final TMouseEvent mouse) {
104
105 if (inScroll) {
106 inScroll = false;
107 return;
108 }
109
110 if (rightValue == leftValue) {
111 return;
112 }
113
114 if ((mouse.getX() == 0)
115 && (mouse.getY() == 0)
116 ) {
117 // Clicked on the left arrow
118 decrement();
119 return;
120 }
121
122 if ((mouse.getY() == 0)
123 && (mouse.getX() == getWidth() - 1)
124 ) {
125 // Clicked on the right arrow
126 increment();
127 return;
128 }
129
130 if ((mouse.getY() == 0)
131 && (mouse.getX() > 0)
132 && (mouse.getX() < boxPosition())
133 ) {
134 // Clicked between the left arrow and the box
135 value -= bigChange;
136 if (value < leftValue) {
137 value = leftValue;
138 }
139 return;
140 }
141
142 if ((mouse.getY() == 0)
143 && (mouse.getX() > boxPosition())
144 && (mouse.getX() < getWidth() - 1)
145 ) {
146 // Clicked between the box and the right arrow
147 value += bigChange;
148 if (value > rightValue) {
149 value = rightValue;
150 }
151 return;
152 }
153 }
154
155 /**
156 * Handle mouse movement events.
157 *
158 * @param mouse mouse motion event
159 */
160 @Override
161 public void onMouseMotion(final TMouseEvent mouse) {
162
163 if (rightValue == leftValue) {
164 inScroll = false;
165 return;
166 }
167
168 if ((mouse.isMouse1())
169 && (inScroll)
170 && (mouse.getX() > 0)
171 && (mouse.getX() < getWidth() - 1)
172 ) {
173 // Recompute value based on new box position
174 value = (rightValue - leftValue)
175 * (mouse.getX()) / (getWidth() - 3) + leftValue;
176 if (value > rightValue) {
177 value = rightValue;
178 }
179 if (value < leftValue) {
180 value = leftValue;
181 }
182 return;
183 }
184 inScroll = false;
185 }
186
187 /**
188 * Handle mouse button press events.
189 *
190 * @param mouse mouse button press event
191 */
192 @Override
193 public void onMouseDown(final TMouseEvent mouse) {
194 if (rightValue == leftValue) {
195 inScroll = false;
196 return;
197 }
198
199 if ((mouse.getY() == 0)
200 && (mouse.getX() == boxPosition())
201 ) {
202 inScroll = true;
203 return;
204 }
205
206 }
207
208 // ------------------------------------------------------------------------
209 // TWidget ----------------------------------------------------------------
210 // ------------------------------------------------------------------------
211
212 /**
213 * Draw a horizontal scroll bar.
214 */
215 @Override
216 public void draw() {
217 CellAttributes arrowColor = getTheme().getColor("tscroller.arrows");
218 CellAttributes barColor = getTheme().getColor("tscroller.bar");
219 putCharXY(0, 0, GraphicsChars.CP437[0x11], arrowColor);
220 putCharXY(getWidth() - 1, 0, GraphicsChars.CP437[0x10], arrowColor);
221
222 // Place the box
223 if (rightValue > leftValue) {
224 hLineXY(1, 0, getWidth() - 2, GraphicsChars.CP437[0xB1], barColor);
225 putCharXY(boxPosition(), 0, GraphicsChars.BOX, arrowColor);
226 } else {
227 hLineXY(1, 0, getWidth() - 2, GraphicsChars.HATCH, barColor);
228 }
229
230 }
231
232 // ------------------------------------------------------------------------
233 // THScroller -------------------------------------------------------------
234 // ------------------------------------------------------------------------
235
236 /**
237 * Get the value that corresponds to being on the left edge of the scroll
238 * bar.
239 *
240 * @return the scroll value
241 */
242 public int getLeftValue() {
243 return leftValue;
244 }
245
246 /**
247 * Set the value that corresponds to being on the left edge of the
248 * scroll bar.
249 *
250 * @param leftValue the new scroll value
251 */
252 public void setLeftValue(final int leftValue) {
253 this.leftValue = leftValue;
254 }
255
256 /**
257 * Get the value that corresponds to being on the right edge of the
258 * scroll bar.
259 *
260 * @return the scroll value
261 */
262 public int getRightValue() {
263 return rightValue;
264 }
265
266 /**
267 * Set the value that corresponds to being on the right edge of the
268 * scroll bar.
269 *
270 * @param rightValue the new scroll value
271 */
272 public void setRightValue(final int rightValue) {
273 this.rightValue = rightValue;
274 }
275
276 /**
277 * Get current value of the scroll.
278 *
279 * @return the scroll value
280 */
281 public int getValue() {
282 return value;
283 }
284
285 /**
286 * Set current value of the scroll.
287 *
288 * @param value the new scroll value
289 */
290 public void setValue(final int value) {
291 this.value = value;
292 }
293
294 /**
295 * Get the increment for clicking on an arrow.
296 *
297 * @return the increment value
298 */
299 public int getSmallChange() {
300 return smallChange;
301 }
302
303 /**
304 * Set the increment for clicking on an arrow.
305 *
306 * @param smallChange the new increment value
307 */
308 public void setSmallChange(final int smallChange) {
309 this.smallChange = smallChange;
310 }
311
312 /**
313 * Set the increment for clicking in the bar between the box and an
314 * arrow.
315 *
316 * @return the increment value
317 */
318 public int getBigChange() {
319 return bigChange;
320 }
321
322 /**
323 * Set the increment for clicking in the bar between the box and an
324 * arrow.
325 *
326 * @param bigChange the new increment value
327 */
328 public void setBigChange(final int bigChange) {
329 this.bigChange = bigChange;
330 }
331
332 /**
333 * Compute the position of the scroll box (a.k.a. grip, thumb).
334 *
335 * @return Y position of the box, between 1 and width - 2
336 */
337 private int boxPosition() {
338 return (getWidth() - 3) * (value - leftValue) / (rightValue - leftValue) + 1;
339 }
340
341 /**
342 * Perform a small step change left.
343 */
344 public void decrement() {
345 if (leftValue == rightValue) {
346 return;
347 }
348 value -= smallChange;
349 if (value < leftValue) {
350 value = leftValue;
351 }
352 }
353
354 /**
355 * Perform a small step change right.
356 */
357 public void increment() {
358 if (leftValue == rightValue) {
359 return;
360 }
361 value += smallChange;
362 if (value > rightValue) {
363 value = rightValue;
364 }
365 }
366
367 /**
368 * Perform a big step change left.
369 */
370 public void bigDecrement() {
371 if (leftValue == rightValue) {
372 return;
373 }
374 value -= bigChange;
375 if (value < leftValue) {
376 value = leftValue;
377 }
378 }
379
380 /**
381 * Perform a big step change right.
382 */
383 public void bigIncrement() {
384 if (rightValue == leftValue) {
385 return;
386 }
387 value += bigChange;
388 if (value > rightValue) {
389 value = rightValue;
390 }
391 }
392
393 /**
394 * Go to the left edge of the scroller.
395 */
396 public void toLeft() {
397 value = leftValue;
398 }
399
400 /**
401 * Go to the right edge of the scroller.
402 */
403 public void toRight() {
404 value = rightValue;
405 }
406
407 }