2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.form.layoutdesign;
44
import java.awt.Rectangle;
47
* Defines a rectangular area in the layout. For each dimension it holds the
48
* starting, ending, and center positions. For vertical dimension also the
49
* "baseline" position.
52
class LayoutRegion implements LayoutConstants {
54
// number of tracked points for each dimension
55
static final int[] POINT_COUNT = new int[] { 3, 4 };
57
// all points - used as param where no particular but all points should be used
58
static final int ALL_POINTS = Integer.MAX_VALUE;
60
// no point - used as param where no point should be processed
61
static final int NO_POINT = Integer.MIN_VALUE;
63
// unknown point position value
64
static final int UNKNOWN = Integer.MIN_VALUE;
66
// array of tracked positions - for each tracked point within each dimension
67
// - for HORIZONTAL dimension there are LEADING, TRAILING, CENTER points
68
// - for VERTICAL dimension there are LEADING, TRAILING, CENTER, BASELINE points
69
// (the constants can be used as indexes to the array)
73
positions = new int[DIM_COUNT][];
74
positions[HORIZONTAL] = new int[] { UNKNOWN, UNKNOWN, UNKNOWN };
75
positions[VERTICAL] = new int[] { UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN }; // including BASELINE
78
LayoutRegion(LayoutRegion reg) {
83
LayoutRegion(Rectangle bounds, int baselinePos) {
85
set(bounds, baselinePos);
89
return isSet(HORIZONTAL) && isSet(VERTICAL);
92
boolean isSet(int dimension) {
93
return positions[dimension][LEADING] != UNKNOWN
94
&& positions[dimension][TRAILING] != UNKNOWN;
97
int size(int dimension) {
98
int trail = positions[dimension][TRAILING];
99
int lead = positions[dimension][LEADING];
100
return trail != UNKNOWN && lead != UNKNOWN ? trail - lead : UNKNOWN;
104
* Sets up the region based on given bounds rectangle and baseline position.
106
void set(Rectangle bounds, int baselinePos) {
107
int[] horiz = positions[HORIZONTAL];
108
horiz[LEADING] = bounds.x;
109
horiz[TRAILING] = bounds.x + bounds.width;
110
horiz[CENTER] = bounds.x + bounds.width / 2;
112
int[] vert = positions[VERTICAL];
113
vert[LEADING] = bounds.y;
114
vert[TRAILING] = bounds.y + bounds.height;
115
vert[CENTER] = bounds.y + bounds.height / 2;
116
vert[BASELINE] = baselinePos;
120
* Converts the region to a rectangle.
121
* @param bounds rectangle to be set (output)
122
* @return Rectangle updated with actual position values (same instance as
123
* passed in as parameter)
125
Rectangle toRectangle(Rectangle bounds) {
126
int[] horiz = positions[HORIZONTAL];
127
bounds.x = horiz[LEADING];
128
bounds.width = horiz[TRAILING] - bounds.x;
129
int[] vert = positions[VERTICAL];
130
bounds.y = vert[LEADING];
131
bounds.height = vert[TRAILING] - bounds.y;
136
* Copies all position values from another region.
138
void set(LayoutRegion reg) {
139
for (int i=0; i < DIM_COUNT; i++) {
145
* Copies position values of given dimension from another region.
147
void set(int dimension, LayoutRegion reg) {
148
int[] pos = positions[dimension];
149
int[] setPos = reg.positions[dimension];
150
for (int j=0; j < pos.length; j++) {
155
void set(int dimension, int leading, int trailing) {
156
int[] pos = positions[dimension];
157
if (pos[LEADING] != leading || pos[TRAILING] != trailing) {
158
pos[LEADING] = leading;
159
pos[TRAILING] = trailing;
160
pos[CENTER] = leading != UNKNOWN && trailing != UNKNOWN ?
161
(leading + trailing) / 2 : UNKNOWN;
162
if (dimension == VERTICAL) {
163
pos[BASELINE] = UNKNOWN; // undefined after change
169
* Reverts the region to unset state - like it was just after the creation.
172
for (int i=0; i < DIM_COUNT; i++) {
173
int[] pos = positions[i];
174
for (int j=0; j < pos.length; j++)
180
* @param points array of alignment constants (LEADING or TRAILING) defining
181
* for each dimension which point should be moved (can be null to
184
void reshape(int[] points, int[] moves) {
185
for (int i=0; i < DIM_COUNT; i++) {
186
reshape(i, (points != null ? points[i] : ALL_POINTS), moves[i]);
190
void reshape(int dimension, int align, int move) {
191
int[] pos = positions[dimension];
192
if (align == ALL_POINTS) { // move everything
193
for (int j=0; j < pos.length; j++) {
194
if (pos[j] != UNKNOWN)
198
else if (align != NO_POINT) { // move only the desired point
199
assert align == LEADING || align == TRAILING;
200
if (pos[align] != UNKNOWN) {
202
if (pos[LEADING] != UNKNOWN && pos[TRAILING] != UNKNOWN) {
203
if (pos[LEADING] > pos[TRAILING]) { // don't allow negative size
204
pos[align] = pos[align^1];
206
pos[CENTER] = (pos[LEADING] + pos[TRAILING]) / 2;
208
if (dimension == VERTICAL && move != 0) {
209
pos[BASELINE] = UNKNOWN; // undefined after resizing
216
* Grows to bounds of given region.
218
void expand(LayoutRegion reg) {
219
for (int i=0; i < DIM_COUNT; i++) {
224
void expand(LayoutRegion reg, int dimension) {
225
int[] pos = positions[dimension];
226
int[] exPos = reg.positions[dimension];
227
if (exPos[LEADING] != UNKNOWN
228
&& (pos[LEADING] == UNKNOWN || exPos[LEADING] < pos[LEADING]))
230
pos[LEADING] = exPos[LEADING];
232
if (exPos[TRAILING] != UNKNOWN
233
&& (pos[TRAILING] == UNKNOWN || exPos[TRAILING] > pos[TRAILING]))
235
pos[TRAILING] = exPos[TRAILING];
237
if (pos[LEADING] != UNKNOWN && pos[TRAILING] != UNKNOWN) {
238
pos[CENTER] = (pos[LEADING] + pos[TRAILING]) / 2;
243
* @param sp1 base LayoutSpace
244
* @param sp2 compared LayoutSpace
245
* @param points array of alignment constants defining what points should
246
* be compared in each dimension (can be null if it does not matter)
247
* @param diffs output array with the position difference for each dimension
249
/* static void positionDiff(LayoutSpace sp1, LayoutSpace sp2,
250
int[] points, int[] diffs)
252
for (int i=0; i < DIM_COUNT; i++) {
253
int[] pos1 = sp1.positions[i];
254
int[] pos2 = sp2.positions[i];
255
int align = points != null ? points[i] : LEADING;
256
if (align != NO_POINT) {
257
if (align == ALL_POINTS) {
260
diffs[i] = pos1[align] != UNKNOWN && pos2[align] != UNKNOWN ?
261
pos2[align] - pos1[align] : UNKNOWN;
266
static boolean isValidCoordinate(int pos) {
267
return pos > Short.MIN_VALUE && pos < Short.MAX_VALUE;
271
* @param r1 base LayoutRegion
272
* @param r2 compared LayoutRegion
273
* @param dimension HORIZONTAL or VERTICAL (dimension index)
274
* @param align1 alignment constant of a point in base LayoutRegion
275
* @param align2 alignment constant of a point in compared LayoutRegion
276
* @return distance sp2 - sp1 in given dimension between given points
278
static int distance(LayoutRegion r1, LayoutRegion r2,
280
int align1, int align2)
282
int pos1 = r1.positions[dimension][align1];
283
int pos2 = r2.positions[dimension][align2];
284
return pos1 != UNKNOWN && pos2 != UNKNOWN ? pos2 - pos1 : UNKNOWN;
288
* Goes through all points of given two regions in given dimension and finds
289
* the smallest distance (abs) between the regions. Positive value is
290
* returned if r2 has higher position.
291
* @return the smallest distance between the corresponding points of given
292
* regions in given dimension
294
static int minDistance(LayoutRegion r1, LayoutRegion r2, int dimension) {
295
int[] pos1 = r1.positions[dimension];
296
int[] pos2 = r2.positions[dimension];
299
for (int i=0; i < pos1.length; i++) {
300
if (pos1[i] != UNKNOWN && pos2[i] != UNKNOWN) {
301
int dst = pos2[i] - pos1[i];
308
if (min == UNKNOWN || dst < min) {
318
* Computes distance between two regions supposing they do not overlap.
319
* The distance is between LEADING point of one region and TRAILING of the
320
* other (or vice versa, depending on their relative position). Positive
321
* value is returned if r2 has higher position.
322
* @return the distance between two regions if they don't overlap, or 0 if
325
static int nonOverlapDistance(LayoutRegion r1, LayoutRegion r2, int dimension) {
326
int[] pos1 = r1.positions[dimension];
327
int[] pos2 = r2.positions[dimension];
328
int dst = pos2[LEADING] - pos1[TRAILING];
332
dst = pos2[TRAILING] - pos1[LEADING];
340
* Checks whether a point of 'contained' region (described by 'alignment')
341
* is inside the 'container' region's area in given 'dimension'.
342
* @return whether a point of a region is inside the other region
344
static boolean pointInside(LayoutRegion contained, int alignment, LayoutRegion container, int dimension) {
345
int[] pos = container.positions[dimension];
346
int point = contained.positions[dimension][alignment];
347
assert point != UNKNOWN && pos[LEADING] != UNKNOWN && pos[TRAILING] != UNKNOWN;
348
if (alignment == LEADING) {
349
return point >= pos[LEADING] && point < pos[TRAILING];
351
// if (alignment == TRAILING) {
352
return point > pos[LEADING] && point <= pos[TRAILING];
357
* @return whether the given regions overlap in given dimension
359
static boolean overlap(LayoutRegion r1, LayoutRegion r2, int dimension,
362
int[] pos1 = r1.positions[dimension];
363
int[] pos2 = r2.positions[dimension];
364
assert pos1[LEADING] != UNKNOWN && pos1[TRAILING] != UNKNOWN
365
&& pos2[LEADING] != UNKNOWN && pos2[TRAILING] != UNKNOWN;
366
return pos1[TRAILING] + margin > pos2[LEADING]
367
&& pos1[LEADING] - margin < pos2[TRAILING];
371
* @return whether given regions occupy the same space
373
static boolean sameSpace(LayoutRegion r1, LayoutRegion r2) {
374
return sameSpace(r1, r2, HORIZONTAL) && sameSpace(r1, r2, VERTICAL);
378
* @return whether given regions occupy the same space in given dimension
380
static boolean sameSpace(LayoutRegion r1, LayoutRegion r2, int dimension) {
381
return r1.positions[dimension][LEADING] == r2.positions[dimension][LEADING]
382
&& r1.positions[dimension][TRAILING] == r2.positions[dimension][TRAILING];