Merge branch 'feature/bufferedimage' into 'master'

Feature/bufferedimage

See merge request FlareMicrosystems/visualforecast-1000!1
This commit is contained in:
Flare Microsystems
2024-03-06 22:30:15 +00:00
45 changed files with 2684 additions and 245 deletions

View File

@@ -2,6 +2,6 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/> <classpathentry kind="src" path="resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@@ -1,11 +1,11 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -0,0 +1,37 @@
package com.flaremicro.flaretv.visualforecast;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.flaremicro.flaretv.visualforecast.interfaces.Tickable;
public class Executor {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final Tickable tickable;
private final long sleepNanos;
//private long nextTick = 0;
Executor(Tickable tickable, long sleepNanos) {
this.tickable = tickable;
this.sleepNanos = sleepNanos;
}
Executor(Tickable tickable, int ticksPerSecond) {
this(tickable, (long) ((1 / (double) ticksPerSecond) * 1000000000L));
}
public void end() {
scheduler.shutdown();
}
public void begin() {
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
tickable.tick();
}
}, 0, sleepNanos, TimeUnit.NANOSECONDS);
}
}

View File

@@ -0,0 +1,53 @@
package com.flaremicro.flaretv.visualforecast;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
import com.flaremicro.util.Util;
public class PropertyManager {
private final Properties underlyingProperties = new Properties();
private static File propFile = new File("./vf1000.properties");
public boolean load() {
Reader reader = null;
try
{
reader = new FileReader(propFile);
underlyingProperties.load(reader);
return true;
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(reader);
}
return false;
}
public boolean store() {
Writer writer = null;
try
{
writer = new FileWriter(propFile);
underlyingProperties.store(writer, "VisualForecast 1000 Properties file. Functional provider must be set for successful boot!");
return true;
}
catch (IOException e)
{
e.printStackTrace();
}
finally{
Util.cleanClose(writer);
}
return false;
}
}

View File

@@ -3,24 +3,29 @@ package com.flaremicro.flaretv.visualforecast;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GradientPaint; import java.awt.GradientPaint;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.Polygon; import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage; import java.awt.image.VolatileImage;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.concurrent.locks.LockSupport;
import javax.swing.JPanel; import javax.swing.JPanel;
import com.flaremicro.flaretv.visualforecast.icons.IconProvider; import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.*;
public class RenderPanel extends JPanel implements Runnable { import com.flaremicro.flaretv.visualforecast.flavour.DayForecastFlavour;
import com.flaremicro.flaretv.visualforecast.flavour.Flavour;
import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil;
import com.flaremicro.flaretv.visualforecast.graphics.FontManager;
import com.flaremicro.flaretv.visualforecast.interfaces.Tickable;
import com.flaremicro.flaretv.visualforecast.providerapi.MockForecastProvider;
public class RenderPanel extends JPanel implements Tickable, ComponentListener {
/** /**
* *
@@ -29,65 +34,32 @@ public class RenderPanel extends JPanel implements Runnable {
private VolatileImage frameBuffer = null; private VolatileImage frameBuffer = null;
/**
* Create the panel.
*/
private Color backgroundPurple = new Color(0x2b29b3);
private Color backgroundOrange = new Color(0xff8c00);
private Color backgroundBlue = new Color(0x394aa8);
private Font font = null; private Font font = null;
float fontMult = 20F; private Flavour currentFlavour = new DayForecastFlavour();
private int animationTick = 0; private int iconAnimationTicks = 0;
private long ticks = 0;
private String[] testString; private Rectangle redrawBound = new Rectangle(0, 0, 1, 1);
private Rectangle exclusiveRedrawBound = null;
private String currentTown = "";
private String currentForecast = "";
public RenderPanel() { public RenderPanel() {
try this.addComponentListener(this);
{ this.setDoubleBuffered(true);
font = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/Star4000.ttf")); font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
} currentFlavour.initFlavour(this, MockForecastProvider.provideMockForecast(), ticks, iconAnimationTicks);
catch (FontFormatException e) //new Thread(new TickThread(this, 30)).start();
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
testString = "The sandwiches at gas stations\nare disgusting, we advise you\ndo not eat them".split("\n");
new Thread(this).start();
} }
private static final int W = 640, H = 480; private Graphics2D prepareFrameBuffer() {
private static final int INFOBAR_HEIGHT = 80;
private static final int TOPBAR_HEIGHT = 80;
private static final int MAINBAR_HEIGHT = H - INFOBAR_HEIGHT - TOPBAR_HEIGHT;
private static final int HEADERBAR_Y = 20;
private static final double HEADERBAR_SHEAR = 0.2;
private static final int HEADERBAR_OFFSET = 20;
private static final int HEADERBAR_WIDTH = 400 + HEADERBAR_OFFSET;
private static final int HEADERBAR_HEIGHT = TOPBAR_HEIGHT - HEADERBAR_Y;
private static final int TIMEBAR_Y = 40;
private static final int TIMEBAR_OFFSET = 20;
private static final int TIMEBAR_WIDTH = 230 + HEADERBAR_OFFSET;
private static final int TIMEBAR_HEIGHT = TOPBAR_HEIGHT - TIMEBAR_Y;
private static final int STROKE_WIDTH = 2;
private static final int STROKE_OFFSET = STROKE_WIDTH / 2;
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMMM d");
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("hh:mm:ss a");
public Graphics2D prepareFrameBuffer() {
GraphicsConfiguration gc = this.getGraphicsConfiguration(); GraphicsConfiguration gc = this.getGraphicsConfiguration();
if (frameBuffer == null || frameBuffer.validate(gc) != VolatileImage.IMAGE_INCOMPATIBLE) if (frameBuffer == null || frameBuffer.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE)
{ {
System.out.println("new image req'd");
frameBuffer = gc.createCompatibleVolatileImage(W, H); frameBuffer = gc.createCompatibleVolatileImage(W, H);
} }
return (Graphics2D) frameBuffer.getGraphics(); return (Graphics2D) frameBuffer.getGraphics();
@@ -115,29 +87,41 @@ public class RenderPanel extends JPanel implements Runnable {
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
Graphics2D g2d = prepareFrameBuffer(); Graphics2D g2d = prepareFrameBuffer();
if (font == null)
font = g2d.getFont(); drawMainRegion(g2d);
if (currentFlavour != null)
{
if (this.getBounds().equals(g.getClipBounds()))
this.currentFlavour.drawFlavour(this, g2d, ticks, iconAnimationTicks);
if (g.getClipBounds() != null)
this.currentFlavour.drawBoundLimitedFlavour(this, g2d, g.getClipBounds(), ticks, iconAnimationTicks);
}
g2d.dispose();
g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this);
}
private void drawMainRegion(Graphics2D g2d) {
g2d.setFont(font.deriveFont(24F)); g2d.setFont(font.deriveFont(24F));
g2d.setStroke(new BasicStroke(2)); g2d.setStroke(new BasicStroke(2));
g2d.setColor(this.backgroundPurple); g2d.setColor(BG_PURPLE);
g2d.fillRect(0, 0, W, TOPBAR_HEIGHT); g2d.fillRect(0, 0, W, TOPBAR_HEIGHT);
g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, backgroundOrange, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), backgroundPurple)); g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_OORANGE, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE));
g2d.shear(HEADERBAR_SHEAR, 0); g2d.shear(HEADERBAR_SHEAR, 0);
g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT); g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT);
g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, backgroundPurple.brighter().brighter().brighter(), 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), backgroundPurple)); g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_PURPLE.brighter().brighter().brighter(), 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE));
g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT);
g2d.shear(-HEADERBAR_SHEAR, 0); g2d.shear(-HEADERBAR_SHEAR, 0);
g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, backgroundPurple, 0, MAINBAR_HEIGHT, backgroundOrange)); g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, BG_PURPLE, 0, MAINBAR_HEIGHT, BG_OORANGE));
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
g2d.setColor(this.backgroundBlue); g2d.setColor(BG_BLUE);
g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT); g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT);
g2d.setColor(Color.DARK_GRAY); g2d.setColor(Color.DARK_GRAY);
@@ -146,105 +130,123 @@ public class RenderPanel extends JPanel implements Runnable {
g2d.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET); g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET);
drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, backgroundBlue.brighter(), backgroundBlue.darker());
g2d.setColor(backgroundBlue.brighter());
g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH);
// g2d.setColor(Color.GRAY); // g2d.setColor(Color.GRAY);
// g2d.drawRect(60, TOPBAR_HEIGHT+2, W-120, MAINBAR_HEIGHT-4); // g2d.drawRect(60, TOPBAR_HEIGHT+2, W-120, MAINBAR_HEIGHT-4);
String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix(); String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix();
String timeString = TIME_FORMAT.format(System.currentTimeMillis()); String timeString = TIME_FORMAT.format(System.currentTimeMillis());
// g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, currentForecast, Color.WHITE, Color.BLACK, 2);
// RenderingHints.VALUE_ANTIALIAS_ON);
drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, "Your local forecast", Color.WHITE, Color.BLACK, 1);
int sw = g2d.getFontMetrics().stringWidth(dateString); int sw = g2d.getFontMetrics().stringWidth(dateString);
drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 1); DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 2);
sw = g2d.getFontMetrics().stringWidth(timeString); sw = g2d.getFontMetrics().stringWidth(timeString);
drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 1); DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 2);
g2d.setFont(font.deriveFont(36F)); g2d.setFont(font.deriveFont(36F));
drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, "New Westminster, BC", Color.YELLOW, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, currentTown, Color.YELLOW, Color.BLACK, 2);
int w2 = g2d.getFontMetrics().stringWidth("EXTREME WEATHER ADVISORY"); g2d.setFont(font.deriveFont(26F));
drawOutlinedString(g2d, (W >> 1) - (w2 >> 1), TOPBAR_HEIGHT + 48, "EXTREME WEATHER ADVISORY", Color.RED, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, -20, H - INFOBAR_HEIGHT + 30, "Welcome to WeatherBC! Stay tuned for your long range forcast", Color.WHITE, Color.BLACK, 2);
g2d.setFont(font.deriveFont(30F));
for (int i = 0; i < testString.length; i++)
{
drawOutlinedString(g2d, 90, TOPBAR_HEIGHT + 78 + 25 * i, testString[i], Color.WHITE, Color.BLACK, 1);
}
// g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
IconProvider.drawIcon(g2d, IconProvider.SNOWFLAKE, 80, 300, 80, animationTick);
IconProvider.drawIcon(g2d, IconProvider.CLOUD, 160, 300, 80, animationTick);
IconProvider.drawIcon(g2d, IconProvider.PARTLY_CLOUDY, 160 + 80, 300, 80, animationTick);
IconProvider.drawIcon(g2d, IconProvider.CLOUDY_CLOUDY, 160 + 160, 300, 80, animationTick);
IconProvider.drawIcon(g2d, IconProvider.RAIN, 160 + 160 + 80, 300, 80, animationTick);
IconProvider.drawIcon(g2d, IconProvider.SCATTERD_SHOWERS, 160 + 160 + 160, 300, 80, animationTick);
g2d.dispose();
g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this);
}
public void drawGradientRect(Graphics2D g, int x, int y, int w, int h, int borderWidth, Color innerColor, Color outerColor) {
g.setColor(innerColor);
g.fillRect(x, y, w, h);
g.setPaint(new GradientPaint(x, 0, outerColor, x + borderWidth, 0, innerColor));
g.fillRect(x, y, borderWidth, h);
g.setPaint(new GradientPaint(x + w - borderWidth, 0, innerColor, x + w, 0, outerColor));
g.fillRect(x + w - borderWidth, y, borderWidth, h);
g.setPaint(new GradientPaint(0, y, outerColor, 0, y + borderWidth, innerColor));
g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y, y, y + borderWidth, y + borderWidth }, 4));
g.fillRect(x, y, w, borderWidth);
g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y + h, y + h, y + h - borderWidth, y + h - borderWidth }, 4));
g.setPaint(new GradientPaint(0, y + h - borderWidth, innerColor, 0, y + h, outerColor));
g.fillRect(x, y + h - borderWidth, w, borderWidth);
g.setClip(null);
} }
public void drawOutlinedString(Graphics2D g2d, int x, int y, String text, Color textColor, Color outline, int outlineSize) { public void tick() {
g2d.setColor(outline); this.ticks++;
for (int i = 1; i <= outlineSize; i++) if (ticks / 3.75F > this.iconAnimationTicks)
{ {
g2d.drawString(text, x + i, y); this.iconAnimationTicks++;
g2d.drawString(text, x - i, y); //Clock and icon animations, should use repaint regions later
g2d.drawString(text, x, y + i); if (getWidth() > 0 && getHeight() > 0)
g2d.drawString(text, x, y - i); {
g2d.drawString(text, x + i, y + i); repaint(this.redrawBound);
g2d.drawString(text, x - i, y - i); }
g2d.drawString(text, x - i, y + i);
g2d.drawString(text, x + i, y - i);
} }
if (this.currentFlavour != null)
this.currentFlavour.tick(this, ticks, iconAnimationTicks);
}
g2d.setColor(textColor); public BufferedImage getSnapshot() {
g2d.drawString(text, x, y); return frameBuffer.getSnapshot();
/* }
* AffineTransform transform = g2d.getTransform();
* transform.translate(x, y); g2d.transform(transform); private void addRedrawBound(int x, int y, int w, int h, boolean isExclusive){
* g2d.setColor(outline); FontRenderContext frc =
* g2d.getFontRenderContext(); TextLayout tl = new TextLayout(text, float wScale = getWidth() / (float) W;
* g2d.getFont(), frc); Shape shape = tl.getOutline(null); float hScale = getHeight() / (float) H;
* g2d.setStroke(new BasicStroke(outlineSize)); g2d.draw(shape); Rectangle rect = new Rectangle((int) (x * wScale), (int) (y * hScale), (int) (w * wScale), (int) (h * hScale));
* g2d.setColor(textColor); g2d.fill(shape); if(isExclusive)
*/ this.exclusiveRedrawBound = rect;
if (redrawBound == null)
this.redrawBound = new Rectangle((int) (x * wScale), (int) (y * hScale), (int) (w * wScale), (int) (h * hScale));
else this.redrawBound.add(rect);
}
public void addRedrawBound(int x, int y, int w, int h) {
addRedrawBound(x, y, w, h, true);
} }
@Override @Override
public void componentResized(ComponentEvent e) {
loseRedrawRegion();
}
public void loseRedrawRegion() {
this.redrawBound = null;
addRedrawBound(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT, false);
if (this.currentFlavour != null)
this.currentFlavour.redrawRegionlost(this);
}
@Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
public void nextFlavour() {
this.currentFlavour = new DayForecastFlavour();
this.currentFlavour.initFlavour(this, MockForecastProvider.provideMockForecast(), ticks, iconAnimationTicks);
}
public void setCurrentTown(String currentTown){
this.currentTown = currentTown;
}
public void setCurrentForecast(String currentForecast){
this.currentForecast = currentForecast;
}
public void requestFullRepaint() {
repaint();
}
public void requestBoundedRepaint() {
repaint(redrawBound);
}
public void requestExclusiveBoundedRepaint() {
repaint(exclusiveRedrawBound);
}
/*@Override
public void run() { public void run() {
while (true) while (true)
{ {
this.animationTick++; this.iconAnimationTicks++;
repaint(); repaint();
LockSupport.parkNanos(125000000); LockSupport.parkNanos(125000000);
} }
} }*/
} }

View File

@@ -1,44 +0,0 @@
package com.flaremicro.flaretv.visualforecast;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
public class SmallTextInfo extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
/**
* Create the frame.
*/
public SmallTextInfo(RenderPanel rp) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 295, 93);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JSpinner spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(new Float(rp.fontMult), null, null, new Float(0.5F)));
spinner.setBounds(12, 12, 255, 22);
spinner.addChangeListener(new ChangeListener(){
@Override
public void stateChanged(ChangeEvent e) {
rp.fontMult = (Float)spinner.getValue();
rp.repaint();
}
});
contentPane.add(spinner);
}
}

View File

@@ -1,5 +1,7 @@
package com.flaremicro.flaretv.visualforecast; package com.flaremicro.flaretv.visualforecast;
import java.util.concurrent.locks.LockSupport;
import com.flaremicro.flaretv.visualforecast.interfaces.Tickable; import com.flaremicro.flaretv.visualforecast.interfaces.Tickable;
public class TickThread implements Runnable { public class TickThread implements Runnable {
@@ -7,20 +9,25 @@ public class TickThread implements Runnable {
private boolean running = true; private boolean running = true;
private final long sleepNanos; private final long sleepNanos;
private long nextTick = 0; //private long nextTick = 0;
TickThread(Tickable tickable, long sleepNanos) { TickThread(Tickable tickable, long sleepNanos) {
this.tickable = tickable; this.tickable = tickable;
this.sleepNanos = sleepNanos; this.sleepNanos = sleepNanos;
} }
TickThread(Tickable tickable, int ticksPerSecond) {
this(tickable, (long) ((1/(double)ticksPerSecond) * 1000000000L));
}
public void end() { public void end() {
this.running = false; this.running = false;
} }
public void run() { public void run() {
long nanosLost = 0;
while (running) { while (running) {
while(System.nanoTime() < nextTick) /*while(System.nanoTime() < nextTick)
{ {
try try
{ {
@@ -32,12 +39,13 @@ public class TickThread implements Runnable {
} }
} }
nextTick = System.nanoTime() + sleepNanos; nextTick = System.nanoTime() + sleepNanos;
tickable.tick();*/
tickable.tick(); tickable.tick();
/*long nanosLost = System.nanoTime();
panel.tick();
nanosLost -= System.nanoTime(); nanosLost -= System.nanoTime();
if(sleepNanos+nanosLost > 0) //Unnecessary conditional?
LockSupport.parkNanos(sleepNanos+nanosLost);*/ //if(sleepNanos+nanosLost > 0)
LockSupport.parkNanos(sleepNanos+nanosLost);
nanosLost = System.nanoTime();
} }
} }
} }

View File

@@ -2,16 +2,26 @@ package com.flaremicro.flaretv.visualforecast;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame; import javax.swing.JFrame;
public class VisualForecastFrame extends JFrame { import com.flaremicro.flaretv.visualforecast.providerapi.ForecastProviderManager;
public class VisualForecastFrame extends JFrame implements WindowListener, KeyListener{
/** /**
* *
*/ */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private RenderPanel contentPane; private RenderPanel renderPane;
private ForecastProviderManager forecastProviderManager;
private Executor executor;
private PropertyManager propertyManager;
private boolean isFullscreen = false;
/** /**
* Launch the application. * Launch the application.
@@ -22,6 +32,9 @@ public class VisualForecastFrame extends JFrame {
try { try {
VisualForecastFrame frame = new VisualForecastFrame(); VisualForecastFrame frame = new VisualForecastFrame();
frame.setVisible(true); frame.setVisible(true);
frame.init();
//GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[1].setFullScreenWindow(frame);
frame.createBufferStrategy(2);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -29,17 +42,108 @@ public class VisualForecastFrame extends JFrame {
}); });
} }
public void end()
{
if(executor != null)
executor.end();
}
public void init()
{
end();
executor = new Executor(this.renderPane, 30);
executor.begin();
forecastProviderManager = new ForecastProviderManager();
}
/** /**
* Create the frame. * Create the frame.
*/ */
public VisualForecastFrame() { public VisualForecastFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(100, 100, 640*2, 480*2); setBounds(100, 100, 640*2, 480*2);
contentPane = new RenderPanel(); renderPane = new RenderPanel();
contentPane.setBorder(null); renderPane.setBorder(null);
contentPane.setLayout(new BorderLayout(0, 0)); renderPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane); setContentPane(renderPane);
setUndecorated(true); setUndecorated(true);
addWindowListener(this);
addKeyListener(this);
}
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent e) {
end();
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_F11)
{
if(isFullscreen)
{
isFullscreen = false;
this.getGraphicsConfiguration().getDevice().setFullScreenWindow(null);
setBounds(100, 100, 640*2, 480*2);
}
else
{
isFullscreen = true;
this.getGraphicsConfiguration().getDevice().setFullScreenWindow(this);
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
} }
} }

View File

@@ -0,0 +1,283 @@
package com.flaremicro.flaretv.visualforecast.flavour;
import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.Locale;
import com.flaremicro.flaretv.visualforecast.RenderPanel;
import com.flaremicro.flaretv.visualforecast.forecast.DayForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ForecastDetails;
import com.flaremicro.flaretv.visualforecast.forecast.TownForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ValueCheck;
import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil;
import com.flaremicro.flaretv.visualforecast.graphics.FontManager;
import com.flaremicro.flaretv.visualforecast.graphics.RenderConstants;
import com.flaremicro.flaretv.visualforecast.icons.IconProvider;
public class DayForecastFlavour implements Flavour {
private int dayOffset = 0;
private Font font;
private Font smallFont;
private ForecastDetails details;
private TownForecast currentTown = null;
private TownForecast previousTown = null;
private int townIndex;
private BufferedImage mainBound = null;
private BufferedImage prevBound = null;
private int ticksBeforeChange = 200;
private int animationTicks = -1;
public DayForecastFlavour() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
smallFont = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000 Small.ttf"));
}
@Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) {
if(animationTicks >= 0)
{
animationTicks += 8;
if(animationTicks > RenderConstants.W - 60)
{
animationTicks = -1;
prevBound.flush();
prevBound = null;
renderer.requestFullRepaint();
renderer.loseRedrawRegion();
}
else renderer.requestExclusiveBoundedRepaint();
}
else
{
ticksBeforeChange--;
if (ticksBeforeChange < 0)
{
animationTicks = 0;
if(prevBound != null)
prevBound.flush();
if(mainBound != null)
mainBound.flush();
prevBound = renderer.getGraphicsConfiguration().createCompatibleImage(526, MAINBAR_HEIGHT - 28, Transparency.BITMASK);
mainBound = renderer.getGraphicsConfiguration().createCompatibleImage(526, MAINBAR_HEIGHT - 28, Transparency.BITMASK);
mainBound.setAccelerationPriority(1);
prevBound.setAccelerationPriority(1);
ticksBeforeChange = 200;
dayOffset = dayOffset + 4;
if (dayOffset >= 8)
{
dayOffset = 0;
townIndex++;
if (townIndex >= details.getTownForecast().length)
{
renderer.nextFlavour();
}
else
{
previousTown = currentTown;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
}
//Flicker workaround
BufferedImage throwaway = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g2d = throwaway.createGraphics();
this.drawFlavour(renderer, g2d, ticks, iconTicks);
g2d.dispose();
throwaway.flush();
renderer.loseRedrawRegion();
renderer.requestFullRepaint();
}
}
}
@Override
public void initFlavour(RenderPanel renderer, ForecastDetails details, long ticks, int iconTicks) {
this.details = details;
renderer.setCurrentForecast("7 Day Forecast");
if (details == null || details.getTownForecast() == null || details.getTownForecast().length <= 0)
this.details = null;
else
{
townIndex = 0;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
redrawRegionlost(renderer);
}
private String getDay(int offset) {
if (offset == 0)
return "Today";
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, offset * 24);
return cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US);
}
@Override
public void drawFlavour(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
if (details == null || currentTown == null || currentTown.getDayForecast() == null || currentTown.getDayForecast().length <= 0)
{
DrawingUtil.drawGradientRect(g2d, RenderConstants.SIDE_OFFSET + 80, RenderConstants.TOPBAR_HEIGHT + 90, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 160, (RenderConstants.TOPBAR_HEIGHT + 20), 10, new Color(0x220088), new Color(0x110055));
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + 60 + (RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 120) / 2 - (g2d.getFontMetrics().stringWidth("Forcast data") / 2), RenderConstants.TOPBAR_HEIGHT + 130, "Forecast data", Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + 60 + (RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 120) / 2 - (g2d.getFontMetrics().stringWidth("temporarily unavailable") / 2), RenderConstants.TOPBAR_HEIGHT + 160, "temporarily unavailable", Color.WHITE, Color.BLACK, 2);
}
else
{
if(animationTicks < 0)
{
drawTownForecast(g2d, currentTown, dayOffset);
}
else
{
Graphics2D gimg = prevBound.createGraphics();
Graphics2D gimg2 = mainBound.createGraphics();
gimg.translate(-RenderConstants.SIDE_OFFSET+1, -RenderConstants.TOPBAR_HEIGHT - 14);
gimg2.translate(-RenderConstants.SIDE_OFFSET+1, -RenderConstants.TOPBAR_HEIGHT - 14);
gimg.setStroke(new BasicStroke(2));
gimg2.setStroke(new BasicStroke(2));
if(dayOffset == 0)
{
drawTownForecast(gimg, previousTown, dayOffset + 4);
drawTownForecast(gimg2, currentTown, dayOffset);
} else {
drawTownForecast(gimg, currentTown, dayOffset - 4);
drawTownForecast(gimg2, currentTown, dayOffset);
}
gimg.dispose();
gimg2.dispose();
g2d.setClip(animationTicks + RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT+14, 526-animationTicks, MAINBAR_HEIGHT - 28);
g2d.drawImage(prevBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
g2d.setClip(0, RenderConstants.TOPBAR_HEIGHT+15, animationTicks, MAINBAR_HEIGHT - 28);
g2d.drawImage(mainBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
g2d.setClip(null);
}
}
if(animationTicks < 0)
{
mainBound = renderer.getSnapshot().getSubimage(RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, 526, MAINBAR_HEIGHT - 28);
mainBound.setAccelerationPriority(1);
}
}
private void drawTownForecast(Graphics2D g2d, TownForecast townForecast, int dayOffset)
{
for (int i = 0; i < Math.min(4, townForecast.getDayForecast().length - dayOffset); i++)
{
DayForecast forecast = townForecast.getDayForecast()[i + dayOffset];
g2d.setColor(RenderConstants.BG_BLUE.brighter().brighter());
g2d.fillRect(RenderConstants.SIDE_OFFSET + 131 * i, RenderConstants.TOPBAR_HEIGHT + 15, 127, MAINBAR_HEIGHT - 30);
g2d.setPaint(new GradientPaint(0, RenderConstants.TOPBAR_HEIGHT + 40, new Color(0x7777FF), 0, (RenderConstants.TOPBAR_HEIGHT + 40) + MAINBAR_HEIGHT - 60, new Color(0x0000BB)));
g2d.fillRoundRect(RenderConstants.SIDE_OFFSET + 5 + 131 * i, RenderConstants.TOPBAR_HEIGHT + 20, 117, MAINBAR_HEIGHT - 40, 10, 10);
g2d.setColor(Color.BLACK);
g2d.drawRoundRect(RenderConstants.SIDE_OFFSET + 5 + 131 * i, RenderConstants.TOPBAR_HEIGHT + 20, 117, MAINBAR_HEIGHT - 40, 10, 10);
g2d.drawRect(RenderConstants.SIDE_OFFSET + 131 * i, RenderConstants.TOPBAR_HEIGHT + 15, 127, MAINBAR_HEIGHT - 30);
String day = getDay(i + dayOffset);
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth(day) / 2), RenderConstants.TOPBAR_HEIGHT + 50, day, Color.WHITE, Color.BLACK, 2);
String statLine1;
String statLine2;
if (ValueCheck.valueNoData(forecast.weatherLine1))
{
statLine1 = "MISSING";
statLine2 = "DATA";
}
else
{
statLine1 = forecast.weatherLine1;
statLine2 = ValueCheck.valueNoData(forecast.weatherLine2) ? "" : forecast.weatherLine2;
}
FontMetrics metrics = g2d.getFontMetrics();
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (metrics.stringWidth(statLine1) / 2), RenderConstants.TOPBAR_HEIGHT + 170, statLine1, Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (metrics.stringWidth(statLine2) / 2), RenderConstants.TOPBAR_HEIGHT + 200, statLine2, Color.WHITE, Color.BLACK, 2);
if (!ValueCheck.valueNoData(forecast.hiTemp) && !ValueCheck.valueNoData(forecast.loTemp))
{
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 30 - (metrics.stringWidth(String.valueOf(forecast.hiTemp)) >> 1), RenderConstants.TOPBAR_HEIGHT + 295, String.valueOf(forecast.hiTemp), Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 92 - (metrics.stringWidth(String.valueOf(forecast.loTemp)) >> 1), RenderConstants.TOPBAR_HEIGHT + 295, String.valueOf(forecast.loTemp), Color.WHITE, Color.BLACK, 2);
g2d.setFont(smallFont.deriveFont(24F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 20, RenderConstants.TOPBAR_HEIGHT + 270, "Hi", Color.RED, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 82, RenderConstants.TOPBAR_HEIGHT + 270, "Lo", Color.CYAN, Color.BLACK, 2);
}
if (!ValueCheck.valueNoData(forecast.percipPercent))
{
String formattedPercent = String.format("%.2f%%", forecast.percipPercent);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth("Precip.") / 2), RenderConstants.TOPBAR_HEIGHT + 230, "Precip.", Color.YELLOW, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth(formattedPercent) / 2), RenderConstants.TOPBAR_HEIGHT + 245, formattedPercent, Color.WHITE, Color.BLACK, 2);
}
}
}
@Override
public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0)
{
if(animationTicks < 0)
{
g2d.drawImage(mainBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
else
{
g2d.setClip(animationTicks + RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT+14, 526, MAINBAR_HEIGHT - 28);
g2d.drawImage(prevBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
if(dayOffset == 0)
{
drawIcons(g2d, previousTown, dayOffset + 4, iconTicks);
g2d.setClip(0, RenderConstants.TOPBAR_HEIGHT+14, animationTicks, MAINBAR_HEIGHT - 28);
g2d.drawImage(mainBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
else
{
drawIcons(g2d, currentTown, dayOffset - 4, iconTicks);
g2d.setClip(0, RenderConstants.TOPBAR_HEIGHT+14, animationTicks, MAINBAR_HEIGHT - 28);
g2d.drawImage(mainBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
g2d.setClip(null);
}
}
}
private void drawIcons(Graphics2D g2d, TownForecast currentTown, int dayOffset, int iconTicks){
for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - dayOffset); i++)
{
DayForecast forecast = currentTown.getDayForecast()[i + dayOffset];
IconProvider.drawIcon(g2d, IconProvider.INDEXED_ICONS[forecast.iconId & IconProvider.INDEXED_ICONS.length - 1], RenderConstants.SIDE_OFFSET + (131 * i) + 24, RenderConstants.TOPBAR_HEIGHT + 60, 80, iconTicks);
}
}
@Override
public void redrawRegionlost(RenderPanel renderer) {
if(animationTicks >= 0)
renderer.addRedrawBound(0, RenderConstants.TOPBAR_HEIGHT, RenderConstants.W, RenderConstants.MAINBAR_HEIGHT);
else
renderer.addRedrawBound(RenderConstants.SIDE_OFFSET + 24, RenderConstants.TOPBAR_HEIGHT + 60, 604, 84);
}
}

View File

@@ -0,0 +1,261 @@
package com.flaremicro.flaretv.visualforecast.flavour;
import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.Locale;
import com.flaremicro.flaretv.visualforecast.RenderPanel;
import com.flaremicro.flaretv.visualforecast.forecast.DayForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ForecastDetails;
import com.flaremicro.flaretv.visualforecast.forecast.TownForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ValueCheck;
import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil;
import com.flaremicro.flaretv.visualforecast.graphics.FontManager;
import com.flaremicro.flaretv.visualforecast.graphics.RenderConstants;
import com.flaremicro.flaretv.visualforecast.icons.IconProvider;
public class DayForecastFlavourOldAnimation implements Flavour {
private int dayOffset = 0;
private Font font;
private Font smallFont;
private ForecastDetails details;
private TownForecast currentTown = null;
private TownForecast previousTown = null;
private int townIndex;
private BufferedImage lastBound = null;
private int ticksBeforeChange = 200;
private int animationTicks = -1;
public DayForecastFlavourOldAnimation() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
smallFont = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000 Small.ttf"));
}
@Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) {
if(animationTicks >= 0)
{
animationTicks += 8;
if(animationTicks > RenderConstants.W - 60)
{
animationTicks = -1;
renderer.requestFullRepaint();
renderer.loseRedrawRegion();
}
else renderer.requestExclusiveBoundedRepaint();
}
else
{
ticksBeforeChange--;
if (ticksBeforeChange < 0)
{
animationTicks = 0;
lastBound = renderer.getGraphicsConfiguration().createCompatibleImage(526*2+RenderConstants.SIDE_OFFSET, MAINBAR_HEIGHT - 28, Transparency.BITMASK);
lastBound.setAccelerationPriority(1);
ticksBeforeChange = 200;
dayOffset = dayOffset + 4;
if (dayOffset >= 8)
{
dayOffset = 0;
townIndex++;
if (townIndex >= details.getTownForecast().length)
{
renderer.nextFlavour();
}
else
{
previousTown = currentTown;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
}
renderer.loseRedrawRegion();
renderer.requestFullRepaint();
}
}
}
@Override
public void initFlavour(RenderPanel renderer, ForecastDetails details, long ticks, int iconTicks) {
this.details = details;
renderer.setCurrentForecast("7 Day Forecast");
if (details == null || details.getTownForecast() == null || details.getTownForecast().length <= 0)
this.details = null;
else
{
townIndex = 0;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
redrawRegionlost(renderer);
}
private String getDay(int offset) {
if (offset == 0)
return "Today";
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, offset * 24);
return cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US);
}
@Override
public void drawFlavour(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
if (details == null || currentTown == null || currentTown.getDayForecast() == null || currentTown.getDayForecast().length <= 0)
{
DrawingUtil.drawGradientRect(g2d, RenderConstants.SIDE_OFFSET + 80, RenderConstants.TOPBAR_HEIGHT + 90, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 160, (RenderConstants.TOPBAR_HEIGHT + 20), 10, new Color(0x220088), new Color(0x110055));
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + 60 + (RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 120) / 2 - (g2d.getFontMetrics().stringWidth("Forcast data") / 2), RenderConstants.TOPBAR_HEIGHT + 130, "Forecast data", Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + 60 + (RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 120) / 2 - (g2d.getFontMetrics().stringWidth("temporarily unavailable") / 2), RenderConstants.TOPBAR_HEIGHT + 160, "temporarily unavailable", Color.WHITE, Color.BLACK, 2);
}
else
{
if(animationTicks < 0)
{
drawTownForecast(g2d, currentTown, dayOffset);
}
else
{
Graphics2D gimg = lastBound.createGraphics();
gimg.translate(-RenderConstants.SIDE_OFFSET+1, -RenderConstants.TOPBAR_HEIGHT - 14);
gimg.setStroke(new BasicStroke(2));
if(dayOffset == 0)
{
drawTownForecast(gimg, previousTown, dayOffset + 4);
gimg.translate(RenderConstants.W - (RenderConstants.SIDE_OFFSET), 0);
drawTownForecast(gimg, currentTown, dayOffset);
gimg.translate(RenderConstants.SIDE_OFFSET - RenderConstants.W, 0);
} else {
drawTownForecast(gimg, currentTown, dayOffset - 4);
gimg.translate(RenderConstants.W - (RenderConstants.SIDE_OFFSET), 0);
drawTownForecast(gimg, currentTown, dayOffset);
gimg.translate(RenderConstants.SIDE_OFFSET - RenderConstants.W, 0);
}
gimg.dispose();
g2d.translate(-animationTicks, 0);
g2d.drawImage(lastBound, RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 15, renderer);
g2d.translate(animationTicks, 0);
}
}
if(animationTicks < 0)
{
lastBound = renderer.getSnapshot().getSubimage(RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, 526, MAINBAR_HEIGHT - 28);
lastBound.setAccelerationPriority(1);
}
}
private void drawTownForecast(Graphics2D g2d, TownForecast townForecast, int dayOffset)
{
for (int i = 0; i < Math.min(4, townForecast.getDayForecast().length - dayOffset); i++)
{
DayForecast forecast = townForecast.getDayForecast()[i + dayOffset];
g2d.setColor(RenderConstants.BG_BLUE.brighter().brighter());
g2d.fillRect(RenderConstants.SIDE_OFFSET + 131 * i, RenderConstants.TOPBAR_HEIGHT + 15, 127, MAINBAR_HEIGHT - 30);
g2d.setPaint(new GradientPaint(0, RenderConstants.TOPBAR_HEIGHT + 40, new Color(0x7777FF), 0, (RenderConstants.TOPBAR_HEIGHT + 40) + MAINBAR_HEIGHT - 60, new Color(0x0000BB)));
g2d.fillRoundRect(RenderConstants.SIDE_OFFSET + 5 + 131 * i, RenderConstants.TOPBAR_HEIGHT + 20, 117, MAINBAR_HEIGHT - 40, 10, 10);
g2d.setColor(Color.BLACK);
g2d.drawRoundRect(RenderConstants.SIDE_OFFSET + 5 + 131 * i, RenderConstants.TOPBAR_HEIGHT + 20, 117, MAINBAR_HEIGHT - 40, 10, 10);
g2d.drawRect(RenderConstants.SIDE_OFFSET + 131 * i, RenderConstants.TOPBAR_HEIGHT + 15, 127, MAINBAR_HEIGHT - 30);
String day = getDay(i + dayOffset);
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth(day) / 2), RenderConstants.TOPBAR_HEIGHT + 50, day, Color.WHITE, Color.BLACK, 2);
String statLine1;
String statLine2;
if (ValueCheck.valueNoData(forecast.weatherLine1))
{
statLine1 = "MISSING";
statLine2 = "DATA";
}
else
{
statLine1 = forecast.weatherLine1;
statLine2 = ValueCheck.valueNoData(forecast.weatherLine2) ? "" : forecast.weatherLine2;
}
FontMetrics metrics = g2d.getFontMetrics();
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (metrics.stringWidth(statLine1) / 2), RenderConstants.TOPBAR_HEIGHT + 170, statLine1, Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (metrics.stringWidth(statLine2) / 2), RenderConstants.TOPBAR_HEIGHT + 200, statLine2, Color.WHITE, Color.BLACK, 2);
if (!ValueCheck.valueNoData(forecast.hiTemp) && !ValueCheck.valueNoData(forecast.loTemp))
{
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 30 - (metrics.stringWidth(String.valueOf(forecast.hiTemp)) >> 1), RenderConstants.TOPBAR_HEIGHT + 295, String.valueOf(forecast.hiTemp), Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 92 - (metrics.stringWidth(String.valueOf(forecast.loTemp)) >> 1), RenderConstants.TOPBAR_HEIGHT + 295, String.valueOf(forecast.loTemp), Color.WHITE, Color.BLACK, 2);
g2d.setFont(smallFont.deriveFont(24F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 20, RenderConstants.TOPBAR_HEIGHT + 270, "Hi", Color.RED, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 82, RenderConstants.TOPBAR_HEIGHT + 270, "Lo", Color.CYAN, Color.BLACK, 2);
}
if (!ValueCheck.valueNoData(forecast.percipPercent))
{
String formattedPercent = String.format("%.2f%%", forecast.percipPercent);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth("Precip.") / 2), RenderConstants.TOPBAR_HEIGHT + 230, "Precip.", Color.YELLOW, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + (127 / 2) - (g2d.getFontMetrics().stringWidth(formattedPercent) / 2), RenderConstants.TOPBAR_HEIGHT + 245, formattedPercent, Color.WHITE, Color.BLACK, 2);
}
}
}
@Override
public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0)
{
if(animationTicks < 0)
{
g2d.drawImage(lastBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
else
{
g2d.translate(-animationTicks, 0);
g2d.drawImage(lastBound, RenderConstants.SIDE_OFFSET-1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
if(dayOffset == 0)
{
drawIcons(g2d, previousTown, dayOffset + 4, iconTicks);
g2d.translate(RenderConstants.W - (RenderConstants.SIDE_OFFSET), 0);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
else
{
drawIcons(g2d, currentTown, dayOffset - 4, iconTicks);
g2d.translate(RenderConstants.W - (RenderConstants.SIDE_OFFSET), 0);
drawIcons(g2d, currentTown, dayOffset, iconTicks);
}
g2d.translate(animationTicks + (RenderConstants.SIDE_OFFSET) - RenderConstants.W, 0);
}
}
}
private void drawIcons(Graphics2D g2d, TownForecast currentTown, int dayOffset, int iconTicks){
for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - dayOffset); i++)
{
DayForecast forecast = currentTown.getDayForecast()[i + dayOffset];
IconProvider.drawIcon(g2d, IconProvider.INDEXED_ICONS[forecast.iconId & IconProvider.INDEXED_ICONS.length - 1], RenderConstants.SIDE_OFFSET + (131 * i) + 24, RenderConstants.TOPBAR_HEIGHT + 60, 80, iconTicks);
}
}
@Override
public void redrawRegionlost(RenderPanel renderer) {
if(animationTicks >= 0)
renderer.addRedrawBound(0, RenderConstants.TOPBAR_HEIGHT, RenderConstants.W, RenderConstants.MAINBAR_HEIGHT);
else
renderer.addRedrawBound(RenderConstants.SIDE_OFFSET + 24, RenderConstants.TOPBAR_HEIGHT + 60, 604, 84);
}
}

View File

@@ -0,0 +1,15 @@
package com.flaremicro.flaretv.visualforecast.flavour;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import com.flaremicro.flaretv.visualforecast.RenderPanel;
import com.flaremicro.flaretv.visualforecast.forecast.ForecastDetails;
public interface Flavour {
public void tick(RenderPanel renderer, long ticks, int iconTicks);
public void initFlavour(RenderPanel renderer, ForecastDetails details, long ticks, int iconTicks);
public void drawFlavour(RenderPanel renderer, Graphics2D g, long ticks, int iconTicks);
public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g, Rectangle bounds, long ticks, int iconTicks);
public void redrawRegionlost(RenderPanel renderer);
}

View File

@@ -0,0 +1,61 @@
package com.flaremicro.flaretv.visualforecast.flavour;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import com.flaremicro.flaretv.visualforecast.RenderPanel;
import com.flaremicro.flaretv.visualforecast.forecast.ForecastDetails;
import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil;
import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.*;
public class TextFlavour implements Flavour{
public TextFlavour(String title, String scrollText)
{
/*
int w2 = g2d.getFontMetrics().stringWidth("EXTREME WEATHER ADVISORY");
drawOutlinedString(g2d, (W >> 1) - (w2 >> 1), TOPBAR_HEIGHT + 48, "EXTREME WEATHER ADVISORY", Color.RED, Color.BLACK, 2);
g2d.setFont(font.deriveFont(30F));
for (int i = 0; i < testString.length; i++)
{
drawOutlinedString(g2d, 90, TOPBAR_HEIGHT + 78 + 25 * i, testString[i], Color.WHITE, Color.BLACK, 1);
}
*/
}
@Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) {
// TODO Auto-generated method stub
}
@Override
public void initFlavour(RenderPanel renderer, ForecastDetails details, long ticks, int iconTicks) {
// TODO Auto-generated method stub
}
@Override
public void drawFlavour(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
DrawingUtil.drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, BG_BLUE.brighter(), BG_BLUE.darker());
g2d.setColor(BG_BLUE.brighter());
g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH);
}
@Override
public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
// TODO Auto-generated method stub
}
@Override
public void redrawRegionlost(RenderPanel renderer) {
// TODO Auto-generated method stub
}
}

View File

@@ -0,0 +1,19 @@
package com.flaremicro.flaretv.visualforecast.forecast;
public class DayForecast {
public byte hiTemp;
public byte loTemp;
public byte iconId;
public String weatherLine1;
public String weatherLine2;
public float percipPercent;
public DayForecast(byte hiTemp, byte loTemp, byte iconId, String weatherLine1, String weatherLine2, float percipPercent){
this.hiTemp = hiTemp;
this.loTemp = loTemp;
this.iconId = (byte)(iconId & 63);
this.weatherLine1 = weatherLine1;
this.weatherLine2 = weatherLine2;
this.percipPercent = percipPercent;
}
}

View File

@@ -0,0 +1,20 @@
package com.flaremicro.flaretv.visualforecast.forecast;
public class ForecastDetails {
//Perhaps could be hashmap?
private TownForecast[] towns;
public ForecastDetails(){
}
public void setTownForecast(TownForecast[] towns){
this.towns = towns;
}
public TownForecast[] getTownForecast()
{
return towns;
}
}

View File

@@ -0,0 +1,19 @@
package com.flaremicro.flaretv.visualforecast.forecast;
public class TownForecast {
public TownForecast(String townName, DayForecast[] dayForecast){
this.townName = townName;
this.dayForecast = dayForecast;
}
private final String townName;
private final DayForecast[] dayForecast;
public DayForecast[] getDayForecast() {
return dayForecast;
}
public String getTownName() {
return townName;
}
}

View File

@@ -0,0 +1,45 @@
package com.flaremicro.flaretv.visualforecast.forecast;
public class ValueCheck {
//Utility for no data
public static final byte NO_DATA_BYTE = Byte.MIN_VALUE;
public static final short NO_DATA_SHORT = Short.MIN_VALUE;
public static final int NO_DATA_INT = Integer.MIN_VALUE;
public static final long NO_DATA_LONG = Long.MIN_VALUE;
public static final float NO_DATA_FLOAT = Float.NaN;
public static final double NO_DATA_DOUBLE = Double.NaN;
public static final boolean valueNoData(byte f)
{
return f == NO_DATA_BYTE;
}
public static final boolean valueNoData(short f)
{
return f == NO_DATA_SHORT;
}
public static final boolean valueNoData(int f)
{
return f == NO_DATA_INT;
}
public static final boolean valueNoData(long f)
{
return f == NO_DATA_LONG;
}
public static final boolean valueNoData(float f)
{
return Float.isInfinite(f) || Float.isNaN(f);
}
public static final boolean valueNoData(double d)
{
return Double.isInfinite(d) || Double.isNaN(d);
}
public static final boolean valueNoData(Object o)
{
return o == null;
}
}

View File

@@ -0,0 +1,76 @@
package com.flaremicro.flaretv.visualforecast.graphics;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Polygon;
public class DrawingUtil {
public static void drawGradientRect(Graphics2D g, int x, int y, int w, int h, int borderWidth, Color innerColor, Color outerColor) {
g.setColor(innerColor);
g.fillRect(x, y, w, h);
g.setPaint(new GradientPaint(x, 0, outerColor, x + borderWidth, 0, innerColor));
g.fillRect(x, y, borderWidth, h);
g.setPaint(new GradientPaint(x + w - borderWidth, 0, innerColor, x + w, 0, outerColor));
g.fillRect(x + w - borderWidth, y, borderWidth, h);
g.setPaint(new GradientPaint(0, y, outerColor, 0, y + borderWidth, innerColor));
g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y, y, y + borderWidth, y + borderWidth }, 4));
g.fillRect(x, y, w, borderWidth);
g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y + h, y + h, y + h - borderWidth, y + h - borderWidth }, 4));
g.setPaint(new GradientPaint(0, y + h - borderWidth, innerColor, 0, y + h, outerColor));
g.fillRect(x, y + h - borderWidth, w, borderWidth);
g.setClip(null);
}
public static void drawOutlinedString(Graphics2D g2d, int x, int y, String text, Color textColor, Color outline, int outlineSize) {
g2d.setColor(outline);
for (int i = 1; i <= outlineSize; i++)
{
g2d.drawString(text, x + i, y);
g2d.drawString(text, x - i, y);
g2d.drawString(text, x, y + i);
g2d.drawString(text, x, y - i);
g2d.drawString(text, x + i, y + i);
g2d.drawString(text, x - i, y - i);
g2d.drawString(text, x - i, y + i);
g2d.drawString(text, x + i, y - i);
}
g2d.setColor(textColor);
g2d.drawString(text, x, y);
/*
* AffineTransform transform = g2d.getTransform();
* transform.translate(x, y); g2d.transform(transform);
* g2d.setColor(outline); FontRenderContext frc =
* g2d.getFontRenderContext(); TextLayout tl = new TextLayout(text,
* g2d.getFont(), frc); Shape shape = tl.getOutline(null);
* g2d.setStroke(new BasicStroke(outlineSize)); g2d.draw(shape);
* g2d.setColor(textColor); g2d.fill(shape);
*/
}
public static void drawOutlinedString(Graphics2D g2d, int x, int y, String text, Color textColor, Color outline, int outlineSize, float outlineStep) {
g2d.setColor(outline);
for (int i = 1; i <= outlineSize; i++)
{
g2d.drawString(text, x + i*outlineStep, y);
g2d.drawString(text, x - i*outlineStep, y);
g2d.drawString(text, x, y + i*outlineStep);
g2d.drawString(text, x, y - i*outlineStep);
g2d.drawString(text, x + i*outlineStep, y + i*outlineStep);
g2d.drawString(text, x - i*outlineStep, y - i*outlineStep);
g2d.drawString(text, x - i*outlineStep, y + i*outlineStep);
g2d.drawString(text, x + i*outlineStep, y - i*outlineStep);
}
g2d.setColor(textColor);
g2d.drawString(text, x, y);
}
}

View File

@@ -0,0 +1,107 @@
package com.flaremicro.flaretv.visualforecast.graphics;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FontManager {
private final Font baseFont;
private static FontManager instance = null;
private Map<URL, Integer> urlToFontMapping = new HashMap<URL, Integer>();
private List<Font> fonts = new ArrayList<Font>();
private FontManager() {
BufferedImage bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY);
Graphics g = bufferedImage.createGraphics();
baseFont = g.getFont();
g.dispose();
}
public static FontManager getInstance() {
if (instance == null)
{
instance = new FontManager();
}
return instance;
}
public Font getFont(int fontId){
if(fontId < 0 || fontId >= fonts.size())
return baseFont;
else return fonts.get(fontId);
}
public Font getFont(URL fontResource){
Integer i = urlToFontMapping.get(fontResource);
if(i == null)
return baseFont;
else return fonts.get(i);
}
public int getFontID(URL fontResource){
Integer i = urlToFontMapping.get(fontResource);
if(i == null)
return -1;
else return i;
}
public Font getOrCreateFont(int fontFormat, URL fontResource)
{
if(fontResource == null)
return baseFont.deriveFont(Font.PLAIN);
int i = getOrPrepareFont(fontFormat, fontResource);
return fonts.get(i);
}
public int getOrPrepareFont(int fontFormat, URL fontResource)
{
Integer i = urlToFontMapping.get(fontResource);
if(i == null)
{
Font f = baseFont.deriveFont(Font.PLAIN);
if(fontResource == null)
return -1;
InputStream stream = null;
try
{
stream = fontResource.openStream();
f = Font.createFont(fontFormat, stream);
}
catch (IOException e)
{
e.printStackTrace();
}
catch (FontFormatException e)
{
e.printStackTrace();
}
finally{
if(stream != null)
try
{
stream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
synchronized(fonts)
{
i = fonts.size();
fonts.add(f);
urlToFontMapping.put(fontResource, i);
}
}
return i;
}
}

View File

@@ -0,0 +1,36 @@
package com.flaremicro.flaretv.visualforecast.graphics;
import java.awt.Color;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class RenderConstants {
public static final int W = 640, H = 480;
public static final int INFOBAR_HEIGHT = 80;
public static final int TOPBAR_HEIGHT = 80;
public static final int MAINBAR_HEIGHT = H - INFOBAR_HEIGHT - TOPBAR_HEIGHT;
public static final int HEADERBAR_Y = 20;
public static final double HEADERBAR_SHEAR = 0.2;
public static final int HEADERBAR_OFFSET = 20;
public static final int HEADERBAR_WIDTH = 400 + HEADERBAR_OFFSET;
public static final int HEADERBAR_HEIGHT = TOPBAR_HEIGHT - HEADERBAR_Y;
public static final int TIMEBAR_Y = 40;
public static final int TIMEBAR_OFFSET = 20;
public static final int TIMEBAR_WIDTH = 230 + HEADERBAR_OFFSET;
public static final int TIMEBAR_HEIGHT = TOPBAR_HEIGHT - TIMEBAR_Y;
public static final int STROKE_WIDTH = 2;
public static final int STROKE_OFFSET = STROKE_WIDTH / 2;
public static final int SIDE_OFFSET = 60;
public static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMMM d");
public static final DateFormat TIME_FORMAT = new SimpleDateFormat("hh:mm:ss a");
public static final Color BG_PURPLE = new Color(0x2b29b3);
public static final Color BG_OORANGE = new Color(0xff8c00);
public static final Color BG_BLUE = new Color(0x394aa8);
}

View File

@@ -2,6 +2,13 @@ package com.flaremicro.flaretv.visualforecast.icons;
import java.awt.Graphics2D; import java.awt.Graphics2D;
public interface Icon { public abstract class Icon {
public void drawIcon(Graphics2D g2d, float scale, int animationStep);
public Icon(int i){
this.id = (byte)i;
}
public final byte id;
public abstract boolean isAnimated();
public abstract void drawIcon(Graphics2D g2d, float scale, int animationStep);
} }

View File

@@ -3,39 +3,79 @@ package com.flaremicro.flaretv.visualforecast.icons;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import com.flaremicro.flaretv.visualforecast.icons.impl.BlizzardIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.ButterIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.CloudIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.FogIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.IceCubeIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.InvalidIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.LightningIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.LightningOverlay;
import com.flaremicro.flaretv.visualforecast.icons.impl.LightningStormIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.PartlyCloudyIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.RainIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.RainSnowIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.SmallCloudIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.SnowIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.SnowflakeIcon;
import com.flaremicro.flaretv.visualforecast.icons.impl.SunIcon;
public class IconProvider { public class IconProvider {
public static int SUN = 0; public static final Icon[] INDEXED_ICONS = new Icon[64];
public static int CLOUD = 1;
public static int PARTLY_CLOUDY = 2;
public static int CLOUDY_CLOUDY = 3;
public static int RAIN = 4;
public static int SCATTERD_SHOWERS = 5;
public static int SNOWFLAKE = 6;
public static final Icon INVALID = registerIcon(setMainIcon(new InvalidIcon(0)));
public static final Icon SUN = registerIcon(new SunIcon(1));
public static final Icon CLOUD = registerIcon(new CloudIcon(2));
public static final Icon PARTLY_CLOUDY = registerIcon(new PartlyCloudyIcon(3, CLOUD, SUN));
public static final Icon CLOUDY_CLOUDY = registerIcon(new PartlyCloudyIcon(4, CLOUD, CLOUD));
public static final Icon RAIN_LIGHTEST = registerIcon(new RainIcon(5, 2, 2F, CLOUD));
public static final Icon RAIN_LIGHT = registerIcon(new RainIcon(6, 3, 2F, CLOUD));
public static final Icon RAIN = registerIcon(new RainIcon(7, 3, 1F, CLOUD));
public static final Icon RAIN_HEAVY = registerIcon(new RainIcon(8, 4, 1F, CLOUD));
public static final Icon RAIN_HEAVIEST = registerIcon(new RainIcon(9, 5, 1F, CLOUD));
public static final Icon RAIN_VANCOUVER = registerIcon(new RainIcon(10, 6, 1F, CLOUD));
public static final Icon SCATTERD_SHOWERS = registerIcon(new PartlyCloudyIcon(11, new RainIcon(-1, 2, 4F, CLOUD), SUN));
public static final Icon SNOWFLAKE = registerIcon(new SnowflakeIcon(12));
public static final Icon SNOW = registerIcon(new SnowIcon(13, CLOUD, SNOWFLAKE));
public static final Icon BLIZZARD = registerIcon(new BlizzardIcon(14, CLOUD, SNOWFLAKE));
public static final Icon RAIN_SNOW = registerIcon(new RainSnowIcon(15, RAIN_LIGHTEST, SNOWFLAKE, true));
public static final Icon FREEZING_RAIN = registerIcon(new RainSnowIcon(16, RAIN_LIGHT, SNOWFLAKE, false));
public static final Icon LIGHTNING_BOLT = registerIcon(new LightningIcon(17));
public static final Icon LIGHTNING_STORM = registerIcon(new LightningStormIcon(18, CLOUD, LIGHTNING_BOLT));
public static final Icon SMALL_CLOUD = registerIcon(new SmallCloudIcon(19));
public static final Icon LIGHTNING_BLIZZARD = registerIcon(new LightningOverlay(20, SMALL_CLOUD, LIGHTNING_BOLT, BLIZZARD));
public static final Icon SCATTERD_THUNDERSTORMS = registerIcon(new PartlyCloudyIcon(21, LIGHTNING_STORM, SUN));
public static final Icon FOG = registerIcon(new FogIcon(22, CLOUD));
public static final Icon ICE_CUBE = registerIcon(new IceCubeIcon(23));
public static final Icon HAIL = registerIcon(new BlizzardIcon(24, CLOUD, ICE_CUBE));
public static final Icon BUTTER = registerIcon(new ButterIcon(25));
public static final Icon BUTTER_RAIN = registerIcon(new BlizzardIcon(26, CLOUD, BUTTER));
//public static final Icon INVALID_RAIN = registerIcon(new LightningOverlay(27, SUN, BUTTER, new BlizzardIcon(-1, LIGHTNING_BOLT, INVALID)));
private static final Icon[] CLASS_DEFS = new Icon[64]; private static Icon registerIcon(Icon icon)
{
static{ INDEXED_ICONS[icon.id] = icon;
CLASS_DEFS[SUN] = new SunIcon(); return icon;
CLASS_DEFS[CLOUD] = new CloudIcon();
CLASS_DEFS[PARTLY_CLOUDY] = new PartlyCloudyIcon(CLASS_DEFS[CLOUD], CLASS_DEFS[SUN]);
CLASS_DEFS[CLOUDY_CLOUDY] = new PartlyCloudyIcon(CLASS_DEFS[CLOUD], CLASS_DEFS[CLOUD]);
CLASS_DEFS[RAIN] = new RainIcon(2, 1F, CLASS_DEFS[CLOUD]);
CLASS_DEFS[SCATTERD_SHOWERS] = new PartlyCloudyIcon(new RainIcon(2, 4F, CLASS_DEFS[CLOUD]), CLASS_DEFS[SUN]);
CLASS_DEFS[SNOWFLAKE] = new SnowflakeIcon();
} }
public static void drawIcon(Graphics2D g2d, int icon, int x, int y, int scale, int animationStep) private static Icon setMainIcon(Icon icon) {
for(int i = 0; i < INDEXED_ICONS.length; i++){
INDEXED_ICONS[i] = icon;
}
return icon;
}
public static void drawIcon(Graphics2D g2d, Icon icon, int x, int y, int scale, int animationStep)
{ {
if(icon >= 0 && CLASS_DEFS.length > icon) if(icon != null)
{ {
AffineTransform af = g2d.getTransform(); AffineTransform af = g2d.getTransform();
g2d.translate(x, y); g2d.translate(x, y);
g2d.scale(scale, scale); g2d.scale(scale, scale);
//1g2d.setColor(Color.RED); //1g2d.setColor(Color.RED);
//g2d.fill(new Rectangle2D.Float(0, 0, 1F, 1F)); //g2d.fill(new Rectangle2D.Float(0, 0, 1F, 1F));
CLASS_DEFS[icon].drawIcon(g2d, scale, animationStep); icon.drawIcon(g2d, scale, animationStep);
g2d.setTransform(af); g2d.setTransform(af);
} }
} }

View File

@@ -0,0 +1,51 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class BlizzardIcon extends Icon {
private final Icon cloudIcon;
private final Icon snowflakeIcon;
public BlizzardIcon(int id, Icon cloudIcon, Icon snowflakeIcon)
{
super(id);
this.cloudIcon = cloudIcon;
this.snowflakeIcon = snowflakeIcon;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
AffineTransform af = g2d.getTransform();
g2d.scale(0.25F, 0.25F);
g2d.translate(0, 3);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep);
g2d.translate(1, -1);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+1);
g2d.translate(1, 1);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+2);
g2d.translate(1, -1);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+3);
g2d.setTransform(af);
g2d.translate(0F, -0.10F);
g2d.scale(1F, 0.8F);
cloudIcon.drawIcon(g2d, scale, animationStep);
g2d.setTransform(af);
g2d.translate(0.3F, 0);
g2d.scale(0.7F, 0.7F);
snowflakeIcon.drawIcon(g2d, scale*0.7F, animationStep+4);
g2d.setTransform(af);
}
@Override
public boolean isAnimated() {
return cloudIcon.isAnimated() || snowflakeIcon.isAnimated();
}
}

View File

@@ -0,0 +1,106 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class ButterIcon extends Icon {
Path2D.Float iceOutline = new Path2D.Float();
Path2D.Float[] iceFaces = new Path2D.Float[3];
Path2D.Float[] iceShines = new Path2D.Float[3];
Color[] iceFaceColors = new Color[] {
new Color(0xfff8a0),
new Color(0xfff14c),
new Color(0xccbc00),
};
Color[] iceShineAnimation = new Color[] {
new Color(0xFFFFFF),
};
public ButterIcon(int id) {
super(id);
iceOutline.moveTo(0F, 0.161F);
iceOutline.lineTo(0.542F, 0F);
iceOutline.lineTo(1.0F, 0.093F);
iceOutline.lineTo(1.0F, 0.441F);
iceOutline.lineTo(0.489F, 0.650F);
iceOutline.lineTo(0.0F, 0.531F);
iceOutline.closePath();
iceFaces[1] = new Path2D.Float();
iceFaces[1].moveTo(0F, 0.161F);
iceFaces[1].lineTo(0.542F, 0F);
iceFaces[1].lineTo(1.0F, 0.093F);
iceFaces[1].lineTo(0.489F, 0.263F);
iceFaces[1].closePath();
iceFaces[2] = new Path2D.Float();
iceFaces[2].moveTo(0.489F, 0.263F);
iceFaces[2].lineTo(1.0F, 0.093F);
iceFaces[2].lineTo(1.0F, 0.441F);
iceFaces[2].lineTo(0.489F, 0.650F);
iceFaces[2].closePath();
iceFaces[0] = new Path2D.Float();
iceFaces[0].moveTo(0.0F, 0.161F);
iceFaces[0].lineTo(0.489F, 0.263F);
iceFaces[0].lineTo(0.489F, 0.650F);
iceFaces[0].lineTo(0.0F, 0.531F);
iceFaces[0].closePath();
iceShines[1] = new Path2D.Float();
iceShines[1].moveTo(0.537F, 0.013F);
iceShines[1].lineTo(0.930F, 0.099F);
iceShines[1].lineTo(0.673F, 0.185F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.742F, 0.086);
iceShines[1].closePath();
iceShines[2] = new Path2D.Float();
iceShines[2].moveTo(0.981F, 0.134F);
iceShines[2].lineTo(0.981F, 0.423F);
iceShines[2].lineTo(0.515F, 0.624F);
iceShines[2].lineTo(0.571F, 0.557F);
iceShines[2].lineTo(0.915F, 0.372F);
iceShines[2].closePath();
iceShines[0] = new Path2D.Float();
iceShines[0].moveTo(0.018F, 0.187F);
iceShines[0].lineTo(0.205F, 0.229F);
iceShines[0].lineTo(0.060F, 0.249F);
iceShines[0].lineTo(0.044F, 0.475F);
iceShines[0].lineTo(0.021F, 0.508F);
iceShines[0].closePath();
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(4 / scale));
g2d.translate(0F, 0.325F);
g2d.setColor(Color.BLACK);
g2d.draw(iceOutline);
for(int i = 0; i < iceFaces.length; i++)
{
g2d.setColor(iceFaceColors[i]);
g2d.fill(iceFaces[i]);
g2d.setColor(iceShineAnimation[(i+animationStep) % iceShineAnimation.length]);
g2d.fill(iceShines[i]);
}
g2d.translate(0F, -0.325F);
}
@Override
public boolean isAnimated() {
return false;
}
}

View File

@@ -1,12 +1,14 @@
package com.flaremicro.flaretv.visualforecast.icons; package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
public class CloudIcon implements Icon { import com.flaremicro.flaretv.visualforecast.icons.Icon;
Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{
public class CloudIcon extends Icon {
private final Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{
new Ellipse2D.Float(0, 0.5F, 0.28F, 0.325F), new Ellipse2D.Float(0, 0.5F, 0.28F, 0.325F),
new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F), new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F),
new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F), new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F),
@@ -18,21 +20,21 @@ public class CloudIcon implements Icon {
}; };
Ellipse2D.Float[] extraStroke = new Ellipse2D.Float[]{ private final Ellipse2D.Float[] extraStroke = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F), new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F),
new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F) new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F)
}; };
Ellipse2D.Float[] overStroke = new Ellipse2D.Float[]{ private final Ellipse2D.Float[] overStroke = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.233F, 0.150F, 0.369F, 0.677F), new Ellipse2D.Float(0.233F, 0.150F, 0.369F, 0.677F),
new Ellipse2D.Float(0.113F, 0.326F, 0.266F, 0.356F), new Ellipse2D.Float(0.113F, 0.326F, 0.266F, 0.356F),
new Ellipse2D.Float(0.749F, 0.412F, 0.251F, 0.417F), new Ellipse2D.Float(0.749F, 0.412F, 0.251F, 0.417F),
new Ellipse2D.Float(0.652F, 0.555F, 0.150F, 0.136F), new Ellipse2D.Float(0.652F, 0.555F, 0.150F, 0.136F),
}; };
Ellipse2D.Float[] lightCircles = new Ellipse2D.Float[]{ private final Ellipse2D.Float[] lightCircles = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.309F, 0.173F, 0.209F, 0.235F), new Ellipse2D.Float(0.309F, 0.173F, 0.209F, 0.235F),
new Ellipse2D.Float(0.554F, 0.276F, 0.204F, 0.314F), new Ellipse2D.Float(0.554F, 0.276F, 0.204F, 0.314F),
new Ellipse2D.Float(0.770F, 0.440F, 0.204F, 0.235F), new Ellipse2D.Float(0.770F, 0.440F, 0.204F, 0.235F),
@@ -40,7 +42,7 @@ public class CloudIcon implements Icon {
new Ellipse2D.Float(0.259F, 0.460F, 0.314F, 0.235F), new Ellipse2D.Float(0.259F, 0.460F, 0.314F, 0.235F),
}; };
Ellipse2D.Float[] overLight = new Ellipse2D.Float[]{ private final Ellipse2D.Float[] overLight = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.328F, 0.188F, 0.209F, 0.235F), new Ellipse2D.Float(0.328F, 0.188F, 0.209F, 0.235F),
new Ellipse2D.Float(0.573F, 0.296F, 0.204F, 0.314F), new Ellipse2D.Float(0.573F, 0.296F, 0.204F, 0.314F),
new Ellipse2D.Float(0.789F, 0.456F, 0.204F, 0.235F), new Ellipse2D.Float(0.789F, 0.456F, 0.204F, 0.235F),
@@ -48,6 +50,10 @@ public class CloudIcon implements Icon {
new Ellipse2D.Float(0.288F, 0.476F, 0.314F, 0.235F), new Ellipse2D.Float(0.288F, 0.476F, 0.314F, 0.235F),
}; };
public CloudIcon(int id)
{
super(id);
}
@Override @Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) { public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
@@ -86,4 +92,10 @@ public class CloudIcon implements Icon {
} }
@Override
public boolean isAnimated() {
return false;
}
} }

View File

@@ -0,0 +1,69 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class FogIcon extends Icon {
private final Icon cloudIcon;
private Path2D fogPath = new Path2D.Float();
Color[] aniColor = {
new Color(0xC0C0C0),
new Color(0xC8C8C8),
new Color(0xD0D0D0),
new Color(0xD8D8D8),
new Color(0xD0D0D0),
new Color(0xC8C8C8),
new Color(0xC0C0C0),
new Color(0xB8B8B8),
new Color(0xB0B0B0),
new Color(0xA8A8A8),
new Color(0xB0B0B0),
new Color(0xB8B8B8),
};
public FogIcon(int id, Icon cloudIcon)
{
super(id);
this.cloudIcon = cloudIcon;
fogPath.moveTo(0F, 0.1F);
fogPath.curveTo(0F, 0.1F, 0.25F, 0F, 0.5F, 0.1F);
fogPath.curveTo(0.5F, 0.1F, 0.75F, 0.2F, 1.0F, 0.1F);
fogPath.lineTo(1F, 0.2F);
fogPath.curveTo(1F, 0.2F, 0.75F, 0.3F, 0.5F, 0.2F);
fogPath.curveTo(0.5F, 0.2F, 0.25F, 0.1F, 0F, 0.2F);
fogPath.closePath();
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
for(int i = 0; i < 3; i++)
{
g2d.setStroke(new BasicStroke(4/scale));
g2d.translate(0, 0.4F + 0.2F*i);
g2d.setColor(Color.BLACK);
g2d.draw(fogPath);
g2d.setColor(aniColor[(animationStep + i) % aniColor.length]);
g2d.fill(fogPath);
g2d.translate(0, -0.4F - 0.2*i);
}
//Fog?
g2d.translate(0F, -0.10F);
g2d.scale(1F, 0.8F);
cloudIcon.drawIcon(g2d, scale, animationStep);
g2d.scale(1F, 1.25F);
g2d.translate(0F, 0.10F);
}
@Override
public boolean isAnimated() {
return true;
}
}

View File

@@ -0,0 +1,129 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class IceCubeIcon extends Icon {
Path2D.Float iceOutline = new Path2D.Float();
Path2D.Float[] iceFaces = new Path2D.Float[3];
Path2D.Float[] iceShines = new Path2D.Float[3];
Path2D.Float iceBeams = new Path2D.Float();
Color[] iceFaceColors = new Color[] {
new Color(0xb9dbff),
new Color(0x92b1ff),
new Color(0x3886ff),
};
Color[] iceShineAnimation = new Color[] {
new Color(0x92B1FF),
new Color(0xA2C1FF),
new Color(0xB2D1FF),
new Color(0xC2E1FF),
new Color(0xD2F1FF),
new Color(0xE2FFFF),
new Color(0xFFFFFF),
new Color(0xE2FFFF),
new Color(0xD2F1FF),
new Color(0xC2E1FF),
new Color(0xB2D1FF),
new Color(0xA2C1FF),
};
public IceCubeIcon(int id) {
super(id);
iceBeams.moveTo(0.15F, 0.35F);
iceBeams.lineTo(0.25F, 0.15F);
iceBeams.moveTo(0.60F, 0.2F);
iceBeams.lineTo(0.70F, 0F);
iceBeams.moveTo(0.9F, 0.25F);
iceBeams.lineTo(1.0F, 0.05F);
iceOutline.moveTo(0F, 0.161F);
iceOutline.lineTo(0.542F, 0F);
iceOutline.lineTo(1.0F, 0.093F);
iceOutline.lineTo(1.0F, 0.441F);
iceOutline.lineTo(0.489F, 0.650F);
iceOutline.lineTo(0.0F, 0.531F);
iceOutline.closePath();
iceFaces[1] = new Path2D.Float();
iceFaces[1].moveTo(0F, 0.161F);
iceFaces[1].lineTo(0.542F, 0F);
iceFaces[1].lineTo(1.0F, 0.093F);
iceFaces[1].lineTo(0.489F, 0.263F);
iceFaces[1].closePath();
iceFaces[2] = new Path2D.Float();
iceFaces[2].moveTo(0.489F, 0.263F);
iceFaces[2].lineTo(1.0F, 0.093F);
iceFaces[2].lineTo(1.0F, 0.441F);
iceFaces[2].lineTo(0.489F, 0.650F);
iceFaces[2].closePath();
iceFaces[0] = new Path2D.Float();
iceFaces[0].moveTo(0.0F, 0.161F);
iceFaces[0].lineTo(0.489F, 0.263F);
iceFaces[0].lineTo(0.489F, 0.650F);
iceFaces[0].lineTo(0.0F, 0.531F);
iceFaces[0].closePath();
iceShines[1] = new Path2D.Float();
iceShines[1].moveTo(0.537F, 0.013F);
iceShines[1].lineTo(0.930F, 0.099F);
iceShines[1].lineTo(0.673F, 0.185F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.742F, 0.086);
iceShines[1].closePath();
iceShines[2] = new Path2D.Float();
iceShines[2].moveTo(0.981F, 0.134F);
iceShines[2].lineTo(0.981F, 0.423F);
iceShines[2].lineTo(0.515F, 0.624F);
iceShines[2].lineTo(0.571F, 0.557F);
iceShines[2].lineTo(0.915F, 0.372F);
iceShines[2].closePath();
iceShines[0] = new Path2D.Float();
iceShines[0].moveTo(0.018F, 0.187F);
iceShines[0].lineTo(0.205F, 0.229F);
iceShines[0].lineTo(0.060F, 0.249F);
iceShines[0].lineTo(0.044F, 0.475F);
iceShines[0].lineTo(0.021F, 0.508F);
iceShines[0].closePath();
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(2 / scale));
g2d.draw(iceBeams);
g2d.setStroke(new BasicStroke(4 / scale));
g2d.translate(0F, 0.325F);
g2d.draw(iceOutline);
for(int i = 0; i < iceFaces.length; i++)
{
g2d.setColor(iceFaceColors[i]);
g2d.fill(iceFaces[i]);
g2d.setColor(iceShineAnimation[(i+animationStep) % iceShineAnimation.length]);
g2d.fill(iceShines[i]);
}
g2d.translate(0F, -0.325F);
}
@Override
public boolean isAnimated() {
return false;
}
}

View File

@@ -0,0 +1,35 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil;
import com.flaremicro.flaretv.visualforecast.graphics.FontManager;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class InvalidIcon extends Icon {
private Font fnt = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
public InvalidIcon(int i)
{
super(i);
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setFont(fnt.deriveFont(0.8F));
g2d.translate(0.2F, 0.8F);
DrawingUtil.drawOutlinedString(g2d, 0, 0, "X", Color.YELLOW, Color.BLACK, 1, 2/scale);
g2d.translate(0.2F, 0F);
DrawingUtil.drawOutlinedString(g2d, 0, 0, "?", Color.RED, Color.BLACK, 1, 2/scale);
g2d.translate(-0.4F, -0.8F);
}
@Override
public boolean isAnimated() {
return false;
}
}

View File

@@ -0,0 +1,36 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class LightningCloudIcon extends Icon {
private final Icon boltIcon;
private final Icon smallCloudIcon;
public LightningCloudIcon(int id, Icon smallCloudIcon, Icon boltIcon) {
super(id);
this.smallCloudIcon = smallCloudIcon;
this.boltIcon = boltIcon;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.scale(0.8F, 0.5F);
g2d.translate(0.0F, 0.8F);
boltIcon.drawIcon(g2d, scale/1.5F, animationStep);
g2d.translate(-0.0F, -0.8F);
g2d.scale(1.25F, 2);
g2d.scale(0.6F, 0.4F);
g2d.translate(0.3F, 0.5F);
smallCloudIcon.drawIcon(g2d, scale/2, animationStep);
g2d.translate(-0.3F, -0.5F);
g2d.scale(1.66666666667F, 2.5F);
}
@Override
public boolean isAnimated() {
return boltIcon.isAnimated() || smallCloudIcon.isAnimated();
}
}

View File

@@ -0,0 +1,88 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class LightningIcon extends Icon {
Path2D.Float boltPath = new Path2D.Float();
Path2D.Float shinePath = new Path2D.Float();
Color[] shine = {
new Color(0xFFDD00),
new Color(0xFFFFFF),
new Color(0xFFFFFF),
new Color(0xFFEE88),
new Color(0xFFDD00),
new Color(0xFFFFFF),
new Color(0xFFFFFF),
new Color(0xFFEE88),
new Color(0xFFDD00),
new Color(0xFFDD00),
new Color(0xFFDD00),
};
Color[] bolt = {
new Color(0xFFFF00),
new Color(0xFFDD00),
new Color(0xFFDD00),
new Color(0xFFEE00),
new Color(0xFFFF00),
new Color(0xFFDD00),
new Color(0xFFDD00),
new Color(0xFFEE00),
new Color(0xFFFF00),
new Color(0xFFFF00),
new Color(0xFFFF00),
};
public LightningIcon(int id)
{
super(id);
boltPath.moveTo(0.380, 0);
boltPath.lineTo(0.680, 0);
boltPath.lineTo(0.577, 0.206);
boltPath.lineTo(0.750, 0.206);
boltPath.lineTo(0.545, 0.617);
boltPath.lineTo(0.678, 0.617);
boltPath.lineTo(0.330, 1);
boltPath.lineTo(0.453, 0.679);
boltPath.lineTo(0.333, 0.679);
boltPath.lineTo(0.461, 0.360);
boltPath.lineTo(0.250, 0.360);
boltPath.closePath();
shinePath.moveTo(0.417, 0.0);
shinePath.lineTo(0.518, 0);
shinePath.lineTo(0.413,0.260);
shinePath.lineTo(0.586,0.260);
shinePath.lineTo(0.417,0.631);
shinePath.lineTo(0.550,0.631);
shinePath.lineTo(0.349,0.970);
shinePath.lineTo(0.489,0.666);
shinePath.lineTo(0.369,0.666);
shinePath.lineTo(0.508,0.327);
shinePath.lineTo(0.297,0.327);
shinePath.closePath();
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setStroke(new BasicStroke(4/scale));
g2d.setColor(Color.BLACK);
g2d.draw(boltPath);
g2d.setColor(bolt[animationStep % bolt.length]);
g2d.fill(boltPath);
g2d.setColor(shine[animationStep % shine.length]);
g2d.fill(shinePath);
}
@Override
public boolean isAnimated() {
return true;
}
}

View File

@@ -0,0 +1,40 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class LightningOverlay extends Icon {
private final Icon boltIcon;
private final Icon smallCloudIcon;
private final Icon weatherIcon;
public LightningOverlay(int id, Icon smallCloudIcon, Icon boltIcon, Icon weatherIcon) {
super(id);
this.smallCloudIcon = smallCloudIcon;
this.boltIcon = boltIcon;
this.weatherIcon = weatherIcon;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
weatherIcon.drawIcon(g2d, scale, animationStep);
g2d.scale(0.8F, 0.5F);
g2d.translate(0.3F, 0.8F);
boltIcon.drawIcon(g2d, scale/1.5F, animationStep);
g2d.translate(-0.3F, -0.8F);
g2d.scale(1.25F, 2);
g2d.scale(0.6F, 0.4F);
g2d.translate(0.6F, 0.5F);
smallCloudIcon.drawIcon(g2d, scale/2, animationStep);
g2d.translate(-0.6F, -0.5F);
g2d.scale(1.66666666667F, 2.5F);
}
@Override
public boolean isAnimated() {
return weatherIcon.isAnimated() || boltIcon.isAnimated() || smallCloudIcon.isAnimated();
}
}

View File

@@ -0,0 +1,39 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class LightningStormIcon extends Icon {
private final Icon boltIcon;
private final Icon cloudIcon;
public LightningStormIcon(int id, Icon cloudIcon, Icon boltIcon)
{
super(id);
this.cloudIcon = cloudIcon;
this.boltIcon = boltIcon;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setStroke(new BasicStroke(4/scale));
g2d.translate(0F, 0.15F);
g2d.scale(0.8F, 0.8F);
boltIcon.drawIcon(g2d, scale, animationStep);
g2d.scale(1.25F, 1.25F);
g2d.translate(0F, -0.25F);
g2d.scale(1F, 0.8F);
cloudIcon.drawIcon(g2d, scale, animationStep);
g2d.scale(1F, 1.25F);
g2d.translate(0F, 0.10F);
}
@Override
public boolean isAnimated() {
return cloudIcon.isAnimated() || boltIcon.isAnimated();
}
}

View File

@@ -1,13 +1,16 @@
package com.flaremicro.flaretv.visualforecast.icons; package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D; import java.awt.Graphics2D;
public class PartlyCloudyIcon implements Icon { import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class PartlyCloudyIcon extends Icon {
private Icon cloud; private Icon cloud;
private Icon sun; private Icon sun;
public PartlyCloudyIcon(Icon cloud, Icon sun) public PartlyCloudyIcon(int id, Icon cloud, Icon sun)
{ {
super(id);
this.cloud = cloud; this.cloud = cloud;
this.sun = sun; this.sun = sun;
} }
@@ -25,4 +28,9 @@ public class PartlyCloudyIcon implements Icon {
g2d.translate(0, -0.07F); g2d.translate(0, -0.07F);
} }
@Override
public boolean isAnimated() {
return sun.isAnimated() || cloud.isAnimated();
}
} }

View File

@@ -1,11 +1,13 @@
package com.flaremicro.flaretv.visualforecast.icons; package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
public class RainIcon implements Icon { import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class RainIcon extends Icon {
private final int rainCount; private final int rainCount;
private final float rainSpace; private final float rainSpace;
private final Icon cloudIcon; private final Icon cloudIcon;
@@ -26,8 +28,9 @@ public class RainIcon implements Icon {
new Color(0x0066FF), new Color(0x0066FF),
}; };
public RainIcon(int rainCount, float rainSpace, Icon cloudIcon) public RainIcon(int id, int rainCount, float rainSpace, Icon cloudIcon)
{ {
super(id);
this.rainCount = rainCount; this.rainCount = rainCount;
this.rainSpace = rainSpace * 0.125F; this.rainSpace = rainSpace * 0.125F;
this.cloudIcon = cloudIcon; this.cloudIcon = cloudIcon;
@@ -73,4 +76,9 @@ public class RainIcon implements Icon {
g2d.translate(0F, 0.10F); g2d.translate(0F, 0.10F);
} }
@Override
public boolean isAnimated() {
return true;
}
} }

View File

@@ -0,0 +1,47 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class RainSnowIcon extends Icon {
private final Icon rainIcon;
private final Icon snowflakeIcon;
private final boolean snow;
public RainSnowIcon(int id, Icon rainIcon, Icon snowflakeIcon, boolean snow)
{
super(id);
this.rainIcon = rainIcon;
this.snowflakeIcon = snowflakeIcon;
this.snow = snow;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
if(snow)
{
g2d.scale(0.25F, 0.25F);
g2d.translate(2, 3);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep);
g2d.translate(1, -1);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep);
g2d.translate(-3, -2);
g2d.scale(4, 4);
}
rainIcon.drawIcon(g2d, scale, animationStep);
g2d.translate(0.3F, 0);
g2d.scale(0.7F, 0.7F);
snowflakeIcon.drawIcon(g2d, scale*0.7F, animationStep);
g2d.scale(1.42857142857F, 1.42857142857F);
g2d.translate(-0.3F, 0);
}
@Override
public boolean isAnimated() {
return rainIcon.isAnimated() || snowflakeIcon.isAnimated();
}
}

View File

@@ -0,0 +1,106 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class SleetIcon extends Icon {
Path2D.Float iceOutline = new Path2D.Float();
Path2D.Float[] iceFaces = new Path2D.Float[3];
Path2D.Float[] iceShines = new Path2D.Float[3];
Color[] iceFaceColors = new Color[] {
new Color(0xfff8a0),
new Color(0xfff14c),
new Color(0xccbc00),
};
Color[] iceShineAnimation = new Color[] {
new Color(0xFFFFFF),
};
public SleetIcon(int id) {
super(id);
iceOutline.moveTo(0F, 0.161F);
iceOutline.lineTo(0.542F, 0F);
iceOutline.lineTo(1.0F, 0.093F);
iceOutline.lineTo(1.0F, 0.441F);
iceOutline.lineTo(0.489F, 0.650F);
iceOutline.lineTo(0.0F, 0.531F);
iceOutline.closePath();
iceFaces[1] = new Path2D.Float();
iceFaces[1].moveTo(0F, 0.161F);
iceFaces[1].lineTo(0.542F, 0F);
iceFaces[1].lineTo(1.0F, 0.093F);
iceFaces[1].lineTo(0.489F, 0.263F);
iceFaces[1].closePath();
iceFaces[2] = new Path2D.Float();
iceFaces[2].moveTo(0.489F, 0.263F);
iceFaces[2].lineTo(1.0F, 0.093F);
iceFaces[2].lineTo(1.0F, 0.441F);
iceFaces[2].lineTo(0.489F, 0.650F);
iceFaces[2].closePath();
iceFaces[0] = new Path2D.Float();
iceFaces[0].moveTo(0.0F, 0.161F);
iceFaces[0].lineTo(0.489F, 0.263F);
iceFaces[0].lineTo(0.489F, 0.650F);
iceFaces[0].lineTo(0.0F, 0.531F);
iceFaces[0].closePath();
iceShines[1] = new Path2D.Float();
iceShines[1].moveTo(0.537F, 0.013F);
iceShines[1].lineTo(0.930F, 0.099F);
iceShines[1].lineTo(0.673F, 0.185F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.556F, 0.187F);
iceShines[1].lineTo(0.742F, 0.086);
iceShines[1].closePath();
iceShines[2] = new Path2D.Float();
iceShines[2].moveTo(0.981F, 0.134F);
iceShines[2].lineTo(0.981F, 0.423F);
iceShines[2].lineTo(0.515F, 0.624F);
iceShines[2].lineTo(0.571F, 0.557F);
iceShines[2].lineTo(0.915F, 0.372F);
iceShines[2].closePath();
iceShines[0] = new Path2D.Float();
iceShines[0].moveTo(0.018F, 0.187F);
iceShines[0].lineTo(0.205F, 0.229F);
iceShines[0].lineTo(0.060F, 0.249F);
iceShines[0].lineTo(0.044F, 0.475F);
iceShines[0].lineTo(0.021F, 0.508F);
iceShines[0].closePath();
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(4 / scale));
g2d.translate(0F, 0.325F);
g2d.setColor(Color.BLACK);
g2d.draw(iceOutline);
for(int i = 0; i < iceFaces.length; i++)
{
g2d.setColor(iceFaceColors[i]);
g2d.fill(iceFaces[i]);
g2d.setColor(iceShineAnimation[(i+animationStep) % iceShineAnimation.length]);
g2d.fill(iceShines[i]);
}
g2d.translate(0F, -0.325F);
}
@Override
public boolean isAnimated() {
return false;
}
}

View File

@@ -0,0 +1,69 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class SmallCloudIcon extends Icon {
public SmallCloudIcon(int id) {
super(id);
}
private final Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.456F, 0.241F, 0.346F, 0.748F),
new Ellipse2D.Float(0.655F, 0.238F, 0.356F, 0.748F),
new Ellipse2D.Float(0.480F, 0.043F, 0.341F, 0.523F),
new Ellipse2D.Float(0.191F, 0.000F, 0.454F, 0.656F),
new Ellipse2D.Float(0.217F, 0.261F, 0.454F, 0.732F),
new Ellipse2D.Float(0.000F, 0.199F, 0.428F, 0.801F)
};
private final Ellipse2D.Float[] lightCircles = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.196F, 0.052F, 0.439F, 0.748F),
new Ellipse2D.Float(0.030F, 0.230F, 0.439F, 0.654F),
new Ellipse2D.Float(0.709F, 0.300F, 0.218F, 0.335F),
new Ellipse2D.Float(0.429F, 0.498F, 0.218F, 0.335F)
};
private final Ellipse2D.Float[] overLight = new Ellipse2D.Float[]{
new Ellipse2D.Float(0.183F, 0.124F, 0.478F, 0.713F),
new Ellipse2D.Float(0.040F, 0.264F, 0.478F, 0.713F),
new Ellipse2D.Float(0.716F, 0.335F, 0.237F, 0.365F),
new Ellipse2D.Float(0.437F, 0.532F, 0.237F, 0.365F)
};
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(4/scale));
for(int i = 0; i < cloudCircles.length; i++)
{
g2d.draw(cloudCircles[i]);
}
g2d.setColor(Color.LIGHT_GRAY);
for(int i = 0; i < cloudCircles.length; i++)
{
g2d.fill(cloudCircles[i]);
}
for(int i = 0; i < lightCircles.length; i++)
{
g2d.setColor(Color.LIGHT_GRAY.brighter());
g2d.fill(lightCircles[i]);
g2d.setColor(Color.LIGHT_GRAY);
g2d.fill(overLight[i]);
}
}
@Override
public boolean isAnimated() {
return false;
}
}

View File

@@ -0,0 +1,47 @@
package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class SnowIcon extends Icon {
private final Icon cloudIcon;
private final Icon snowflakeIcon;
public SnowIcon(int id, Icon cloudIcon, Icon snowflakeIcon)
{
super(id);
this.cloudIcon = cloudIcon;
this.snowflakeIcon = snowflakeIcon;
}
@Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
AffineTransform af = g2d.getTransform();
g2d.scale(0.25F, 0.25F);
g2d.translate(0.5F, 2F);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep);
g2d.translate(2F, 1F);
snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep);
g2d.setTransform(af);
g2d.translate(0F, -0.10F);
g2d.scale(1F, 0.8F);
cloudIcon.drawIcon(g2d, scale, animationStep);
g2d.setTransform(af);
g2d.translate(0.3F, 0);
g2d.scale(0.7F, 0.7F);
snowflakeIcon.drawIcon(g2d, scale*0.7F, animationStep);
g2d.setTransform(af);
}
@Override
public boolean isAnimated() {
return snowflakeIcon.isAnimated() || cloudIcon.isAnimated();
}
}

View File

@@ -1,17 +1,35 @@
package com.flaremicro.flaretv.visualforecast.icons; package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
public class SnowflakeIcon implements Icon { import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class SnowflakeIcon extends Icon {
Path2D.Float flakePath = new Path2D.Float(); Path2D.Float flakePath = new Path2D.Float();
Path2D.Float gradPath = new Path2D.Float(); Path2D.Float gradPath = new Path2D.Float();
Path2D.Float trianglePath = new Path2D.Float(); Path2D.Float trianglePath = new Path2D.Float();
public SnowflakeIcon() Color[] animColor = {
new Color(0x2288FF),
new Color(0x4499FF),
new Color(0x66AAFF),
new Color(0x88BBFF),
new Color(0xAACCFF),
new Color(0xCCDDFF),
new Color(0xAACCFF),
new Color(0x88BBFF),
new Color(0x66AAFF),
new Color(0x4499FF),
new Color(0x2288FF),
new Color(0x2288FF),
};
public SnowflakeIcon(int id)
{ {
super(id);
flakePath.moveTo(0.400, 0); flakePath.moveTo(0.400, 0);
flakePath.lineTo(0.600, 0); flakePath.lineTo(0.600, 0);
flakePath.lineTo(0.600, 0.327); flakePath.lineTo(0.600, 0.327);
@@ -94,13 +112,18 @@ public class SnowflakeIcon implements Icon {
g2d.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g2d.fill(flakePath); g2d.fill(flakePath);
//g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(0x2288FF)); g2d.setPaint(animColor[animationStep % animColor.length]);//new Color(0x2288FF));
g2d.fill(gradPath); g2d.fill(gradPath);
g2d.setStroke(new BasicStroke(1/scale)); //g2d.setStroke(new BasicStroke(1/scale));
g2d.draw(gradPath); //g2d.draw(gradPath);
//g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setPaint(Color.BLACK); g2d.setColor(Color.BLACK);
g2d.fill(trianglePath); g2d.fill(trianglePath);
} }
@Override
public boolean isAnimated() {
return true;
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.flaretv.visualforecast.icons; package com.flaremicro.flaretv.visualforecast.icons.impl;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
@@ -6,7 +6,9 @@ import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
public class SunIcon implements Icon { import com.flaremicro.flaretv.visualforecast.icons.Icon;
public class SunIcon extends Icon {
Path2D.Float sunPath = new Path2D.Float(); Path2D.Float sunPath = new Path2D.Float();
Ellipse2D.Float sunCircle1 = new Ellipse2D.Float(0.2F, 0.2F, 0.6F, 0.6F); Ellipse2D.Float sunCircle1 = new Ellipse2D.Float(0.2F, 0.2F, 0.6F, 0.6F);
Ellipse2D.Float sunInternalCircle1 = new Ellipse2D.Float(0.28F, 0.22F, 0.5F, 0.5F); Ellipse2D.Float sunInternalCircle1 = new Ellipse2D.Float(0.28F, 0.22F, 0.5F, 0.5F);
@@ -25,8 +27,9 @@ public class SunIcon implements Icon {
new Color(255, 140, 0), new Color(255, 140, 0),
new Color(255, 120, 0), new Color(255, 120, 0),
}; };
public SunIcon() public SunIcon(int id)
{ {
super(id);
sunPath.moveTo(0.5F, 0.0F); sunPath.moveTo(0.5F, 0.0F);
sunPath.lineTo(0.605F, 0.106F); sunPath.lineTo(0.605F, 0.106F);
sunPath.lineTo(0.750F, 0.067F); sunPath.lineTo(0.750F, 0.067F);
@@ -72,4 +75,9 @@ public class SunIcon implements Icon {
g2d.draw(sunCircle1); g2d.draw(sunCircle1);
} }
@Override
public boolean isAnimated() {
return true;
}
} }

View File

@@ -0,0 +1,12 @@
package com.flaremicro.flaretv.visualforecast.providerapi;
public abstract class ForecastProvider {
ForecastProviderManager pluginManager;
protected final void setAsProvider(String authority)
{
}
public abstract void init();
}

View File

@@ -0,0 +1,70 @@
package com.flaremicro.flaretv.visualforecast.providerapi;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;
import java.util.logging.Logger;
import com.flaremicro.util.Util;
public class ForecastProviderManager {
public static final float API_VERSION = 0.0F;
private Logger log = Util.getDefaultLogger();
private ForecastProvider loadedProvider;
public void loadProviders(File file) {
Util.getDefaultLogger().info("Loading provider " + file.getName());
try
{
URLClassLoader classLoader = new URLClassLoader(new URL[] { file.toURI().toURL() });
Properties properties = new Properties();
InputStream propStream = classLoader.getResourceAsStream("provider.inf");
properties.load(propStream);
Util.cleanClose(propStream);
String mainClassStr = properties.getProperty("main-class", "");
Class<?> mainClass = classLoader.loadClass(mainClassStr);
Object instance = mainClass.newInstance();
if (instance instanceof ForecastProvider)
{
loadedProvider = (ForecastProvider) instance;
loadedProvider.init();
log.info("Provider " + file.getName() + " loaded!");
}
else
{
log.info("Provider " + file.getName() + " main class is wrong object type");
log.info("(Does main class not extend ForecastProvider?)");
}
}
catch (ClassNotFoundException e)
{
log.info("Provider " + file.getName() + " main class not found:");
e.printStackTrace();
log.info("(Is the information file invalid?)");
}
catch (IOException e)
{
log.info("Provider " + file.getName() + " failed to read information file:");
e.printStackTrace();
log.info("(Is the information file defined?)");
}
catch (InstantiationException e)
{
log.info("Provider " + file.getName() + " failed to instantiate main class:");
e.printStackTrace();
log.info("(Does main class not implement empty constructor?)");
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,125 @@
package com.flaremicro.flaretv.visualforecast.providerapi;
import java.util.Random;
import com.flaremicro.flaretv.visualforecast.forecast.DayForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ForecastDetails;
import com.flaremicro.flaretv.visualforecast.forecast.TownForecast;
import com.flaremicro.flaretv.visualforecast.forecast.ValueCheck;
import com.flaremicro.flaretv.visualforecast.icons.IconProvider;
public class MockForecastProvider {
private static final String[] townNames = {
"Vancouver",
"Burnaby",
"Kamloops",
"Kelona",
"Lytton"
};
private final static WeatherType[] possibleWeather = {
new WeatherType(IconProvider.BLIZZARD.id, "Blizzard", true),
new WeatherType(IconProvider.CLOUD.id, "Cloudy", false),
new WeatherType(IconProvider.CLOUDY_CLOUDY.id, "Very", "Cloudy", false),
new WeatherType(IconProvider.FREEZING_RAIN.id, "Freezing", "Rain", true),
new WeatherType(IconProvider.LIGHTNING_STORM.id, "Thunder", "Storm", true),
new WeatherType(IconProvider.LIGHTNING_BLIZZARD.id, "Blizzard", "T'Storm", true),
new WeatherType(IconProvider.PARTLY_CLOUDY.id, "Partly", "Cloudy", false),
new WeatherType(IconProvider.RAIN.id, "Rain", true),
new WeatherType(IconProvider.RAIN_HEAVIEST.id, "Extreme","Rain", true),
new WeatherType(IconProvider.RAIN_HEAVY.id, "Heavy","Rain", true),
new WeatherType(IconProvider.RAIN_LIGHT.id, "Light","Rain", true),
new WeatherType(IconProvider.RAIN_LIGHTEST.id, "Drizzle", true),
new WeatherType(IconProvider.RAIN_SNOW.id, "Rain","Snow", true),
new WeatherType(IconProvider.RAIN_VANCOUVER.id, "Vancouver","Rain", true),
new WeatherType(IconProvider.SCATTERD_SHOWERS.id, "Scattered","Showers", true),
new WeatherType(IconProvider.SCATTERD_THUNDERSTORMS.id, "Scattered","T'Storms", true),
new WeatherType(IconProvider.SNOW.id, "Snow", true),
new WeatherType(IconProvider.SUN.id, "Sun", false),
new WeatherType(IconProvider.FOG.id, "Fog", false),
new WeatherType(IconProvider.HAIL.id, "Hail", false),
new WeatherType(IconProvider.BUTTER_RAIN.id, "Paula", "Dean", false),
new WeatherType(IconProvider.BUTTER.id, "Unsalted", "Butter", false),
//new WeatherType(IconProvider.INVALID_RAIN.id, "Your", "Mom", false),
};
public static ForecastDetails provideMockForecast()
{
Random random = new Random();
ForecastDetails fd = new ForecastDetails();
fd.setTownForecast(provideTownForecast(random));
return fd;
}
private static TownForecast[] provideTownForecast(Random random) {
TownForecast[] tf = new TownForecast[townNames.length];
for(int i = 0; i < tf.length; i++)
{
tf[i] = new TownForecast(townNames[i], provideDayForecast(random));
}
return tf;
}
private static DayForecast[] provideDayForecast(Random random)
{
DayForecast[] df = new DayForecast[8];
for(int i = 0; i < df.length; i++)
{
if(random.nextInt(11) == 10)
{
df[i] = new DayForecast(ValueCheck.NO_DATA_BYTE, ValueCheck.NO_DATA_BYTE, (byte)0, null, null, ValueCheck.NO_DATA_FLOAT);
}
else
{
byte hiTemp = (byte)(random.nextInt(60)-20);
byte loTemp = (byte)(random.nextInt(60)-20);
if(hiTemp < loTemp)
{
byte temp = hiTemp;
hiTemp = loTemp;
loTemp = temp;
}
byte iconId = 0;
String weatherLine1 = null;
String weatherLine2 = null;
float percipPercent = ValueCheck.NO_DATA_FLOAT;
WeatherType wt = possibleWeather[random.nextInt(possibleWeather.length)];
iconId = wt.iconId;
weatherLine1 = wt.line1;
weatherLine2 = wt.line2;
if(wt.hasPercipitation)
{
percipPercent = random.nextFloat() * 100;
}
df[i] = new DayForecast(hiTemp, loTemp, iconId, weatherLine1, weatherLine2, percipPercent);
}
}
return df;
}
}
class WeatherType{
byte iconId;
String line1;
String line2;
boolean hasPercipitation;
public WeatherType(byte iconId, String line1, boolean hasPercipitation){
this(iconId, line1, null, hasPercipitation);
}
public WeatherType(byte iconId, String line1, String line2, boolean hasPercipitation){
this.iconId = iconId;
this.line1 = line1;
this.line2 = line2;
this.hasPercipitation = hasPercipitation;
}
}

View File

@@ -0,0 +1,93 @@
package com.flaremicro.util;
import java.applet.Applet;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Random;
import java.util.logging.ConsoleHandler;
import java.util.logging.Logger;
import com.flaremicro.util.logging.LogFormatter;
import com.flaremicro.util.logging.LogOutputStream;
public class Util {
public static final long INSTANCE_ID = Math.abs(new Random().nextLong());
public static final String LOGGER_NAME = "VisualForecast 1000 Logger";
static
{
initLogger();
}
public static Logger getDefaultLogger() {
return Logger.getLogger(LOGGER_NAME);
}
public static void initLogger() {
Logger log = getDefaultLogger();
log.setUseParentHandlers(false);
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new LogFormatter());
log.addHandler(handler);
System.setErr(new PrintStream(new LogOutputStream(log, java.util.logging.Level.SEVERE)));
System.setOut(new PrintStream(new LogOutputStream(log, java.util.logging.Level.INFO)));
log.info("Initialized logger successfully");
log.info("Using native Java logger, ID 0J3QvtGCINGD0YHQtdC70LXRgdGBINCbNNCI");
}
/**
* Parse arguments, in arg=value format, or just arg for arguments with no
* value. Values can contain = signs, but not arguments.
*
* @param args
* @param keyToLower
* @return
*/
public static HashMap<String, String> parseArgs(String args[], boolean keyToLower) {
HashMap<String, String> map = new HashMap<String, String>();
for (String s : args)
{
String[] res = s.split("=", 2);
if (keyToLower)
res[0].toLowerCase();
if (res.length > 1)
{
map.put(res[0], res[1]);
}
else map.put(res[0], "");
}
return map;
}
public static boolean cleanClose(Closeable closeable) {
try
{
if (closeable != null)
closeable.close();
return true;
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
}
public static HashMap<String, String> toArguments(Applet applet, String[] expectedParameters) {
HashMap<String, String> arguments = new HashMap<String, String>();
if (applet == null || expectedParameters == null)
return arguments;
for (String parameter : expectedParameters)
{
String value = applet.getParameter(parameter);
if (value != null)
{
arguments.put(parameter, value);
}
}
return arguments;
}
}

View File

@@ -0,0 +1,31 @@
package com.flaremicro.util.logging;
import java.text.SimpleDateFormat;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
public class LogFormatter extends Formatter {
String sep = System.getProperty("line.separator");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public String format(LogRecord record) {
String fmessage = "";
if(record.getLevel() == Level.SEVERE)
fmessage += "["+format.format(System.currentTimeMillis())+"][SEVERE]";
else if(record.getLevel() == Level.WARNING)
fmessage += "["+format.format(System.currentTimeMillis())+"][WARNING]";
else if(record.getLevel() == Level.INFO)
fmessage += "["+format.format(System.currentTimeMillis())+"][INFO]";
return fmessage += this.formatMessage(record) + sep;
}
public String getHead(Handler h) {
return "";
}
public String getTail(Handler h) {
return "";
}
}

View File

@@ -0,0 +1,38 @@
package com.flaremicro.util.logging;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogOutputStream extends OutputStream {
String buffer = "";
Logger logger;
Level level;
public LogOutputStream(Logger logger, Level level)
{
this.logger = logger;
this.level = level;
}
@Override
public void write(int b) throws IOException {
buffer += (char)((byte)b);
if(buffer.endsWith("\n") || buffer.endsWith("\r\n"))
{
buffer = buffer.replace("\r", "").replace("\n", "");
flush();
}
}
public void flush()
{
logger.log(level, buffer);
buffer = "";
}
}