/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*/
package com.sun.jna.contrib.demo;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.MouseInputAdapter;
import com.sun.jna.platform.WindowUtils;
/** Example which uses the {@link WindowUtils} class. Demonstrates the
* definition of a cross-platform library with several platform-specific
* implementations based on JNA native library definitions.
*/
public class ShapedWindowDemo {
public static final int ICON_SIZE = 64;
private static class ClockFace extends JComponent {
private static final long serialVersionUID = 1L;
private Stroke border;
private Stroke secondHand;
private Stroke minuteHand;
private Stroke hourHand;
private Stroke ticks;
public ClockFace(Dimension size) {
setPreferredSize(size);
setSize(size);
setOpaque(false);
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
Window w = SwingUtilities.getWindowAncestor(ClockFace.this);
while (!(w instanceof Frame)) {
w = w.getOwner();
}
if (w instanceof Frame) {
((Frame)w).setIconImage(getIconImage());
}
}
});
timer.setRepeats(true);
timer.start();
}
private String getRomanNumeral(int number) {
switch(number) {
case 1: return "I";
case 2: return "II";
case 3: return "III";
case 4: return "IV";
case 5: return "V";
case 6: return "VI";
case 7: return "VII";
case 8: return "VIII";
case 9: return "IX";
case 10: return "X";
case 11: return "XI";
case 12:
default: return "XII";
}
}
protected void paintComponent(Graphics graphics) {
paintFace(graphics, Math.min(getWidth(), getHeight()));
}
protected void paintFace(Graphics graphics, int size) {
Point center = new Point(size/2, size/2);
int radius = center.x;
int margin = radius / 20;
int w = size;
border = new BasicStroke(Math.max(1f, w/150f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
secondHand = new BasicStroke(Math.max(1f, w/75f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
minuteHand = new BasicStroke(Math.max(1f, w/38f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
hourHand = new BasicStroke(Math.max(1.5f, w/20f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
ticks = new BasicStroke(1f);
Graphics2D g = (Graphics2D)graphics.create();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Color bg = getBackground();
g.setColor(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));
g.fill(new Ellipse2D.Float(0,0,size,size));
Font font = getFont();
g.setFont(font.deriveFont(Font.BOLD, size/12));
g.setColor(new Color(0,0,0,128));
g.setStroke(border);
g.draw(new Ellipse2D.Float(0,0,size-1,size-1));
g.draw(new Ellipse2D.Float(margin,margin,size-margin*2-1,size-margin*2-1));
Calendar c = Calendar.getInstance();
int minute = c.get(Calendar.MINUTE);
int hour = c.get(Calendar.HOUR);
int second = c.get(Calendar.SECOND);
g.translate(center.x, center.y);
g.setColor(getForeground());
int numbers = radius * 3 / 4;
for (int i=0;i < 12;i++) {
double theta = Math.PI*2*i/12;
String str = getRomanNumeral((i+2)%12+1);
Rectangle2D rect = g.getFontMetrics().getStringBounds(str, g);
g.drawString(str, Math.round(numbers*Math.cos(theta)-rect.getWidth()/2),
Math.round(numbers*Math.sin(theta)+margin*2));
}
for (int i=0;i < 60;i++) {
g.setColor(getForeground());
g.setStroke(ticks);
g.drawLine(radius-margin*2, 0, radius-margin, 0);
if ((i % 5) == 0) {
g.drawLine(radius-margin*3, 0, radius-margin, 0);
}
if ((i + 15) % 60 == minute) {
g.setStroke(minuteHand);
g.drawLine(0, 0, radius-margin*4, 0);
}
if ((i + 15) % 60 == (hour * 5 + minute * 5 / 60)) {
g.setStroke(hourHand);
g.drawLine(0, 0, radius/2, 0);
}
if ((i + 15) % 60 == second) {
g.setColor(new Color(255, 0, 0, 128));
g.setStroke(secondHand);
g.drawLine(0, 0, radius-margin*4, 0);
}
g.rotate(Math.PI*2/60);
}
g.dispose();
}
public Image getIconImage() {
BufferedImage image = new BufferedImage(ICON_SIZE, ICON_SIZE,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
Composite old = g.getComposite();
g.setComposite(AlphaComposite.Clear);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setComposite(old);
paintFace(g, ICON_SIZE);
return image;
}
}
public static void main(String[] args) {
try {
System.setProperty("sun.java2d.noddraw", "true");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
}
final JFrame frame = new JFrame("Shaped Window Demo");
MouseInputAdapter handler = new MouseInputAdapter() {
private Point offset;
private void showPopup(MouseEvent e) {
final JPopupMenu m = new JPopupMenu();
m.add(new AbstractAction("Hide") {
public void actionPerformed(ActionEvent e) {
frame.setState(JFrame.ICONIFIED);
}
private static final long serialVersionUID = 1L;
});
m.add(new AbstractAction("Close") {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
private static final long serialVersionUID = 1L;
});
m.pack();
m.show(e.getComponent(), e.getX(), e.getY());
}
public void mousePressed(MouseEvent e) {
offset = e.getPoint();
if (e.isPopupTrigger()) {
showPopup(e);
}
}
public void mouseDragged(MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e))
return;
Point where = e.getPoint();
where.translate(-offset.x, -offset.y);
Point loc = frame.getLocationOnScreen();
loc.translate(where.x, where.y);
frame.setLocation(loc.x, loc.y);
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
showPopup(e);
}
}
};
frame.addMouseListener(handler);
frame.addMouseMotionListener(handler);
ClockFace face = new ClockFace(new Dimension(150, 150));
frame.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
frame.getContentPane().add(face);
frame.setUndecorated(true);
try {
Shape mask = new Area(new Ellipse2D.Float(0, 0, 150, 150));
WindowUtils.setWindowMask(frame, mask);
if (WindowUtils.isWindowAlphaSupported()) {
WindowUtils.setWindowAlpha(frame, .7f);
}
frame.setIconImage(face.getIconImage());
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocation(100, 100);
frame.setVisible(true);
}
catch(UnsatisfiedLinkError e) {
e.printStackTrace();
String msg = e.getMessage()
+ "\nError loading the JNA library";
JTextArea area = new JTextArea(msg);
area.setOpaque(false);
area.setFont(UIManager.getFont("Label.font"));
area.setEditable(false);
area.setColumns(80);
area.setRows(8);
area.setWrapStyleWord(true);
area.setLineWrap(true);
JOptionPane.showMessageDialog(frame, new JScrollPane(area),
"Library Load Error: "
+ System.getProperty("os.name")
+ "/" + System.getProperty("os.arch"),
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
}