001/* Animation renderer. 002 003 Copyright (c) 1999-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.vergil.kernel; 029 030import java.awt.Color; 031import java.awt.Stroke; 032import java.util.Hashtable; 033 034import javax.swing.SwingUtilities; 035 036import diva.canvas.Figure; 037import diva.canvas.FigureContainer; 038import diva.canvas.FigureDecorator; 039import diva.canvas.interactor.SelectionRenderer; 040import diva.canvas.toolbox.BasicHighlighter; 041 042/////////////////////////////////////////////////////////////////// 043//// AnimationRenderer 044 045/** 046 An implementation of a selection renderer that is used for animation. 047 It highlights specified figures by wrapping them in an instance of 048 a FigureDecorator. The figure decorator is obtained by 049 cloning a prototype decorator, accessible through the 050 get/setFigureDecorator() methods. The default prototype 051 is an instance of BasicHighlighter that highlights in red. 052 <p> 053 This class is fashioned after BasicSelectionRenderer, but differs 054 in that it ensures that selection and deselection occurs in the event 055 thread. Also, it highlights objects in red rather than yellow. 056 057 @author Edward A. Lee 058 @version $Id$ 059 @since Ptolemy II 2.0 060 @Pt.ProposedRating Red (eal) 061 @Pt.AcceptedRating Red (johnr) 062 */ 063public class AnimationRenderer implements SelectionRenderer { 064 /** Create a new selection renderer with the default prototype 065 * decorator. 066 */ 067 public AnimationRenderer() { 068 this(Color.red); 069 } 070 071 /** Create a new selection renderer with the default prototype 072 * decorator using the specified color. 073 * @param color The color for the highlight. 074 */ 075 public AnimationRenderer(Color color) { 076 _prototypeDecorator = new BasicHighlighter(color, 6.0f); 077 } 078 079 /** Create a new selection renderer with the default prototype 080 * decorator using the specified color and halo size. 081 * @param color The color for the highlight. 082 * @param halo The halo size. 083 */ 084 public AnimationRenderer(Color color, float halo) { 085 _prototypeDecorator = new BasicHighlighter(color, halo); 086 } 087 088 /** Create a new selection renderer with the default prototype 089 * decorator using the specified color and stroke. This draws 090 * an outline rather than a filled shape. 091 * @param color The color for the highlight. 092 * @param stroke The stroke for the highlight. 093 */ 094 public AnimationRenderer(Color color, Stroke stroke) { 095 _prototypeDecorator = new BasicHighlighter(color, 4.0f, null, stroke); 096 } 097 098 /////////////////////////////////////////////////////////////////// 099 //// public methods //// 100 101 /** Create a new renderer with the given prototype decorator. 102 * @param decorator The prototype decorator. 103 */ 104 public AnimationRenderer(FigureDecorator decorator) { 105 _prototypeDecorator = decorator; 106 } 107 108 /** Get the prototype decorator. 109 * @return The prototype decorator. 110 * @see #setDecorator(FigureDecorator) 111 */ 112 public FigureDecorator getDecorator() { 113 return _prototypeDecorator; 114 } 115 116 /** Test whether the given figure is currently rendered highlighted. 117 * @param figure The figure that may be highlighted. 118 * @return True if the figure is highlighted. 119 */ 120 @Override 121 public synchronized boolean isRenderedSelected(Figure figure) { 122 return _decorators.containsKey(figure); 123 } 124 125 /** Set the rendering of the figure to not be highlighted. The figure 126 * has the decorator unwrapped off it and is inserted back into 127 * its parent figure container, if there is one. If the figure is 128 * not rendered highlighted, do nothing. 129 * The rendering is performed later in the event thread, 130 * and the calling thread is suspended by calling Thread.yield(), 131 * to give the event thread a chance to catch up. 132 * @param figure The figure to deselect. 133 */ 134 @Override 135 public void renderDeselected(final Figure figure) { 136 Runnable doUndecorate = new Runnable() { 137 @Override 138 public void run() { 139 synchronized (AnimationRenderer.this) { 140 if (!_decorators.containsKey(figure)) { 141 return; 142 } 143 144 // Rather than just get the parent of the 145 // figure, we must get the decorator out of 146 // the hashtable, since other wrappers may 147 // have been inserted between the figure and 148 // its decorator 149 FigureDecorator d = (FigureDecorator) _decorators 150 .get(figure); 151 152 if (d.getParent() != null) { 153 figure.repaint(); 154 ((FigureContainer) d.getParent()).undecorate(d); 155 } 156 157 _decorators.remove(figure); 158 } 159 } 160 }; 161 162 SwingUtilities.invokeLater(doUndecorate); 163 Thread.yield(); 164 } 165 166 /** Set the rendering of the figure as highlighted. If the figure is 167 * already rendered highlighted, just repaint. Otherwise create a new 168 * BasicHighlighter, and wrap the figure in the decorator, 169 * inserting the decorator into the figure's parent. 170 * The rendering is performed later in the event thread, 171 * and the calling thread is suspended by calling Thread.yield(), 172 * to give the event thread a chance to catch up. 173 * @param figure The figure to highlight. 174 */ 175 @Override 176 public void renderSelected(final Figure figure) { 177 Runnable doDecorate = new Runnable() { 178 @Override 179 public void run() { 180 synchronized (AnimationRenderer.this) { 181 if (_decorators.containsKey(figure)) { 182 ((Figure) _decorators.get(figure)).repaint(); 183 } else { 184 FigureContainer parent = (FigureContainer) figure 185 .getParent(); 186 if (parent != null) { 187 FigureDecorator d = _prototypeDecorator 188 .newInstance(figure); 189 parent.decorate(figure, d); 190 _decorators.put(figure, d); 191 } 192 } 193 } 194 } 195 }; 196 197 SwingUtilities.invokeLater(doDecorate); 198 Thread.yield(); 199 } 200 201 /** Set the prototype decorator. 202 * @param decorator The prototype decorator. 203 * @see #getDecorator() 204 */ 205 public void setDecorator(FigureDecorator decorator) { 206 _prototypeDecorator = decorator; 207 } 208 209 /////////////////////////////////////////////////////////////////// 210 //// protected variables //// 211 212 /** The prototype decorator. 213 */ 214 protected FigureDecorator _prototypeDecorator; 215 216 /////////////////////////////////////////////////////////////////// 217 //// private variables //// 218 219 /** Mapping from figures to decorators 220 */ 221 private Hashtable _decorators = new Hashtable(); 222}