2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import jexer
.bits
.CellAttributes
;
32 import jexer
.bits
.GraphicsChars
;
33 import jexer
.event
.TMenuEvent
;
34 import jexer
.event
.TMouseEvent
;
35 import jexer
.event
.TResizeEvent
;
36 import jexer
.menu
.TMenu
;
39 * TSplitPane contains two widgets with a draggable horizontal or vertical
42 public class TSplitPane
extends TWidget
{
44 // ------------------------------------------------------------------------
45 // Variables --------------------------------------------------------------
46 // ------------------------------------------------------------------------
49 * If true, split vertically. If false, split horizontally.
51 private boolean vertical
= true;
54 * The location of the split bar, either as a column number for vertical
55 * split or a row number for horizontal split.
57 private int split
= 0;
60 * The widget on the left side.
65 * The widget on the right side.
67 private TWidget right
;
70 * The widget on the top side.
75 * The widget on the bottom side.
77 private TWidget bottom
;
80 * If true, we are in the middle of a split move.
82 private boolean inSplitMove
= false;
84 // ------------------------------------------------------------------------
85 // Constructors -----------------------------------------------------------
86 // ------------------------------------------------------------------------
91 * @param parent parent widget
92 * @param x column relative to parent
93 * @param y row relative to parent
94 * @param width width of widget
95 * @param height height of widget
96 * @param vertical if true, split vertically
98 public TSplitPane(final TWidget parent
, final int x
, final int y
,
99 final int width
, final int height
, final boolean vertical
) {
101 super(parent
, x
, y
, width
, height
);
103 this.vertical
= vertical
;
107 // ------------------------------------------------------------------------
108 // Event handlers ---------------------------------------------------------
109 // ------------------------------------------------------------------------
112 * Handle window/screen resize events.
114 * @param event resize event
117 public void onResize(final TResizeEvent event
) {
118 if (event
.getType() == TResizeEvent
.Type
.WIDGET
) {
120 super.onResize(event
);
122 if (vertical
&& (split
>= getWidth() - 2)) {
124 } else if (!vertical
&& (split
>= getHeight() - 2)) {
133 * Handle mouse button presses.
135 * @param mouse mouse button event
138 public void onMouseDown(final TMouseEvent mouse
) {
142 if (mouse
.isMouse1()) {
144 inSplitMove
= (mouse
.getX() == split
);
146 inSplitMove
= (mouse
.getY() == split
);
153 // I didn't take it, pass it on to my children
154 super.onMouseDown(mouse
);
158 * Handle mouse button releases.
160 * @param mouse mouse button release event
163 public void onMouseUp(final TMouseEvent mouse
) {
165 if (inSplitMove
&& mouse
.isMouse1()) {
171 // I didn't take it, pass it on to my children
172 super.onMouseUp(mouse
);
176 * Handle mouse movements.
178 * @param mouse mouse motion event
181 public void onMouseMotion(final TMouseEvent mouse
) {
185 split
= mouse
.getX();
186 split
= Math
.min(Math
.max(1, split
), getWidth() - 2);
188 split
= mouse
.getY();
189 split
= Math
.min(Math
.max(1, split
), getHeight() - 2);
195 // I didn't take it, pass it on to my children
196 super.onMouseMotion(mouse
);
199 // ------------------------------------------------------------------------
200 // TWidget ----------------------------------------------------------------
201 // ------------------------------------------------------------------------
208 CellAttributes attr
= getTheme().getColor("tsplitpane");
210 vLineXY(split
, 0, getHeight(), GraphicsChars
.WINDOW_SIDE
, attr
);
211 // TODO: draw intersections of children
213 hLineXY(0, split
, getWidth(), GraphicsChars
.SINGLE_BAR
, attr
);
214 // TODO: draw intersections of children
218 // ------------------------------------------------------------------------
219 // TSplitPane -------------------------------------------------------------
220 // ------------------------------------------------------------------------
223 * Get the widget on the left side.
225 * @return the widget on the left, or null if not set
227 public TWidget
getLeft() {
232 * Set the widget on the left side.
234 * @param left the widget to set, or null to remove
236 public void setLeft(final TWidget left
) {
238 throw new IllegalArgumentException("cannot set left on " +
239 "horizontal split pane");
247 left
.setParent(this, false);
248 onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
, getWidth(),
253 * Get the widget on the right side.
255 * @return the widget on the right, or null if not set
257 public TWidget
getRight() {
262 * Set the widget on the right side.
264 * @param right the widget to set, or null to remove
266 public void setRight(final TWidget right
) {
268 throw new IllegalArgumentException("cannot set right on " +
269 "horizontal split pane");
277 right
.setParent(this, false);
278 onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
, getWidth(),
283 * Get the widget on the top side.
285 * @return the widget on the top, or null if not set
287 public TWidget
getTop() {
292 * Set the widget on the top side.
294 * @param top the widget to set, or null to remove
296 public void setTop(final TWidget top
) {
298 throw new IllegalArgumentException("cannot set top on vertical " +
307 top
.setParent(this, false);
308 onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
, getWidth(),
313 * Get the widget on the bottom side.
315 * @return the widget on the bottom, or null if not set
317 public TWidget
getBottom() {
322 * Set the widget on the bottom side.
324 * @param bottom the widget to set, or null to remove
326 public void setBottom(final TWidget bottom
) {
328 throw new IllegalArgumentException("cannot set bottom on " +
329 "vertical split pane");
331 if (bottom
== null) {
336 this.bottom
= bottom
;
337 bottom
.setParent(this, false);
338 onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
, getWidth(),
343 * Layout the two child widgets.
345 private void layoutChildren() {
348 left
.setDimensions(0, 0, split
, getHeight());
349 left
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
350 left
.getWidth(), left
.getHeight()));
353 right
.setDimensions(split
+ 1, 0, getWidth() - split
- 1,
355 right
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
356 right
.getWidth(), right
.getHeight()));
360 top
.setDimensions(0, 0, getWidth(), split
);
361 top
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
362 top
.getWidth(), top
.getHeight()));
364 if (bottom
!= null) {
365 bottom
.setDimensions(0, split
+ 1, getWidth(),
366 getHeight() - split
- 1);
367 bottom
.onResize(new TResizeEvent(TResizeEvent
.Type
.WIDGET
,
368 bottom
.getWidth(), bottom
.getHeight()));
374 * Recenter the split to the middle of this split pane.
376 public void center() {
378 split
= getWidth() / 2;
380 split
= getHeight() / 2;