PMD code sweep, #6 don't add MyWindow twice to MyApplication
[nikiroo-utils.git] / src / jexer / backend / SwingComponent.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 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.backend;
30
31 import java.awt.Color;
32 import java.awt.Cursor;
33 import java.awt.Font;
34 import java.awt.Graphics;
35 import java.awt.Insets;
36 import java.awt.Point;
37 import java.awt.Toolkit;
38 import java.awt.event.ComponentListener;
39 import java.awt.event.KeyListener;
40 import java.awt.event.MouseListener;
41 import java.awt.event.MouseMotionListener;
42 import java.awt.event.MouseWheelListener;
43 import java.awt.event.WindowListener;
44 import java.awt.image.BufferedImage;
45 import java.awt.image.BufferStrategy;
46 import javax.swing.JComponent;
47 import javax.swing.JFrame;
48
49 /**
50 * Wrapper for integrating with Swing, because JFrame and JComponent have
51 * separate hierarchies.
52 */
53 class SwingComponent {
54
55 // ------------------------------------------------------------------------
56 // Variables --------------------------------------------------------------
57 // ------------------------------------------------------------------------
58
59 /**
60 * If true, use triple buffering when drawing to a JFrame.
61 */
62 public static boolean tripleBuffer = true;
63
64 /**
65 * The frame reference, if we are drawing to a JFrame.
66 */
67 private JFrame frame;
68
69 /**
70 * The component reference, if we are drawing to a JComponent.
71 */
72 private JComponent component;
73
74 // ------------------------------------------------------------------------
75 // Constructors -----------------------------------------------------------
76 // ------------------------------------------------------------------------
77
78 /**
79 * Construct using a JFrame.
80 *
81 * @param frame the JFrame to draw to
82 */
83 public SwingComponent(final JFrame frame) {
84 this.frame = frame;
85 setupFrame();
86 }
87
88 /**
89 * Construct using a JComponent.
90 *
91 * @param component the JComponent to draw to
92 */
93 public SwingComponent(final JComponent component) {
94 this.component = component;
95 setupComponent();
96 }
97
98 // ------------------------------------------------------------------------
99 // SwingComponent ---------------------------------------------------------
100 // ------------------------------------------------------------------------
101
102 /**
103 * Get the BufferStrategy object needed for triple-buffering.
104 *
105 * @return the BufferStrategy
106 * @throws IllegalArgumentException if this function is called when
107 * not rendering to a JFrame
108 */
109 public BufferStrategy getBufferStrategy() {
110 if (frame != null) {
111 return frame.getBufferStrategy();
112 } else {
113 throw new IllegalArgumentException("BufferStrategy not used " +
114 "for JComponent access");
115 }
116 }
117
118 /**
119 * Get the JFrame reference.
120 *
121 * @return the frame, or null if this is drawing to a JComponent
122 */
123 public JFrame getFrame() {
124 return frame;
125 }
126
127 /**
128 * Get the JComponent reference.
129 *
130 * @return the component, or null if this is drawing to a JFrame
131 */
132 public JComponent getComponent() {
133 return component;
134 }
135
136 /**
137 * Setup to render to an existing JComponent.
138 */
139 public void setupComponent() {
140 component.setBackground(Color.black);
141
142 // Kill the X11 cursor
143 // Transparent 16 x 16 pixel cursor image.
144 BufferedImage cursorImg = new BufferedImage(16, 16,
145 BufferedImage.TYPE_INT_ARGB);
146 // Create a new blank cursor.
147 Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
148 cursorImg, new Point(0, 0), "blank cursor");
149 component.setCursor(blankCursor);
150
151 // Be capable of seeing Tab / Shift-Tab
152 component.setFocusTraversalKeysEnabled(false);
153 }
154
155 /**
156 * Setup to render to an existing JFrame.
157 */
158 public void setupFrame() {
159 frame.setTitle("Jexer Application");
160 frame.setBackground(Color.black);
161 frame.pack();
162
163 // Kill the X11 cursor
164 // Transparent 16 x 16 pixel cursor image.
165 BufferedImage cursorImg = new BufferedImage(16, 16,
166 BufferedImage.TYPE_INT_ARGB);
167 // Create a new blank cursor.
168 Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
169 cursorImg, new Point(0, 0), "blank cursor");
170 frame.setCursor(blankCursor);
171
172 // Be capable of seeing Tab / Shift-Tab
173 frame.setFocusTraversalKeysEnabled(false);
174
175 // Setup triple-buffering
176 if (tripleBuffer) {
177 frame.setIgnoreRepaint(true);
178 frame.createBufferStrategy(3);
179 }
180 }
181
182 /**
183 * Set the window title.
184 *
185 * @param title the new title
186 */
187 public void setTitle(final String title) {
188 if (frame != null) {
189 frame.setTitle(title);
190 }
191 }
192
193 /**
194 * Paints this component.
195 *
196 * @param g the graphics context to use for painting
197 */
198 public void paint(Graphics g) {
199 if (frame != null) {
200 frame.paint(g);
201 } else {
202 component.paint(g);
203 }
204 }
205
206 /**
207 * Repaints this component.
208 */
209 public void repaint() {
210 if (frame != null) {
211 frame.repaint();
212 } else {
213 component.repaint();
214 }
215 }
216
217 /**
218 * Repaints the specified rectangle of this component.
219 *
220 * @param x the x coordinate
221 * @param y the y coordinate
222 * @param width the width
223 * @param height the height
224 */
225 public void repaint(int x, int y, int width, int height) {
226 if (frame != null) {
227 frame.repaint(x, y, width, height);
228 } else {
229 component.repaint(x, y, width, height);
230 }
231 }
232
233 /**
234 * If a border has been set on this component, returns the border's
235 * insets; otherwise calls super.getInsets.
236 *
237 * @return the value of the insets property
238 */
239 public Insets getInsets() {
240 if (frame != null) {
241 return frame.getInsets();
242 } else {
243 return component.getInsets();
244 }
245 }
246
247 /**
248 * Returns the current width of this component.
249 *
250 * @return the current width of this component
251 */
252 public int getWidth() {
253 if (frame != null) {
254 return frame.getWidth();
255 } else {
256 return component.getWidth();
257 }
258 }
259
260 /**
261 * Returns the current height of this component.
262 *
263 * @return the current height of this component
264 */
265 public int getHeight() {
266 if (frame != null) {
267 return frame.getHeight();
268 } else {
269 return component.getHeight();
270 }
271 }
272
273 /**
274 * Gets the font of this component.
275 *
276 * @return this component's font; if a font has not been set for this
277 * component, the font of its parent is returned
278 */
279 public Font getFont() {
280 if (frame != null) {
281 return frame.getFont();
282 } else {
283 return component.getFont();
284 }
285 }
286
287 /**
288 * Sets the font of this component.
289 *
290 * @param f the font to become this component's font; if this parameter
291 * is null then this component will inherit the font of its parent
292 */
293 public void setFont(final Font f) {
294 if (frame != null) {
295 frame.setFont(f);
296 } else {
297 component.setFont(f);
298 }
299 }
300
301 /**
302 * Shows or hides this Window depending on the value of parameter b.
303 *
304 * @param b if true, make visible, else make invisible
305 */
306 public void setVisible(final boolean b) {
307 if (frame != null) {
308 frame.setVisible(b);
309 } else {
310 component.setVisible(b);
311 }
312 }
313
314 /**
315 * Creates a graphics context for this component. This method will return
316 * null if this component is currently not displayable.
317 *
318 * @return a graphics context for this component, or null if it has none
319 */
320 public Graphics getGraphics() {
321 if (frame != null) {
322 return frame.getGraphics();
323 } else {
324 return component.getGraphics();
325 }
326 }
327
328 /**
329 * Releases all of the native screen resources used by this Window, its
330 * subcomponents, and all of its owned children. That is, the resources
331 * for these Components will be destroyed, any memory they consume will
332 * be returned to the OS, and they will be marked as undisplayable.
333 */
334 public void dispose() {
335 if (frame != null) {
336 frame.dispose();
337 } else {
338 component.getParent().remove(component);
339 }
340 }
341
342 /**
343 * Resize the component to match the font dimensions.
344 *
345 * @param width the new width in pixels
346 * @param height the new height in pixels
347 */
348 public void setDimensions(final int width, final int height) {
349 // Figure out the thickness of borders and use that to set the final
350 // size.
351 Insets insets = getInsets();
352
353 if (frame != null) {
354 frame.setSize(width + insets.left + insets.right,
355 height + insets.top + insets.bottom);
356 } else {
357 component.setSize(width + insets.left + insets.right,
358 height + insets.top + insets.bottom);
359 }
360 }
361
362 /**
363 * Adds the specified component listener to receive component events from
364 * this component. If listener l is null, no exception is thrown and no
365 * action is performed.
366 *
367 * @param l the component listener
368 */
369 public void addComponentListener(ComponentListener l) {
370 if (frame != null) {
371 frame.addComponentListener(l);
372 } else {
373 component.addComponentListener(l);
374 }
375 }
376
377 /**
378 * Adds the specified key listener to receive key events from this
379 * component. If l is null, no exception is thrown and no action is
380 * performed.
381 *
382 * @param l the key listener.
383 */
384 public void addKeyListener(KeyListener l) {
385 if (frame != null) {
386 frame.addKeyListener(l);
387 } else {
388 component.addKeyListener(l);
389 }
390 }
391
392 /**
393 * Adds the specified mouse listener to receive mouse events from this
394 * component. If listener l is null, no exception is thrown and no action
395 * is performed.
396 *
397 * @param l the mouse listener
398 */
399 public void addMouseListener(MouseListener l) {
400 if (frame != null) {
401 frame.addMouseListener(l);
402 } else {
403 component.addMouseListener(l);
404 }
405 }
406
407 /**
408 * Adds the specified mouse motion listener to receive mouse motion
409 * events from this component. If listener l is null, no exception is
410 * thrown and no action is performed.
411 *
412 * @param l the mouse motion listener
413 */
414 public void addMouseMotionListener(MouseMotionListener l) {
415 if (frame != null) {
416 frame.addMouseMotionListener(l);
417 } else {
418 component.addMouseMotionListener(l);
419 }
420 }
421
422 /**
423 * Adds the specified mouse wheel listener to receive mouse wheel events
424 * from this component. Containers also receive mouse wheel events from
425 * sub-components.
426 *
427 * @param l the mouse wheel listener
428 */
429 public void addMouseWheelListener(MouseWheelListener l) {
430 if (frame != null) {
431 frame.addMouseWheelListener(l);
432 } else {
433 component.addMouseWheelListener(l);
434 }
435 }
436
437 /**
438 * Adds the specified window listener to receive window events from this
439 * window. If l is null, no exception is thrown and no action is
440 * performed.
441 *
442 * @param l the window listener
443 */
444 public void addWindowListener(WindowListener l) {
445 if (frame != null) {
446 frame.addWindowListener(l);
447 }
448 }
449
450 }