001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.ui.swingViewer.basicRenderer; 033 034import java.awt.Color; 035import java.awt.Font; 036import java.awt.Graphics2D; 037import java.awt.geom.AffineTransform; 038import java.awt.geom.Point2D; 039 040import org.graphstream.graph.Element; 041import org.graphstream.ui.geom.Point3; 042import org.graphstream.ui.graphicGraph.GraphicElement; 043import org.graphstream.ui.graphicGraph.GraphicSprite; 044import org.graphstream.ui.graphicGraph.StyleGroup; 045import org.graphstream.ui.graphicGraph.StyleGroup.ElementEvents; 046import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants; 047import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.Units; 048import org.graphstream.ui.swingViewer.util.Camera; 049import org.graphstream.ui.swingViewer.util.FontCache; 050import org.graphstream.ui.swingViewer.util.DefaultCamera; 051 052public abstract class ElementRenderer { 053 // Attribute 054 055 /** 056 * Allow to know if an event began or ended. 057 */ 058 protected boolean hadEvents = false; 059 060 protected Font textFont; 061 062 protected Color textColor; 063 064 protected int textSize; 065 066 // Constructor 067 068 /** 069 * New swing element renderer for the given style group. 070 */ 071 public ElementRenderer() { 072 } 073 074 // Command 075 076 /** 077 * Render all the (visible) elements of the group. 078 */ 079 public void render(StyleGroup group, Graphics2D g, Camera camera) { 080 setupRenderingPass(group, g, camera); 081 pushStyle(group, g, camera); 082 083 for (Element e : group.bulkElements()) { 084 GraphicElement ge = (GraphicElement) e; 085 086 if (camera.isVisible(ge)) 087 renderElement(group, g, camera, ge); 088 else 089 elementInvisible(group, g, camera, ge); 090 } 091 092 if (group.hasDynamicElements()) { 093 for (Element e : group.dynamicElements()) { 094 GraphicElement ge = (GraphicElement) e; 095 096 if (camera.isVisible(ge)) { 097 if (!group.elementHasEvents(ge)) { 098 pushDynStyle(group, g, camera, ge); 099 renderElement(group, g, camera, ge); 100 } 101 } else { 102 elementInvisible(group, g, camera, ge); 103 } 104 } 105 } 106 107 if (group.hasEventElements()) { 108 for (ElementEvents event : group.elementsEvents()) { 109 GraphicElement ge = (GraphicElement) event.getElement(); 110 111 if (camera.isVisible(ge)) { 112 event.activate(); 113 pushStyle(group, g, camera); 114 renderElement(group, g, camera, ge); 115 event.deactivate(); 116 } else { 117 elementInvisible(group, g, camera, ge); 118 } 119 } 120 121 hadEvents = true; 122 } else { 123 hadEvents = false; 124 } 125 } 126 127 /** 128 * Called before the whole rendering pass for all elements. 129 * 130 * @param g 131 * The Swing graphics. 132 * @param camera 133 * The camera. 134 */ 135 protected abstract void setupRenderingPass(StyleGroup group, Graphics2D g, 136 Camera camera); 137 138 /** 139 * Called before the rendering of bulk and event elements. 140 * 141 * @param g 142 * The Swing graphics. 143 * @param camera 144 * The camera. 145 */ 146 protected abstract void pushStyle(StyleGroup group, Graphics2D g, 147 Camera camera); 148 149 /** 150 * Called before the rendering of elements on dynamic styles. This must only 151 * change the style properties that can change dynamically. 152 * 153 * @param g 154 * The Swing graphics. 155 * @param camera 156 * The camera. 157 * @param element 158 * The graphic element concerned by the dynamic style change. 159 */ 160 protected abstract void pushDynStyle(StyleGroup group, Graphics2D g, 161 Camera camera, GraphicElement element); 162 163 /** 164 * Render a single element knowing the style is already prepared. Elements 165 * that are not visible are not drawn. 166 * 167 * @param g 168 * The Swing graphics. 169 * @param camera 170 * The camera. 171 * @param element 172 * The element to render. 173 */ 174 protected abstract void renderElement(StyleGroup group, Graphics2D g, 175 Camera camera, GraphicElement element); 176 177 /** 178 * Called during rendering in place of 179 * {@link #renderElement(StyleGroup, Graphics2D, Camera, GraphicElement)} 180 * to signal that the given element is not inside the view. The 181 * renderElement() method will be called as soon as the element becomes 182 * visible anew. 183 * 184 * @param g 185 * The Swing graphics. 186 * @param camera 187 * The camera. 188 * @param element 189 * The element to render. 190 */ 191 protected abstract void elementInvisible(StyleGroup group, Graphics2D g, 192 Camera camera, GraphicElement element); 193 194 // Utility 195 196 protected void configureText(StyleGroup group, Camera camera) { 197 String fontName = group.getTextFont(); 198 StyleConstants.TextStyle textStyle = group.getTextStyle(); 199 200 textSize = (int) group.getTextSize().value; 201 textColor = group.getTextColor(0); 202 textFont = FontCache.defaultFontCache().getFont(fontName, textStyle, 203 textSize); 204 } 205 206 protected void renderText(StyleGroup group, Graphics2D g, Camera camera, 207 GraphicElement element) { 208 String label = element.getLabel(); 209 210 if (label != null && group.getTextMode() != StyleConstants.TextMode.HIDDEN 211 && group.getTextVisibilityMode() != StyleConstants.TextVisibilityMode.HIDDEN) { 212 213 Point3 p = null; 214 GraphicSprite s = null; 215 Point2D.Double pos = null; 216 217 if (element instanceof GraphicSprite) { 218 s = (GraphicSprite) element; 219 pos = ((DefaultCamera) camera).getSpritePosition(s, 220 new Point2D.Double(), StyleConstants.Units.GU); 221 } 222 223 if (pos != null && s.getUnits() == Units.PX) { 224 double w = camera.getMetrics().lengthToPx(group.getSize(), 225 0); 226 p = camera.transformGuToPx(pos.x, pos.y, 0); 227 p.x += w/2; 228 } else if (s != null && s.getUnits() == Units.PERCENTS) { 229 double w = camera.getMetrics().lengthToPx(group.getSize(), 230 0); 231 p = camera.transformGuToPx(camera.getMetrics().viewport[2] * pos.x, 232 camera.getMetrics().viewport[3] * pos.y, 0); 233 p.x += (w/2); 234 } else { 235 double w = camera.getMetrics().lengthToGu(group.getSize(), 236 0); 237 p = camera.transformGuToPx(element.getX() + (w / 2), element 238 .getY(), 0); 239 } 240 241 AffineTransform Tx = g.getTransform(); 242 Color c = g.getColor(); 243 244 g.setColor(textColor); 245 g.setFont(textFont); 246 g.setTransform(new AffineTransform()); 247 g.drawString(label, (float) p.x, (float) (p.y + textSize / 3)); // approximation 248 // to gain time. 249 g.setTransform(Tx); 250 g.setColor(c); 251 } 252 } 253 254 protected Color interpolateColor(StyleGroup group, GraphicElement element) { 255 Color color = group.getFillColor(0); 256 257 int n = group.getFillColorCount(); 258 259 if (n > 1) { 260 if (element.hasNumber("ui.color") && n > 1) { 261 double value = element.getNumber("ui.color"); 262 263 if (value < 0) 264 value = 0; 265 else if (value > 1) 266 value = 1; 267 268 if (value == 1) { 269 color = group.getFillColor(n - 1); // Simplification, 270 // faster. 271 } else if (value != 0) // If value == 0, color is already set 272 // above. 273 { 274 double div = 1f / (n - 1); 275 int col = (int) (value / div); 276 277 div = (value - (div * col)) / div; 278 // div = value / div - col; 279 280 Color color0 = group.getFillColor(col); 281 Color color1 = group.getFillColor(col + 1); 282 double red = ((color0.getRed() * (1 - div)) + (color1 283 .getRed() * div)) / 255f; 284 double green = ((color0.getGreen() * (1 - div)) + (color1 285 .getGreen() * div)) / 255f; 286 double blue = ((color0.getBlue() * (1 - div)) + (color1 287 .getBlue() * div)) / 255f; 288 double alpha = ((color0.getAlpha() * (1 - div)) + (color1 289 .getAlpha() * div)) / 255f; 290 291 color = new Color((float) red, (float) green, (float) blue, 292 (float) alpha); 293 } 294 } else if (element.hasAttribute("ui.color", Color.class)) { 295 color = element.getAttribute("ui.color"); 296 } 297 } else if (element.hasAttribute("ui.color", Color.class)) { 298 color = element.getAttribute("ui.color"); 299 } 300 301 return color; 302 } 303}