Merge branch 'subtree'
[fanfix.git] / src / jexer / TTableWindow.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 java.io.File;
32 import java.io.IOException;
33 import java.text.MessageFormat;
34 import java.util.ResourceBundle;
35
36 import jexer.event.TCommandEvent;
37 import jexer.event.TKeypressEvent;
38 import jexer.event.TMenuEvent;
39 import jexer.event.TMouseEvent;
40 import jexer.event.TResizeEvent;
41 import jexer.menu.TMenu;
42 import jexer.menu.TMenuItem;
43 import static jexer.TCommand.*;
44 import static jexer.TKeypress.*;
45
46 /**
47 * TTableWindow is used to display and edit regular two-dimensional tables of
48 * cells.
49 */
50 public class TTableWindow extends TScrollableWindow {
51
52 /**
53 * Translated strings.
54 */
55 private static final ResourceBundle i18n = ResourceBundle.getBundle(TTableWindow.class.getName());
56
57 // ------------------------------------------------------------------------
58 // Variables --------------------------------------------------------------
59 // ------------------------------------------------------------------------
60
61 /**
62 * The table widget.
63 */
64 private TTableWidget tableField;
65
66 // ------------------------------------------------------------------------
67 // Constructors -----------------------------------------------------------
68 // ------------------------------------------------------------------------
69
70 /**
71 * Public constructor sets window title.
72 *
73 * @param parent the main application
74 * @param title the window title
75 */
76 public TTableWindow(final TApplication parent, final String title) {
77
78 super(parent, title, 0, 0, parent.getScreen().getWidth() / 2,
79 parent.getScreen().getHeight() / 2 - 2, RESIZABLE | CENTERED);
80
81 tableField = addTable(0, 0, getWidth() - 2, getHeight() - 2);
82 setupAfterTable();
83 }
84
85 /**
86 * Public constructor loads a grid from a RFC4180 CSV file.
87 *
88 * @param parent the main application
89 * @param csvFile a File referencing the CSV data
90 * @throws IOException if a java.io operation throws
91 */
92 public TTableWindow(final TApplication parent,
93 final File csvFile) throws IOException {
94
95 super(parent, csvFile.getName(), 0, 0,
96 parent.getScreen().getWidth() / 2,
97 parent.getScreen().getHeight() / 2 - 2,
98 RESIZABLE | CENTERED);
99
100 tableField = addTable(0, 0, getWidth() - 2, getHeight() - 2, 1, 1);
101 setupAfterTable();
102 tableField.loadCsvFile(csvFile);
103 }
104
105 // ------------------------------------------------------------------------
106 // Event handlers ---------------------------------------------------------
107 // ------------------------------------------------------------------------
108
109 /**
110 * Called by application.switchWindow() when this window gets the
111 * focus, and also by application.addWindow().
112 */
113 public void onFocus() {
114 // Enable the table menu items.
115 getApplication().enableMenuItem(TMenu.MID_TABLE_RENAME_COLUMN);
116 getApplication().enableMenuItem(TMenu.MID_TABLE_RENAME_ROW);
117 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
118 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
119 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
120 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
121 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
122 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
123 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_CELL_NONE);
124 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_CELL_ALL);
125 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
126 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
127 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
128 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
129 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
130 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
131 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
132 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_UP);
133 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
134 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
135 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
136 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
137 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
138 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
139 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
140 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
141 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_OPEN_CSV);
142 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
143 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
144
145 if (tableField != null) {
146
147 // Set the menu to match the flags.
148 TMenuItem menuItem = getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
149 if (menuItem != null) {
150 menuItem.setChecked(tableField.getShowRowLabels());
151 }
152 menuItem = getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
153 if (menuItem != null) {
154 menuItem.setChecked(tableField.getShowColumnLabels());
155 }
156 menuItem = getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
157 if (menuItem != null) {
158 menuItem.setChecked(tableField.getHighlightRow());
159 }
160 menuItem = getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
161 if (menuItem != null) {
162 menuItem.setChecked(tableField.getHighlightColumn());
163 }
164 }
165 }
166
167 /**
168 * Called by application.switchWindow() when another window gets the
169 * focus.
170 */
171 public void onUnfocus() {
172 // Disable the table menu items.
173 getApplication().disableMenuItem(TMenu.MID_TABLE_RENAME_COLUMN);
174 getApplication().disableMenuItem(TMenu.MID_TABLE_RENAME_ROW);
175 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
176 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
177 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
178 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
179 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
180 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
181 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_CELL_NONE);
182 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_CELL_ALL);
183 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
184 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
185 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
186 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
187 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
188 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
189 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
190 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_UP);
191 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
192 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
193 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
194 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
195 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
196 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
197 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
198 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
199 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_OPEN_CSV);
200 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
201 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
202 }
203
204 // ------------------------------------------------------------------------
205 // TWindow ----------------------------------------------------------------
206 // ------------------------------------------------------------------------
207
208 /**
209 * Handle mouse press events.
210 *
211 * @param mouse mouse button press event
212 */
213 @Override
214 public void onMouseDown(final TMouseEvent mouse) {
215 // Use TWidget's code to pass the event to the children.
216 super.onMouseDown(mouse);
217
218 if (mouseOnTable(mouse)) {
219 // The table might have changed, update the scollbars.
220 setBottomValue(tableField.getRowCount() - 1);
221 setVerticalValue(tableField.getSelectedRowNumber());
222 setRightValue(tableField.getColumnCount() - 1);
223 setHorizontalValue(tableField.getSelectedColumnNumber());
224 }
225 }
226
227 /**
228 * Handle mouse release events.
229 *
230 * @param mouse mouse button release event
231 */
232 @Override
233 public void onMouseUp(final TMouseEvent mouse) {
234 // Use TWidget's code to pass the event to the children.
235 super.onMouseUp(mouse);
236
237 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
238 // Clicked/dragged on vertical scrollbar.
239 tableField.setSelectedRowNumber(getVerticalValue());
240 }
241 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
242 // Clicked/dragged on horizontal scrollbar.
243 tableField.setSelectedColumnNumber(getHorizontalValue());
244 }
245 }
246
247 /**
248 * Method that subclasses can override to handle mouse movements.
249 *
250 * @param mouse mouse motion event
251 */
252 @Override
253 public void onMouseMotion(final TMouseEvent mouse) {
254 // Use TWidget's code to pass the event to the children.
255 super.onMouseMotion(mouse);
256
257 if (mouseOnTable(mouse) && mouse.isMouse1()) {
258 // The table might have changed, update the scollbars.
259 setBottomValue(tableField.getRowCount() - 1);
260 setVerticalValue(tableField.getSelectedRowNumber());
261 setRightValue(tableField.getColumnCount() - 1);
262 setHorizontalValue(tableField.getSelectedColumnNumber());
263 } else {
264 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
265 // Clicked/dragged on vertical scrollbar.
266 tableField.setSelectedRowNumber(getVerticalValue());
267 }
268 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
269 // Clicked/dragged on horizontal scrollbar.
270 tableField.setSelectedColumnNumber(getHorizontalValue());
271 }
272 }
273
274 }
275
276 /**
277 * Handle keystrokes.
278 *
279 * @param keypress keystroke event
280 */
281 @Override
282 public void onKeypress(final TKeypressEvent keypress) {
283 // Use TWidget's code to pass the event to the children.
284 super.onKeypress(keypress);
285
286 // The table might have changed, update the scollbars.
287 setBottomValue(tableField.getRowCount() - 1);
288 setVerticalValue(tableField.getSelectedRowNumber());
289 setRightValue(tableField.getColumnCount() - 1);
290 setHorizontalValue(tableField.getSelectedColumnNumber());
291 }
292
293 /**
294 * Handle window/screen resize events.
295 *
296 * @param event resize event
297 */
298 @Override
299 public void onResize(final TResizeEvent event) {
300 if (event.getType() == TResizeEvent.Type.WIDGET) {
301 // Resize the table
302 TResizeEvent tableSize = new TResizeEvent(TResizeEvent.Type.WIDGET,
303 event.getWidth() - 2, event.getHeight() - 2);
304 tableField.onResize(tableSize);
305
306 // Have TScrollableWindow handle the scrollbars
307 super.onResize(event);
308 return;
309 }
310
311 // Pass to children instead
312 for (TWidget widget: getChildren()) {
313 widget.onResize(event);
314 }
315 }
316
317 /**
318 * Method that subclasses can override to handle posted command events.
319 *
320 * @param command command event
321 */
322 @Override
323 public void onCommand(final TCommandEvent command) {
324 if (command.equals(cmOpen)) {
325 try {
326 String filename = fileOpenBox(".");
327 if (filename != null) {
328 try {
329 new TTableWindow(getApplication(), new File(filename));
330 } catch (IOException e) {
331 messageBox(i18n.getString("errorDialogTitle"),
332 MessageFormat.format(i18n.
333 getString("errorReadingFile"), e.getMessage()));
334 }
335 }
336 } catch (IOException e) {
337 messageBox(i18n.getString("errorDialogTitle"),
338 MessageFormat.format(i18n.
339 getString("errorOpeningFileDialog"), e.getMessage()));
340 }
341 return;
342 }
343
344 if (command.equals(cmSave)) {
345 try {
346 String filename = fileSaveBox(".");
347 if (filename != null) {
348 tableField.saveToCsvFilename(filename);
349 }
350 } catch (IOException e) {
351 messageBox(i18n.getString("errorDialogTitle"),
352 MessageFormat.format(i18n.
353 getString("errorWritingFile"), e.getMessage()));
354 }
355 return;
356 }
357
358 // Didn't handle it, let children get it instead
359 super.onCommand(command);
360 }
361
362 /**
363 * Handle posted menu events.
364 *
365 * @param menu menu event
366 */
367 @Override
368 public void onMenu(final TMenuEvent menu) {
369 TInputBox inputBox = null;
370 String filename = null;
371
372 switch (menu.getId()) {
373 case TMenu.MID_TABLE_RENAME_COLUMN:
374 inputBox = inputBox(i18n.getString("renameColumnInputTitle"),
375 i18n.getString("renameColumnInputCaption"),
376 tableField.getColumnLabel(tableField.getSelectedColumnNumber()),
377 TMessageBox.Type.OKCANCEL);
378 if (inputBox.isOk()) {
379 tableField.setColumnLabel(tableField.getSelectedColumnNumber(),
380 inputBox.getText());
381 }
382 return;
383 case TMenu.MID_TABLE_RENAME_ROW:
384 inputBox = inputBox(i18n.getString("renameRowInputTitle"),
385 i18n.getString("renameRowInputCaption"),
386 tableField.getRowLabel(tableField.getSelectedRowNumber()),
387 TMessageBox.Type.OKCANCEL);
388 if (inputBox.isOk()) {
389 tableField.setRowLabel(tableField.getSelectedRowNumber(),
390 inputBox.getText());
391 }
392 return;
393 case TMenu.MID_TABLE_VIEW_ROW_LABELS:
394 tableField.setShowRowLabels(getApplication().getMenuItem(
395 menu.getId()).getChecked());
396 return;
397 case TMenu.MID_TABLE_VIEW_COLUMN_LABELS:
398 tableField.setShowColumnLabels(getApplication().getMenuItem(
399 menu.getId()).getChecked());
400 return;
401 case TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW:
402 tableField.setHighlightRow(getApplication().getMenuItem(
403 menu.getId()).getChecked());
404 return;
405 case TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN:
406 tableField.setHighlightColumn(getApplication().getMenuItem(
407 menu.getId()).getChecked());
408 return;
409 case TMenu.MID_TABLE_BORDER_NONE:
410 tableField.setBorderAllNone();
411 return;
412 case TMenu.MID_TABLE_BORDER_ALL:
413 tableField.setBorderAllSingle();
414 return;
415 case TMenu.MID_TABLE_BORDER_CELL_NONE:
416 tableField.setBorderCellNone();
417 return;
418 case TMenu.MID_TABLE_BORDER_CELL_ALL:
419 tableField.setBorderCellSingle();
420 return;
421 case TMenu.MID_TABLE_BORDER_RIGHT:
422 tableField.setBorderColumnRightSingle();
423 return;
424 case TMenu.MID_TABLE_BORDER_LEFT:
425 tableField.setBorderColumnLeftSingle();
426 return;
427 case TMenu.MID_TABLE_BORDER_TOP:
428 tableField.setBorderRowAboveSingle();
429 return;
430 case TMenu.MID_TABLE_BORDER_BOTTOM:
431 tableField.setBorderRowBelowSingle();
432 return;
433 case TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM:
434 tableField.setBorderRowBelowDouble();
435 return;
436 case TMenu.MID_TABLE_BORDER_THICK_BOTTOM:
437 tableField.setBorderRowBelowThick();
438 return;
439 case TMenu.MID_TABLE_DELETE_LEFT:
440 tableField.deleteCellShiftLeft();
441 return;
442 case TMenu.MID_TABLE_DELETE_UP:
443 tableField.deleteCellShiftUp();
444 return;
445 case TMenu.MID_TABLE_DELETE_ROW:
446 tableField.deleteRow(tableField.getSelectedRowNumber());
447 return;
448 case TMenu.MID_TABLE_DELETE_COLUMN:
449 tableField.deleteColumn(tableField.getSelectedColumnNumber());
450 return;
451 case TMenu.MID_TABLE_INSERT_LEFT:
452 tableField.insertColumnLeft(tableField.getSelectedColumnNumber());
453 return;
454 case TMenu.MID_TABLE_INSERT_RIGHT:
455 tableField.insertColumnRight(tableField.getSelectedColumnNumber());
456 return;
457 case TMenu.MID_TABLE_INSERT_ABOVE:
458 tableField.insertRowAbove(tableField.getSelectedColumnNumber());
459 return;
460 case TMenu.MID_TABLE_INSERT_BELOW:
461 tableField.insertRowBelow(tableField.getSelectedColumnNumber());
462 return;
463 case TMenu.MID_TABLE_COLUMN_NARROW:
464 tableField.setColumnWidth(tableField.getSelectedColumnNumber(),
465 tableField.getColumnWidth(tableField.getSelectedColumnNumber()) - 1);
466 return;
467 case TMenu.MID_TABLE_COLUMN_WIDEN:
468 tableField.setColumnWidth(tableField.getSelectedColumnNumber(),
469 tableField.getColumnWidth(tableField.getSelectedColumnNumber()) + 1);
470 return;
471 case TMenu.MID_TABLE_FILE_OPEN_CSV:
472 try {
473 filename = fileOpenBox(".");
474 if (filename != null) {
475 try {
476 new TTableWindow(getApplication(), new File(filename));
477 } catch (IOException e) {
478 messageBox(i18n.getString("errorDialogTitle"),
479 MessageFormat.format(i18n.
480 getString("errorReadingFile"), e.getMessage()));
481 }
482 }
483 } catch (IOException e) {
484 messageBox(i18n.getString("errorDialogTitle"),
485 MessageFormat.format(i18n.
486 getString("errorOpeningFileDialog"), e.getMessage()));
487 }
488 return;
489 case TMenu.MID_TABLE_FILE_SAVE_CSV:
490 try {
491 filename = fileSaveBox(".");
492 if (filename != null) {
493 tableField.saveToCsvFilename(filename);
494 }
495 } catch (IOException e) {
496 messageBox(i18n.getString("errorDialogTitle"),
497 MessageFormat.format(i18n.
498 getString("errorWritingFile"), e.getMessage()));
499 }
500 return;
501 case TMenu.MID_TABLE_FILE_SAVE_TEXT:
502 try {
503 filename = fileSaveBox(".");
504 if (filename != null) {
505 tableField.saveToTextFilename(filename);
506 }
507 } catch (IOException e) {
508 messageBox(i18n.getString("errorDialogTitle"),
509 MessageFormat.format(i18n.
510 getString("errorWritingFile"), e.getMessage()));
511 }
512 return;
513 default:
514 break;
515 }
516
517 super.onMenu(menu);
518 }
519
520 // ------------------------------------------------------------------------
521 // TTableWindow -----------------------------------------------------------
522 // ------------------------------------------------------------------------
523
524 /**
525 * Setup other fields after the table is created.
526 */
527 private void setupAfterTable() {
528 hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
529 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
530 setMinimumWindowWidth(25);
531 setMinimumWindowHeight(10);
532 setTopValue(tableField.getSelectedRowNumber());
533 setBottomValue(tableField.getRowCount() - 1);
534 setLeftValue(tableField.getSelectedColumnNumber());
535 setRightValue(tableField.getColumnCount() - 1);
536
537 statusBar = newStatusBar(i18n.getString("statusBar"));
538 statusBar.addShortcutKeypress(kbF1, cmHelp,
539 i18n.getString("statusBarHelp"));
540
541 statusBar.addShortcutKeypress(kbF2, cmSave,
542 i18n.getString("statusBarSave"));
543 statusBar.addShortcutKeypress(kbF3, cmOpen,
544 i18n.getString("statusBarOpen"));
545 statusBar.addShortcutKeypress(kbF10, cmMenu,
546 i18n.getString("statusBarMenu"));
547
548 // Synchronize the menu with tableField's flags.
549 onFocus();
550 }
551
552 /**
553 * Check if a mouse press/release/motion event coordinate is over the
554 * table.
555 *
556 * @param mouse a mouse-based event
557 * @return whether or not the mouse is on the table
558 */
559 private boolean mouseOnTable(final TMouseEvent mouse) {
560 if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
561 && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
562 && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
563 && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
564 ) {
565 return true;
566 }
567 return false;
568 }
569
570 }