diff --git a/pom.xml b/pom.xml index 542bdd9..f7a73de 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.openautonomousconnection OACSwing - 1.0.0-BETA.1.0 + 1.0.0-BETA.1.1 Open Autonomous Connection https://open-autonomous-connection.org/ diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java index 84dfb29..8ef7699 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACButton.java @@ -81,6 +81,7 @@ public class OACButton extends JButton implements OACPressable { setContentAreaFilled(false); setOpaque(false); setFocusPainted(false); + setBorderPainted(false); if (!isEnabled() && getDisabledColor() != null) { super.setBackground(getDisabledColor()); @@ -182,4 +183,4 @@ public class OACButton extends JButton implements OACPressable { g2.dispose(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACFrame.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACFrame.java index c97da88..a5b4584 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACFrame.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACFrame.java @@ -3,6 +3,8 @@ package org.openautonomousconnection.oacswing.component; import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; import java.awt.*; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; @@ -64,6 +66,7 @@ public class OACFrame extends JFrame { setBackground(new Color(0, 0, 0, 1)); roundedRoot.setLayout(new BorderLayout()); + roundedRoot.setBorder(new EmptyBorder(TITLE_BAR_HEIGHT, 0, 0, 0)); setContentPane(roundedRoot); titleBar = new OACTitleBar(this); @@ -79,16 +82,20 @@ public class OACFrame extends JFrame { @Override public void componentResized(ComponentEvent e) { titleRoot.setBounds(0, 0, getWidth(), TITLE_BAR_HEIGHT); + updateWindowChrome(); roundedRoot.repaint(); } @Override public void componentShown(ComponentEvent e) { titleRoot.setBounds(0, 0, getWidth(), TITLE_BAR_HEIGHT); + updateWindowChrome(); roundedRoot.repaint(); } }); + addWindowStateListener(e -> updateWindowChrome()); + setSize(900, 600); SwingUtilities.invokeLater(() -> { @@ -99,6 +106,7 @@ public class OACFrame extends JFrame { installResizeHandling(); DesignManager.apply(this); + updateWindowChrome(); } @Override @@ -142,18 +150,29 @@ public class OACFrame extends JFrame { MouseAdapter adapter = new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { + if (isInFullscreenState()) { + resizeCursor = Cursor.DEFAULT_CURSOR; + setCursor(Cursor.getDefaultCursor()); + return; + } resizeCursor = getResizeCursor(e); setCursor(Cursor.getPredefinedCursor(resizeCursor)); } @Override public void mousePressed(MouseEvent e) { + if (isInFullscreenState()) { + dragStart = null; + startBounds = null; + return; + } dragStart = e.getLocationOnScreen(); startBounds = getBounds(); } @Override public void mouseDragged(MouseEvent e) { + if (isInFullscreenState()) return; if (resizeCursor == Cursor.DEFAULT_CURSOR) return; Point dragNow = e.getLocationOnScreen(); @@ -207,6 +226,10 @@ public class OACFrame extends JFrame { } private int getResizeCursor(MouseEvent e) { + if (isInFullscreenState()) { + return Cursor.DEFAULT_CURSOR; + } + int x = e.getX(); int y = e.getY(); int w = e.getComponent().getWidth(); @@ -229,13 +252,29 @@ public class OACFrame extends JFrame { return Cursor.DEFAULT_CURSOR; } + private boolean isInFullscreenState() { + return (getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH; + } + /** * Root panel that paints a near-transparent full-window layer (alpha=1) * to prevent click-through, then paints the rounded background and clips children. */ + private void updateWindowChrome() { + boolean fullscreen = isInFullscreenState(); + roundedRoot.setArc(fullscreen ? 0 : CORNER_ARC); + if (fullscreen) { + getRootPane().setBorder(new LineBorder(DesignManager.resolveBorderColor(Color.GRAY), 1)); + setCursor(Cursor.getDefaultCursor()); + } else { + getRootPane().setBorder(new EmptyBorder(0, 0, 0, 0)); + } + repaint(); + } + private static final class RoundedRootPanel extends OACPanel { - private final int arc; + private int arc; private RoundedRootPanel(int arc) { super(new BorderLayout()); @@ -243,6 +282,10 @@ public class OACFrame extends JFrame { setOpaque(false); } + private void setArc(int arc) { + this.arc = Math.max(0, arc); + } + @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g.create(); @@ -292,4 +335,4 @@ public class OACFrame extends JFrame { } } } -} \ No newline at end of file +} diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACOptionPane.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACOptionPane.java index a4bd9aa..519b407 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACOptionPane.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACOptionPane.java @@ -5,9 +5,14 @@ package org.openautonomousconnection.oacswing.component; import lombok.NonNull; +import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; +import javax.swing.border.EmptyBorder; import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.atomic.AtomicInteger; public class OACOptionPane extends JOptionPane implements OACComponent { public OACOptionPane() { @@ -38,6 +43,140 @@ public class OACOptionPane extends JOptionPane implements OACComponent { super(message, messageType, optionType, icon, options, initialValue); } + @Override + public void init() { + setOpaque(true); + setBackground(DesignManager.resolveBackground(OACOptionPane.class, getBackground())); + setForeground(DesignManager.resolveForeground(OACOptionPane.class, getForeground())); + } + + public static int showOptionDialog(Component parentComponent, + Object message, + String title, + int optionType, + int messageType, + Icon icon, + Object[] options, + Object initialValue) throws HeadlessException { + AtomicInteger result = new AtomicInteger(CLOSED_OPTION); + OACDialog dialog = new OACDialog(JOptionPane.getFrameForComponent(parentComponent), title, true); + dialog.setUndecorated(true); + dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + dialog.setContentPane(buildDialogContent(title, message, icon, optionType, options, result, dialog)); + dialog.setResizable(false); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + result.set(CLOSED_OPTION); + } + }); + dialog.pack(); + dialog.setMinimumSize(new Dimension(420, dialog.getHeight())); + dialog.setLocationRelativeTo(parentComponent); + dialog.setVisible(true); + dialog.dispose(); + return result.get(); + } + + private static Container buildDialogContent(String title, + Object message, + Icon icon, + int optionType, + Object[] options, + AtomicInteger result, + OACDialog dialog) { + OACPanel root = new OACPanel(new BorderLayout()); + Color background = DesignManager.resolveBackground(OACOptionPane.class, root.getBackground()); + Color headerBackground = DesignManager.resolveBackground(OACTitleBar.class, background.darker()); + Color foreground = DesignManager.resolveForeground(OACOptionPane.class, Color.LIGHT_GRAY); + Color borderColor = DesignManager.resolveBorderColor(foreground.darker()); + + root.setBackground(background); + root.setBorder(BorderFactory.createLineBorder(borderColor, 1)); + + OACPanel header = new OACPanel(new BorderLayout()); + header.setBorder(new EmptyBorder(10, 12, 10, 12)); + header.setBackground(headerBackground); + JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL); + separator.setForeground(borderColor); + separator.setBackground(borderColor); + header.add(separator, BorderLayout.SOUTH); + + OACLabel titleLabel = new OACLabel(title == null ? "" : title); + titleLabel.setForeground(foreground); + header.add(titleLabel, BorderLayout.WEST); + + OACPanel center = new OACPanel(new BorderLayout(10, 0)); + center.setBackground(background); + center.setBorder(new EmptyBorder(14, 12, 12, 12)); + + if (icon != null) { + OACLabel iconLabel = new OACLabel(icon); + iconLabel.setForeground(foreground); + center.add(iconLabel, BorderLayout.WEST); + } + + JTextArea messageArea = new JTextArea(String.valueOf(message)); + messageArea.setEditable(false); + messageArea.setLineWrap(true); + messageArea.setWrapStyleWord(true); + messageArea.setOpaque(false); + messageArea.setForeground(foreground); + messageArea.setBorder(null); + center.add(messageArea, BorderLayout.CENTER); + + OACPanel buttons = new OACPanel(new FlowLayout(FlowLayout.RIGHT, 8, 8)); + buttons.setBackground(background); + + Object[] displayOptions = resolveOptions(optionType, options); + for (int i = 0; i < displayOptions.length; i++) { + final int index = i; + OACButton button = new OACButton(String.valueOf(displayOptions[i])); + button.initDesign(); + button.setBackground(DesignManager.resolveBackground(OACButton.class, button.getBackground())); + button.setForeground(DesignManager.resolveForeground(OACButton.class, button.getForeground())); + button.setHoveredColor(DesignManager.resolveHovered(OACButton.class, button.getBackground().brighter())); + button.setPressedColor(DesignManager.resolvePressed(OACButton.class, button.getBackground().darker())); + button.setBorder(BorderFactory.createLineBorder(borderColor, 1, true)); + button.setPreferredSize(new Dimension(100, 32)); + button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + button.addActionListener(e -> { + result.set(mapResult(optionType, options, index)); + dialog.dispose(); + }); + buttons.add(button); + } + + root.add(header, BorderLayout.NORTH); + root.add(center, BorderLayout.CENTER); + root.add(buttons, BorderLayout.SOUTH); + return root; + } + + private static Object[] resolveOptions(int optionType, Object[] options) { + if (options != null && options.length > 0) { + return options; + } + return switch (optionType) { + case YES_NO_OPTION -> new Object[]{"Yes", "No"}; + case YES_NO_CANCEL_OPTION -> new Object[]{"Yes", "No", "Cancel"}; + case OK_CANCEL_OPTION -> new Object[]{"OK", "Cancel"}; + default -> new Object[]{"OK"}; + }; + } + + private static int mapResult(int optionType, Object[] providedOptions, int clickedIndex) { + if (providedOptions != null && providedOptions.length > 0) { + return clickedIndex; + } + return switch (optionType) { + case YES_NO_OPTION -> clickedIndex == 0 ? YES_OPTION : NO_OPTION; + case YES_NO_CANCEL_OPTION -> clickedIndex == 0 ? YES_OPTION : (clickedIndex == 1 ? NO_OPTION : CANCEL_OPTION); + case OK_CANCEL_OPTION -> clickedIndex == 0 ? OK_OPTION : CANCEL_OPTION; + default -> OK_OPTION; + }; + } + @Override public Component add(Component comp) { this.initOther(comp); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACPasswordField.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACPasswordField.java index a236e1c..08da179 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACPasswordField.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACPasswordField.java @@ -5,8 +5,10 @@ package org.openautonomousconnection.oacswing.component; import lombok.NonNull; +import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.text.Document; import java.awt.*; @@ -31,6 +33,39 @@ public class OACPasswordField extends JPasswordField implements OACComponent { super(doc, txt, columns); } + @Override + public void init() { + setOpaque(true); + applyInputBorder(); + setCaretColor(getForeground()); + setSelectionColor(getForeground().darker()); + setSelectedTextColor(getBackground().brighter()); + setPreferredSize(new Dimension(Math.max(160, getPreferredSize().width), 34)); + } + + @Override + public void updateUI() { + super.updateUI(); + applyInputBorder(); + } + + private void applyInputBorder() { + setBorder(new EmptyBorder(6, 10, 6, 10)); + } + + @Override + protected void paintBorder(Graphics g) { + Graphics2D g2 = (Graphics2D) g.create(); + try { + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(DesignManager.resolveBorderColor(getForeground())); + g2.setStroke(new BasicStroke(2f)); + g2.drawRoundRect(1, 1, getWidth() - 3, getHeight() - 3, 10, 10); + } finally { + g2.dispose(); + } + } + @Override public Component add(Component comp) { this.initOther(comp); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextArea.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextArea.java index 12af7ee..d7ac742 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextArea.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextArea.java @@ -5,6 +5,7 @@ package org.openautonomousconnection.oacswing.component; import lombok.NonNull; +import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; import javax.swing.text.Document; @@ -35,6 +36,16 @@ public class OACTextArea extends JTextArea implements OACComponent { super(doc, text, rows, columns); } + @Override + public void init() { + setOpaque(true); + setMargin(new Insets(6, 10, 6, 10)); + setBorder(DesignManager.createTextComponentBorder()); + setCaretColor(getForeground()); + setSelectionColor(getForeground().darker()); + setSelectedTextColor(getBackground().brighter()); + } + @Override public Component add(Component comp) { this.initOther(comp); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextField.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextField.java index a1c7a33..0c6f5ef 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextField.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextField.java @@ -4,7 +4,12 @@ package org.openautonomousconnection.oacswing.component; +import org.openautonomousconnection.oacswing.border.RoundedBorder; +import org.openautonomousconnection.oacswing.component.design.DesignManager; + import javax.swing.*; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; import javax.swing.text.Document; import java.awt.*; @@ -29,6 +34,29 @@ public class OACTextField extends JTextField implements OACComponent { super(doc, text, columns); } + @Override + public void init() { + setOpaque(true); + applyInputBorder(); + setCaretColor(getForeground()); + setSelectionColor(getForeground().darker()); + setSelectedTextColor(getBackground().brighter()); + setPreferredSize(new Dimension(Math.max(160, getPreferredSize().width), 34)); + } + + @Override + public void updateUI() { + super.updateUI(); + applyInputBorder(); + } + + private void applyInputBorder() { + setBorder(new CompoundBorder( + new RoundedBorder(DesignManager.resolveBorderColor(getForeground()), 10, 2), + new EmptyBorder(6, 10, 6, 10) + )); + } + @Override public Component add(Component comp) { this.initOther(comp); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextPane.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextPane.java index 650c73f..3ef36fb 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACTextPane.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACTextPane.java @@ -5,6 +5,7 @@ package org.openautonomousconnection.oacswing.component; import lombok.NonNull; +import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; import javax.swing.text.StyledDocument; @@ -18,6 +19,16 @@ public class OACTextPane extends JTextPane implements OACComponent { super(doc); } + @Override + public void init() { + setOpaque(true); + setMargin(new Insets(6, 10, 6, 10)); + setBorder(DesignManager.createTextComponentBorder()); + setCaretColor(getForeground()); + setSelectionColor(getForeground().darker()); + setSelectedTextColor(getBackground().brighter()); + } + @Override public Component add(Component comp) { this.initOther(comp); diff --git a/src/main/java/org/openautonomousconnection/oacswing/component/OACTitleBar.java b/src/main/java/org/openautonomousconnection/oacswing/component/OACTitleBar.java index ea95e62..6e35a9e 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/OACTitleBar.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/OACTitleBar.java @@ -6,6 +6,7 @@ package org.openautonomousconnection.oacswing.component; import lombok.Getter; import lombok.Setter; +import org.openautonomousconnection.oacswing.component.design.DesignManager; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -39,6 +40,9 @@ public class OACTitleBar extends OACPanel { super(new BorderLayout()); this.frame = frame; + setOpaque(true); + setBackground(DesignManager.resolveBackground(OACTitleBar.class, getBackground())); + setForeground(DesignManager.resolveForeground(OACTitleBar.class, getForeground())); setPreferredSize(new Dimension(1, HEIGHT)); setBorder(new EmptyBorder(6, 10, 6, 10)); @@ -170,4 +174,4 @@ public class OACTitleBar extends OACPanel { frame.dispatchEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); } -} \ No newline at end of file +} 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 b335364..af7dbf9 100644 --- a/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java +++ b/src/main/java/org/openautonomousconnection/oacswing/component/design/DesignManager.java @@ -10,11 +10,23 @@ import org.openautonomousconnection.oacswing.border.RoundedBorder; import org.openautonomousconnection.oacswing.component.*; import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import javax.swing.text.JTextComponent; +import java.awt.*; +import java.awt.event.ContainerAdapter; +import java.awt.event.ContainerEvent; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class DesignManager { + private static final String OAC_INIT_PROPERTY = "oac.design.initialized"; + private static final String OAC_LISTENER_PROPERTY = "oac.design.listener"; + private static final Border INVISIBLE_BORDER = new EmptyBorder(0, 0, 0, 0); + @Getter @Setter private static Design globalDesign; @@ -27,13 +39,13 @@ public class DesignManager { OACColor.DARK_INPUT_BUTTON_HOVER, OACColor.DARK_INPUT_BUTTON_HOVER, OACColor.DARK_INACTIVE_BUTTON, - true + false )); 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(OACTextField.class, new DesignFlags(OACColor.DARK_ITEM, OACColor.DARK_TEXT)); - Design.DARK.getElements().put(OACTextArea.class, new DesignFlags(OACColor.DARK_ITEM, OACColor.DARK_TEXT)); + Design.DARK.getElements().put(OACTextField.class, new DesignFlags(OACColor.DARK_INPUT_FIELD, OACColor.DARK_TEXT)); + Design.DARK.getElements().put(OACTextArea.class, new DesignFlags(OACColor.DARK_INPUT_FIELD, OACColor.DARK_TEXT)); 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)); @@ -44,14 +56,16 @@ public class DesignManager { 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(OACPanel.class, new DesignFlags(OACColor.DARK_BACKGROUND, false)); + Design.DARK.getElements().put(OACPasswordField.class, new DesignFlags(OACColor.DARK_INPUT_FIELD, OACColor.DARK_TEXT)); 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.getElements().put(OACDialog.class, new DesignFlags(OACColor.DARK_BACKGROUND)); + Design.DARK.getElements().put(OACTitleBar.class, new DesignFlags(OACColor.DARK_HEADER)); - Design.DARK.border =new RoundedBorder(OACColor.DARK_BORDERS.getColor(), 18, 1); + Design.DARK.border = new RoundedBorder(OACColor.DARK_BORDERS.getColor(), 18, 1); + globalDesign = Design.DARK; DesignManager.getInstance().registerDesign(Design.DARK); } @@ -73,7 +87,7 @@ public class DesignManager { if (globalDesign == null) return; - DesignFlags designFlags = globalDesign.getElements().get(component.getClass()); + DesignFlags designFlags = resolveFlags(component.getClass()); if (designFlags == null) return; @@ -96,22 +110,101 @@ public class DesignManager { if (disabled != null) pressable.setDisabledColor(disabled.getColor()); } - if (component instanceof JComponent jComponent) { - jComponent.setBackground(backgroundColour.getColor()); + if (component instanceof Component awtComponent) { + awtComponent.setBackground(backgroundColour.getColor()); if (foregroundColour != null) { - jComponent.setForeground(foregroundColour.getColor()); + awtComponent.setForeground(foregroundColour.getColor()); } + } + if (component instanceof JComponent jComponent) { if (hasBorder) { jComponent.setBorder(globalDesign.getBorder()); jComponent.setOpaque(false); + } else if (!(jComponent instanceof OACTitleBar) && !(jComponent instanceof JTextComponent)) { + Border currentBorder = jComponent.getBorder(); + if (currentBorder == null || hasZeroInsets(currentBorder, jComponent)) { + jComponent.setBorder(INVISIBLE_BORDER); + } } + if (jComponent instanceof JTextComponent textComponent) { + textComponent.setOpaque(true); + textComponent.setBorder(createTextComponentBorder()); + } + + if (!Boolean.TRUE.equals(jComponent.getClientProperty(OAC_INIT_PROPERTY))) { + component.init(); + jComponent.putClientProperty(OAC_INIT_PROPERTY, Boolean.TRUE); + } + } else { component.init(); } } + private static boolean hasZeroInsets(Border border, JComponent component) { + Insets insets = border.getBorderInsets(component); + return insets.top == 0 && insets.left == 0 && insets.bottom == 0 && insets.right == 0; + } + + public static DesignFlags getFlagsFor(Class type) { + if (globalDesign == null) { + return null; + } + return resolveFlags(type); + } + + public static Color resolveBackground(Class type, Color fallback) { + DesignFlags flags = getFlagsFor(type); + if (flags != null && flags.background() != null) { + return flags.background().getColor(); + } + return fallback; + } + + public static Color resolveForeground(Class type, Color fallback) { + DesignFlags flags = getFlagsFor(type); + if (flags != null && flags.foreground() != null) { + return flags.foreground().getColor(); + } + if (globalDesign != null && globalDesign.getForegroundColour() != null) { + return globalDesign.getForegroundColour().getColor(); + } + return fallback; + } + + public static Color resolveHovered(Class type, Color fallback) { + DesignFlags flags = getFlagsFor(type); + if (flags != null && flags.hovered() != null) { + return flags.hovered().getColor(); + } + return fallback; + } + + public static Color resolvePressed(Class type, Color fallback) { + DesignFlags flags = getFlagsFor(type); + if (flags != null && flags.pressed() != null) { + return flags.pressed().getColor(); + } + return fallback; + } + + public static Border createTextComponentBorder() { + Color borderColor = resolveBorderColor(new Color(120, 120, 120)); + return new CompoundBorder( + new LineBorder(borderColor, 2, true), + new EmptyBorder(4, 8, 4, 8) + ); + } + + public static Color resolveBorderColor(Color fallback) { + if (globalDesign != null && globalDesign.getBorder() instanceof RoundedBorder roundedBorder) { + return roundedBorder.getColor(); + } + return fallback; + } + public static void apply(OACFrame frame) { DesignFlags designFlags; @@ -122,8 +215,50 @@ public class DesignManager { frame.getContentPane().setBackground(designFlags.background().getColor()); } + applyTree(frame.getRootPane()); + applyTree(frame.getLayeredPane()); + installAutoApply(frame.getRootPane()); + installAutoApply(frame.getLayeredPane()); + } + private static DesignFlags resolveFlags(Class type) { + Class current = type; + while (current != null) { + DesignFlags flags = globalDesign.getElements().get(current); + if (flags != null) { + return flags; + } + current = current.getSuperclass(); + } + return null; + } + private static void applyTree(Component component) { + if (component instanceof OACComponent oacComponent) { + oacComponent.initDesign(); + } + if (component instanceof Container container) { + installAutoApply(container); + for (Component child : container.getComponents()) { + applyTree(child); + } + } + } + + private static void installAutoApply(Container container) { + if (!(container instanceof JComponent jComponent)) { + return; + } + if (Boolean.TRUE.equals(jComponent.getClientProperty(OAC_LISTENER_PROPERTY))) { + return; + } + container.addContainerListener(new ContainerAdapter() { + @Override + public void componentAdded(ContainerEvent e) { + applyTree(e.getChild()); + } + }); + jComponent.putClientProperty(OAC_LISTENER_PROPERTY, Boolean.TRUE); } public void registerDesign(Design design) { diff --git a/src/test/java/org/openautonomousconnection/oacswing/test/CustomizedTests.java b/src/test/java/org/openautonomousconnection/oacswing/test/CustomizedTests.java index 11b88b4..6a2ffa5 100644 --- a/src/test/java/org/openautonomousconnection/oacswing/test/CustomizedTests.java +++ b/src/test/java/org/openautonomousconnection/oacswing/test/CustomizedTests.java @@ -5,13 +5,11 @@ package org.openautonomousconnection.oacswing.test; import org.junit.jupiter.api.Test; -import org.openautonomousconnection.oacswing.component.OACButton; -import org.openautonomousconnection.oacswing.component.OACFrame; -import org.openautonomousconnection.oacswing.component.OACPanel; -import org.openautonomousconnection.oacswing.component.OACTextField; +import org.openautonomousconnection.oacswing.component.*; import org.openautonomousconnection.oacswing.component.design.Design; import org.openautonomousconnection.oacswing.component.design.DesignManager; +import javax.swing.*; import java.awt.*; public class CustomizedTests { @@ -29,9 +27,19 @@ public class CustomizedTests { navBar.add(textField, BorderLayout.CENTER); frame.getContentPane().add(navBar, BorderLayout.NORTH); - +frame.add(navBar); frame.setVisible(true); - - wait(15000); + Object[] options = {"Continue", "Cancel"}; + OACOptionPane.showOptionDialog( + frame, + "You never connected to this INS before!\n" + + "Fingerprint: " + "caFingerprint" + "\nDo you want to connect?", + "INS Connection", + OACOptionPane.YES_NO_OPTION, + OACOptionPane.INFORMATION_MESSAGE, + null, + options, + options[0] + ); wait(15000); } }