diff --git a/src/main/java/org/openautonomousconnection/oacswing/border/RoundedBorder.java b/src/main/java/org/openautonomousconnection/oacswing/border/RoundedBorder.java new file mode 100644 index 0000000..04e5578 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/oacswing/border/RoundedBorder.java @@ -0,0 +1,45 @@ +// Source - https://stackoverflow.com/a/3634480 +// Posted by Lalchand, modified by community. See post 'Timeline' for change history +// Retrieved 2026-02-08, License - CC BY-SA 3.0 + +package org.openautonomousconnection.oacswing.border; + +import lombok.Getter; + +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; +import java.awt.*; + +@Getter +public class RoundedBorder extends AbstractBorder { + + private int radius; + private Color color; + + public RoundedBorder(int radius, Color color) { + this.radius = radius; + this.color = color; + } + + + public Insets getBorderInsets( Component c, Insets insets ) { + insets.left = insets.top = insets.right = insets.bottom = 18; + return insets; + } + + public boolean isBorderOpaque() { + return true; + } + + + public void paintBorder( Component c, Graphics g, int x, int y, + int width, int height) { + int w = width; + int h = height; + + g.translate(x, y); + g.setColor( c.getBackground().darker() ); + g.drawRoundRect( 0, 0, w-2, h-2, 8, 8 ); + g.translate(-x, -y); + } +} \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java index ac0fef3..c2070df 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java @@ -4,33 +4,89 @@ package org.openautonomousconnection.oacswing.component; +import lombok.Getter; import lombok.NonNull; +import lombok.Setter; import org.openautonomousconnection.oacswing.component.design.Design; +import org.openautonomousconnection.oacswing.component.design.OACColor; import javax.swing.*; import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.beans.ConstructorProperties; -public class OACButton extends JButton implements OACComponent { +public class OACButton extends JButton implements OACPressable { + @Getter @Setter + protected Color pressColor = null; + + protected Color previousColor = null; + public OACButton() { super(null, null); + + this.init(); } - public OACButton(Design design, Icon icon) { + public OACButton(Icon icon) { super(null, icon); + + this.init(); } @ConstructorProperties({"text"}) public OACButton(String text) { super(text, null); + + this.init(); } public OACButton(Action a) { super(a); + + this.init(); } public OACButton(String text, Icon icon) { super(text, icon); + + this.init(); + } + + protected void init() { + this.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + previousColor = getBackground(); + + if(pressColor != null) + setBackground(pressColor); + + super.mousePressed(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + setBackground(previousColor); + + super.mouseReleased(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + //TODO: Hover + + super.mouseEntered(e); + } + + @Override + public void mouseExited(MouseEvent e) { + //TODO: Hover + + super.mouseExited(e); + } + + }); } @Override diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACPressable.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACPressable.java new file mode 100644 index 0000000..746693c --- /dev/null +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACPressable.java @@ -0,0 +1,12 @@ +package org.openautonomousconnection.oacswing.component; + +import org.openautonomousconnection.oacswing.component.design.OACColor; + +import java.awt.*; + +public interface OACPressable extends OACComponent { + + Color getPressColor(); + + void setPressColor(Color color); +} diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/design/Design.java b/src/main/java/org/openautonomousconnection/oacswing/component/design/Design.java index d950be5..2fe0fb0 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/design/Design.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/design/Design.java @@ -14,31 +14,36 @@ import java.util.Map; import java.util.Objects; public final class Design { - public static final Design LIGHT = new Design("light", new HashMap<>()); + public static final Design LIGHT = new Design("light", new HashMap<>(), OACColor.DARK_TEXT); - public static final Design DARK = new Design("dark", new HashMap<>()); + public static final Design DARK = new Design("dark", new HashMap<>(), OACColor.DARK_TEXT); - public static final Design CONTRAST = new Design("contrast", new HashMap<>()); + public static final Design CONTRAST = new Design("contrast", new HashMap<>(), OACColor.DARK_TEXT); @Getter private final String name; @Getter - private final Map, OACColor> elements; + private final Map, DesignFlags> elements; + + @Getter + private final OACColor foregroundColour; @Getter protected Border border; - public Design(String name, Map, OACColor> elements, @NonNull Border border) { + public Design(String name, Map, DesignFlags> elements, @NonNull Border border, @NonNull OACColor foregroundColour) { this.name = name; this.elements = elements; this.border = border; + this.foregroundColour = foregroundColour; } - private Design(String name, Map, OACColor> elements) { + private Design(String name, Map, DesignFlags> elements, OACColor foregroundColour) { this.name = name; this.elements = elements; this.border = null; + this.foregroundColour = foregroundColour; } diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignFlags.java b/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignFlags.java new file mode 100644 index 0000000..7d26b58 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignFlags.java @@ -0,0 +1,19 @@ +package org.openautonomousconnection.oacswing.component.design; + +public record DesignFlags(OACColor background, OACColor foreground, OACColor pressed, OACColor hovered, boolean hasBorder) { + public DesignFlags(OACColor background) { + this(background, null, null, null, false); + } + + public DesignFlags(OACColor background, OACColor foreground) { + this(background, foreground, null, null, false); + } + + public DesignFlags(OACColor background, boolean hasBorder) { + this(background, null, null, null, hasBorder); + } + + public DesignFlags(OACColor background, OACColor foreground, boolean hasBorder) { + this(background, foreground, null, null, hasBorder); + } +} diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java b/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java index 7ce9142..4c45c39 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java @@ -6,12 +6,11 @@ package org.openautonomousconnection.oacswing.component.design; import lombok.Getter; import lombok.Setter; +import org.openautonomousconnection.oacswing.border.RoundedBorder; import org.openautonomousconnection.oacswing.component.*; import javax.swing.*; -import javax.swing.border.BevelBorder; import javax.swing.border.Border; -import javax.swing.border.LineBorder; import java.awt.*; import java.util.ArrayList; import java.util.List; @@ -40,22 +39,52 @@ public class DesignManager { if(globalDesign == null) return; - OACColor backgroundColour = globalDesign.getElements().get(component.getClass()); + DesignFlags designFlags = globalDesign.getElements().get(component.getClass()); + + if(designFlags == null) + return; + + OACColor backgroundColour = designFlags.background(); + OACColor foregroundColour = designFlags.foreground(); + + OACColor hovered = designFlags.hovered(); + OACColor pressed = designFlags.pressed(); + + boolean hasBorder = designFlags.hasBorder(); + Border border = globalDesign.getBorder(); if(backgroundColour == null) - return; + throw new NullPointerException("Background color cannot be null; please exclude the component from your design instead"); component.setBackground(backgroundColour.getColor()); - if(component instanceof JComponent jComponent) - jComponent.setBorder(border); + + if(component instanceof OACPressable pressable) { + // TODO: if(hovered != null) + + if(pressed != null) + pressable.setPressColor(pressed.getColor()); + } + + if(component instanceof JComponent jComponent) { + if(foregroundColour != null) + jComponent.setForeground(foregroundColour.getColor()); + + if (hasBorder) + jComponent.setBorder(BorderFactory.createCompoundBorder(border, jComponent.getBorder())); + } } public static void apply(OACFrame frame) { - OACColor color; + DesignFlags designFlags; - if(globalDesign != null && ((color = globalDesign.getElements().get(frame.getClass())) != null)) - frame.getContentPane().setBackground(color.getColor()); + if(globalDesign != null && ((designFlags = globalDesign.getElements().get(frame.getClass())) != null)) { + if(designFlags.hasBorder()) + frame.getRootPane().setBorder(globalDesign.border); + + frame.getContentPane().setBackground(designFlags.background().getColor()); + + } } @@ -64,7 +93,7 @@ public class DesignManager { this.designs.add(design); } - public void registerComponent(Class componentClass, OACColor color) { + public void registerComponent(Class componentClass, DesignFlags flags) { Style.Design eDesign = Style.Design.DARK; if(componentClass.isAnnotationPresent(Style.class)) @@ -78,31 +107,31 @@ public class DesignManager { design.getElements().putIfAbsent(componentClass, null); - design.getElements().replace(componentClass, color); + design.getElements().replace(componentClass, flags); } static { - Design.DARK.getElements().put(OACButton.class, OACColor.DARK_BUTTON); - Design.DARK.getElements().put(OACCheckBox.class, OACColor.DARK_INPUT_FIELD); - Design.DARK.getElements().put(OACCheckBoxMenuItem.class, OACColor.DARK_ITEM); - Design.DARK.getElements().put(OACColorChooser.class, OACColor.DARK_SECTION); - Design.DARK.getElements().put(OACComboBox.class, OACColor.DARK_INPUT_FIELD); - Design.DARK.getElements().put(OACFrame.class, OACColor.DARK_BACKGROUND); - Design.DARK.getElements().put(OACLabel.class, OACColor.DARK_TEXT); - Design.DARK.getElements().put(OACLayeredPane.class, OACColor.DARK_BACKGROUND); - Design.DARK.getElements().put(OACList.class, OACColor.DARK_SECTION); - Design.DARK.getElements().put(OACMenu.class, OACColor.DARK_INPUT_BUTTON); - Design.DARK.getElements().put(OACMenuBar.class, OACColor.DARK_SECTION); - Design.DARK.getElements().put(OACMenuItem.class, OACColor.DARK_ITEM); - Design.DARK.getElements().put(OACOptionPane.class, OACColor.DARK_BACKGROUND); - Design.DARK.getElements().put(OACPanel.class, OACColor.DARK_BACKGROUND); - Design.DARK.getElements().put(OACPasswordField.class, OACColor.DARK_INPUT_FIELD); - Design.DARK.getElements().put(OACPopupMenu.class, OACColor.DARK_BACKGROUND); - Design.DARK.getElements().put(OACProgressBar.class, OACColor.DARK_ITEM); - Design.DARK.getElements().put(OACRadioButton.class, OACColor.DARK_BUTTON); - Design.DARK.getElements().put(OACTitleBar.class, OACColor.DARK_SECTION); + Design.DARK.getElements().put(OACButton.class, new DesignFlags(OACColor.DARK_BUTTON, OACColor.DARK_TEXT, OACColor.DARK_BUTTON_HOVER, OACColor.DARK_BUTTON_HOVER, true)); + Design.DARK.getElements().put(OACCheckBox.class, new DesignFlags(OACColor.DARK_INPUT_FIELD)); + Design.DARK.getElements().put(OACCheckBoxMenuItem.class, new DesignFlags(OACColor.DARK_ITEM)); + Design.DARK.getElements().put(OACColorChooser.class, new DesignFlags(OACColor.DARK_SECTION)); + Design.DARK.getElements().put(OACComboBox.class, new DesignFlags(OACColor.DARK_INPUT_FIELD)); + Design.DARK.getElements().put(OACFrame.class, new DesignFlags(OACColor.DARK_BACKGROUND)); + Design.DARK.getElements().put(OACLabel.class, new DesignFlags(OACColor.DARK_TEXT)); + Design.DARK.getElements().put(OACLayeredPane.class, new DesignFlags(OACColor.DARK_BACKGROUND)); + Design.DARK.getElements().put(OACList.class, new DesignFlags(OACColor.DARK_SECTION)); + Design.DARK.getElements().put(OACMenu.class, new DesignFlags(OACColor.DARK_INPUT_BUTTON)); + Design.DARK.getElements().put(OACMenuBar.class, new DesignFlags(OACColor.DARK_SECTION)); + Design.DARK.getElements().put(OACMenuItem.class, new DesignFlags(OACColor.DARK_ITEM)); + Design.DARK.getElements().put(OACOptionPane.class, new DesignFlags(OACColor.DARK_BACKGROUND)); + Design.DARK.getElements().put(OACPanel.class, new DesignFlags(OACColor.DARK_BACKGROUND, true)); + Design.DARK.getElements().put(OACPasswordField.class, new DesignFlags(OACColor.DARK_INPUT_FIELD)); + Design.DARK.getElements().put(OACPopupMenu.class, new DesignFlags(OACColor.DARK_BACKGROUND)); + Design.DARK.getElements().put(OACProgressBar.class, new DesignFlags(OACColor.DARK_ITEM)); + Design.DARK.getElements().put(OACRadioButton.class, new DesignFlags(OACColor.DARK_BUTTON)); + Design.DARK.getElements().put(OACTitleBar.class, new DesignFlags(OACColor.DARK_SECTION)); - Design.DARK.border = new LineBorder(OACColor.DARK_BORDERS.getColor(), 1); + Design.DARK.border = new RoundedBorder(10, OACColor.DARK_BORDERS.getColor()); //Design.DARK.border = new BevelBorder(BevelBorder.LOWERED, OACColor.DARK_BORDERS.getColor(), OACColor.DARK_SHADOW.getColor()); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/design/OACColor.java b/src/main/java/org/openautonomousconnection/oacswing/component/design/OACColor.java index 65eb2f0..f5cc4a2 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/design/OACColor.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/design/OACColor.java @@ -17,7 +17,8 @@ public enum OACColor { DARK_INPUT_BUTTON_HOVER(Color.decode("#1c2140")), DARK_ITEM(Color.decode("#d7dbe5")), DARK_BORDERS(Color.decode("#2a2f42")), - DARK_BUTTON(Color.decode("#151a2b")), + DARK_BUTTON(Color.decode("#3b5bdb")), + DARK_INACTIVE_BUTTON(Color.decode("#151a2b")), DARK_BUTTON_HOVER(Color.decode("#151a2b")), DARK_TEXT(Color.decode("#cfd3dc")), DARK_SUBTITLE(Color.decode("#9aa0aa")),