1 /* 2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 package transparentruler; 41 42 43 import java.awt.*; 44 import java.awt.GraphicsDevice.WindowTranslucency; 45 import static java.awt.GraphicsDevice.WindowTranslucency.*; 46 import java.awt.event.ActionEvent; 47 import java.awt.event.ComponentAdapter; 48 import java.awt.event.ComponentEvent; 49 import java.awt.event.KeyAdapter; 50 import java.awt.event.KeyEvent; 51 import java.awt.event.MouseAdapter; 52 import java.awt.event.MouseEvent; 53 import java.awt.geom.Path2D.Float; 54 import java.lang.reflect.InvocationTargetException; 55 import javax.swing.AbstractAction; 56 import javax.swing.Action; 57 import javax.swing.JFrame; 58 import javax.swing.JMenuItem; 59 import javax.swing.JPanel; 60 import javax.swing.JPopupMenu; 61 import javax.swing.SwingUtilities; 62 import javax.swing.WindowConstants; 63 64 65 /** 66 * This sample demonstrates shaped and translucent window feature. 67 * @author Alexander Kouznetsov 68 */ 69 @SuppressWarnings("serial") 70 public class Ruler extends JFrame { 71 72 private static final Color BACKGROUND = Color.RED; 73 private static final Color FOREGROUND = Color.WHITE; 74 private static final int OPACITY = 180; 75 private static final int W = 70; 76 private static final int F_HEIGHT = 400; 77 private static final int F_WIDTH = (int) (F_HEIGHT * 1.618 + 0.5); 78 79 private static boolean translucencySupported; 80 private static boolean transparencySupported; 81 82 private static boolean checkTranslucencyMode(WindowTranslucency arg) { 83 GraphicsEnvironment ge = 84 GraphicsEnvironment.getLocalGraphicsEnvironment(); 85 GraphicsDevice gd = ge.getDefaultScreenDevice(); 86 return gd.isWindowTranslucencySupported(arg); 87 } 88 89 public Shape buildShape() { 90 int h = getHeight(); 91 int w = getWidth(); 92 float a = (float) Math.hypot(h, w); 93 Float path = new java.awt.geom.Path2D.Float(); 94 path.moveTo(0, 0); 95 path.lineTo(w, 0); 96 path.lineTo(0, h); 97 path.closePath(); 98 path.moveTo(W, W); 99 path.lineTo(W, h - W * (a + h) / w); 100 path.lineTo(w - W * (a + w) / h, W); 101 path.closePath(); 102 return path; 103 } 104 105 private final ComponentAdapter componentListener = new ComponentAdapter() { 106 107 /** 108 * Applies the shape to window. It is recommended to apply shape in 109 * componentResized() method 110 */ 111 @Override 112 public void componentResized(ComponentEvent e) { 113 114 // We do apply shape only if PERPIXEL_TRANSPARENT is supported 115 if (transparencySupported) { 116 setShape(buildShape()); 117 } 118 } 119 }; 120 121 private final Action exitAction = new AbstractAction("Exit") { 122 123 { 124 putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X); 125 } 126 127 @Override 128 public void actionPerformed(ActionEvent e) { 129 System.exit(0); 130 } 131 }; 132 133 private final JPopupMenu jPopupMenu = new JPopupMenu(); 134 135 { 136 jPopupMenu.add(new JMenuItem(exitAction)); 137 } 138 139 /** 140 * Implements mouse-related behavior: window dragging and popup menu 141 * invocation 142 */ 143 private final MouseAdapter mouseListener = new MouseAdapter() { 144 145 int x, y; 146 147 @Override 148 public void mousePressed(MouseEvent e) { 149 if (e.getButton() == MouseEvent.BUTTON1) { 150 x = e.getX(); 151 y = e.getY(); 152 } 153 } 154 155 @Override 156 public void mouseDragged(MouseEvent e) { 157 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0) { 158 setLocation(e.getXOnScreen() - x, e.getYOnScreen() - y); 159 } 160 } 161 162 @Override 163 public void mouseReleased(MouseEvent e) { 164 if (e.isPopupTrigger()) { 165 jPopupMenu.show(getContentPane(), e.getX(), e.getY()); 166 } 167 } 168 }; 169 170 /** 171 * Implements keyboard navigation. Arrows move by 5 pixels, Ctrl + arrows 172 * move by 50 pixels, Alt + arrows move by 1 pixel. 173 * Esc exits the application. 174 */ 175 private final KeyAdapter keyboardListener = new KeyAdapter() { 176 177 @Override 178 public void keyPressed(KeyEvent e) { 179 int step = e.isControlDown() ? 50 : e.isAltDown() ? 1 : 5; 180 switch (e.getKeyCode()) { 181 case KeyEvent.VK_LEFT: 182 setLocation(getX() - step, getY()); 183 break; 184 case KeyEvent.VK_RIGHT: 185 setLocation(getX() + step, getY()); 186 break; 187 case KeyEvent.VK_UP: 188 setLocation(getX(), getY() - step); 189 break; 190 case KeyEvent.VK_DOWN: 191 setLocation(getX(), getY() + step); 192 break; 193 case KeyEvent.VK_ESCAPE: 194 exitAction.actionPerformed(null); 195 } 196 } 197 }; 198 199 public Ruler() { 200 setUndecorated(true); 201 202 // Enables perpixel translucency 203 setBackground(new Color(BACKGROUND.getRed(), BACKGROUND.getGreen(), 204 BACKGROUND.getBlue(), OPACITY)); 205 206 addMouseListener(mouseListener); 207 addMouseMotionListener(mouseListener); 208 addComponentListener(componentListener); 209 addKeyListener(keyboardListener); 210 setContentPane(new JPanel() { 211 212 @Override 213 protected void paintComponent(Graphics g) { 214 Graphics2D gg = (Graphics2D) g.create(); 215 int w = getWidth(); 216 int h = getHeight(); 217 int hh = gg.getFontMetrics().getAscent(); 218 219 // This is an approach to apply shape when PERPIXEL_TRANSPARENT 220 // isn't supported 221 if (!transparencySupported) { 222 gg.setBackground(new Color(0, 0, 0, 0)); 223 gg.clearRect(0, 0, w, h); 224 gg.clip(buildShape()); 225 226 gg.setBackground(Ruler.this.getBackground()); 227 gg.clearRect(0, 0, w, h); 228 } 229 230 gg.setColor(FOREGROUND); 231 for (int x = 0; x < w * (h - 8) / h - 5; x += 5) { 232 boolean hi = x % 50 == 0; 233 gg.drawLine(x + 5, 0, x + 5, 234 hi ? 20 : (x % 25 == 0 ? 13 : 8)); 235 if (hi) { 236 String number = Integer.toString(x); 237 int ww = gg.getFontMetrics().stringWidth(number); 238 gg.drawString(number, x + 5 - ww / 2, 20 + hh); 239 } 240 } 241 242 gg.dispose(); 243 } 244 }); 245 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 246 setSize(F_WIDTH, F_HEIGHT); 247 setLocationByPlatform(true); 248 } 249 250 /** 251 * @param args the command line arguments are ignored 252 */ 253 public static void main(String[] args) throws InterruptedException, InvocationTargetException { 254 255 SwingUtilities.invokeAndWait(new Runnable() { 256 257 @Override 258 public void run() { 259 translucencySupported = checkTranslucencyMode(PERPIXEL_TRANSLUCENT); 260 transparencySupported = checkTranslucencyMode(PERPIXEL_TRANSPARENT); 261 262 if (!translucencySupported) { 263 System.err.println("This application requires " 264 + "'PERPIXEL_TRANSLUCENT' translucency mode to " 265 + "be supported."); 266 System.exit(-1); 267 } 268 269 Ruler ruler = new Ruler(); 270 ruler.setVisible(true); 271 } 272 }); 273 } 274 }