Changed how properties act. Changed the default for showing from 5 seconds (to hide), to never hide. Added smooth animation (via active rendering swing components). Added progress-bar to show when popup will be hidden. Made "shake" move the popup in a random direction instead of all in the same direction.

This commit is contained in:
nathan 2015-11-20 11:14:38 +01:00
parent 8d814f02ab
commit 4288dd46e5
7 changed files with 335 additions and 166 deletions

View File

@ -4,6 +4,8 @@
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/dist" /> <excludeFolder url="file://$MODULE_DIR$/dist" />
<excludeFolder url="file://$MODULE_DIR$/libs" /> <excludeFolder url="file://$MODULE_DIR$/libs" />
</content> </content>

View File

@ -49,8 +49,6 @@ import java.util.Map;
public final public final
class Growl { class Growl {
public static final int FOREVER = 0;
/** /**
* Location of the dialog image resources. By default they must be in the 'resources' directory relative to the application * Location of the dialog image resources. By default they must be in the 'resources' directory relative to the application
*/ */
@ -119,7 +117,7 @@ class Growl {
String title; String title;
String text; String text;
Pos position = Pos.BOTTOM_RIGHT; Pos position = Pos.BOTTOM_RIGHT;
int hideAfterDurationInMillis = 5000; int hideAfterDurationInMillis = 0;
boolean hideCloseButton; boolean hideCloseButton;
boolean isDark = false; boolean isDark = false;
int screenNumber = Short.MIN_VALUE; int screenNumber = Short.MIN_VALUE;
@ -171,7 +169,8 @@ class Growl {
} }
/** /**
* Specifies the duration that the notification should show, after which it will be hidden. 0 means to show forever. * Specifies the duration that the notification should show, after which it will be hidden. 0 means to show forever. By default it
* will show forever
*/ */
public public
Growl hideAfter(int durationInMillis) { Growl hideAfter(int durationInMillis) {
@ -294,10 +293,13 @@ class Growl {
} }
/** /**
* "shakes" the notification, to bring user attention * "shakes" the notification, to bring user attention to it.
*
* @param durationInMillis now long it will shake
* @param amplitude a measure of how much it needs to shake. 4 is a small amount of shaking, 10 is a lot.
*/ */
public public
void shake(final int durationInMillis, final int amplitude) { Growl shake(final int durationInMillis, final int amplitude) {
this.shakeDurationInMillis = durationInMillis; this.shakeDurationInMillis = durationInMillis;
this.shakeAmplitude = amplitude; this.shakeAmplitude = amplitude;
@ -312,6 +314,8 @@ class Growl {
} }
}); });
} }
return this;
} }
/** /**

View File

@ -15,67 +15,68 @@
*/ */
package dorkbox.util.growl; package dorkbox.util.growl;
import dorkbox.util.ActionHandlerLong;
import dorkbox.util.OS; import dorkbox.util.OS;
import dorkbox.util.Property;
import dorkbox.util.ScreenUtil; import dorkbox.util.ScreenUtil;
import dorkbox.util.SwingUtil; import dorkbox.util.SwingUtil;
import dorkbox.util.SystemProps; import dorkbox.util.swing.SwingActiveRender;
import dorkbox.util.tweenengine.BaseTween; import dorkbox.util.tweenengine.BaseTween;
import dorkbox.util.tweenengine.Tween; import dorkbox.util.tweenengine.Tween;
import dorkbox.util.tweenengine.TweenCallback; import dorkbox.util.tweenengine.TweenCallback;
import dorkbox.util.tweenengine.TweenEquations; import dorkbox.util.tweenengine.TweenEquations;
import dorkbox.util.tweenengine.TweenManager; import dorkbox.util.tweenengine.TweenManager;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
// we can't use regular popup, because if we have no owner, it won't work! // we can't use regular popup, because if we have no owner, it won't work!
// instead, we just create a JFrame and use it to hold our content // instead, we just create a JFrame and use it to hold our content
@SuppressWarnings("Duplicates") @SuppressWarnings({"Duplicates", "FieldCanBeLocal"})
public public
class GrowlPopup extends JFrame { class GrowlPopup extends JFrame {
private static final int padding = 40; @Property
/** title font used by growl */
public static String TITLE_TEXT_FONT = "Source Code Pro BOLD 16";
public static final float FADE_DURATION = 1.5F; @Property
/** main text font used by growl */
public static String MAIN_TEXT_FONT = "Source Code Pro BOLD 12";
@Property
/** How long we want it to take for the popups to relocate when one is closed */
public static final float MOVE_DURATION = 1.0F; public static final float MOVE_DURATION = 1.0F;
private static final int padding = 40;
private static final Map<String, ArrayList<GrowlPopup>> popups = new HashMap<String, ArrayList<GrowlPopup>>(); private static final Map<String, ArrayList<GrowlPopup>> popups = new HashMap<String, ArrayList<GrowlPopup>>();
private static final GrowlPopupAccessor accessor = new GrowlPopupAccessor(); private static final GrowlPopupAccessor accessor = new GrowlPopupAccessor();
private static final TweenManager tweenManager = new TweenManager(); private static final TweenManager tweenManager = new TweenManager();
private static ActionHandlerLong frameStartHandler;
private static Timer timer;
private static WindowUtil opacity_compat; private static WindowUtil opacity_compat;
static { static {
// this timer is on the EDT (this is not the java.util timer) // this is for updating the tween engine during active-rendering
// 30 times a second frameStartHandler = new ActionHandlerLong() {
//noinspection Convert2Lambda
timer = new Timer(1000/30, new ActionListener() {
@Override @Override
public public
void actionPerformed(final ActionEvent e) { void handle(final long deltaInNanos) {
tweenManager.update(); GrowlPopup.tweenManager.update(deltaInNanos);
} }
}); };
timer.setRepeats(true);
if (OS.javaVersion == 6) { if (OS.javaVersion == 6) {
opacity_compat = new WindowUtil_Java6(); opacity_compat = new WindowUtil_Java6();
@ -85,8 +86,23 @@ class GrowlPopup extends JFrame {
} }
private static final int WIDTH = 300; private static final int WIDTH = 300;
private static final int HEIGHT = 90; private static final int HEIGHT = 87;
private static final int PROGRESS_HEIGHT = HEIGHT - 1;
private static final Stroke stroke = new BasicStroke(2);
private static final int closeX = 282;
private static final int closeY = 2;
private static final int Y_1 = closeY + 5;
private static final int X_1 = closeX + 5;
private static final int Y_2 = closeY + 11;
private static final int X_2 = closeX + 11;
private final Color panel_BG;
private final Color titleText_FG;
private final Color mainText_FG;
private final Color closeX_FG;
private final Color progress_FG;
private final int anchorX; private final int anchorX;
@ -96,6 +112,7 @@ class GrowlPopup extends JFrame {
private final MouseAdapter mouseListener; private final MouseAdapter mouseListener;
private final Growl notification; private final Growl notification;
private final ImageIcon imageIcon;
// this is used in combination with position, so that we can track which screen and what position a popup is in // this is used in combination with position, so that we can track which screen and what position a popup is in
private final String idAndPosition; private final String idAndPosition;
@ -105,11 +122,21 @@ class GrowlPopup extends JFrame {
private Tween tween = null; private Tween tween = null;
private Tween hideTween = null; private Tween hideTween = null;
// for the progress bar. we directly draw this onscreen
// non-volatile because it's always accessed in the active render thread
private int progress = 0;
private final boolean showCloseButton;
private BufferedImage cachedImage;
private static final Random RANDOM = new Random();
// this is on the swing EDT // this is on the swing EDT
@SuppressWarnings("NumericCastThatLosesPrecision") @SuppressWarnings("NumericCastThatLosesPrecision")
GrowlPopup(Growl notification, Image image, ImageIcon imageIcon) { GrowlPopup(Growl notification, Image image, ImageIcon imageIcon) {
this.notification = notification; this.notification = notification;
this.imageIcon = imageIcon;
windowListener = new GrowlPopupWindowAdapter(); windowListener = new GrowlPopupWindowAdapter();
mouseListener = new GrowlPopupClickAdapter(); mouseListener = new GrowlPopupClickAdapter();
@ -117,7 +144,9 @@ class GrowlPopup extends JFrame {
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setUndecorated(true); setUndecorated(true);
setOpacity_Compat(1.0F); setOpacity_Compat(1.0F);
setAlwaysOnTop(false);
setAlwaysOnTop(true); setAlwaysOnTop(true);
setLayout(null);
setSize(WIDTH, HEIGHT); setSize(WIDTH, HEIGHT);
setLocation(Short.MIN_VALUE, Short.MIN_VALUE); setLocation(Short.MIN_VALUE, Short.MIN_VALUE);
@ -136,26 +165,23 @@ class GrowlPopup extends JFrame {
addMouseListener(mouseListener); addMouseListener(mouseListener);
final Color text_BG;
final Color titleText_FG;
final Color mainText_FG;
final Color closeX_FG;
if (notification.isDark) { if (notification.isDark) {
text_BG = Color.DARK_GRAY; panel_BG = Color.DARK_GRAY;
titleText_FG = Color.GRAY; titleText_FG = Color.GRAY;
mainText_FG = Color.LIGHT_GRAY; mainText_FG = Color.LIGHT_GRAY;
closeX_FG = Color.GRAY; closeX_FG = Color.GRAY;
progress_FG = Color.gray;
} }
else { else {
text_BG = Color.WHITE; panel_BG = Color.WHITE;
titleText_FG = Color.DARK_GRAY; titleText_FG = Color.GRAY.darker();
mainText_FG = Color.GRAY; mainText_FG = Color.GRAY;
closeX_FG = Color.LIGHT_GRAY; closeX_FG = Color.LIGHT_GRAY;
progress_FG = new Color(0x42A5F5);
} }
setBackground(text_BG); setBackground(panel_BG);
showCloseButton = !notification.hideCloseButton;
GraphicsDevice device; GraphicsDevice device;
if (notification.screenNumber == Short.MIN_VALUE) { if (notification.screenNumber == Short.MIN_VALUE) {
@ -192,105 +218,6 @@ class GrowlPopup extends JFrame {
final int screenWidth = (int) screenBounds.getWidth(); final int screenWidth = (int) screenBounds.getWidth();
final int screenHeight = (int) screenBounds.getHeight(); final int screenHeight = (int) screenBounds.getHeight();
// makes sure everything is spaced nicely
final JPanel contentPane = new JPanel();
contentPane.setBackground(text_BG);
contentPane.setBorder(new EmptyBorder(0, 10, 10, 5));
contentPane.setLayout(new BorderLayout(10, 5));
setContentPane(contentPane);
// closebutton is the 'x' button, but it is really just a font
Font closeButtonFont = SwingUtil.getFontFromProperty(SystemProps.growl_closeButtonFontName, "Source Code Pro", Font.BOLD, 12);
Font mainTextFont = SwingUtil.getFontFromProperty(SystemProps.growl_titleTextFontName, "Source Code Pro", Font.BOLD, 14);
Font titleTextFont = SwingUtil.getFontFromProperty(SystemProps.growl_mainTextFontName, "Source Code Pro", Font.BOLD, 16);
// TITLE AND CLOSE BUTTON
{
Box box = new Box(BoxLayout.X_AXIS);
box.setBackground(text_BG);
box.setAlignmentX(Component.CENTER_ALIGNMENT);
{
Box textBox = new Box(BoxLayout.X_AXIS);
textBox.setAlignmentX(Component.LEFT_ALIGNMENT);
final JLabel titleLabel = new JLabel();
titleLabel.setForeground(titleText_FG);
titleLabel.setFont(titleTextFont);
titleLabel.setText(notification.title);
textBox.add(titleLabel);
textBox.add(Box.createHorizontalGlue());
box.add(textBox);
if (!notification.hideCloseButton) {
// can specify to hide the close button
Box closeBox = new Box(BoxLayout.X_AXIS);
closeBox.setBorder(new EmptyBorder(4, 4, 4, 4));
closeBox.setAlignmentX(Component.RIGHT_ALIGNMENT);
final JLabel closeButton = new JLabel();
closeButton.setForeground(closeX_FG);
closeButton.setFont(closeButtonFont);
closeButton.setText("x");
closeButton.setVerticalTextPosition(SwingConstants.TOP);
closeBox.addMouseListener(new GrowlCloseAdapter(this));
closeBox.add(closeButton);
box.add(closeBox);
}
}
contentPane.add(box, BorderLayout.NORTH);
}
int textLengthLimit = 98;
// ICON
if (imageIcon != null) {
textLengthLimit = 76;
JLabel iconLabel = new JLabel(imageIcon);
contentPane.add(iconLabel, BorderLayout.WEST);
}
// MAIN TEXT
{
String notText = notification.text;
int length = notText.length();
StringBuilder text = new StringBuilder(length);
// are we "html" already? just check for the starting tag and strip off END html tag
if (length >= 13 && notText.regionMatches(true, length-7, "</html>", 0, 7)) {
text.append(notText);
text.delete(text.length() - 7, text.length());
length -= 7;
}
else {
text.append("<html>");
text.append(notText);
}
// make sure the text is the correct length
if (length > textLengthLimit) {
text.delete(6 + textLengthLimit, text.length());
text.append("...");
}
text.append("</html>");
JLabel mainTextLabel = new JLabel();
mainTextLabel.setForeground(mainText_FG);
mainTextLabel.setFont(mainTextFont);
mainTextLabel.setText(text.toString());
contentPane.add(mainTextLabel, BorderLayout.CENTER);
}
// determine location for the popup // determine location for the popup
final Pos position = notification.position; final Pos position = notification.position;
@ -336,9 +263,156 @@ class GrowlPopup extends JFrame {
} }
} }
public void close() { @Override
removePopupFromMap(); public
void paint(Graphics g) {
// we cache the text + image (to another image), and then always render the close + progressbar
int width = getWidth();
int height = getHeight();
if (width <= 0 || height <= 0) {
return;
}
if (cachedImage == null) {
cachedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g2 = cachedImage.createGraphics();
try {
g2.setColor(panel_BG);
g2.fillRect(0, 0, WIDTH, HEIGHT);
// Draw the title text
Font titleTextFont = SwingUtil.parseFont(TITLE_TEXT_FONT);
g2.setColor(titleText_FG);
g2.setFont(titleTextFont);
g2.drawString(notification.title, 5, 20);
int posX = 10;
int textLengthLimit = 108;
// ICON
if (imageIcon != null) {
textLengthLimit = 88;
posX = 60;
// Draw the image
imageIcon.paintIcon(this, g2, 5, 30);
}
// Draw the main text
Font mainTextFont = SwingUtil.parseFont(MAIN_TEXT_FONT);
String notText = notification.text;
int length = notText.length();
StringBuilder text = new StringBuilder(length);
// are we "html" already? just check for the starting tag and strip off END html tag
if (length >= 13 && notText.regionMatches(true, length-7, "</html>", 0, 7)) {
text.append(notText);
text.delete(text.length() - 7, text.length());
length -= 7;
}
else {
text.append("<html>");
text.append(notText);
}
// make sure the text is the correct length
if (length > textLengthLimit) {
text.delete(6 + textLengthLimit, text.length());
text.append("...");
}
text.append("</html>");
JLabel mainTextLabel = new JLabel();
mainTextLabel.setForeground(mainText_FG);
mainTextLabel.setFont(mainTextFont);
mainTextLabel.setText(text.toString());
int posY = -8;
mainTextLabel.setBounds(0, 0, WIDTH - posX - 2, HEIGHT);
g2.translate(posX, posY);
mainTextLabel.paint(g2);
g2.translate(-posX, -posY);
} finally {
g2.dispose();
}
g.drawImage(cachedImage, 0, 0, null);
}
else {
// use our cached image, so we don't have to re-render text
g.drawImage(cachedImage, getX(), getY(), null);
// the progress bar and close button are the only things that can change, so we always draw them
Graphics2D g2 = (Graphics2D) g.create();
try {
if (showCloseButton) {
Graphics2D g3 = (Graphics2D) g.create();
g3.setColor(panel_BG);
g3.setStroke(stroke);
final Point p = getMousePosition();
// reasonable position for detecting mouse over
if (p != null && p.getX() >= 280 && p.getY() <= 20) {
g3.setColor(Color.RED);
} else {
g3.setColor(closeX_FG);
}
// draw the X
g3.drawLine(X_1, Y_1, X_2, Y_2);
g3.drawLine(X_2, Y_1, X_1, Y_2);
}
g2.setColor(progress_FG);
g2.fillRect(0, PROGRESS_HEIGHT, progress, 1);
} finally {
g2.dispose();
}
}
}
public
void onClick(final int x, final int y) {
// Check - we were over the 'X' (and thus no notify), or was it in the general area?
if (showCloseButton && x >= 280 && y <= 20) {
// reasonable position for detecting mouse over
close();
}
else {
notification.onClick();
close();
}
}
@Override
public
void setVisible(final boolean b) {
// necessary for active rendering
setIgnoreRepaint(true);
super.setVisible(b);
if (b) {
toFront();
// set this jframe to use active rendering
SwingActiveRender.addActiveRender(this);
addPopupToMap();
}
else {
removePopupFromMap();
SwingActiveRender.removeActiveRender(this);
}
}
public void close() {
WindowEvent winClosingEvent = new WindowEvent(this, WindowEvent.WINDOW_CLOSING); WindowEvent winClosingEvent = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(winClosingEvent); Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(winClosingEvent);
@ -383,9 +457,11 @@ class GrowlPopup extends JFrame {
if (notification.hideAfterDurationInMillis > 0 && hideTween == null) { if (notification.hideAfterDurationInMillis > 0 && hideTween == null) {
// begin a timeline to get rid of the popup (default is 5 seconds) // begin a timeline to get rid of the popup (default is 5 seconds)
hideTween = Tween.set(this, GrowlPopupAccessor.OPACITY, accessor) final float durationInSeconds = notification.hideAfterDurationInMillis / 1000.0F;
.delay(FADE_DURATION + (notification.hideAfterDurationInMillis / 1000.0F))
.target(0) hideTween = Tween.to(this, GrowlPopupAccessor.PROGRESS, accessor, durationInSeconds)
.target(WIDTH)
.ease(TweenEquations.Linear)
.addCallback(new TweenCallback() { .addCallback(new TweenCallback() {
@Override @Override
public public
@ -395,8 +471,9 @@ class GrowlPopup extends JFrame {
}); });
tweenManager.add(hideTween); tweenManager.add(hideTween);
if (!timer.isRunning()) { if (!SwingActiveRender.containsActiveRenderFrameStart(frameStartHandler)) {
timer.start(); tweenManager.resetUpdateTime();
SwingActiveRender.addActiveRenderFrameStart(frameStartHandler);
} }
} }
} }
@ -428,8 +505,8 @@ class GrowlPopup extends JFrame {
} }
// if there's nothing left, stop the timer. // if there's nothing left, stop the timer.
if (copies.isEmpty()) { if (popups.isEmpty()) {
timer.stop(); SwingActiveRender.removeActiveRenderFrameStart(frameStartHandler);
} }
return; return;
} }
@ -478,12 +555,9 @@ class GrowlPopup extends JFrame {
popups.put(idAndPosition, copies); popups.put(idAndPosition, copies);
// if there's nothing left, stop the timer. // if there's nothing left, stop the timer.
if (copies.isEmpty()) { if (!SwingActiveRender.containsActiveRenderFrameStart(frameStartHandler)) {
timer.stop();
}
else if (!timer.isRunning()) {
tweenManager.resetUpdateTime(); tweenManager.resetUpdateTime();
timer.start(); SwingActiveRender.addActiveRenderFrameStart(frameStartHandler);
} }
} }
} }
@ -505,19 +579,45 @@ class GrowlPopup extends JFrame {
setLocation(getX(), newY); setLocation(getX(), newY);
} }
public
void onClick() {
notification.onClick();
close();
}
/**
* Shakes the popup
*
* @param durationInMillis now long it will shake
* @param amplitude a measure of how much it needs to shake. 4 is a small amount of shaking, 10 is a lot.
*/
public public
void shake(final int durationInMillis, final int amplitude) { void shake(final int durationInMillis, final int amplitude) {
System.err.println("shake"); int i1 = RANDOM.nextInt((amplitude << 2) + 1) - amplitude;
int i2 = RANDOM.nextInt((amplitude << 2) + 1) - amplitude;
i1 = i1 >> 2;
i2 = i2 >> 2;
// make sure it always moves by some amount
if (i1 < 0) {
i1 -= amplitude >> 2;
}
else {
i1 += amplitude >> 2;
}
if (i2 < 0) {
i2 -= amplitude >> 2;
}
else {
i2 += amplitude >> 2;
}
int count = durationInMillis / 50;
// make sure we always end the animation where we start
if ((count & 1) == 0) {
count++;
}
Tween tween = Tween.to(this, GrowlPopupAccessor.X_Y_POS, accessor, 0.05F) Tween tween = Tween.to(this, GrowlPopupAccessor.X_Y_POS, accessor, 0.05F)
.targetRelative(amplitude, amplitude) .targetRelative(i1, i2)
.repeatAutoReverse(durationInMillis / 50, 0) .repeatAutoReverse(count, 0)
.ease(TweenEquations.Linear); .ease(TweenEquations.Linear);
tweenManager.add(tween); tweenManager.add(tween);
} }
@ -531,4 +631,14 @@ class GrowlPopup extends JFrame {
float getOpacity_Compat() { float getOpacity_Compat() {
return opacity_compat.getOpacity(this); return opacity_compat.getOpacity(this);
} }
public
int getProgress() {
return progress;
}
public
void setProgress(final int progress) {
this.progress = progress;
}
} }

View File

@ -22,6 +22,7 @@ class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
static final int OPACITY = 0; static final int OPACITY = 0;
static final int Y_POS = 1; static final int Y_POS = 1;
static final int X_Y_POS = 2; static final int X_Y_POS = 2;
static final int PROGRESS = 3;
GrowlPopupAccessor() { GrowlPopupAccessor() {
@ -41,10 +42,14 @@ class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
returnValues[0] = (float) target.getX(); returnValues[0] = (float) target.getX();
returnValues[1] = (float) target.getY(); returnValues[1] = (float) target.getY();
return 2; return 2;
case PROGRESS:
returnValues[0] = (float) target.getProgress();
return 1;
} }
return 1; return 1;
} }
@SuppressWarnings({"NumericCastThatLosesPrecision", "UnnecessaryReturnStatement"})
@Override @Override
public public
void setValues(final GrowlPopup target, final int tweenType, final float[] newValues) { void setValues(final GrowlPopup target, final int tweenType, final float[] newValues) {
@ -53,12 +58,14 @@ class GrowlPopupAccessor implements TweenAccessor<GrowlPopup> {
target.setOpacity_Compat(newValues[0]); target.setOpacity_Compat(newValues[0]);
return; return;
case Y_POS: case Y_POS:
//noinspection NumericCastThatLosesPrecision
target.setY((int) newValues[0]); target.setY((int) newValues[0]);
return; return;
case X_Y_POS: case X_Y_POS:
//noinspection NumericCastThatLosesPrecision
target.setLocation((int) newValues[0], (int) newValues[1]); target.setLocation((int) newValues[0], (int) newValues[1]);
return;
case PROGRESS:
target.setProgress((int) newValues[0]);
return;
} }
} }
} }

View File

@ -28,6 +28,6 @@ class GrowlPopupClickAdapter extends MouseAdapter {
public public
void mouseReleased(final MouseEvent e) { void mouseReleased(final MouseEvent e) {
GrowlPopup source = (GrowlPopup) e.getSource(); GrowlPopup source = (GrowlPopup) e.getSource();
source.onClick(); source.onClick(e.getX(), e.getY());
} }
} }

View File

@ -20,8 +20,14 @@ import java.awt.event.WindowEvent;
class GrowlPopupWindowAdapter extends WindowAdapter { class GrowlPopupWindowAdapter extends WindowAdapter {
public public
void windowOpened(WindowEvent e) { void windowLostFocus(WindowEvent e) {
GrowlPopup source = (GrowlPopup) e.getSource(); if (e.getNewState() != WindowEvent.WINDOW_CLOSED) {
source.addPopupToMap(); GrowlPopup source = (GrowlPopup) e.getSource();
//toFront();
//requestFocus();
source.setAlwaysOnTop(false);
source.setAlwaysOnTop(true);
//requestFocusInWindow();
}
} }
} }

40
test/GrowlTest.java Normal file
View File

@ -0,0 +1,40 @@
import dorkbox.util.ActionHandler;
import dorkbox.util.growl.Growl;
import dorkbox.util.growl.Pos;
/**
*
*/
public
class GrowlTest {
public static
void main(String[] args) {
Growl growl;
int count = 3;
for (int i = 0; i < count; i++) {
growl = Growl.create()
.title("Growl title " + i)
.text("This is a growl notification popup message This is a growl notification popup message This is a growl notification popup message")
.hideAfter(50000)
.position(Pos.TOP_RIGHT)
// .setScreen(0)
.darkStyle()
.shake(1300, 4)
// .shake(1300, 10)
// .hideCloseButton()
.onAction(new ActionHandler<Growl>() {
@Override
public
void handle(final Growl arg0) {
System.out.println("Notification clicked on!");
}
});
growl.showWarning();
// growl.show();
}
}
}