Merge branch 'subtree'
[fanfix.git] / src / jexer / TScrollableWindow.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.event.TMouseEvent;
32 import jexer.event.TResizeEvent;
33
34 /**
35 * TScrollableWindow is a convenience superclass for windows that have
36 * scrollbars.
37 */
38 public class TScrollableWindow extends TWindow implements Scrollable {
39
40 // ------------------------------------------------------------------------
41 // Variables --------------------------------------------------------------
42 // ------------------------------------------------------------------------
43
44 /**
45 * The horizontal scrollbar.
46 */
47 protected THScroller hScroller = null;
48
49 /**
50 * The vertical scrollbar.
51 */
52 protected TVScroller vScroller = null;
53
54 // ------------------------------------------------------------------------
55 // Constructors -----------------------------------------------------------
56 // ------------------------------------------------------------------------
57
58 /**
59 * Public constructor. Window will be located at (0, 0).
60 *
61 * @param application TApplication that manages this window
62 * @param title window title, will be centered along the top border
63 * @param width width of window
64 * @param height height of window
65 */
66 public TScrollableWindow(final TApplication application, final String title,
67 final int width, final int height) {
68
69 super(application, title, width, height);
70 }
71
72 /**
73 * Public constructor. Window will be located at (0, 0).
74 *
75 * @param application TApplication that manages this window
76 * @param title window title, will be centered along the top border
77 * @param width width of window
78 * @param height height of window
79 * @param flags bitmask of RESIZABLE, CENTERED, or MODAL
80 */
81 public TScrollableWindow(final TApplication application, final String title,
82 final int width, final int height, final int flags) {
83
84 super(application, title, width, height, flags);
85 }
86
87 /**
88 * Public constructor.
89 *
90 * @param application TApplication that manages this window
91 * @param title window title, will be centered along the top border
92 * @param x column relative to parent
93 * @param y row relative to parent
94 * @param width width of window
95 * @param height height of window
96 */
97 public TScrollableWindow(final TApplication application, final String title,
98 final int x, final int y, final int width, final int height) {
99
100 super(application, title, x, y, width, height);
101 }
102
103 /**
104 * Public constructor.
105 *
106 * @param application TApplication that manages this window
107 * @param title window title, will be centered along the top border
108 * @param x column relative to parent
109 * @param y row relative to parent
110 * @param width width of window
111 * @param height height of window
112 * @param flags mask of RESIZABLE, CENTERED, or MODAL
113 */
114 public TScrollableWindow(final TApplication application, final String title,
115 final int x, final int y, final int width, final int height,
116 final int flags) {
117
118 super(application, title, x, y, width, height, flags);
119 }
120
121 // ------------------------------------------------------------------------
122 // TWindow ----------------------------------------------------------------
123 // ------------------------------------------------------------------------
124
125 /**
126 * Handle window/screen resize events.
127 *
128 * @param event resize event
129 */
130 @Override
131 public void onResize(final TResizeEvent event) {
132 if (event.getType() == TResizeEvent.Type.WIDGET) {
133 reflowData();
134 placeScrollbars();
135 return;
136 } else {
137 super.onResize(event);
138 }
139 }
140
141 /**
142 * Maximize window.
143 */
144 @Override
145 public void maximize() {
146 super.maximize();
147 placeScrollbars();
148 }
149
150 /**
151 * Restore (unmaximize) window.
152 */
153 @Override
154 public void restore() {
155 super.restore();
156 placeScrollbars();
157 }
158
159 // ------------------------------------------------------------------------
160 // TScrollableWindow ------------------------------------------------------
161 // ------------------------------------------------------------------------
162
163 /**
164 * Place the scrollbars on the edge of this widget, and adjust bigChange
165 * to match the new size. This is called by onResize().
166 */
167 protected void placeScrollbars() {
168 if (hScroller != null) {
169 hScroller.setX(Math.min(Math.max(0, getWidth() - 17), 17));
170 hScroller.setY(getHeight() - 2);
171 hScroller.setWidth(getWidth() - hScroller.getX() - 3);
172 hScroller.setBigChange(getWidth() - hScroller.getX() - 3);
173 }
174 if (vScroller != null) {
175 vScroller.setX(getWidth() - 2);
176 vScroller.setHeight(getHeight() - 2);
177 vScroller.setBigChange(getHeight() - 2);
178 }
179 }
180
181 /**
182 * Recompute whatever data is displayed by this widget.
183 */
184 public void reflowData() {
185 // Default: nothing to do
186 }
187
188 /**
189 * Get the horizontal scrollbar, or null if this Viewport does not
190 * support horizontal scrolling.
191 *
192 * @return the horizontal scrollbar
193 */
194 public THScroller getHorizontalScroller() {
195 return hScroller;
196 }
197
198 /**
199 * Get the vertical scrollbar, or null if this Viewport does not support
200 * vertical scrolling.
201 *
202 * @return the vertical scrollbar
203 */
204 public TVScroller getVerticalScroller() {
205 return vScroller;
206 }
207
208 /**
209 * Get the value that corresponds to being on the top edge of the
210 * vertical scroll bar.
211 *
212 * @return the scroll value
213 */
214 public int getTopValue() {
215 if (vScroller == null) {
216 return 0;
217 } else {
218 return vScroller.getTopValue();
219 }
220 }
221
222 /**
223 * Set the value that corresponds to being on the top edge of the
224 * vertical scroll bar.
225 *
226 * @param topValue the new scroll value
227 */
228 public void setTopValue(final int topValue) {
229 if (vScroller == null) {
230 return;
231 } else {
232 vScroller.setTopValue(topValue);
233 }
234 }
235
236 /**
237 * Get the value that corresponds to being on the bottom edge of the
238 * vertical scroll bar.
239 *
240 * @return the scroll value
241 */
242 public int getBottomValue() {
243 if (vScroller == null) {
244 return 0;
245 } else {
246 return vScroller.getBottomValue();
247 }
248 }
249
250 /**
251 * Set the value that corresponds to being on the bottom edge of the
252 * vertical scroll bar.
253 *
254 * @param bottomValue the new scroll value
255 */
256 public void setBottomValue(final int bottomValue) {
257 if (vScroller == null) {
258 return;
259 } else {
260 vScroller.setBottomValue(bottomValue);
261 }
262 }
263
264 /**
265 * Get current value of the vertical scroll.
266 *
267 * @return the scroll value
268 */
269 public int getVerticalValue() {
270 if (vScroller == null) {
271 return 0;
272 } else {
273 return vScroller.getValue();
274 }
275 }
276
277 /**
278 * Set current value of the vertical scroll.
279 *
280 * @param value the new scroll value
281 */
282 public void setVerticalValue(final int value) {
283 if (vScroller == null) {
284 return;
285 } else {
286 vScroller.setValue(value);
287 }
288 }
289
290 /**
291 * Get the increment for clicking on an arrow on the vertical scrollbar.
292 *
293 * @return the increment value
294 */
295 public int getVerticalSmallChange() {
296 if (vScroller == null) {
297 return 0;
298 } else {
299 return vScroller.getSmallChange();
300 }
301 }
302
303 /**
304 * Set the increment for clicking on an arrow on the vertical scrollbar.
305 *
306 * @param smallChange the new increment value
307 */
308 public void setVerticalSmallChange(final int smallChange) {
309 if (vScroller == null) {
310 return;
311 } else {
312 vScroller.setSmallChange(smallChange);
313 }
314 }
315
316 /**
317 * Get the increment for clicking in the bar between the box and an
318 * arrow on the vertical scrollbar.
319 *
320 * @return the increment value
321 */
322 public int getVerticalBigChange() {
323 if (vScroller == null) {
324 return 0;
325 } else {
326 return vScroller.getBigChange();
327 }
328 }
329
330 /**
331 * Set the increment for clicking in the bar between the box and an
332 * arrow on the vertical scrollbar.
333 *
334 * @param bigChange the new increment value
335 */
336 public void setVerticalBigChange(final int bigChange) {
337 if (vScroller == null) {
338 return;
339 } else {
340 vScroller.setBigChange(bigChange);
341 }
342 }
343
344 /**
345 * Perform a small step change up.
346 */
347 public void verticalDecrement() {
348 if (vScroller == null) {
349 return;
350 } else {
351 vScroller.decrement();
352 }
353 }
354
355 /**
356 * Perform a small step change down.
357 */
358 public void verticalIncrement() {
359 if (vScroller == null) {
360 return;
361 } else {
362 vScroller.increment();
363 }
364 }
365
366 /**
367 * Perform a big step change up.
368 */
369 public void bigVerticalDecrement() {
370 if (vScroller == null) {
371 return;
372 } else {
373 vScroller.bigDecrement();
374 }
375 }
376
377 /**
378 * Perform a big step change down.
379 */
380 public void bigVerticalIncrement() {
381 if (vScroller == null) {
382 return;
383 } else {
384 vScroller.bigIncrement();
385 }
386 }
387
388 /**
389 * Go to the top edge of the vertical scroller.
390 */
391 public void toTop() {
392 if (vScroller == null) {
393 return;
394 } else {
395 vScroller.toTop();
396 }
397 }
398
399 /**
400 * Go to the bottom edge of the vertical scroller.
401 */
402 public void toBottom() {
403 if (vScroller == null) {
404 return;
405 } else {
406 vScroller.toBottom();
407 }
408 }
409
410 /**
411 * Get the value that corresponds to being on the left edge of the
412 * horizontal scroll bar.
413 *
414 * @return the scroll value
415 */
416 public int getLeftValue() {
417 if (hScroller == null) {
418 return 0;
419 } else {
420 return hScroller.getLeftValue();
421 }
422 }
423
424 /**
425 * Set the value that corresponds to being on the left edge of the
426 * horizontal scroll bar.
427 *
428 * @param leftValue the new scroll value
429 */
430 public void setLeftValue(final int leftValue) {
431 if (hScroller == null) {
432 return;
433 } else {
434 hScroller.setLeftValue(leftValue);
435 }
436 }
437
438 /**
439 * Get the value that corresponds to being on the right edge of the
440 * horizontal scroll bar.
441 *
442 * @return the scroll value
443 */
444 public int getRightValue() {
445 if (hScroller == null) {
446 return 0;
447 } else {
448 return hScroller.getRightValue();
449 }
450 }
451
452 /**
453 * Set the value that corresponds to being on the right edge of the
454 * horizontal scroll bar.
455 *
456 * @param rightValue the new scroll value
457 */
458 public void setRightValue(final int rightValue) {
459 if (hScroller == null) {
460 return;
461 } else {
462 hScroller.setRightValue(rightValue);
463 }
464 }
465
466 /**
467 * Get current value of the horizontal scroll.
468 *
469 * @return the scroll value
470 */
471 public int getHorizontalValue() {
472 if (hScroller == null) {
473 return 0;
474 } else {
475 return hScroller.getValue();
476 }
477 }
478
479 /**
480 * Set current value of the horizontal scroll.
481 *
482 * @param value the new scroll value
483 */
484 public void setHorizontalValue(final int value) {
485 if (hScroller == null) {
486 return;
487 } else {
488 hScroller.setValue(value);
489 }
490 }
491
492 /**
493 * Get the increment for clicking on an arrow on the horizontal
494 * scrollbar.
495 *
496 * @return the increment value
497 */
498 public int getHorizontalSmallChange() {
499 if (hScroller == null) {
500 return 0;
501 } else {
502 return hScroller.getSmallChange();
503 }
504 }
505
506 /**
507 * Set the increment for clicking on an arrow on the horizontal
508 * scrollbar.
509 *
510 * @param smallChange the new increment value
511 */
512 public void setHorizontalSmallChange(final int smallChange) {
513 if (hScroller == null) {
514 return;
515 } else {
516 hScroller.setSmallChange(smallChange);
517 }
518 }
519
520 /**
521 * Get the increment for clicking in the bar between the box and an
522 * arrow on the horizontal scrollbar.
523 *
524 * @return the increment value
525 */
526 public int getHorizontalBigChange() {
527 if (hScroller == null) {
528 return 0;
529 } else {
530 return hScroller.getBigChange();
531 }
532 }
533
534 /**
535 * Set the increment for clicking in the bar between the box and an
536 * arrow on the horizontal scrollbar.
537 *
538 * @param bigChange the new increment value
539 */
540 public void setHorizontalBigChange(final int bigChange) {
541 if (hScroller == null) {
542 return;
543 } else {
544 hScroller.setBigChange(bigChange);
545 }
546 }
547
548 /**
549 * Perform a small step change left.
550 */
551 public void horizontalDecrement() {
552 if (hScroller == null) {
553 return;
554 } else {
555 hScroller.decrement();
556 }
557 }
558
559 /**
560 * Perform a small step change right.
561 */
562 public void horizontalIncrement() {
563 if (hScroller == null) {
564 return;
565 } else {
566 hScroller.increment();
567 }
568 }
569
570 /**
571 * Perform a big step change left.
572 */
573 public void bigHorizontalDecrement() {
574 if (hScroller == null) {
575 return;
576 } else {
577 hScroller.bigDecrement();
578 }
579 }
580
581 /**
582 * Perform a big step change right.
583 */
584 public void bigHorizontalIncrement() {
585 if (hScroller == null) {
586 return;
587 } else {
588 hScroller.bigIncrement();
589 }
590 }
591
592 /**
593 * Go to the left edge of the horizontal scroller.
594 */
595 public void toLeft() {
596 if (hScroller == null) {
597 return;
598 } else {
599 hScroller.toLeft();
600 }
601 }
602
603 /**
604 * Go to the right edge of the horizontal scroller.
605 */
606 public void toRight() {
607 if (hScroller == null) {
608 return;
609 } else {
610 hScroller.toRight();
611 }
612 }
613
614 /**
615 * Go to the top-left edge of the horizontal and vertical scrollers.
616 */
617 public void toHome() {
618 if (hScroller != null) {
619 hScroller.toLeft();
620 }
621 if (vScroller != null) {
622 vScroller.toTop();
623 }
624 }
625
626 /**
627 * Go to the bottom-right edge of the horizontal and vertical scrollers.
628 */
629 public void toEnd() {
630 if (hScroller != null) {
631 hScroller.toRight();
632 }
633 if (vScroller != null) {
634 vScroller.toBottom();
635 }
636 }
637
638 /**
639 * Check if a mouse press/release/motion event coordinate is over the
640 * vertical scrollbar.
641 *
642 * @param mouse a mouse-based event
643 * @return whether or not the mouse is on the scrollbar
644 */
645 protected final boolean mouseOnVerticalScroller(final TMouseEvent mouse) {
646 if (vScroller == null) {
647 return false;
648 }
649 if ((mouse.getAbsoluteX() == vScroller.getAbsoluteX())
650 && (mouse.getAbsoluteY() >= vScroller.getAbsoluteY())
651 && (mouse.getAbsoluteY() < vScroller.getAbsoluteY() +
652 vScroller.getHeight())
653 ) {
654 return true;
655 }
656 return false;
657 }
658
659 /**
660 * Check if a mouse press/release/motion event coordinate is over the
661 * horizontal scrollbar.
662 *
663 * @param mouse a mouse-based event
664 * @return whether or not the mouse is on the scrollbar
665 */
666 protected final boolean mouseOnHorizontalScroller(final TMouseEvent mouse) {
667 if (hScroller == null) {
668 return false;
669 }
670 if ((mouse.getAbsoluteY() == hScroller.getAbsoluteY())
671 && (mouse.getAbsoluteX() >= hScroller.getAbsoluteX())
672 && (mouse.getAbsoluteX() < hScroller.getAbsoluteX() +
673 hScroller.getWidth())
674 ) {
675 return true;
676 }
677 return false;
678 }
679
680 }