3 Commits

Author SHA1 Message Date
Flare Microsystems
81d81bebae No idea what this changed 2024-03-07 19:30:15 -08:00
Flare Microsystems
107f83084e crawl 2024-03-07 16:27:21 -08:00
Flare Microsystems
e0ef9e61f8 Merge branch 'feature/providers' into 'master'
Added providers

See merge request FlareMicrosystems/visualforecast-1000!3
2024-03-07 22:19:59 +00:00
13 changed files with 221 additions and 449 deletions

Binary file not shown.

View File

@@ -1,4 +1,4 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Thu Mar 07 14:12:25 PST 2024 #Thu Mar 07 19:30:06 PST 2024
towns-by-code= towns-by-code=
towns-by-name-and-province=Vancouver,BC;Kamloops,BC;Kelowna,BC towns-by-name-and-province=Vancouver,BC;Kamloops,BC;Kelowna,BC

View File

@@ -1,4 +0,0 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Thu Mar 07 14:12:28 PST 2024
towns-by-code=
towns-by-name-and-province=Vancouver,BC;Kamloops,BC;Kelowna,BC

1
crawl.txt Normal file
View File

@@ -0,0 +1 @@
Datamart information retrieved from ECCC and from TMSC. Information displayed on short-form forecasts may be formatted to fit on screen, however intent was kept as accurate as possible. Weather warnings and alerts displayed are as provided.

View File

@@ -9,34 +9,10 @@ import java.util.Random;
import java.util.logging.ConsoleHandler; import java.util.logging.ConsoleHandler;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.flaremicro.util.logging.LogFormatter;
import com.flaremicro.util.logging.LogOutputStream;
public class Util { 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 * Parse arguments, in arg=value format, or just arg for arguments with no

View File

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

View File

@@ -1,38 +0,0 @@
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 = "";
}
}

View File

@@ -12,12 +12,19 @@ import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener; import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage; import java.awt.image.VolatileImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import javax.swing.JPanel; import javax.swing.JPanel;
import static com.flaremicro.visualforecast.graphics.RenderConstants.*; import static com.flaremicro.visualforecast.graphics.RenderConstants.*;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.BootupDisplay; import com.flaremicro.visualforecast.displays.BootupDisplay;
import com.flaremicro.visualforecast.displays.DayForecastDisplay; import com.flaremicro.visualforecast.displays.DayForecastDisplay;
@@ -34,7 +41,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
*/ */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private VolatileImage frameBuffer = null; private BufferedImage frameBuffer = null;
private Font font = null; private Font font = null;
@@ -50,24 +57,24 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
private String currentForecast = ""; private String currentForecast = "";
private ForecastProvider forecastProvider = null; private ForecastProvider forecastProvider = null;
private PropertyManager propManager; private PropertyManager propManager;
public Rectangle nextRedrawBound = null;
public RenderPanel(PropertyManager propManager) { public RenderPanel(PropertyManager propManager) {
//loadCrawlStrings();
this.addComponentListener(this); this.addComponentListener(this);
this.setDoubleBuffered(true); this.setDoubleBuffered(true);
this.propManager = propManager; this.propManager = propManager;
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")); font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
currentFlavour.initDisplay(this, null, ticks, iconAnimationTicks); currentFlavour.initDisplay(this, null, ticks, iconAnimationTicks);
//new Thread(new TickThread(this, 30)).start();
} }
private Graphics2D prepareFrameBuffer() { private Graphics2D getBuffer() {
GraphicsConfiguration gc = this.getGraphicsConfiguration(); if (frameBuffer == null)
if (frameBuffer == null || frameBuffer.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE)
{ {
System.out.println("new image req'd"); frameBuffer = this.getGraphicsConfiguration().createCompatibleImage(W, H);
frameBuffer = gc.createCompatibleVolatileImage(W, H);
} }
return (Graphics2D) frameBuffer.getGraphics(); return (Graphics2D) frameBuffer.getGraphics();
} }
@@ -93,41 +100,67 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
@Override @Override
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
Graphics2D g2d = prepareFrameBuffer(); if(frameBuffer == null)
drawMainRegion(g2d);
if (currentFlavour != null)
{ {
if (this.getBounds().equals(g.getClipBounds())) initBuffer();
this.currentFlavour.drawDisplay(this, g2d, ticks, iconAnimationTicks);
if (g.getClipBounds() != null)
this.currentFlavour.drawBoundLimitedDisplay(this, g2d, g.getClipBounds(), ticks, iconAnimationTicks);
} }
g2d.dispose();
g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this); g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this);
} }
public void initBuffer() {
Graphics2D g2d = getBuffer();
this.drawEntireMainRegion(g2d);
g2d.dispose();
}
private void drawMainRegion(Graphics2D g2d) { private void drawTitleHeader(Graphics2D g2d)
{
g2d.setFont(font.deriveFont(24F)); g2d.setFont(font.deriveFont(24F));
g2d.setStroke(new BasicStroke(2));
g2d.setColor(BG_PURPLE);
g2d.fillRect(0, 0, W, TOPBAR_HEIGHT);
g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_OORANGE, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE)); g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_OORANGE, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE));
g2d.shear(HEADERBAR_SHEAR, 0); g2d.shear(HEADERBAR_SHEAR, 0);
g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT); g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT);
g2d.shear(-HEADERBAR_SHEAR, 0);
DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, currentForecast, Color.WHITE, Color.BLACK, 2);
g2d.setFont(font.deriveFont(36F));
DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, currentTown, Color.YELLOW, Color.BLACK, 2);
}
private void drawTimeHeader(Graphics2D g2d)
{
g2d.setFont(font.deriveFont(24F));
g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_PURPLE.brighter().brighter().brighter(), 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE)); g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_PURPLE.brighter().brighter().brighter(), 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE));
g2d.shear(HEADERBAR_SHEAR, 0);
g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT);
g2d.shear(-HEADERBAR_SHEAR, 0); g2d.shear(-HEADERBAR_SHEAR, 0);
String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix();
String timeString = TIME_FORMAT.format(System.currentTimeMillis());
int sw = g2d.getFontMetrics().stringWidth(dateString);
DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 2);
sw = g2d.getFontMetrics().stringWidth(timeString);
DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 2);
}
private void drawHeader(Graphics2D g2d)
{
g2d.setColor(BG_PURPLE);
g2d.fillRect(0, 0, W, TOPBAR_HEIGHT);
drawTitleHeader(g2d);
drawTimeHeader(g2d);
}
public void drawMainGradient(Graphics2D g2d)
{
g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, BG_PURPLE, 0, MAINBAR_HEIGHT, BG_OORANGE)); g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, BG_PURPLE, 0, MAINBAR_HEIGHT, BG_OORANGE));
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
}
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
private void drawCrawlBar(Graphics2D g2d){
g2d.setStroke(new BasicStroke(2));
g2d.setColor(BG_BLUE); g2d.setColor(BG_BLUE);
g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT); g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT);
@@ -136,24 +169,17 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
g2d.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET); g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET);
/*if (this.currentCrawlString != null)
{
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, this.crawlPosition, H - INFOBAR_HEIGHT + 30, this.currentCrawlString, Color.WHITE, Color.BLACK, 2);
}*/
}
// g2d.setColor(Color.GRAY); private void drawEntireMainRegion(Graphics2D g2d) {
// g2d.drawRect(60, TOPBAR_HEIGHT+2, W-120, MAINBAR_HEIGHT-4); drawHeader(g2d);
drawMainGradient(g2d);
String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix(); drawCrawlBar(g2d);
String timeString = TIME_FORMAT.format(System.currentTimeMillis());
DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, currentForecast, Color.WHITE, Color.BLACK, 2);
int sw = g2d.getFontMetrics().stringWidth(dateString);
DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 2);
sw = g2d.getFontMetrics().stringWidth(timeString);
DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 2);
g2d.setFont(font.deriveFont(36F));
DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, currentTown, Color.YELLOW, Color.BLACK, 2);
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 tick() { public void tick() {
@@ -164,15 +190,28 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
//Clock and icon animations, should use repaint regions later //Clock and icon animations, should use repaint regions later
if (getWidth() > 0 && getHeight() > 0) if (getWidth() > 0 && getHeight() > 0)
{ {
repaint(this.redrawBound); Graphics2D g2d = this.getBuffer();
this.drawTimeHeader(g2d);
g2d.dispose();
requestBoundedRepaint();
//repaint(this.redrawBound);
} }
} }
if (this.currentFlavour != null) if (this.currentFlavour != null)
{
this.currentFlavour.tick(this, ticks, iconAnimationTicks); this.currentFlavour.tick(this, ticks, iconAnimationTicks);
} }
if(this.nextRedrawBound != null)
public BufferedImage getSnapshot() { {
return frameBuffer.getSnapshot(); Graphics2D g2d = this.getBuffer();
if(nextRedrawBound.equals(this.getBounds()))
{
this.currentFlavour.drawDisplay(this, g2d, ticks, iconAnimationTicks);
}
this.currentFlavour.drawBoundLimitedDisplay(this, g2d, nextRedrawBound, ticks, iconAnimationTicks);
g2d.dispose();
repaint(nextRedrawBound);
}
} }
private void addRedrawBound(int x, int y, int w, int h, boolean isExclusive) { private void addRedrawBound(int x, int y, int w, int h, boolean isExclusive) {
@@ -225,9 +264,8 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
this.forecastProvider = forecastProvider; this.forecastProvider = forecastProvider;
this.currentFlavour.notifyForecastProviderUpdate(this, forecastProvider); this.currentFlavour.notifyForecastProviderUpdate(this, forecastProvider);
} }
public void notifyForecastProviderUpdate() public void notifyForecastProviderUpdate() {
{
this.currentFlavour.notifyForecastProviderUpdate(this, forecastProvider); this.currentFlavour.notifyForecastProviderUpdate(this, forecastProvider);
} }
@@ -238,6 +276,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
public void nextDisplay() { public void nextDisplay() {
this.currentFlavour = new DayForecastDisplay(); this.currentFlavour = new DayForecastDisplay();
this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks); this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks);
initBuffer();
this.loseRedrawRegion(); this.loseRedrawRegion();
this.requestFullRepaint(); this.requestFullRepaint();
} }
@@ -251,17 +290,51 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
} }
public void requestFullRepaint() { public void requestFullRepaint() {
repaint(); this.nextRedrawBound = this.getBounds();
} }
public void requestBoundedRepaint() { public void requestBoundedRepaint() {
repaint(redrawBound); if(nextRedrawBound == null)
nextRedrawBound = redrawBound;
else
nextRedrawBound.add(redrawBound);
} }
public void requestExclusiveBoundedRepaint() { public void requestExclusiveBoundedRepaint() {
repaint(exclusiveRedrawBound); if(nextRedrawBound == null)
nextRedrawBound = exclusiveRedrawBound;
else
nextRedrawBound.add(exclusiveRedrawBound);
//repaint(exclusiveRedrawBound);
} }
/*private void loadCrawlStrings() {
File crawl = new File("./crawl.txt");
ArrayList<String> strings = new ArrayList<String>();
if (crawl != null)
{
BufferedReader br = null;
try
{
br = new BufferedReader(new FileReader(crawl));
String line;
while ((line = br.readLine()) != null)
{
strings.add(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(br);
}
}
this.crawlStrings = strings.toArray(new String[strings.size()]);
}*/
/*@Override /*@Override
public void run() { public void run() {
while (true) while (true)

View File

@@ -0,0 +1,57 @@
package com.flaremicro.visualforecast;
/**
* TImer class, deals with ticks, game speedup, and slowdown
* @author Vulpovile
*
*/
public class Timer {
private final int ticksPerSecond;
private long lastTickTime = 0;
private long currentTime = 0;
private long ticksPassed = 0;
/**
* Creates a timer with a set amount ticks per second
* @param ticksPerSecond
*/
public Timer(int ticksPerSecond)
{
this.ticksPerSecond = 1000/ticksPerSecond;
currentTime = System.currentTimeMillis();
lastTickTime = currentTime;
}
/**
* Resets the timer, prevents the superspeed bug when loading or generating levels
*/
public void reset()
{
currentTime = System.currentTimeMillis();
lastTickTime = currentTime;
}
/**
* Ticks the timer and returns how many ticks were missed by the game (to catch up with bad framerates)
* @return ticks passed
*/
public long tick()
{
if(ticksPassed > 0) ticksPassed--;
currentTime = System.currentTimeMillis();
if(lastTickTime < currentTime-ticksPerSecond)
{
ticksPassed = (currentTime-lastTickTime)/ticksPerSecond;
lastTickTime = currentTime - (currentTime-lastTickTime)%ticksPerSecond;
}
if(ticksPassed > 200L)
{
System.out.println("Time moving too fast! Did the system time change or is the game overloaded?");
System.out.println("Moving time forward " + ticksPassed + " ticks");
ticksPassed = 0;
}
else if(ticksPassed < 0L)
{
System.out.println("Time moved backwards! Did the system time change?");
System.out.println("Moving time backwards " + -ticksPassed + " ticks");
ticksPassed = 0;
}
return ticksPassed;
}
}

View File

@@ -6,14 +6,12 @@ import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Logger;
import com.flaremicro.util.Util; import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
public class ForecastProviderManager { public class ForecastProviderManager {
public static final float API_VERSION = 0.0F; public static final float API_VERSION = 0.0F;
private Logger log = Util.getDefaultLogger();
private ForecastProvider loadedProvider; private ForecastProvider loadedProvider;
private String loadedProviderName; private String loadedProviderName;
private RenderPanel mainPanel; private RenderPanel mainPanel;
@@ -29,7 +27,7 @@ public class ForecastProviderManager {
} }
public ForecastProvider loadProvider(File file) { public ForecastProvider loadProvider(File file) {
Util.getDefaultLogger().info("Loading provider " + file.getName()); //Util.getDefaultLogger().info("Loading provider " + file.getName());
try try
{ {
URLClassLoader classLoader = new URLClassLoader(new URL[] { file.toURI().toURL() }); URLClassLoader classLoader = new URLClassLoader(new URL[] { file.toURI().toURL() });
@@ -49,53 +47,53 @@ public class ForecastProviderManager {
loadedProvider.forecastProviderManager = this; loadedProvider.forecastProviderManager = this;
loadedProviderName = file.getName().substring(0, file.getName().length() - 4); loadedProviderName = file.getName().substring(0, file.getName().length() - 4);
loadedProvider.init(); loadedProvider.init();
log.info("Provider " + file.getName() + " loaded! (Name set to " + loadedProviderName +")"); //log.info("Provider " + file.getName() + " loaded! (Name set to " + loadedProviderName +")");
return loadedProvider; return loadedProvider;
} }
else else
{ {
log.info("Provider " + file.getName() + " main class is wrong object type"); //log.info("Provider " + file.getName() + " main class is wrong object type");
log.info("(Does main class not extend ForecastProvider?)"); //log.info("(Does main class not extend ForecastProvider?)");
} }
} }
else else
{ {
log.info("Provider " + file.getName() + " properties file was not found"); //log.info("Provider " + file.getName() + " properties file was not found");
log.info("(Is the jar path correct?)"); //log.info("(Is the jar path correct?)");
} }
} }
catch (ClassNotFoundException e) catch (ClassNotFoundException e)
{ {
log.info("Provider " + file.getName() + " main class not found:"); //log.info("Provider " + file.getName() + " main class not found:");
e.printStackTrace(); e.printStackTrace();
log.info("(Is the information file invalid?)"); //log.info("(Is the information file invalid?)");
} }
catch (IOException e) catch (IOException e)
{ {
log.info("Provider " + file.getName() + " failed to read information file:"); //log.info("Provider " + file.getName() + " failed to read information file:");
e.printStackTrace(); e.printStackTrace();
log.info("(Is the information file defined?)"); //log.info("(Is the information file defined?)");
} }
catch (InstantiationException e) catch (InstantiationException e)
{ {
log.info("Provider " + file.getName() + " failed to instantiate main class:"); //log.info("Provider " + file.getName() + " failed to instantiate main class:");
e.printStackTrace(); e.printStackTrace();
log.info("(Does main class not implement empty constructor?)"); //log.info("(Does main class not implement empty constructor?)");
} }
catch (IllegalAccessException e) catch (IllegalAccessException e)
{ {
log.info("Provider " + file.getName() + " failed to instantiate main class:"); //log.info("Provider " + file.getName() + " failed to instantiate main class:");
e.printStackTrace(); e.printStackTrace();
log.info("(Does the program have reflection permission?)"); //log.info("(Does the program have reflection permission?)");
} }
catch (Exception e) catch (Exception e)
{ {
log.info("Provider " + file.getName() + " failed while loading:"); //log.info("Provider " + file.getName() + " failed while loading:");
e.printStackTrace(); e.printStackTrace();
} }
catch (Throwable e) catch (Throwable e)
{ {
log.info("Provider " + file.getName() + " failed catastrophically while loading:"); //log.info("Provider " + file.getName() + " failed catastrophically while loading:");
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;

View File

@@ -133,6 +133,7 @@ public class DayForecastDisplay implements Display {
@Override @Override
public void drawDisplay(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) { public void drawDisplay(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
g2d.setStroke(new BasicStroke(2));
if (details == null || currentTown == null || currentTown.getDayForecast() == null || currentTown.getDayForecast().length <= 0) 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)); 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));
@@ -175,11 +176,6 @@ public class DayForecastDisplay implements Display {
} }
} }
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) { private void drawTownForecast(Graphics2D g2d, TownForecast townForecast, int dayOffset) {
@@ -217,13 +213,21 @@ public class DayForecastDisplay implements Display {
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(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) + (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)) if (!ValueCheck.valueNoData(forecast.hiTemp))
{ {
g2d.setFont(font.deriveFont(26F));
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) + 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)); 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) + 20, RenderConstants.TOPBAR_HEIGHT + 270, "Hi", Color.RED, Color.BLACK, 2);
}
if (!ValueCheck.valueNoData(forecast.loTemp))
{
g2d.setFont(font.deriveFont(26F));
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) + 82, RenderConstants.TOPBAR_HEIGHT + 270, "Lo", Color.CYAN, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET + (131 * i) + 82, RenderConstants.TOPBAR_HEIGHT + 270, "Lo", Color.CYAN, Color.BLACK, 2);
} }
@@ -238,15 +242,17 @@ public class DayForecastDisplay implements Display {
@Override @Override
public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) { public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
g2d.setStroke(new BasicStroke(2));
if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0) if (details != null && currentTown != null && currentTown.getDayForecast() != null && currentTown.getDayForecast().length > 0)
{ {
if (animationTicks < 0) if (animationTicks < 0)
{ {
g2d.drawImage(mainBound, RenderConstants.SIDE_OFFSET - 1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
drawIcons(g2d, currentTown, dayOffset, iconTicks); drawIcons(g2d, currentTown, dayOffset, iconTicks);
} }
else else
{ {
g2d.setClip(animationTicks, RenderConstants.TOPBAR_HEIGHT + 14, RenderConstants.SIDE_OFFSET, MAINBAR_HEIGHT - 28);
renderer.drawMainGradient(g2d);
g2d.setClip(animationTicks + RenderConstants.SIDE_OFFSET - 1, RenderConstants.TOPBAR_HEIGHT + 14, 526, MAINBAR_HEIGHT - 28); 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); g2d.drawImage(prevBound, RenderConstants.SIDE_OFFSET - 1, RenderConstants.TOPBAR_HEIGHT + 14, renderer);
if (dayOffset == 0) if (dayOffset == 0)

View File

@@ -1,266 +0,0 @@
package com.flaremicro.visualforecast.displays;
import static com.flaremicro.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.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.forecast.ValueCheck;
import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager;
import com.flaremicro.visualforecast.graphics.RenderConstants;
import com.flaremicro.visualforecast.icons.IconProvider;
public class DayForecastDisplayOldAnimation implements Display {
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 DayForecastDisplayOldAnimation() {
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.nextDisplay();
}
else
{
previousTown = currentTown;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
}
renderer.loseRedrawRegion();
renderer.requestFullRepaint();
}
}
}
@Override
public void initDisplay(RenderPanel renderer, ForecastProvider forecastProvider, long ticks, int iconTicks) {
this.details = forecastProvider != null ? forecastProvider.getForecast() : null;
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 drawDisplay(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 drawBoundLimitedDisplay(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);
}
@Override
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
}
}

View File

@@ -1,3 +1,3 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Thu Mar 07 14:12:28 PST 2024 #Thu Mar 07 19:30:06 PST 2024
forecast-provider-jar=EnvironmentCanadaProvider.jar forecast-provider-jar=CanadaDatamartProvider.jar