propane 3.9.0-java → 3.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +2 -2
  4. data/README.md +3 -3
  5. data/Rakefile +6 -6
  6. data/lib/java/japplemenubar/JAppleMenuBar.java +88 -0
  7. data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
  8. data/lib/java/monkstone/ColorUtil.java +127 -0
  9. data/lib/java/monkstone/MathToolModule.java +287 -0
  10. data/lib/java/monkstone/PropaneLibrary.java +46 -0
  11. data/lib/java/monkstone/core/LibraryProxy.java +136 -0
  12. data/lib/java/monkstone/fastmath/DegLutTables.java +111 -0
  13. data/lib/java/monkstone/fastmath/Deglut.java +71 -0
  14. data/lib/java/monkstone/fastmath/package-info.java +6 -0
  15. data/lib/java/monkstone/filechooser/Chooser.java +39 -0
  16. data/{src/main → lib}/java/monkstone/noise/FastTerrain.java +0 -0
  17. data/{src/main → lib}/java/monkstone/noise/Noise.java +0 -0
  18. data/{src/main → lib}/java/monkstone/noise/NoiseGenerator.java +0 -0
  19. data/{src/main → lib}/java/monkstone/noise/NoiseMode.java +0 -0
  20. data/lib/java/monkstone/noise/OpenSimplex2F.java +881 -0
  21. data/lib/java/monkstone/noise/OpenSimplex2S.java +1106 -0
  22. data/{src/main → lib}/java/monkstone/noise/SmoothTerrain.java +0 -0
  23. data/lib/java/monkstone/slider/CustomHorizontalSlider.java +164 -0
  24. data/lib/java/monkstone/slider/CustomVerticalSlider.java +178 -0
  25. data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +145 -0
  26. data/lib/java/monkstone/slider/SimpleSlider.java +166 -0
  27. data/lib/java/monkstone/slider/SimpleVerticalSlider.java +157 -0
  28. data/lib/java/monkstone/slider/Slider.java +61 -0
  29. data/lib/java/monkstone/slider/SliderBar.java +245 -0
  30. data/lib/java/monkstone/slider/SliderGroup.java +56 -0
  31. data/lib/java/monkstone/slider/WheelHandler.java +35 -0
  32. data/lib/java/monkstone/vecmath/GfxRender.java +86 -0
  33. data/lib/java/monkstone/vecmath/JRender.java +56 -0
  34. data/lib/java/monkstone/vecmath/ShapeRender.java +87 -0
  35. data/lib/java/monkstone/vecmath/package-info.java +20 -0
  36. data/lib/java/monkstone/vecmath/vec2/Vec2.java +802 -0
  37. data/lib/java/monkstone/vecmath/vec2/package-info.java +6 -0
  38. data/lib/java/monkstone/vecmath/vec3/Vec3.java +727 -0
  39. data/lib/java/monkstone/vecmath/vec3/package-info.java +6 -0
  40. data/lib/java/monkstone/videoevent/CaptureEvent.java +27 -0
  41. data/lib/java/monkstone/videoevent/MovieEvent.java +32 -0
  42. data/lib/java/monkstone/videoevent/package-info.java +20 -0
  43. data/lib/java/processing/awt/PGraphicsJava2D.java +3040 -0
  44. data/lib/java/processing/awt/PImageAWT.java +377 -0
  45. data/lib/java/processing/awt/PShapeJava2D.java +387 -0
  46. data/lib/java/processing/awt/PSurfaceAWT.java +1581 -0
  47. data/lib/java/processing/awt/ShimAWT.java +581 -0
  48. data/lib/java/processing/core/PApplet.java +15156 -0
  49. data/lib/java/processing/core/PConstants.java +523 -0
  50. data/lib/java/processing/core/PFont.java +1126 -0
  51. data/lib/java/processing/core/PGraphics.java +8600 -0
  52. data/lib/java/processing/core/PImage.java +3377 -0
  53. data/lib/java/processing/core/PMatrix.java +208 -0
  54. data/lib/java/processing/core/PMatrix2D.java +562 -0
  55. data/lib/java/processing/core/PMatrix3D.java +890 -0
  56. data/lib/java/processing/core/PShape.java +3561 -0
  57. data/lib/java/processing/core/PShapeOBJ.java +483 -0
  58. data/lib/java/processing/core/PShapeSVG.java +2016 -0
  59. data/lib/java/processing/core/PStyle.java +63 -0
  60. data/lib/java/processing/core/PSurface.java +198 -0
  61. data/lib/java/processing/core/PSurfaceNone.java +431 -0
  62. data/lib/java/processing/core/PVector.java +1066 -0
  63. data/lib/java/processing/core/ThinkDifferent.java +115 -0
  64. data/lib/java/processing/data/DoubleDict.java +850 -0
  65. data/lib/java/processing/data/DoubleList.java +928 -0
  66. data/lib/java/processing/data/FloatDict.java +847 -0
  67. data/lib/java/processing/data/FloatList.java +936 -0
  68. data/lib/java/processing/data/IntDict.java +807 -0
  69. data/lib/java/processing/data/IntList.java +936 -0
  70. data/lib/java/processing/data/JSONArray.java +1260 -0
  71. data/lib/java/processing/data/JSONObject.java +2282 -0
  72. data/lib/java/processing/data/JSONTokener.java +435 -0
  73. data/lib/java/processing/data/LongDict.java +802 -0
  74. data/lib/java/processing/data/LongList.java +937 -0
  75. data/lib/java/processing/data/Sort.java +46 -0
  76. data/lib/java/processing/data/StringDict.java +613 -0
  77. data/lib/java/processing/data/StringList.java +800 -0
  78. data/lib/java/processing/data/Table.java +4936 -0
  79. data/lib/java/processing/data/TableRow.java +198 -0
  80. data/lib/java/processing/data/XML.java +1156 -0
  81. data/lib/java/processing/dxf/RawDXF.java +404 -0
  82. data/lib/java/processing/event/Event.java +125 -0
  83. data/lib/java/processing/event/KeyEvent.java +70 -0
  84. data/lib/java/processing/event/MouseEvent.java +114 -0
  85. data/lib/java/processing/event/TouchEvent.java +57 -0
  86. data/lib/java/processing/javafx/PGraphicsFX2D.java +32 -0
  87. data/lib/java/processing/javafx/PSurfaceFX.java +173 -0
  88. data/lib/java/processing/net/Client.java +744 -0
  89. data/lib/java/processing/net/Server.java +388 -0
  90. data/lib/java/processing/opengl/FontTexture.java +378 -0
  91. data/lib/java/processing/opengl/FrameBuffer.java +513 -0
  92. data/lib/java/processing/opengl/LinePath.java +627 -0
  93. data/lib/java/processing/opengl/LineStroker.java +681 -0
  94. data/lib/java/processing/opengl/PGL.java +3483 -0
  95. data/lib/java/processing/opengl/PGraphics2D.java +615 -0
  96. data/lib/java/processing/opengl/PGraphics3D.java +281 -0
  97. data/lib/java/processing/opengl/PGraphicsOpenGL.java +13753 -0
  98. data/lib/java/processing/opengl/PJOGL.java +2008 -0
  99. data/lib/java/processing/opengl/PShader.java +1484 -0
  100. data/lib/java/processing/opengl/PShapeOpenGL.java +5269 -0
  101. data/lib/java/processing/opengl/PSurfaceJOGL.java +1385 -0
  102. data/lib/java/processing/opengl/Texture.java +1696 -0
  103. data/lib/java/processing/opengl/VertexBuffer.java +88 -0
  104. data/lib/java/processing/opengl/cursors/arrow.png +0 -0
  105. data/lib/java/processing/opengl/cursors/cross.png +0 -0
  106. data/lib/java/processing/opengl/cursors/hand.png +0 -0
  107. data/lib/java/processing/opengl/cursors/license.txt +27 -0
  108. data/lib/java/processing/opengl/cursors/move.png +0 -0
  109. data/lib/java/processing/opengl/cursors/text.png +0 -0
  110. data/lib/java/processing/opengl/cursors/wait.png +0 -0
  111. data/lib/java/processing/opengl/shaders/ColorFrag.glsl +32 -0
  112. data/lib/java/processing/opengl/shaders/ColorVert.glsl +34 -0
  113. data/lib/java/processing/opengl/shaders/LightFrag.glsl +33 -0
  114. data/lib/java/processing/opengl/shaders/LightVert.glsl +151 -0
  115. data/lib/java/processing/opengl/shaders/LineFrag.glsl +32 -0
  116. data/lib/java/processing/opengl/shaders/LineVert.glsl +100 -0
  117. data/lib/java/processing/opengl/shaders/MaskFrag.glsl +40 -0
  118. data/lib/java/processing/opengl/shaders/PointFrag.glsl +32 -0
  119. data/lib/java/processing/opengl/shaders/PointVert.glsl +56 -0
  120. data/lib/java/processing/opengl/shaders/TexFrag.glsl +37 -0
  121. data/lib/java/processing/opengl/shaders/TexLightFrag.glsl +37 -0
  122. data/lib/java/processing/opengl/shaders/TexLightVert.glsl +157 -0
  123. data/lib/java/processing/opengl/shaders/TexVert.glsl +38 -0
  124. data/lib/java/processing/pdf/PGraphicsPDF.java +581 -0
  125. data/lib/java/processing/svg/PGraphicsSVG.java +378 -0
  126. data/lib/propane/app.rb +8 -13
  127. data/lib/propane/version.rb +1 -1
  128. data/mvnw +3 -3
  129. data/mvnw.cmd +2 -2
  130. data/pom.rb +7 -2
  131. data/pom.xml +14 -2
  132. data/propane.gemspec +2 -2
  133. data/src/main/java/monkstone/FastNoiseModuleJava.java +127 -0
  134. data/src/main/java/monkstone/MathToolModule.java +30 -30
  135. data/src/main/java/monkstone/PropaneLibrary.java +2 -0
  136. data/src/main/java/monkstone/SmoothNoiseModuleJava.java +127 -0
  137. data/src/main/java/monkstone/fastmath/DegLutTables.java +15 -15
  138. data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
  139. data/src/main/java/monkstone/noise/OpenSimplex2F.java +752 -820
  140. data/src/main/java/monkstone/noise/OpenSimplex2S.java +1138 -1106
  141. data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
  142. data/src/main/java/monkstone/vecmath/JRender.java +6 -6
  143. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +20 -19
  144. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +12 -12
  145. data/src/main/java/processing/awt/PGraphicsJava2D.java +11 -3
  146. data/src/main/java/processing/core/PApplet.java +89 -89
  147. data/src/main/java/processing/core/PConstants.java +155 -163
  148. data/src/main/java/processing/opengl/PJOGL.java +6 -5
  149. data/vendors/Rakefile +1 -1
  150. metadata +136 -19
@@ -0,0 +1,1581 @@
1
+ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
+
3
+ /*
4
+ Part of the Processing project - http://processing.org
5
+
6
+ Copyright (c) 2014-15 The Processing Foundation
7
+
8
+ This library is free software; you can redistribute it and/or
9
+ modify it under the terms of the GNU Lesser General Public
10
+ License as published by the Free Software Foundation, version 2.1.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General
18
+ Public License along with this library; if not, write to the
19
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20
+ Boston, MA 02111-1307 USA
21
+ */
22
+
23
+ package processing.awt;
24
+
25
+ import java.awt.Canvas;
26
+ import java.awt.Color;
27
+ import java.awt.Cursor;
28
+ import java.awt.Dimension;
29
+ import java.awt.Frame;
30
+ import java.awt.Graphics;
31
+ import java.awt.Graphics2D;
32
+ import java.awt.GraphicsConfiguration;
33
+ import java.awt.GraphicsDevice;
34
+ import java.awt.GraphicsEnvironment;
35
+ import java.awt.Image;
36
+ import java.awt.Insets;
37
+ import java.awt.Label;
38
+ import java.awt.Point;
39
+ import java.awt.Rectangle;
40
+ import java.awt.Toolkit;
41
+ import java.awt.event.*;
42
+ import java.awt.geom.Rectangle2D;
43
+ import java.awt.image.*;
44
+ import java.io.File;
45
+ import java.lang.management.ManagementFactory;
46
+ import java.lang.reflect.InvocationTargetException;
47
+ import java.lang.reflect.Method;
48
+ import java.net.URL;
49
+ import java.util.ArrayList;
50
+ import java.util.List;
51
+
52
+ import javax.swing.JFrame;
53
+
54
+ import processing.core.PApplet;
55
+ import processing.core.PConstants;
56
+ import processing.core.PGraphics;
57
+ import processing.core.PImage;
58
+ import processing.core.PSurfaceNone;
59
+ import processing.event.KeyEvent;
60
+ import processing.event.MouseEvent;
61
+
62
+
63
+ public class PSurfaceAWT extends PSurfaceNone {
64
+ GraphicsDevice displayDevice;
65
+
66
+ // used for canvas to determine whether resizable or not
67
+ // boolean resizable; // default is false
68
+
69
+ // Internally, we know it's always a JFrame (not just a Frame)
70
+ // JFrame frame;
71
+ // Trying Frame again with a11 to see if this avoids some Swing nastiness.
72
+ // In the past, AWT Frames caused some problems on Windows and Linux,
73
+ // but those may not be a problem for our reworked PSurfaceAWT class.
74
+ Frame frame;
75
+
76
+ // Note that x and y may not be zero, depending on the display configuration
77
+ Rectangle screenRect;
78
+
79
+ // Used for resizing, at least on Windows insets size changes when
80
+ // frame.setResizable() is called, and in resize listener we need
81
+ // to know what size the window was before.
82
+ Insets currentInsets = new Insets(0, 0, 0, 0);
83
+
84
+ // 3.0a5 didn't use strategy, and active was shut off during init() w/ retina
85
+ // boolean useStrategy = true;
86
+
87
+ Canvas canvas;
88
+ // Component canvas;
89
+
90
+ // PGraphics graphics; // moved to PSurfaceNone
91
+
92
+ int sketchWidth;
93
+ int sketchHeight;
94
+
95
+ int windowScaleFactor;
96
+
97
+
98
+ public PSurfaceAWT(PGraphics graphics) {
99
+ //this.graphics = graphics;
100
+ super(graphics);
101
+
102
+ /*
103
+ if (checkRetina()) {
104
+ // System.out.println("retina in use");
105
+
106
+ // The active-mode rendering seems to be 2x slower, so disable it
107
+ // with retina. On a non-retina machine, however, useActive seems
108
+ // the only (or best) way to handle the rendering.
109
+ // useActive = false;
110
+ // canvas = new JPanel(true) {
111
+ // @Override
112
+ // public void paint(Graphics screen) {
113
+ //// if (!sketch.insideDraw) {
114
+ // screen.drawImage(PSurfaceAWT.this.graphics.image, 0, 0, sketchWidth, sketchHeight, null);
115
+ //// }
116
+ // }
117
+ // };
118
+ // Under 1.8 and the current 3.0a6 threading regime, active mode w/o
119
+ // strategy is far faster, but perhaps only because it's blitting with
120
+ // flicker--pushing pixels out before the screen has finished rendering.
121
+ // useStrategy = false;
122
+ }
123
+ */
124
+ canvas = new SmoothCanvas();
125
+ // if (useStrategy) {
126
+ //canvas.setIgnoreRepaint(true);
127
+ // }
128
+
129
+ // Pass tab key to the sketch, rather than moving between components
130
+ canvas.setFocusTraversalKeysEnabled(false);
131
+
132
+ canvas.addComponentListener(new ComponentAdapter() {
133
+ @Override
134
+ public void componentResized(ComponentEvent e) {
135
+ if (!sketch.isLooping()) {
136
+ // make sure this is a real resize event, not just initial setup
137
+ // https://github.com/processing/processing/issues/3310
138
+ Dimension canvasSize = canvas.getSize();
139
+ if (canvasSize.width != sketch.sketchWidth() ||
140
+ canvasSize.height != sketch.sketchHeight()) {
141
+ sketch.redraw();
142
+ }
143
+ }
144
+ }
145
+ });
146
+ addListeners();
147
+ }
148
+
149
+
150
+ // /**
151
+ // * Handle grabbing the focus on startup. Other renderers can override this
152
+ // * if handling needs to be different. For the AWT, the request is invoked
153
+ // * later on the EDT. Other implementations may not require that, so the
154
+ // * invokeLater() happens in here rather than requiring the caller to wrap it.
155
+ // */
156
+ // @Override
157
+ // void requestFocus() {
158
+ //// System.out.println("requesFocus() outer " + EventQueue.isDispatchThread());
159
+ // // for 2.0a6, moving this request to the EDT
160
+ // EventQueue.invokeLater(new Runnable() {
161
+ // public void run() {
162
+ // // Call the request focus event once the image is sure to be on
163
+ // // screen and the component is valid. The OpenGL renderer will
164
+ // // request focus for its canvas inside beginDraw().
165
+ // // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/FocusSpec.html
166
+ // // Disabling for 0185, because it causes an assertion failure on OS X
167
+ // // http://code.google.com/p/processing/issues/detail?id=258
168
+ // // requestFocus();
169
+ //
170
+ // // Changing to this version for 0187
171
+ // // http://code.google.com/p/processing/issues/detail?id=279
172
+ // //requestFocusInWindow();
173
+ //
174
+ // // For 3.0, just call this directly on the Canvas object
175
+ // if (canvas != null) {
176
+ // //System.out.println("requesting focus " + EventQueue.isDispatchThread());
177
+ // //System.out.println("requesting focus " + frame.isVisible());
178
+ // //canvas.requestFocusInWindow();
179
+ // canvas.requestFocus();
180
+ // }
181
+ // }
182
+ // });
183
+ // }
184
+
185
+
186
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
187
+
188
+
189
+ public class SmoothCanvas extends Canvas {
190
+ private Dimension oldSize = new Dimension(0, 0);
191
+ private Dimension newSize = new Dimension(0, 0);
192
+
193
+
194
+ // Turns out getParent() returns a JPanel on a JFrame. Yech.
195
+ public Frame getFrame() {
196
+ return frame;
197
+ }
198
+
199
+
200
+ @Override
201
+ public Dimension getPreferredSize() {
202
+ return new Dimension(sketchWidth, sketchHeight);
203
+ }
204
+
205
+
206
+ @Override
207
+ public Dimension getMinimumSize() {
208
+ return getPreferredSize();
209
+ }
210
+
211
+
212
+ @Override
213
+ public Dimension getMaximumSize() {
214
+ //return resizable ? super.getMaximumSize() : getPreferredSize();
215
+ return frame.isResizable() ? super.getMaximumSize() : getPreferredSize();
216
+ }
217
+
218
+
219
+ @Override
220
+ public void validate() {
221
+ super.validate();
222
+ newSize.width = getWidth();
223
+ newSize.height = getHeight();
224
+ // if (oldSize.equals(newSize)) {
225
+ //// System.out.println("validate() return " + oldSize);
226
+ // return;
227
+ // } else {
228
+ if (!oldSize.equals(newSize)) {
229
+ // System.out.println("validate() render old=" + oldSize + " -> new=" + newSize);
230
+ oldSize = newSize;
231
+ sketch.setSize(newSize.width / windowScaleFactor, newSize.height / windowScaleFactor);
232
+ // try {
233
+ render();
234
+ // } catch (IllegalStateException ise) {
235
+ // System.out.println(ise.getMessage());
236
+ // }
237
+ }
238
+ }
239
+
240
+
241
+ @Override
242
+ public void update(Graphics g) {
243
+ // System.out.println("updating");
244
+ paint(g);
245
+ }
246
+
247
+
248
+ @Override
249
+ public void paint(Graphics screen) {
250
+ // System.out.println("painting");
251
+ // if (useStrategy) {
252
+ render();
253
+ /*
254
+ if (graphics != null) {
255
+ System.out.println("drawing to screen " + canvas);
256
+ screen.drawImage(graphics.image, 0, 0, sketchWidth, sketchHeight, null);
257
+ }
258
+ */
259
+
260
+ // } else {
261
+ //// new Exception("painting").printStackTrace(System.out);
262
+ //// if (graphics.image != null) { // && !sketch.insideDraw) {
263
+ // if (onscreen != null) {
264
+ //// synchronized (graphics.image) {
265
+ // // Needs the width/height to be set so that retina images are properly scaled down
266
+ //// screen.drawImage(graphics.image, 0, 0, sketchWidth, sketchHeight, null);
267
+ // synchronized (offscreenLock) {
268
+ // screen.drawImage(onscreen, 0, 0, sketchWidth, sketchHeight, null);
269
+ // }
270
+ // }
271
+ // }
272
+ }
273
+ }
274
+
275
+ /*
276
+ @Override
277
+ public void addNotify() {
278
+ // System.out.println("adding notify");
279
+ super.addNotify();
280
+ // prior to Java 7 on OS X, this no longer works [121222]
281
+ // createBufferStrategy(2);
282
+ }
283
+ */
284
+
285
+
286
+ synchronized protected void render() {
287
+ if (canvas.isDisplayable() &&
288
+ graphics.image != null) {
289
+ if (canvas.getBufferStrategy() == null) {
290
+ canvas.createBufferStrategy(2);
291
+ }
292
+ BufferStrategy strategy = canvas.getBufferStrategy();
293
+ if (strategy != null) {
294
+ // Render single frame
295
+ // try {
296
+ do {
297
+ // The following loop ensures that the contents of the drawing buffer
298
+ // are consistent in case the underlying surface was recreated
299
+ do {
300
+ Graphics2D draw = (Graphics2D) strategy.getDrawGraphics();
301
+ // draw to width/height, since this may be a 2x image
302
+ draw.drawImage(graphics.image, 0, 0, sketchWidth, sketchHeight, null);
303
+ draw.dispose();
304
+ } while (strategy.contentsRestored());
305
+
306
+ // Display the buffer
307
+ strategy.show();
308
+
309
+ // Repeat the rendering if the drawing buffer was lost
310
+ } while (strategy.contentsLost());
311
+ }
312
+ }
313
+ }
314
+
315
+
316
+ /*
317
+ protected void blit() {
318
+ // Other folks that call render() (i.e. paint()) are already on the EDT.
319
+ // We need to be using the EDT since we're messing with the Canvas
320
+ // object and BufferStrategy and friends.
321
+ //EventQueue.invokeLater(new Runnable() {
322
+ //public void run() {
323
+ //((SmoothCanvas) canvas).render();
324
+ //}
325
+ //});
326
+
327
+ if (useStrategy) {
328
+ // Not necessary to be on the EDT to update BufferStrategy
329
+ //((SmoothCanvas) canvas).render();
330
+ render();
331
+ } else {
332
+ if (graphics.image != null) {
333
+ BufferedImage graphicsImage = (BufferedImage) graphics.image;
334
+ if (offscreen == null ||
335
+ offscreen.getWidth() != graphicsImage.getWidth() ||
336
+ offscreen.getHeight() != graphicsImage.getHeight()) {
337
+ System.out.println("creating new image");
338
+ offscreen = (BufferedImage)
339
+ canvas.createImage(graphicsImage.getWidth(),
340
+ graphicsImage.getHeight());
341
+ // off = offscreen.getGraphics();
342
+ }
343
+ // synchronized (offscreen) {
344
+ Graphics2D off = (Graphics2D) offscreen.getGraphics();
345
+ // off.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
346
+ off.drawImage(graphicsImage, 0, 0, null);
347
+ // }
348
+ off.dispose();
349
+ synchronized (offscreenLock) {
350
+ BufferedImage temp = onscreen;
351
+ onscreen = offscreen;
352
+ offscreen = temp;
353
+ }
354
+ canvas.repaint();
355
+ }
356
+ }
357
+ }
358
+ */
359
+
360
+
361
+ /*
362
+ @Override
363
+ public int displayDensity() {
364
+ return shim.displayDensity();
365
+ }
366
+
367
+
368
+ @Override
369
+ public int displayDensity(int display) {
370
+ return shim.displayDensity(display);
371
+ }
372
+ */
373
+
374
+
375
+ @Override
376
+ public void selectInput(String prompt, String callback,
377
+ File file, Object callbackObject) {
378
+ ShimAWT.selectInput(prompt, callback, file, callbackObject);
379
+ }
380
+
381
+
382
+ @Override
383
+ public void selectOutput(String prompt, String callback,
384
+ File file, Object callbackObject) {
385
+ ShimAWT.selectOutput(prompt, callback, file, callbackObject);
386
+ }
387
+
388
+
389
+ @Override
390
+ public void selectFolder(String prompt, String callback,
391
+ File file, Object callbackObject) {
392
+ ShimAWT.selectFolder(prompt, callback, file, callbackObject);
393
+ }
394
+
395
+
396
+ // what needs to happen here?
397
+ @Override
398
+ public void initOffscreen(PApplet sketch) {
399
+ this.sketch = sketch;
400
+ }
401
+
402
+ /*
403
+ public Frame initOffscreen() {
404
+ Frame dummy = new Frame();
405
+ dummy.pack(); // get legit AWT graphics
406
+ // but don't show it
407
+ return dummy;
408
+ }
409
+ */
410
+
411
+ /*
412
+ @Override
413
+ public Component initComponent(PApplet sketch) {
414
+ this.sketch = sketch;
415
+
416
+ // needed for getPreferredSize() et al
417
+ sketchWidth = sketch.sketchWidth();
418
+ sketchHeight = sketch.sketchHeight();
419
+
420
+ return canvas;
421
+ }
422
+ */
423
+
424
+
425
+ @Override
426
+ public void initFrame(final PApplet sketch) {/*, int backgroundColor,
427
+ int deviceIndex, boolean fullScreen, boolean spanDisplays) {*/
428
+ this.sketch = sketch;
429
+
430
+ GraphicsEnvironment environment =
431
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
432
+
433
+ int displayNum = sketch.sketchDisplay();
434
+ // System.out.println("display from sketch is " + displayNum);
435
+ if (displayNum > 0) { // if -1, use the default device
436
+ GraphicsDevice[] devices = environment.getScreenDevices();
437
+ if (displayNum <= devices.length) {
438
+ displayDevice = devices[displayNum - 1];
439
+ } else {
440
+ System.err.format("Display %d does not exist, " +
441
+ "using the default display instead.%n", displayNum);
442
+ for (int i = 0; i < devices.length; i++) {
443
+ System.err.format("Display %d is %s%n", (i+1), devices[i]);
444
+ }
445
+ }
446
+ }
447
+ if (displayDevice == null) {
448
+ displayDevice = environment.getDefaultScreenDevice();
449
+ }
450
+
451
+ // Need to save the window bounds at full screen,
452
+ // because pack() will cause the bounds to go to zero.
453
+ // http://dev.processing.org/bugs/show_bug.cgi?id=923
454
+ boolean spanDisplays = sketch.sketchDisplay() == PConstants.SPAN;
455
+ screenRect = spanDisplays ? getDisplaySpan() :
456
+ displayDevice.getDefaultConfiguration().getBounds();
457
+ // DisplayMode doesn't work here, because we can't get the upper-left
458
+ // corner of the display, which is important for multi-display setups.
459
+
460
+ // Set the displayWidth/Height variables inside PApplet, so that they're
461
+ // usable and can even be returned by the sketchWidth()/Height() methods.
462
+ sketch.displayWidth = screenRect.width;
463
+ sketch.displayHeight = screenRect.height;
464
+
465
+ windowScaleFactor = PApplet.platform == PConstants.MACOS ?
466
+ 1 : sketch.pixelDensity;
467
+
468
+ sketchWidth = sketch.sketchWidth() * windowScaleFactor;
469
+ sketchHeight = sketch.sketchHeight() * windowScaleFactor;
470
+
471
+ boolean fullScreen = sketch.sketchFullScreen();
472
+ // Removing the section below because sometimes people want to do the
473
+ // full screen size in a window, and it also breaks insideSettings().
474
+ // With 3.x, fullScreen() is so easy, that it's just better that way.
475
+ // https://github.com/processing/processing/issues/3545
476
+ /*
477
+ // Sketch has already requested to be the same as the screen's
478
+ // width and height, so let's roll with full screen mode.
479
+ if (screenRect.width == sketchWidth &&
480
+ screenRect.height == sketchHeight) {
481
+ fullScreen = true;
482
+ sketch.fullScreen(); // won't change the renderer
483
+ }
484
+ */
485
+
486
+ if (fullScreen || spanDisplays) {
487
+ sketchWidth = screenRect.width;
488
+ sketchHeight = screenRect.height;
489
+ }
490
+
491
+ // Using a JFrame fixes a Windows problem with Present mode. This might
492
+ // be our error, but usually this is the sort of crap we usually get from
493
+ // OS X. It's time for a turnaround: Redmond is thinking different too!
494
+ // https://github.com/processing/processing/issues/1955
495
+ frame = new JFrame(displayDevice.getDefaultConfiguration());
496
+ // frame = new Frame(displayDevice.getDefaultConfiguration());
497
+ // // Default Processing gray, which will be replaced below if another
498
+ // // color is specified on the command line (i.e. in the prefs).
499
+ // ((JFrame) frame).getContentPane().setBackground(WINDOW_BGCOLOR);
500
+ // // Cannot call setResizable(false) until later due to OS X (issue #467)
501
+
502
+ // // Removed code above, also removed from what's now in the placeXxxx()
503
+ // // methods. Not sure why it was being double-set; hopefully anachronistic.
504
+ // if (backgroundColor == 0) {
505
+ // backgroundColor = WINDOW_BGCOLOR;
506
+ // }
507
+ final Color windowColor = new Color(sketch.sketchWindowColor(), false);
508
+ if (frame instanceof JFrame) {
509
+ ((JFrame) frame).getContentPane().setBackground(windowColor);
510
+ } else {
511
+ frame.setBackground(windowColor);
512
+ }
513
+
514
+ // Put the p5 logo in the Frame's corner to override the Java coffee cup.
515
+ setProcessingIcon(frame);
516
+
517
+ // For 0149, moving this code (up to the pack() method) before init().
518
+ // For OpenGL (and perhaps other renderers in the future), a peer is
519
+ // needed before a GLDrawable can be created. So pack() needs to be
520
+ // called on the Frame before applet.init(), which itself calls size(),
521
+ // and launches the Thread that will kick off setup().
522
+ // http://dev.processing.org/bugs/show_bug.cgi?id=891
523
+ // http://dev.processing.org/bugs/show_bug.cgi?id=908
524
+
525
+ frame.add(canvas);
526
+ setSize(sketchWidth / windowScaleFactor, sketchHeight / windowScaleFactor);
527
+
528
+ /*
529
+ if (fullScreen) {
530
+ // Called here because the graphics device is needed before we can
531
+ // determine whether the sketch wants size(displayWidth, displayHeight),
532
+ // and getting the graphics device will be PSurface-specific.
533
+ PApplet.hideMenuBar();
534
+
535
+ // Tried to use this to fix the 'present' mode issue.
536
+ // Did not help, and the screenRect setup seems to work fine.
537
+ //frame.setExtendedState(Frame.MAXIMIZED_BOTH);
538
+
539
+ // https://github.com/processing/processing/pull/3162
540
+ frame.dispose(); // release native resources, allows setUndecorated()
541
+ frame.setUndecorated(true);
542
+ // another duplicate?
543
+ // if (backgroundColor != null) {
544
+ // frame.getContentPane().setBackground(backgroundColor);
545
+ // }
546
+ // this may be the bounds of all screens
547
+ frame.setBounds(screenRect);
548
+ // will be set visible in placeWindow() [3.0a10]
549
+ //frame.setVisible(true); // re-add native resources
550
+ }
551
+ */
552
+ frame.setLayout(null);
553
+ //frame.add(applet);
554
+
555
+ // Need to pass back our new sketchWidth/Height here, because it may have
556
+ // been overridden by numbers we calculated above if fullScreen and/or
557
+ // spanScreens was in use.
558
+ // pg = sketch.makePrimaryGraphics(sketchWidth, sketchHeight);
559
+ // pg = sketch.makePrimaryGraphics();
560
+
561
+ // resize sketch to sketchWidth/sketchHeight here
562
+
563
+ if (fullScreen) {
564
+ frame.invalidate();
565
+ } else {
566
+ // frame.pack();
567
+ }
568
+
569
+ // insufficient, places the 100x100 sketches offset strangely
570
+ //frame.validate();
571
+
572
+ // disabling resize has to happen after pack() to avoid apparent Apple bug
573
+ // http://code.google.com/p/processing/issues/detail?id=467
574
+ frame.setResizable(false);
575
+
576
+ frame.addWindowListener(new WindowAdapter() {
577
+ @Override
578
+ public void windowClosing(WindowEvent e) {
579
+ sketch.exit(); // don't quit, need to just shut everything down (0133)
580
+ }
581
+ });
582
+
583
+ // sketch.setFrame(frame);
584
+ }
585
+
586
+
587
+ @Override
588
+ public Object getNative() {
589
+ return canvas;
590
+ }
591
+
592
+
593
+ // public Toolkit getToolkit() {
594
+ // return canvas.getToolkit();
595
+ // }
596
+
597
+
598
+ /** Set the window (and dock, or whatever necessary) title.
599
+ * @param title */
600
+ @Override
601
+ public void setTitle(String title) {
602
+ frame.setTitle(title);
603
+ // Workaround for apparent Java bug on OS X?
604
+ // https://github.com/processing/processing/issues/3472
605
+ if (cursorVisible &&
606
+ (PApplet.platform == PConstants.MACOS) &&
607
+ (cursorType != PConstants.ARROW)) {
608
+ hideCursor();
609
+ showCursor();
610
+ }
611
+ }
612
+
613
+
614
+ /** Set true if we want to resize things (default is not resizable)
615
+ * @param resizable */
616
+ @Override
617
+ public void setResizable(boolean resizable) {
618
+ //this.resizable = resizable; // really only used for canvas
619
+
620
+ if (frame != null) {
621
+ frame.setResizable(resizable);
622
+ }
623
+ }
624
+
625
+
626
+ @Override
627
+ public void setIcon(PImage image) {
628
+ Image awtImage = (Image) image.getNative();
629
+
630
+ if (PApplet.platform != PConstants.MACOS) {
631
+ frame.setIconImage(awtImage);
632
+
633
+ } else {
634
+ try {
635
+ final String td = "processing.core.ThinkDifferent";
636
+ Class<?> thinkDifferent =
637
+ Thread.currentThread().getContextClassLoader().loadClass(td);
638
+ Method method =
639
+ thinkDifferent.getMethod("setIconImage", Image.class);
640
+ method.invoke(null, awtImage);
641
+ } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException | SecurityException | InvocationTargetException e) {
642
+ // That's unfortunate
643
+
644
+ }
645
+ }
646
+ }
647
+
648
+
649
+ @Override
650
+ public void setAlwaysOnTop(boolean always) {
651
+ frame.setAlwaysOnTop(always);
652
+ }
653
+
654
+
655
+ @Override
656
+ public void setLocation(int x, int y) {
657
+ frame.setLocation(x, y);
658
+ }
659
+
660
+
661
+ List<Image> iconImages;
662
+
663
+ protected void setProcessingIcon(Frame frame) {
664
+ // On OS X, this only affects what shows up in the dock when minimized.
665
+ // So replacing it is actually a step backwards. Brilliant.
666
+ if (PApplet.platform != PConstants.MACOS) {
667
+ //Image image = Toolkit.getDefaultToolkit().createImage(ICON_IMAGE);
668
+ //frame.setIconImage(image);
669
+ try {
670
+ if (iconImages == null) {
671
+ iconImages = new ArrayList<>();
672
+ final int[] sizes = { 16, 32, 48, 64, 128, 256, 512 };
673
+
674
+ for (int sz : sizes) {
675
+ //URL url = getClass().getResource("/icon/icon-" + sz + ".png");
676
+ URL url = PApplet.class.getResource("/icon/icon-" + sz + ".png");
677
+ Image image = Toolkit.getDefaultToolkit().getImage(url);
678
+ iconImages.add(image);
679
+ //iconImages.add(Toolkit.getLibImage("icons/pde-" + sz + ".png", frame));
680
+ }
681
+ }
682
+ frame.setIconImages(iconImages);
683
+
684
+ } catch (Exception e) { } // harmless; keep this to ourselves
685
+
686
+ } else { // handle OS X differently
687
+ if (!dockIconSpecified()) { // don't override existing -Xdock param
688
+ // On OS X, set this for AWT surfaces, which handles the dock image
689
+ // as well as the cmd-tab image that's shown. Just one size, I guess.
690
+ URL url = PApplet.class.getResource("/icon/icon-512.png");
691
+ // Seems dangerous to have this in code instead of using reflection, no?
692
+ //ThinkDifferent.setIconImage(Toolkit.getDefaultToolkit().getImage(url));
693
+ try {
694
+ final String td = "processing.core.ThinkDifferent";
695
+ Class<?> thinkDifferent =
696
+ Thread.currentThread().getContextClassLoader().loadClass(td);
697
+ Method method =
698
+ thinkDifferent.getMethod("setIconImage", Image.class);
699
+ method.invoke(null, Toolkit.getDefaultToolkit().getImage(url));
700
+ } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException | SecurityException | InvocationTargetException e) {
701
+ // That's unfortunate
702
+
703
+ }
704
+ }
705
+ }
706
+ }
707
+
708
+
709
+ /**
710
+ * @return true if -Xdock:icon was specified on the command line
711
+ */
712
+ private boolean dockIconSpecified() {
713
+ // TODO This is incomplete... Haven't yet found a way to figure out if
714
+ // the app has an icns file specified already. Help?
715
+ List<String> jvmArgs =
716
+ ManagementFactory.getRuntimeMXBean().getInputArguments();
717
+ // dock image already set
718
+ return jvmArgs.stream().anyMatch((arg) -> (arg.startsWith("-Xdock:icon")));
719
+ }
720
+
721
+
722
+ @Override
723
+ public void setVisible(boolean visible) {
724
+ frame.setVisible(visible);
725
+
726
+ // Generally useful whenever setting the frame visible
727
+ if (canvas != null) {
728
+ //canvas.requestFocusInWindow();
729
+ canvas.requestFocus();
730
+ }
731
+
732
+ // removing per https://github.com/processing/processing/pull/3162
733
+ // can remove the code below once 3.0a6 is tested and behaving
734
+ /*
735
+ if (visible && PApplet.platform == PConstants.LINUX) {
736
+ // Linux doesn't deal with insets the same way. We get fake insets
737
+ // earlier, and then the window manager will slap its own insets
738
+ // onto things once the frame is realized on the screen. Awzm.
739
+ if (PApplet.platform == PConstants.LINUX) {
740
+ Insets insets = frame.getInsets();
741
+ frame.setSize(Math.max(sketchWidth, MIN_WINDOW_WIDTH) +
742
+ insets.left + insets.right,
743
+ Math.max(sketchHeight, MIN_WINDOW_HEIGHT) +
744
+ insets.top + insets.bottom);
745
+ }
746
+ }
747
+ */
748
+ }
749
+
750
+
751
+ //public void placeFullScreen(boolean hideStop) {
752
+ @Override
753
+ public void placePresent(int stopColor) {
754
+ setFullFrame();
755
+
756
+ // After the pack(), the screen bounds are gonna be 0s
757
+ // frame.setBounds(screenRect); // already called in setFullFrame()
758
+ canvas.setBounds((screenRect.width - sketchWidth) / 2,
759
+ (screenRect.height - sketchHeight) / 2,
760
+ sketchWidth, sketchHeight);
761
+
762
+ // if (PApplet.platform == PConstants.MACOSX) {
763
+ // macosxFullScreenEnable(frame);
764
+ // macosxFullScreenToggle(frame);
765
+ // }
766
+
767
+ if (stopColor != 0) {
768
+ Label label = new Label("stop");
769
+ label.setForeground(new Color(stopColor, false));
770
+ label.addMouseListener(new MouseAdapter() {
771
+ @Override
772
+ public void mousePressed(java.awt.event.MouseEvent e) {
773
+ sketch.exit();
774
+ }
775
+ });
776
+ frame.add(label);
777
+
778
+ Dimension labelSize = label.getPreferredSize();
779
+ // sometimes shows up truncated on mac
780
+ //System.out.println("label width is " + labelSize.width);
781
+ labelSize = new Dimension(100, labelSize.height);
782
+ label.setSize(labelSize);
783
+ label.setLocation(20, screenRect.height - labelSize.height - 20);
784
+ }
785
+
786
+ // if (sketch.getGraphics().displayable()) {
787
+ // setVisible(true);
788
+ // }
789
+ }
790
+
791
+
792
+ /*
793
+ @Override
794
+ public void placeWindow(int[] location) {
795
+ setFrameSize(); //sketchWidth, sketchHeight);
796
+
797
+ if (location != null) {
798
+ // a specific location was received from the Runner
799
+ // (applet has been run more than once, user placed window)
800
+ frame.setLocation(location[0], location[1]);
801
+
802
+ } else { // just center on screen
803
+ // Can't use frame.setLocationRelativeTo(null) because it sends the
804
+ // frame to the main display, which undermines the --display setting.
805
+ frame.setLocation(screenRect.x + (screenRect.width - sketchWidth) / 2,
806
+ screenRect.y + (screenRect.height - sketchHeight) / 2);
807
+ }
808
+ Point frameLoc = frame.getLocation();
809
+ if (frameLoc.y < 0) {
810
+ // Windows actually allows you to place frames where they can't be
811
+ // closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508
812
+ frame.setLocation(frameLoc.x, 30);
813
+ }
814
+
815
+ // if (backgroundColor != null) {
816
+ // ((JFrame) frame).getContentPane().setBackground(backgroundColor);
817
+ // }
818
+
819
+ setCanvasSize(); //sketchWidth, sketchHeight);
820
+
821
+ frame.addWindowListener(new WindowAdapter() {
822
+ @Override
823
+ public void windowClosing(WindowEvent e) {
824
+ System.exit(0);
825
+ }
826
+ });
827
+
828
+ // handle frame resizing events
829
+ setupFrameResizeListener();
830
+
831
+ // all set for rockin
832
+ if (sketch.getGraphics().displayable()) {
833
+ frame.setVisible(true);
834
+ }
835
+ }
836
+ */
837
+
838
+
839
+ private void setCanvasSize() {
840
+ // System.out.format("setting canvas size %d %d%n", sketchWidth, sketchHeight);
841
+ // new Exception().printStackTrace(System.out);
842
+ int contentW = Math.max(sketchWidth, MIN_WINDOW_WIDTH);
843
+ int contentH = Math.max(sketchHeight, MIN_WINDOW_HEIGHT);
844
+
845
+ canvas.setBounds((contentW - sketchWidth)/2,
846
+ (contentH - sketchHeight)/2,
847
+ sketchWidth, sketchHeight);
848
+ }
849
+
850
+
851
+ /** Resize frame for these sketch (canvas) dimensions. */
852
+ private Dimension setFrameSize() { //int sketchWidth, int sketchHeight) {
853
+ // https://github.com/processing/processing/pull/3162
854
+ frame.addNotify(); // using instead of show() to add the peer [fry]
855
+
856
+ // System.out.format("setting frame size %d %d %n", sketchWidth, sketchHeight);
857
+ // new Exception().printStackTrace(System.out);
858
+ currentInsets = frame.getInsets();
859
+ int windowW = Math.max(sketchWidth, MIN_WINDOW_WIDTH) +
860
+ currentInsets.left + currentInsets.right;
861
+ int windowH = Math.max(sketchHeight, MIN_WINDOW_HEIGHT) +
862
+ currentInsets.top + currentInsets.bottom;
863
+ frame.setSize(windowW, windowH);
864
+ return new Dimension(windowW, windowH);
865
+ }
866
+
867
+
868
+ private void setFrameCentered() {
869
+ // Can't use frame.setLocationRelativeTo(null) because it sends the
870
+ // frame to the main display, which undermines the --display setting.
871
+ frame.setLocation(screenRect.x + (screenRect.width - sketchWidth) / 2,
872
+ screenRect.y + (screenRect.height - sketchHeight) / 2);
873
+ }
874
+
875
+
876
+ /** Hide the menu bar, make the Frame undecorated, set it to screenRect. */
877
+ private void setFullFrame() {
878
+ // Called here because the graphics device is needed before we can
879
+ // determine whether the sketch wants size(displayWidth, displayHeight),
880
+ // and getting the graphics device will be PSurface-specific.
881
+ PApplet.hideMenuBar();
882
+
883
+ // Tried to use this to fix the 'present' mode issue.
884
+ // Did not help, and the screenRect setup seems to work fine.
885
+ //frame.setExtendedState(Frame.MAXIMIZED_BOTH);
886
+
887
+ // https://github.com/processing/processing/pull/3162
888
+ //frame.dispose(); // release native resources, allows setUndecorated()
889
+ frame.removeNotify();
890
+ frame.setUndecorated(true);
891
+ frame.addNotify();
892
+
893
+ // this may be the bounds of all screens
894
+ frame.setBounds(screenRect);
895
+ // will be set visible in placeWindow() [3.0a10]
896
+ //frame.setVisible(true); // re-add native resources
897
+ }
898
+
899
+
900
+ @Override
901
+ public void placeWindow(int[] location, int[] editorLocation) {
902
+ //Dimension window = setFrameSize(sketchWidth, sketchHeight);
903
+ Dimension window = setFrameSize(); //sketchWidth, sketchHeight);
904
+
905
+ int contentW = Math.max(sketchWidth, MIN_WINDOW_WIDTH);
906
+ int contentH = Math.max(sketchHeight, MIN_WINDOW_HEIGHT);
907
+
908
+ if (sketch.sketchFullScreen()) {
909
+ setFullFrame();
910
+ }
911
+
912
+ // Ignore placement of previous window and editor when full screen
913
+ if (!sketch.sketchFullScreen()) {
914
+ if (location != null) {
915
+ // a specific location was received from the Runner
916
+ // (applet has been run more than once, user placed window)
917
+ frame.setLocation(location[0], location[1]);
918
+
919
+ } else if (editorLocation != null) {
920
+ int locationX = editorLocation[0] - 20;
921
+ int locationY = editorLocation[1];
922
+
923
+ if (locationX - window.width > 10) {
924
+ // if it fits to the left of the window
925
+ frame.setLocation(locationX - window.width, locationY);
926
+
927
+ } else { // doesn't fit
928
+ // if it fits inside the editor window,
929
+ // offset slightly from upper lefthand corner
930
+ // so that it's plunked inside the text area
931
+ //locationX = editorLocation[0] + 66;
932
+ //locationY = editorLocation[1] + 66;
933
+ locationX = (sketch.displayWidth - window.width) / 2;
934
+ locationY = (sketch.displayHeight - window.height) / 2;
935
+
936
+ /*
937
+ if ((locationX + window.width > sketch.displayWidth - 33) ||
938
+ (locationY + window.height > sketch.displayHeight - 33)) {
939
+ // otherwise center on screen
940
+ locationX = (sketch.displayWidth - window.width) / 2;
941
+ locationY = (sketch.displayHeight - window.height) / 2;
942
+ }
943
+ */
944
+ frame.setLocation(locationX, locationY);
945
+ }
946
+ } else { // just center on screen
947
+ setFrameCentered();
948
+ }
949
+ Point frameLoc = frame.getLocation();
950
+ if (frameLoc.y < 0) {
951
+ // Windows actually allows you to place frames where they can't be
952
+ // closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508
953
+ frame.setLocation(frameLoc.x, 30);
954
+ }
955
+ }
956
+
957
+ canvas.setBounds((contentW - sketchWidth)/2,
958
+ (contentH - sketchHeight)/2,
959
+ sketchWidth, sketchHeight);
960
+
961
+ // handle frame resizing events
962
+ setupFrameResizeListener();
963
+
964
+ /*
965
+ // If displayable() is false, then PSurfaceNone should be used, but...
966
+ if (sketch.getGraphics().displayable()) {
967
+ frame.setVisible(true);
968
+ // System.out.println("setting visible on EDT? " + EventQueue.isDispatchThread());
969
+ //requestFocus();
970
+ // if (canvas != null) {
971
+ // //canvas.requestFocusInWindow();
972
+ // canvas.requestFocus();
973
+ // }
974
+ }
975
+ */
976
+ // if (sketch.getGraphics().displayable()) {
977
+ // setVisible(true);
978
+ // }
979
+ }
980
+
981
+
982
+ // needs to resize the frame, which will resize the canvas, and so on...
983
+ @Override
984
+ public void setSize(int wide, int high) {
985
+ // When the surface is set to resizable via surface.setResizable(true),
986
+ // a crash may occur if the user sets the window to size zero.
987
+ // https://github.com/processing/processing/issues/5052
988
+ if (high <= 0) {
989
+ high = 1;
990
+ }
991
+ if (wide <= 0) {
992
+ wide = 1;
993
+ }
994
+
995
+ // if (PApplet.DEBUG) {
996
+ // //System.out.format("frame visible %b, setSize(%d, %d) %n", frame.isVisible(), wide, high);
997
+ // new Exception(String.format("setSize(%d, %d)", wide, high)).printStackTrace(System.out);
998
+ // }
999
+
1000
+ //if (wide == sketchWidth && high == sketchHeight) { // doesn't work on launch
1001
+ if (wide == sketch.width && high == sketch.height &&
1002
+ (frame == null || currentInsets.equals(frame.getInsets()))) {
1003
+ // if (PApplet.DEBUG) {
1004
+ // new Exception("w/h unchanged " + wide + " " + high).printStackTrace(System.out);
1005
+ // }
1006
+ return; // unchanged, don't rebuild everything
1007
+ }
1008
+
1009
+ sketchWidth = wide * windowScaleFactor;
1010
+ sketchHeight = high * windowScaleFactor;
1011
+
1012
+ // canvas.setSize(wide, high);
1013
+ // frame.setSize(wide, high);
1014
+ if (frame != null) { // skip if just a canvas
1015
+ setFrameSize(); //wide, high);
1016
+ }
1017
+ setCanvasSize();
1018
+ // if (frame != null) {
1019
+ // frame.setLocationRelativeTo(null);
1020
+ // }
1021
+
1022
+ //initImage(graphics, wide, high);
1023
+
1024
+ //throw new RuntimeException("implement me, see readme.md");
1025
+ sketch.setSize(wide, high);
1026
+ // sketch.width = wide;
1027
+ // sketch.height = high;
1028
+
1029
+ // set PGraphics variables for width/height/pixelWidth/pixelHeight
1030
+ graphics.setSize(wide, high);
1031
+ // System.out.println("out of setSize()");
1032
+ }
1033
+
1034
+
1035
+ //public void initImage(PGraphics gr, int wide, int high) {
1036
+ /*
1037
+ @Override
1038
+ public void initImage(PGraphics graphics) {
1039
+ GraphicsConfiguration gc = canvas.getGraphicsConfiguration();
1040
+ // If not realized (off-screen, i.e the Color Selector Tool), gc will be null.
1041
+ if (gc == null) {
1042
+ System.err.println("GraphicsConfiguration null in initImage()");
1043
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
1044
+ gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
1045
+ }
1046
+
1047
+ // Formerly this was broken into separate versions based on offscreen or
1048
+ // not, but we may as well create a compatible image; it won't hurt, right?
1049
+ int wide = graphics.width * graphics.pixelFactor;
1050
+ int high = graphics.height * graphics.pixelFactor;
1051
+ graphics.image = gc.createCompatibleImage(wide, high);
1052
+ }
1053
+ */
1054
+
1055
+
1056
+ // @Override
1057
+ // public Component getComponent() {
1058
+ // return canvas;
1059
+ // }
1060
+
1061
+
1062
+ // @Override
1063
+ // public void setSmooth(int level) {
1064
+ // }
1065
+
1066
+
1067
+ /*
1068
+ private boolean checkRetina() {
1069
+ if (PApplet.platform == PConstants.MACOSX) {
1070
+ // This should probably be reset each time there's a display change.
1071
+ // A 5-minute search didn't turn up any such event in the Java 7 API.
1072
+ // Also, should we use the Toolkit associated with the editor window?
1073
+ final String javaVendor = System.getProperty("java.vendor");
1074
+ if (javaVendor.contains("Oracle")) {
1075
+ GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
1076
+ GraphicsDevice device = env.getDefaultScreenDevice();
1077
+
1078
+ try {
1079
+ Field field = device.getClass().getDeclaredField("scale");
1080
+ if (field != null) {
1081
+ field.setAccessible(true);
1082
+ Object scale = field.get(device);
1083
+
1084
+ if (scale instanceof Integer && ((Integer)scale).intValue() == 2) {
1085
+ return true;
1086
+ }
1087
+ }
1088
+ } catch (Exception ignore) { }
1089
+ }
1090
+ }
1091
+ return false;
1092
+ }
1093
+ */
1094
+
1095
+
1096
+ /** Get the bounds rectangle for all displays. */
1097
+ static Rectangle getDisplaySpan() {
1098
+ Rectangle bounds = new Rectangle();
1099
+ GraphicsEnvironment environment =
1100
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
1101
+ for (GraphicsDevice device : environment.getScreenDevices()) {
1102
+ for (GraphicsConfiguration config : device.getConfigurations()) {
1103
+ Rectangle2D.union(bounds, config.getBounds(), bounds);
1104
+ }
1105
+ }
1106
+ return bounds;
1107
+ }
1108
+
1109
+
1110
+ /*
1111
+ private void checkDisplaySize() {
1112
+ if (canvas.getGraphicsConfiguration() != null) {
1113
+ GraphicsDevice displayDevice = getGraphicsConfiguration().getDevice();
1114
+
1115
+ if (displayDevice != null) {
1116
+ Rectangle screenRect =
1117
+ displayDevice.getDefaultConfiguration().getBounds();
1118
+
1119
+ displayWidth = screenRect.width;
1120
+ displayHeight = screenRect.height;
1121
+ }
1122
+ }
1123
+ }
1124
+ */
1125
+
1126
+
1127
+ /**
1128
+ * Set this sketch to communicate its state back to the PDE.
1129
+ *
1130
+ * This uses the stderr stream to write positions of the window
1131
+ * (so that it will be saved by the PDE for the next run) and
1132
+ * notify on quit. See more notes in the Worker class.
1133
+ */
1134
+ @Override
1135
+ public void setupExternalMessages() {
1136
+ frame.addComponentListener(new ComponentAdapter() {
1137
+ @Override
1138
+ public void componentMoved(ComponentEvent e) {
1139
+ Point where = ((Frame) e.getSource()).getLocation();
1140
+ sketch.frameMoved(where.x, where.y);
1141
+ }
1142
+ });
1143
+ }
1144
+
1145
+
1146
+ /**
1147
+ * Set up a listener that will fire proper component resize events
1148
+ * in cases where frame.setResizable(true) is called.
1149
+ */
1150
+ private void setupFrameResizeListener() {
1151
+ frame.addWindowStateListener((WindowEvent e) -> {
1152
+ // This seems to be firing when dragging the window on OS X
1153
+ // https://github.com/processing/processing/issues/3092
1154
+ if (Frame.MAXIMIZED_BOTH == e.getNewState()) {
1155
+ // Supposedly, sending the frame to back and then front is a
1156
+ // workaround for this bug:
1157
+ // http://stackoverflow.com/a/23897602
1158
+ // but is not working for me...
1159
+ //frame.toBack();
1160
+ //frame.toFront();
1161
+ // Packing the frame works, but that causes the window to collapse
1162
+ // on OS X when the window is dragged. Changing to addNotify() for
1163
+ // https://github.com/processing/processing/issues/3092
1164
+ //frame.pack();
1165
+ frame.addNotify();
1166
+ }
1167
+ });
1168
+
1169
+ frame.addComponentListener(new ComponentAdapter() {
1170
+ @Override
1171
+ public void componentResized(ComponentEvent e) {
1172
+ // Ignore bad resize events fired during setup to fix
1173
+ // http://dev.processing.org/bugs/show_bug.cgi?id=341
1174
+ // This should also fix the blank screen on Linux bug
1175
+ // http://dev.processing.org/bugs/show_bug.cgi?id=282
1176
+ if (frame.isResizable()) {
1177
+ // might be multiple resize calls before visible (i.e. first
1178
+ // when pack() is called, then when it's resized for use).
1179
+ // ignore them because it's not the user resizing things.
1180
+ Frame farm = (Frame) e.getComponent();
1181
+ if (farm.isVisible()) {
1182
+ Dimension windowSize = farm.getSize();
1183
+ int x = farm.getX() + currentInsets.left;
1184
+ int y = farm.getY() + currentInsets.top;
1185
+
1186
+ // JFrame (unlike java.awt.Frame) doesn't include the left/top
1187
+ // insets for placement (though it does seem to need them for
1188
+ // overall size of the window. Perhaps JFrame sets its coord
1189
+ // system so that (0, 0) is always the upper-left of the content
1190
+ // area. Which seems nice, but breaks any f*ing AWT-based code.
1191
+ int w = windowSize.width - currentInsets.left - currentInsets.right;
1192
+ int h = windowSize.height - currentInsets.top - currentInsets.bottom;
1193
+ setSize(w / windowScaleFactor, h / windowScaleFactor);
1194
+
1195
+ // correct the location when inset size changes
1196
+ setLocation(x - currentInsets.left, y - currentInsets.top);
1197
+ }
1198
+ }
1199
+ }
1200
+ });
1201
+ }
1202
+
1203
+
1204
+ // /**
1205
+ // * (No longer in use) Use reflection to call
1206
+ // * <code>com.apple.eawt.FullScreenUtilities.setWindowCanFullScreen(window, true);</code>
1207
+ // */
1208
+ // static void macosxFullScreenEnable(Window window) {
1209
+ // try {
1210
+ // Class<?> util = Class.forName("com.apple.eawt.FullScreenUtilities");
1211
+ // Class params[] = new Class[] { Window.class, Boolean.TYPE };
1212
+ // Method method = util.getMethod("setWindowCanFullScreen", params);
1213
+ // method.invoke(util, window, true);
1214
+ //
1215
+ // } catch (ClassNotFoundException cnfe) {
1216
+ // // ignored
1217
+ // } catch (Exception e) {
1218
+ // e.printStackTrace();
1219
+ // }
1220
+ // }
1221
+ //
1222
+ //
1223
+ // /**
1224
+ // * (No longer in use) Use reflection to call
1225
+ // * <code>com.apple.eawt.Application.getApplication().requestToggleFullScreen(window);</code>
1226
+ // */
1227
+ // static void macosxFullScreenToggle(Window window) {
1228
+ // try {
1229
+ // Class<?> appClass = Class.forName("com.apple.eawt.Application");
1230
+ //
1231
+ // Method getAppMethod = appClass.getMethod("getApplication");
1232
+ // Object app = getAppMethod.invoke(null, new Object[0]);
1233
+ //
1234
+ // Method requestMethod =
1235
+ // appClass.getMethod("requestToggleFullScreen", Window.class);
1236
+ // requestMethod.invoke(app, window);
1237
+ //
1238
+ // } catch (ClassNotFoundException cnfe) {
1239
+ // // ignored
1240
+ // } catch (Exception e) {
1241
+ // e.printStackTrace();
1242
+ // }
1243
+ // }
1244
+
1245
+
1246
+ //////////////////////////////////////////////////////////////
1247
+
1248
+
1249
+ /*
1250
+ // disabling for now; requires Java 1.7 and "precise" semantics are odd...
1251
+ // returns 0.1 for tick-by-tick scrolling on OS X, but it's not a matter of
1252
+ // calling ceil() on the value: 1.5 goes to 1, but 2.3 goes to 2.
1253
+ // "precise" is a whole different animal, so add later API to shore that up.
1254
+ static protected Method preciseWheelMethod;
1255
+ static {
1256
+ try {
1257
+ preciseWheelMethod = MouseWheelEvent.class.getMethod("getPreciseWheelRotation", new Class[] { });
1258
+ } catch (Exception e) {
1259
+ // ignored, the method will just be set to null
1260
+ }
1261
+ }
1262
+ */
1263
+
1264
+
1265
+ /**
1266
+ * Figure out how to process a mouse event.When loop() has been
1267
+ called, the events will be queued up until drawing is complete. If noLoop() has been called, then events will happen immediately.
1268
+ * @param nativeEvent
1269
+ */
1270
+ protected void nativeMouseEvent(java.awt.event.MouseEvent nativeEvent) {
1271
+ // the 'amount' is the number of button clicks for a click event,
1272
+ // or the number of steps/clicks on the wheel for a mouse wheel event.
1273
+ int peCount = nativeEvent.getClickCount();
1274
+
1275
+ int peAction = 0;
1276
+ switch (nativeEvent.getID()) {
1277
+ case java.awt.event.MouseEvent.MOUSE_PRESSED:
1278
+ peAction = MouseEvent.PRESS;
1279
+ break;
1280
+ case java.awt.event.MouseEvent.MOUSE_RELEASED:
1281
+ peAction = MouseEvent.RELEASE;
1282
+ break;
1283
+ case java.awt.event.MouseEvent.MOUSE_CLICKED:
1284
+ peAction = MouseEvent.CLICK;
1285
+ break;
1286
+ case java.awt.event.MouseEvent.MOUSE_DRAGGED:
1287
+ peAction = MouseEvent.DRAG;
1288
+ break;
1289
+ case java.awt.event.MouseEvent.MOUSE_MOVED:
1290
+ peAction = MouseEvent.MOVE;
1291
+ break;
1292
+ case java.awt.event.MouseEvent.MOUSE_ENTERED:
1293
+ peAction = MouseEvent.ENTER;
1294
+ break;
1295
+ case java.awt.event.MouseEvent.MOUSE_EXITED:
1296
+ peAction = MouseEvent.EXIT;
1297
+ break;
1298
+ //case java.awt.event.MouseWheelEvent.WHEEL_UNIT_SCROLL:
1299
+ case java.awt.event.MouseEvent.MOUSE_WHEEL:
1300
+ peAction = MouseEvent.WHEEL;
1301
+ /*
1302
+ if (preciseWheelMethod != null) {
1303
+ try {
1304
+ peAmount = ((Double) preciseWheelMethod.invoke(nativeEvent, (Object[]) null)).floatValue();
1305
+ } catch (Exception e) {
1306
+ preciseWheelMethod = null;
1307
+ }
1308
+ }
1309
+ */
1310
+ peCount = ((MouseWheelEvent) nativeEvent).getWheelRotation();
1311
+ break;
1312
+ }
1313
+
1314
+ // Switching to getModifiersEx() for 4.0a2 because of Java 9 deprecation.
1315
+ // Had trouble with this in the past and rolled it back because it was
1316
+ // optional at the time. This time around, just need to iron out the issue.
1317
+ // http://code.google.com/p/processing/issues/detail?id=1294
1318
+ // http://code.google.com/p/processing/issues/detail?id=1332
1319
+ int modifiers = nativeEvent.getModifiersEx();
1320
+
1321
+ int peButton = 0;
1322
+ if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0) {
1323
+ peButton = PConstants.LEFT;
1324
+ } else if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0) {
1325
+ peButton = PConstants.CENTER;
1326
+ } else if ((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0) {
1327
+ peButton = PConstants.RIGHT;
1328
+ }
1329
+
1330
+ sketch.postEvent(new MouseEvent(nativeEvent, nativeEvent.getWhen(),
1331
+ peAction, modifiers,
1332
+ nativeEvent.getX() / windowScaleFactor,
1333
+ nativeEvent.getY() / windowScaleFactor,
1334
+ peButton,
1335
+ peCount));
1336
+ }
1337
+
1338
+
1339
+ protected void nativeKeyEvent(java.awt.event.KeyEvent event) {
1340
+ int peAction = 0;
1341
+ switch (event.getID()) {
1342
+ case java.awt.event.KeyEvent.KEY_PRESSED:
1343
+ peAction = KeyEvent.PRESS;
1344
+ break;
1345
+ case java.awt.event.KeyEvent.KEY_RELEASED:
1346
+ peAction = KeyEvent.RELEASE;
1347
+ break;
1348
+ case java.awt.event.KeyEvent.KEY_TYPED:
1349
+ peAction = KeyEvent.TYPE;
1350
+ break;
1351
+ }
1352
+
1353
+ int modifiers = event.getModifiersEx();
1354
+
1355
+ /*
1356
+ // int peModifiers = event.getModifiersEx() &
1357
+ // (InputEvent.SHIFT_DOWN_MASK |
1358
+ // InputEvent.CTRL_DOWN_MASK |
1359
+ // InputEvent.META_DOWN_MASK |
1360
+ // InputEvent.ALT_DOWN_MASK);
1361
+ int peModifiers = event.getModifiers() &
1362
+ (InputEvent.SHIFT_MASK |
1363
+ InputEvent.CTRL_MASK |
1364
+ InputEvent.META_MASK |
1365
+ InputEvent.ALT_MASK);
1366
+ */
1367
+
1368
+ sketch.postEvent(new KeyEvent(event, event.getWhen(),
1369
+ peAction, modifiers,
1370
+ event.getKeyChar(), event.getKeyCode()));
1371
+ }
1372
+
1373
+
1374
+ // listeners, for all my men!
1375
+ protected void addListeners() {
1376
+
1377
+ canvas.addMouseListener(new MouseListener() {
1378
+
1379
+ @Override
1380
+ public void mousePressed(java.awt.event.MouseEvent e) {
1381
+ nativeMouseEvent(e);
1382
+ }
1383
+
1384
+ @Override
1385
+ public void mouseReleased(java.awt.event.MouseEvent e) {
1386
+ nativeMouseEvent(e);
1387
+ }
1388
+
1389
+ @Override
1390
+ public void mouseClicked(java.awt.event.MouseEvent e) {
1391
+ nativeMouseEvent(e);
1392
+ }
1393
+
1394
+ @Override
1395
+ public void mouseEntered(java.awt.event.MouseEvent e) {
1396
+ nativeMouseEvent(e);
1397
+ }
1398
+
1399
+ @Override
1400
+ public void mouseExited(java.awt.event.MouseEvent e) {
1401
+ nativeMouseEvent(e);
1402
+ }
1403
+ });
1404
+
1405
+ canvas.addMouseMotionListener(new MouseMotionListener() {
1406
+
1407
+ @Override
1408
+ public void mouseDragged(java.awt.event.MouseEvent e) {
1409
+ nativeMouseEvent(e);
1410
+ }
1411
+
1412
+ @Override
1413
+ public void mouseMoved(java.awt.event.MouseEvent e) {
1414
+ nativeMouseEvent(e);
1415
+ }
1416
+ });
1417
+
1418
+ canvas.addMouseWheelListener((MouseWheelEvent e) -> {
1419
+ nativeMouseEvent(e);
1420
+ });
1421
+
1422
+ canvas.addKeyListener(new KeyListener() {
1423
+
1424
+ @Override
1425
+ public void keyPressed(java.awt.event.KeyEvent e) {
1426
+ nativeKeyEvent(e);
1427
+ }
1428
+
1429
+
1430
+ @Override
1431
+ public void keyReleased(java.awt.event.KeyEvent e) {
1432
+ nativeKeyEvent(e);
1433
+ }
1434
+
1435
+
1436
+ @Override
1437
+ public void keyTyped(java.awt.event.KeyEvent e) {
1438
+ nativeKeyEvent(e);
1439
+ }
1440
+ });
1441
+
1442
+ canvas.addFocusListener(new FocusListener() {
1443
+
1444
+ @Override
1445
+ public void focusGained(FocusEvent e) {
1446
+ sketch.focused = true;
1447
+ sketch.focusGained();
1448
+ }
1449
+
1450
+ @Override
1451
+ public void focusLost(FocusEvent e) {
1452
+ sketch.focused = false;
1453
+ sketch.focusLost();
1454
+ }
1455
+ });
1456
+ }
1457
+
1458
+
1459
+ /*
1460
+ public void addListeners(Component comp) {
1461
+ comp.addMouseListener(this);
1462
+ comp.addMouseWheelListener(this);
1463
+ comp.addMouseMotionListener(this);
1464
+ comp.addKeyListener(this);
1465
+ comp.addFocusListener(this);
1466
+ }
1467
+
1468
+
1469
+ public void removeListeners(Component comp) {
1470
+ comp.removeMouseListener(this);
1471
+ comp.removeMouseWheelListener(this);
1472
+ comp.removeMouseMotionListener(this);
1473
+ comp.removeKeyListener(this);
1474
+ comp.removeFocusListener(this);
1475
+ }
1476
+ */
1477
+
1478
+
1479
+ // /**
1480
+ // * Call to remove, then add, listeners to a component.
1481
+ // * Avoids issues with double-adding.
1482
+ // */
1483
+ // public void updateListeners(Component comp) {
1484
+ // removeListeners(comp);
1485
+ // addListeners(comp);
1486
+ // }
1487
+
1488
+
1489
+
1490
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1491
+
1492
+
1493
+ int cursorType = PConstants.ARROW;
1494
+ boolean cursorVisible = true;
1495
+ Cursor invisibleCursor;
1496
+
1497
+
1498
+ @Override
1499
+ public void setCursor(int kind) {
1500
+ // Swap the HAND cursor because MOVE doesn't seem to be available on OS X
1501
+ // https://github.com/processing/processing/issues/2358
1502
+ if (PApplet.platform == PConstants.MACOS && kind == PConstants.MOVE) {
1503
+ kind = PConstants.HAND;
1504
+ }
1505
+ canvas.setCursor(Cursor.getPredefinedCursor(kind));
1506
+ cursorVisible = true;
1507
+ this.cursorType = kind;
1508
+ }
1509
+
1510
+
1511
+ @Override
1512
+ public void setCursor(PImage img, int x, int y) {
1513
+ // Don't set cursorType, instead use cursorType to save the last
1514
+ // regular cursor type used for when cursor() is called.
1515
+ //cursor_type = Cursor.CUSTOM_CURSOR;
1516
+
1517
+ // this is a temporary workaround for the CHIP, will be removed
1518
+ Dimension cursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(img.width, img.height);
1519
+ if (cursorSize.width == 0 || cursorSize.height == 0) {
1520
+ return;
1521
+ }
1522
+
1523
+ Cursor cursor =
1524
+ canvas.getToolkit().createCustomCursor((Image) img.getNative(),
1525
+ new Point(x, y),
1526
+ "custom");
1527
+ canvas.setCursor(cursor);
1528
+ cursorVisible = true;
1529
+ }
1530
+
1531
+
1532
+ @Override
1533
+ public void showCursor() {
1534
+ // Maybe should always set here? Seems dangerous, since it's likely that
1535
+ // Java will set the cursor to something else on its own, and the sketch
1536
+ // will be stuck b/c p5 thinks the cursor is set to one particular thing.
1537
+ if (!cursorVisible) {
1538
+ cursorVisible = true;
1539
+ canvas.setCursor(Cursor.getPredefinedCursor(cursorType));
1540
+ }
1541
+ }
1542
+
1543
+
1544
+ @Override
1545
+ public void hideCursor() {
1546
+ // Because the OS may have shown the cursor on its own,
1547
+ // don't return if 'cursorVisible' is set to true. [rev 0216]
1548
+
1549
+ if (invisibleCursor == null) {
1550
+ BufferedImage cursorImg =
1551
+ new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
1552
+ // this is a temporary workaround for the CHIP, will be removed
1553
+ Dimension cursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(16, 16);
1554
+ if (cursorSize.width == 0 || cursorSize.height == 0) {
1555
+ invisibleCursor = Cursor.getDefaultCursor();
1556
+ } else {
1557
+ invisibleCursor =
1558
+ canvas.getToolkit().createCustomCursor(cursorImg, new Point(8, 8), "blank");
1559
+ }
1560
+ }
1561
+ canvas.setCursor(invisibleCursor);
1562
+ cursorVisible = false;
1563
+ }
1564
+
1565
+
1566
+ @Override
1567
+ public Thread createThread() {
1568
+ return new AnimationThread() {
1569
+ @Override
1570
+ public void callDraw() {
1571
+ sketch.handleDraw();
1572
+ render();
1573
+ }
1574
+ };
1575
+ }
1576
+
1577
+
1578
+ void debug(String format, Object ... args) {
1579
+ System.out.format(format + "%n", args);
1580
+ }
1581
+ }