From 5e21c7725a2b4fec3e54f16b8e1fb02e0109ec93 Mon Sep 17 00:00:00 2001 From: Flare Microsystems Date: Sun, 3 Mar 2024 21:58:56 -0800 Subject: [PATCH 1/3] Icons --- .../flaretv/visualforecast/RenderPanel.java | 33 +++++-- .../visualforecast/flavour/Flavour.java | 5 ++ .../forecast/ForecastInformation.java | 5 ++ .../flaretv/visualforecast/icons/Icon.java | 1 + .../visualforecast/icons/IconProvider.java | 58 ++++++++----- .../icons/impl/BlizzardIcon.java | 50 +++++++++++ .../icons/{ => impl}/CloudIcon.java | 10 ++- .../icons/impl/LightningIcon.java | 87 +++++++++++++++++++ .../icons/impl/LightningOverlay.java | 39 +++++++++ .../icons/impl/LightningStormIcon.java | 38 ++++++++ .../icons/{ => impl}/PartlyCloudyIcon.java | 9 +- .../icons/{ => impl}/RainIcon.java | 9 +- .../icons/impl/RainSnowIcon.java | 46 ++++++++++ .../icons/impl/SmallCloudIcon.java | 64 ++++++++++++++ .../visualforecast/icons/impl/SnowIcon.java | 46 ++++++++++ .../icons/{ => impl}/SnowflakeIcon.java | 32 +++++-- .../icons/{ => impl}/SunIcon.java | 9 +- 17 files changed, 501 insertions(+), 40 deletions(-) create mode 100644 src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java rename src/com/flaremicro/flaretv/visualforecast/icons/{ => impl}/CloudIcon.java (93%) create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java rename src/com/flaremicro/flaretv/visualforecast/icons/{ => impl}/PartlyCloudyIcon.java (73%) rename src/com/flaremicro/flaretv/visualforecast/icons/{ => impl}/RainIcon.java (91%) create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java rename src/com/flaremicro/flaretv/visualforecast/icons/{ => impl}/SnowflakeIcon.java (81%) rename src/com/flaremicro/flaretv/visualforecast/icons/{ => impl}/SunIcon.java (92%) diff --git a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java index 38cecda..6531260 100644 --- a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java +++ b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java @@ -58,7 +58,7 @@ public class RenderPanel extends JPanel implements Runnable { { e.printStackTrace(); } - testString = "The sandwiches at gas stations\nare disgusting, we advise you\ndo not eat them".split("\n"); + testString = "".split("\n"); new Thread(this).start(); } @@ -157,13 +157,13 @@ public class RenderPanel extends JPanel implements Runnable { // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON); - drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, "Your local forecast", Color.WHITE, Color.BLACK, 1); + drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, "7 Day Forecast", Color.WHITE, Color.BLACK, 1); int sw = g2d.getFontMetrics().stringWidth(dateString); drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 1); sw = g2d.getFontMetrics().stringWidth(timeString); drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 1); g2d.setFont(font.deriveFont(36F)); - drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, "New Westminster, BC", Color.YELLOW, Color.BLACK, 2); + drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, "Burnaby, BC", Color.YELLOW, Color.BLACK, 2); 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); @@ -176,12 +176,27 @@ public class RenderPanel extends JPanel implements Runnable { // 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); + + IconProvider.drawIcon(g2d, IconProvider.SUN, 80, 220, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.CLOUD, 160, 220, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.PARTLY_CLOUDY, 160 + 80, 220, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.CLOUDY_CLOUDY, 160 + 160, 220, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.SCATTERD_SHOWERS, 160 + 160 + 80, 220, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.SNOWFLAKE, 160 + 160 + 160, 220, 80, animationTick); + + IconProvider.drawIcon(g2d, IconProvider.BLIZZARD, 80, 140, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.SNOW, 160, 140, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.FREEZING_RAIN, 160 + 80, 140, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN_SNOW, 160 + 160, 140, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.LIGHTNING_OVERLAY, 160 + 160+80, 140, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.LIGHTNING_STORM, 160 + 160+160, 140, 80, animationTick); + + IconProvider.drawIcon(g2d, IconProvider.RAIN_LIGHTEST, 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN_LIGHT, 160, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN, 160 + 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN_HEAVY, 160 + 160, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN_HEAVIEST, 160 + 160 + 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN_VANCOUVER, 160 + 160 + 160, 300, 80, animationTick); g2d.dispose(); g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this); diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java b/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java new file mode 100644 index 0000000..eef212f --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java @@ -0,0 +1,5 @@ +package com.flaremicro.flaretv.visualforecast.flavour; + +public interface Flavour { + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java b/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java new file mode 100644 index 0000000..bac895d --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java @@ -0,0 +1,5 @@ +package com.flaremicro.flaretv.visualforecast.forecast; + +public class ForecastInformation { + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java index 380354a..4259d06 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java @@ -3,5 +3,6 @@ package com.flaremicro.flaretv.visualforecast.icons; import java.awt.Graphics2D; public interface Icon { + public boolean isAnimated(); public void drawIcon(Graphics2D g2d, float scale, int animationStep); } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java index e2b1570..80665f4 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java @@ -3,39 +3,53 @@ package com.flaremicro.flaretv.visualforecast.icons; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; +import com.flaremicro.flaretv.visualforecast.icons.impl.BlizzardIcon; +import com.flaremicro.flaretv.visualforecast.icons.impl.CloudIcon; +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 static int SUN = 0; - 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; - - private static final Icon[] CLASS_DEFS = new Icon[64]; + public static final Icon SUN = new SunIcon(); + public static final Icon CLOUD = new CloudIcon(); + public static final Icon PARTLY_CLOUDY = new PartlyCloudyIcon(CLOUD, SUN); + public static final Icon CLOUDY_CLOUDY = new PartlyCloudyIcon(CLOUD, CLOUD); + public static final Icon RAIN_LIGHTEST = new RainIcon(2, 2F, CLOUD); + public static final Icon RAIN_LIGHT = new RainIcon(3, 2F, CLOUD); + public static final Icon RAIN = new RainIcon(3, 1F, CLOUD); + public static final Icon RAIN_HEAVY = new RainIcon(4, 1F, CLOUD); + public static final Icon RAIN_HEAVIEST = new RainIcon(5, 1F, CLOUD); + public static final Icon RAIN_VANCOUVER = new RainIcon(6, 1F, CLOUD); + public static final Icon SCATTERD_SHOWERS = new PartlyCloudyIcon(new RainIcon(2, 4F, CLOUD), SUN); + public static final Icon SNOWFLAKE = new SnowflakeIcon(); + public static final Icon SNOW = new SnowIcon(CLOUD, SNOWFLAKE); + public static final Icon BLIZZARD = new BlizzardIcon(CLOUD, SNOWFLAKE); + public static final Icon RAIN_SNOW = new RainSnowIcon(RAIN_LIGHTEST, SNOWFLAKE, true); + public static final Icon FREEZING_RAIN = new RainSnowIcon(RAIN_LIGHT, SNOWFLAKE, false); + public static final Icon LIGHTNING_BOLT = new LightningIcon(); + public static final Icon LIGHTNING_STORM = new LightningStormIcon(CLOUD, LIGHTNING_BOLT); + public static final Icon SMALL_CLOUD = new SmallCloudIcon(); + public static final Icon LIGHTNING_OVERLAY = new LightningOverlay(SMALL_CLOUD, LIGHTNING_BOLT, BLIZZARD); - static{ - CLASS_DEFS[SUN] = new SunIcon(); - 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) + 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(); g2d.translate(x, y); g2d.scale(scale, scale); //1g2d.setColor(Color.RED); //g2d.fill(new Rectangle2D.Float(0, 0, 1F, 1F)); - CLASS_DEFS[icon].drawIcon(g2d, scale, animationStep); + icon.drawIcon(g2d, scale, animationStep); g2d.setTransform(af); } } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java new file mode 100644 index 0000000..8851f81 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java @@ -0,0 +1,50 @@ +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 implements Icon { + private final Icon cloudIcon; + private final Icon snowflakeIcon; + + + + public BlizzardIcon(Icon cloudIcon, Icon snowflakeIcon) + { + 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); + g2d.translate(1, 1); + snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep); + g2d.translate(1, -1); + 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 cloudIcon.isAnimated() || snowflakeIcon.isAnimated(); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java similarity index 93% rename from src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java rename to src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java index b47569c..67e6447 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java @@ -1,10 +1,12 @@ -package com.flaremicro.flaretv.visualforecast.icons; +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 CloudIcon implements Icon { Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{ new Ellipse2D.Float(0, 0.5F, 0.28F, 0.325F), @@ -86,4 +88,10 @@ public class CloudIcon implements Icon { } + + @Override + public boolean isAnimated() { + return false; + } + } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java new file mode 100644 index 0000000..7127e53 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java @@ -0,0 +1,87 @@ +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 implements 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() + { + 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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java new file mode 100644 index 0000000..782addf --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java @@ -0,0 +1,39 @@ +package com.flaremicro.flaretv.visualforecast.icons.impl; + +import java.awt.Graphics2D; +import com.flaremicro.flaretv.visualforecast.icons.Icon; + +public class LightningOverlay implements Icon { + + private final Icon boltIcon; + private final Icon smallCloudIcon; + private final Icon weatherIcon; + + public LightningOverlay(Icon smallCloudIcon, Icon boltIcon, Icon weatherIcon) { + 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(); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java new file mode 100644 index 0000000..ad7ed78 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java @@ -0,0 +1,38 @@ +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 implements Icon { + private final Icon boltIcon; + private final Icon cloudIcon; + + + public LightningStormIcon(Icon cloudIcon, Icon boltIcon) + { + 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(); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java similarity index 73% rename from src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java rename to src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java index 0c37cd7..1ee7382 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java @@ -1,7 +1,9 @@ -package com.flaremicro.flaretv.visualforecast.icons; +package com.flaremicro.flaretv.visualforecast.icons.impl; import java.awt.Graphics2D; +import com.flaremicro.flaretv.visualforecast.icons.Icon; + public class PartlyCloudyIcon implements Icon { private Icon cloud; private Icon sun; @@ -25,4 +27,9 @@ public class PartlyCloudyIcon implements Icon { g2d.translate(0, -0.07F); } + @Override + public boolean isAnimated() { + return sun.isAnimated() || cloud.isAnimated(); + } + } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java similarity index 91% rename from src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java rename to src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java index 5c9c8c5..cf62ee7 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java @@ -1,10 +1,12 @@ -package com.flaremicro.flaretv.visualforecast.icons; +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 RainIcon implements Icon { private final int rainCount; private final float rainSpace; @@ -73,4 +75,9 @@ public class RainIcon implements Icon { g2d.translate(0F, 0.10F); } + @Override + public boolean isAnimated() { + return true; + } + } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java new file mode 100644 index 0000000..a964408 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java @@ -0,0 +1,46 @@ +package com.flaremicro.flaretv.visualforecast.icons.impl; + +import java.awt.Graphics2D; +import com.flaremicro.flaretv.visualforecast.icons.Icon; + +public class RainSnowIcon implements Icon { + private final Icon rainIcon; + private final Icon snowflakeIcon; + private final boolean snow; + + + + public RainSnowIcon(Icon rainIcon, Icon snowflakeIcon, boolean snow) + { + 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(); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java new file mode 100644 index 0000000..f8fc5db --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java @@ -0,0 +1,64 @@ +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 implements Icon { + 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) + }; + + 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) + }; + + 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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java new file mode 100644 index 0000000..b64c6c6 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java @@ -0,0 +1,46 @@ +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 implements Icon { + private final Icon cloudIcon; + private final Icon snowflakeIcon; + + + + public SnowIcon(Icon cloudIcon, Icon snowflakeIcon) + { + 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(); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java similarity index 81% rename from src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java rename to src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java index 5276d04..c7cba30 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java @@ -1,15 +1,32 @@ -package com.flaremicro.flaretv.visualforecast.icons; +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 SnowflakeIcon implements Icon { Path2D.Float flakePath = new Path2D.Float(); Path2D.Float gradPath = new Path2D.Float(); Path2D.Float trianglePath = new Path2D.Float(); + 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() { flakePath.moveTo(0.400, 0); @@ -94,13 +111,18 @@ public class SnowflakeIcon implements Icon { g2d.setColor(Color.WHITE); g2d.fill(flakePath); //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.setStroke(new BasicStroke(1/scale)); - g2d.draw(gradPath); + //g2d.setStroke(new BasicStroke(1/scale)); + //g2d.draw(gradPath); //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - g2d.setPaint(Color.BLACK); + g2d.setColor(Color.BLACK); g2d.fill(trianglePath); } + @Override + public boolean isAnimated() { + return true; + } + } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java similarity index 92% rename from src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java rename to src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java index f603a18..b65f077 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java @@ -1,4 +1,4 @@ -package com.flaremicro.flaretv.visualforecast.icons; +package com.flaremicro.flaretv.visualforecast.icons.impl; import java.awt.BasicStroke; import java.awt.Color; @@ -6,6 +6,8 @@ import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Path2D; +import com.flaremicro.flaretv.visualforecast.icons.Icon; + public class SunIcon implements Icon { Path2D.Float sunPath = new Path2D.Float(); Ellipse2D.Float sunCircle1 = new Ellipse2D.Float(0.2F, 0.2F, 0.6F, 0.6F); @@ -72,4 +74,9 @@ public class SunIcon implements Icon { g2d.draw(sunCircle1); } + @Override + public boolean isAnimated() { + return true; + } + } -- 2.39.5 From 0fb5900a78cf5ddcea0f063d583b16e53ce62e0f Mon Sep 17 00:00:00 2001 From: Flare Microsystems Date: Tue, 5 Mar 2024 01:46:07 -0800 Subject: [PATCH 2/3] Optimizations, flavours, mock weather --- .classpath | 2 +- .settings/org.eclipse.jdt.core.prefs | 6 +- .../flaretv/visualforecast/RenderPanel.java | 274 ++++++++---------- .../flaretv/visualforecast/SmallTextInfo.java | 44 --- .../flaretv/visualforecast/TickThread.java | 19 +- .../flavour/DayForecastFlavour.java | 172 +++++++++++ .../visualforecast/flavour/Flavour.java | 12 +- .../visualforecast/flavour/TextFlavour.java | 61 ++++ .../visualforecast/forecast/DayForecast.java | 19 ++ .../forecast/ForecastDetails.java | 20 ++ .../forecast/ForecastInformation.java | 5 - .../forecast/MockForecastProvider.java | 109 +++++++ .../visualforecast/forecast/TownForecast.java | 19 ++ .../visualforecast/forecast/ValueCheck.java | 45 +++ .../visualforecast/graphics/DrawingUtil.java | 76 +++++ .../visualforecast/graphics/FontManager.java | 107 +++++++ .../graphics/RenderConstants.java | 36 +++ .../flaretv/visualforecast/icons/Icon.java | 12 +- .../visualforecast/icons/IconProvider.java | 57 ++-- .../icons/impl/BlizzardIcon.java | 5 +- .../visualforecast/icons/impl/CloudIcon.java | 16 +- .../icons/impl/InvalidIcon.java | 35 +++ .../icons/impl/LightningCloudIcon.java | 36 +++ .../icons/impl/LightningIcon.java | 5 +- .../icons/impl/LightningOverlay.java | 5 +- .../icons/impl/LightningStormIcon.java | 5 +- .../icons/impl/PartlyCloudyIcon.java | 5 +- .../visualforecast/icons/impl/RainIcon.java | 5 +- .../icons/impl/RainSnowIcon.java | 5 +- .../icons/impl/SmallCloudIcon.java | 13 +- .../visualforecast/icons/impl/SnowIcon.java | 5 +- .../icons/impl/SnowflakeIcon.java | 5 +- .../visualforecast/icons/impl/SunIcon.java | 5 +- 33 files changed, 978 insertions(+), 267 deletions(-) delete mode 100644 src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/flavour/TextFlavour.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/ForecastDetails.java delete mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/TownForecast.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/forecast/ValueCheck.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/graphics/DrawingUtil.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/graphics/FontManager.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/graphics/RenderConstants.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/InvalidIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningCloudIcon.java diff --git a/.classpath b/.classpath index 5c59d7a..ad3f9d4 100644 --- a/.classpath +++ b/.classpath @@ -2,6 +2,6 @@ - + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 3a21537..8000cd6 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,11 +1,11 @@ eclipse.preferences.version=1 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.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.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=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 diff --git a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java index 6531260..3f853cb 100644 --- a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java +++ b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java @@ -3,24 +3,29 @@ package com.flaremicro.flaretv.visualforecast; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; -import java.awt.FontFormatException; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; 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.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.concurrent.locks.LockSupport; 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.forecast.MockForecastProvider; +import com.flaremicro.flaretv.visualforecast.graphics.DrawingUtil; +import com.flaremicro.flaretv.visualforecast.graphics.FontManager; +import com.flaremicro.flaretv.visualforecast.interfaces.Tickable; + +public class RenderPanel extends JPanel implements Tickable, ComponentListener { /** * @@ -29,65 +34,30 @@ public class RenderPanel extends JPanel implements Runnable { 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; - 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 String currentTown = ""; + private String currentForecast = ""; public RenderPanel() { - try - { - font = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/Star4000.ttf")); - } - catch (FontFormatException e) - { - e.printStackTrace(); - } - catch (IOException e) - { - e.printStackTrace(); - } - testString = "".split("\n"); - new Thread(this).start(); + this.addComponentListener(this); + font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")); + currentFlavour.initFlavour(this, MockForecastProvider.provideMockForecast(), ticks, iconAnimationTicks); + new Thread(new TickThread(this, 30)).start(); } - private static final int W = 640, H = 480; - 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() { + private Graphics2D prepareFrameBuffer() { 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); } return (Graphics2D) frameBuffer.getGraphics(); @@ -115,29 +85,41 @@ public class RenderPanel extends JPanel implements Runnable { public void paintComponent(Graphics g) { super.paintComponent(g); 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.setStroke(new BasicStroke(2)); - g2d.setColor(this.backgroundPurple); + g2d.setColor(BG_PURPLE); 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.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.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.setColor(this.backgroundBlue); + g2d.setColor(BG_BLUE); g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT); g2d.setColor(Color.DARK_GRAY); @@ -146,120 +128,104 @@ public class RenderPanel extends JPanel implements Runnable { g2d.setColor(Color.WHITE); 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.drawRect(60, TOPBAR_HEIGHT+2, W-120, MAINBAR_HEIGHT-4); String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix(); String timeString = TIME_FORMAT.format(System.currentTimeMillis()); - // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - // RenderingHints.VALUE_ANTIALIAS_ON); - drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, "7 Day Forecast", Color.WHITE, Color.BLACK, 1); + DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, currentForecast, Color.WHITE, Color.BLACK, 2); 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); - 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)); - drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, "Burnaby, 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"); - 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); - } - - // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - // RenderingHints.VALUE_ANTIALIAS_ON); - - IconProvider.drawIcon(g2d, IconProvider.SUN, 80, 220, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.CLOUD, 160, 220, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.PARTLY_CLOUDY, 160 + 80, 220, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.CLOUDY_CLOUDY, 160 + 160, 220, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.SCATTERD_SHOWERS, 160 + 160 + 80, 220, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.SNOWFLAKE, 160 + 160 + 160, 220, 80, animationTick); - - IconProvider.drawIcon(g2d, IconProvider.BLIZZARD, 80, 140, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.SNOW, 160, 140, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.FREEZING_RAIN, 160 + 80, 140, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN_SNOW, 160 + 160, 140, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.LIGHTNING_OVERLAY, 160 + 160+80, 140, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.LIGHTNING_STORM, 160 + 160+160, 140, 80, animationTick); - - IconProvider.drawIcon(g2d, IconProvider.RAIN_LIGHTEST, 80, 300, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN_LIGHT, 160, 300, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN, 160 + 80, 300, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN_HEAVY, 160 + 160, 300, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN_HEAVIEST, 160 + 160 + 80, 300, 80, animationTick); - IconProvider.drawIcon(g2d, IconProvider.RAIN_VANCOUVER, 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); + g2d.setFont(font.deriveFont(26F)); + DrawingUtil.drawOutlinedString(g2d, -20, H - INFOBAR_HEIGHT + 30, "Welcome to WeatherBC! Stay tuned for your long range forcast", Color.WHITE, Color.BLACK, 2); } - public 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++) + public void tick() { + this.ticks++; + if (ticks / 3.75F > this.iconAnimationTicks) { - 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); + this.iconAnimationTicks++; + //Clock and icon animations, should use repaint regions later + if (getWidth() > 0 && getHeight() > 0) + { + repaint(this.redrawBound); + } } + if (this.currentFlavour != null) + this.currentFlavour.tick(this, ticks, iconAnimationTicks); + } - 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 BufferedImage getSnapshot() { + return frameBuffer.getSnapshot(); + } + + public void addRedrawBound(int x, int y, int w, int h) { + float wScale = getWidth() / (float) W; + float hScale = getHeight() / (float) H; + Rectangle rect = new Rectangle((int) (x * wScale), (int) (y * hScale), (int) (w * wScale), (int) (h * hScale)); + if (redrawBound == null) + this.redrawBound = new Rectangle((int) (x * wScale), (int) (y * hScale), (int) (w * wScale), (int) (h * hScale)); + else this.redrawBound.add(rect); } @Override + public void componentResized(ComponentEvent e) { + this.redrawBound = null; + addRedrawBound(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); + 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 setFullRepaint() { + repaint(); + } + + /*@Override public void run() { while (true) { - this.animationTick++; + this.iconAnimationTicks++; repaint(); LockSupport.parkNanos(125000000); } - } + }*/ } diff --git a/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java b/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java deleted file mode 100644 index 56eb452..0000000 --- a/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java +++ /dev/null @@ -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); - } -} diff --git a/src/com/flaremicro/flaretv/visualforecast/TickThread.java b/src/com/flaremicro/flaretv/visualforecast/TickThread.java index b9037db..fdd3964 100644 --- a/src/com/flaremicro/flaretv/visualforecast/TickThread.java +++ b/src/com/flaremicro/flaretv/visualforecast/TickThread.java @@ -1,5 +1,7 @@ package com.flaremicro.flaretv.visualforecast; +import java.util.concurrent.locks.LockSupport; + import com.flaremicro.flaretv.visualforecast.interfaces.Tickable; public class TickThread implements Runnable { @@ -7,12 +9,16 @@ public class TickThread implements Runnable { private boolean running = true; private final long sleepNanos; - private long nextTick = 0; + //private long nextTick = 0; TickThread(Tickable tickable, long sleepNanos) { this.tickable = tickable; this.sleepNanos = sleepNanos; } + + TickThread(Tickable tickable, int ticksPerSecond) { + this(tickable, (long) ((1/(double)ticksPerSecond) * 1000000000L)); + } public void end() { this.running = false; @@ -20,7 +26,7 @@ public class TickThread implements Runnable { public void run() { while (running) { - while(System.nanoTime() < nextTick) + /*while(System.nanoTime() < nextTick) { try { @@ -32,12 +38,13 @@ public class TickThread implements Runnable { } } nextTick = System.nanoTime() + sleepNanos; + tickable.tick();*/ + long nanosLost = System.nanoTime(); tickable.tick(); - /*long nanosLost = System.nanoTime(); - panel.tick(); nanosLost -= System.nanoTime(); - if(sleepNanos+nanosLost > 0) - LockSupport.parkNanos(sleepNanos+nanosLost);*/ + //Unnecessary conditional? + //if(sleepNanos+nanosLost > 0) + LockSupport.parkNanos(sleepNanos+nanosLost); } } } \ No newline at end of file diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java new file mode 100644 index 0000000..546a3ae --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java @@ -0,0 +1,172 @@ +package com.flaremicro.flaretv.visualforecast.flavour; + +import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT; + +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.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 int townIndex; + + private BufferedImage lastBound = null; + + private int ticksBeforeChange = 200; + + 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) { + ticksBeforeChange--; + if (ticksBeforeChange < 0) + { + ticksBeforeChange = 200; + dayOffset = dayOffset + 4; + if (dayOffset >= 8) + { + dayOffset = 0; + townIndex++; + if (townIndex >= details.getTownForecast().length) + { + renderer.nextFlavour(); + } + else + { + currentTown = details.getTownForecast()[townIndex]; + renderer.setCurrentTown(currentTown.getTownName()); + } + } + renderer.setFullRepaint(); + } + } + + @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 + { + for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - this.dayOffset); i++) + { + + DayForecast forecast = currentTown.getDayForecast()[i+this.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); + + 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); + } + } + } + lastBound = renderer.getSnapshot().getSubimage(RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 15, 524, MAINBAR_HEIGHT - 30); + lastBound.setAccelerationPriority(1); + } + + @Override + public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) { + g2d.drawImage(lastBound, RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 15, renderer); + if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0) + { + for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - this.dayOffset); i++) + { + DayForecast forecast = currentTown.getDayForecast()[i+this.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) { + renderer.addRedrawBound(RenderConstants.SIDE_OFFSET + 24, RenderConstants.TOPBAR_HEIGHT + 60, 604, 84); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java b/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java index eef212f..0f5ddab 100644 --- a/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/Flavour.java @@ -1,5 +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); } diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/TextFlavour.java b/src/com/flaremicro/flaretv/visualforecast/flavour/TextFlavour.java new file mode 100644 index 0000000..2c0e82c --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/TextFlavour.java @@ -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 + + } + + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java b/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java new file mode 100644 index 0000000..5dfacc9 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java @@ -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 = iconId; + this.weatherLine1 = weatherLine1; + this.weatherLine2 = weatherLine2; + this.percipPercent = percipPercent; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastDetails.java b/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastDetails.java new file mode 100644 index 0000000..37eefb8 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastDetails.java @@ -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; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java b/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java deleted file mode 100644 index bac895d..0000000 --- a/src/com/flaremicro/flaretv/visualforecast/forecast/ForecastInformation.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.flaremicro.flaretv.visualforecast.forecast; - -public class ForecastInformation { - -} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java b/src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java new file mode 100644 index 0000000..dae6732 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java @@ -0,0 +1,109 @@ +package com.flaremicro.flaretv.visualforecast.forecast; + +import java.util.Random; + +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), + }; + + + 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[7 + random.nextInt(2)]; + for(int i = 0; i < df.length; i++) + { + 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; + } +} \ No newline at end of file diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/TownForecast.java b/src/com/flaremicro/flaretv/visualforecast/forecast/TownForecast.java new file mode 100644 index 0000000..693716a --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/TownForecast.java @@ -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; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/ValueCheck.java b/src/com/flaremicro/flaretv/visualforecast/forecast/ValueCheck.java new file mode 100644 index 0000000..f718147 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/ValueCheck.java @@ -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; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/graphics/DrawingUtil.java b/src/com/flaremicro/flaretv/visualforecast/graphics/DrawingUtil.java new file mode 100644 index 0000000..86a08a5 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/graphics/DrawingUtil.java @@ -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); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/graphics/FontManager.java b/src/com/flaremicro/flaretv/visualforecast/graphics/FontManager.java new file mode 100644 index 0000000..59ad676 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/graphics/FontManager.java @@ -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 urlToFontMapping = new HashMap(); + private List fonts = new ArrayList(); + + 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; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/graphics/RenderConstants.java b/src/com/flaremicro/flaretv/visualforecast/graphics/RenderConstants.java new file mode 100644 index 0000000..20be0be --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/graphics/RenderConstants.java @@ -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); +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java index 4259d06..71d54f3 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java @@ -2,7 +2,13 @@ package com.flaremicro.flaretv.visualforecast.icons; import java.awt.Graphics2D; -public interface Icon { - public boolean isAnimated(); - public void drawIcon(Graphics2D g2d, float scale, int animationStep); +public abstract class Icon { + + 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); } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java index 80665f4..9f0dd7d 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java @@ -5,6 +5,7 @@ import java.awt.geom.AffineTransform; import com.flaremicro.flaretv.visualforecast.icons.impl.BlizzardIcon; import com.flaremicro.flaretv.visualforecast.icons.impl.CloudIcon; +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; @@ -18,28 +19,44 @@ import com.flaremicro.flaretv.visualforecast.icons.impl.SunIcon; public class IconProvider { + public static final Icon[] INDEXED_ICONS = new Icon[64]; - public static final Icon SUN = new SunIcon(); - public static final Icon CLOUD = new CloudIcon(); - public static final Icon PARTLY_CLOUDY = new PartlyCloudyIcon(CLOUD, SUN); - public static final Icon CLOUDY_CLOUDY = new PartlyCloudyIcon(CLOUD, CLOUD); - public static final Icon RAIN_LIGHTEST = new RainIcon(2, 2F, CLOUD); - public static final Icon RAIN_LIGHT = new RainIcon(3, 2F, CLOUD); - public static final Icon RAIN = new RainIcon(3, 1F, CLOUD); - public static final Icon RAIN_HEAVY = new RainIcon(4, 1F, CLOUD); - public static final Icon RAIN_HEAVIEST = new RainIcon(5, 1F, CLOUD); - public static final Icon RAIN_VANCOUVER = new RainIcon(6, 1F, CLOUD); - public static final Icon SCATTERD_SHOWERS = new PartlyCloudyIcon(new RainIcon(2, 4F, CLOUD), SUN); - public static final Icon SNOWFLAKE = new SnowflakeIcon(); - public static final Icon SNOW = new SnowIcon(CLOUD, SNOWFLAKE); - public static final Icon BLIZZARD = new BlizzardIcon(CLOUD, SNOWFLAKE); - public static final Icon RAIN_SNOW = new RainSnowIcon(RAIN_LIGHTEST, SNOWFLAKE, true); - public static final Icon FREEZING_RAIN = new RainSnowIcon(RAIN_LIGHT, SNOWFLAKE, false); - public static final Icon LIGHTNING_BOLT = new LightningIcon(); - public static final Icon LIGHTNING_STORM = new LightningStormIcon(CLOUD, LIGHTNING_BOLT); - public static final Icon SMALL_CLOUD = new SmallCloudIcon(); - public static final Icon LIGHTNING_OVERLAY = new LightningOverlay(SMALL_CLOUD, LIGHTNING_BOLT, BLIZZARD); + 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)); + private static Icon registerIcon(Icon icon) + { + INDEXED_ICONS[icon.id] = icon; + return icon; + } + + 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 != null) diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java index 8851f81..d9205ed 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java @@ -5,14 +5,15 @@ import java.awt.geom.AffineTransform; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class BlizzardIcon implements Icon { +public class BlizzardIcon extends Icon { private final Icon cloudIcon; private final Icon snowflakeIcon; - public BlizzardIcon(Icon cloudIcon, Icon snowflakeIcon) + public BlizzardIcon(int id, Icon cloudIcon, Icon snowflakeIcon) { + super(id); this.cloudIcon = cloudIcon; this.snowflakeIcon = snowflakeIcon; } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java index 67e6447..658cdfa 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/CloudIcon.java @@ -7,8 +7,8 @@ import java.awt.geom.Ellipse2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class CloudIcon implements 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.142F, 0.619F, 0.287F, 0.231F), new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F), @@ -20,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.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.113F, 0.326F, 0.266F, 0.356F), new Ellipse2D.Float(0.749F, 0.412F, 0.251F, 0.417F), 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.554F, 0.276F, 0.204F, 0.314F), new Ellipse2D.Float(0.770F, 0.440F, 0.204F, 0.235F), @@ -42,7 +42,7 @@ public class CloudIcon implements Icon { 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.573F, 0.296F, 0.204F, 0.314F), new Ellipse2D.Float(0.789F, 0.456F, 0.204F, 0.235F), @@ -50,6 +50,10 @@ public class CloudIcon implements Icon { new Ellipse2D.Float(0.288F, 0.476F, 0.314F, 0.235F), }; + public CloudIcon(int id) + { + super(id); + } @Override public void drawIcon(Graphics2D g2d, float scale, int animationStep) { diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/InvalidIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/InvalidIcon.java new file mode 100644 index 0000000..ec502e7 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/InvalidIcon.java @@ -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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningCloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningCloudIcon.java new file mode 100644 index 0000000..5d1834b --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningCloudIcon.java @@ -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(); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java index 7127e53..aaec729 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningIcon.java @@ -7,7 +7,7 @@ import java.awt.geom.Path2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class LightningIcon implements Icon { +public class LightningIcon extends Icon { Path2D.Float boltPath = new Path2D.Float(); Path2D.Float shinePath = new Path2D.Float(); @@ -39,8 +39,9 @@ public class LightningIcon implements Icon { new Color(0xFFFF00), }; - public LightningIcon() + public LightningIcon(int id) { + super(id); boltPath.moveTo(0.380, 0); boltPath.lineTo(0.680, 0); boltPath.lineTo(0.577, 0.206); diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java index 782addf..03766c2 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningOverlay.java @@ -3,13 +3,14 @@ package com.flaremicro.flaretv.visualforecast.icons.impl; import java.awt.Graphics2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class LightningOverlay implements Icon { +public class LightningOverlay extends Icon { private final Icon boltIcon; private final Icon smallCloudIcon; private final Icon weatherIcon; - public LightningOverlay(Icon smallCloudIcon, Icon boltIcon, Icon weatherIcon) { + public LightningOverlay(int id, Icon smallCloudIcon, Icon boltIcon, Icon weatherIcon) { + super(id); this.smallCloudIcon = smallCloudIcon; this.boltIcon = boltIcon; this.weatherIcon = weatherIcon; diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java index ad7ed78..6f3a8ae 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/LightningStormIcon.java @@ -4,13 +4,14 @@ import java.awt.BasicStroke; import java.awt.Graphics2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class LightningStormIcon implements Icon { +public class LightningStormIcon extends Icon { private final Icon boltIcon; private final Icon cloudIcon; - public LightningStormIcon(Icon cloudIcon, Icon boltIcon) + public LightningStormIcon(int id, Icon cloudIcon, Icon boltIcon) { + super(id); this.cloudIcon = cloudIcon; this.boltIcon = boltIcon; diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java index 1ee7382..d0c5e9c 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/PartlyCloudyIcon.java @@ -4,12 +4,13 @@ import java.awt.Graphics2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class PartlyCloudyIcon implements Icon { +public class PartlyCloudyIcon extends Icon { private Icon cloud; private Icon sun; - public PartlyCloudyIcon(Icon cloud, Icon sun) + public PartlyCloudyIcon(int id, Icon cloud, Icon sun) { + super(id); this.cloud = cloud; this.sun = sun; } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java index cf62ee7..ec8b7c5 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainIcon.java @@ -7,7 +7,7 @@ import java.awt.geom.Path2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class RainIcon implements Icon { +public class RainIcon extends Icon { private final int rainCount; private final float rainSpace; private final Icon cloudIcon; @@ -28,8 +28,9 @@ public class RainIcon implements Icon { 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.rainSpace = rainSpace * 0.125F; this.cloudIcon = cloudIcon; diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java index a964408..5e7a1bd 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/RainSnowIcon.java @@ -3,15 +3,16 @@ package com.flaremicro.flaretv.visualforecast.icons.impl; import java.awt.Graphics2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class RainSnowIcon implements Icon { +public class RainSnowIcon extends Icon { private final Icon rainIcon; private final Icon snowflakeIcon; private final boolean snow; - public RainSnowIcon(Icon rainIcon, Icon snowflakeIcon, boolean snow) + public RainSnowIcon(int id, Icon rainIcon, Icon snowflakeIcon, boolean snow) { + super(id); this.rainIcon = rainIcon; this.snowflakeIcon = snowflakeIcon; this.snow = snow; diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java index f8fc5db..39a5dff 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SmallCloudIcon.java @@ -6,8 +6,13 @@ import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class SmallCloudIcon implements Icon { - Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{ +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), @@ -16,14 +21,14 @@ public class SmallCloudIcon implements Icon { new Ellipse2D.Float(0.000F, 0.199F, 0.428F, 0.801F) }; - Ellipse2D.Float[] lightCircles = new Ellipse2D.Float[]{ + 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) }; - Ellipse2D.Float[] overLight = new Ellipse2D.Float[]{ + 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), diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java index b64c6c6..58d1c26 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowIcon.java @@ -5,14 +5,15 @@ import java.awt.geom.AffineTransform; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class SnowIcon implements Icon { +public class SnowIcon extends Icon { private final Icon cloudIcon; private final Icon snowflakeIcon; - public SnowIcon(Icon cloudIcon, Icon snowflakeIcon) + public SnowIcon(int id, Icon cloudIcon, Icon snowflakeIcon) { + super(id); this.cloudIcon = cloudIcon; this.snowflakeIcon = snowflakeIcon; } diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java index c7cba30..6a971ec 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SnowflakeIcon.java @@ -7,7 +7,7 @@ import java.awt.geom.Path2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class SnowflakeIcon implements Icon { +public class SnowflakeIcon extends Icon { Path2D.Float flakePath = new Path2D.Float(); Path2D.Float gradPath = new Path2D.Float(); Path2D.Float trianglePath = new Path2D.Float(); @@ -27,8 +27,9 @@ public class SnowflakeIcon implements Icon { new Color(0x2288FF), }; - public SnowflakeIcon() + public SnowflakeIcon(int id) { + super(id); flakePath.moveTo(0.400, 0); flakePath.lineTo(0.600, 0); flakePath.lineTo(0.600, 0.327); diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java index b65f077..307ea46 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SunIcon.java @@ -8,7 +8,7 @@ import java.awt.geom.Path2D; import com.flaremicro.flaretv.visualforecast.icons.Icon; -public class SunIcon implements Icon { +public class SunIcon extends Icon { Path2D.Float sunPath = new Path2D.Float(); 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); @@ -27,8 +27,9 @@ public class SunIcon implements Icon { new Color(255, 140, 0), new Color(255, 120, 0), }; - public SunIcon() + public SunIcon(int id) { + super(id); sunPath.moveTo(0.5F, 0.0F); sunPath.lineTo(0.605F, 0.106F); sunPath.lineTo(0.750F, 0.067F); -- 2.39.5 From 3e225d407814f7d997ba564fb44fe6d2cc97e61b Mon Sep 17 00:00:00 2001 From: Flare Microsystems Date: Wed, 6 Mar 2024 14:24:23 -0800 Subject: [PATCH 3/3] ??? --- .../flaretv/visualforecast/Executor.java | 37 +++ .../visualforecast/PropertyManager.java | 53 ++++ .../flaretv/visualforecast/RenderPanel.java | 31 ++- .../flaretv/visualforecast/TickThread.java | 3 +- .../visualforecast/VisualForecastFrame.java | 118 +++++++- .../flavour/DayForecastFlavour.java | 235 +++++++++++----- .../DayForecastFlavourOldAnimation.java | 261 ++++++++++++++++++ .../visualforecast/forecast/DayForecast.java | 2 +- .../visualforecast/icons/IconProvider.java | 9 + .../icons/impl/BlizzardIcon.java | 8 +- .../visualforecast/icons/impl/ButterIcon.java | 106 +++++++ .../visualforecast/icons/impl/FogIcon.java | 69 +++++ .../icons/impl/IceCubeIcon.java | 129 +++++++++ .../visualforecast/icons/impl/SleetIcon.java | 106 +++++++ .../providerapi/ForecastProvider.java | 12 + .../providerapi/ForecastProviderManager.java | 70 +++++ .../MockForecastProvider.java | 62 +++-- src/com/flaremicro/util/Util.java | 93 +++++++ .../flaremicro/util/logging/LogFormatter.java | 31 +++ .../util/logging/LogOutputStream.java | 38 +++ 20 files changed, 1370 insertions(+), 103 deletions(-) create mode 100644 src/com/flaremicro/flaretv/visualforecast/Executor.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/PropertyManager.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavourOldAnimation.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/ButterIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/FogIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/IceCubeIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/icons/impl/SleetIcon.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProvider.java create mode 100644 src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProviderManager.java rename src/com/flaremicro/flaretv/visualforecast/{forecast => providerapi}/MockForecastProvider.java (62%) create mode 100644 src/com/flaremicro/util/Util.java create mode 100644 src/com/flaremicro/util/logging/LogFormatter.java create mode 100644 src/com/flaremicro/util/logging/LogOutputStream.java diff --git a/src/com/flaremicro/flaretv/visualforecast/Executor.java b/src/com/flaremicro/flaretv/visualforecast/Executor.java new file mode 100644 index 0000000..ce6af6b --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/Executor.java @@ -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); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/PropertyManager.java b/src/com/flaremicro/flaretv/visualforecast/PropertyManager.java new file mode 100644 index 0000000..3efc6df --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/PropertyManager.java @@ -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; + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java index 3f853cb..bd74c49 100644 --- a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java +++ b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java @@ -20,10 +20,10 @@ import static com.flaremicro.flaretv.visualforecast.graphics.RenderConstants.*; import com.flaremicro.flaretv.visualforecast.flavour.DayForecastFlavour; import com.flaremicro.flaretv.visualforecast.flavour.Flavour; -import com.flaremicro.flaretv.visualforecast.forecast.MockForecastProvider; 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 { @@ -42,15 +42,17 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener { private long ticks = 0; private Rectangle redrawBound = new Rectangle(0, 0, 1, 1); + private Rectangle exclusiveRedrawBound = null; private String currentTown = ""; private String currentForecast = ""; public RenderPanel() { this.addComponentListener(this); + this.setDoubleBuffered(true); font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")); currentFlavour.initFlavour(this, MockForecastProvider.provideMockForecast(), ticks, iconAnimationTicks); - new Thread(new TickThread(this, 30)).start(); + //new Thread(new TickThread(this, 30)).start(); } private Graphics2D prepareFrameBuffer() { @@ -165,20 +167,31 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener { public BufferedImage getSnapshot() { return frameBuffer.getSnapshot(); } + + private void addRedrawBound(int x, int y, int w, int h, boolean isExclusive){ - public void addRedrawBound(int x, int y, int w, int h) { float wScale = getWidth() / (float) W; float hScale = getHeight() / (float) H; Rectangle rect = new Rectangle((int) (x * wScale), (int) (y * hScale), (int) (w * wScale), (int) (h * hScale)); + 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 public void componentResized(ComponentEvent e) { + loseRedrawRegion(); + } + + public void loseRedrawRegion() { this.redrawBound = null; - addRedrawBound(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); + addRedrawBound(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT, false); if (this.currentFlavour != null) this.currentFlavour.redrawRegionlost(this); } @@ -214,10 +227,18 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener { this.currentForecast = currentForecast; } - public void setFullRepaint() { + public void requestFullRepaint() { repaint(); } + public void requestBoundedRepaint() { + repaint(redrawBound); + } + + public void requestExclusiveBoundedRepaint() { + repaint(exclusiveRedrawBound); + } + /*@Override public void run() { while (true) diff --git a/src/com/flaremicro/flaretv/visualforecast/TickThread.java b/src/com/flaremicro/flaretv/visualforecast/TickThread.java index fdd3964..4556df1 100644 --- a/src/com/flaremicro/flaretv/visualforecast/TickThread.java +++ b/src/com/flaremicro/flaretv/visualforecast/TickThread.java @@ -25,6 +25,7 @@ public class TickThread implements Runnable { } public void run() { + long nanosLost = 0; while (running) { /*while(System.nanoTime() < nextTick) { @@ -39,12 +40,12 @@ public class TickThread implements Runnable { } nextTick = System.nanoTime() + sleepNanos; tickable.tick();*/ - long nanosLost = System.nanoTime(); tickable.tick(); nanosLost -= System.nanoTime(); //Unnecessary conditional? //if(sleepNanos+nanosLost > 0) LockSupport.parkNanos(sleepNanos+nanosLost); + nanosLost = System.nanoTime(); } } } \ No newline at end of file diff --git a/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java b/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java index 4428ca9..a467588 100644 --- a/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java +++ b/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java @@ -2,16 +2,26 @@ package com.flaremicro.flaretv.visualforecast; import java.awt.BorderLayout; 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; -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 RenderPanel contentPane; + private RenderPanel renderPane; + private ForecastProviderManager forecastProviderManager; + private Executor executor; + private PropertyManager propertyManager; + private boolean isFullscreen = false; /** * Launch the application. @@ -22,24 +32,118 @@ public class VisualForecastFrame extends JFrame { try { VisualForecastFrame frame = new VisualForecastFrame(); frame.setVisible(true); + frame.init(); + //GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[1].setFullScreenWindow(frame); + frame.createBufferStrategy(2); } catch (Exception e) { e.printStackTrace(); } } }); } + + 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. */ public VisualForecastFrame() { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setBounds(100, 100, 640*2, 480*2); - contentPane = new RenderPanel(); - contentPane.setBorder(null); - contentPane.setLayout(new BorderLayout(0, 0)); - setContentPane(contentPane); + renderPane = new RenderPanel(); + renderPane.setBorder(null); + renderPane.setLayout(new BorderLayout(0, 0)); + setContentPane(renderPane); 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 + } } diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java index 546a3ae..d11eb35 100644 --- a/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavour.java @@ -2,12 +2,14 @@ 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; @@ -28,11 +30,14 @@ public class DayForecastFlavour implements Flavour { private Font smallFont; private ForecastDetails details; private TownForecast currentTown = null; + private TownForecast previousTown = null; private int townIndex; - private BufferedImage lastBound = null; + 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")); @@ -41,26 +46,62 @@ public class DayForecastFlavour implements Flavour { @Override public void tick(RenderPanel renderer, long ticks, int iconTicks) { - ticksBeforeChange--; - if (ticksBeforeChange < 0) + if(animationTicks >= 0) { - ticksBeforeChange = 200; - dayOffset = dayOffset + 4; - if (dayOffset >= 8) + animationTicks += 8; + if(animationTicks > RenderConstants.W - 60) { - dayOffset = 0; - townIndex++; - if (townIndex >= details.getTownForecast().length) - { - renderer.nextFlavour(); - } - else - { - currentTown = details.getTownForecast()[townIndex]; - renderer.setCurrentTown(currentTown.getTownName()); - } + 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(); } - renderer.setFullRepaint(); } } @@ -95,78 +136,148 @@ public class DayForecastFlavour implements Flavour { 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 { - for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - this.dayOffset); i++) + if(animationTicks < 0) { - - DayForecast forecast = currentTown.getDayForecast()[i+this.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)) + 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) { - statLine1 = "MISSING"; - statLine2 = "DATA"; + drawTownForecast(gimg, previousTown, dayOffset + 4); + drawTownForecast(gimg2, currentTown, dayOffset); + } else { + drawTownForecast(gimg, currentTown, dayOffset - 4); + drawTownForecast(gimg2, currentTown, dayOffset); } - 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); + 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); - } + 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); } } - lastBound = renderer.getSnapshot().getSubimage(RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 15, 524, MAINBAR_HEIGHT - 30); - lastBound.setAccelerationPriority(1); } @Override public void drawBoundLimitedFlavour(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) { - g2d.drawImage(lastBound, RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 15, renderer); if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0) { - for (int i = 0; i < Math.min(4, currentTown.getDayForecast().length - this.dayOffset); i++) + if(animationTicks < 0) { - DayForecast forecast = currentTown.getDayForecast()[i+this.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); + 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) { - renderer.addRedrawBound(RenderConstants.SIDE_OFFSET + 24, RenderConstants.TOPBAR_HEIGHT + 60, 604, 84); + 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); } } diff --git a/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavourOldAnimation.java b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavourOldAnimation.java new file mode 100644 index 0000000..2013a2a --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/flavour/DayForecastFlavourOldAnimation.java @@ -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); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java b/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java index 5dfacc9..281ac55 100644 --- a/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java +++ b/src/com/flaremicro/flaretv/visualforecast/forecast/DayForecast.java @@ -11,7 +11,7 @@ public class DayForecast { public DayForecast(byte hiTemp, byte loTemp, byte iconId, String weatherLine1, String weatherLine2, float percipPercent){ this.hiTemp = hiTemp; this.loTemp = loTemp; - this.iconId = iconId; + this.iconId = (byte)(iconId & 63); this.weatherLine1 = weatherLine1; this.weatherLine2 = weatherLine2; this.percipPercent = percipPercent; diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java index 9f0dd7d..6f0897d 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java @@ -4,7 +4,10 @@ import java.awt.Graphics2D; 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; @@ -43,6 +46,12 @@ public class IconProvider { 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 Icon registerIcon(Icon icon) { diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java index d9205ed..bbdf4b6 100644 --- a/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/BlizzardIcon.java @@ -25,11 +25,11 @@ public class BlizzardIcon extends Icon { g2d.translate(0, 3); snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep); g2d.translate(1, -1); - snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep); + snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+1); g2d.translate(1, 1); - snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep); + snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+2); g2d.translate(1, -1); - snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep); + snowflakeIcon.drawIcon(g2d, scale*0.25F, animationStep+3); g2d.setTransform(af); g2d.translate(0F, -0.10F); g2d.scale(1F, 0.8F); @@ -37,7 +37,7 @@ public class BlizzardIcon extends Icon { g2d.setTransform(af); g2d.translate(0.3F, 0); g2d.scale(0.7F, 0.7F); - snowflakeIcon.drawIcon(g2d, scale*0.7F, animationStep); + snowflakeIcon.drawIcon(g2d, scale*0.7F, animationStep+4); g2d.setTransform(af); diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/ButterIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/ButterIcon.java new file mode 100644 index 0000000..98ede5f --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/ButterIcon.java @@ -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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/FogIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/FogIcon.java new file mode 100644 index 0000000..108b1b0 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/FogIcon.java @@ -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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/IceCubeIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/IceCubeIcon.java new file mode 100644 index 0000000..9e8bc92 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/IceCubeIcon.java @@ -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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/impl/SleetIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SleetIcon.java new file mode 100644 index 0000000..bc9fbac --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/impl/SleetIcon.java @@ -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; + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProvider.java b/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProvider.java new file mode 100644 index 0000000..c3b3dc8 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProvider.java @@ -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(); +} diff --git a/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProviderManager.java b/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProviderManager.java new file mode 100644 index 0000000..b158b6e --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/providerapi/ForecastProviderManager.java @@ -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(); + } + + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java b/src/com/flaremicro/flaretv/visualforecast/providerapi/MockForecastProvider.java similarity index 62% rename from src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java rename to src/com/flaremicro/flaretv/visualforecast/providerapi/MockForecastProvider.java index dae6732..b844e2c 100644 --- a/src/com/flaremicro/flaretv/visualforecast/forecast/MockForecastProvider.java +++ b/src/com/flaremicro/flaretv/visualforecast/providerapi/MockForecastProvider.java @@ -1,7 +1,11 @@ -package com.flaremicro.flaretv.visualforecast.forecast; +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 { @@ -34,6 +38,11 @@ public class MockForecastProvider { 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), }; @@ -57,34 +66,41 @@ public class MockForecastProvider { private static DayForecast[] provideDayForecast(Random random) { - DayForecast[] df = new DayForecast[7 + random.nextInt(2)]; + DayForecast[] df = new DayForecast[8]; for(int i = 0; i < df.length; i++) { - byte hiTemp = (byte)(random.nextInt(60)-20); - byte loTemp = (byte)(random.nextInt(60)-20); - if(hiTemp < loTemp) + if(random.nextInt(11) == 10) { - byte temp = hiTemp; - hiTemp = loTemp; - loTemp = temp; + df[i] = new DayForecast(ValueCheck.NO_DATA_BYTE, ValueCheck.NO_DATA_BYTE, (byte)0, null, null, ValueCheck.NO_DATA_FLOAT); } - - 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) + else { - percipPercent = random.nextFloat() * 100; + 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); } - - df[i] = new DayForecast(hiTemp, loTemp, iconId, weatherLine1, weatherLine2, percipPercent); } return df; } diff --git a/src/com/flaremicro/util/Util.java b/src/com/flaremicro/util/Util.java new file mode 100644 index 0000000..53693f3 --- /dev/null +++ b/src/com/flaremicro/util/Util.java @@ -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 parseArgs(String args[], boolean keyToLower) { + HashMap map = new HashMap(); + 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 toArguments(Applet applet, String[] expectedParameters) { + HashMap arguments = new HashMap(); + 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; + } +} diff --git a/src/com/flaremicro/util/logging/LogFormatter.java b/src/com/flaremicro/util/logging/LogFormatter.java new file mode 100644 index 0000000..ca7015a --- /dev/null +++ b/src/com/flaremicro/util/logging/LogFormatter.java @@ -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 ""; + } +} diff --git a/src/com/flaremicro/util/logging/LogOutputStream.java b/src/com/flaremicro/util/logging/LogOutputStream.java new file mode 100644 index 0000000..ab5acd5 --- /dev/null +++ b/src/com/flaremicro/util/logging/LogOutputStream.java @@ -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 = ""; + } + +} \ No newline at end of file -- 2.39.5