1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.layout.labeling;
29  
30  import y.view.DefaultLabelConfiguration;
31  import y.view.EdgeLabel;
32  import y.view.YLabel;
33  import y.view.YRenderingHints;
34  
35  import java.awt.BasicStroke;
36  import java.awt.Color;
37  import java.awt.Font;
38  import java.awt.Graphics2D;
39  import java.awt.Stroke;
40  import java.awt.geom.Ellipse2D;
41  import java.awt.geom.Line2D;
42  import java.awt.geom.Rectangle2D;
43  
44  /**
45   * A label painter that doesn't paint the label text but instead visualizes the label bounds by painting the
46   * up-vector and anchor point as well as indicators for the width and height of the label bounds.
47   */
48  class VisualizingBoundsLabelConfiguration extends DefaultLabelConfiguration {
49  
50    private static final Color COLOR_HEIGHT_INDICATOR = new Color(51, 102, 153);
51    private static final Color COLOR_WIDTH_INDICATOR = new Color(102, 204, 51);
52    private static final Color COLOR_UP_VECTOR = new Color(204, 153, 51);
53    private static final Color COLOR_ANCHOR_POINT = new Color(153, 51, 51);
54    private static final Color COLOR_LABEL_BACKGROUND = new Color(210, 210, 210);
55    private static final Color COLOR_LABEL_SELECTED = Color.RED;
56  
57    private static final Stroke STROKE_UNSELECTED = new BasicStroke(0.5f);
58    private static final Stroke STROKE_SELECTED = new BasicStroke(1f);
59  
60    private static final double DIAGONAL_THIN_STROKE_OFFSET = Math.sqrt(2) * 0.25;
61  
62    private static Font tinyFont;
63  
64  
65    public void paintContent(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
66      // we don't want to paint the label text
67    }
68  
69    public void paintBox(YLabel label, Graphics2D gfx, double x, double y, double width, double height) {
70      if (label instanceof EdgeLabel) {
71        final Stroke oldStroke = gfx.getStroke();
72        final Color oldColor = gfx.getColor();
73        final Font oldFont = gfx.getFont();
74  
75        try {
76          final double x2 = x + width;
77          final double y2 = y + height;
78          final double cx = x + width / 2;
79  
80          // we don't want to label our bounds description upside-down, so we check
81          // if we have to flip vertical and/or horizontal text
82          final boolean flipVerticalText = label.getOrientedBox().getUpX() < 0;
83          final boolean flipHorizontalText = label.getOrientedBox().getUpY() > 0;
84  
85          // fill background of the complete label bounds
86          gfx.setColor(COLOR_LABEL_BACKGROUND);
87          gfx.fill(new Rectangle2D.Double(x, y, width, height));
88  
89          gfx.setStroke(STROKE_UNSELECTED);
90          gfx.setFont(getTinyFont(gfx));
91  
92          // paint up vector
93          gfx.setColor(COLOR_UP_VECTOR);
94          gfx.draw(new Line2D.Double(x, y + 0.5, x, y2 - 0.25));
95          gfx.draw(new Line2D.Double(x, y + DIAGONAL_THIN_STROKE_OFFSET, x - 2, y + 2 + DIAGONAL_THIN_STROKE_OFFSET));
96          gfx.draw(new Line2D.Double(x, y + DIAGONAL_THIN_STROKE_OFFSET, x + 2, y + 2 + DIAGONAL_THIN_STROKE_OFFSET));
97  
98          // paint anchor point
99          gfx.setColor(COLOR_ANCHOR_POINT);
100         gfx.fill(new Ellipse2D.Double(x - 1, y2 - 1, 2, 2));
101 
102         // paint height indicator
103         gfx.setColor(COLOR_HEIGHT_INDICATOR);
104         gfx.draw(new Line2D.Double(cx, y + 0.5, cx, y2 - 0.5));
105 
106         gfx.draw(new Line2D.Double(cx, y + DIAGONAL_THIN_STROKE_OFFSET, cx - 2, y + 2 + DIAGONAL_THIN_STROKE_OFFSET));
107         gfx.draw(new Line2D.Double(cx, y + DIAGONAL_THIN_STROKE_OFFSET, cx + 2, y + 2 + DIAGONAL_THIN_STROKE_OFFSET));
108 
109         gfx.draw(new Line2D.Double(cx, y2 - DIAGONAL_THIN_STROKE_OFFSET, cx - 2, y2 - 2 - DIAGONAL_THIN_STROKE_OFFSET));
110         gfx.draw(new Line2D.Double(cx, y2 - DIAGONAL_THIN_STROKE_OFFSET, cx + 2, y2 - 2 - DIAGONAL_THIN_STROKE_OFFSET));
111 
112         if (flipVerticalText) {
113           gfx.rotate(Math.PI / 2, x, y);
114           gfx.drawString("height", (float) (x + 3), (float) (y - width / 2 + 4));
115           gfx.rotate(-Math.PI / 2, x, y);
116 
117         } else {
118           gfx.rotate(-Math.PI / 2, x, y);
119           gfx.drawString("height", (float) (x - height + 4), (float) (y + width / 2 - 2));
120           gfx.rotate(Math.PI / 2, x, y);
121         }
122 
123         // paint width indicator
124         gfx.setColor(COLOR_WIDTH_INDICATOR);
125         gfx.draw(new Line2D.Double(x + 0.5, y2, x2 - 0.5, y2));
126 
127         gfx.draw(new Line2D.Double(x + DIAGONAL_THIN_STROKE_OFFSET, y2, x + 2 + DIAGONAL_THIN_STROKE_OFFSET, y2 - 2));
128         gfx.draw(new Line2D.Double(x + DIAGONAL_THIN_STROKE_OFFSET, y2, x + 2 + DIAGONAL_THIN_STROKE_OFFSET, y2 + 2));
129 
130         gfx.draw(new Line2D.Double(x2 - DIAGONAL_THIN_STROKE_OFFSET, y2, x2 - 2 - DIAGONAL_THIN_STROKE_OFFSET, y2 - 2));
131         gfx.draw(new Line2D.Double(x2 - DIAGONAL_THIN_STROKE_OFFSET, y2, x2 - 2 - DIAGONAL_THIN_STROKE_OFFSET, y2 + 2));
132 
133         if (flipHorizontalText) {
134           gfx.rotate(-Math.PI, x + width / 2, y + height);
135           gfx.drawString("width", (float) (x + width / 2 - 5), (float) (y + height));
136           gfx.rotate(Math.PI, x + width / 2, y + height);
137         } else {
138           gfx.drawString("width", (float) (x + width / 2 - 5), (float) (y + height + 3));
139         }
140 
141         // draw selection box
142         if (useSelectionStyle(label, gfx)) {
143           gfx.setStroke(STROKE_SELECTED);
144           gfx.setColor(COLOR_LABEL_SELECTED);
145           gfx.draw(new Rectangle2D.Double(x, y, width, height));
146         }
147       } finally {
148         gfx.setFont(oldFont);
149         gfx.setStroke(oldStroke);
150         gfx.setColor(oldColor);
151       }
152     }
153   }
154 
155   private boolean useSelectionStyle(final YLabel label, final Graphics2D gfx) {
156     return label.isSelected() && YRenderingHints.isSelectionPaintingEnabled(gfx);
157   }
158 
159   private static Font getTinyFont(final Graphics2D gfx) {
160     if (tinyFont == null) {
161       final Font font = gfx.getFont();
162       tinyFont = new Font(font.getName(), font.getStyle(), 4);
163     }
164     return tinyFont;
165   }
166 }
167