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]
29 package jexer
.backend
;
31 import java
.awt
.BorderLayout
;
32 import java
.awt
.Color
;
34 import java
.awt
.FontMetrics
;
35 import java
.awt
.Graphics2D
;
36 import java
.awt
.Graphics
;
37 import java
.awt
.Insets
;
38 import java
.awt
.Rectangle
;
39 import java
.awt
.Toolkit
;
40 import java
.awt
.event
.ComponentEvent
;
41 import java
.awt
.event
.ComponentListener
;
42 import java
.awt
.event
.KeyEvent
;
43 import java
.awt
.event
.KeyListener
;
44 import java
.awt
.event
.MouseEvent
;
45 import java
.awt
.event
.MouseListener
;
46 import java
.awt
.event
.MouseMotionListener
;
47 import java
.awt
.event
.MouseWheelEvent
;
48 import java
.awt
.event
.MouseWheelListener
;
49 import java
.awt
.event
.WindowEvent
;
50 import java
.awt
.event
.WindowListener
;
51 import java
.awt
.geom
.Rectangle2D
;
52 import java
.awt
.image
.BufferedImage
;
53 import java
.io
.InputStream
;
54 import java
.util
.ArrayList
;
55 import java
.util
.HashMap
;
56 import java
.util
.List
;
58 import javax
.swing
.JComponent
;
59 import javax
.swing
.JFrame
;
60 import javax
.swing
.ImageIcon
;
61 import javax
.swing
.SwingUtilities
;
63 import jexer
.TKeypress
;
64 import jexer
.bits
.Cell
;
65 import jexer
.bits
.CellAttributes
;
66 import jexer
.event
.TCommandEvent
;
67 import jexer
.event
.TInputEvent
;
68 import jexer
.event
.TKeypressEvent
;
69 import jexer
.event
.TMouseEvent
;
70 import jexer
.event
.TResizeEvent
;
71 import static jexer
.TCommand
.*;
72 import static jexer
.TKeypress
.*;
75 * This Screen backend reads keystrokes and mouse events and draws to either
76 * a Java Swing JFrame (potentially triple-buffered) or a JComponent.
78 * This class is a bit of an inversion of typical GUI classes. It performs
79 * all of the drawing logic from SwingTerminal (which is not a Swing class),
80 * and uses a SwingComponent wrapper class to call the JFrame or JComponent
83 public class SwingTerminal
extends LogicalScreen
84 implements TerminalReader
,
85 ComponentListener
, KeyListener
,
86 MouseListener
, MouseMotionListener
,
87 MouseWheelListener
, WindowListener
{
89 // ------------------------------------------------------------------------
90 // Constants --------------------------------------------------------------
91 // ------------------------------------------------------------------------
94 * The icon image location.
96 private static final String ICONFILE
= "jexer_logo_128.png";
99 * The terminus font resource filename.
101 public static final String FONTFILE
= "terminus-ttf-4.39/TerminusTTF-Bold-4.39.ttf";
104 * Cursor style to draw.
106 public enum CursorStyle
{
108 * Use an underscore for the cursor.
113 * Use a solid block for the cursor.
118 * Use an outlined block for the cursor.
123 // ------------------------------------------------------------------------
124 // Variables --------------------------------------------------------------
125 // ------------------------------------------------------------------------
127 // Colors to map DOS colors to AWT colors.
128 private static Color MYBLACK
;
129 private static Color MYRED
;
130 private static Color MYGREEN
;
131 private static Color MYYELLOW
;
132 private static Color MYBLUE
;
133 private static Color MYMAGENTA
;
134 private static Color MYCYAN
;
135 private static Color MYWHITE
;
136 private static Color MYBOLD_BLACK
;
137 private static Color MYBOLD_RED
;
138 private static Color MYBOLD_GREEN
;
139 private static Color MYBOLD_YELLOW
;
140 private static Color MYBOLD_BLUE
;
141 private static Color MYBOLD_MAGENTA
;
142 private static Color MYBOLD_CYAN
;
143 private static Color MYBOLD_WHITE
;
146 * When true, all the MYBLACK, MYRED, etc. colors are set.
148 private static boolean dosColors
= false;
151 * The Swing component or frame to draw to.
153 private SwingComponent swing
;
156 * A cache of previously-rendered glyphs for blinking text, when it is
159 private Map
<Cell
, BufferedImage
> glyphCacheBlink
;
162 * A cache of previously-rendered glyphs for non-blinking, or
163 * blinking-and-visible, text.
165 private Map
<Cell
, BufferedImage
> glyphCache
;
168 * If true, we were successful at getting the font dimensions.
170 private boolean gotFontDimensions
= false;
173 * The currently selected font.
175 private Font font
= null;
178 * The currently selected font size in points.
180 private int fontSize
= 16;
183 * Width of a character cell in pixels.
185 private int textWidth
= 16;
188 * Height of a character cell in pixels.
190 private int textHeight
= 20;
193 * Width of a character cell in pixels, as reported by font.
195 private int fontTextWidth
= 1;
198 * Height of a character cell in pixels, as reported by font.
200 private int fontTextHeight
= 1;
203 * Descent of a character cell in pixels.
205 private int maxDescent
= 0;
208 * System-dependent Y adjustment for text in the character cell.
210 private int textAdjustY
= 0;
213 * System-dependent X adjustment for text in the character cell.
215 private int textAdjustX
= 0;
218 * System-dependent height adjustment for text in the character cell.
220 private int textAdjustHeight
= 0;
223 * System-dependent width adjustment for text in the character cell.
225 private int textAdjustWidth
= 0;
228 * Top pixel absolute location.
230 private int top
= 30;
233 * Left pixel absolute location.
235 private int left
= 30;
238 * The cursor style to draw.
240 private CursorStyle cursorStyle
= CursorStyle
.UNDERLINE
;
243 * The number of millis to wait before switching the blink from visible
244 * to invisible. Set to 0 or negative to disable blinking.
246 private long blinkMillis
= 500;
249 * If true, the cursor should be visible right now based on the blink
252 private boolean cursorBlinkVisible
= true;
255 * The time that the blink last flipped from visible to invisible or
256 * from invisible to visible.
258 private long lastBlinkTime
= 0;
261 * The session information.
263 private SwingSessionInfo sessionInfo
;
266 * The listening object that run() wakes up on new input.
268 private Object listener
;
271 * The event queue, filled up by a thread reading on input.
273 private List
<TInputEvent
> eventQueue
;
276 * The last reported mouse X position.
278 private int oldMouseX
= -1;
281 * The last reported mouse Y position.
283 private int oldMouseY
= -1;
286 * true if mouse1 was down. Used to report mouse1 on the release event.
288 private boolean mouse1
= false;
291 * true if mouse2 was down. Used to report mouse2 on the release event.
293 private boolean mouse2
= false;
296 * true if mouse3 was down. Used to report mouse3 on the release event.
298 private boolean mouse3
= false;
300 // ------------------------------------------------------------------------
301 // Constructors -----------------------------------------------------------
302 // ------------------------------------------------------------------------
305 * Static constructor.
312 * Public constructor creates a new JFrame to render to.
314 * @param windowWidth the number of text columns to start with
315 * @param windowHeight the number of text rows to start with
316 * @param fontSize the size in points. Good values to pick are: 16, 20,
318 * @param listener the object this backend needs to wake up when new
321 public SwingTerminal(final int windowWidth
, final int windowHeight
,
322 final int fontSize
, final Object listener
) {
324 this.fontSize
= fontSize
;
329 SwingUtilities
.invokeAndWait(new Runnable() {
332 JFrame frame
= new JFrame() {
335 * Serializable version.
337 private static final long serialVersionUID
= 1;
340 * The code that performs the actual drawing.
342 public SwingTerminal screen
= null;
345 * Anonymous class initializer saves the screen
346 * reference, so that paint() and the like call out
350 this.screen
= SwingTerminal
.this;
354 * Update redraws the whole screen.
356 * @param gr the Swing Graphics context
359 public void update(final Graphics gr
) {
360 // The default update clears the area. Don't do
361 // that, instead just paint it directly.
366 * Paint redraws the whole screen.
368 * @param gr the Swing Graphics context
371 public void paint(final Graphics gr
) {
372 if (screen
!= null) {
379 ClassLoader loader
= Thread
.currentThread().
380 getContextClassLoader();
381 frame
.setIconImage((new ImageIcon(loader
.
382 getResource(ICONFILE
))).getImage());
384 // Get the Swing component
385 SwingTerminal
.this.swing
= new SwingComponent(frame
);
387 // Hang onto top and left for drawing.
388 Insets insets
= SwingTerminal
.this.swing
.getInsets();
389 SwingTerminal
.this.left
= insets
.left
;
390 SwingTerminal
.this.top
= insets
.top
;
392 // Load the font so that we can set sessionInfo.
395 // Get the default cols x rows and set component size
397 SwingTerminal
.this.sessionInfo
=
398 new SwingSessionInfo(SwingTerminal
.this.swing
,
399 SwingTerminal
.this.textWidth
,
400 SwingTerminal
.this.textHeight
,
401 windowWidth
, windowHeight
);
403 SwingTerminal
.this.setDimensions(sessionInfo
.
404 getWindowWidth(), sessionInfo
.getWindowHeight());
406 SwingTerminal
.this.resizeToScreen(true);
407 SwingTerminal
.this.swing
.setVisible(true);
410 } catch (java
.lang
.reflect
.InvocationTargetException e
) {
412 } catch (InterruptedException e
) {
416 this.listener
= listener
;
420 eventQueue
= new ArrayList
<TInputEvent
>();
422 // Add listeners to Swing.
423 swing
.addKeyListener(this);
424 swing
.addWindowListener(this);
425 swing
.addComponentListener(this);
426 swing
.addMouseListener(this);
427 swing
.addMouseMotionListener(this);
428 swing
.addMouseWheelListener(this);
432 * Public constructor renders to an existing JComponent.
434 * @param component the Swing component to render to
435 * @param windowWidth the number of text columns to start with
436 * @param windowHeight the number of text rows to start with
437 * @param fontSize the size in points. Good values to pick are: 16, 20,
439 * @param listener the object this backend needs to wake up when new
442 public SwingTerminal(final JComponent component
, final int windowWidth
,
443 final int windowHeight
, final int fontSize
, final Object listener
) {
445 this.fontSize
= fontSize
;
450 SwingUtilities
.invokeAndWait(new Runnable() {
453 JComponent newComponent
= new JComponent() {
456 * Serializable version.
458 private static final long serialVersionUID
= 1;
461 * The code that performs the actual drawing.
463 public SwingTerminal screen
= null;
466 * Anonymous class initializer saves the screen
467 * reference, so that paint() and the like call out
471 this.screen
= SwingTerminal
.this;
475 * Update redraws the whole screen.
477 * @param gr the Swing Graphics context
480 public void update(final Graphics gr
) {
481 // The default update clears the area. Don't do
482 // that, instead just paint it directly.
487 * Paint redraws the whole screen.
489 * @param gr the Swing Graphics context
492 public void paint(final Graphics gr
) {
493 if (screen
!= null) {
498 component
.setLayout(new BorderLayout());
499 component
.add(newComponent
);
501 // Allow key events to be received
502 component
.setFocusable(true);
504 // Get the Swing component
505 SwingTerminal
.this.swing
= new SwingComponent(component
);
507 // Hang onto top and left for drawing.
508 Insets insets
= SwingTerminal
.this.swing
.getInsets();
509 SwingTerminal
.this.left
= insets
.left
;
510 SwingTerminal
.this.top
= insets
.top
;
512 // Load the font so that we can set sessionInfo.
515 // Get the default cols x rows and set component size
517 SwingTerminal
.this.sessionInfo
=
518 new SwingSessionInfo(SwingTerminal
.this.swing
,
519 SwingTerminal
.this.textWidth
,
520 SwingTerminal
.this.textHeight
);
523 } catch (java
.lang
.reflect
.InvocationTargetException e
) {
525 } catch (InterruptedException e
) {
529 this.listener
= listener
;
533 eventQueue
= new ArrayList
<TInputEvent
>();
535 // Add listeners to Swing.
536 swing
.addKeyListener(this);
537 swing
.addWindowListener(this);
538 swing
.addComponentListener(this);
539 swing
.addMouseListener(this);
540 swing
.addMouseMotionListener(this);
541 swing
.addMouseWheelListener(this);
544 // ------------------------------------------------------------------------
545 // LogicalScreen ----------------------------------------------------------
546 // ------------------------------------------------------------------------
549 * Set the window title.
551 * @param title the new title
554 public void setTitle(final String title
) {
555 swing
.setTitle(title
);
559 * Push the logical screen to the physical device.
562 public void flushPhysical() {
563 // See if it is time to flip the blink time.
564 long nowTime
= System
.currentTimeMillis();
565 if (nowTime
>= blinkMillis
+ lastBlinkTime
) {
566 lastBlinkTime
= nowTime
;
567 cursorBlinkVisible
= !cursorBlinkVisible
;
568 // System.err.println("New lastBlinkTime: " + lastBlinkTime);
571 if ((swing
.getFrame() != null)
572 && (swing
.getBufferStrategy() != null)
578 } while (swing
.getBufferStrategy().contentsRestored());
580 swing
.getBufferStrategy().show();
581 Toolkit
.getDefaultToolkit().sync();
582 } while (swing
.getBufferStrategy().contentsLost());
585 // Non-triple-buffered, call drawToSwing() once
590 // ------------------------------------------------------------------------
591 // TerminalReader ---------------------------------------------------------
592 // ------------------------------------------------------------------------
595 * Check if there are events in the queue.
597 * @return if true, getEvents() has something to return to the backend
599 public boolean hasEvents() {
600 synchronized (eventQueue
) {
601 return (eventQueue
.size() > 0);
606 * Return any events in the IO queue.
608 * @param queue list to append new events to
610 public void getEvents(final List
<TInputEvent
> queue
) {
611 synchronized (eventQueue
) {
612 if (eventQueue
.size() > 0) {
613 synchronized (queue
) {
614 queue
.addAll(eventQueue
);
622 * Restore terminal to normal state.
624 public void closeTerminal() {
629 * Set listener to a different Object.
631 * @param listener the new listening object that run() wakes up on new
634 public void setListener(final Object listener
) {
635 this.listener
= listener
;
639 * Reload options from System properties.
641 public void reloadOptions() {
642 // Figure out my cursor style.
643 String cursorStyleString
= System
.getProperty(
644 "jexer.Swing.cursorStyle", "underline").toLowerCase();
645 if (cursorStyleString
.equals("underline")) {
646 cursorStyle
= CursorStyle
.UNDERLINE
;
647 } else if (cursorStyleString
.equals("outline")) {
648 cursorStyle
= CursorStyle
.OUTLINE
;
649 } else if (cursorStyleString
.equals("block")) {
650 cursorStyle
= CursorStyle
.BLOCK
;
653 // Pull the system property for triple buffering.
654 if (System
.getProperty("jexer.Swing.tripleBuffer",
655 "true").equals("true")
657 SwingComponent
.tripleBuffer
= true;
659 SwingComponent
.tripleBuffer
= false;
663 // ------------------------------------------------------------------------
664 // SwingTerminal ----------------------------------------------------------
665 // ------------------------------------------------------------------------
668 * Get the width of a character cell in pixels.
670 * @return the width in pixels of a character cell
672 public int getTextWidth() {
677 * Get the height of a character cell in pixels.
679 * @return the height in pixels of a character cell
681 public int getTextHeight() {
686 * Setup Swing colors to match DOS color palette.
688 private static void setDOSColors() {
692 MYBLACK
= new Color(0x00, 0x00, 0x00);
693 MYRED
= new Color(0xa8, 0x00, 0x00);
694 MYGREEN
= new Color(0x00, 0xa8, 0x00);
695 MYYELLOW
= new Color(0xa8, 0x54, 0x00);
696 MYBLUE
= new Color(0x00, 0x00, 0xa8);
697 MYMAGENTA
= new Color(0xa8, 0x00, 0xa8);
698 MYCYAN
= new Color(0x00, 0xa8, 0xa8);
699 MYWHITE
= new Color(0xa8, 0xa8, 0xa8);
700 MYBOLD_BLACK
= new Color(0x54, 0x54, 0x54);
701 MYBOLD_RED
= new Color(0xfc, 0x54, 0x54);
702 MYBOLD_GREEN
= new Color(0x54, 0xfc, 0x54);
703 MYBOLD_YELLOW
= new Color(0xfc, 0xfc, 0x54);
704 MYBOLD_BLUE
= new Color(0x54, 0x54, 0xfc);
705 MYBOLD_MAGENTA
= new Color(0xfc, 0x54, 0xfc);
706 MYBOLD_CYAN
= new Color(0x54, 0xfc, 0xfc);
707 MYBOLD_WHITE
= new Color(0xfc, 0xfc, 0xfc);
713 * Get the number of millis to wait before switching the blink from
714 * visible to invisible.
716 * @return the number of milli to wait before switching the blink from
717 * visible to invisible
719 public long getBlinkMillis() {
724 * Get the current status of the blink flag.
726 * @return true if the cursor and blinking text should be visible
728 public boolean getCursorBlinkVisible() {
729 return cursorBlinkVisible
;
733 * Get the font size in points.
735 * @return font size in points
737 public int getFontSize() {
742 * Set the font size in points.
744 * @param fontSize font size in points
746 public void setFontSize(final int fontSize
) {
747 this.fontSize
= fontSize
;
748 Font newFont
= font
.deriveFont((float) fontSize
);
753 * Set to a new font, and resize the screen to match its dimensions.
755 * @param font the new font
757 public void setFont(final Font font
) {
758 synchronized (this) {
762 glyphCacheBlink
= new HashMap
<Cell
, BufferedImage
>();
763 glyphCache
= new HashMap
<Cell
, BufferedImage
>();
764 resizeToScreen(true);
769 * Get the font this screen was last set to.
773 public Font
getFont() {
778 * Set the font to Terminus, the best all-around font for both CP437 and
781 public void setDefaultFont() {
783 ClassLoader loader
= Thread
.currentThread().getContextClassLoader();
784 InputStream in
= loader
.getResourceAsStream(FONTFILE
);
785 Font terminusRoot
= Font
.createFont(Font
.TRUETYPE_FONT
, in
);
786 Font terminus
= terminusRoot
.deriveFont(Font
.PLAIN
, fontSize
);
788 } catch (java
.awt
.FontFormatException e
) {
790 font
= new Font(Font
.MONOSPACED
, Font
.PLAIN
, fontSize
);
791 } catch (java
.io
.IOException e
) {
793 font
= new Font(Font
.MONOSPACED
, Font
.PLAIN
, fontSize
);
800 * Get the X text adjustment.
802 * @return X text adjustment
804 public int getTextAdjustX() {
809 * Set the X text adjustment.
811 * @param textAdjustX the X text adjustment
813 public void setTextAdjustX(final int textAdjustX
) {
814 synchronized (this) {
815 this.textAdjustX
= textAdjustX
;
816 glyphCacheBlink
= new HashMap
<Cell
, BufferedImage
>();
817 glyphCache
= new HashMap
<Cell
, BufferedImage
>();
823 * Get the Y text adjustment.
825 * @return Y text adjustment
827 public int getTextAdjustY() {
832 * Set the Y text adjustment.
834 * @param textAdjustY the Y text adjustment
836 public void setTextAdjustY(final int textAdjustY
) {
837 synchronized (this) {
838 this.textAdjustY
= textAdjustY
;
839 glyphCacheBlink
= new HashMap
<Cell
, BufferedImage
>();
840 glyphCache
= new HashMap
<Cell
, BufferedImage
>();
846 * Get the height text adjustment.
848 * @return height text adjustment
850 public int getTextAdjustHeight() {
851 return textAdjustHeight
;
855 * Set the height text adjustment.
857 * @param textAdjustHeight the height text adjustment
859 public void setTextAdjustHeight(final int textAdjustHeight
) {
860 synchronized (this) {
861 this.textAdjustHeight
= textAdjustHeight
;
862 textHeight
= fontTextHeight
+ textAdjustHeight
;
863 glyphCacheBlink
= new HashMap
<Cell
, BufferedImage
>();
864 glyphCache
= new HashMap
<Cell
, BufferedImage
>();
870 * Get the width text adjustment.
872 * @return width text adjustment
874 public int getTextAdjustWidth() {
875 return textAdjustWidth
;
879 * Set the width text adjustment.
881 * @param textAdjustWidth the width text adjustment
883 public void setTextAdjustWidth(final int textAdjustWidth
) {
884 synchronized (this) {
885 this.textAdjustWidth
= textAdjustWidth
;
886 textWidth
= fontTextWidth
+ textAdjustWidth
;
887 glyphCacheBlink
= new HashMap
<Cell
, BufferedImage
>();
888 glyphCache
= new HashMap
<Cell
, BufferedImage
>();
894 * Convert a CellAttributes foreground color to an Swing Color.
896 * @param attr the text attributes
897 * @return the Swing Color
899 public static Color
attrToForegroundColor(final CellAttributes attr
) {
900 int rgb
= attr
.getForeColorRGB();
902 int red
= (rgb
>> 16) & 0xFF;
903 int green
= (rgb
>> 8) & 0xFF;
904 int blue
= rgb
& 0xFF;
906 return new Color(red
, green
, blue
);
910 if (attr
.getForeColor().equals(jexer
.bits
.Color
.BLACK
)) {
912 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.RED
)) {
914 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.BLUE
)) {
916 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.GREEN
)) {
918 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.YELLOW
)) {
919 return MYBOLD_YELLOW
;
920 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.CYAN
)) {
922 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.MAGENTA
)) {
923 return MYBOLD_MAGENTA
;
924 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.WHITE
)) {
928 if (attr
.getForeColor().equals(jexer
.bits
.Color
.BLACK
)) {
930 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.RED
)) {
932 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.BLUE
)) {
934 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.GREEN
)) {
936 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.YELLOW
)) {
938 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.CYAN
)) {
940 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.MAGENTA
)) {
942 } else if (attr
.getForeColor().equals(jexer
.bits
.Color
.WHITE
)) {
946 throw new IllegalArgumentException("Invalid color: " +
947 attr
.getForeColor().getValue());
951 * Convert a CellAttributes background color to an Swing Color.
953 * @param attr the text attributes
954 * @return the Swing Color
956 public static Color
attrToBackgroundColor(final CellAttributes attr
) {
957 int rgb
= attr
.getBackColorRGB();
959 int red
= (rgb
>> 16) & 0xFF;
960 int green
= (rgb
>> 8) & 0xFF;
961 int blue
= rgb
& 0xFF;
963 return new Color(red
, green
, blue
);
966 if (attr
.getBackColor().equals(jexer
.bits
.Color
.BLACK
)) {
968 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.RED
)) {
970 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.BLUE
)) {
972 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.GREEN
)) {
974 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.YELLOW
)) {
976 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.CYAN
)) {
978 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.MAGENTA
)) {
980 } else if (attr
.getBackColor().equals(jexer
.bits
.Color
.WHITE
)) {
983 throw new IllegalArgumentException("Invalid color: " +
984 attr
.getBackColor().getValue());
988 * Figure out what textAdjustX, textAdjustY, textAdjustHeight, and
989 * textAdjustWidth should be, based on the location of a vertical bar and
992 private void getFontAdjustments() {
993 BufferedImage image
= null;
995 // What SHOULD happen is that the topmost/leftmost white pixel is at
996 // position (gr2x, gr2y). But it might also be off by a pixel in
999 Graphics2D gr2
= null;
1002 image
= new BufferedImage(fontTextWidth
* 2, fontTextHeight
* 2,
1003 BufferedImage
.TYPE_INT_ARGB
);
1005 gr2
= image
.createGraphics();
1006 gr2
.setFont(swing
.getFont());
1007 gr2
.setColor(java
.awt
.Color
.BLACK
);
1008 gr2
.fillRect(0, 0, fontTextWidth
* 2, fontTextHeight
* 2);
1009 gr2
.setColor(java
.awt
.Color
.WHITE
);
1010 char [] chars
= new char[1];
1011 chars
[0] = jexer
.bits
.GraphicsChars
.SINGLE_BAR
;
1012 gr2
.drawChars(chars
, 0, 1, gr2x
, gr2y
+ fontTextHeight
- maxDescent
);
1013 chars
[0] = jexer
.bits
.GraphicsChars
.VERTICAL_BAR
;
1014 gr2
.drawChars(chars
, 0, 1, gr2x
, gr2y
+ fontTextHeight
- maxDescent
);
1017 int top
= fontTextHeight
* 2;
1019 int left
= fontTextWidth
* 2;
1023 textAdjustHeight
= 0;
1024 textAdjustWidth
= 0;
1026 for (int x
= 0; x
< fontTextWidth
* 2; x
++) {
1027 for (int y
= 0; y
< fontTextHeight
* 2; y
++) {
1030 System.err.println("H X: " + x + " Y: " + y + " " +
1031 image.getRGB(x, y));
1034 if ((image
.getRGB(x
, y
) & 0xFFFFFF) != 0) {
1035 // Pixel is present.
1052 textAdjustX
= (gr2x
- left
);
1053 textAdjustWidth
= fontTextWidth
- (right
- left
+ 1);
1056 textAdjustY
= (gr2y
- top
);
1057 textAdjustHeight
= fontTextHeight
- (bottom
- top
+ 1);
1059 // System.err.println("top " + top + " bottom " + bottom);
1060 // System.err.println("left " + left + " right " + right);
1062 // Special case: do not believe fonts that claim to be wider than
1064 if (fontTextWidth
>= fontTextHeight
) {
1066 textAdjustWidth
= 0;
1067 fontTextWidth
= fontTextHeight
/ 2;
1072 * Figure out my font dimensions. This code path works OK for the JFrame
1073 * case, and can be called immediately after JFrame creation.
1075 private void getFontDimensions() {
1076 swing
.setFont(font
);
1077 Graphics gr
= swing
.getGraphics();
1081 getFontDimensions(gr
);
1085 * Figure out my font dimensions. This code path is needed to lazy-load
1086 * the information inside paint().
1088 * @param gr Graphics object to use
1090 private void getFontDimensions(final Graphics gr
) {
1091 swing
.setFont(font
);
1092 FontMetrics fm
= gr
.getFontMetrics();
1093 maxDescent
= fm
.getMaxDescent();
1094 Rectangle2D bounds
= fm
.getMaxCharBounds(gr
);
1095 int leading
= fm
.getLeading();
1096 fontTextWidth
= (int)Math
.round(bounds
.getWidth());
1097 // fontTextHeight = (int)Math.round(bounds.getHeight()) - maxDescent;
1099 // This produces the same number, but works better for ugly
1101 fontTextHeight
= fm
.getMaxAscent() + maxDescent
- leading
;
1103 getFontAdjustments();
1104 textHeight
= fontTextHeight
+ textAdjustHeight
;
1105 textWidth
= fontTextWidth
+ textAdjustWidth
;
1107 if (sessionInfo
!= null) {
1108 sessionInfo
.setTextCellDimensions(textWidth
, textHeight
);
1110 gotFontDimensions
= true;
1114 * Resize the physical screen to match the logical screen dimensions.
1116 * @param resizeComponent if true, resize the Swing component
1118 private void resizeToScreen(final boolean resizeComponent
) {
1119 if (resizeComponent
) {
1120 swing
.setDimensions(textWidth
* width
, textHeight
* height
);
1126 * Resize the physical screen to match the logical screen dimensions.
1129 public void resizeToScreen() {
1130 resizeToScreen(false);
1134 * Draw one cell's image to the screen.
1136 * @param gr the Swing Graphics context
1137 * @param cell the Cell to draw
1138 * @param xPixel the x-coordinate to render to. 0 means the
1139 * left-most pixel column.
1140 * @param yPixel the y-coordinate to render to. 0 means the top-most
1143 private void drawImage(final Graphics gr
, final Cell cell
,
1144 final int xPixel
, final int yPixel
) {
1147 System.err.println("drawImage(): " + xPixel + " " + yPixel +
1151 // Draw the background rectangle, then the foreground character.
1152 assert (cell
.isImage());
1153 gr
.setColor(cell
.getBackground());
1154 gr
.fillRect(xPixel
, yPixel
, textWidth
, textHeight
);
1156 BufferedImage image
= cell
.getImage();
1157 if (image
!= null) {
1158 if (swing
.getFrame() != null) {
1159 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getFrame());
1161 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getComponent());
1168 * Draw one glyph to the screen.
1170 * @param gr the Swing Graphics context
1171 * @param cell the Cell to draw
1172 * @param xPixel the x-coordinate to render to. 0 means the
1173 * left-most pixel column.
1174 * @param yPixel the y-coordinate to render to. 0 means the top-most
1177 private void drawGlyph(final Graphics gr
, final Cell cell
,
1178 final int xPixel
, final int yPixel
) {
1181 System.err.println("drawGlyph(): " + xPixel + " " + yPixel +
1185 BufferedImage image
= null;
1186 if (cell
.isBlink() && !cursorBlinkVisible
) {
1187 image
= glyphCacheBlink
.get(cell
);
1189 image
= glyphCache
.get(cell
);
1191 if (image
!= null) {
1192 if (swing
.getFrame() != null) {
1193 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getFrame());
1195 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getComponent());
1200 // Generate glyph and draw it.
1201 Graphics2D gr2
= null;
1204 if ((SwingComponent
.tripleBuffer
) && (swing
.getFrame() != null)) {
1205 image
= new BufferedImage(textWidth
, textHeight
,
1206 BufferedImage
.TYPE_INT_ARGB
);
1207 gr2
= image
.createGraphics();
1208 gr2
.setFont(swing
.getFont());
1212 gr2
= (Graphics2D
) gr
;
1215 Cell cellColor
= new Cell(cell
);
1217 // Check for reverse
1218 if (cell
.isReverse()) {
1219 cellColor
.setForeColor(cell
.getBackColor());
1220 cellColor
.setBackColor(cell
.getForeColor());
1223 // Draw the background rectangle, then the foreground character.
1224 gr2
.setColor(attrToBackgroundColor(cellColor
));
1225 gr2
.fillRect(gr2x
, gr2y
, textWidth
, textHeight
);
1227 // Handle blink and underline
1229 || (cell
.isBlink() && cursorBlinkVisible
)
1231 gr2
.setColor(attrToForegroundColor(cellColor
));
1232 char [] chars
= Character
.toChars(cell
.getChar());
1233 gr2
.drawChars(chars
, 0, chars
.length
, gr2x
+ textAdjustX
,
1234 gr2y
+ textHeight
- maxDescent
+ textAdjustY
);
1236 if (cell
.isUnderline()) {
1237 gr2
.fillRect(gr2x
, gr2y
+ textHeight
- 2, textWidth
, 2);
1241 if ((SwingComponent
.tripleBuffer
) && (swing
.getFrame() != null)) {
1244 // We need a new key that will not be mutated by
1246 Cell key
= new Cell(cell
);
1247 if (cell
.isBlink() && !cursorBlinkVisible
) {
1248 glyphCacheBlink
.put(key
, image
);
1250 glyphCache
.put(key
, image
);
1253 if (swing
.getFrame() != null) {
1254 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getFrame());
1256 gr
.drawImage(image
, xPixel
, yPixel
, swing
.getComponent());
1263 * Check if the cursor is visible, and if so draw it.
1265 * @param gr the Swing Graphics context
1267 private void drawCursor(final Graphics gr
) {
1272 && (cursorY
<= height
- 1)
1273 && (cursorX
<= width
- 1)
1274 && cursorBlinkVisible
1276 int xPixel
= cursorX
* textWidth
+ left
;
1277 int yPixel
= cursorY
* textHeight
+ top
;
1278 Cell lCell
= logical
[cursorX
][cursorY
];
1279 int cursorWidth
= textWidth
;
1280 switch (lCell
.getWidth()) {
1289 xPixel
-= textWidth
;
1292 gr
.setColor(attrToForegroundColor(lCell
));
1293 switch (cursorStyle
) {
1297 gr
.fillRect(xPixel
, yPixel
+ textHeight
- 2, cursorWidth
, 2);
1300 gr
.fillRect(xPixel
, yPixel
, cursorWidth
, textHeight
);
1303 gr
.drawRect(xPixel
, yPixel
, cursorWidth
- 1, textHeight
- 1);
1310 * Reset the blink timer.
1312 private void resetBlinkTimer() {
1313 lastBlinkTime
= System
.currentTimeMillis();
1314 cursorBlinkVisible
= true;
1318 * Paint redraws the whole screen.
1320 * @param gr the Swing Graphics context
1322 public void paint(final Graphics gr
) {
1324 if (gotFontDimensions
== false) {
1325 // Lazy-load the text width/height
1326 getFontDimensions(gr
);
1328 System.err.println("textWidth " + textWidth +
1329 " textHeight " + textHeight);
1330 System.err.println("FONT: " + swing.getFont() + " font " + font);
1334 if ((swing
.getFrame() != null)
1335 && (swing
.getBufferStrategy() != null)
1336 && (SwingUtilities
.isEventDispatchThread())
1338 // System.err.println("paint(), skip first paint on swing thread");
1343 int xCellMax
= width
;
1345 int yCellMax
= height
;
1347 Rectangle bounds
= gr
.getClipBounds();
1348 if (bounds
!= null) {
1349 // Only update what is in the bounds
1350 xCellMin
= textColumn(bounds
.x
);
1351 xCellMax
= textColumn(bounds
.x
+ bounds
.width
);
1352 if (xCellMax
> width
) {
1355 if (xCellMin
>= xCellMax
) {
1356 xCellMin
= xCellMax
- 2;
1361 yCellMin
= textRow(bounds
.y
);
1362 yCellMax
= textRow(bounds
.y
+ bounds
.height
);
1363 if (yCellMax
> height
) {
1366 if (yCellMin
>= yCellMax
) {
1367 yCellMin
= yCellMax
- 2;
1373 // We need a total repaint
1374 reallyCleared
= true;
1377 // Prevent updates to the screen's data from the TApplication
1379 synchronized (this) {
1382 System.err.printf("bounds %s X %d %d Y %d %d\n",
1383 bounds, xCellMin, xCellMax, yCellMin, yCellMax);
1386 for (int y
= yCellMin
; y
< yCellMax
; y
++) {
1387 for (int x
= xCellMin
; x
< xCellMax
; x
++) {
1389 int xPixel
= x
* textWidth
+ left
;
1390 int yPixel
= y
* textHeight
+ top
;
1392 Cell lCell
= logical
[x
][y
];
1393 Cell pCell
= physical
[x
][y
];
1395 if (!lCell
.equals(pCell
)
1398 || (swing
.getFrame() == null)) {
1400 if (lCell
.isImage()) {
1401 drawImage(gr
, lCell
, xPixel
, yPixel
);
1403 drawGlyph(gr
, lCell
, xPixel
, yPixel
);
1406 // Physical is always updated
1407 physical
[x
][y
].setTo(lCell
);
1413 reallyCleared
= false;
1414 } // synchronized (this)
1418 * Restore terminal to normal state.
1420 public void shutdown() {
1425 * Push the logical screen to the physical device.
1427 private void drawToSwing() {
1430 System.err.printf("drawToSwing(): reallyCleared %s dirty %s\n",
1431 reallyCleared, dirty);
1434 // If reallyCleared is set, we have to draw everything.
1435 if ((swing
.getFrame() != null)
1436 && (swing
.getBufferStrategy() != null)
1437 && (reallyCleared
== true)
1439 // Triple-buffering: we have to redraw everything on this thread.
1440 Graphics gr
= swing
.getBufferStrategy().getDrawGraphics();
1443 swing
.getBufferStrategy().show();
1444 Toolkit
.getDefaultToolkit().sync();
1446 } else if (((swing
.getFrame() != null)
1447 && (swing
.getBufferStrategy() == null))
1448 || (reallyCleared
== true)
1450 // Repaint everything on the Swing thread.
1451 // System.err.println("REPAINT ALL");
1456 if ((swing
.getFrame() != null) && (swing
.getBufferStrategy() != null)) {
1457 Graphics gr
= swing
.getBufferStrategy().getDrawGraphics();
1459 synchronized (this) {
1460 for (int y
= 0; y
< height
; y
++) {
1461 for (int x
= 0; x
< width
; x
++) {
1462 Cell lCell
= logical
[x
][y
];
1463 Cell pCell
= physical
[x
][y
];
1465 int xPixel
= x
* textWidth
+ left
;
1466 int yPixel
= y
* textHeight
+ top
;
1468 if (!lCell
.equals(pCell
)
1472 || (lCell
.isBlink())
1474 if (lCell
.isImage()) {
1475 drawImage(gr
, lCell
, xPixel
, yPixel
);
1477 drawGlyph(gr
, lCell
, xPixel
, yPixel
);
1479 physical
[x
][y
].setTo(lCell
);
1484 } // synchronized (this)
1487 swing
.getBufferStrategy().show();
1488 Toolkit
.getDefaultToolkit().sync();
1492 // Swing thread version: request a repaint, but limit it to the area
1493 // that has changed.
1495 // Find the minimum-size damaged region.
1496 int xMin
= swing
.getWidth();
1498 int yMin
= swing
.getHeight();
1501 synchronized (this) {
1502 for (int y
= 0; y
< height
; y
++) {
1503 for (int x
= 0; x
< width
; x
++) {
1504 Cell lCell
= logical
[x
][y
];
1505 Cell pCell
= physical
[x
][y
];
1507 int xPixel
= x
* textWidth
+ left
;
1508 int yPixel
= y
* textHeight
+ top
;
1510 if (!lCell
.equals(pCell
)
1516 if (xPixel
< xMin
) {
1519 if (xPixel
+ textWidth
> xMax
) {
1520 xMax
= xPixel
+ textWidth
;
1522 if (yPixel
< yMin
) {
1525 if (yPixel
+ textHeight
> yMax
) {
1526 yMax
= yPixel
+ textHeight
;
1532 if (xMin
+ textWidth
>= xMax
) {
1535 if (yMin
+ textHeight
>= yMax
) {
1539 // Repaint the desired area
1541 System.err.printf("REPAINT X %d %d Y %d %d\n", xMin, xMax,
1545 if ((swing
.getFrame() != null) && (swing
.getBufferStrategy() != null)) {
1546 // This path should never be taken, but is left here for
1548 Graphics gr
= swing
.getBufferStrategy().getDrawGraphics();
1549 Rectangle bounds
= new Rectangle(xMin
, yMin
, xMax
- xMin
,
1554 swing
.getBufferStrategy().show();
1555 Toolkit
.getDefaultToolkit().sync();
1557 // Repaint on the Swing thread.
1558 swing
.repaint(xMin
, yMin
, xMax
- xMin
, yMax
- yMin
);
1563 * Convert pixel column position to text cell column position.
1565 * @param x pixel column position
1566 * @return text cell column position
1568 public int textColumn(final int x
) {
1569 int column
= ((x
- left
) / textWidth
);
1573 if (column
> width
- 1) {
1580 * Convert pixel row position to text cell row position.
1582 * @param y pixel row position
1583 * @return text cell row position
1585 public int textRow(final int y
) {
1586 int row
= ((y
- top
) / textHeight
);
1590 if (row
> height
- 1) {
1597 * Getter for sessionInfo.
1599 * @return the SessionInfo
1601 public SessionInfo
getSessionInfo() {
1606 * Getter for the underlying Swing component.
1608 * @return the SwingComponent
1610 public SwingComponent
getSwingComponent() {
1614 // ------------------------------------------------------------------------
1615 // KeyListener ------------------------------------------------------------
1616 // ------------------------------------------------------------------------
1619 * Pass Swing keystrokes into the event queue.
1621 * @param key keystroke received
1623 public void keyReleased(final KeyEvent key
) {
1624 // Ignore release events
1628 * Pass Swing keystrokes into the event queue.
1630 * @param key keystroke received
1632 public void keyTyped(final KeyEvent key
) {
1633 // Ignore typed events
1637 * Pass Swing keystrokes into the event queue.
1639 * @param key keystroke received
1641 public void keyPressed(final KeyEvent key
) {
1642 boolean alt
= false;
1643 boolean shift
= false;
1644 boolean ctrl
= false;
1646 boolean isKey
= false;
1647 if (key
.isActionKey()) {
1650 ch
= key
.getKeyChar();
1652 alt
= key
.isAltDown();
1653 ctrl
= key
.isControlDown();
1654 shift
= key
.isShiftDown();
1657 System.err.printf("Swing Key: %s\n", key);
1658 System.err.printf(" isKey: %s\n", isKey);
1659 System.err.printf(" alt: %s\n", alt);
1660 System.err.printf(" ctrl: %s\n", ctrl);
1661 System.err.printf(" shift: %s\n", shift);
1662 System.err.printf(" ch: %s\n", ch);
1665 // Special case: not return the bare modifier presses
1666 switch (key
.getKeyCode()) {
1667 case KeyEvent
.VK_ALT
:
1669 case KeyEvent
.VK_ALT_GRAPH
:
1671 case KeyEvent
.VK_CONTROL
:
1673 case KeyEvent
.VK_SHIFT
:
1675 case KeyEvent
.VK_META
:
1681 TKeypress keypress
= null;
1683 switch (key
.getKeyCode()) {
1684 case KeyEvent
.VK_F1
:
1685 keypress
= new TKeypress(true, TKeypress
.F1
, ' ',
1688 case KeyEvent
.VK_F2
:
1689 keypress
= new TKeypress(true, TKeypress
.F2
, ' ',
1692 case KeyEvent
.VK_F3
:
1693 keypress
= new TKeypress(true, TKeypress
.F3
, ' ',
1696 case KeyEvent
.VK_F4
:
1697 keypress
= new TKeypress(true, TKeypress
.F4
, ' ',
1700 case KeyEvent
.VK_F5
:
1701 keypress
= new TKeypress(true, TKeypress
.F5
, ' ',
1704 case KeyEvent
.VK_F6
:
1705 keypress
= new TKeypress(true, TKeypress
.F6
, ' ',
1708 case KeyEvent
.VK_F7
:
1709 keypress
= new TKeypress(true, TKeypress
.F7
, ' ',
1712 case KeyEvent
.VK_F8
:
1713 keypress
= new TKeypress(true, TKeypress
.F8
, ' ',
1716 case KeyEvent
.VK_F9
:
1717 keypress
= new TKeypress(true, TKeypress
.F9
, ' ',
1720 case KeyEvent
.VK_F10
:
1721 keypress
= new TKeypress(true, TKeypress
.F10
, ' ',
1724 case KeyEvent
.VK_F11
:
1725 keypress
= new TKeypress(true, TKeypress
.F11
, ' ',
1728 case KeyEvent
.VK_F12
:
1729 keypress
= new TKeypress(true, TKeypress
.F12
, ' ',
1732 case KeyEvent
.VK_HOME
:
1733 keypress
= new TKeypress(true, TKeypress
.HOME
, ' ',
1736 case KeyEvent
.VK_END
:
1737 keypress
= new TKeypress(true, TKeypress
.END
, ' ',
1740 case KeyEvent
.VK_PAGE_UP
:
1741 keypress
= new TKeypress(true, TKeypress
.PGUP
, ' ',
1744 case KeyEvent
.VK_PAGE_DOWN
:
1745 keypress
= new TKeypress(true, TKeypress
.PGDN
, ' ',
1748 case KeyEvent
.VK_INSERT
:
1749 keypress
= new TKeypress(true, TKeypress
.INS
, ' ',
1752 case KeyEvent
.VK_DELETE
:
1753 keypress
= new TKeypress(true, TKeypress
.DEL
, ' ',
1756 case KeyEvent
.VK_RIGHT
:
1757 keypress
= new TKeypress(true, TKeypress
.RIGHT
, ' ',
1760 case KeyEvent
.VK_LEFT
:
1761 keypress
= new TKeypress(true, TKeypress
.LEFT
, ' ',
1764 case KeyEvent
.VK_UP
:
1765 keypress
= new TKeypress(true, TKeypress
.UP
, ' ',
1768 case KeyEvent
.VK_DOWN
:
1769 keypress
= new TKeypress(true, TKeypress
.DOWN
, ' ',
1772 case KeyEvent
.VK_TAB
:
1773 // Special case: distinguish TAB vs BTAB
1775 keypress
= kbShiftTab
;
1780 case KeyEvent
.VK_ENTER
:
1781 keypress
= new TKeypress(true, TKeypress
.ENTER
, ' ',
1784 case KeyEvent
.VK_ESCAPE
:
1785 keypress
= new TKeypress(true, TKeypress
.ESC
, ' ',
1788 case KeyEvent
.VK_BACK_SPACE
:
1789 keypress
= kbBackspace
;
1792 // Unsupported, ignore
1797 if (keypress
== null) {
1800 // Disambiguate ^H from Backspace.
1801 if (KeyEvent
.getKeyText(key
.getKeyCode()).equals("H")) {
1803 keypress
= kbBackspace
;
1805 // We are emulating Xterm here, where the backspace key
1806 // on the keyboard returns ^?.
1807 keypress
= kbBackspaceDel
;
1821 keypress
= kbShiftTab
;
1830 if (!alt
&& ctrl
&& !shift
) {
1831 // Control character, replace ch with 'A', 'B', etc.
1832 ch
= KeyEvent
.getKeyText(key
.getKeyCode()).charAt(0);
1834 // Not a special key, put it together
1835 keypress
= new TKeypress(false, 0, ch
, alt
, ctrl
, shift
);
1839 // Save it and we are done.
1840 synchronized (eventQueue
) {
1841 eventQueue
.add(new TKeypressEvent(keypress
));
1844 if (listener
!= null) {
1845 synchronized (listener
) {
1846 listener
.notifyAll();
1851 // ------------------------------------------------------------------------
1852 // WindowListener ---------------------------------------------------------
1853 // ------------------------------------------------------------------------
1856 * Pass window events into the event queue.
1858 * @param event window event received
1860 public void windowActivated(final WindowEvent event
) {
1861 // Force a total repaint
1862 synchronized (this) {
1868 * Pass window events into the event queue.
1870 * @param event window event received
1872 public void windowClosed(final WindowEvent event
) {
1877 * Pass window events into the event queue.
1879 * @param event window event received
1881 public void windowClosing(final WindowEvent event
) {
1882 // Drop a cmBackendDisconnect and walk away
1883 synchronized (eventQueue
) {
1884 eventQueue
.add(new TCommandEvent(cmBackendDisconnect
));
1887 if (listener
!= null) {
1888 synchronized (listener
) {
1889 listener
.notifyAll();
1895 * Pass window events into the event queue.
1897 * @param event window event received
1899 public void windowDeactivated(final WindowEvent event
) {
1904 * Pass window events into the event queue.
1906 * @param event window event received
1908 public void windowDeiconified(final WindowEvent event
) {
1913 * Pass window events into the event queue.
1915 * @param event window event received
1917 public void windowIconified(final WindowEvent event
) {
1922 * Pass window events into the event queue.
1924 * @param event window event received
1926 public void windowOpened(final WindowEvent event
) {
1930 // ------------------------------------------------------------------------
1931 // ComponentListener ------------------------------------------------------
1932 // ------------------------------------------------------------------------
1935 * Pass component events into the event queue.
1937 * @param event component event received
1939 public void componentHidden(final ComponentEvent event
) {
1944 * Pass component events into the event queue.
1946 * @param event component event received
1948 public void componentShown(final ComponentEvent event
) {
1953 * Pass component events into the event queue.
1955 * @param event component event received
1957 public void componentMoved(final ComponentEvent event
) {
1962 * Pass component events into the event queue.
1964 * @param event component event received
1966 public void componentResized(final ComponentEvent event
) {
1967 if (gotFontDimensions
== false) {
1968 // We are still waiting to get font information. Don't pass a
1970 // System.err.println("size " + swing.getComponent().getSize());
1974 if (sessionInfo
== null) {
1975 // This is the initial component resize in construction, bail
1980 // Drop a new TResizeEvent into the queue
1981 sessionInfo
.queryWindowSize();
1982 synchronized (eventQueue
) {
1983 TResizeEvent windowResize
= new TResizeEvent(TResizeEvent
.Type
.SCREEN
,
1984 sessionInfo
.getWindowWidth(), sessionInfo
.getWindowHeight());
1985 eventQueue
.add(windowResize
);
1988 System.err.println("Add resize event: " + windowResize.getWidth() +
1989 " x " + windowResize.getHeight());
1992 if (listener
!= null) {
1993 synchronized (listener
) {
1994 listener
.notifyAll();
1999 // ------------------------------------------------------------------------
2000 // MouseMotionListener ----------------------------------------------------
2001 // ------------------------------------------------------------------------
2004 * Pass mouse events into the event queue.
2006 * @param mouse mouse event received
2008 public void mouseDragged(final MouseEvent mouse
) {
2009 int modifiers
= mouse
.getModifiersEx();
2010 boolean eventMouse1
= false;
2011 boolean eventMouse2
= false;
2012 boolean eventMouse3
= false;
2013 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
2016 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
2019 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
2022 mouse1
= eventMouse1
;
2023 mouse2
= eventMouse2
;
2024 mouse3
= eventMouse3
;
2025 int x
= textColumn(mouse
.getX());
2026 int y
= textRow(mouse
.getY());
2028 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_MOTION
,
2029 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
2031 synchronized (eventQueue
) {
2032 eventQueue
.add(mouseEvent
);
2035 if (listener
!= null) {
2036 synchronized (listener
) {
2037 listener
.notifyAll();
2043 * Pass mouse events into the event queue.
2045 * @param mouse mouse event received
2047 public void mouseMoved(final MouseEvent mouse
) {
2048 int x
= textColumn(mouse
.getX());
2049 int y
= textRow(mouse
.getY());
2050 if ((x
== oldMouseX
) && (y
== oldMouseY
)) {
2051 // Bail out, we've moved some pixels but not a whole text cell.
2057 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_MOTION
,
2058 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
2060 synchronized (eventQueue
) {
2061 eventQueue
.add(mouseEvent
);
2064 if (listener
!= null) {
2065 synchronized (listener
) {
2066 listener
.notifyAll();
2071 // ------------------------------------------------------------------------
2072 // MouseListener ----------------------------------------------------------
2073 // ------------------------------------------------------------------------
2076 * Pass mouse events into the event queue.
2078 * @param mouse mouse event received
2080 public void mouseClicked(final MouseEvent mouse
) {
2085 * Pass mouse events into the event queue.
2087 * @param mouse mouse event received
2089 public void mouseEntered(final MouseEvent mouse
) {
2094 * Pass mouse events into the event queue.
2096 * @param mouse mouse event received
2098 public void mouseExited(final MouseEvent mouse
) {
2103 * Pass mouse events into the event queue.
2105 * @param mouse mouse event received
2107 public void mousePressed(final MouseEvent mouse
) {
2108 int modifiers
= mouse
.getModifiersEx();
2109 boolean eventMouse1
= false;
2110 boolean eventMouse2
= false;
2111 boolean eventMouse3
= false;
2112 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
2115 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
2118 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
2121 mouse1
= eventMouse1
;
2122 mouse2
= eventMouse2
;
2123 mouse3
= eventMouse3
;
2124 int x
= textColumn(mouse
.getX());
2125 int y
= textRow(mouse
.getY());
2127 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_DOWN
,
2128 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, false, false);
2130 synchronized (eventQueue
) {
2131 eventQueue
.add(mouseEvent
);
2134 if (listener
!= null) {
2135 synchronized (listener
) {
2136 listener
.notifyAll();
2142 * Pass mouse events into the event queue.
2144 * @param mouse mouse event received
2146 public void mouseReleased(final MouseEvent mouse
) {
2147 int modifiers
= mouse
.getModifiersEx();
2148 boolean eventMouse1
= false;
2149 boolean eventMouse2
= false;
2150 boolean eventMouse3
= false;
2151 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
2154 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
2157 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
2172 int x
= textColumn(mouse
.getX());
2173 int y
= textRow(mouse
.getY());
2175 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_UP
,
2176 x
, y
, x
, y
, eventMouse1
, eventMouse2
, eventMouse3
, false, false);
2178 synchronized (eventQueue
) {
2179 eventQueue
.add(mouseEvent
);
2182 if (listener
!= null) {
2183 synchronized (listener
) {
2184 listener
.notifyAll();
2189 // ------------------------------------------------------------------------
2190 // MouseWheelListener -----------------------------------------------------
2191 // ------------------------------------------------------------------------
2194 * Pass mouse events into the event queue.
2196 * @param mouse mouse event received
2198 public void mouseWheelMoved(final MouseWheelEvent mouse
) {
2199 int modifiers
= mouse
.getModifiersEx();
2200 boolean eventMouse1
= false;
2201 boolean eventMouse2
= false;
2202 boolean eventMouse3
= false;
2203 boolean mouseWheelUp
= false;
2204 boolean mouseWheelDown
= false;
2205 if ((modifiers
& MouseEvent
.BUTTON1_DOWN_MASK
) != 0) {
2208 if ((modifiers
& MouseEvent
.BUTTON2_DOWN_MASK
) != 0) {
2211 if ((modifiers
& MouseEvent
.BUTTON3_DOWN_MASK
) != 0) {
2214 mouse1
= eventMouse1
;
2215 mouse2
= eventMouse2
;
2216 mouse3
= eventMouse3
;
2217 int x
= textColumn(mouse
.getX());
2218 int y
= textRow(mouse
.getY());
2219 if (mouse
.getWheelRotation() > 0) {
2220 mouseWheelDown
= true;
2222 if (mouse
.getWheelRotation() < 0) {
2223 mouseWheelUp
= true;
2226 TMouseEvent mouseEvent
= new TMouseEvent(TMouseEvent
.Type
.MOUSE_DOWN
,
2227 x
, y
, x
, y
, mouse1
, mouse2
, mouse3
, mouseWheelUp
, mouseWheelDown
);
2229 synchronized (eventQueue
) {
2230 eventQueue
.add(mouseEvent
);
2233 if (listener
!= null) {
2234 synchronized (listener
) {
2235 listener
.notifyAll();