*
* The MIT License (MIT)
*
- * Copyright (C) 2017 Kevin Lamonte
+ * Copyright (C) 2019 Kevin Lamonte
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferStrategy;
+import java.io.IOException;
+import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
/**
* Wrapper for integrating with Swing, because JFrame and JComponent have
*/
class SwingComponent {
- /**
- * If true, use triple buffering when drawing to a JFrame.
- */
- public static boolean tripleBuffer = false;
+ // ------------------------------------------------------------------------
+ // Variables --------------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
- * Get the BufferStrategy object needed for triple-buffering.
- *
- * @return the BufferStrategy
- * @throws IllegalArgumentException if this function is called when
- * not rendering to a JFrame
+ * If true, use triple buffering when drawing to a JFrame.
*/
- public BufferStrategy getBufferStrategy() {
- if (frame != null) {
- return frame.getBufferStrategy();
- } else {
- throw new IllegalArgumentException("BufferStrategy not used " +
- "for JComponent access");
- }
- }
+ public static boolean tripleBuffer = true;
/**
* The frame reference, if we are drawing to a JFrame.
private JComponent component;
/**
- * Get the JFrame reference.
- *
- * @return the frame, or null if this is drawing to a JComponent
+ * An optional border in pixels to add.
*/
- public JFrame getFrame() {
- return frame;
- }
+ private static final int BORDER = 1;
/**
- * Get the JComponent reference.
- *
- * @return the component, or null if this is drawing to a JFrame
+ * Adjustable Insets for this component. This has the effect of adding a
+ * black border around the drawing area.
*/
- public JComponent getComponent() {
- return component;
- }
+ Insets adjustInsets = new Insets(BORDER + 5, BORDER, BORDER, BORDER);
+
+ // ------------------------------------------------------------------------
+ // Constructors -----------------------------------------------------------
+ // ------------------------------------------------------------------------
/**
* Construct using a JFrame.
setupComponent();
}
+ // ------------------------------------------------------------------------
+ // SwingComponent ---------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get the BufferStrategy object needed for triple-buffering.
+ *
+ * @return the BufferStrategy
+ * @throws IllegalArgumentException if this function is called when
+ * not rendering to a JFrame
+ */
+ public BufferStrategy getBufferStrategy() {
+ if (frame != null) {
+ return frame.getBufferStrategy();
+ } else {
+ throw new IllegalArgumentException("BufferStrategy not used " +
+ "for JComponent access");
+ }
+ }
+
+ /**
+ * Get the JFrame reference.
+ *
+ * @return the frame, or null if this is drawing to a JComponent
+ */
+ public JFrame getFrame() {
+ return frame;
+ }
+
+ /**
+ * Get the JComponent reference.
+ *
+ * @return the component, or null if this is drawing to a JFrame
+ */
+ public JComponent getComponent() {
+ return component;
+ }
+
/**
* Setup to render to an existing JComponent.
*/
public void setupComponent() {
component.setBackground(Color.black);
- // Kill the X11 cursor
- // Transparent 16 x 16 pixel cursor image.
- BufferedImage cursorImg = new BufferedImage(16, 16,
- BufferedImage.TYPE_INT_ARGB);
- // Create a new blank cursor.
- Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
- cursorImg, new Point(0, 0), "blank cursor");
- component.setCursor(blankCursor);
+ if (System.getProperty("jexer.Swing.mouseImage") != null) {
+ component.setCursor(getMouseImage());
+ } else if (System.getProperty("jexer.Swing.mouseStyle") != null) {
+ component.setCursor(getMouseCursor());
+ } else if (System.getProperty("jexer.textMouse",
+ "true").equals("false")
+ ) {
+ // If the user has suppressed the text mouse, don't kill the X11
+ // mouse.
+ component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ } else {
+ // Kill the X11 cursor
+ // Transparent 16 x 16 pixel cursor image.
+ BufferedImage cursorImg = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ // Create a new blank cursor.
+ Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
+ cursorImg, new Point(0, 0), "blank cursor");
+ component.setCursor(blankCursor);
+ }
// Be capable of seeing Tab / Shift-Tab
component.setFocusTraversalKeysEnabled(false);
frame.setBackground(Color.black);
frame.pack();
- // Kill the X11 cursor
- // Transparent 16 x 16 pixel cursor image.
- BufferedImage cursorImg = new BufferedImage(16, 16,
- BufferedImage.TYPE_INT_ARGB);
- // Create a new blank cursor.
- Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
- cursorImg, new Point(0, 0), "blank cursor");
- frame.setCursor(blankCursor);
+ if (System.getProperty("jexer.Swing.mouseImage") != null) {
+ frame.setCursor(getMouseImage());
+ } else if (System.getProperty("jexer.Swing.mouseStyle") != null) {
+ frame.setCursor(getMouseCursor());
+ } else if (System.getProperty("jexer.textMouse",
+ "true").equals("false")
+ ) {
+ // If the user has suppressed the text mouse, don't kill the X11
+ // mouse.
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ } else {
+ // Kill the X11 cursor
+ // Transparent 16 x 16 pixel cursor image.
+ BufferedImage cursorImg = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ // Create a new blank cursor.
+ Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
+ cursorImg, new Point(0, 0), "blank cursor");
+ frame.setCursor(blankCursor);
+ }
// Be capable of seeing Tab / Shift-Tab
frame.setFocusTraversalKeysEnabled(false);
}
}
+ /**
+ * Load an image named in jexer.Swing.mouseImage as the mouse cursor.
+ * The image must be on the classpath.
+ *
+ * @return the cursor
+ */
+ private Cursor getMouseImage() {
+ Cursor cursor = Cursor.getDefaultCursor();
+ String filename = System.getProperty("jexer.Swing.mouseImage");
+ assert (filename != null);
+
+ try {
+ ClassLoader loader = Thread.currentThread().
+ getContextClassLoader();
+
+ java.net.URL url = loader.getResource(filename);
+ if (url == null) {
+ // User named a file, but it's not on the classpath. Bail
+ // out.
+ return cursor;
+ }
+
+ BufferedImage cursorImage = ImageIO.read(url);
+ java.awt.Dimension cursorSize = Toolkit.getDefaultToolkit().
+ getBestCursorSize(
+ cursorImage.getWidth(), cursorImage.getHeight());
+
+ cursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImage,
+ new Point((int) Math.min(cursorImage.getWidth() / 2,
+ cursorSize.getWidth() - 1),
+ (int) Math.min(cursorImage.getHeight() / 2,
+ cursorSize.getHeight() - 1)),
+ "custom cursor");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return cursor;
+ }
+
+ /**
+ * Get the appropriate mouse cursor based on jexer.Swing.mouseStyle.
+ *
+ * @return the cursor
+ */
+ private Cursor getMouseCursor() {
+ Cursor cursor = Cursor.getDefaultCursor();
+ String style = System.getProperty("jexer.Swing.mouseStyle");
+ assert (style != null);
+
+ style = style.toLowerCase();
+
+ if (style.equals("none")) {
+ // Transparent 16 x 16 pixel cursor image.
+ BufferedImage cursorImg = new BufferedImage(16, 16,
+ BufferedImage.TYPE_INT_ARGB);
+ // Create a new blank cursor.
+ cursor = Toolkit.getDefaultToolkit().createCustomCursor(
+ cursorImg, new Point(0, 0), "blank cursor");
+ } else if (style.equals("default")) {
+ cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
+ } else if (style.equals("hand")) {
+ cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ } else if (style.equals("text")) {
+ cursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
+ } else if (style.equals("move")) {
+ cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
+ } else if (style.equals("crosshair")) {
+ cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
+ }
+
+ return cursor;
+ }
+
/**
* Set the window title.
*
* @return the value of the insets property
*/
public Insets getInsets() {
+ Insets swingInsets = null;
if (frame != null) {
- return frame.getInsets();
+ swingInsets = frame.getInsets();
} else {
- return component.getInsets();
+ swingInsets = component.getInsets();
}
+ Insets result = new Insets(swingInsets.top + adjustInsets.top,
+ swingInsets.left + adjustInsets.left,
+ swingInsets.bottom + adjustInsets.bottom,
+ swingInsets.right + adjustInsets.right);
+ return result;
}
/**
* @param height the new height in pixels
*/
public void setDimensions(final int width, final int height) {
- // Figure out the thickness of borders and use that to set the final
- // size.
- Insets insets = getInsets();
-
- if (frame != null) {
- frame.setSize(width + insets.left + insets.right,
- height + insets.top + insets.bottom);
- } else {
- component.setSize(width + insets.left + insets.right,
- height + insets.top + insets.bottom);
+ if (SwingUtilities.isEventDispatchThread()) {
+ // We are in the Swing thread and can safely set the size.
+
+ // Figure out the thickness of borders and use that to set the
+ // final size.
+ if (frame != null) {
+ Insets insets = getInsets();
+ frame.setSize(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ } else {
+ Insets insets = getInsets();
+ component.setSize(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ }
+ return;
}
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ // Figure out the thickness of borders and use that to set
+ // the final size.
+ if (frame != null) {
+ Insets insets = getInsets();
+ frame.setSize(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ } else {
+ Insets insets = getInsets();
+ component.setSize(width + insets.left + insets.right,
+ height + insets.top + insets.bottom);
+ }
+ }
+ });
}
/**
}
}
+ /**
+ * Requests that this Component get the input focus, if this Component's
+ * top-level ancestor is already the focused Window.
+ */
+ public void requestFocusInWindow() {
+ if (frame != null) {
+ frame.requestFocusInWindow();
+ } else {
+ component.requestFocusInWindow();
+ }
+ }
+
}