diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..43c4ed6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/nbproject/private/
diff --git a/README.md b/README.md
index f22be01..dae09e6 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,9 @@
# SwingMaterialDesign
A **Material Design** components for java swing. Trying to make java swing more beautiful and vivid. With *shadows* and *ripples*.
+Image upload design, gradients and more!
-I used **netbeans** for this project, so it's easy to work with WYSIWYG IDE.
+I used **netbeans** for this project.
## Screenshots
-
-
-
-
-
-
-
-
-
+
diff --git a/build.xml b/build.xml
index c38789a..71607e9 100644
--- a/build.xml
+++ b/build.xml
@@ -1,73 +1,73 @@
-
-
-
-
-
-
-
-
-
-
- * Keep on mind that setting a background color in a Material component like - * this will also set the foreground color to either white or black and the - * ripple color to a brighter or darker shade of the color, depending of how - * bright or dark is the chosen background color. If you want to use a - * custom foreground color and ripple color, ensure the background color has - * been set first. - *
- * NOTE: It is up to the look and feel to honor this property, some - * may choose to ignore it. To avoid any conflicts, using the - * - * Metal Look and Feel is recommended. - * - * @param bg - */ - @Override - public void setBackground(Color bg) { - super.setBackground(bg); - setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.BLACK); - setRippleColor(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialUtils.darken(MaterialUtils.darken(bg))); - } - - /** - * Gets the ripple color. - * - * @return the ripple color - */ - public Color getRippleColor() { - return rippleColor; - } - - /** - * Sets the ripple color. You should only do this for flat buttons. - * - * @param rippleColor the ripple color - */ - public void setRippleColor(Color rippleColor) { - this.rippleColor = rippleColor; - } - - /** - * Gets the current border radius of this button. - * - * @return the current border radius of this button, in pixels. - */ - public int getBorderRadius() { - return borderRadius; - } - - /** - * Sets the border radius of this button. You can define a custom radius in - * order to get some rounded corners in your button, making it look like a - * pill or even a circular action button. - * - * @param borderRadius the new border radius of this button, in pixels. - */ - public void setBorderRadius(int borderRadius) { - this.borderRadius = borderRadius; - elevation.setBorderRadius(borderRadius); - } - - @Override - public void setEnabled(boolean b) { - super.setEnabled(b); - super.setCursor(b ? cursor : Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - @Override - public void setCursor(Cursor cursor) { - super.setCursor(cursor); - this.cursor = cursor; - } - - @Override - protected void processFocusEvent(FocusEvent focusEvent) { - super.processFocusEvent(focusEvent); - } - - @Override - protected void processMouseEvent(MouseEvent mouseEvent) { - super.processMouseEvent(mouseEvent); - } - - private int getElevation() { - if (isMousePressed) { - return 2; - } else if (type == Type.RAISED || isMouseOver) { - return 1; - } else { - return 0; - } - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - if ((type != Type.FLAT) && isEnabled()) { - elevation.paint(g); - g2.translate(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP); - } - - int offset_lr; - int offset_td; - if (type == Type.FLAT) { - offset_td = 0; - offset_lr = 0; - } else { - offset_td = MaterialShadow.OFFSET_TOP + MaterialShadow.OFFSET_BOTTOM; - offset_lr = MaterialShadow.OFFSET_LEFT + MaterialShadow.OFFSET_RIGHT; - } - - if (isEnabled()) { - g2.setColor(getBackground()); - g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius)); - g2.setColor(new Color(rippleColor.getRed() / 255f, rippleColor.getBlue() / 255f, rippleColor.getBlue() / 255f, 0.12f)); - if (type == Type.FLAT) { - elevation.paint(g); - //g2.setColor(MaterialUtils.brighten(getBackground())); - //g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius)); - } - } else { - Color bg = getBackground(); - g2.setColor(new Color(bg.getRed() / 255f, bg.getGreen() / 255f, bg.getBlue() / 255f, 0.6f)); - g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius * 2, borderRadius * 2)); - } - - FontMetrics metrics = g.getFontMetrics(getFont()); - int x = (getWidth() - offset_lr - metrics.stringWidth(getText().toUpperCase())) / 2; - int y = (getHeight() - offset_td - metrics.getHeight()) / 2 + metrics.getAscent(); - g2.setFont(getFont()); - if (isEnabled()) { - g2.setColor(getForeground()); - } else { - Color fg = getForeground(); - g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, 0.6f)); - } - g2.drawString(getText().toUpperCase(), x, y); - - if (isEnabled()) { - g2.setClip(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, Math.max(borderRadius * 2 - 4, 0), Math.max(borderRadius * 2 - 4, 0))); - g2.setColor(rippleColor); - ripple.paint(g2); - } - } - - @Override - protected void paintBorder(Graphics g) { - //intentionally left blank - } - - /** - * Button types. - */ - public enum Type { - /** - * A default button. - */ - DEFAULT, - /** - * A raised button. Raised buttons have a shadow even if they are not - * focused. - */ - RAISED, - /** - * A flat button. Flat buttons don't have shadows and are typically - * transparent. - */ - FLAT - } -} +package com.hq.swingmaterialdesign.materialdesign; + +import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import javax.swing.JButton; +import javax.swing.plaf.basic.BasicButtonUI; +import java.awt.event.FocusEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.RoundRectangle2D; +import javax.swing.JComponent; + +/** + * A material design button. + * + * + * @author abner (abner.js05@gmail.com) + */ +public class MButton extends JButton { + + private RippleEffect ripple; + private ElevationEffect elevation; + private Type type = Type.DEFAULT; + private boolean isMousePressed = false; + private boolean isMouseOver = false; + private Color rippleColor = Color.WHITE; + private Cursor cursor = super.getCursor(); + private int borderRadius = 2; + + /** + * Creates a new button. + */ + public MButton() { + ripple = RippleEffect.applyTo(this); + elevation = ElevationEffect.applyTo(this, 0); + setOpaque(false); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent mouseEvent) { + isMousePressed = true; + elevation.setLevel(getElevation()); + } + + @Override + public void mouseReleased(MouseEvent mouseEvent) { + isMousePressed = false; + elevation.setLevel(getElevation()); + } + + @Override + public void mouseEntered(MouseEvent e) { + isMouseOver = true; + elevation.setLevel(getElevation()); + } + + @Override + public void mouseExited(MouseEvent e) { + isMouseOver = false; + elevation.setLevel(getElevation()); + } + }); + + setUI(new BasicButtonUI() { + @Override + public boolean contains(JComponent c, int x, int y) { + return x > MaterialShadow.OFFSET_LEFT && y > MaterialShadow.OFFSET_TOP + && x < getWidth() - MaterialShadow.OFFSET_RIGHT && y < getHeight() - MaterialShadow.OFFSET_BOTTOM; + } + }); + } + + /** + * Gets the type of this button. + * + * @return the type of this button + * @see Type + */ + public Type getType() { + return type; + } + + /** + * Sets the type of this button. + * + * @param type the type of this button + * @see Type + */ + public void setType(Type type) { + this.type = type; + repaint(); + } + + /** + * Sets the background color of this button. + *
+ * Keep on mind that setting a background color in a Material component like + * this will also set the foreground color to either white or black and the + * ripple color to a brighter or darker shade of the color, depending of how + * bright or dark is the chosen background color. If you want to use a + * custom foreground color and ripple color, ensure the background color has + * been set first. + *
+ * NOTE: It is up to the look and feel to honor this property, some
+ * may choose to ignore it. To avoid any conflicts, using the
+ *
+ * Metal Look and Feel is recommended.
+ *
+ * @param bg
+ */
+ @Override
+ public void setBackground(Color bg) {
+ super.setBackground(bg);
+ setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.BLACK);
+ setRippleColor(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialUtils.darken(MaterialUtils.darken(bg)));
+ }
+
+ /**
+ * Gets the ripple color.
+ *
+ * @return the ripple color
+ */
+ public Color getRippleColor() {
+ return rippleColor;
+ }
+
+ /**
+ * Sets the ripple color. You should only do this for flat buttons.
+ *
+ * @param rippleColor the ripple color
+ */
+ public void setRippleColor(Color rippleColor) {
+ this.rippleColor = rippleColor;
+ }
+
+ /**
+ * Gets the current border radius of this button.
+ *
+ * @return the current border radius of this button, in pixels.
+ */
+ public int getBorderRadius() {
+ return borderRadius;
+ }
+
+ /**
+ * Sets the border radius of this button. You can define a custom radius in
+ * order to get some rounded corners in your button, making it look like a
+ * pill or even a circular action button.
+ *
+ * @param borderRadius the new border radius of this button, in pixels.
+ */
+ public void setBorderRadius(int borderRadius) {
+ this.borderRadius = borderRadius;
+ elevation.setBorderRadius(borderRadius);
+ }
+
+ @Override
+ public void setEnabled(boolean b) {
+ super.setEnabled(b);
+ super.setCursor(b ? cursor : Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ @Override
+ public void setCursor(Cursor cursor) {
+ super.setCursor(cursor);
+ this.cursor = cursor;
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent focusEvent) {
+ super.processFocusEvent(focusEvent);
+ }
+
+ @Override
+ protected void processMouseEvent(MouseEvent mouseEvent) {
+ super.processMouseEvent(mouseEvent);
+ }
+
+ private int getElevation() {
+ if (isMousePressed) {
+ return 2;
+ } else if (type == Type.RAISED || isMouseOver) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ if ((type != Type.FLAT) && isEnabled()) {
+ elevation.paint(g);
+ g2.translate(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP);
+ }
+
+ int offset_lr;
+ int offset_td;
+ if (type == Type.FLAT) {
+ offset_td = 0;
+ offset_lr = 0;
+ } else {
+ offset_td = MaterialShadow.OFFSET_TOP + MaterialShadow.OFFSET_BOTTOM;
+ offset_lr = MaterialShadow.OFFSET_LEFT + MaterialShadow.OFFSET_RIGHT;
+ }
+
+ if (isEnabled()) {
+ g2.setColor(getBackground());
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ g2.setColor(new Color(rippleColor.getRed() / 255f, rippleColor.getBlue() / 255f, rippleColor.getBlue() / 255f, 0.12f));
+ if (type == Type.FLAT) {
+ elevation.paint(g);
+ //g2.setColor(MaterialUtils.brighten(getBackground()));
+ //g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ }
+ } else {
+ Color bg = getBackground();
+ g2.setColor(new Color(bg.getRed() / 255f, bg.getGreen() / 255f, bg.getBlue() / 255f, 0.6f));
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius * 2, borderRadius * 2));
+ }
+
+ FontMetrics metrics = g.getFontMetrics(getFont());
+ int x = (getWidth() - offset_lr - metrics.stringWidth(getText().toUpperCase())) / 2;
+ int y = (getHeight() - offset_td - metrics.getHeight()) / 2 + metrics.getAscent();
+ g2.setFont(getFont());
+ if (isEnabled()) {
+ g2.setColor(getForeground());
+ } else {
+ Color fg = getForeground();
+ g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, 0.6f));
+ }
+ g2.drawString(getText().toUpperCase(), x, y);
+
+ if (isEnabled()) {
+ g2.setClip(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, Math.max(borderRadius - 6, 0), Math.max(borderRadius * 2 - 4, 0)));
+ g2.setColor(rippleColor);
+ ripple.paint(g2);
+ }
+ }
+
+// @Override
+// protected void paintBorder(Graphics g) {
+// //intentionally left blank
+// }
+
+ /**
+ * Button types.
+ */
+ public enum Type {
+ /**
+ * A default button.
+ */
+ DEFAULT,
+ /**
+ * A raised button. Raised buttons have a shadow even if they are not
+ * focused.
+ */
+ RAISED,
+ /**
+ * A flat button. Flat buttons don't have shadows and are typically
+ * transparent.
+ */
+ FLAT
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MaterialComboBox.java b/src/com/hq/swingmaterialdesign/materialdesign/MComboBox.java
similarity index 94%
rename from src/com/hq/swingmaterialdesign/materialdesign/MaterialComboBox.java
rename to src/com/hq/swingmaterialdesign/materialdesign/MComboBox.java
index d620015..1d8e32f 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/MaterialComboBox.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MComboBox.java
@@ -1,287 +1,287 @@
-package com.hq.swingmaterialdesign.materialdesign;
-
-import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
-import static com.hq.swingmaterialdesign.materialdesign.MaterialTextField.HINT_OPACITY_MASK;
-import static com.hq.swingmaterialdesign.materialdesign.MaterialTextField.LINE_OPACITY_MASK;
-import com.hq.swingmaterialdesign.materialdesign.resource.Roboto;
-import javax.swing.*;
-import javax.swing.border.MatteBorder;
-import javax.swing.plaf.basic.BasicComboBoxUI;
-import javax.swing.plaf.basic.BasicComboPopup;
-import javax.swing.plaf.basic.BasicScrollBarUI;
-import javax.swing.plaf.basic.ComboPopup;
-import java.awt.*;
-import java.awt.event.FocusEvent;
-
-/**
- * A Material Design combo box.
- *
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class MaterialComboBox
+ * Keep on mind that setting a background color in a Material component like
+ * this will also set the foreground color to either white or black and the
+ * ripple color to a brighter or darker shade of the color, depending of how
+ * bright or dark is the chosen background color. If you want to use a
+ * custom foreground color and ripple color, ensure the background color has
+ * been set first.
+ *
+ * NOTE: It is up to the look and feel to honor this property, some
+ * may choose to ignore it. To avoid any conflicts, using the
+ *
+ * Metal Look and Feel is recommended.
+ *
+ * @param bg
+ */
+ @Override
+ public void setBackground(Color bg) {
+// super.setBackground(bg);
+// setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.BLACK);
+// setRippleColor(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialUtils.darken(MaterialUtils.darken(bg)));
+ }
+
+ /**
+ * Gets the ripple color.
+ *
+ * @return the ripple color
+ */
+ public Color getRippleColor() {
+ return rippleColor;
+ }
+
+ /**
+ * Sets the ripple color. You should only do this for flat buttons.
+ *
+ * @param rippleColor the ripple color
+ */
+ public void setRippleColor(Color rippleColor) {
+ this.rippleColor = rippleColor;
+ }
+
+ public Color getStartColor() {
+ return startColor;
+ }
+
+ public void setStartColor(Color startColor) {
+ this.startColor = startColor;
+ }
+
+ public Color getEndColor() {
+ return endColor;
+ }
+
+ public void setEndColor(Color endColor) {
+ this.endColor = endColor;
+ }
+
+ public Color getHoverStartColor() {
+ return hoverStartColor;
+ }
+
+ public void setHoverStartColor(Color hoverStartColor) {
+ this.hoverStartColor = hoverStartColor;
+ }
+
+ public Color getHoverEndColor() {
+ return hoverEndColor;
+ }
+
+ public void setHoverEndColor(Color hoverEndColor) {
+ this.hoverEndColor = hoverEndColor;
+ }
+
+
+
+
+
+ /**
+ * Gets the current border radius of this button.
+ *
+ * @return the current border radius of this button, in pixels.
+ */
+ public int getBorderRadius() {
+ return borderRadius;
+ }
+
+ /**
+ * Sets the border radius of this button. You can define a custom radius in
+ * order to get some rounded corners in your button, making it look like a
+ * pill or even a circular action button.
+ *
+ * @param borderRadius the new border radius of this button, in pixels.
+ */
+ public void setBorderRadius(int borderRadius) {
+ this.borderRadius = borderRadius;
+ elevation.setBorderRadius(borderRadius);
+ }
+
+ @Override
+ public void setEnabled(boolean b) {
+ super.setEnabled(b);
+ super.setCursor(b ? cursor : Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ @Override
+ public void setCursor(Cursor cursor) {
+ super.setCursor(cursor);
+ this.cursor = cursor;
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent focusEvent) {
+ super.processFocusEvent(focusEvent);
+ }
+
+ @Override
+ protected void processMouseEvent(MouseEvent mouseEvent) {
+ super.processMouseEvent(mouseEvent);
+ }
+
+ private int getElevation() {
+ if (isMousePressed) {
+ return 2;
+ } else if (type == Type.RAISED || isMouseOver) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ if ((type != Type.FLAT) && isEnabled()) {
+ elevation.paint(g);
+ g2.translate(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP);
+ }
+
+ int offset_lr;
+ int offset_td;
+ if (type == Type.FLAT) {
+ offset_td = 0;
+ offset_lr = 0;
+ } else {
+ offset_td = MaterialShadow.OFFSET_TOP + MaterialShadow.OFFSET_BOTTOM;
+ offset_lr = MaterialShadow.OFFSET_LEFT + MaterialShadow.OFFSET_RIGHT;
+ }
+
+ if (isEnabled()) {
+ if(isMouseOver){
+ GradientPaint gp = new GradientPaint(0, 0, hoverStartColor, 300, getHeight(), hoverEndColor);
+ g2.setPaint(gp);
+ } else {
+ GradientPaint gp = new GradientPaint(0, 0, startColor, 300, getHeight(), endColor);
+ g2.setPaint(gp);
+ }
+
+
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ g2.setColor(new Color(rippleColor.getRed() / 255f, rippleColor.getBlue() / 255f, rippleColor.getBlue() / 255f, 0.12f));
+ if (type == Type.FLAT) {
+ elevation.paint(g);
+ //g2.setColor(MaterialUtils.brighten(getBackground()));
+ //g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ }
+ } else {
+ GradientPaint gp = new GradientPaint(0, 0, startColor, 300, getHeight(), endColor);
+ g2.setPaint(gp);
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius * 2, borderRadius * 2));
+ }
+
+ FontMetrics metrics = g.getFontMetrics(getFont());
+ int x = (getWidth() - offset_lr - metrics.stringWidth(getText().toUpperCase())) / 2;
+ int y = (getHeight() - offset_td - metrics.getHeight()) / 2 + metrics.getAscent();
+ g2.setFont(getFont());
+ if (isEnabled()) {
+ g2.setColor(getForeground());
+ } else {
+ Color fg = getForeground();
+ g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, 0.6f));
+ }
+ g2.drawString(getText().toUpperCase(), x, y);
+
+ if (isEnabled()) {
+ g2.setClip(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, Math.max(borderRadius - 6, 0), Math.max(borderRadius * 2 - 4, 0)));
+ g2.setColor(rippleColor);
+ ripple.paint(g2);
+ }
+ }
+
+ @Override
+ protected void paintBorder(Graphics g) {
+ //intentionally left blank
+ }
+
+ /**
+ * Button types.
+ */
+ public enum Type {
+ /**
+ * A default button.
+ */
+ DEFAULT,
+ /**
+ * A raised button. Raised buttons have a shadow even if they are not
+ * focused.
+ */
+ RAISED,
+ /**
+ * A flat button. Flat buttons don't have shadows and are typically
+ * transparent.
+ */
+ FLAT
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MGradientPanel.java b/src/com/hq/swingmaterialdesign/materialdesign/MGradientPanel.java
new file mode 100644
index 0000000..30097a1
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MGradientPanel.java
@@ -0,0 +1,236 @@
+package com.hq.swingmaterialdesign.materialdesign;
+
+import java.awt.Component;
+import javax.swing.JRadioButton;
+import javax.swing.JToolBar;
+import javax.swing.JFormattedTextField;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.event.MouseMotionListener;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.RenderingHints;
+import java.awt.AlphaComposite;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.Dimension;
+import java.awt.Image;
+import javax.swing.ImageIcon;
+import java.awt.Color;
+import javax.swing.JPanel;
+
+public class MGradientPanel extends JPanel
+{
+ private Color startColor;
+ private Color endColor;
+ private boolean transparentControl;
+ private int gradientFocus;
+ private int borderRadius;
+ private boolean fillBackground;
+ private String imagePath;
+ private ImageIcon icon;
+ private Image image;
+ private boolean fillImage;
+ private boolean drawBorder;
+ private static Color backgroundColor;
+
+ public String getImagePath() {
+ return this.imagePath;
+ }
+
+ public void setImagePath(final String imagePath) {
+ this.imagePath = imagePath;
+ this.icon = new ImageIcon(this.getClass().getResource(this.imagePath));
+ this.image = this.icon.getImage();
+ }
+
+ public ImageIcon getIcon() {
+ return this.icon;
+ }
+
+ public void setIcon() {
+ this.icon = new ImageIcon(this.getClass().getResource(this.imagePath));
+ }
+
+ public Image getImage() {
+ return this.image;
+ }
+
+ public void setImage(final Image image) {
+ this.image = image;
+ }
+
+ public static Color getBackgroundColor() {
+ return MGradientPanel.backgroundColor;
+ }
+
+ public void setBackgroundColor(final Color backgroundColor) {
+ MGradientPanel.backgroundColor = backgroundColor;
+ }
+
+ public boolean isDrawBorder() {
+ return this.drawBorder;
+ }
+
+ public void setDrawBorder(final boolean drawBorder) {
+ this.drawBorder = drawBorder;
+ }
+
+ public boolean isFillImage() {
+ return this.fillImage;
+ }
+
+ public void setFillImage(final boolean fillImage) {
+ this.fillImage = fillImage;
+ }
+
+ public boolean isFillBackground() {
+ return this.fillBackground;
+ }
+
+ public void setFillBackground(final boolean kFillBackground) {
+ this.fillBackground = kFillBackground;
+ }
+
+ public int getBorderRadius() {
+ return this.borderRadius;
+ }
+
+ public void setBorderRadius(final int kBorderRadius) {
+ this.borderRadius = kBorderRadius;
+ }
+
+ public Color getStartColor() {
+ return this.startColor;
+ }
+
+ public void setStartColor(final Color kStartColor) {
+ this.startColor = kStartColor;
+ }
+
+ public Color getEndColor() {
+ return this.endColor;
+ }
+
+ public void setEndColor(final Color kEndColor) {
+ this.endColor = kEndColor;
+ }
+
+ public boolean isTransparentControls() {
+ return this.transparentControl;
+ }
+
+ public void setTransparentControls(final boolean kTransparentControls) {
+ this.transparentControl = kTransparentControls;
+ }
+
+ public int getGradientFocus() {
+ return this.gradientFocus;
+ }
+
+ public void setGradientFocus(final int kGradientFocus) {
+ this.gradientFocus = kGradientFocus;
+ }
+
+ public MGradientPanel() {
+ this.startColor = Color.MAGENTA;
+ this.endColor = Color.BLUE;
+ this.transparentControl = true;
+ this.gradientFocus = 500;
+ this.borderRadius = 10;
+ this.fillBackground = true;
+ this.imagePath = "/com/hq/swingmaterialdesign/images/profile.jpg";
+ this.icon = new ImageIcon(this.getClass().getResource(this.imagePath));
+ this.image = this.icon.getImage();
+ this.fillImage = false;
+ this.drawBorder = false;
+ this.setPreferredSize(new Dimension(50, 50));
+ if (this.transparentControl) {
+ this.setBg(true);
+ }
+ else {
+ this.setBg(false);
+ }
+ }
+
+ public static BufferedImage toBufferedImage(final Image img) {
+ if (img instanceof BufferedImage) {
+ return (BufferedImage)img;
+ }
+ final BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), 2);
+ final Graphics2D bGr = bimage.createGraphics();
+ bGr.drawImage(img, 0, 0, null);
+ bGr.dispose();
+ return bimage;
+ }
+
+ public static BufferedImage makeRoundedCorner(final BufferedImage image, final int cornerRadius) {
+ final int w = image.getWidth();
+ final int h = image.getHeight();
+ final BufferedImage output = new BufferedImage(w, h, 2);
+ final Graphics2D g2 = output.createGraphics();
+ g2.setComposite(AlphaComposite.Src);
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(getBackgroundColor());
+ g2.fill(new RoundRectangle2D.Float(0.0f, 0.0f, (float)w, (float)h, (float)cornerRadius, (float)cornerRadius));
+ g2.setComposite(AlphaComposite.SrcAtop);
+ g2.drawImage(image, 0, 0, null);
+ g2.dispose();
+ return output;
+ }
+
+ @Override
+ public synchronized void addMouseMotionListener(final MouseMotionListener l) {
+ super.addMouseMotionListener(l);
+ }
+
+ @Override
+ protected void paintComponent(final Graphics g) {
+ super.paintComponent(g);
+ final Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ final int w = this.getWidth();
+ final int h = this.getHeight();
+ final Dimension arcs = new Dimension(this.borderRadius, this.borderRadius);
+ if (this.isFillImage()) {
+ g2d.setComposite(AlphaComposite.SrcAtop);
+ g2d.drawImage(this.image = makeRoundedCorner(toBufferedImage(this.image), this.borderRadius), 0, 0, this.getWidth(), this.getHeight(), this);
+ }
+ else {
+ final GradientPaint gp = new GradientPaint(0.0f, 0.0f, this.startColor, (float)this.gradientFocus, (float)h, this.endColor);
+ g2d.setPaint(gp);
+ }
+ if (this.fillBackground && !this.fillImage) {
+ g2d.fillRoundRect(0, 0, w - 1, h - 1, arcs.width, arcs.height);
+ }
+ if (!this.fillImage) {
+ g2d.drawRoundRect(0, 0, w - 1, h - 1, arcs.width, arcs.height);
+ g2d.fillRoundRect(0, 0, w - 1, h - 1, arcs.width, arcs.height);
+ }
+ else if (this.drawBorder) {
+ g2d.drawRoundRect(0, 0, w - 1, h - 1, arcs.width, arcs.height);
+ }
+ }
+
+ private void setBg(final boolean isOpaque) {
+ final Component[] components2;
+ final Component[] components = components2 = this.getComponents();
+ for (final Component component : components2) {
+ ((JLabel)component).setOpaque(isOpaque);
+ ((JCheckBox)component).setOpaque(isOpaque);
+ ((JTextField)component).setOpaque(isOpaque);
+ ((JPasswordField)component).setOpaque(isOpaque);
+ ((JFormattedTextField)component).setOpaque(isOpaque);
+ ((JToolBar)component).setOpaque(isOpaque);
+ ((JRadioButton)component).setOpaque(isOpaque);
+ }
+ }
+
+ static {
+ MGradientPanel.backgroundColor = Color.WHITE;
+ }
+}
\ No newline at end of file
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MaterialIconButton.java b/src/com/hq/swingmaterialdesign/materialdesign/MIconButton.java
similarity index 92%
rename from src/com/hq/swingmaterialdesign/materialdesign/MaterialIconButton.java
rename to src/com/hq/swingmaterialdesign/materialdesign/MIconButton.java
index 54b965d..cfe45da 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/MaterialIconButton.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MIconButton.java
@@ -1,73 +1,74 @@
-package com.hq.swingmaterialdesign.materialdesign;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.FocusEvent;
-import java.awt.event.MouseEvent;
-
-/**
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class MaterialIconButton extends JButton {
-
- private final RippleEffect ripple;
-
- /**
- * Creates a new button.
- */
- public MaterialIconButton() {
- ripple = RippleEffect.applyFixedTo(this);
- setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
- setOpaque(false);
- setBackground(new Color(0, 0, 0, 0));
- }
-
- @Override
- public void setIcon(Icon icon) {
- super.setIcon(icon);
- repaint();
- }
-
- @Override
- public void setEnabled(boolean b) {
- super.setEnabled(b);
- repaint();
- }
-
- @Override
- protected void processFocusEvent(FocusEvent focusEvent) {
- super.processFocusEvent(focusEvent);
- repaint();
- }
-
- @Override
- protected void processMouseEvent(MouseEvent mouseEvent) {
- super.processMouseEvent(mouseEvent);
- repaint();
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- Graphics2D g2 = (Graphics2D) g;
- g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-
- if (isEnabled()) {
- if (getIcon() != null) {
- getIcon().paintIcon(this, g2, 12, 12);
- }
- g2.setColor(getForeground());
- ripple.paint(g2);
- } else if (getIcon() != null) {
- AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
- g2.setComposite(ac);
- getIcon().paintIcon(this, g2, 12, 12);
- }
- }
-
- @Override
- protected void paintBorder(Graphics g) {
- //intentionally left blank
- }
-}
+package com.hq.swingmaterialdesign.materialdesign;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.MouseEvent;
+
+/**
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class MIconButton extends JButton {
+
+ private final RippleEffect ripple;
+
+ /**
+ * Creates a new button.
+ */
+ public MIconButton() {
+ ripple = RippleEffect.applyFixedTo(this);
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ setOpaque(false);
+ setBackground(new Color(0, 0, 0, 0));
+ }
+
+ @Override
+ public void setIcon(Icon icon) {
+ super.setIcon(icon);
+ repaint();
+ }
+
+ @Override
+ public void setEnabled(boolean b) {
+ super.setEnabled(b);
+ repaint();
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent focusEvent) {
+ super.processFocusEvent(focusEvent);
+ repaint();
+ }
+
+ @Override
+ protected void processMouseEvent(MouseEvent mouseEvent) {
+ super.processMouseEvent(mouseEvent);
+ repaint();
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ if (isEnabled()) {
+ if (getIcon() != null) {
+ getIcon().paintIcon(this, g2, 12, 12);
+ }
+ g2.setColor(getForeground());
+ ripple.paint(g2);
+ } else if (getIcon() != null) {
+ AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
+ g2.setComposite(ac);
+ getIcon().paintIcon(this, g2, 12, 12);
+ }
+ }
+
+ @Override
+ protected void paintBorder(Graphics g) {
+ //intentionally left blank
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MaterialPanel.java b/src/com/hq/swingmaterialdesign/materialdesign/MPanel.java
similarity index 96%
rename from src/com/hq/swingmaterialdesign/materialdesign/MaterialPanel.java
rename to src/com/hq/swingmaterialdesign/materialdesign/MPanel.java
index 1fa38fb..a23ad39 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/MaterialPanel.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MPanel.java
@@ -1,98 +1,98 @@
-package com.hq.swingmaterialdesign.materialdesign;
-
-import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import java.awt.*;
-
-/**
- * A JPanel customized for Material components. What makes these panels special
- * is the possibility of assigning them an elevation level. Elevation can help
- * distinguishing elements inside a Material-based GUI, and any changes done to
- * them result in nicely animated transitions, helping to achieve that Material
- * flow.
- *
- * However, there is a catch: shadows are kinda expensive to compute, as Java2D
- * relies on the CPU for anything other than images, so having a lot of elements
- * with a given elevation (and thus, a shadow) can reduce performance when these
- * elevations change due to the triggered animations.
- *
- * Letting the components suggest a prefered size based on their contents is
- * still under development, so it is not advised to use your favorite
- * {@link LayoutManager} inside a {@code MaterialPanel} unless you set the
- * prefered, minimum and maximum size of each component by yourself. Currently,
- * the prefereable approach to follow is overriding {@link #doLayout()} and
- * taking care of any arrangements by yourself.
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class MaterialPanel extends JPanel {
-
- private final ElevationEffect elevation;
-
- /**
- * Creates a new {@code MaterialPanel}. These panels cast a shadow below
- * them, although technically it is painted inside its borders. If you don't
- * need a shadow to be casted from this panel, use a {@link JPanel} instead.
- */
- public MaterialPanel() {
- elevation = ElevationEffect.applyTo(this, 1);
- setBorder(new EmptyBorder(MaterialShadow.OFFSET_TOP, MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_BOTTOM, MaterialShadow.OFFSET_RIGHT));
- }
-
- /**
- * Gets the elevation level of this panel. Changes in elevation trigger an
- * animated transition if the component is currently visible, so it is
- * incorrect to assume the returned value will reflect how the resulting
- * shadow looks right now.
- *
- * @return elevation level [0~5]
- * @see ElevationEffect
- */
- public double getElevation() {
- return elevation.getLevel();
- }
-
- /**
- * Sets the elevation level of this panel. Changes in elevation trigger an
- * animated transition if the component is currently visible, so it will
- * take a little while for the resulting shadow to reflect the level once it
- * is set.
- *
- * @param elevation elevation level [0~5]
- * @see ElevationEffect
- */
- public void setElevation(int elevation) {
- this.elevation.setLevel(elevation);
- }
-
- /**
- * Sets the background color of this panel. Keep on mind that setting a
- * background color in a Material component like this will also set the
- * foreground color to either white or black, depending of how bright or
- * dark is the chosen background color.
- *
+ * Keep on mind that setting a background color in a Material component like
+ * this will also set the foreground color to either white or black and the
+ * ripple color to a brighter or darker shade of the color, depending of how
+ * bright or dark is the chosen background color. If you want to use a
+ * custom foreground color and ripple color, ensure the background color has
+ * been set first.
+ *
+ * NOTE: It is up to the look and feel to honor this property, some
+ * may choose to ignore it. To avoid any conflicts, using the
+ *
+ * Metal Look and Feel is recommended.
+ *
+ * @param bg
+ */
+ @Override
+ public void setBackground(Color bg) {
+ super.setBackground(bg);
+ setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.BLACK);
+ setRippleColor(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialUtils.darken(MaterialUtils.darken(bg)));
+ }
+
+ /**
+ * Gets the ripple color.
+ *
+ * @return the ripple color
+ */
+ public Color getRippleColor() {
+ return rippleColor;
+ }
+
+ /**
+ * Sets the ripple color. You should only do this for flat buttons.
+ *
+ * @param rippleColor the ripple color
+ */
+ public void setRippleColor(Color rippleColor) {
+ this.rippleColor = rippleColor;
+ }
+
+ /**
+ * Gets the current border radius of this button.
+ *
+ * @return the current border radius of this button, in pixels.
+ */
+ public int getBorderRadius() {
+ return borderRadius;
+ }
+
+ /**
+ * Sets the border radius of this button. You can define a custom radius in
+ * order to get some rounded corners in your button, making it look like a
+ * pill or even a circular action button.
+ *
+ * @param borderRadius the new border radius of this button, in pixels.
+ */
+ public void setBorderRadius(int borderRadius) {
+ this.borderRadius = borderRadius;
+ }
+
+ @Override
+ public void setEnabled(boolean b) {
+ super.setEnabled(b);
+ super.setCursor(b ? cursor : Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ @Override
+ public void setCursor(Cursor cursor) {
+ super.setCursor(cursor);
+ this.cursor = cursor;
+ }
+
+ public Color getSelectedColor() {
+ return selectedColor;
+ }
+
+ public void setSelectedColor(Color selectedColor) {
+ this.selectedColor = selectedColor;
+ }
+
+ public int getIndicatorThickness() {
+ return indicatorThickness;
+ }
+
+ public void setIndicatorThickness(int indicatorThickness) {
+ this.indicatorThickness = indicatorThickness;
+ }
+
+ public Color getIndicatorColor() {
+ return indicatorColor;
+ }
+
+ public void setIndicatorColor(Color indicatorColor) {
+ this.indicatorColor = indicatorColor;
+ }
+
+ public Color getStartColor() {
+ return startColor;
+ }
+
+ public void setStartColor(Color startColor) {
+ this.startColor = startColor;
+ }
+
+ public boolean isAllowTab() {
+ return allowTab;
+ }
+
+ public void setAllowTab(boolean allowTab) {
+ this.allowTab = allowTab;
+ }
+
+ public Color getEndColor() {
+ return endColor;
+ }
+
+ public void setEndColor(Color endColor) {
+ this.endColor = endColor;
+ }
+
+ public void select() {
+ this.setSelected(true);
+ this.setBorder(BorderFactory.createMatteBorder(0, this.indicatorThickness, 0, 0, this.indicatorColor));
+ this.repaint();
+ }
+
+ public void unselect(){
+ this.setSelected(false);
+ this.setBorder(BorderFactory.createEmptyBorder());
+ }
+
+ public Color getHoverStartColor() {
+ return hoverStartColor;
+ }
+
+ public void setHoverStartColor(Color hoverStartColor) {
+ this.hoverStartColor = hoverStartColor;
+ }
+
+ public Color getHoverEndColor() {
+ return hoverEndColor;
+ }
+
+ public void setHoverEndColor(Color hoverEndColor) {
+ this.hoverEndColor = hoverEndColor;
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent focusEvent) {
+ super.processFocusEvent(focusEvent);
+ }
+
+ @Override
+ protected void processMouseEvent(MouseEvent mouseEvent) {
+ super.processMouseEvent(mouseEvent);
+ }
+
+ private void getStyle() {
+ if (isMousePressed) {
+
+ if (isAllowTab()) {
+ Component[] comp = getParent().getComponents();
+ for (int i = 0; i < comp.length; i++) {
+ if (comp[i] instanceof MToggleButton) {
+
+ ((MToggleButton) comp[i]).setSelected(false);
+ ((MToggleButton) comp[i]).setBorder(BorderFactory.createEmptyBorder());
+ }
+ }
+ this.setBorder(BorderFactory.createMatteBorder(0, indicatorThickness, 0, 0, indicatorColor));
+ this.setSelected(true);
+ }
+
+ } else {
+ this.setBorder(BorderFactory.createEmptyBorder());
+ this.setSelected(false);
+ }
+ }
+
+ private int getElevation() {
+ if (isMousePressed) {
+ this.setBorder(BorderFactory.createMatteBorder(0, indicatorThickness, 0, 0, indicatorColor));
+ this.setSelected(true);
+ return 2;
+ } else if (type == Type.RAISED || isMouseOver) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ if ((type != Type.FLAT) && isEnabled()) {
+ g2.translate(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP);
+ }
+
+ int offset_lr;
+ int offset_td;
+ if (type == Type.FLAT) {
+ offset_td = 0;
+ offset_lr = 0;
+ } else {
+ offset_td = MaterialShadow.OFFSET_TOP + MaterialShadow.OFFSET_BOTTOM;
+ offset_lr = MaterialShadow.OFFSET_LEFT + MaterialShadow.OFFSET_RIGHT;
+ }
+
+ if (isEnabled()) {
+ GradientPaint gp = new GradientPaint(0, 0, startColor, 300, getHeight(), endColor);
+ g2.setPaint(gp);
+ if (isMouseOver) {
+ gp = new GradientPaint(0, 0, hoverStartColor, 300, getHeight(), hoverEndColor);
+ g2.setPaint(gp);
+ } else {
+ gp = new GradientPaint(0, 0, startColor, 300, getHeight(), endColor);
+ g2.setPaint(gp);
+ }
+
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ if (type == Type.FLAT) {
+ //g2.setColor(MaterialUtils.brighten(getBackground()));
+ //g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius, borderRadius));
+ }
+
+ } else {
+ Color bg = getBackground();
+ g2.setColor(new Color(bg.getRed() / 255f, bg.getGreen() / 255f, bg.getBlue() / 255f, 0.6f));
+
+ g2.fill(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, borderRadius * 2, borderRadius * 2));
+ }
+
+ if (isSelected()) {
+ g2.setPaint(selectedColor);
+ g2.fillRoundRect(0, 0, getWidth(), getHeight(), borderRadius, borderRadius);
+ }
+
+ FontMetrics metrics = g.getFontMetrics(getFont());
+ int x = (getWidth() - offset_lr - metrics.stringWidth(getText().toUpperCase())) / 2;
+ int y = (getHeight() - offset_td - metrics.getHeight()) / 2 + metrics.getAscent();
+ g2.setFont(getFont());
+ if (isEnabled()) {
+ g2.setColor(getForeground());
+
+ } else {
+ Color fg = getForeground();
+ g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, 0.6f));
+ }
+ g2.drawString(getText().toUpperCase(), x, y);
+
+ if (isEnabled()) {
+ g2.setClip(new RoundRectangle2D.Float(0, 0, getWidth() - offset_lr, getHeight() - offset_td, Math.max(borderRadius - 6, 0), Math.max(borderRadius * 2 - 4, 0)));
+ g2.setColor(rippleColor);
+ ripple.paint(g2);
+ }
+ }
+
+// @Override
+// protected void paintBorder(Graphics g) {
+// //intentionally left blank
+// }
+ /**
+ * Button types.
+ */
+ public enum Type {
+ /**
+ * A default button.
+ */
+ DEFAULT,
+ /**
+ * A raised button. Raised buttons have a shadow even if they are not
+ * focused.
+ */
+ RAISED,
+ /**
+ * A flat button. Flat buttons don't have shadows and are typically
+ * transparent.
+ */
+ FLAT
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton_old.java b/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton_old.java
new file mode 100644
index 0000000..c231103
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton_old.java
@@ -0,0 +1,310 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.hq.swingmaterialdesign.materialdesign;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+
+/**
+ *
+ * @auauthor oXCToo
+ */
+public class MToggleButton_old extends JButton {
+
+ public Color kBackGroundColor = Color.magenta;
+ public Color kStartColor = new Color(0, 153, 153);
+ public Color kEndColor = Color.GREEN;
+ public Color kHoverStartColor = new Color(255, 0, 255);
+ public Color kHoverEndColor = Color.green;
+ public Color kHoverColor = Color.white;
+ public boolean kAllowGradient = true;
+ public int kBorderRadius = 10;
+ private boolean mouseExited = false;
+ private boolean mouseEntered = false;
+ private boolean mousePressed = false;
+ private boolean mouseReleased = false;
+ public boolean kFillButton = true;
+ public Color kSelectedColor = Color.magenta;
+ public Color kPressedColor = Color.LIGHT_GRAY;
+ public int kIndicatorThickness = 2;
+ public Color kIndicatorColor = Color.white;
+ public boolean kAllowTab = true;
+
+ public boolean iskAllowTab() {
+ return kAllowTab;
+ }
+
+ public void setkAllowTab(boolean kAllowTab) {
+ this.kAllowTab = kAllowTab;
+ }
+
+ public int getkIndicatorThickness() {
+ return kIndicatorThickness;
+ }
+
+ public void setkIndicatorThickness(int kIndicatorThickness) {
+ this.kIndicatorThickness = kIndicatorThickness;
+
+ }
+
+ public Color getkIndicatorColor() {
+ return kIndicatorColor;
+ }
+
+ public void setkIndicatorColor(Color kIndicatorColor) {
+ this.kIndicatorColor = kIndicatorColor;
+ }
+
+ public Color getkPressedColor() {
+ return kPressedColor;
+ }
+
+ public void setkPressedColor(Color kPressedColor) {
+ this.kPressedColor = kPressedColor;
+ }
+
+ public Color getkSelectedColor() {
+ return kSelectedColor;
+ }
+
+ public void setkSelectedColor(Color kSelectedColor) {
+ this.kSelectedColor = kSelectedColor;
+ }
+
+
+ public Color getkBackGroundColor() {
+ return kBackGroundColor;
+ }
+
+ public void setkBackGroundColor(Color kBackGroundColor) {
+ this.kBackGroundColor = kBackGroundColor;
+ }
+
+ public Color getkStartColor() {
+ return kStartColor;
+ }
+
+ public void setkStartColor(Color kStartColor) {
+ this.kStartColor = kStartColor;
+ }
+
+ public Color getkEndColor() {
+ return kEndColor;
+ }
+
+ public void setkEndColor(Color kEndColor) {
+ this.kEndColor = kEndColor;
+ }
+
+ public Color getkHoverStartColor() {
+ return kHoverStartColor;
+ }
+
+ public void setkHoverStartColor(Color kHoverStartColor) {
+ this.kHoverStartColor = kHoverStartColor;
+ }
+
+ public Color getkHoverEndColor() {
+ return kHoverEndColor;
+ }
+
+ public void setkHoverEndColor(Color kHoverEndColor) {
+ this.kHoverEndColor = kHoverEndColor;
+ }
+
+ public Color getkHoverColor() {
+ return kHoverColor;
+ }
+
+ public void setkHoverColor(Color kHoverColor) {
+ this.kHoverColor = kHoverColor;
+ }
+
+ public boolean iskAllowGradient() {
+ return kAllowGradient;
+ }
+
+ public void setkAllowGradient(boolean kAllowGradient) {
+ this.kAllowGradient = kAllowGradient;
+ }
+
+ public int getkBorderRadius() {
+ return kBorderRadius;
+ }
+
+ public void setkBorderRadius(int kBorderRadius) {
+ this.kBorderRadius = kBorderRadius;
+ }
+
+ public boolean iskFillButton() {
+ return kFillButton;
+ }
+
+ public void setkFillButton(boolean kFillButton) {
+ this.kFillButton = kFillButton;
+ }
+
+ public MToggleButton_old() {
+
+ this.setPreferredSize(new Dimension(185, 45));
+ this.setForeground(Color.white);
+
+ MouseAdapter mouseAdapter = new MouseAdapter() {
+ @Override
+ public void mouseEntered(MouseEvent me) {
+ if (contains(me.getX(), me.getY())) {
+ mouseEntered = true;
+ repaint();
+ }
+ }
+
+ @Override
+ public void mouseExited(MouseEvent me) {
+ mouseExited = false;
+ mouseEntered = false;
+ repaint();
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ mousePressed = false;
+ mouseReleased = true;
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ mousePressed = true;
+ mouseReleased = false;
+ }
+
+ };
+ addMouseListener(mouseAdapter);
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+
+ Graphics2D g2 = (Graphics2D) g.create();
+
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ if (mousePressed == true) {
+ g2.setPaint(kPressedColor);
+ if (iskAllowTab()) {
+ Component[] comp = getParent().getComponents();
+ for (int i = 0; i < comp.length; i++) {
+ if (comp[i] instanceof MToggleButton_old) {
+
+ ((MToggleButton_old) comp[i]).setSelected(false);
+ ((MToggleButton_old) comp[i]).setBorder(BorderFactory.createMatteBorder(0, 0, 0, 0, kIndicatorColor));
+ }
+ }
+ this.setBorder(BorderFactory.createMatteBorder(0, kIndicatorThickness, 0, 0, kIndicatorColor));
+ this.setSelected(true);
+ }
+
+ } else {
+ GradientPaint gp = new GradientPaint(0, 0, kStartColor, 300, getHeight(), kEndColor);
+ g2.setPaint(gp);
+ if (mouseEntered) {
+ gp = new GradientPaint(0, 0, kHoverStartColor, 300, getHeight(), kHoverEndColor);
+ g2.setPaint(gp);
+ } else if (mouseExited) {
+ gp = new GradientPaint(0, 0, kStartColor, 300, getHeight(), kEndColor);
+ g2.setPaint(gp);
+ }
+ }
+ // g2.fillRect(0, 0, getWidth(), getHeight());
+ if (isSelected()) {
+ g2.setPaint(kSelectedColor);
+ }
+ if (kFillButton == true) {
+ g2.fillRoundRect(0, 0, getWidth(), getHeight(), kBorderRadius, kBorderRadius);
+ }
+ g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, kBorderRadius, kBorderRadius);
+ // The drawString(string) must be put after the setPaint(gradient)
+ g2.setPaint(Color.BLACK);
+ centerString(g, new Rectangle(getWidth(), getHeight()), getText(), getFont());
+
+ // draw account
+// try {
+// getIcon().paintIcon(this, g2, getHeight()/2, 4);
+// } catch (Exception e) {
+// }
+ drawIcons(g, new Rectangle(0, 0, getWidth(), getHeight()));
+
+
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ //dispose
+ g2.dispose();
+
+ }
+
+ public void centerString(Graphics g, Rectangle r, String s,
+ Font font) {
+ FontRenderContext frc
+ = new FontRenderContext(null, true, true);
+
+ Rectangle2D r2D = font.getStringBounds(s, frc);
+ int rWidth = (int) Math.round(r2D.getWidth());
+ int rHeight = (int) Math.round(r2D.getHeight());
+ int rX = (int) Math.round(r2D.getX());
+ int rY = (int) Math.round(r2D.getY());
+
+ int a = (r.width / 2) - (rWidth / 2) - rX;
+ int b = (r.height / 2) - (rHeight / 2) - rY;
+
+ g.setFont(font);
+ g.drawString(s, r.x + a, r.y + b);
+ }
+
+ public void drawIcons(Graphics g, Rectangle r) {
+
+ try {
+ FontRenderContext frc
+ = new FontRenderContext(null, true, true);
+
+ Rectangle2D r2D = getFont().getStringBounds(getText(), frc);
+ int rWidth = (int) Math.round(r2D.getWidth());
+ int rHeight = (int) Math.round(r2D.getHeight());
+ int rX = (int) Math.round(r2D.getX());
+ int rY = (int) Math.round(r2D.getY());
+
+ int a = (r.width / 2) - (rWidth / 2) - rX;
+ int b = (r.height / 2) - (rHeight / 2) - rY;
+
+ getIcon().paintIcon(this, g, getIconTextGap(), (getHeight() / 3));
+
+// if (getIcon().getIconHeight() > getHeight() / 2) {
+// int zoomLevel = 10;
+// int newImageWidth = getIcon().getIconWidth() * zoomLevel;
+// int newImageHeight = getIcon().getIconHeight() * zoomLevel;
+// BufferedImage resizedImage = new BufferedImage(newImageWidth, newImageHeight, 0);
+// resizedImage.createGraphics();
+// g.drawImage((Image) getIcon(), 0, 0, newImageWidth, newImageHeight, null);
+//
+// }
+ } catch (Exception e) {
+ }
+
+ }
+
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MaterialFloatingLabel.java b/src/com/hq/swingmaterialdesign/materialdesign/MaterialFloatingLabel.java
index cf7d11e..fe971bb 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/MaterialFloatingLabel.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MaterialFloatingLabel.java
@@ -1,102 +1,102 @@
-package com.hq.swingmaterialdesign.materialdesign;
-
-import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
-import com.hq.swingmaterialdesign.materialdesign.resource.Roboto;
-import com.hq.swingmaterialdesign.materialdesign.animation.AnimationListener;
-import com.hq.swingmaterialdesign.materialdesign.animation.Animator;
-
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * A floating label of a text field.
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class MaterialFloatingLabel {
-
- public static final int HINT_OPACITY_MASK = 0x99000000;
-
- private final JTextField target;
- private final Animator animator;
- private Color color;
- private String text;
- private Color accentColor = MaterialColor.CYAN_500;
- private double fontCrement;
- private double targetFontSize;
- private double fontSize;
-
- MaterialFloatingLabel(JTextField target) {
- this.target = target;
- targetFontSize = fontSize = 16d;
- color = MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK);
- animator = new Animator(new AnimationListener() {
- @Override
- public void onStart() {
-
- }
-
- @Override
- public void onAnimation(double percent) {
- fontSize += fontCrement;
- target.repaint();
- }
-
- @Override
- public void onEnd() {
- fontSize = targetFontSize;
- target.repaint();
- }
-
- @Override
- public void onStop() {
- fontSize = targetFontSize;
- target.repaint();
- }
- })
- .setDelay(0)
- .setDuration(100);
- }
-
- void update() {
- animator.stop();
- targetFontSize = target.isFocusOwner() ? 12d : 16d;
- if (fontSize != targetFontSize) {
- fontCrement = +(double) (targetFontSize - fontSize) / 100;
- animator.start();
- }
-
- if (target.isFocusOwner()) {
- color = accentColor;
- } else {
- color = MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK);
- }
- }
-
- public void updateForeground() {
- color = (MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK));
- }
-
- public Color getAccent() {
- return accentColor;
- }
-
- public void setAccent(Color accentColor) {
- this.accentColor = accentColor;
- }
-
- String getText() {
- return text;
- }
-
- void setText(String text) {
- this.text = text;
- }
-
- void paint(Graphics2D g) {
- g.setFont(Roboto.REGULAR.deriveFont((float) fontSize));
- g.setColor(color);
- FontMetrics metrics = g.getFontMetrics(g.getFont());
- g.drawString(getText(), 0, metrics.getAscent() + 0);
- }
-}
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
+import com.hq.swingmaterialdesign.materialdesign.resource.Roboto;
+import com.hq.swingmaterialdesign.materialdesign.animation.AnimationListener;
+import com.hq.swingmaterialdesign.materialdesign.animation.Animator;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * A floating label of a text field.
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class MaterialFloatingLabel {
+
+ public static final int HINT_OPACITY_MASK = 0x99000000;
+
+ private final JTextField target;
+ private final Animator animator;
+ private Color color;
+ private String text;
+ private Color accentColor = MaterialColor.CYAN_500;
+ private double fontCrement;
+ private double targetFontSize;
+ private double fontSize;
+
+ MaterialFloatingLabel(JTextField target) {
+ this.target = target;
+ targetFontSize = fontSize = 16d;
+ color = MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK);
+ animator = new Animator(new AnimationListener() {
+ @Override
+ public void onStart() {
+
+ }
+
+ @Override
+ public void onAnimation(double percent) {
+ fontSize += fontCrement;
+ target.repaint();
+ }
+
+ @Override
+ public void onEnd() {
+ fontSize = targetFontSize;
+ target.repaint();
+ }
+
+ @Override
+ public void onStop() {
+ fontSize = targetFontSize;
+ target.repaint();
+ }
+ })
+ .setDelay(0)
+ .setDuration(100);
+ }
+
+ void update() {
+ animator.stop();
+ targetFontSize = target.isFocusOwner() ? 12d : 16d;
+ if (fontSize != targetFontSize) {
+ fontCrement = +(double) (targetFontSize - fontSize) / 100;
+ animator.start();
+ }
+
+ if (target.isFocusOwner()) {
+ color = accentColor;
+ } else {
+ color = MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK);
+ }
+ }
+
+ public void updateForeground() {
+ color = (MaterialUtils.applyAlphaMask(target.getForeground(), HINT_OPACITY_MASK));
+ }
+
+ public Color getAccent() {
+ return accentColor;
+ }
+
+ public void setAccent(Color accentColor) {
+ this.accentColor = accentColor;
+ }
+
+ String getText() {
+ return text;
+ }
+
+ void setText(String text) {
+ this.text = text;
+ }
+
+ void paint(Graphics2D g) {
+ g.setFont(Roboto.REGULAR.deriveFont((float) fontSize));
+ g.setColor(color);
+ FontMetrics metrics = g.getFontMetrics(g.getFont());
+ g.drawString(getText(), 0, metrics.getAscent() + 0);
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/RippleEffect.java b/src/com/hq/swingmaterialdesign/materialdesign/RippleEffect.java
index a884d6b..b7eeab5 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/RippleEffect.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/RippleEffect.java
@@ -1,168 +1,172 @@
-package com.hq.swingmaterialdesign.materialdesign;
-
-import com.hq.swingmaterialdesign.materialdesign.animation.AnimationListener;
-import com.hq.swingmaterialdesign.materialdesign.animation.Animator;
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-/**
- * A {@code RippleEffect} is applied into certain components, like buttons and
- * certain list elements. Basically, is that wave of color that appears when you
- * click stuff.
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class RippleEffect {
-
- private final JComponent target;
- private final RippleAnimation ripple = new RippleAnimation();
-
- private RippleEffect(final JComponent component) {
- this.target = component;
- }
-
- /**
- * Paints this effect. Each component is responsible of calling {@link
- * #paint(Graphics)} in order to display the effect. Here's an example of
- * how the ripple effect can be used:
- *
- * @param g canvas
- */
- public void paint(Graphics g) {
- if (ripple.isRippling()) {
- Graphics2D g2 = (Graphics2D) g;
- float rippleOpacity = (float) ripple.getRippleOpacity();
- Point rippleCenter = ripple.getRippleCenter();
- int rippleRadius = (int) ripple.getRippleRadius();
- Color fg = g2.getColor();
- g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, rippleOpacity));
- g2.fillOval(rippleCenter.x - rippleRadius, rippleCenter.y - rippleRadius, 2 * rippleRadius, 2 * rippleRadius);
- }
- }
-
- /**
- * Adds a ripple at the given point.
- *
- * @param point point to add the ripple at
- * @param maxRadius the maximum radius of the ripple
- */
- private void addRipple(Point point, int maxRadius) {
- ripple.setRipple(point, maxRadius);
- ripple.start();
- }
-
- /**
- * Creates a ripple effect for the given component. Each component is
- * responsible of calling {@link #paint(Graphics)} in order to display the
- * effect. Here's an example of how the ripple effect can be used:
- *
- * @param target target component
- * @return ripple effect for that component
- * @see MaterialButton for an example of how the ripple effect is used
- */
- public static RippleEffect applyTo(final JComponent target) {
- final RippleEffect rippleEffect = new RippleEffect(target);
- target.addMouseListener(new MouseAdapter() {
- @Override
- public void mousePressed(MouseEvent e) {
- rippleEffect.addRipple(e.getPoint(), target.getWidth());
- }
- });
- return rippleEffect;
- }
-
- /**
- * Creates a ripple effect for the given component that is limited to the
- * component's size and will always start in the center. Each component is
- * responsible of calling {@link #paint(Graphics)} in order to display the
- * effect. Here's an example of how the ripple effect can be used:
- *
- * @param target target component
- * @return ripple effect for that component
- * @see MaterialButton for an example of how the ripple effect is used
- */
- public static RippleEffect applyFixedTo(final JComponent target) {
- final RippleEffect rippleEffect = new RippleEffect(target);
- target.addMouseListener(new MouseAdapter() {
- @Override
- public void mousePressed(MouseEvent e) {
- rippleEffect.addRipple(new Point(24, 24), target.getWidth() / 2);
- }
- });
- return rippleEffect;
- }
-
- /**
- * A ripple animation (one ripple circle after one click).
- */
- private class RippleAnimation {
-
- private final Animator animator;
- private Point rippleCenter;
- private int maxRadius;
- private double rippleRadius;
- private double targetRippleRadius;
- private double rippleRadiusCrement;
- private double rippleOpacity;
-
- private RippleAnimation() {
- animator = new Animator(new AnimationListener() {
- @Override
- public void onStart() {
- rippleRadius = 0;
- targetRippleRadius = maxRadius;
- rippleRadiusCrement = +(double) (targetRippleRadius - rippleRadius);
- rippleOpacity = 0.5;
- }
-
- @Override
- public void onAnimation(double percent) {
- rippleRadius = rippleRadiusCrement * percent * percent;
- rippleOpacity = 0.5 * Math.sin(3.0 * percent * percent);
- target.repaint();
- }
-
- @Override
- public void onEnd() {
- rippleRadius = 0;
- target.repaint();
- }
-
- @Override
- public void onStop() {
- rippleRadius = 0;
- target.repaint();
- }
- })
- .setDelay(0)
- .setDuration(999);
- }
-
- void start() {
- animator.start();
- }
-
- public void setRipple(Point rippleCenter, int maxRadius) {
- this.rippleCenter = rippleCenter;
- this.maxRadius = maxRadius;
- }
-
- public double getRippleOpacity() {
- return rippleOpacity;
- }
-
- public Point getRippleCenter() {
- return rippleCenter;
- }
-
- public double getRippleRadius() {
- return rippleRadius;
- }
-
- public boolean isRippling() {
- return animator.isRunning();
- }
- }
-}
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.animation.AnimationListener;
+import com.hq.swingmaterialdesign.materialdesign.animation.Animator;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/**
+ * A {@code RippleEffect} is applied into certain components, like buttons and
+ * certain list elements. Basically, is that wave of color that appears when you
+ * click stuff.
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class RippleEffect {
+
+ private final JComponent target;
+ private final RippleAnimation ripple = new RippleAnimation();
+
+ private RippleEffect(final JComponent component) {
+ this.target = component;
+ }
+
+ /**
+ * Paints this effect. Each component is responsible of calling {@link
+ * #paint(Graphics)} in order to display the effect. Here's an example of
+ * how the ripple effect can be used:
+ *
+ * @param g canvas
+ */
+ public void paint(Graphics g) {
+ if (ripple.isRippling()) {
+ Graphics2D g2 = (Graphics2D) g;
+ float rippleOpacity = (float) ripple.getRippleOpacity();
+ Point rippleCenter = ripple.getRippleCenter();
+ int rippleRadius = (int) ripple.getRippleRadius();
+ Color fg = g2.getColor();
+ try {
+ g2.setColor(new Color(fg.getRed() / 255f, fg.getGreen() / 255f, fg.getBlue() / 255f, rippleOpacity));
+ } catch (Exception e) {
+ //
+ }
+ g2.fillOval(rippleCenter.x - rippleRadius, rippleCenter.y - rippleRadius, 2 * rippleRadius, 2 * rippleRadius);
+ }
+ }
+
+ /**
+ * Adds a ripple at the given point.
+ *
+ * @param point point to add the ripple at
+ * @param maxRadius the maximum radius of the ripple
+ */
+ private void addRipple(Point point, int maxRadius) {
+ ripple.setRipple(point, maxRadius);
+ ripple.start();
+ }
+
+ /**
+ * Creates a ripple effect for the given component. Each component is
+ * responsible of calling {@link #paint(Graphics)} in order to display the
+ * effect. Here's an example of how the ripple effect can be used:
+ *
+ * @param target target component
+ * @return ripple effect for that component
+ * @see MaterialButton for an example of how the ripple effect is used
+ */
+ public static RippleEffect applyTo(final JComponent target) {
+ final RippleEffect rippleEffect = new RippleEffect(target);
+ target.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ rippleEffect.addRipple(e.getPoint(), target.getWidth());
+ }
+ });
+ return rippleEffect;
+ }
+
+ /**
+ * Creates a ripple effect for the given component that is limited to the
+ * component's size and will always start in the center. Each component is
+ * responsible of calling {@link #paint(Graphics)} in order to display the
+ * effect. Here's an example of how the ripple effect can be used:
+ *
+ * @param target target component
+ * @return ripple effect for that component
+ * @see MaterialButton for an example of how the ripple effect is used
+ */
+ public static RippleEffect applyFixedTo(final JComponent target) {
+ final RippleEffect rippleEffect = new RippleEffect(target);
+ target.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ rippleEffect.addRipple(new Point(24, 24), target.getWidth() / 2);
+ }
+ });
+ return rippleEffect;
+ }
+
+ /**
+ * A ripple animation (one ripple circle after one click).
+ */
+ private class RippleAnimation {
+
+ private final Animator animator;
+ private Point rippleCenter;
+ private int maxRadius;
+ private double rippleRadius;
+ private double targetRippleRadius;
+ private double rippleRadiusCrement;
+ private double rippleOpacity;
+
+ private RippleAnimation() {
+ animator = new Animator(new AnimationListener() {
+ @Override
+ public void onStart() {
+ rippleRadius = 0;
+ targetRippleRadius = maxRadius;
+ rippleRadiusCrement = +(double) (targetRippleRadius - rippleRadius);
+ rippleOpacity = 0.5;
+ }
+
+ @Override
+ public void onAnimation(double percent) {
+ rippleRadius = rippleRadiusCrement * percent * percent;
+ rippleOpacity = 0.5 * Math.sin(3.0 * percent * percent);
+ target.repaint();
+ }
+
+ @Override
+ public void onEnd() {
+ rippleRadius = 0;
+ target.repaint();
+ }
+
+ @Override
+ public void onStop() {
+ rippleRadius = 0;
+ target.repaint();
+ }
+ })
+ .setDelay(0)
+ .setDuration(999);
+ }
+
+ void start() {
+ animator.start();
+ }
+
+ public void setRipple(Point rippleCenter, int maxRadius) {
+ this.rippleCenter = rippleCenter;
+ this.maxRadius = maxRadius;
+ }
+
+ public double getRippleOpacity() {
+ return rippleOpacity;
+ }
+
+ public Point getRippleCenter() {
+ return rippleCenter;
+ }
+
+ public double getRippleRadius() {
+ return rippleRadius;
+ }
+
+ public boolean isRippling() {
+ return animator.isRunning();
+ }
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/animation/Animator.java b/src/com/hq/swingmaterialdesign/materialdesign/animation/Animator.java
index 9395241..85982f6 100644
--- a/src/com/hq/swingmaterialdesign/materialdesign/animation/Animator.java
+++ b/src/com/hq/swingmaterialdesign/materialdesign/animation/Animator.java
@@ -1,67 +1,71 @@
-package com.hq.swingmaterialdesign.materialdesign.animation;
-
-import javax.swing.*;
-
-/**
- *
- * @author bilux (i.bilux@gmail.com)
- */
-public class Animator {
-
- private final AnimationListener animationListener;
- private Timer animatorTimer;
-
- private int duration;
- private int takenTime;
- private long startTime;
-
- public Animator(AnimationListener listener) {
- this.animationListener = listener;
-
- animatorTimer = new Timer(1, e -> {
- takenTime = (int) (System.currentTimeMillis() - startTime);
- animationListener.onAnimation((double) takenTime / duration);
- if (takenTime >= duration) {
- SwingUtilities.invokeLater(() -> {
- animatorTimer.stop();
- animationListener.onEnd();
- });
- }
- });
- animatorTimer.setCoalesce(true);
- }
-
- public Animator setDelay(int delay) {
- animatorTimer.setInitialDelay(delay);
- return this;
- }
-
- public Animator setDuration(int duration) {
- this.duration = duration;
- return this;
- }
-
- public int getDuration() {
- return duration;
- }
-
- public void start() {
- animatorTimer.stop();
- animationListener.onStart();
- startTime = System.currentTimeMillis();
-
- animatorTimer.start();
- }
-
- public Animator stop() {
- if (animatorTimer != null && animatorTimer.isRunning()) {
- animationListener.onStop();
- animatorTimer.stop();
- }
- return this;
- }
-
- public boolean isRunning() {
- return animatorTimer != null && animatorTimer.isRunning();
- }
-}
+package com.hq.swingmaterialdesign.materialdesign.animation;
+
+import javax.swing.*;
+
+/**
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class Animator {
+
+ private final AnimationListener animationListener;
+ private Timer animatorTimer;
+
+ private int duration;
+ private int takenTime;
+ private long startTime;
+
+ public Animator(AnimationListener listener) {
+ this.animationListener = listener;
+
+ animatorTimer = new Timer(1, e -> {
+ takenTime = (int) (System.currentTimeMillis() - startTime);
+ try {
+ animationListener.onAnimation((double) takenTime / duration * 2);
+ } catch (java.lang.IllegalArgumentException except) {
+ System.out.println("Tá certo fio, confia");
+ }
+ if (takenTime >= (duration / 2)) {
+ SwingUtilities.invokeLater(() -> {
+ animatorTimer.stop();
+ animationListener.onEnd();
+ });
+ }
+ });
+ animatorTimer.setCoalesce(true);
+ }
+
+ public Animator setDelay(int delay) {
+ animatorTimer.setInitialDelay(delay);
+ return this;
+ }
+
+ public Animator setDuration(int duration) {
+ this.duration = duration;
+ return this;
+ }
+
+ public int getDuration() {
+ return duration;
+ }
+
+ public void start() {
+ animatorTimer.stop();
+ animationListener.onStart();
+ startTime = System.currentTimeMillis();
+
+ animatorTimer.start();
+ }
+
+ public Animator stop() {
+ if (animatorTimer != null && animatorTimer.isRunning()) {
+ animationListener.onStop();
+ animatorTimer.stop();
+ }
+ return this;
+ }
+
+ public boolean isRunning() {
+ return animatorTimer != null && animatorTimer.isRunning();
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/resource/Nunito.java b/src/com/hq/swingmaterialdesign/materialdesign/resource/Nunito.java
new file mode 100644
index 0000000..036f070
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/resource/Nunito.java
@@ -0,0 +1,37 @@
+package com.hq.swingmaterialdesign.materialdesign.resource;
+
+import java.awt.*;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The Nunito font.
+ *
+ *
+ * @author abner (abner.js05@gmail.com)
+ */
+public class Nunito {
+
+ public static final Font BLACK = loadFont("Nunito-Black.ttf").deriveFont(Font.BOLD);
+ public static final Font BLACK_ITALIC = loadFont("Nunito-BlackItalic.ttf").deriveFont(Font.BOLD | Font.ITALIC);
+ public static final Font BOLD = loadFont("Nunito-Bold.ttf").deriveFont(Font.BOLD);
+ public static final Font BOLD_ITALIC = loadFont("Nunito-BoldItalic.ttf").deriveFont(Font.BOLD | Font.ITALIC);
+ public static final Font EXTRA_BOLD = loadFont("Nunito-ExtraBold.ttf").deriveFont(Font.BOLD);
+ public static final Font EXTRA_BOLD_ITALIC = loadFont("Nunito-ExtraBoldItalic.ttf").deriveFont(Font.ITALIC);
+ public static final Font EXTRA_LIGHT = loadFont("Nunito-ExtraLight.ttf").deriveFont(Font.PLAIN);
+ public static final Font EXTRA_LIGHT_ITALIC = loadFont("Nunito-ExtraLightItalic.ttf").deriveFont(Font.ITALIC);
+ public static final Font LIGHT = loadFont("Nunito-Light.ttf").deriveFont(Font.PLAIN);
+ public static final Font LIGHT_ITALIC = loadFont("Nunito-LightItalic.ttf").deriveFont(Font.ITALIC);
+ public static final Font REGULAR = loadFont("Nunito-Regular.ttf").deriveFont(Font.PLAIN);
+ public static final Font REGULAR_ITALIC = loadFont("Nunito-RegularItalic.ttf").deriveFont(Font.ITALIC);
+ public static final Font SEMI_BOLD = loadFont("Roboto-SemiBold.ttf").deriveFont(Font.PLAIN);
+ public static final Font SEMI_BOLD_ITALIC = loadFont("Roboto-SemiBoldItalic.ttf").deriveFont(Font.ITALIC);
+
+ private static Font loadFont(String resourceName) {
+ try (InputStream inputStream = Nunito.class.getResourceAsStream("/resources/fonts/" + resourceName)) {
+ return Font.createFont(Font.TRUETYPE_FONT, inputStream);
+ } catch (IOException | FontFormatException e) {
+ throw new RuntimeException("Could not load " + resourceName, e);
+ }
+ }
+}
diff --git a/src/resources/fonts/Nunito-Black.ttf b/src/resources/fonts/Nunito-Black.ttf
new file mode 100644
index 0000000..330a207
Binary files /dev/null and b/src/resources/fonts/Nunito-Black.ttf differ
diff --git a/src/resources/fonts/Nunito-BlackItalic.ttf b/src/resources/fonts/Nunito-BlackItalic.ttf
new file mode 100644
index 0000000..2fe2ecf
Binary files /dev/null and b/src/resources/fonts/Nunito-BlackItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-Bold.ttf b/src/resources/fonts/Nunito-Bold.ttf
new file mode 100644
index 0000000..99d0735
Binary files /dev/null and b/src/resources/fonts/Nunito-Bold.ttf differ
diff --git a/src/resources/fonts/Nunito-BoldItalic.ttf b/src/resources/fonts/Nunito-BoldItalic.ttf
new file mode 100644
index 0000000..35d6d27
Binary files /dev/null and b/src/resources/fonts/Nunito-BoldItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-ExtraBold.ttf b/src/resources/fonts/Nunito-ExtraBold.ttf
new file mode 100644
index 0000000..993de65
Binary files /dev/null and b/src/resources/fonts/Nunito-ExtraBold.ttf differ
diff --git a/src/resources/fonts/Nunito-ExtraBoldItalic.ttf b/src/resources/fonts/Nunito-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..9d569fd
Binary files /dev/null and b/src/resources/fonts/Nunito-ExtraBoldItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-ExtraLight.ttf b/src/resources/fonts/Nunito-ExtraLight.ttf
new file mode 100644
index 0000000..2b71830
Binary files /dev/null and b/src/resources/fonts/Nunito-ExtraLight.ttf differ
diff --git a/src/resources/fonts/Nunito-ExtraLightItalic.ttf b/src/resources/fonts/Nunito-ExtraLightItalic.ttf
new file mode 100644
index 0000000..77bfabd
Binary files /dev/null and b/src/resources/fonts/Nunito-ExtraLightItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-Light.ttf b/src/resources/fonts/Nunito-Light.ttf
new file mode 100644
index 0000000..54a9a90
Binary files /dev/null and b/src/resources/fonts/Nunito-Light.ttf differ
diff --git a/src/resources/fonts/Nunito-LightItalic.ttf b/src/resources/fonts/Nunito-LightItalic.ttf
new file mode 100644
index 0000000..8dbb8dc
Binary files /dev/null and b/src/resources/fonts/Nunito-LightItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-Regular.ttf b/src/resources/fonts/Nunito-Regular.ttf
new file mode 100644
index 0000000..fb9a17a
Binary files /dev/null and b/src/resources/fonts/Nunito-Regular.ttf differ
diff --git a/src/resources/fonts/Nunito-RegularItalic.ttf b/src/resources/fonts/Nunito-RegularItalic.ttf
new file mode 100644
index 0000000..5f88353
Binary files /dev/null and b/src/resources/fonts/Nunito-RegularItalic.ttf differ
diff --git a/src/resources/fonts/Nunito-SemiBold.ttf b/src/resources/fonts/Nunito-SemiBold.ttf
new file mode 100644
index 0000000..bd39ecf
Binary files /dev/null and b/src/resources/fonts/Nunito-SemiBold.ttf differ
diff --git a/src/resources/fonts/Nunito-SemiBoldItalic.ttf b/src/resources/fonts/Nunito-SemiBoldItalic.ttf
new file mode 100644
index 0000000..d5d3dec
Binary files /dev/null and b/src/resources/fonts/Nunito-SemiBoldItalic.ttf differ
Color
- */
- @Override
- public void setBackground(Color bg) {
- super.setBackground(bg);
- setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.DARK_BLACK);
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- Graphics2D g2 = (Graphics2D) g;
- elevation.paint(g);
- g.setClip(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP,
- getWidth() - MaterialShadow.OFFSET_LEFT - MaterialShadow.OFFSET_RIGHT,
- getHeight() - MaterialShadow.OFFSET_TOP - MaterialShadow.OFFSET_BOTTOM);
- super.paintComponent(g2);
- g.setClip(null);
- }
-}
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+
+/**
+ * A JPanel customized for Material components. What makes these panels special
+ * is the possibility of assigning them an elevation level. Elevation can help
+ * distinguishing elements inside a Material-based GUI, and any changes done to
+ * them result in nicely animated transitions, helping to achieve that Material
+ * flow.
+ *
+ * However, there is a catch: shadows are kinda expensive to compute, as Java2D
+ * relies on the CPU for anything other than images, so having a lot of elements
+ * with a given elevation (and thus, a shadow) can reduce performance when these
+ * elevations change due to the triggered animations.
+ *
+ * Letting the components suggest a prefered size based on their contents is
+ * still under development, so it is not advised to use your favorite
+ * {@link LayoutManager} inside a {@code MaterialPanel} unless you set the
+ * prefered, minimum and maximum size of each component by yourself. Currently,
+ * the prefereable approach to follow is overriding {@link #doLayout()} and
+ * taking care of any arrangements by yourself.
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class MPanel extends JPanel {
+
+ private final ElevationEffect elevation;
+
+ /**
+ * Creates a new {@code MaterialPanel}. These panels cast a shadow below
+ * them, although technically it is painted inside its borders. If you don't
+ * need a shadow to be casted from this panel, use a {@link JPanel} instead.
+ */
+ public MPanel() {
+ elevation = ElevationEffect.applyTo(this, 1);
+ setBorder(new EmptyBorder(MaterialShadow.OFFSET_TOP, MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_BOTTOM, MaterialShadow.OFFSET_RIGHT));
+ }
+
+ /**
+ * Gets the elevation level of this panel. Changes in elevation trigger an
+ * animated transition if the component is currently visible, so it is
+ * incorrect to assume the returned value will reflect how the resulting
+ * shadow looks right now.
+ *
+ * @return elevation level [0~5]
+ * @see ElevationEffect
+ */
+ public double getElevation() {
+ return elevation.getLevel();
+ }
+
+ /**
+ * Sets the elevation level of this panel. Changes in elevation trigger an
+ * animated transition if the component is currently visible, so it will
+ * take a little while for the resulting shadow to reflect the level once it
+ * is set.
+ *
+ * @param elevation elevation level [0~5]
+ * @see ElevationEffect
+ */
+ public void setElevation(int elevation) {
+ this.elevation.setLevel(elevation);
+ }
+
+ /**
+ * Sets the background color of this panel. Keep on mind that setting a
+ * background color in a Material component like this will also set the
+ * foreground color to either white or black, depending of how bright or
+ * dark is the chosen background color.
+ *
+ * NOTE: It is up to the look and feel to honor this property, some
+ * may choose to ignore it. To avoid any conflicts, using the
+ *
+ * Metal Look and Feel is recommended.
+ *
+ * @param bg the desired background Color
+ */
+ @Override
+ public void setBackground(Color bg) {
+ super.setBackground(bg);
+ setForeground(MaterialUtils.isDark(bg) ? MaterialColor.WHITE : MaterialColor.DARK_BLACK);
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ elevation.paint(g);
+ g.setClip(MaterialShadow.OFFSET_LEFT, MaterialShadow.OFFSET_TOP,
+ getWidth() - MaterialShadow.OFFSET_LEFT - MaterialShadow.OFFSET_RIGHT,
+ getHeight() - MaterialShadow.OFFSET_TOP - MaterialShadow.OFFSET_BOTTOM);
+ super.paintComponent(g2);
+ g.setClip(null);
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MPasswordField.java b/src/com/hq/swingmaterialdesign/materialdesign/MPasswordField.java
new file mode 100644
index 0000000..c844dd0
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MPasswordField.java
@@ -0,0 +1,172 @@
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
+import com.hq.swingmaterialdesign.materialdesign.resource.Roboto;
+
+import javax.swing.*;
+import javax.swing.text.DefaultCaret;
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * A material design password text field
+ *
+ *
+ * @author abner (abner.js05@gmail.com)
+ */
+public class MPasswordField extends JPasswordField {
+
+ public static final int HINT_OPACITY_MASK = 0x99000000;
+ public static final int LINE_OPACITY_MASK = 0x66000000;
+
+ private final MaterialFloatingLabel hintLabel = new MaterialFloatingLabel(this);
+ private final MaterialLine line = new MaterialLine(this);
+
+ private Color accentColor = MaterialColor.CYAN_500;
+
+ /**
+ * Default constructor for {@code MaterialTextField}. A default model is
+ * created and the initial string is empty.
+ */
+ public MPasswordField() {
+ super();
+ setBorder(null);
+ setFont(Roboto.REGULAR.deriveFont(16f));
+ hintLabel.setText("");
+ setOpaque(false);
+ setBackground(MaterialColor.WHITE);
+
+ setCaret(new DefaultCaret() {
+ @Override
+ protected synchronized void damage(Rectangle r) {
+ MPasswordField.this.repaint(); //fix caret not being removed completely
+ }
+ });
+ getCaret().setBlinkRate(500);
+ }
+
+ /**
+ * Default constructor for {@code MaterialTextField}. A default model is
+ * created and the initial string is the one provided.
+ *
+ * @param text An starting value for this text field
+ */
+ public MPasswordField(String text) {
+ super.setText(text);
+ }
+
+
+
+ /**
+ * Gets the label text. The label will float above any contents input into
+ * this text field.
+ *
+ * @return the text being used in the textfield label
+ */
+ public String getLabel() {
+ return hintLabel.getText();
+ }
+
+ /**
+ * Sets the label text. The label text is displayed when this textfield is
+ * empty.
+ *
+ *
+ * @param label the text to use in the floating label
+ */
+ public void setLabel(String label) {
+ hintLabel.setText(label);
+ repaint();
+ }
+
+ /**
+ * Gets the color the label changes to when this {@code materialTextField}
+ * is focused.
+ *
+ * @return the {@code "Color"} currently in use for accent. The default
+ * value is {@link MaterialColor#CYAN_300}.
+ */
+ public Color getAccent() {
+ return accentColor;
+ }
+
+ /**
+ * Sets the color the label changes to when this {@code materialTextField}
+ * is focused. The default value is {@link MaterialColor#CYAN_300}.
+ *
+ * @param accentColor the {@code "Color"} that should be used for accent.
+ */
+ public void setAccent(Color accentColor) {
+ this.accentColor = accentColor;
+ hintLabel.setAccent(accentColor);
+ }
+
+ @Override
+ public void setForeground(Color fg) {
+ super.setForeground(fg);
+ if (hintLabel != null) {
+ hintLabel.updateForeground();
+ }
+ }
+
+ @Override
+ public void setText(String string) {
+ super.setText(string);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent e) {
+ super.processFocusEvent(e);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void processKeyEvent(KeyEvent e) {
+ super.processKeyEvent(e);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ // paint text baground
+ g2.setColor(getBackground());
+ g2.fillRect(0, (getHeight() / 2) - 4, getWidth(), getHeight() / 2);
+
+ g2.translate(0, 9);
+ super.paintComponent(g);
+ g2.translate(0, -9);
+
+ // hint label in text
+ if (!getLabel().isEmpty() && getText().isEmpty() && (getLabel().isEmpty() || isFocusOwner())) {
+ g.setFont(Roboto.REGULAR.deriveFont(16f));
+ g2.setColor(MaterialUtils.applyAlphaMask(getForeground(), HINT_OPACITY_MASK));
+ FontMetrics metrics = g.getFontMetrics(g.getFont());
+ g.drawString(getLabel(), 0, metrics.getAscent() + getHeight() / 2);
+ }
+
+ // paint hint label
+ hintLabel.paint(g2);
+
+ // paint line under text
+ g2.setColor(MaterialUtils.applyAlphaMask(getForeground(), LINE_OPACITY_MASK));
+ g2.fillRect(0, getHeight() - 4, getWidth(), 1);
+
+ // paint animated line under text
+ g2.setColor(accentColor);
+ g2.fillRect((int) ((getWidth() - line.getWidth()) / 2), getHeight() - 5, (int) line.getWidth(), 2);
+ }
+
+ @Override
+ protected void paintBorder(Graphics g) {
+ //intentionally left blank
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MTextField.java b/src/com/hq/swingmaterialdesign/materialdesign/MTextField.java
new file mode 100644
index 0000000..780f8a1
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MTextField.java
@@ -0,0 +1,173 @@
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
+import com.hq.swingmaterialdesign.materialdesign.resource.Roboto;
+
+import javax.swing.*;
+import javax.swing.text.DefaultCaret;
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+
+/**
+ * A Material Design single-line text field is the basic way of getting user
+ * input. It includes a descriptive label that appears as a placeholder and then
+ * floats above the text field as content is written. You can also set a hint
+ * for it to appear below the label when the text field is empty.
+ *
+ *
+ * @author bilux (i.bilux@gmail.com)
+ */
+public class MTextField extends JTextField {
+
+ public static final int HINT_OPACITY_MASK = 0x99000000;
+ public static final int LINE_OPACITY_MASK = 0x66000000;
+
+ private final MaterialFloatingLabel hintLabel = new MaterialFloatingLabel(this);
+ private final MaterialLine line = new MaterialLine(this);
+
+ private Color accentColor = MaterialColor.CYAN_500;
+
+ /**
+ * Default constructor for {@code MaterialTextField}. A default model is
+ * created and the initial string is empty.
+ */
+ public MTextField() {
+ super();
+ setBorder(null);
+ setFont(Roboto.REGULAR.deriveFont(16f));
+ hintLabel.setText("");
+ setOpaque(false);
+ setBackground(MaterialColor.WHITE);
+
+ setCaret(new DefaultCaret() {
+ @Override
+ protected synchronized void damage(Rectangle r) {
+ MTextField.this.repaint(); //fix caret not being removed completely
+ }
+ });
+ getCaret().setBlinkRate(500);
+ }
+
+ /**
+ * Default constructor for {@code MaterialTextField}. A default model is
+ * created and the initial string is the one provided.
+ *
+ * @param text An starting value for this text field
+ */
+ public MTextField(String text) {
+ super.setText(text);
+ }
+
+ /**
+ * Gets the label text. The label will float above any contents input into
+ * this text field.
+ *
+ * @return the text being used in the textfield label
+ */
+ public String getLabel() {
+ return hintLabel.getText();
+ }
+
+ /**
+ * Sets the label text. The label text is displayed when this textfield is
+ * empty.
+ *
+ *
+ * @param label the text to use in the floating label
+ */
+ public void setLabel(String label) {
+ hintLabel.setText(label);
+ repaint();
+ }
+
+ /**
+ * Gets the color the label changes to when this {@code materialTextField}
+ * is focused.
+ *
+ * @return the {@code "Color"} currently in use for accent. The default
+ * value is {@link MaterialColor#CYAN_300}.
+ */
+ public Color getAccent() {
+ return accentColor;
+ }
+
+ /**
+ * Sets the color the label changes to when this {@code materialTextField}
+ * is focused. The default value is {@link MaterialColor#CYAN_300}.
+ *
+ * @param accentColor the {@code "Color"} that should be used for accent.
+ */
+ public void setAccent(Color accentColor) {
+ this.accentColor = accentColor;
+ hintLabel.setAccent(accentColor);
+ }
+
+ @Override
+ public void setForeground(Color fg) {
+ super.setForeground(fg);
+ if (hintLabel != null) {
+ hintLabel.updateForeground();
+ }
+ }
+
+ @Override
+ public void setText(String string) {
+ super.setText(string);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void processFocusEvent(FocusEvent e) {
+ super.processFocusEvent(e);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void processKeyEvent(KeyEvent e) {
+ super.processKeyEvent(e);
+ hintLabel.update();
+ line.update();
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ // paint text baground
+ g2.setColor(getBackground());
+ g2.fillRect(0, (getHeight() / 2) - 4, getWidth(), getHeight() / 2);
+
+ g2.translate(0, 9);
+ super.paintComponent(g);
+ g2.translate(0, -9);
+
+ // hint label in text
+ if (!getLabel().isEmpty() && getText().isEmpty() && (getLabel().isEmpty() || isFocusOwner())) {
+ g.setFont(Roboto.REGULAR.deriveFont(16f));
+ g2.setColor(MaterialUtils.applyAlphaMask(getForeground(), HINT_OPACITY_MASK));
+ FontMetrics metrics = g.getFontMetrics(g.getFont());
+ g.drawString(getLabel(), 0, metrics.getAscent() + getHeight() / 2);
+ }
+
+ // paint hint label
+ hintLabel.paint(g2);
+
+ // paint line under text
+ g2.setColor(MaterialUtils.applyAlphaMask(getForeground(), LINE_OPACITY_MASK));
+ g2.fillRect(0, getHeight() - 4, getWidth(), 1);
+
+ // paint animated line under text
+ g2.setColor(accentColor);
+ g2.fillRect((int) ((getWidth() - line.getWidth()) / 2), getHeight() - 5, (int) line.getWidth(), 2);
+ }
+
+ @Override
+ protected void paintBorder(Graphics g) {
+ //intentionally left blank
+ }
+}
diff --git a/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton.java b/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton.java
new file mode 100644
index 0000000..6b63932
--- /dev/null
+++ b/src/com/hq/swingmaterialdesign/materialdesign/MToggleButton.java
@@ -0,0 +1,391 @@
+package com.hq.swingmaterialdesign.materialdesign;
+
+import com.hq.swingmaterialdesign.materialdesign.resource.MaterialColor;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import javax.swing.JButton;
+import javax.swing.plaf.basic.BasicButtonUI;
+import java.awt.event.FocusEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RoundRectangle2D;
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+
+/**
+ * A material design button.
+ *
+ *
+ * @author abner (abner.js05@gmail.com)
+ */
+public class MToggleButton extends JButton {
+
+ private RippleEffect ripple;
+ private Type type = Type.DEFAULT;
+ private boolean isMousePressed = false;
+ private boolean isMouseOver = false;
+ private Color rippleColor = Color.WHITE;
+ private Cursor cursor = super.getCursor();
+ private int borderRadius = 2;
+ private Color startColor = new Color(0, 153, 153);
+ private Color endColor = Color.GREEN;
+ private Color hoverStartColor = new Color(255, 0, 255);
+ private Color hoverEndColor = Color.green;
+ private int indicatorThickness = 2;
+ private Color indicatorColor = Color.white;
+ private Color selectedColor = Color.green;
+ private boolean allowTab = true;
+
+ /**
+ * Creates a new button.
+ */
+ public MToggleButton() {
+ ripple = RippleEffect.applyTo(this);
+ setOpaque(false);
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent mouseEvent) {
+ isMousePressed = true;
+ getStyle();
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent mouseEvent) {
+ isMousePressed = false;
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ isMouseOver = true;
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ isMouseOver = false;
+ }
+ });
+
+ setUI(new BasicButtonUI() {
+ @Override
+ public boolean contains(JComponent c, int x, int y) {
+ return x > MaterialShadow.OFFSET_LEFT && y > MaterialShadow.OFFSET_TOP
+ && x < getWidth() - MaterialShadow.OFFSET_RIGHT && y < getHeight() - MaterialShadow.OFFSET_BOTTOM;
+ }
+ });
+ }
+
+ /**
+ * Gets the type of this button.
+ *
+ * @return the type of this button
+ * @see Type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Sets the type of this button.
+ *
+ * @param type the type of this button
+ * @see Type
+ */
+ public void setType(Type type) {
+ this.type = type;
+ repaint();
+ }
+
+ /**
+ * Sets the background color of this button.
+ *