From 3e225d407814f7d997ba564fb44fe6d2cc97e61b Mon Sep 17 00:00:00 2001 From: Flare Microsystems Date: Wed, 6 Mar 2024 14:24:23 -0800 Subject: [PATCH] ??? --- .../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