diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java index 10f8a4d797edbf09fda291719df551e85554a539..799af373a1eff41a2c04e49bcde16005baf2a2df 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -27,8 +27,6 @@ import java.util.ArrayList; import com.oracle.truffle.r.library.fastrGrid.GridState.GridDeviceState; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice.DeviceCloseException; -import com.oracle.truffle.r.library.fastrGrid.device.awt.BufferedJFrameDevice; -import com.oracle.truffle.r.library.fastrGrid.device.awt.JFrameDevice; import com.oracle.truffle.r.library.fastrGrid.graphics.RGridGraphicsAdapter; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; @@ -89,8 +87,7 @@ public final class GridContext { public void openDefaultDevice() { String defaultDev = RGridGraphicsAdapter.getDefaultDevice(); if (defaultDev.equals("awt") || defaultDev.startsWith("X11")) { - BufferedJFrameDevice result = new BufferedJFrameDevice(JFrameDevice.create(GridDevice.DEFAULT_WIDTH, GridDevice.DEFAULT_HEIGHT)); - setCurrentDevice(defaultDev, result); + setCurrentDevice(defaultDev, WindowDevice.createWindowDevice()); } else { throw RError.error(RError.NO_CALLER, Message.GENERIC, "FastR does not support device '" + defaultDev + "'."); } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java new file mode 100644 index 0000000000000000000000000000000000000000..4ae0265a3882cab15161dd01c7b65f6f654af53c --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.library.fastrGrid; + +import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; +import com.oracle.truffle.r.library.fastrGrid.device.awt.BufferedJFrameDevice; +import com.oracle.truffle.r.library.fastrGrid.device.awt.JFrameDevice; + +/** + * Contains code specific to FastR device that shows the graphical output interactively in a window. + */ +public final class WindowDevice { + private WindowDevice() { + // only static members + } + + public static GridDevice createWindowDevice() { + return createWindowDevice(GridDevice.DEFAULT_WIDTH, GridDevice.DEFAULT_HEIGHT); + } + + public static GridDevice createWindowDevice(int width, int height) { + JFrameDevice frameDevice = JFrameDevice.create(width, height); + return new BufferedJFrameDevice(frameDevice); + } +} diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java index a99d30e2d1f29731409bc78a5ca1779328a609a6..90bf1adc20281dd8002220b8599c20c35214d8ea 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java @@ -91,7 +91,7 @@ public class Graphics2DDevice implements GridDevice { @Override public void openNewPage() { - graphics.clearRect(0, 0, width, height); + graphics.clearRect(0, 0, getWidthAwt(), getHeightAwt()); } @Override @@ -142,12 +142,12 @@ public class Graphics2DDevice implements GridDevice { @Override public double getWidth() { - return width / AWT_POINTS_IN_INCH; + return getWidthAwt() / AWT_POINTS_IN_INCH; } @Override public double getHeight() { - return height / AWT_POINTS_IN_INCH; + return getHeightAwt() / AWT_POINTS_IN_INCH; } @Override @@ -165,6 +165,20 @@ public class Graphics2DDevice implements GridDevice { return swingUnits / AWT_POINTS_IN_INCH; } + /** + * Allows to override the default fixed width behavior with dynamically computed width. + */ + int getWidthAwt() { + return width; + } + + /** + * Allows to override the default fixed height behavior with dynamically computed height. + */ + int getHeightAwt() { + return height; + } + void setGraphics2D(Graphics2D newGraphics) { assert newGraphics != null; graphics = newGraphics; @@ -175,7 +189,7 @@ public class Graphics2DDevice implements GridDevice { } private int transY(double y) { - return height - (int) (y * AWT_POINTS_IN_INCH); + return getHeightAwt() - (int) (y * AWT_POINTS_IN_INCH); } private static int transX(double x) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java index 7571ced32fe356ba76c1e85273c5231eed22a3d1..b9faaaa9ffbda0758f11f75e2f2a8b268917f2f5 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java @@ -27,8 +27,12 @@ import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.HeadlessException; import java.awt.Toolkit; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.Timer; +import java.util.TimerTask; import javax.swing.JFrame; import javax.swing.JPanel; @@ -37,6 +41,7 @@ public final class JFrameDevice extends Graphics2DDevice { private final JFrame currentFrame; private final boolean disposeResources; + private Runnable onResize; /** * @param frame The frame that should be used for drawing. @@ -49,6 +54,9 @@ public final class JFrameDevice extends Graphics2DDevice { super(graphics, frame.getContentPane().getWidth(), frame.getContentPane().getHeight(), true); currentFrame = frame; this.disposeResources = disposeResources; + if (currentFrame instanceof FastRFrame) { + ((FastRFrame) currentFrame).device = this; + } } /** @@ -72,6 +80,20 @@ public final class JFrameDevice extends Graphics2DDevice { } } + @Override + int getWidthAwt() { + return currentFrame.getContentPane().getWidth(); + } + + @Override + int getHeightAwt() { + return currentFrame.getContentPane().getHeight(); + } + + public void setResizeListener(Runnable onResize) { + this.onResize = onResize; + } + JFrame getCurrentFrame() { return currentFrame; } @@ -79,12 +101,20 @@ public final class JFrameDevice extends Graphics2DDevice { static class FastRFrame extends JFrame { private static final long serialVersionUID = 1L; private final JPanel fastRComponent = new JPanel(); + private JFrameDevice device; + + volatile boolean resizeScheduled = false; + private int oldWidth; + private int oldHeight; + private final Timer timer = new Timer(); FastRFrame(int width, int height) throws HeadlessException { super("FastR"); - addCloseListener(); + addListeners(); createUI(width, height); center(); + oldWidth = width; + oldHeight = height; } private void createUI(int width, int height) { @@ -94,13 +124,35 @@ public final class JFrameDevice extends Graphics2DDevice { fastRComponent.setPreferredSize(getSize()); } - private void addCloseListener() { + private void addListeners() { addWindowFocusListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { dispose(); } }); + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + if (oldHeight == getHeight() && oldWidth == getWidth()) { + return; + } + if (!resizeScheduled) { + resizeScheduled = true; + timer.schedule(new TimerTask() { + @Override + public void run() { + oldWidth = getWidth(); + oldHeight = getHeight(); + resizeScheduled = false; + if (device.onResize != null) { + device.onResize.run(); + } + } + }, 1000); + } + } + }); } private void center() { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R index d799ca533c6b3089920dbdce13a7307f9f01280a..068c5fb4f50a1c2eb42ef574881321d47aee4db3 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/fastrGrid.R @@ -15,6 +15,11 @@ # logic to R. Some functions implement whole externals, like L_downvppath, some implement coherent # parts of the logic and the rest is in Java. +# Used by the interactive device to redraw the whole scene if the window gets resized. +redrawAll <- function() { + popViewport(0, recording = FALSE) + grid:::draw.all() +} # chull from grDevices package is used in EdgeDetection.java # Note: chull calls to native function, which we may consider diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java index 52fe6b7900d78cfff8120be09557d0a39cd532b0..1fdc13be7449408ce369ebfabe6fc5dcd90aadbd 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/InitWindowedDevice.java @@ -28,12 +28,11 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.r.library.fastrGrid.GridContext; +import com.oracle.truffle.r.library.fastrGrid.WindowDevice; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.library.fastrGrid.device.awt.BufferedImageDevice; import com.oracle.truffle.r.library.fastrGrid.device.awt.BufferedImageDevice.NotSupportedImageFormatException; -import com.oracle.truffle.r.library.fastrGrid.device.awt.BufferedJFrameDevice; import com.oracle.truffle.r.library.fastrGrid.device.awt.Graphics2DDevice; -import com.oracle.truffle.r.library.fastrGrid.device.awt.JFrameDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; @@ -84,7 +83,7 @@ public final class InitWindowedDevice extends RExternalBuiltinNode { } // otherwise create the window ourselves - BufferedJFrameDevice device = new BufferedJFrameDevice(JFrameDevice.create(width, height)); + GridDevice device = WindowDevice.createWindowDevice(width, height); String name = isFastRDevice ? "awt" : "X11cairo"; GridContext.getContext().setCurrentDevice(name, device); return RNull.instance;