001 /* 002 * Copyright 2007 - 2007 JEuclid, http://jeuclid.sf.net 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 /* $Id: AbstractRoot.java,v bc1d5fde7b73 2009/06/01 14:40:54 maxberger $ */ 018 019 package net.sourceforge.jeuclid.elements.presentation.general; 020 021 import java.awt.Color; 022 import java.awt.FontMetrics; 023 import java.awt.Graphics2D; 024 import java.util.List; 025 026 import net.sourceforge.jeuclid.LayoutContext; 027 import net.sourceforge.jeuclid.context.Parameter; 028 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement; 029 import net.sourceforge.jeuclid.elements.support.GraphicsSupport; 030 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper; 031 import net.sourceforge.jeuclid.layout.GraphicsObject; 032 import net.sourceforge.jeuclid.layout.LayoutInfo; 033 import net.sourceforge.jeuclid.layout.LayoutStage; 034 import net.sourceforge.jeuclid.layout.LayoutView; 035 import net.sourceforge.jeuclid.layout.LayoutableNode; 036 import net.sourceforge.jeuclid.layout.LineObject; 037 038 import org.apache.batik.dom.AbstractDocument; 039 import org.w3c.dom.mathml.MathMLRadicalElement; 040 041 /** 042 * common superclass for root like elements (root, sqrt). 043 * 044 * @version $Revision: bc1d5fde7b73 $ 045 */ 046 public abstract class AbstractRoot extends AbstractJEuclidElement implements 047 MathMLRadicalElement { 048 049 private static final String EXTRA_SPACE = "0.1ex"; 050 051 private static final String ROOT_WIDTH = "0.5em"; 052 053 /** 054 * Default constructor. Sets MathML Namespace. 055 * 056 * @param qname 057 * Qualified name. 058 * @param odoc 059 * Owner Document. 060 */ 061 public AbstractRoot(final String qname, final AbstractDocument odoc) { 062 super(qname, odoc); 063 } 064 065 /** 066 * retrieve the content of this radical element. 067 * 068 * @return A List<MathElement> with the contents for this element. 069 */ 070 protected abstract List<LayoutableNode> getContent(); 071 072 /** {@inheritDoc} */ 073 // CHECKSTYLE:OFF 074 // This function is too long, but it depends on too many parameters. 075 @Override 076 protected void layoutStageInvariant(final LayoutView view, 077 final LayoutInfo info, final LayoutStage stage, 078 final LayoutContext context) { 079 // CHECKSTYLE:ON 080 081 // Basic Calculations 082 final Graphics2D g = view.getGraphics(); 083 final LayoutContext now = this.applyLocalAttributesToContext(context); 084 final float middleShift = this.getMiddleShift(g, context); 085 final float linethickness = GraphicsSupport.lineWidth(now); 086 final float extraSpace = AttributesHelper.convertSizeToPt( 087 AbstractRoot.EXTRA_SPACE, now, ""); 088 final float rootwidth = AttributesHelper.convertSizeToPt( 089 AbstractRoot.ROOT_WIDTH, context, ""); 090 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR); 091 float xPos = linethickness; 092 final LayoutableNode index = (LayoutableNode) this.getIndex(); 093 final List<GraphicsObject> graphicObjects = info.getGraphicObjects(); 094 graphicObjects.clear(); 095 096 // Draw Index 097 float indexAscent; 098 if (index == null) { 099 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 // Skip Root Space 112 xPos += rootwidth; 113 114 // Draw Content below Root 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 // Fill in Info 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 // Add Root Glyph 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 }