1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package net.sourceforge.jeuclid.elements.presentation.general;
20  
21  import java.awt.Color;
22  import java.awt.FontMetrics;
23  import java.awt.Graphics2D;
24  import java.util.List;
25  
26  import net.sourceforge.jeuclid.LayoutContext;
27  import net.sourceforge.jeuclid.context.Parameter;
28  import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
29  import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
30  import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
31  import net.sourceforge.jeuclid.layout.GraphicsObject;
32  import net.sourceforge.jeuclid.layout.LayoutInfo;
33  import net.sourceforge.jeuclid.layout.LayoutStage;
34  import net.sourceforge.jeuclid.layout.LayoutView;
35  import net.sourceforge.jeuclid.layout.LayoutableNode;
36  import net.sourceforge.jeuclid.layout.LineObject;
37  
38  import org.apache.batik.dom.AbstractDocument;
39  import org.w3c.dom.mathml.MathMLRadicalElement;
40  
41  
42  
43  
44  
45  
46  public abstract class AbstractRoot extends AbstractJEuclidElement implements
47          MathMLRadicalElement {
48  
49      private static final String EXTRA_SPACE = "0.1ex";
50  
51      private static final String ROOT_WIDTH = "0.5em";
52  
53      
54  
55  
56  
57  
58  
59  
60  
61      public AbstractRoot(final String qname, final AbstractDocument odoc) {
62          super(qname, odoc);
63      }
64  
65      
66  
67  
68  
69  
70      protected abstract List<LayoutableNode> getContent();
71  
72      
73      
74      
75      @Override
76      protected void layoutStageInvariant(final LayoutView view,
77              final LayoutInfo info, final LayoutStage stage,
78              final LayoutContext context) {
79          
80  
81          
82          final Graphics2D g = view.getGraphics();
83          final LayoutContext now = this.applyLocalAttributesToContext(context);
84          final float middleShift = this.getMiddleShift(g, context);
85          final float linethickness = GraphicsSupport.lineWidth(now);
86          final float extraSpace = AttributesHelper.convertSizeToPt(
87                  AbstractRoot.EXTRA_SPACE, now, "");
88          final float rootwidth = AttributesHelper.convertSizeToPt(
89                  AbstractRoot.ROOT_WIDTH, context, "");
90          final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
91          float xPos = linethickness;
92          final LayoutableNode index = (LayoutableNode) this.getIndex();
93          final List<GraphicsObject> graphicObjects = info.getGraphicObjects();
94          graphicObjects.clear();
95  
96          
97          float indexAscent;
98          if (index == null) {
99              indexAscent = 0.0f;
100         } else {
101             final LayoutInfo indexInfo = view.getInfo(index);
102             final float indexPos = middleShift + linethickness / 2.0f
103                     + extraSpace + indexInfo.getDescentHeight(stage);
104             indexInfo.moveTo(xPos, -indexPos, stage);
105             xPos += indexInfo.getWidth(stage);
106             graphicObjects.add(new LineObject(linethickness, -middleShift,
107                     xPos, -middleShift, linethickness, color));
108             indexAscent = indexPos + indexInfo.getAscentHeight(stage);
109         }
110 
111         
112         xPos += rootwidth;
113 
114         
115         final float contentStartX = xPos;
116         final FontMetrics metrics = this
117                 .getFontMetrics(view.getGraphics(), now);
118         float maxAscent = metrics.getAscent();
119         float maxDescent = metrics.getDescent();
120         for (final LayoutableNode child : this.getContent()) {
121             final LayoutInfo childInfo = view.getInfo(child);
122             childInfo.moveTo(xPos, 0, stage);
123             maxAscent = Math.max(maxAscent, childInfo.getAscentHeight(stage));
124             maxDescent = Math
125                     .max(maxDescent, childInfo.getDescentHeight(stage));
126             xPos += childInfo.getWidth(stage);
127         }
128         xPos += 2 * extraSpace;
129         final float topLinePos = maxAscent + 2 * extraSpace + linethickness
130                 / 2.0f;
131 
132         
133         info.setAscentHeight(Math.max(topLinePos + linethickness / 2.0f,
134                 indexAscent), stage);
135         info.setDescentHeight(maxDescent + linethickness / 2.0f, stage);
136         info.setHorizontalCenterOffset(xPos / 2.0f, stage);
137         info.setWidth(xPos + linethickness, stage);
138         info.setStretchAscent(maxAscent);
139         info.setStretchDescent(maxDescent);
140 
141         
142         graphicObjects.add(new LineObject(contentStartX - rootwidth,
143                 -middleShift, contentStartX - rootwidth / 2.0f, maxDescent,
144                 linethickness, color));
145         graphicObjects.add(new LineObject(contentStartX - rootwidth / 2.0f,
146                 maxDescent, contentStartX, -topLinePos, linethickness, color));
147         graphicObjects.add(new LineObject(contentStartX, -topLinePos, xPos,
148                 -topLinePos, linethickness, color));
149     }
150 }