1/*
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.apple.laf;
27
28import java.awt.*;
29
30import javax.swing.plaf.*;
31import javax.swing.text.JTextComponent;
32
33import apple.laf.JRSUIConstants.*;
34
35import com.apple.laf.AquaUtilControlSize.*;
36import com.apple.laf.AquaUtils.*;
37
38public class AquaTextFieldBorder extends AquaBorder {
39    private static final RecyclableSingleton<AquaTextFieldBorder> instance = new RecyclableSingletonFromDefaultConstructor<AquaTextFieldBorder>(AquaTextFieldBorder.class);
40    public static AquaTextFieldBorder getTextFieldBorder() {
41        return instance.get();
42    }
43
44    public AquaTextFieldBorder() {
45        this(new SizeDescriptor(new SizeVariant().alterMargins(6, 7, 6, 7).alterInsets(3, 3, 3, 3)));
46        painter.state.set(Widget.FRAME_TEXT_FIELD);
47        painter.state.set(FrameOnly.YES);
48        painter.state.set(Size.LARGE);
49    }
50
51    public AquaTextFieldBorder(final SizeDescriptor sizeDescriptor) {
52        super(sizeDescriptor);
53    }
54
55    public AquaTextFieldBorder(final AquaTextFieldBorder other) {
56        super(other);
57    }
58
59    protected void setSize(final Size size) {
60        super.setSize(size);
61        painter.state.set(Size.LARGE);
62    }
63
64    public void paintBorder(final Component c, final Graphics g, int x, int y, int width, int height) {
65//        g.setColor(Color.MAGENTA);
66//        g.drawRect(x, y, width - 1, height - 1);
67
68        if (!(c instanceof JTextComponent)) {
69            painter.state.set(State.ACTIVE);
70            painter.state.set(Focused.NO);
71            painter.paint(g, c, x, y, width, height);
72            return;
73        }
74
75        final JTextComponent jc = (JTextComponent)c;
76        final State state = getStateFor(jc);
77        painter.state.set(state);
78        painter.state.set(State.ACTIVE == state && jc.hasFocus() ? Focused.YES : Focused.NO);
79
80        if (jc.isOpaque()) {
81            painter.paint(g, c, x, y, width, height);
82            return;
83        }
84
85        final int shrinkage = getShrinkageFor(jc, height);
86        final Insets subInsets = getSubInsets(shrinkage);
87        x += subInsets.left;
88        y += subInsets.top;
89        width -= (subInsets.left + subInsets.right);
90        height -= (subInsets.top + subInsets.bottom);
91
92        if (shrinkage > 0) {
93            final Rectangle clipBounds = g.getClipBounds();
94            clipBounds.x += shrinkage;
95            clipBounds.width -= shrinkage * 2;
96            g.setClip(clipBounds);
97        }
98
99        painter.paint(g, c, x, y, width, height);
100//        g.setColor(Color.ORANGE);
101//        g.drawRect(x, y, width - 1, height - 1);
102    }
103
104    static int getShrinkageFor(final JTextComponent jc, final int height) {
105        if (jc == null) return 0;
106        final TextUI ui = jc.getUI();
107        if (ui == null) return 0;
108        final Dimension size = ui.getPreferredSize(jc);
109        if (size == null) return 0;
110        final int shrinkage = size.height - height;
111        return (shrinkage < 0) ? 0 : (shrinkage > 3) ? 3 : shrinkage;
112    }
113
114    // this determines the rect that we should draw inset to our existing bounds
115    protected Insets getSubInsets(final int shrinkage) {
116        final Insets insets = sizeVariant.insets;
117
118        if (shrinkage > 0) {
119            return new InsetsUIResource(insets.top - shrinkage, insets.left, insets.bottom - shrinkage, insets.right);
120        }
121
122        return insets;
123    }
124
125    public Insets getBorderInsets(final Component c) {
126        if (!(c instanceof JTextComponent) || c.isOpaque()) return new InsetsUIResource(3, 7, 3, 7);
127        return new InsetsUIResource(5, 5, 5, 5);
128    }
129
130    protected static State getStateFor(final JTextComponent jc) {
131        if (!AquaFocusHandler.isActive(jc)) {
132            return State.INACTIVE;
133        }
134
135        if (!jc.isEnabled()) {
136            return State.DISABLED;
137        }
138
139        if (!jc.isEditable()) {
140            return State.DISABLED;
141        }
142
143        return State.ACTIVE;
144    }
145}
146