1
28 package demo.layout.labeling;
29
30 import y.geom.YPoint;
31 import y.geom.YVector;
32 import y.layout.PreferredPlacementDescriptor;
33 import y.view.DefaultLabelConfiguration;
34 import y.view.EdgeLabel;
35 import y.view.YLabel;
36 import y.view.YRenderingHints;
37
38 import java.awt.Color;
39 import java.awt.Font;
40 import java.awt.GradientPaint;
41 import java.awt.Graphics2D;
42 import java.awt.Paint;
43 import java.awt.geom.Arc2D;
44 import java.awt.geom.GeneralPath;
45 import java.awt.geom.Line2D;
46
47
50 class VisualizingDescriptorLabelConfiguration extends DefaultLabelConfiguration {
51
52 private static final Color COLOR_ROTATION = new Color(51, 102, 153);
53 private static final Color COLOR_DISTANCE = new Color(102,204,51);
54 private static final Color COLOR_PREFERRED_SIDE = new Color(204, 153, 51);
55 private static final Color COLOR_ADDITIONAL_ROTATION = new Color(153, 51, 51);
56 private static final double TWO_PI = Math.PI * 2;
57
58 private static Font smallFont;
59
60 public void paintContent(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
61 final boolean flipText = label.getOrientedBox().getUpY() > 0;
63 try {
64 if (flipText) {
65 gfx.rotate(Math.PI, x + width/2-2, y + height/2);
66 }
67
68 super.paintContent(label, gfx, x, y, width, height);
69 } finally {
70 if (flipText) {
71 gfx.rotate(Math.PI, x + width/2-2, y + height/2);
72 }
73 }
74 }
75
76 public void paintBox(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
77 if (label instanceof EdgeLabel) {
78 final Color oldColor = gfx.getColor();
79 final Paint oldPaint = gfx.getPaint();
80 final Font oldFont = gfx.getFont();
81
82 try {
83 final double x2 = x + width;
84 final double y2 = y + height;
85 final double cx = x + width / 2;
86 final double cy = y + height / 2;
87
88 final PreferredPlacementDescriptor placementDescriptor = ((EdgeLabel) label).getPreferredPlacementDescriptor();
89 final double dist = Math.max(1, placementDescriptor.getDistanceToEdge());
90
91 final boolean labelFlowIsFlipped =
93 placementDescriptor.isRightOfEdge() && placementDescriptor.isAngleOffsetOnRightSide180();
94 final boolean angleRotationIsFlipped =
95 placementDescriptor.isRightOfEdge() && placementDescriptor.isAngleOnRightSideCounterRotating();
96
97 double angle = placementDescriptor.getAngle();
98 if (angleRotationIsFlipped) {
99 angle = -angle;
100 }
101
102 final double angleWithoutOffset = angle;
103 if (labelFlowIsFlipped) {
104 angle += Math.PI;
105 }
106
107 final GeneralPath labelShapePath = new GeneralPath();
109 labelShapePath.moveTo((float) x, (float) y);
110 labelShapePath.lineTo((float) (x2 - height / 4), (float) y);
111 labelShapePath.lineTo((float) x2, (float) cy);
112 labelShapePath.lineTo((float) (x2 - height / 4), (float) y2);
113 labelShapePath.lineTo((float) x, (float) y2);
114
115 gfx.setPaint(
117 new GradientPaint(
118 (float) x,
119 (float) y,
120 Color.white,
121 (float) (x + width + height / 2),
122 (float) y, COLOR_ROTATION, true));
123 gfx.fill(labelShapePath);
124
125 YVector rightVector = new YVector(width, 0);
126 rightVector = rightVector.rotate(-angle);
127
128 if (placementDescriptor.isAngleRelativeToEdgeFlow() && !placementDescriptor.isOnEdge()) {
130
133 double edgeAngle = -label.getOrientedBox().getAngle() - angle;
135 edgeAngle = normalizeAngle(edgeAngle);
136
137 final boolean labelIsLeftOfEdgeInFlow = isLabelLeftOfEdgeInFlow(placementDescriptor, edgeAngle);
138 final boolean bottomSideIsCloserToEdge = placementDescriptor.isLeftOfEdge()
140 ? labelIsLeftOfEdgeInFlow
141 : labelIsLeftOfEdgeInFlow ^ labelFlowIsFlipped;
142
143 final double yValue = bottomSideIsCloserToEdge ? y + height : y;
144 final YPoint cLabelBorder = new YPoint(cx, yValue);
146
147 final double distToEdge =
148 dist + Math.abs(rightVector.getY() / 2) - 0.5; YVector lineToEdge = new YVector(0, labelIsLeftOfEdgeInFlow ? distToEdge : -distToEdge);
152 lineToEdge = lineToEdge.rotate(-angle);
153
154 final YPoint cEdge = new YPoint(cLabelBorder.getX() + lineToEdge.getX(), cLabelBorder.getY() + lineToEdge.getY());
156
157 gfx.setColor(COLOR_DISTANCE);
158 gfx.fill(new Arc2D.Double(cLabelBorder.getX() - 2, cLabelBorder.getY() - 2, 4, 4, bottomSideIsCloserToEdge ? 0 : 180, -180, Arc2D.CHORD));
159
160 gfx.draw(new Line2D.Double(cLabelBorder.getX(), cLabelBorder.getY(), cEdge.getX(), cEdge.getY()));
161
162 gfx.fill(new Arc2D.Double(cEdge.getX() - 2, cEdge.getY() - 2, 4, 4, Math.toDegrees(angle), labelIsLeftOfEdgeInFlow ? 180 : -180, Arc2D.CHORD));
163 }
164
165 if (angleWithoutOffset != 0) {
167 gfx.setColor(COLOR_ROTATION);
170 if (labelFlowIsFlipped) {
171 gfx.draw(new Line2D.Double(x, y, x - rightVector.getX(), y - rightVector.getY()));
172 } else {
173 gfx.draw(new Line2D.Double(x, y, x + rightVector.getX(), y + rightVector.getY()));
174 }
175 gfx.draw(new Arc2D.Double(x - 10, y - 10, 20, 20, 0, angleWithoutOffset, Arc2D.OPEN));
177 }
178
179 if (labelFlowIsFlipped) {
181 gfx.setColor(COLOR_ADDITIONAL_ROTATION);
184 gfx.draw(new Line2D.Double(x, y, x + rightVector.getX()/2, y + rightVector.getY()/2));
185 gfx.draw(new Arc2D.Double(x - 5, y - 5, 10, 10, Math.toDegrees(angle), -180, Arc2D.OPEN));
188 }
189
190 gfx.setColor(COLOR_PREFERRED_SIDE);
192 gfx.setFont(getSmallFont(gfx));
193 gfx.rotate(-Math.PI/2, x, y);
194 final String position = isOnAnySide(placementDescriptor) ? "Any"
195 : placementDescriptor.isLeftOfEdge() ? "Left"
196 : placementDescriptor.isRightOfEdge() ? "Right"
197 : "OnEdge";
198 gfx.drawString(position, (float) (x - height + 1), (float) (y - 1));
199 gfx.rotate(Math.PI/2, x, y);
200
201 if (useSelectionStyle(label, gfx)) {
203 gfx.setColor(Color.RED);
204 gfx.draw(labelShapePath);
205 }
206 } finally {
207 gfx.setFont(oldFont);
209 gfx.setColor(oldColor);
210 gfx.setPaint(oldPaint);
211 }
212 }
213 }
214
215 private static double normalizeAngle(final double angle) {
216 return angle - TWO_PI * Math.floor(angle / TWO_PI);
217 }
218
219
220 private boolean isOnAnySide(final PreferredPlacementDescriptor placementDescriptor) {
221 return placementDescriptor.getSideOfEdge() ==
222 (PreferredPlacementDescriptor.PLACE_LEFT_OF_EDGE |
223 PreferredPlacementDescriptor.PLACE_ON_EDGE |
224 PreferredPlacementDescriptor.PLACE_RIGHT_OF_EDGE);
225 }
226
227 private boolean isLabelLeftOfEdgeInFlow(final PreferredPlacementDescriptor placementDescriptor, final double edgeAngle) {
228 if (placementDescriptor.isSideRelativeToEdgeFlow()) {
229 return placementDescriptor.isLeftOfEdge();
230 } else if (0 < edgeAngle && edgeAngle < Math.PI) {
231 return placementDescriptor.isRightOfEdge();
233 } else if (Math.PI < edgeAngle && edgeAngle < 2 * Math.PI) {
234 return placementDescriptor.isLeftOfEdge();
236 } else if (edgeAngle == 0) {
237 return placementDescriptor.isLeftOfEdge() ^ placementDescriptor.isSideAbsoluteWithRightInNorth();
239 } else {
240 return placementDescriptor.isLeftOfEdge() ^ placementDescriptor.isSideAbsoluteWithLeftInNorth();
242 }
243 }
244
245 private boolean useSelectionStyle(final YLabel label, final Graphics2D gfx) {
246 return label.isSelected() && YRenderingHints.isSelectionPaintingEnabled(gfx);
247 }
248
249 private Font getSmallFont(final Graphics2D gfx) {
250 if (smallFont == null) {
251 final Font font = gfx.getFont();
252 smallFont = new Font(font.getName(), font.getStyle(), 6);
253 }
254 return smallFont;
255 }
256 }
257