/*
 * @(#)VisualMargin.java  2.2  2005-10-01
 *
 * Copyright (c) 2004-2005 Werner Randelshofer
 * Staldenmattweg 2, Immensee, CH-6405, Switzerland.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Werner Randelshofer. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Werner Randelshofer.
 */

package contrib.ch.randelshofer.quaqua;

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;

/**
 * The VisualMargin is used to visually align components using bounds
 * based on other criterias than the clip bounds of the component.
 *
 * For example: The clip bounds of a JButton includes its cast shadow and its
 * focus ring. When we align the JButton with a JLabel, we want to align the
 * baseline of the Text of the JButton with the text in the JLabel.
 *
 * The visual margin may be quite large. We allow to programmatically set a
 * smaller margin using the client property "Quaqua.Component.margin".
 *
 * @author  Werner Randelshofer
 * @version 2.2 2005-10-01 Added method getVisualMargin.
 * <br>2.1 2005-06-21 Implements UIResource.
 * <br>2.0 2005-05-08 Renamed from BorderMargin to VisualMargin. Reworked
 * API.
 * <br>1.0  31 March 2005  Created.
 */
public class VisualMargin extends AbstractBorder implements UIResource {
    /**
     * Defines the margin from the clip bounds of the
     * component to its visually perceived borderline.
     */
    private Insets layoutMargin;
    
    /**
     * The UIManager Property to be used for the default margin.
     */
    private String uiManagerPropertyName = "Component.visualMargin";
    /**
     * The Client Property to be used for the default margin.
     */
    private String propertyName = "Quaqua.Component.visualMargin";
    
    private boolean isTopFixed, isLeftFixed, isBottomFixed, isRightFixed;
    
    /**
     * Creates a new VisualMargin.
     */
    public VisualMargin() {
        layoutMargin = new Insets(0, 0, 0, 0);
    }
    
    /**
     * The UIManager Property to be used for the default margin.
     */
    public void setPropertyName(String propertyName) {
        //  this.propertyName = propertyName;
    }
    
    /*
     * Specifies SwingConstants.TOP, LEFT, BOTTOM, RIGHT to be fixed.
     * Set to false to unfix.
     */
    public void setFixed(boolean top, boolean left, boolean bottom, boolean right) {
        isTopFixed = top;
        isLeftFixed = left;
        isBottomFixed = bottom;
        isRightFixed = right;
    }
    /**
     * Creates a new VisualMargin.
     *
     * @param top Defines the margin from the clip bounds of the
     * component to its visual bounds.
     * @param left Defines the margin from the clip bounds of the
     * component to its visual bounds.
     * @param bottom Defines the margin from the clip bounds of the
     * component to its visual bounds.
     * @param right Defines the margin from the clip bounds of the
     * component to its visual bounds.
     */
    public VisualMargin(int top, int left, int bottom, int right) {
        layoutMargin = new Insets(top, left, bottom, right);
    }
    public VisualMargin(int top, int left, int bottom, int right, boolean ftop, boolean fleft, boolean fbottom, boolean fright) {
        layoutMargin = new Insets(top, left, bottom, right);
        isTopFixed = ftop;
        isLeftFixed = fleft;
        isBottomFixed = fbottom;
        isRightFixed = fright;
    }
    public VisualMargin(boolean ftop, boolean fleft, boolean fbottom, boolean fright) {
        layoutMargin = new Insets(0, 0, 0, 0);
        isTopFixed = ftop;
        isLeftFixed = fleft;
        isBottomFixed = fbottom;
        isRightFixed = fright;
    }
    /**
     * Creates a new VisualMargin.
     *
     * @param layoutMargin Defines the margin from the clip bounds of the
     * component to its visual bounds. The margin has usually negative values!
     */
    public VisualMargin(Insets layoutMargin) {
        this.layoutMargin = layoutMargin;
    }
    
    public Insets getVisualMargin(Component c) {
        Insets insets = new Insets(
         layoutMargin.top,
        layoutMargin.left,
        layoutMargin.bottom,
         layoutMargin.right
         );
        
        if (c instanceof JComponent) {
            Insets componentMargin = (Insets) ((JComponent) c).getClientProperty(propertyName);
            if (componentMargin == null && propertyName != null) {
                componentMargin = UIManager.getInsets(uiManagerPropertyName);
            }
            if (componentMargin != null) {
                if (! isTopFixed) insets.top = componentMargin.top;
                if (! isLeftFixed) insets.left = componentMargin.left;
                if (! isBottomFixed) insets.bottom = componentMargin.bottom;
                if (! isRightFixed) insets.right = componentMargin.right;
            }
        }
        return insets;
    }
    
    public Insets getBorderInsets(Component c) {
        return getBorderInsets(c, new Insets(0, 0, 0, 0));
    }
    
    /**
     * Reinitializes the insets parameter with this Border's current Insets.
     * @param c the component for which this border insets value applies
     * @param insets the object to be reinitialized
     * @return the <code>insets</code> object
     */
    public Insets getBorderInsets(Component c, Insets insets) {
        return getVisualMargin(c, insets);
    }
    /**
     * Reinitializes the insets parameter with this Border's current Insets.
     * @param c the component for which this border insets value applies
     * @param insets the object to be reinitialized
     * @return the <code>insets</code> object
     */
    protected Insets getVisualMargin(Component c, Insets insets) {
        insets.top = -layoutMargin.top;
        insets.left = -layoutMargin.left;
        insets.bottom = -layoutMargin.bottom;
        insets.right = -layoutMargin.right;
        
        if (c instanceof JComponent) {
            Insets componentMargin = (Insets) ((JComponent) c).getClientProperty(propertyName);
            if (componentMargin == null && propertyName != null) {
                componentMargin = UIManager.getInsets(uiManagerPropertyName);
            }
            if (componentMargin != null) {
                if (! isTopFixed) insets.top += componentMargin.top;
                if (! isLeftFixed) insets.left += componentMargin.left;
                if (! isBottomFixed) insets.bottom += componentMargin.bottom;
                if (! isRightFixed) insets.right += componentMargin.right;
            }
        }
        return insets;
    }
}
