mdlaf.animation.MaterialUITimer Maven / Gradle / Ivy
/**
* MIT License
*
* Copyright (c) 2018-2020 atharva washimkar, Vincenzo Palazzo [email protected]
* Copyright (c) 2021 Vincenzo Palazzo [email protected]
*
*
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
*
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package mdlaf.animation;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.plaf.ColorUIResource;
import mdlaf.components.button.MaterialButtonUI;
/**
* This class implement a complex mouse hover event with a timer
*
*
This event call component.setBackground() inside the timer it should be managed the live cycle
* more complex
*
* @author https://github.com/vincenzopalazzo
* @author https://github.com/atarw
*/
public class MaterialUITimer implements ActionListener, MaterialMouseHover {
private Color from;
private Color to;
private boolean forward;
private int alpha;
private int steps;
private int[] forwardDeltas;
private int[] backwardDeltas;
private JComponent component;
private Timer timer;
/**
* Dont use the !component.isEnabled() how check in the builder if the component born disabled the
* mouse hover will never install
*/
protected MaterialUITimer(JComponent component, Color to, int steps, int interval) {
component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
if (component instanceof JButton) {
JButton button = (JButton) component;
if (button.getUI() instanceof MaterialButtonUI) {
MaterialButtonUI materialButtonUI = (MaterialButtonUI) button.getUI();
if (button.isDefaultButton()) {
this.from = UIManager.getColor("Button[Default].background");
materialButtonUI.setColorMouseHoverDefaultButton(to);
} else {
this.from = component.getBackground();
materialButtonUI.setColorMouseHoverNormalButton(to);
}
}
} else {
this.from = component.getBackground();
}
this.to = to;
this.forwardDeltas = new int[4];
this.backwardDeltas = new int[4];
forwardDeltas[0] = (from.getRed() - to.getRed()) / steps;
forwardDeltas[1] = (from.getGreen() - to.getGreen()) / steps;
forwardDeltas[2] = (from.getBlue() - to.getBlue()) / steps;
forwardDeltas[3] = (from.getAlpha() - to.getAlpha()) / steps;
backwardDeltas[0] = (to.getRed() - from.getRed()) / steps;
backwardDeltas[1] = (to.getGreen() - from.getGreen()) / steps;
backwardDeltas[2] = (to.getBlue() - from.getBlue()) / steps;
backwardDeltas[3] = (to.getAlpha() - from.getAlpha()) / steps;
this.steps = steps;
this.component = component;
// this.component.addMouseListener(this);
timer = new Timer(interval, this);
component.setBackground(from);
}
private Color nextColor() {
int rValue = from.getRed() - alpha * forwardDeltas[0];
int gValue = from.getGreen() - alpha * forwardDeltas[1];
int bValue = from.getBlue() - alpha * forwardDeltas[2];
int aValue = from.getAlpha() - alpha * forwardDeltas[3];
return new ColorUIResource(new Color(rValue, gValue, bValue, aValue));
}
private Color previousColor() {
int rValue = to.getRed() - (steps - alpha) * backwardDeltas[0];
int gValue = to.getGreen() - (steps - alpha) * backwardDeltas[1];
int bValue = to.getBlue() - (steps - alpha) * backwardDeltas[2];
int aValue = to.getAlpha() - (steps - alpha) * backwardDeltas[3];
return new ColorUIResource(new Color(rValue, gValue, bValue, aValue));
}
@Override
public void mousePressed(MouseEvent me) {
if (!me.getComponent().isEnabled()) {
return;
}
alpha = steps - 1;
forward = false;
this.stopTimer();
// timer.start(); //TODO TEST IT
alpha = 0;
forward = true;
// timer.start();
// TODO test this in the future but this is the
// solution when the button return the status pressed because the
// !!!! This solution fix the bug that when open a modal dialog the button stayed paint pressed
// !!!!
// !!!! TEST !!!!
this.component.setBackground(this.from);
}
@Override
public void mouseExited(MouseEvent me) {
if (!me.getComponent().isEnabled()) {
return;
}
if (timer.isRunning()) {
timer.stop();
}
alpha = steps - 1;
forward = false;
timer.start();
}
@Override
public void mouseEntered(MouseEvent me) {
if (!me.getComponent().isEnabled()) {
return;
}
alpha = 0;
forward = true;
this.stopTimer();
timer.start();
}
@Override
public void actionPerformed(ActionEvent ae) {
if (!component.isEnabled()) {
timer.stop();
return;
}
if (forward) {
component.setBackground(nextColor());
++alpha;
} else {
component.setBackground(previousColor());
--alpha;
}
if (alpha == steps + 1 || alpha == -1) {
this.stopTimer();
if (alpha == -1) {
this.component.setBackground(this.from);
}
}
}
@Override
public void mouseDragged(MouseEvent e) {
// do nothing this is util only implements interface MouseMotions
}
@Override
public void mouseMoved(MouseEvent e) {
this.stopTimer();
}
@Override
public void mouseReleased(MouseEvent me) {
this.stopTimer();
}
@Override
public void mouseClicked(MouseEvent me) {
this.stopTimer();
}
/**
* Include inside the function the logic to disable the timer with all control on null object.
*
*
!! DONT USE THIS METHOD IN OTHER PLACE WHEN IS CHECKED THE COMPONENT IS DISABLED !! THIS
* METHOD IS ONLY TO CHECK IF THE TIMER IS A VALID INSTANCE. !! Fro example: if you insert this
* method inside the actionPerformed, you will introduce the bug inside button when the button
* have been disabled after click.
*/
protected void stopTimer() {
if (component != null && component.isEnabled()) {
if (timer != null && timer.isRunning()) {
timer.stop();
}
}
}
@Override
public boolean isRunning() {
if (timer != null) {
return timer.isRunning();
}
return false;
}
}