| /* |
| * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| package transparentruler; |
| |
| |
| import java.awt.*; |
| import java.awt.GraphicsDevice.WindowTranslucency; |
| import static java.awt.GraphicsDevice.WindowTranslucency.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ComponentAdapter; |
| import java.awt.event.ComponentEvent; |
| import java.awt.event.KeyAdapter; |
| import java.awt.event.KeyEvent; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.awt.geom.Path2D.Float; |
| import java.lang.reflect.InvocationTargetException; |
| import javax.swing.AbstractAction; |
| import javax.swing.Action; |
| import javax.swing.JFrame; |
| import javax.swing.JMenuItem; |
| import javax.swing.JPanel; |
| import javax.swing.JPopupMenu; |
| import javax.swing.SwingUtilities; |
| import javax.swing.WindowConstants; |
| |
| |
| /** |
| * This sample demonstrates shaped and translucent window feature. |
| * @author Alexander Kouznetsov |
| */ |
| @SuppressWarnings("serial") |
| public class Ruler extends JFrame { |
| |
| private static final Color BACKGROUND = Color.RED; |
| private static final Color FOREGROUND = Color.WHITE; |
| private static final int OPACITY = 180; |
| private static final int W = 70; |
| private static final int F_HEIGHT = 400; |
| private static final int F_WIDTH = (int) (F_HEIGHT * 1.618 + 0.5); |
| |
| private static boolean translucencySupported; |
| private static boolean transparencySupported; |
| |
| private static boolean checkTranslucencyMode(WindowTranslucency arg) { |
| GraphicsEnvironment ge = |
| GraphicsEnvironment.getLocalGraphicsEnvironment(); |
| GraphicsDevice gd = ge.getDefaultScreenDevice(); |
| return gd.isWindowTranslucencySupported(arg); |
| } |
| |
| public Shape buildShape() { |
| int h = getHeight(); |
| int w = getWidth(); |
| float a = (float) Math.hypot(h, w); |
| Float path = new java.awt.geom.Path2D.Float(); |
| path.moveTo(0, 0); |
| path.lineTo(w, 0); |
| path.lineTo(0, h); |
| path.closePath(); |
| path.moveTo(W, W); |
| path.lineTo(W, h - W * (a + h) / w); |
| path.lineTo(w - W * (a + w) / h, W); |
| path.closePath(); |
| return path; |
| } |
| |
| private final ComponentAdapter componentListener = new ComponentAdapter() { |
| |
| /** |
| * Applies the shape to window. It is recommended to apply shape in |
| * componentResized() method |
| */ |
| @Override |
| public void componentResized(ComponentEvent e) { |
| |
| // We do apply shape only if PERPIXEL_TRANSPARENT is supported |
| if (transparencySupported) { |
| setShape(buildShape()); |
| } |
| } |
| }; |
| |
| private final Action exitAction = new AbstractAction("Exit") { |
| |
| { |
| putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X); |
| } |
| |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| System.exit(0); |
| } |
| }; |
| |
| private final JPopupMenu jPopupMenu = new JPopupMenu(); |
| |
| { |
| jPopupMenu.add(new JMenuItem(exitAction)); |
| |
| // To avoid popup cutting by main window shape forbid light-weight popups |
| jPopupMenu.setLightWeightPopupEnabled(false); |
| } |
| |
| /** |
| * Implements mouse-related behavior: window dragging and popup menu |
| * invocation |
| */ |
| private final MouseAdapter mouseListener = new MouseAdapter() { |
| |
| int x, y; |
| |
| @Override |
| public void mousePressed(MouseEvent e) { |
| if (e.getButton() == MouseEvent.BUTTON1) { |
| x = e.getX(); |
| y = e.getY(); |
| } |
| } |
| |
| @Override |
| public void mouseDragged(MouseEvent e) { |
| if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0) { |
| setLocation(e.getXOnScreen() - x, e.getYOnScreen() - y); |
| } |
| } |
| |
| @Override |
| public void mouseReleased(MouseEvent e) { |
| if (e.isPopupTrigger()) { |
| jPopupMenu.show(getContentPane(), e.getX(), e.getY()); |
| } |
| } |
| }; |
| |
| /** |
| * Implements keyboard navigation. Arrows move by 5 pixels, Ctrl + arrows |
| * move by 50 pixels, Alt + arrows move by 1 pixel. |
| * Esc exits the application. |
| */ |
| private final KeyAdapter keyboardListener = new KeyAdapter() { |
| |
| @Override |
| public void keyPressed(KeyEvent e) { |
| int step = e.isControlDown() ? 50 : e.isAltDown() ? 1 : 5; |
| switch (e.getKeyCode()) { |
| case KeyEvent.VK_LEFT: |
| setLocation(getX() - step, getY()); |
| break; |
| case KeyEvent.VK_RIGHT: |
| setLocation(getX() + step, getY()); |
| break; |
| case KeyEvent.VK_UP: |
| setLocation(getX(), getY() - step); |
| break; |
| case KeyEvent.VK_DOWN: |
| setLocation(getX(), getY() + step); |
| break; |
| case KeyEvent.VK_ESCAPE: |
| exitAction.actionPerformed(null); |
| } |
| } |
| }; |
| |
| public Ruler() { |
| setUndecorated(true); |
| |
| // Enables perpixel translucency |
| setBackground(new Color(BACKGROUND.getRed(), BACKGROUND.getGreen(), |
| BACKGROUND.getBlue(), OPACITY)); |
| |
| addMouseListener(mouseListener); |
| addMouseMotionListener(mouseListener); |
| addComponentListener(componentListener); |
| addKeyListener(keyboardListener); |
| setContentPane(new JPanel() { |
| |
| @Override |
| protected void paintComponent(Graphics g) { |
| Graphics2D gg = (Graphics2D) g.create(); |
| int w = getWidth(); |
| int h = getHeight(); |
| int hh = gg.getFontMetrics().getAscent(); |
| |
| // This is an approach to apply shape when PERPIXEL_TRANSPARENT |
| // isn't supported |
| if (!transparencySupported) { |
| gg.setBackground(new Color(0, 0, 0, 0)); |
| gg.clearRect(0, 0, w, h); |
| gg.clip(buildShape()); |
| |
| gg.setBackground(Ruler.this.getBackground()); |
| gg.clearRect(0, 0, w, h); |
| } |
| |
| gg.setColor(FOREGROUND); |
| for (int x = 0; x < w * (h - 8) / h - 5; x += 5) { |
| boolean hi = x % 50 == 0; |
| gg.drawLine(x + 5, 0, x + 5, |
| hi ? 20 : (x % 25 == 0 ? 13 : 8)); |
| if (hi) { |
| String number = Integer.toString(x); |
| int ww = gg.getFontMetrics().stringWidth(number); |
| gg.drawString(number, x + 5 - ww / 2, 20 + hh); |
| } |
| } |
| |
| gg.dispose(); |
| } |
| }); |
| setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); |
| setSize(F_WIDTH, F_HEIGHT); |
| setLocationByPlatform(true); |
| } |
| |
| /** |
| * @param args the command line arguments are ignored |
| */ |
| public static void main(String[] args) throws InterruptedException, InvocationTargetException { |
| |
| SwingUtilities.invokeAndWait(new Runnable() { |
| |
| @Override |
| public void run() { |
| translucencySupported = checkTranslucencyMode(PERPIXEL_TRANSLUCENT); |
| transparencySupported = checkTranslucencyMode(PERPIXEL_TRANSPARENT); |
| |
| if (!translucencySupported) { |
| System.err.println("This application requires " |
| + "'PERPIXEL_TRANSLUCENT' translucency mode to " |
| + "be supported."); |
| System.exit(-1); |
| } |
| |
| Ruler ruler = new Ruler(); |
| ruler.setVisible(true); |
| } |
| }); |
| } |
| } |