Skip to content

Commit 73f802b

Browse files
authored
Merge pull request #5829 from kwvanderlinde/bugfix/5828-sync-corner-state--4726-token-opacity
Fix token state opacity and dot position
2 parents 4df49b6 + 54384c6 commit 73f802b

25 files changed

+993
-1175
lines changed

common/src/main/java/net/rptools/lib/AwtUtil.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package net.rptools.lib;
1616

1717
import java.awt.Dimension;
18+
import java.awt.geom.Rectangle2D;
1819

1920
public final class AwtUtil {
2021
private AwtUtil() {
@@ -48,4 +49,40 @@ public static void constrainTo(Dimension dim, int width, int height) {
4849
constrainTo(dim, size);
4950
}
5051
}
52+
53+
/**
54+
* Modifies {@code inner} so that it fits into {@code outer} and is centered within.
55+
*
56+
* <p>The aspect ration of {@code inner} is preserved, but this method will translate and scale it
57+
* as needed to fit within {@code other}.
58+
*
59+
* @param inner
60+
* @param outer
61+
*/
62+
public static void fitInto(Rectangle2D inner, Rectangle2D outer) {
63+
if (outer.getWidth() == 0 || outer.getHeight() == 0) {
64+
inner.setRect(outer);
65+
return;
66+
}
67+
68+
var widthRatio = outer.getWidth() / inner.getWidth();
69+
var heightRatio = outer.getHeight() / inner.getHeight();
70+
71+
boolean fitToWidth = widthRatio < heightRatio;
72+
double x, y, width, height;
73+
if (fitToWidth) {
74+
x = outer.getMinX();
75+
width = outer.getWidth();
76+
77+
height = inner.getHeight() * widthRatio;
78+
y = outer.getMinY() + (outer.getHeight() - height) / 2.;
79+
} else {
80+
y = outer.getMinY();
81+
height = outer.getHeight();
82+
83+
width = inner.getWidth() * heightRatio;
84+
x = outer.getMinX() + (outer.getWidth() - width) / 2.;
85+
}
86+
inner.setRect(x, y, width, height);
87+
}
5188
}

messages/src/main/proto/data_transfer_objects.proto

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -201,30 +201,68 @@ enum QuadrantDto {
201201
}
202202

203203
message BooleanTokenOverlayDto {
204-
enum BooleanTokenOverlayTypeDto {
204+
TokenOverlayDto common = 1;
205+
oneof child_type {
206+
ShapeTokenOverlayDto shape = 2;
207+
FlowShapeTokenOverlayDto flow_shape = 3;
208+
ColorDotTokenOverlayDto color_dot = 4;
209+
ImageTokenOverlayDto image = 5;
210+
CornerImageTokenOverlayDto corner_image = 6;
211+
FlowImageTokenOverlayDto flow_image = 7;
212+
ShadedTokenOverlayDto shaded = 8;
213+
}
214+
}
215+
216+
message ShapeTokenOverlayDto {
217+
enum TypeTag {
205218
X = 0;
206219
YIELD = 1;
207220
O = 2;
208-
COLOR_DOT = 3;
209-
DIAMOND = 4;
210-
TRIANGLE = 5;
211-
CROSS = 6;
212-
FLOW_COLOR_DOT = 7;
213-
FLOW_DIAMOND = 8;
214-
FLOW_COLOR_SQUARE = 9;
215-
FLOW_YIELD = 10;
216-
SHADED = 11;
217-
IMAGE = 12;
218-
FLOW_IMAGE = 13;
219-
CORNER_IMAGE = 14;
221+
DIAMOND = 3;
222+
TRIANGLE = 4;
223+
CROSS = 5;
220224
}
221-
TokenOverlayDto common = 1;
222-
int32 color = 2;
223-
StrokeDto stroke = 3;
224-
QuadrantDto quadrant = 4;
225-
int32 grid_size = 5;
226-
string asset_id = 6;
227-
BooleanTokenOverlayTypeDto type = 7;
225+
226+
int32 color = 1;
227+
float stroke_width = 2;
228+
TypeTag type = 3;
229+
}
230+
231+
message FlowShapeTokenOverlayDto {
232+
enum TypeTag {
233+
DOT = 0;
234+
SQUARE = 1;
235+
DIAMOND = 2;
236+
TRIANGLE = 3;
237+
YIELD = 4;
238+
}
239+
240+
int32 color = 1;
241+
int32 grid_size = 2;
242+
TypeTag type = 3;
243+
}
244+
245+
message ColorDotTokenOverlayDto {
246+
int32 color = 1;
247+
QuadrantDto quadrant = 2;
248+
}
249+
250+
message ImageTokenOverlayDto {
251+
string asset_id = 1;
252+
}
253+
254+
message CornerImageTokenOverlayDto {
255+
string asset_id = 1;
256+
QuadrantDto quadrant = 2;
257+
}
258+
259+
message FlowImageTokenOverlayDto {
260+
string asset_id = 1;
261+
int32 gridSize = 2;
262+
}
263+
264+
message ShadedTokenOverlayDto {
265+
int32 color = 1;
228266
}
229267

230268
message StrokeDto {
@@ -251,7 +289,6 @@ message LightSourceListDto {
251289
repeated LightSourceDto light_sources = 1;
252290
}
253291

254-
255292
enum WalkerMetricDto {
256293
NO_DIAGONALS = 0;
257294
MANHATTAN = 1;

src/main/java/net/rptools/maptool/client/ui/campaignproperties/TokenStatesController.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -512,41 +512,39 @@ public void valueChanged(ListSelectionEvent e) {
512512

513513
// Get most of the colors and all of the widths from the XTokenOverlay
514514
OverlayType type = OverlayType.Image;
515-
if (s instanceof XTokenOverlay) {
515+
if (s instanceof XTokenOverlay xTokenOverlay) {
516516
type = OverlayType.X;
517-
formPanel.getSpinner(WIDTH).setValue(((XTokenOverlay) s).getWidth());
518-
((ColorWell) formPanel.getComponent(COLOR)).setColor(((XTokenOverlay) s).getColor());
517+
formPanel.getSpinner(WIDTH).setValue(xTokenOverlay.getWidth());
518+
((ColorWell) formPanel.getComponent(COLOR)).setColor(xTokenOverlay.getColor());
519519
} // endif
520520

521521
// Get the the flow grid for most components from FlowColorDotTokenOverlay
522-
if (s instanceof FlowColorDotTokenOverlay) {
522+
if (s instanceof FlowColorDotTokenOverlay flowColorDotTokenOverlay) {
523523
type = OverlayType.GridDot;
524-
int size = ((FlowColorDotTokenOverlay) s).getGrid();
524+
int size = flowColorDotTokenOverlay.getGrid();
525525
formPanel.getSpinner(FLOW_GRID).setValue(size + "x" + size);
526526
} // endif
527527

528528
// Handle the
529-
if (s instanceof CornerImageTokenOverlay) {
529+
if (s instanceof CornerImageTokenOverlay cornerImageTokenOverlay) {
530530
type = OverlayType.CornerImage;
531531
formPanel
532532
.getComboBox(CORNER)
533-
.setSelectedIndex(((CornerImageTokenOverlay) s).getCorner().ordinal());
534-
} else if (s instanceof FlowImageTokenOverlay) {
533+
.setSelectedIndex(cornerImageTokenOverlay.getCorner().ordinal());
534+
} else if (s instanceof FlowImageTokenOverlay flowImageTokenOverlay) {
535535
type = OverlayType.GridImage;
536-
int size = ((FlowImageTokenOverlay) s).getGrid(); // Still need grid size
536+
int size = flowImageTokenOverlay.getGrid(); // Still need grid size
537537
formPanel.getSpinner(FLOW_GRID).setValue(size + "x" + size);
538538
} else if (s instanceof ImageTokenOverlay) {
539539
type = OverlayType.Image;
540-
} else if (s instanceof ColorDotTokenOverlay) {
540+
} else if (s instanceof ColorDotTokenOverlay colorDotTokenOverlay) {
541541
type = OverlayType.Dot;
542-
formPanel
543-
.getComboBox(CORNER)
544-
.setSelectedIndex(((ColorDotTokenOverlay) s).getCorner().ordinal());
542+
formPanel.getComboBox(CORNER).setSelectedIndex(colorDotTokenOverlay.getCorner().ordinal());
545543
} else if (s instanceof OTokenOverlay) {
546544
type = OverlayType.Circle;
547-
} else if (s instanceof ShadedTokenOverlay) {
545+
} else if (s instanceof ShadedTokenOverlay shadedTokenOverlay) {
548546
type = OverlayType.Shaded;
549-
((ColorWell) formPanel.getComponent(COLOR)).setColor(((ShadedTokenOverlay) s).getColor());
547+
((ColorWell) formPanel.getComponent(COLOR)).setColor(shadedTokenOverlay.getColor());
550548
} else if (s instanceof CrossTokenOverlay) {
551549
type = OverlayType.Cross;
552550
} else if (s instanceof DiamondTokenOverlay) {
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*
2+
* This software Copyright by the RPTools.net development team, and
3+
* licensed under the Affero GPL Version 3 or, at your option, any later
4+
* version.
5+
*
6+
* MapTool Source Code is distributed in the hope that it will be
7+
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
8+
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
*
10+
* You should have received a copy of the GNU Affero General Public
11+
* License * along with this source Code. If not, please visit
12+
* <http://www.gnu.org/licenses/> and specifically the Affero license
13+
* text at <http://www.gnu.org/licenses/agpl.html>.
14+
*/
15+
package net.rptools.maptool.client.ui.token;
16+
17+
import java.awt.BasicStroke;
18+
import java.awt.Color;
19+
import java.awt.Graphics2D;
20+
import java.awt.Rectangle;
21+
import java.awt.Shape;
22+
import java.awt.geom.Rectangle2D;
23+
import net.rptools.maptool.model.Token;
24+
import net.rptools.maptool.server.proto.FlowShapeTokenOverlayDto;
25+
import org.apache.logging.log4j.LogManager;
26+
import org.apache.logging.log4j.Logger;
27+
28+
public abstract sealed class AbstractFlowShapeTokenOverlay extends BooleanTokenOverlay
29+
permits FlowColorDotTokenOverlay,
30+
FlowDiamondTokenOverlay,
31+
FlowColorSquareTokenOverlay,
32+
FlowYieldTokenOverlay,
33+
FlowTriangleTokenOverlay {
34+
private static final Logger log = LogManager.getLogger(AbstractFlowShapeTokenOverlay.class);
35+
private static final Color DEFAULT_COLOR = Color.RED;
36+
private static final int DEFAULT_GRID_SIZE = 3;
37+
38+
/** Color used when filling the overlay shape. */
39+
private Color color;
40+
41+
/**
42+
* @deprecated This is a hold over from when FlowColorDotTokenOverlay (and by extension the other
43+
* flow shape overlays) inherited from XTokenOverlay. It didn't do anything then, and does
44+
* nothing now.
45+
*/
46+
@Deprecated private BasicStroke stroke;
47+
48+
/** Size of the grid used to place a token with this state. */
49+
private int grid;
50+
51+
/** Flow used to define position of states */
52+
private transient TokenOverlayFlow flow;
53+
54+
public AbstractFlowShapeTokenOverlay(String name, Color color, int gridSize) {
55+
super(name);
56+
57+
if (color == null) {
58+
color = DEFAULT_COLOR;
59+
}
60+
this.color = color;
61+
62+
if (gridSize <= 0) {
63+
gridSize = DEFAULT_GRID_SIZE;
64+
}
65+
this.grid = gridSize;
66+
}
67+
68+
public AbstractFlowShapeTokenOverlay(AbstractFlowShapeTokenOverlay other) {
69+
super(other);
70+
this.color = other.color;
71+
this.grid = other.grid;
72+
}
73+
74+
public final Color getColor() {
75+
return color;
76+
}
77+
78+
public final void setColor(Color color) {
79+
this.color = color;
80+
}
81+
82+
public final int getGrid() {
83+
return grid;
84+
}
85+
86+
/**
87+
* Get the flow used to position the states.
88+
*
89+
* @return Flow used to position the states
90+
*/
91+
protected final TokenOverlayFlow getFlow() {
92+
if (flow == null) {
93+
flow = TokenOverlayFlow.getInstance(grid);
94+
}
95+
return flow;
96+
}
97+
98+
@Override
99+
public final void paintOverlay(Graphics2D g, Token token, Rectangle bounds) {
100+
g.setColor(getColor());
101+
Rectangle2D gridCellBounds = getFlow().getStateBounds2D(bounds, token, getName());
102+
Shape s = getShape(getFlow().getStateBounds2D(bounds, token, getName()));
103+
g.fill(s);
104+
}
105+
106+
/**
107+
* Return the overlay's shape.
108+
*
109+
* @param bounds Bounds of the token
110+
* @param token Token being rendered.
111+
* @return The shape of to render for the overlay.
112+
*/
113+
@Deprecated
114+
public final Shape getShape(Rectangle bounds, Token token) {
115+
Rectangle2D gridCellBounds = getFlow().getStateBounds2D(bounds, token, getName());
116+
return getShape(gridCellBounds);
117+
}
118+
119+
public abstract Shape getShape(Rectangle2D bounds);
120+
121+
public final FlowShapeTokenOverlayDto toFlowShapeDto() {
122+
var dto = FlowShapeTokenOverlayDto.newBuilder();
123+
dto.setColor(color.getRGB());
124+
dto.setGridSize(grid);
125+
dto.setType(
126+
switch (this) {
127+
case FlowColorDotTokenOverlay ignored -> FlowShapeTokenOverlayDto.TypeTag.DOT;
128+
case FlowColorSquareTokenOverlay ignored -> FlowShapeTokenOverlayDto.TypeTag.SQUARE;
129+
case FlowDiamondTokenOverlay ignored -> FlowShapeTokenOverlayDto.TypeTag.DIAMOND;
130+
case FlowTriangleTokenOverlay ignored -> FlowShapeTokenOverlayDto.TypeTag.TRIANGLE;
131+
case FlowYieldTokenOverlay ignored -> FlowShapeTokenOverlayDto.TypeTag.YIELD;
132+
});
133+
return dto.build();
134+
}
135+
136+
public static AbstractFlowShapeTokenOverlay fromDto(FlowShapeTokenOverlayDto dto) {
137+
var color = new Color(dto.getColor(), true);
138+
var gridSize = dto.getGridSize();
139+
return switch (dto.getType()) {
140+
case DOT -> new FlowColorDotTokenOverlay(DEFAULT_STATE_NAME, color, gridSize);
141+
case SQUARE -> new FlowColorSquareTokenOverlay(DEFAULT_STATE_NAME, color, gridSize);
142+
case DIAMOND -> new FlowDiamondTokenOverlay(DEFAULT_STATE_NAME, color, gridSize);
143+
case TRIANGLE -> new FlowTriangleTokenOverlay(DEFAULT_STATE_NAME, color, gridSize);
144+
case YIELD -> new FlowYieldTokenOverlay(DEFAULT_STATE_NAME, color, gridSize);
145+
case UNRECOGNIZED -> {
146+
log.error("Unrecognized AbstractShapeOverlay type");
147+
yield null;
148+
}
149+
};
150+
}
151+
}

0 commit comments

Comments
 (0)