001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas/
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see https://www.gnu.org/licenses/.
027 */
028package edu.wisc.ssec.mcidasv.ui;
029
030import java.awt.Color;
031import java.awt.Component;
032import java.awt.Graphics;
033import java.awt.Graphics2D;
034import java.awt.Insets;
035import java.awt.RenderingHints;
036
037import javax.swing.border.LineBorder;
038
039/**
040 * This is a better version of LineBorder which allows you to show line only at one side or several
041 * sides and supports rounded corner.
042 */
043public class PartialLineBorder extends LineBorder {
044
045    final static int NORTH = 1;
046    final static int SOUTH = 2;
047    final static int EAST = 4;
048    final static int WEST = 8;
049    final static int HORIZONTAL = NORTH | SOUTH;
050    final static int VERTICAL = EAST | WEST;
051    final static int ALL = VERTICAL | HORIZONTAL;
052    
053    private int _sides = ALL;
054    private int _roundedCornerSize = 5;
055
056    public PartialLineBorder(Color color) {
057        super(color);
058    }
059
060    public PartialLineBorder(Color color, int thickness) {
061        super(color, thickness);
062    }
063
064    public PartialLineBorder(Color color, int thickness, boolean roundedCorners) {
065        super(color, thickness, roundedCorners);
066    }
067
068    public PartialLineBorder(Color color, int thickness, boolean roundedCorners, int roundedCornerSize) {
069        super(color, thickness, roundedCorners);
070        _roundedCornerSize = roundedCornerSize;
071    }
072
073    public PartialLineBorder(Color color, int thickness, int side) {
074        super(color, thickness);
075        _sides = side;
076    }
077
078    public int getSides() {
079        return _sides;
080    }
081
082    public void setSides(int sides) {
083        _sides = sides;
084    }
085
086    public int getRoundedCornerSize() {
087        return _roundedCornerSize;
088    }
089
090    public void setRoundedCornerSize(int roundedCornerSize) {
091        _roundedCornerSize = roundedCornerSize;
092    }
093
094    @Override
095    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
096        Color oldColor = g.getColor();
097        int i;
098
099        g.setColor(lineColor);
100        for (i = 0; i < thickness; i++) {
101            if (_sides == ALL) {
102                if (!roundedCorners)
103                    g.drawRect(x + i, y + i, width - i - i - 1, height - i - i - 1);
104                else {
105                    Object o = setupShapeAntialiasing(g);
106                    g.drawRoundRect(x + i, y + i, width - i - i - 1, height - i - i - 1, _roundedCornerSize, _roundedCornerSize);
107                    restoreShapeAntialiasing(g, o);
108                }
109            }
110
111            else {
112                if ((_sides & NORTH) != 0) {
113                    g.drawLine(x, y + i, x + width - 1, y + i);
114                }
115                if ((_sides & SOUTH) != 0) {
116                    g.drawLine(x, y + height - i - 1, x + width - 1, y + height - i - 1);
117                }
118                if ((_sides & WEST) != 0) {
119                    g.drawLine(x + i, y, x + i, y + height - 1);
120                }
121                if ((_sides & EAST) != 0) {
122                    g.drawLine(x + width - i - 1, y, x + width - i - 1, y + height - 1);
123                }
124            }
125
126        }
127        g.setColor(oldColor);
128    }
129
130    @Override
131    public Insets getBorderInsets(Component c) {
132        Insets borderInsets = super.getBorderInsets(c);
133        if ((_sides & NORTH) == 0) {
134            borderInsets.top = 0;
135        }
136        if ((_sides & SOUTH) == 0) {
137            borderInsets.bottom = 0;
138        }
139        if ((_sides & WEST) == 0) {
140            borderInsets.left = 0;
141        }
142        if ((_sides & EAST) == 0) {
143            borderInsets.right = 0;
144        }
145        return borderInsets;
146    }
147
148    @Override
149    public Insets getBorderInsets(Component c, Insets insets) {
150        Insets borderInsets = super.getBorderInsets(c, insets);
151        if ((_sides & NORTH) == 0) {
152            borderInsets.top = 0;
153        }
154        if ((_sides & SOUTH) == 0) {
155            borderInsets.bottom = 0;
156        }
157        if ((_sides & WEST) == 0) {
158            borderInsets.left = 0;
159        }
160        if ((_sides & EAST) == 0) {
161            borderInsets.right = 0;
162        }
163        return borderInsets;
164    }
165
166    /**
167     * Setups the graphics to draw shape using anti-alias.
168     *
169     * @param g
170     * @return the old hints. You will need this value as the third parameter in {@link
171     *         #restoreShapeAntialiasing(java.awt.Graphics,Object)}.
172     */
173    private static Object setupShapeAntialiasing(Graphics g) {
174        Graphics2D g2d = (Graphics2D) g;
175        Object oldHints = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
176        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
177        return oldHints;
178    }
179
180    /**
181     * Restores the old setting for shape anti-alias.
182     *
183     * @param g
184     * @param oldHints the value returned from {@link #setupShapeAntialiasing(java.awt.Graphics)}.
185     */
186    private static void restoreShapeAntialiasing(Graphics g, Object oldHints) {
187        Graphics2D g2d = (Graphics2D) g;
188        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldHints);
189    }
190}