Coverage Report - com.liquidatom.derbyscore.ui.ScoreboardWindow
 
Classes in this File Line Coverage Branch Coverage Complexity
ScoreboardWindow
0%
0/110
0%
0/24
1.824
 
 1  
 package com.liquidatom.derbyscore.ui;
 2  
 
 3  
 import com.liquidatom.derbyscore.domain.Bout;
 4  
 import com.liquidatom.derbyscore.domain.BoutListener;
 5  
 import com.liquidatom.derbyscore.theme.ImageElement;
 6  
 import com.liquidatom.derbyscore.theme.TextElement;
 7  
 import com.liquidatom.derbyscore.theme.Theme;
 8  
 import com.liquidatom.derbyscore.theme.ThemeElement;
 9  
 import com.liquidatom.derbyscore.theme.ThemeFactory;
 10  
 import java.awt.Color;
 11  
 import java.awt.Font;
 12  
 import java.awt.FontMetrics;
 13  
 import java.awt.Graphics;
 14  
 import java.awt.Graphics2D;
 15  
 import java.awt.GraphicsConfiguration;
 16  
 import java.awt.GraphicsEnvironment;
 17  
 import java.awt.Point;
 18  
 import java.awt.Rectangle;
 19  
 import java.awt.RenderingHints;
 20  
 import java.awt.Transparency;
 21  
 import java.awt.event.ComponentEvent;
 22  
 import java.awt.event.ComponentListener;
 23  
 import java.awt.geom.AffineTransform;
 24  
 import java.awt.geom.Rectangle2D;
 25  
 import java.awt.image.BufferStrategy;
 26  
 import java.awt.image.BufferedImage;
 27  
 import java.io.IOException;
 28  
 import java.net.URL;
 29  
 import java.util.Collection;
 30  
 import java.util.LinkedHashMap;
 31  
 import java.util.Map;
 32  
 import javax.imageio.ImageIO;
 33  
 import javax.swing.JFrame;
 34  
 import org.slf4j.Logger;
 35  
 import org.slf4j.LoggerFactory;
 36  
 
 37  
 /**
 38  
  *
 39  
  * @author Russell Francis (russ@metro-six.com)
 40  
  */
 41  
 public class ScoreboardWindow extends JFrame implements BoutListener, ComponentListener {
 42  
 
 43  0
     static private final Logger log = LoggerFactory.getLogger(ScoreboardWindow.class);
 44  
     static private final int DEFAULT_WINDOW_WIDTH = 800;
 45  
     static private final int DEFAULT_WINDOW_HEIGHT = 600;
 46  
     
 47  
     // cached copies for quick drawing and other useful rendering information.
 48  0
     private GraphicsConfiguration graphicsConfiguration =
 49  
             GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
 50  
 
 51  0
     private AffineTransform xform = AffineTransform.getTranslateInstance(0.0, 0.0);
 52  
     private Bout bout;
 53  0
     private Map<String, Object> scriptScope = new LinkedHashMap<String, Object>();
 54  
 
 55  
     public ScoreboardWindow(Bout bout) {
 56  0
         super(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration());
 57  0
         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 58  0
         setSize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
 59  0
         setLocationByPlatform(true);
 60  0
         setFocusTraversalKeysEnabled(false);
 61  
 // Fixes issue with scoreboard not redrawing itself when other windows are over top of it.
 62  
 //        setIgnoreRepaint(true);
 63  0
         addComponentListener(this);
 64  0
         this.getRootPane().setDoubleBuffered(true);
 65  
 
 66  
         try {
 67  0
             URL appLogo = getClass().getResource("/gfx/brrg.png");
 68  0
             setIconImage(ImageIO.read(appLogo));
 69  
         }
 70  0
         catch (IOException e) {
 71  0
             if (log.isWarnEnabled()) {
 72  0
                 log.warn("Unable to set window icon for scoreboard.");
 73  
             }
 74  0
         }
 75  
         
 76  0
         setBout(bout);
 77  0
     }
 78  
 
 79  
     @Override
 80  
     public void paint(Graphics parentGraphics) {
 81  0
         BufferStrategy strategy = getBufferStrategy();
 82  0
         if (strategy != null) {
 83  0
             Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
 84  
             try {
 85  
                 // fixes issue of showing the gray square.
 86  
                 //super.paint(g);
 87  0
                 Rectangle r = parentGraphics.getClipBounds();
 88  0
                 if (r != null) {
 89  0
                     g.setClip((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
 90  
                 }
 91  0
                 g.transform(xform);
 92  0
                 render(g);
 93  0
                 strategy.show();
 94  
             }
 95  
             finally {
 96  0
                 g.dispose();
 97  0
             }
 98  
         }
 99  0
     }
 100  
 
 101  
     protected void render(Graphics2D g) {
 102  0
         getBout().getPeriodClock().readLock().lock();
 103  
         try {
 104  0
             getBout().getJamClock().readLock().lock();
 105  
             try {
 106  0
                 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
 107  0
                 Collection<ThemeElement> elements = getTheme().getThemeElements();
 108  0
                 for (ThemeElement element : elements) {
 109  0
                     drawThemeElement(g, element);
 110  
                 }
 111  
             }
 112  
             finally {
 113  0
                 getBout().getJamClock().readLock().unlock();
 114  0
             }
 115  
         }
 116  
         finally {
 117  0
             getBout().getPeriodClock().readLock().unlock();
 118  0
         }
 119  0
     }
 120  
 
 121  
     protected void drawThemeElement(Graphics2D g, ThemeElement element) {
 122  0
         if (element.isVisible(getScriptScope())) {
 123  0
             if (element instanceof TextElement) {
 124  0
                 drawTextElement(g, (TextElement)element);
 125  
             }
 126  0
             else if (element instanceof ImageElement) {
 127  0
                 drawImageElement(g, (ImageElement)element);
 128  
             }
 129  
         }
 130  0
     }
 131  
 
 132  
     protected void drawTextElement(Graphics2D g, TextElement element) {
 133  0
         String text = element.getText(getScriptScope());
 134  0
         Font font = element.getFont();
 135  0
         Color color = element.getColor();
 136  
 
 137  0
         g.setFont(font);
 138  0
         g.setColor(color);
 139  0
         FontMetrics fontMetrics = g.getFontMetrics();
 140  0
         Rectangle2D bounds = fontMetrics.getStringBounds(text, g);
 141  0
         int width = (int) bounds.getWidth();
 142  0
         int height = (int) bounds.getHeight();
 143  0
         if (width > 0 && height > 0) {
 144  0
             BufferedImage textImage = getDefaultConfiguration().createCompatibleImage(width, height, Transparency.BITMASK);
 145  0
             Graphics2D textG = textImage.createGraphics();
 146  
             try {
 147  0
                 textG.setFont(font);
 148  0
                 textG.setColor(color);
 149  0
                 textG.drawString(text, 0, fontMetrics.getAscent());
 150  
 
 151  0
                 Rectangle position = element.getPosition();
 152  0
                 g.drawImage(textImage,
 153  
                         (int)position.getX(),
 154  
                         (int)position.getY(),
 155  
                         (int)position.getWidth(),
 156  
                         (int)position.getHeight(),
 157  
                         null);
 158  
             }
 159  
             finally {
 160  0
                 textG.dispose();
 161  0
             }
 162  
         }
 163  0
     }
 164  
 
 165  
     protected void drawImageElement(Graphics2D g, ImageElement element) {
 166  0
         BufferedImage image = getTheme().getImage(element.getImgRef());
 167  0
         if (image != null) {
 168  0
             Rectangle position = element.getPosition();
 169  0
             int x = (int) position.getX();
 170  0
             int y = (int) position.getY();
 171  0
             int width = (int) position.getWidth();
 172  0
             int height = (int) position.getHeight();
 173  0
             g.drawImage(image, x, y, width, height, null);
 174  
         }
 175  0
     }
 176  
 
 177  
     protected GraphicsConfiguration getDefaultConfiguration() {
 178  0
         return graphicsConfiguration;
 179  
     }
 180  
 
 181  
     protected void setScriptScope(Map<String, Object> scriptScope) {
 182  0
         if (scriptScope == null) {
 183  0
             throw new IllegalArgumentException("The parameter scriptScope must be non-null.");
 184  
         }
 185  0
         this.scriptScope = scriptScope;
 186  0
     }
 187  
 
 188  
     protected Map<String, Object> getScriptScope() {
 189  0
         return scriptScope;
 190  
     }
 191  
 
 192  
     protected Theme getTheme() {
 193  0
         return ThemeFactory.getInstance().getCurrent();
 194  
     }
 195  
 
 196  
     protected void setBout(Bout bout) {
 197  0
         this.bout = bout;
 198  0
         if (bout == null) {
 199  0
             scriptScope.remove("bout");
 200  
         }
 201  
         else {
 202  0
             scriptScope.put("bout", bout);
 203  
         }
 204  0
     }
 205  
 
 206  
     protected Bout getBout() {
 207  0
         return bout;
 208  
     }
 209  
 
 210  
     public void onChanged() {
 211  0
         repaint();
 212  0
     }
 213  
 
 214  
     public void componentResized(ComponentEvent e) {
 215  
         // Determine the translation which we must apply to render away from the window controls.
 216  0
         Point parentPoint = getLocationOnScreen();
 217  0
         Point childPoint = getContentPane().getLocationOnScreen();
 218  0
         double tx = childPoint.getX() - parentPoint.getX();
 219  0
         double ty = childPoint.getY() - parentPoint.getY();
 220  0
         AffineTransform transform = AffineTransform.getTranslateInstance(tx, ty);
 221  
 
 222  
         // Determine the scaling which must be applied to the text and images.
 223  0
         BufferedImage original = getTheme().getBackdrop();
 224  0
         int width = getContentPane().getWidth();
 225  0
         int height = getContentPane().getHeight();
 226  0
         double sx = (double)width / (double)original.getWidth();
 227  0
         double sy = (double)height / (double)original.getHeight();
 228  0
         transform.concatenate(AffineTransform.getScaleInstance(sx, sy));
 229  
 
 230  
         // Apply this transformation matrix to be used during rendering.
 231  0
         this.xform = transform;
 232  
 
 233  
         // Instruct the application to rerender the scoreboard.
 234  0
         repaint();
 235  0
     }
 236  
 
 237  
     public void componentMoved(ComponentEvent e) {
 238  0
     }
 239  
 
 240  
     public void componentShown(ComponentEvent e) {
 241  0
         createBufferStrategy(2);
 242  0
     }
 243  
 
 244  
     public void componentHidden(ComponentEvent e) {
 245  0
     }
 246  
 }