-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathComponentBorder.java
More file actions
296 lines (260 loc) · 7.68 KB
/
ComponentBorder.java
File metadata and controls
296 lines (260 loc) · 7.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
/**
* The ComponentBorder class allows you to place a real component in
* the space reserved for painting the Border of a component.
*
* This class takes advantage of the knowledge that all Swing components are
* also Containers. By default the layout manager is null, so we should be
* able to place a child component anywhere in the parent component. In order
* to prevent the child component from painting over top of the parent
* component a Border is added to the parent componet such that the insets of
* the Border will reserve space for the child component to be painted without
* affecting the parent component.
*/
public class ComponentBorder implements Border
{
public enum Edge
{
TOP,
LEFT,
BOTTOM,
RIGHT;
}
public static final float LEADING = 0.0f;
public static final float CENTER = 0.5f;
public static final float TRAILING = 1.0f;
private JComponent parent;
private JComponent component;
private Edge edge;
private float alignment;
private int gap = 5;
private boolean adjustInsets = true;
private Insets borderInsets = new Insets(0, 0, 0, 0);
/**
* Convenience constructor that uses the default edge (Edge.RIGHT) and
* alignment (CENTER).
*
* @param component the component to be added in the Border area
*/
public ComponentBorder(JComponent component)
{
this(component, Edge.RIGHT);
}
/**
* Convenience constructor that uses the default alignment (CENTER).
*
* @param component the component to be added in the Border area
* @param edge a valid Edge enum of TOP, LEFT, BOTTOM, RIGHT
*/
public ComponentBorder(JComponent component, Edge edge)
{
this(component, edge, CENTER);
}
/**
* Main constructor to create a ComponentBorder.
*
* @param component the component to be added in the Border area
* @param edge a valid Edge enum of TOP, LEFT, BOTTOM, RIGHT
* @param alignment the alignment of the component along the
* specified Edge. Must be in the range 0 - 1.0.
*/
public ComponentBorder(JComponent component, Edge edge, float alignment )
{
this.component = component;
component.setSize( component.getPreferredSize() );
component.setCursor(Cursor.getDefaultCursor());
setEdge( edge );
setAlignment( alignment );
}
public boolean isAdjustInsets()
{
return adjustInsets;
}
public void setAdjustInsets(boolean adjustInsets)
{
this.adjustInsets = adjustInsets;
}
/**
* Get the component alignment along the Border Edge
*
* @return the alignment
*/
public float getAlignment()
{
return alignment;
}
/**
* Set the component alignment along the Border Edge
*
* @param alignment a value in the range 0 - 1.0. Standard values would be
* CENTER (default), LEFT and RIGHT.
*/
public void setAlignment(float alignment)
{
this.alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
}
/**
* Get the Edge the component is positioned along
*
* @return the Edge
*/
public Edge getEdge()
{
return edge;
}
/**
* Set the Edge the component is positioned along
*
* @param edge the Edge the component is position on.
*/
public void setEdge(Edge edge)
{
this.edge = edge;
}
/**
* Get the gap between the border component and the parent component
*
* @return the gap in pixels.
*/
public int getGap()
{
return gap;
}
/**
* Set the gap between the border component and the parent component
*
* @param gap the gap in pixels (default is 5)
*/
public void setGap(int gap)
{
this.gap = gap;
}
//
// Implement the Border interface
//
public Insets getBorderInsets(Component c)
{
return borderInsets;
}
public boolean isBorderOpaque()
{
return false;
}
/**
* In this case a real component is to be painted. Setting the location
* of the component will cause it to be painted at that location.
*/
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
float x2 = (width - component.getWidth()) * component.getAlignmentX() + x;
float y2 = (height - component.getHeight()) * component.getAlignmentY() + y;
component.setLocation((int)x2, (int)y2);
}
/*
* Install this Border on the specified component by replacing the
* existing Border with a CompoundBorder containing the original Border
* and our ComponentBorder
*
* This method should only be invoked once all the properties of this
* class have been set. Installing the Border more than once will cause
* unpredictable results.
*/
public void install(JComponent parent)
{
this.parent = parent;
determineInsetsAndAlignment();
// Add this Border to the parent
Border current = parent.getBorder();
if (current == null)
{
parent.setBorder(this);
}
else
{
CompoundBorder compound = new CompoundBorder(current, this);
parent.setBorder(compound);
}
// Add component to the parent
parent.add(component);
}
/**
* The insets need to be determined so they are included in the preferred
* size of the component the Border is attached to.
*
* The alignment of the component is determined here so it doesn't need
* to be recalculated every time the Border is painted.
*/
private void determineInsetsAndAlignment()
{
borderInsets = new Insets(0, 0, 0, 0);
// The insets will only be updated for the edge the component will be
// diplayed on.
//
// The X, Y alignment of the component is controlled by both the edge
// and alignment parameters
if (edge == Edge.TOP)
{
borderInsets.top = component.getPreferredSize().height + gap;
component.setAlignmentX(alignment);
component.setAlignmentY(0.0f);
}
else if (edge == Edge.BOTTOM)
{
borderInsets.bottom = component.getPreferredSize().height + gap;
component.setAlignmentX(alignment);
component.setAlignmentY(1.0f);
}
else if (edge == Edge.LEFT)
{
borderInsets.left = component.getPreferredSize().width + gap;
component.setAlignmentX(0.0f);
component.setAlignmentY(alignment);
}
else if (edge == Edge.RIGHT)
{
borderInsets.right = component.getPreferredSize().width + gap;
component.setAlignmentX(1.0f);
component.setAlignmentY(alignment);
}
if (adjustInsets)
adjustBorderInsets();
}
/*
* The complimentary edges of the Border may need to be adjusted to allow
* the component to fit completely in the bounds of the parent component.
*/
private void adjustBorderInsets()
{
Insets parentInsets = parent.getInsets();
// May need to adust the height of the parent component to fit
// the component in the Border
if (edge == Edge.RIGHT || edge == Edge.LEFT)
{
int parentHeight = parent.getPreferredSize().height - parentInsets.top - parentInsets.bottom;
int diff = component.getHeight() - parentHeight;
if (diff > 0)
{
int topDiff = (int)(diff * alignment);
int bottomDiff = diff - topDiff;
borderInsets.top += topDiff;
borderInsets.bottom += bottomDiff;
}
}
// May need to adust the width of the parent component to fit
// the component in the Border
if (edge == Edge.TOP || edge == Edge.BOTTOM)
{
int parentWidth = parent.getPreferredSize().width - parentInsets.left - parentInsets.right;
int diff = component.getWidth() - parentWidth;
if (diff > 0)
{
int leftDiff = (int)(diff * alignment);
int rightDiff = diff - leftDiff;
borderInsets.left += leftDiff;
borderInsets.right += rightDiff;
}
}
}
}