Gridarta Editor
DirectionLayout.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2023 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.utils;
21 
22 import java.awt.Component;
23 import java.awt.Container;
24 import java.awt.Dimension;
25 import java.awt.Insets;
26 import java.awt.LayoutManager2;
27 import java.io.Serializable;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31 
42 public class DirectionLayout implements LayoutManager2, Serializable {
43 
47  private static final long serialVersionUID = 1L;
48 
55  @NotNull
56  private static final Direction @NotNull [] DAIMONIN_TO_DIRECTION_MAP = new Direction[10];
57 
58  static {
69  }
70 
75  @NotNull
76  private static final Dimension EMPTY = new Dimension(0, 0);
77 
82  private static void addDirection(@NotNull final Direction direction) {
83  DAIMONIN_TO_DIRECTION_MAP[direction.ordinal()] = direction;
84  }
85 
90  private final int hGap;
91 
96  private final int vGap;
97 
102  @Nullable
103  private Component cNW;
104 
109  @Nullable
110  private Component cN;
111 
116  @Nullable
117  private Component cNE;
118 
123  @Nullable
124  private Component cE;
125 
130  @Nullable
131  private Component cSE;
132 
137  @Nullable
138  private Component cS;
139 
144  @Nullable
145  private Component cSW;
146 
151  @Nullable
152  private Component cW;
153 
158  @Nullable
159  private Component cC;
160 
165  @Nullable
166  private Component cU;
167 
172  @Nullable
173  private Component cD;
174 
178  public DirectionLayout() {
179  this(0, 0);
180  }
181 
187  private DirectionLayout(final int hGap, final int vGap) {
188  this.hGap = hGap;
189  this.vGap = vGap;
190  }
191 
192  @SuppressWarnings("ChainOfInstanceofChecks")
193  @Override
194  public void addLayoutComponent(@NotNull final Component comp, @Nullable final Object constraints) {
195  if (constraints == null) {
196  cC = comp;
197  return;
198  }
199  final Direction direction;
200  if (constraints instanceof Integer) {
201  direction = getDirectionFromDaimonin((Integer) constraints);
202  } else if (!(constraints instanceof Direction)) {
203  throw new IllegalArgumentException("DirectionLayout does not support " + constraints.getClass().getName() + " constraints.");
204  } else {
205  direction = (Direction) constraints;
206  }
207  synchronized (comp.getTreeLock()) {
208  switch (direction) {
209  case NORTH:
210  cN = comp;
211  break;
212  case EAST:
213  cE = comp;
214  break;
215  case SOUTH:
216  cS = comp;
217  break;
218  case WEST:
219  cW = comp;
220  break;
221  case NORTH_EAST:
222  cNE = comp;
223  break;
224  case SOUTH_EAST:
225  cSE = comp;
226  break;
227  case SOUTH_WEST:
228  cSW = comp;
229  break;
230  case NORTH_WEST:
231  cNW = comp;
232  break;
233  case UP:
234  cU = comp;
235  break;
236  case DOWN:
237  cD = comp;
238  break;
239  default:
240  assert false;
241  break;
242  }
243  }
244  }
245 
246  @Override
247  public void addLayoutComponent(@NotNull final String name, @NotNull final Component comp) {
248  throw new IllegalArgumentException("DirectionLayout does not support String constraints.");
249  }
250 
251  @Override
252  @SuppressWarnings("ObjectEquality")
253  public void removeLayoutComponent(@NotNull final Component comp) {
254  synchronized (comp.getTreeLock()) {
255  if (cC == comp) {
256  cC = null;
257  } else if (cN == comp) {
258  cN = null;
259  } else if (cE == comp) {
260  cE = null;
261  } else if (cS == comp) {
262  cS = null;
263  } else if (cW == comp) {
264  cW = null;
265  } else if (cNE == comp) {
266  cNE = null;
267  } else if (cSE == comp) {
268  cSE = null;
269  } else if (cSW == comp) {
270  cSW = null;
271  } else if (cNW == comp) {
272  cNW = null;
273  } else if (cU == comp) {
274  cU = null;
275  } else if (cD == comp) {
276  cD = null;
277  }
278  }
279  }
280 
281  @NotNull
282  @Override
283  public Dimension minimumLayoutSize(@NotNull final Container parent) {
284  synchronized (parent.getTreeLock()) {
285  final Dimension dim = new Dimension(0, 0); // return dimension
286  final Dimension dC = getMinimumSize(cC);
287  final Dimension dN = getMinimumSize(cN);
288  final Dimension dE = getMinimumSize(cE);
289  final Dimension dS = getMinimumSize(cS);
290  final Dimension dW = getMinimumSize(cW);
291  final Dimension dNE = getMinimumSize(cNE);
292  final Dimension dSE = getMinimumSize(cSE);
293  final Dimension dSW = getMinimumSize(cSW);
294  final Dimension dNW = getMinimumSize(cNW);
295  final Dimension dU = getMinimumSize(cU);
296  final Dimension dD = getMinimumSize(cD);
297  dim.height = vGap * 4 + dNW.height + max(dW.height, dN.height) + max(dSW.height, dC.height, dNE.height) + max(dS.height, dE.height) + dSE.height + max(dU.height, dD.height);
298  dim.width = max(hGap * 2 + dSW.width + max(dNW.width, dC.width, dSE.width) + dNE.width, hGap + max(dW.width, dS.width) + max(dN.width, dE.width), max(dNW.width, dSE.width));
299  final Insets insets = parent.getInsets();
300  dim.width += insets.left + insets.right;
301  dim.height += insets.top + insets.bottom;
302  return dim;
303  }
304  }
305 
312  @NotNull
313  private static Dimension getMinimumSize(@Nullable final Component component) {
314  return component == null ? EMPTY : component.getMinimumSize();
315  }
316 
317  @NotNull
318  @Override
319  public Dimension preferredLayoutSize(final Container parent) {
320  synchronized (parent.getTreeLock()) {
321  final Dimension dim = new Dimension(0, 0); // return dimension
322  final Dimension dC = getPreferredSize(cC);
323  final Dimension dN = getPreferredSize(cN);
324  final Dimension dE = getPreferredSize(cE);
325  final Dimension dS = getPreferredSize(cS);
326  final Dimension dW = getPreferredSize(cW);
327  final Dimension dNE = getPreferredSize(cNE);
328  final Dimension dSE = getPreferredSize(cSE);
329  final Dimension dSW = getPreferredSize(cSW);
330  final Dimension dNW = getPreferredSize(cNW);
331  final Dimension dU = getMinimumSize(cU);
332  final Dimension dD = getMinimumSize(cD);
333  dim.height = vGap * 4 + dNW.height + max(dW.height, dN.height) + max(dSW.height, dC.height, dNE.height) + max(dS.height, dE.height) + dSE.height + max(dU.height, dD.height);
334  dim.width = hGap * 2 + dSW.width + max(dNW.width, dC.width, dSE.width) + dNE.width;
335  final Insets insets = parent.getInsets();
336  dim.width += insets.left + insets.right;
337  dim.height += insets.top + insets.bottom;
338  return dim;
339  }
340  }
341 
348  @NotNull
349  private static Dimension getPreferredSize(@Nullable final Component component) {
350  return component == null ? EMPTY : component.getMinimumSize();
351  }
352 
353  @NotNull
354  @Override
355  public Dimension maximumLayoutSize(@NotNull final Container target) {
356  return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
357  }
358 
359  @Override
360  public float getLayoutAlignmentX(@NotNull final Container target) {
361  return 0.5f;
362  }
363 
364  @Override
365  public float getLayoutAlignmentY(@NotNull final Container target) {
366  return 0.5f;
367  }
368 
369  @Override
370  public void invalidateLayout(@NotNull final Container target) {
371  /* Do Nothing, like BorderLayout. */
372  }
373 
374  @Override
375  public void layoutContainer(@NotNull final Container parent) {
376  synchronized (parent.getTreeLock()) {
377  final Dimension size = parent.getSize();
378  final Insets padding = parent.getInsets();
379  final int innerWidth = size.width - padding.left - padding.right;
380  final int innerHeight = size.height - padding.top - padding.bottom;
381  int rows = 0;
382  //noinspection VariableNotUsedInsideIf
383  if (cNW != null) {
384  rows++;
385  }
386  if (cW != null || cN != null) {
387  rows++;
388  }
389  if (cSW != null || cC != null || cNE != null) {
390  rows++;
391  }
392  if (cS != null || cE != null) {
393  rows++;
394  }
395  //noinspection VariableNotUsedInsideIf
396  if (cSE != null) {
397  rows++;
398  }
399  if (cU != null || cD != null) {
400  rows++;
401  }
402  if (rows <= 0) {
403  return;
404  }
405  final int colWidth = (innerWidth - hGap * 2) / 3;
406  final int rowHeight = (innerHeight - vGap * (rows - 1)) / rows;
407  int top = padding.top;
408  final int left = padding.left;
409  if (cNW != null) {
410  cNW.setBounds(left + colWidth + hGap, top, colWidth, rowHeight);
411  top += rowHeight + vGap;
412  }
413  if (cW != null || cN != null) {
414  if (cW != null) {
415  cW.setBounds(left + ((colWidth + hGap) / 2), top, colWidth, rowHeight);
416  }
417  if (cN != null) {
418  cN.setBounds(left + ((colWidth + hGap) * 3 / 2), top, colWidth, rowHeight);
419  }
420  top += rowHeight + vGap;
421  }
422  if (cSW != null || cC != null || cNE != null) {
423  if (cSW != null) {
424  cSW.setBounds(left, top, colWidth, rowHeight);
425  }
426  if (cC != null) {
427  cC.setBounds(left + colWidth + hGap, top, colWidth, rowHeight);
428  }
429  if (cNE != null) {
430  cNE.setBounds(left + ((colWidth + hGap) * 2), top, colWidth, rowHeight);
431  }
432  top += rowHeight + vGap;
433  }
434  if (cS != null || cE != null) {
435  if (cS != null) {
436  cS.setBounds(left + ((colWidth + hGap) / 2), top, colWidth, rowHeight);
437  }
438  if (cE != null) {
439  cE.setBounds(left + ((colWidth + hGap) * 3 / 2), top, colWidth, rowHeight);
440  }
441  top += rowHeight + vGap;
442  }
443  if (cSE != null) {
444  cSE.setBounds(left + colWidth + hGap, top, colWidth, rowHeight);
445  top += rowHeight + vGap;
446  }
447  if (cU != null || cD != null) {
448  if (cU != null) {
449  cU.setBounds(left + ((colWidth + hGap) / 2), top, colWidth, rowHeight);
450  }
451  if (cD != null) {
452  cD.setBounds(left + ((colWidth + hGap) * 3 / 2), top, colWidth, rowHeight);
453  }
454  top += rowHeight + vGap;
455  }
456  }
457  }
458 
459  @NotNull
460  @Override
461  public String toString() {
462  return getClass().getName() + "[hGap=" + hGap + ",vGap=" + vGap + ']';
463  }
464 
473  private static int max(@NotNull final int... numbers) {
474  int ret = Integer.MIN_VALUE;
475  for (final int number : numbers) {
476  if (number > ret) {
477  ret = number;
478  }
479  }
480  return ret;
481  }
482 
488  @NotNull
489  private static Direction getDirectionFromDaimonin(final int daimoninDirection) {
490  return DAIMONIN_TO_DIRECTION_MAP[daimoninDirection];
491  }
492 
493 }
net.sf.gridarta.model.direction.Direction
A direction.
Definition: Direction.java:28
name
name
Definition: ArchetypeTypeSetParserTest-ignoreDefaultAttribute1-result.txt:2
net.sf.gridarta.gui.utils.DirectionLayout.invalidateLayout
void invalidateLayout(@NotNull final Container target)
Definition: DirectionLayout.java:370
net.sf.gridarta.gui.utils.DirectionLayout
This class implements a layout that is similar to {} but implements those directions used in Daimonin...
Definition: DirectionLayout.java:42
net.sf.gridarta.gui.utils.DirectionLayout.cNW
Component cNW
NorthWest Component.
Definition: DirectionLayout.java:103
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.gui.utils.DirectionLayout.getLayoutAlignmentX
float getLayoutAlignmentX(@NotNull final Container target)
Definition: DirectionLayout.java:360
net.sf.gridarta.gui.utils.DirectionLayout.serialVersionUID
static final long serialVersionUID
Serial Version.
Definition: DirectionLayout.java:47
net.sf.gridarta.model.direction.Direction.SOUTH
SOUTH
South.
Definition: Direction.java:43
net.sf.gridarta.gui.utils.DirectionLayout.cN
Component cN
North Component.
Definition: DirectionLayout.java:110
net.sf.gridarta.gui.utils.DirectionLayout.max
static int max(@NotNull final int... numbers)
Helper method for returning the maximum of an unspecified number of arguments.
Definition: DirectionLayout.java:473
net.sf
net.sf.gridarta.gui.utils.DirectionLayout.cS
Component cS
South Component.
Definition: DirectionLayout.java:138
net.sf.gridarta.gui.utils.DirectionLayout.cU
Component cU
Up Component.
Definition: DirectionLayout.java:166
net.sf.gridarta.model.direction.Direction.SOUTH_WEST
SOUTH_WEST
South west.
Definition: Direction.java:63
net.sf.gridarta.gui.utils.DirectionLayout.layoutContainer
void layoutContainer(@NotNull final Container parent)
Definition: DirectionLayout.java:375
net.sf.gridarta.gui.utils.DirectionLayout.preferredLayoutSize
Dimension preferredLayoutSize(final Container parent)
Definition: DirectionLayout.java:319
net.sf.gridarta.gui.utils.DirectionLayout.DirectionLayout
DirectionLayout(final int hGap, final int vGap)
Creates a DirectionLayout with specified gaps.
Definition: DirectionLayout.java:187
net.sf.gridarta.gui.utils.DirectionLayout.vGap
final int vGap
Vertical Gap.
Definition: DirectionLayout.java:96
net.sf.gridarta.gui.utils.DirectionLayout.cSW
Component cSW
SouthWest Component.
Definition: DirectionLayout.java:145
net.sf.gridarta.gui.utils.DirectionLayout.toString
String toString()
Definition: DirectionLayout.java:461
net.sf.gridarta.gui.utils.DirectionLayout.cE
Component cE
East Component.
Definition: DirectionLayout.java:124
net.sf.gridarta.gui.utils.DirectionLayout.minimumLayoutSize
Dimension minimumLayoutSize(@NotNull final Container parent)
Definition: DirectionLayout.java:283
net.sf.gridarta.model.direction.Direction.NORTH
NORTH
North.
Definition: Direction.java:33
net.sf.gridarta.model.direction.Direction.NORTH_WEST
NORTH_WEST
North west.
Definition: Direction.java:68
net
net.sf.gridarta.gui.utils.DirectionLayout.DirectionLayout
DirectionLayout()
Creates a DirectionLayout with zero gaps.
Definition: DirectionLayout.java:178
net.sf.gridarta.gui.utils.DirectionLayout.addLayoutComponent
void addLayoutComponent(@NotNull final String name, @NotNull final Component comp)
Definition: DirectionLayout.java:247
net.sf.gridarta.gui.utils.DirectionLayout.maximumLayoutSize
Dimension maximumLayoutSize(@NotNull final Container target)
Definition: DirectionLayout.java:355
net.sf.gridarta.model.direction.Direction.SOUTH_EAST
SOUTH_EAST
South east.
Definition: Direction.java:58
net.sf.gridarta.model.direction.Direction.DOWN
DOWN
Down.
Definition: Direction.java:78
net.sf.gridarta.gui.utils.DirectionLayout.getMinimumSize
static Dimension getMinimumSize(@Nullable final Component component)
Returns the minimum size of a component or EMPTY for.
Definition: DirectionLayout.java:313
net.sf.gridarta.gui.utils.DirectionLayout.addLayoutComponent
void addLayoutComponent(@NotNull final Component comp, @Nullable final Object constraints)
Definition: DirectionLayout.java:194
net.sf.gridarta.model.direction.Direction.UP
UP
Up.
Definition: Direction.java:73
net.sf.gridarta.gui.utils.DirectionLayout.cNE
Component cNE
NorthEast Component.
Definition: DirectionLayout.java:117
net.sf.gridarta.gui.utils.DirectionLayout.getLayoutAlignmentY
float getLayoutAlignmentY(@NotNull final Container target)
Definition: DirectionLayout.java:365
net.sf.gridarta.gui.utils.DirectionLayout.cD
Component cD
Down Component.
Definition: DirectionLayout.java:173
net.sf.gridarta.model
net.sf.gridarta.gui.utils.DirectionLayout.EMPTY
static final Dimension EMPTY
Empty dimension as fallback for.
Definition: DirectionLayout.java:76
net.sf.gridarta.gui.utils.DirectionLayout.cC
Component cC
Center Component.
Definition: DirectionLayout.java:159
net.sf.gridarta.model.direction.Direction.EAST
EAST
East.
Definition: Direction.java:38
net.sf.gridarta.gui.utils.DirectionLayout.addDirection
static void addDirection(@NotNull final Direction direction)
Adds an entry to DAIMONIN_TO_DIRECTION_MAP.
Definition: DirectionLayout.java:82
net.sf.gridarta.gui.utils.DirectionLayout.cW
Component cW
West Component.
Definition: DirectionLayout.java:152
net.sf.gridarta.gui.utils.DirectionLayout.hGap
final int hGap
Horizontal Gap.
Definition: DirectionLayout.java:90
net.sf.gridarta.gui.utils.DirectionLayout.getPreferredSize
static Dimension getPreferredSize(@Nullable final Component component)
Returns the preferred size of a component or EMPTY for.
Definition: DirectionLayout.java:349
net.sf.gridarta.model.direction.Direction.NORTH_EAST
NORTH_EAST
North east.
Definition: Direction.java:53
net.sf.gridarta.gui.utils.DirectionLayout.removeLayoutComponent
void removeLayoutComponent(@NotNull final Component comp)
Definition: DirectionLayout.java:253
net.sf.gridarta.model.direction.Direction.WEST
WEST
West.
Definition: Direction.java:48
net.sf.gridarta.gui.utils.DirectionLayout.getDirectionFromDaimonin
static Direction getDirectionFromDaimonin(final int daimoninDirection)
Returns the Direction for a Daimonin direction.
Definition: DirectionLayout.java:489
net.sf.gridarta.gui.utils.DirectionLayout.DAIMONIN_TO_DIRECTION_MAP
static final Direction[] DAIMONIN_TO_DIRECTION_MAP
The array to quickly find the direction enum constants for a daimonin direction.
Definition: DirectionLayout.java:56
net.sf.gridarta.model.direction
Definition: Direction.java:20
net.sf.gridarta.gui.utils.DirectionLayout.cSE
Component cSE
SouthEast Component.
Definition: DirectionLayout.java:131