Merge pull request 'feature/current_conditions' (#5) from feature/current_conditions into master

Reviewed-on: #5
This commit is contained in:
2025-04-27 04:31:00 +00:00
34 changed files with 938 additions and 212 deletions

View File

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

3
.gitignore vendored
View File

@@ -24,3 +24,6 @@ bin/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
*.dat *.dat
#Can contain copyrighted music!
Music/

View File

@@ -1,5 +1,6 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.compliance=1.6
@@ -7,5 +8,8 @@ org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.compiler.source=1.6

BIN
Announcements/7-day-dis.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +1,13 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Fri Mar 15 19:46:22 PDT 2024 #Sat Nov 23 19:50:15 PST 2024
towns-by-code= displays-enabled.town.prince_rupert.bc=7-day,hourly
displays-enabled.town.victora.bc=36-hour,7-day,hourly
displays-enabled.town.nanaimo.bc=7-day,hourly
displays-enabled.town.prince\ rupert.bc=
displays-enabled.town.kelowna.bc=7-day,hourly
displays-enabled.town.prince_george.bc=36-hour,7-day,hourly
displays-enabled.town.prince\ george.bc=
towns-by-name-and-province=Vancouver,BC;Victora,BC;Kelowna,BC;Nanaimo,BC;Squamish,BC;Prince George,BC;Prince Rupert,BC towns-by-name-and-province=Vancouver,BC;Victora,BC;Kelowna,BC;Nanaimo,BC;Squamish,BC;Prince George,BC;Prince Rupert,BC
displays-enabled.town.squamish.bc=7-day,hourly
towns-by-code=
displays-enabled.town.vancouver.bc=

BIN
jlayer-1.0.4.jar Normal file

Binary file not shown.

View File

@@ -0,0 +1,286 @@
package com.flaremicro.audio;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Random;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import com.flaremicro.util.Util;
public class AgnosticAudioSystem implements GameAudioSystem {
private Collection<AudioFinishedListener> listeners = new ArrayList<AudioFinishedListener>();
private HashMap<String, AudioSystemThread> threads = new HashMap<String, AudioSystemThread>();
private Random random = new Random();
public void init() {
}
public void destroy() {
}
public void addAudioFinishedListener(AudioFinishedListener listener) {
this.listeners.add(listener);
}
public void removeAudioFinishedListener(AudioFinishedListener listener) {
this.listeners.remove(listener);
}
public void removeAudioFinishedListeners() {
this.listeners.clear();
}
public String play(URL res) {
if (res.getPath().contains("."))
{
String key = String.valueOf(random.nextLong());
String ext = res.getPath().substring(res.getPath().lastIndexOf(".") + 1).toLowerCase();
AudioSystemThread audioSystemThread = null;
if (ext.equalsIgnoreCase("mp3"))
audioSystemThread = new AgnosticMp3AudioSystemThread(res, key, this, false);
if (ext.equalsIgnoreCase("wav"))
audioSystemThread = new AgnosticWavAudioSystemThread(res, key, this, false);
if (audioSystemThread != null)
{
synchronized (threads)
{
threads.put(key, audioSystemThread);
}
new Thread(audioSystemThread).start();
return key;
}
}
return null;
}
public void playbg(URL res) {
stopbg();
if (res.getPath().contains("."))
{
String ext = res.getPath().substring(res.getPath().lastIndexOf(".") + 1).toLowerCase();
AudioSystemThread audioSystemThread = null;
if (ext.equalsIgnoreCase("mp3"))
audioSystemThread = new AgnosticMp3AudioSystemThread(res, "bg", this, true);
if (ext.equalsIgnoreCase("wav"))
audioSystemThread = new AgnosticWavAudioSystemThread(res, "bg", this, true);
if (audioSystemThread != null)
{
synchronized (threads)
{
threads.put("bg", audioSystemThread);
}
new Thread(audioSystemThread).start();
}
}
}
public void stopbg() {
if (threads.containsKey("bg"))
threads.get("bg").stopMusic();
stopped("bg", threads.get("bg"));
}
public void stopped(String threadName, AudioSystemThread audioSystemThread) {
synchronized (threads)
{
if (audioSystemThread != null && audioSystemThread == threads.get(threadName))
{
threads.remove(threadName);
}
}
for (AudioFinishedListener listener : listeners)
{
listener.audioFinished(threadName, audioSystemThread.resource);
}
}
public void setVolume(float percent, String key) {
AudioSystemThread ast = threads.get(key);
if (ast != null)
{
ast.setVolume(percent);
}
}
public void stop(String currentKey) {
AudioSystemThread ast = threads.get(currentKey);
if (ast != null)
{
ast.stopMusic();
}
}
}
abstract class AudioSystemThread implements Runnable {
protected final boolean looping;
protected final AgnosticAudioSystem system;
protected final URL resource;
protected final String threadName;
public AudioSystemThread(URL resource, String threadName, AgnosticAudioSystem system, boolean looping) {
this.resource = resource;
this.looping = looping;
this.threadName = threadName;
this.system = system;
}
public abstract void setVolume(float percent);
public abstract void stopMusic();
public final void onStop() {
this.system.stopped(threadName, this);
}
}
class AgnosticMp3AudioSystemThread extends AudioSystemThread {
private boolean running = true;
private Player player = null;
private static final int FRAME_BUFFER = 2;
private float volume = 1F;
public AgnosticMp3AudioSystemThread(URL resource, String threadName, AgnosticAudioSystem system, boolean looping) {
super(resource, threadName, system, looping);
}
public void run() {
do
{
try
{
player = new Player(new BufferedInputStream(resource.openStream()));
player.setVolume(volume);
while (running && player.play(FRAME_BUFFER));
}
catch (JavaLayerException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
while (running && looping);
super.onStop();
}
public void stopMusic() {
this.running = false;
if (player != null)
player.close();
}
@Override
public void setVolume(float percent) {
volume = percent;
if (player != null)
{
player.setVolume(volume);
}
}
}
class AgnosticWavAudioSystemThread extends AudioSystemThread {
private boolean running = true;
private SourceDataLine sourceLine = null;
private float volume = 1.0F;
public AgnosticWavAudioSystemThread(URL resource, String threadName, AgnosticAudioSystem system, boolean looping) {
super(resource, threadName, system, looping);
}
public void run() {
AudioInputStream audioStream = null;
do
{
try
{
audioStream = AudioSystem.getAudioInputStream(resource);
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open();
sourceLine.start();
FloatControl volume = (FloatControl) sourceLine.getControl(FloatControl.Type.MASTER_GAIN);
volume.setValue(this.volume);
int nBytesRead = 0;
byte[] abData = new byte[4096];
while (nBytesRead != -1 && running)
{
try
{
nBytesRead = audioStream.read(abData, 0, abData.length);
}
catch (IOException e)
{
e.printStackTrace();
}
if (nBytesRead >= 0)
{
@SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(audioStream);
if (sourceLine != null)
{
sourceLine.drain();
sourceLine.close();
}
}
}
while (running && looping);
onStop();
}
public void stopMusic() {
this.running = false;
if (sourceLine != null)
{
sourceLine.drain();
sourceLine.close();
}
}
@Override
public void setVolume(float percent) {
if (sourceLine != null)
{
this.volume = percent;
FloatControl volume = (FloatControl) sourceLine.getControl(FloatControl.Type.MASTER_GAIN);
volume.setValue(percent);
}
}
}

View File

@@ -0,0 +1,7 @@
package com.flaremicro.audio;
import java.net.URL;
public interface AudioFinishedListener {
public void audioFinished(String key, URL resource);
}

View File

@@ -0,0 +1,83 @@
package com.flaremicro.audio;
import java.net.URL;
import java.util.Random;
public class AudioPlaylist implements AudioFinishedListener{
private final AgnosticAudioSystem aas;
public AudioPlaylist(AgnosticAudioSystem aas)
{
this.aas = aas;
}
String currentKey = null;
int currentPlaylistIndex = 0;
URL[] playlist = null;
float currVol = 1F;
private boolean stopped = true;
public void setPlaylist(URL[] url)
{
this.playlist = url;
this.currentPlaylistIndex = 0;
}
public void shuffle(){
Random rand = new Random();
for (int i = 0; i < playlist.length; i++) {
int randomIndexToSwap = rand.nextInt(playlist.length);
URL temp = playlist[randomIndexToSwap];
playlist[randomIndexToSwap] = playlist[i];
playlist[i] = temp;
}
}
public void start()
{
stopped = false;
currentPlaylistIndex = 0;
aas.addAudioFinishedListener(this);
if(currentKey == null && playlist != null && playlist.length > 0)
{
currentKey = aas.play(playlist[0]);
aas.setVolume(currVol, currentKey);
}
}
public void next()
{
if(playlist != null && playlist.length > 0)
{
currentPlaylistIndex = (currentPlaylistIndex + 1 ) % playlist.length;
currentKey = aas.play(playlist[currentPlaylistIndex]);
aas.setVolume(currVol, currentKey);
}
}
public void audioFinished(String key, URL resource) {
if(!stopped && key == currentKey)
{
next();
}
}
public void setVolume(float volume) {
currVol = volume;
aas.setVolume(currVol, currentKey);
}
public void stop() {
stopped = true;
aas.stop(currentKey);
}
public float getVolume() {
return currVol;
}
}

View File

@@ -0,0 +1,16 @@
package com.flaremicro.audio;
import java.net.URL;
public interface GameAudioSystem {
public void init();
public void destroy();
public void playbg(URL res);
public String play(URL res);
public void stopbg();
}

View File

@@ -0,0 +1,127 @@
package com.flaremicro.visualforecast;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import com.flaremicro.audio.AgnosticAudioSystem;
import com.flaremicro.audio.AudioFinishedListener;
import com.flaremicro.audio.AudioPlaylist;
public class AudioManager implements AudioFinishedListener {
private PropertyManager propertyManager;
private AgnosticAudioSystem aas;
private AudioPlaylist audioPlaylist;
private File playlistDirectory = new File("./Music");
HashSet<String> playingKeys = new HashSet<String>();
public AudioManager(PropertyManager propertyManager) {
this.propertyManager = propertyManager;
this.aas = new AgnosticAudioSystem();
this.aas.addAudioFinishedListener(this);
this.audioPlaylist = new AudioPlaylist(aas);
updatePlaylist();
}
private void updatePlaylist() {
playlistDirectory = propertyManager.getFile("music-dir", playlistDirectory);
if (playlistDirectory == null || !playlistDirectory.isDirectory())
return;
File[] files = playlistDirectory.listFiles();
URL[] urls = new URL[files.length];
for (int i = 0; i < files.length; i++)
{
try
{
urls[i] = files[i].toURI().toURL();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
}
audioPlaylist.setPlaylist(urls);
audioPlaylist.shuffle();
}
public void audioFinished(String key, URL resource) {
playingKeys.remove(key);
if (playingKeys.size() == 0)
rampVolume(1F);
}
public void startPlaylist() {
if (playlistDirectory == null || !playlistDirectory.isDirectory())
return;
audioPlaylist.start();
}
public void stopPlaylist() {
audioPlaylist.stop();
}
public void end() {
audioPlaylist.stop();
aas.destroy();
}
public void playAnnouncement(File file) {
try
{
URL url = file.toURI().toURL();
rampVolume(-10F);
playingKeys.add(aas.play(url));
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Thread currThread = null;
private float volume = 1F;
//***horrible***
private void rampVolume(float newVolume) {
this.volume = newVolume;
if (currThread != null)
return;
currThread = new Thread(new Runnable() {
public void run() {
try
{
if (volume < audioPlaylist.getVolume())
{
while (audioPlaylist.getVolume() > volume)
{
audioPlaylist.setVolume(audioPlaylist.getVolume() - 0.1F);
Thread.sleep(10L);
}
}
else if (volume > audioPlaylist.getVolume())
{
while (audioPlaylist.getVolume() < volume)
{
audioPlaylist.setVolume(audioPlaylist.getVolume() + 0.1F);
Thread.sleep(10L);
}
}
}
catch (InterruptedException ex)
{
}
audioPlaylist.setVolume(volume);
currThread = null;
}
});
currThread.start();
}
}

View File

@@ -1,11 +1,11 @@
package com.flaremicro.visualforecast; package com.flaremicro.visualforecast;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileInputStream;
import java.io.FileWriter; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.InputStream;
import java.io.Writer; import java.io.OutputStream;
import java.util.Properties; import java.util.Properties;
import com.flaremicro.util.Util; import com.flaremicro.util.Util;
@@ -22,12 +22,13 @@ public class PropertyManager {
} }
public boolean load() { public boolean load() {
Reader reader = null; synchronized(prop){
InputStream reader = null;
try try
{ {
if (propFile.exists()) if (propFile.exists())
{ {
reader = new FileReader(propFile); reader = new FileInputStream(propFile);
prop.load(reader); prop.load(reader);
return true; return true;
} }
@@ -43,12 +44,14 @@ public class PropertyManager {
} }
return false; return false;
} }
}
public boolean store() { public boolean store() {
Writer writer = null; synchronized(prop){
OutputStream writer = null;
try try
{ {
writer = new FileWriter(propFile); writer = new FileOutputStream(propFile);
prop.store(writer, "VisualForecast 1000 Properties file. Functional provider must be set for successful boot!"); prop.store(writer, "VisualForecast 1000 Properties file. Functional provider must be set for successful boot!");
return true; return true;
} }
@@ -62,11 +65,47 @@ public class PropertyManager {
} }
return false; return false;
} }
}
public String getString(String key, String fallback) { public String getString(String key, String fallback) {
String result = prop.getProperty(key, fallback); String result = prop.getProperty(key, fallback);
System.out.println(result);
prop.setProperty(key, result); prop.setProperty(key, result);
return result; return result;
} }
public String getStringNoSet(String key, String fallback) {
String result = prop.getProperty(key, fallback);
return result;
}
public int getInteger(String key, int fallback) {
String resultString = getString(key, String.valueOf(fallback));
int resultInt = fallback;
try
{
resultInt = Integer.parseInt(resultString);
}
catch (NumberFormatException ex)
{
}
prop.setProperty(key, String.valueOf(resultInt));
return resultInt;
}
public void setString(String key, String value) {
if (value == null)
prop.remove(key);
else prop.setProperty(key, value);
}
public void setInteger(String key, int value) {
prop.setProperty(key, String.valueOf(value));
}
public File getFile(String key, File fallback) {
String resultString = getString(key, fallback.toString());
if (resultString == null)
return fallback;
else return new File(resultString);
}
} }

View File

@@ -25,12 +25,9 @@ import static com.flaremicro.visualforecast.graphics.RenderConstants.*;
import com.flaremicro.util.Util; 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.DayForecastDisplay;
import com.flaremicro.visualforecast.displays.Display; import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.displays.DisplayFactory; import com.flaremicro.visualforecast.displays.DisplayFactory;
import com.flaremicro.visualforecast.displays.HourlyForecastDisplay; import com.flaremicro.visualforecast.displays.impl.BootupDisplay;
import com.flaremicro.visualforecast.displays.ThirtySixHourDisplay;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
@@ -73,6 +70,8 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
DisplayFactory displayFactory; DisplayFactory displayFactory;
AudioManager audioManager;
public RenderPanel(PropertyManager propManager) { public RenderPanel(PropertyManager propManager) {
loadCrawlStrings(); loadCrawlStrings();
this.addComponentListener(this); this.addComponentListener(this);
@@ -81,6 +80,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
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);
displayFactory = new DisplayFactory(propManager); displayFactory = new DisplayFactory(propManager);
audioManager = new AudioManager(propManager);
//new Thread(new TickThread(this, 30)).start(); //new Thread(new TickThread(this, 30)).start();
} }
@@ -209,7 +209,6 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
currentBound = this.getBounds(); currentBound = this.getBounds();
} }
public void requestRepaint(Rectangle bound) { public void requestRepaint(Rectangle bound) {
if (currentBound.width == 0) if (currentBound.width == 0)
currentBound = new Rectangle(bound); currentBound = new Rectangle(bound);
@@ -257,7 +256,6 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
addRedrawBound(x, y, w, h, true); addRedrawBound(x, y, w, h, true);
} }
@Override
public void componentResized(ComponentEvent e) { public void componentResized(ComponentEvent e) {
loseRedrawRegion(); loseRedrawRegion();
} }
@@ -273,19 +271,16 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
this.currentFlavour.redrawRegionlost(this); this.currentFlavour.redrawRegionlost(this);
} }
@Override
public void componentMoved(ComponentEvent e) { public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void componentShown(ComponentEvent e) { public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void componentHidden(ComponentEvent e) { public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@@ -305,14 +300,25 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
} }
public void nextDisplay() { public void nextDisplay() {
/*if(this.currentFlavour instanceof DayForecastDisplay) if (this.currentFlavour instanceof BootupDisplay)
this.currentFlavour = new HourlyForecastDisplay(); {
else audioManager.startPlaylist();
this.currentFlavour = new DayForecastDisplay();*/ }
this.currentFlavour = displayFactory.nextDisplay(); this.currentFlavour = displayFactory.nextDisplay();
/*this.currentFlavour = new ThirtySixHourDisplay();
*/
this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks); this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks);
File announcementDirectory = this.propManager.getFile("announcement-dir", new File("Announcements"));
if (announcementDirectory != null && announcementDirectory.isDirectory())
{
File file = new File(announcementDirectory, currentFlavour.getDisplayName() + ".wav");
if(file.exists())
{
this.audioManager.playAnnouncement(file);
}
}
this.loseRedrawRegion(); this.loseRedrawRegion();
this.requestFullRepaint(); this.requestFullRepaint();
} }
@@ -352,6 +358,10 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
this.crawlStrings = strings.toArray(new String[strings.size()]); this.crawlStrings = strings.toArray(new String[strings.size()]);
} }
public void end() {
this.audioManager.end();
}
/*@Override /*@Override
public void run() { public void run() {
while (true) while (true)

View File

@@ -31,7 +31,7 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
private Executor executor; private Executor executor;
private PropertyManager propertyManager = new PropertyManager(); private PropertyManager propertyManager = new PropertyManager();
private Timer timer; private Timer timer;
private Timer timer2; //private Timer timer2;
private boolean isFullscreen = false; private boolean isFullscreen = false;
/** /**
@@ -87,6 +87,7 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
{ {
timer.stop(); timer.stop();
} }
renderPane.end();
if (forecastProviderManager != null) if (forecastProviderManager != null)
forecastProviderManager.end(); forecastProviderManager.end();
propertyManager.store(); propertyManager.store();
@@ -96,7 +97,6 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
executor = new Executor(this.renderPane, 30); executor = new Executor(this.renderPane, 30);
executor.begin(); executor.begin();
timer = new Timer(33, new ActionListener() { timer = new Timer(33, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
renderPane.performPaintIfNeeded(); renderPane.performPaintIfNeeded();
} }
@@ -106,7 +106,6 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
new Thread() { new Thread() {
public void run() { public void run() {
forecastProviderManager = new ForecastProviderManager(renderPane); forecastProviderManager = new ForecastProviderManager(renderPane);
propertyManager.load();
String forecastProvider = propertyManager.getString("forecast-provider-jar", ""); String forecastProvider = propertyManager.getString("forecast-provider-jar", "");
propertyManager.store(); propertyManager.store();
ForecastProvider provider = forecastProviderManager.loadProvider(new File(forecastProvider)); ForecastProvider provider = forecastProviderManager.loadProvider(new File(forecastProvider));
@@ -121,8 +120,9 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
* Create the frame. * Create the frame.
*/ */
public VisualForecastFrame() { public VisualForecastFrame() {
propertyManager.load();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(100, 100, 640 * 2, 480 * 2); setBounds(100, 100, 640, 480);
renderPane = new RenderPanel(propertyManager); renderPane = new RenderPanel(propertyManager);
//renderPane.setBorder(null); //renderPane.setBorder(null);
//renderPane.setLayout(new BorderLayout(0, 0)); //renderPane.setLayout(new BorderLayout(0, 0));
@@ -132,55 +132,46 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
addKeyListener(this); addKeyListener(this);
} }
@Override
public void windowOpened(WindowEvent e) { public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
end(); end();
} }
@Override
public void windowClosed(WindowEvent e) { public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void windowIconified(WindowEvent e) { public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void windowDeiconified(WindowEvent e) { public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void windowActivated(WindowEvent e) { public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void windowDeactivated(WindowEvent e) { public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void keyTyped(KeyEvent e) { public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F11) if (e.getKeyCode() == KeyEvent.VK_F11)
{ {
@@ -199,7 +190,6 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
} }
} }
@Override
public void keyReleased(KeyEvent e) { public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@@ -13,4 +13,6 @@ public interface Display {
public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g, Rectangle bounds, long ticks, int iconTicks); public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g, Rectangle bounds, long ticks, int iconTicks);
public void redrawRegionlost(RenderPanel renderer); public void redrawRegionlost(RenderPanel renderer);
public void notifyForecastProviderUpdate(RenderPanel renderPanel, ForecastProvider forecastProvider); public void notifyForecastProviderUpdate(RenderPanel renderPanel, ForecastProvider forecastProvider);
public String getDisplayName();
} }

View File

@@ -1,27 +1,67 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.flaremicro.visualforecast.PropertyManager; import com.flaremicro.visualforecast.PropertyManager;
import com.flaremicro.visualforecast.displays.impl.SevenDayForecastDisplay;
import com.flaremicro.visualforecast.displays.impl.HourlyForecastDisplay;
import com.flaremicro.visualforecast.displays.impl.MessageForecastDisplay;
import com.flaremicro.visualforecast.displays.impl.ThirtySixHourForecastDisplay;
public class DisplayFactory { public class DisplayFactory {
private static final int CURRENT_SELECTION = 1;
int currentIndex = -1; int currentIndex = -1;
String indexValue = ""; String indexValue = "";
PropertyManager propertyManager;
private List<String> nameOrder = new ArrayList<String>(); private List<String> nameOrder = new ArrayList<String>();
private Map<String, Display> displays = new HashMap<String, Display>(); private Map<String, Display> displays = new HashMap<String, Display>();
public DisplayFactory(PropertyManager propertyManager) public DisplayFactory(PropertyManager propertyManager) {
this.propertyManager = propertyManager;
nameOrder.add(register(new MessageForecastDisplay()));
//nameOrder.add(register(new CurrentForecastDisplay()));
nameOrder.add(register(new ThirtySixHourForecastDisplay()));
nameOrder.add(register(new SevenDayForecastDisplay()));
nameOrder.add(register(new HourlyForecastDisplay()));
int selection = propertyManager.getInteger("current-display-version", -1);
String nameOrderString = getCurrentNameOrder();
if ((selection >= 0 && selection != CURRENT_SELECTION))
{ {
displays.put("message", new MessageForecastDisplay()); propertyManager.setInteger("current-display-version", CURRENT_SELECTION);
displays.put("day", new DayForecastDisplay()); propertyManager.setString("display-selection", nameOrderString);
displays.put("hourly", new HourlyForecastDisplay()); propertyManager.store();
nameOrder.add("message"); }
nameOrder.add("day"); else
nameOrder.add("hourly"); {
System.out.println("got good order: " + propertyManager.getString("display-selection", "oh no"));
nameOrder.clear();
String[] s = propertyManager.getString("display-selection", nameOrderString).split(",");
nameOrder.addAll(Arrays.asList(s));
}
}
private String getCurrentNameOrder() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < nameOrder.size(); i++)
{
if (i != 0)
{
sb.append(",");
}
sb.append(nameOrder.get(i));
}
return sb.toString();
}
private String register(Display display) {
displays.put(display.getDisplayName(), display);
return display.getDisplayName();
} }
public Display nextDisplay() { public Display nextDisplay() {

View File

@@ -1,55 +0,0 @@
package com.flaremicro.visualforecast.displays;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.graphics.DrawingUtil;
import static com.flaremicro.visualforecast.graphics.RenderConstants.*;
public class TextDisplay implements Display {
public TextDisplay(String title, String scrollText) {
/*
int w2 = g2d.getFontMetrics().stringWidth("EXTREME WEATHER ADVISORY");
drawOutlinedString(g2d, (W >> 1) - (w2 >> 1), TOPBAR_HEIGHT + 48, "EXTREME WEATHER ADVISORY", Color.RED, Color.BLACK, 2);
g2d.setFont(font.deriveFont(30F));
for (int i = 0; i < testString.length; i++)
{
drawOutlinedString(g2d, 90, TOPBAR_HEIGHT + 78 + 25 * i, testString[i], Color.WHITE, Color.BLACK, 1);
}
*/
}
@Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) {
}
@Override
public void initDisplay(RenderPanel renderer, ForecastProvider forecastProvider, long ticks, int iconTicks) {
}
@Override
public void drawDisplay(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
DrawingUtil.drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, BG_BLUE.brighter(), BG_BLUE.darker());
g2d.setColor(BG_BLUE.brighter());
g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH);
}
@Override
public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
}
@Override
public void redrawRegionlost(RenderPanel renderer) {
}
@Override
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
}
}

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
@@ -7,6 +7,7 @@ import java.awt.Rectangle;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
import com.flaremicro.visualforecast.graphics.RenderConstants; import com.flaremicro.visualforecast.graphics.RenderConstants;
@@ -64,7 +65,7 @@ public class BootupDisplay implements Display {
IconProvider.drawIcon(g2d, IconProvider.INDEXED_ICONS[i], x, y, 80, iconTicks); IconProvider.drawIcon(g2d, IconProvider.INDEXED_ICONS[i], x, y, 80, iconTicks);
} }
g2d.setFont(font.deriveFont(40F)); g2d.setFont(font.deriveFont(40F));
DrawingUtil.drawOutlinedString(g2d, RenderConstants.W / 2 - g2d.getFontMetrics().stringWidth("VisualForecast 1000") / 2, RenderConstants.H / 2, "VisualForecast 1000", Color.WHITE, Color.BLACK, 2); //DrawingUtil.drawOutlinedString(g2d, RenderConstants.W / 2 - g2d.getFontMetrics().stringWidth("VisualForecast 1000") / 2, RenderConstants.H / 2, "VisualForecast 1000", Color.WHITE, Color.BLACK, 2);
} }
else if (this.ticks > 90) else if (this.ticks > 90)
{ {
@@ -102,4 +103,9 @@ public class BootupDisplay implements Display {
this.forecastReady = provider.isForecastReady(); this.forecastReady = provider.isForecastReady();
} }
} }
@Override
public String getDisplayName() {
return "bootup";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
@@ -63,8 +64,8 @@ public class CurrentForecastDisplay implements Display {
String test = "*IMPORTANT NOTICE*\n*THIS BETA IS UNFINISHED*\n\nThis is a Beta version of the VisualForeast 1000! Many things are not finished, and only the hourly and 7 day forecasts are ready. There will be a lot more to come!\nPlease note that there are some issues with data collection from Environment Canada resulting in missing or potentially incorrect information around midnight hours. This will be fixed as the project continues and the disclaimer will be removed."; String test = "*IMPORTANT NOTICE*\n*THIS BETA IS UNFINISHED*\n\nThis is a Beta version of the VisualForeast 1000! Many things are not finished, and only the hourly and 7 day forecasts are ready. There will be a lot more to come!\nPlease note that there are some issues with data collection from Environment Canada resulting in missing or potentially incorrect information around midnight hours. This will be fixed as the project continues and the disclaimer will be removed.";
ArrayList<String> linesList = new ArrayList<String>(); ArrayList<String> linesList = new ArrayList<String>();
renderer.setCurrentForecast("Welcome to the"); renderer.setCurrentForecast("Current Conditions");
renderer.setCurrentTown("VisualForecast 1000"); renderer.setCurrentTown("TOWN NAME HERE");
BufferedImage disposableImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY); BufferedImage disposableImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = disposableImage.createGraphics(); Graphics2D g = disposableImage.createGraphics();
@@ -172,4 +173,8 @@ public class CurrentForecastDisplay implements Display {
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "current";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import static com.flaremicro.visualforecast.graphics.RenderConstants.BG_BLUE; import static com.flaremicro.visualforecast.graphics.RenderConstants.BG_BLUE;
import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT; import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
@@ -9,18 +9,13 @@ import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.GradientPaint; import java.awt.GradientPaint;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.forecast.DayForecast; import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.HourlyForecast; import com.flaremicro.visualforecast.forecast.HourlyForecast;
import com.flaremicro.visualforecast.forecast.TownForecast; import com.flaremicro.visualforecast.forecast.TownForecast;
@@ -38,7 +33,7 @@ public class HourlyForecastDisplay implements Display {
private int townIndex; private int townIndex;
private int ticksBeforeChange = 200; private int ticksBeforeChange = 200;
private int animationTicks = -1; // private int animationTicks = -1;
private byte[] windchill = null; private byte[] windchill = null;
private byte[] tempval = null; private byte[] tempval = null;
@@ -70,7 +65,7 @@ public class HourlyForecastDisplay implements Display {
} }
this.currentTown = details.getTownForecast()[townIndex]; this.currentTown = details.getTownForecast()[townIndex];
} }
while (this.currentTown == null || currentTown.getHourlyForecast() == null || currentTown.getHourlyForecast().length == 0); while (this.currentTown == null || !currentTown.isDisplaySupported(this.getDisplayName()) || currentTown.getHourlyForecast() == null || currentTown.getHourlyForecast().length == 0);
renderer.setCurrentTown(currentTown.getTownName()); renderer.setCurrentTown(currentTown.getTownName());
setGraphValues(currentTown); setGraphValues(currentTown);
renderer.requestFullRepaint(); renderer.requestFullRepaint();
@@ -346,4 +341,9 @@ public class HourlyForecastDisplay implements Display {
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "hourly";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
@@ -172,4 +173,8 @@ public class MessageForecastDisplay implements Display {
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "message";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT; import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
@@ -16,6 +16,7 @@ import java.util.Locale;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.forecast.DayForecast; import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.TownForecast; import com.flaremicro.visualforecast.forecast.TownForecast;
@@ -25,7 +26,7 @@ import com.flaremicro.visualforecast.graphics.FontManager;
import com.flaremicro.visualforecast.graphics.RenderConstants; import com.flaremicro.visualforecast.graphics.RenderConstants;
import com.flaremicro.visualforecast.icons.IconProvider; import com.flaremicro.visualforecast.icons.IconProvider;
public class DayForecastDisplay implements Display { public class SevenDayForecastDisplay implements Display {
private int dayOffset = 0; private int dayOffset = 0;
private Font font; private Font font;
private Font smallFont; private Font smallFont;
@@ -40,14 +41,19 @@ public class DayForecastDisplay implements Display {
private int ticksBeforeChange = 200; private int ticksBeforeChange = 200;
private int animationTicks = -1; private int animationTicks = -1;
public DayForecastDisplay() { public SevenDayForecastDisplay() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")); 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")); smallFont = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000 Small.ttf"));
} }
//TODO improve
@Override @Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) { public void tick(RenderPanel renderer, long ticks, int iconTicks) {
if (animationTicks >= 0) if(details == null || details.getTownForecast() == null){
renderer.nextDisplay();
return;
}
else if (animationTicks >= 0)
{ {
animationTicks += 8; animationTicks += 8;
if (animationTicks > RenderConstants.W - 60) if (animationTicks > RenderConstants.W - 60)
@@ -69,6 +75,8 @@ public class DayForecastDisplay implements Display {
ticksBeforeChange = 200; ticksBeforeChange = 200;
dayOffset = dayOffset + 4; dayOffset = dayOffset + 4;
if (dayOffset >= 8) if (dayOffset >= 8)
{
do
{ {
dayOffset = 0; dayOffset = 0;
townIndex++; townIndex++;
@@ -84,6 +92,8 @@ public class DayForecastDisplay implements Display {
renderer.setCurrentTown(currentTown.getTownName()); renderer.setCurrentTown(currentTown.getTownName());
} }
} }
while (this.currentTown != null && !this.currentTown.isDisplaySupported(this.getDisplayName()));
}
animationTicks = 0; animationTicks = 0;
if (prevBound != null) if (prevBound != null)
@@ -296,4 +306,9 @@ public class DayForecastDisplay implements Display {
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "7-day";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT; import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
@@ -16,6 +16,7 @@ import java.util.Locale;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.forecast.DayForecast; import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.TownForecast; import com.flaremicro.visualforecast.forecast.TownForecast;
@@ -25,7 +26,7 @@ import com.flaremicro.visualforecast.graphics.FontManager;
import com.flaremicro.visualforecast.graphics.RenderConstants; import com.flaremicro.visualforecast.graphics.RenderConstants;
import com.flaremicro.visualforecast.icons.IconProvider; import com.flaremicro.visualforecast.icons.IconProvider;
public class DayForecastDisplayOldAnimation implements Display { public class SevenDayForecastDisplayOldAnimation implements Display {
private int dayOffset = 0; private int dayOffset = 0;
private Font font; private Font font;
private Font smallFont; private Font smallFont;
@@ -39,7 +40,7 @@ public class DayForecastDisplayOldAnimation implements Display {
private int ticksBeforeChange = 200; private int ticksBeforeChange = 200;
private int animationTicks = -1; private int animationTicks = -1;
public DayForecastDisplayOldAnimation() { public SevenDayForecastDisplayOldAnimation() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")); 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")); smallFont = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000 Small.ttf"));
} }
@@ -263,4 +264,9 @@ public class DayForecastDisplayOldAnimation implements Display {
@Override @Override
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "7-day-old";
}
} }

View File

@@ -1,4 +1,4 @@
package com.flaremicro.visualforecast.displays; package com.flaremicro.visualforecast.displays.impl;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
@@ -10,18 +10,25 @@ import java.util.ArrayList;
import com.flaremicro.visualforecast.RenderPanel; import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
import static com.flaremicro.visualforecast.graphics.RenderConstants.*; import static com.flaremicro.visualforecast.graphics.RenderConstants.*;
public class ThirtySixHourDisplay implements Display { public class ThirtySixHourForecastDisplay implements Display {
private int townIndex = 0;
private TownForecast[] townForecasts;
private String[] lines = new String[0]; private String[] lines = new String[0];
private Font font; private Font font;
private int stringOffset = 0;
private int ticksBeforeChange = 0;
public ThirtySixHourDisplay() { public ThirtySixHourForecastDisplay() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")).deriveFont(30F); font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf")).deriveFont(30F);
/* /*
@@ -38,18 +45,83 @@ public class ThirtySixHourDisplay implements Display {
@Override @Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) { public void tick(RenderPanel renderer, long ticks, int iconTicks) {
ticksBeforeChange--;
if (ticksBeforeChange <= 0)
{
stringOffset += 9;
if (stringOffset < lines.length)
{
ticksBeforeChange = 200;
renderer.requestExclusiveBoundedRepaint();
}
else
{
if(!setNextTown(renderer))
{
renderer.nextDisplay();
}
else
{
ticksBeforeChange = 200;
renderer.requestExclusiveBoundedRepaint();
}
}
}
} }
@Override @Override
public void initDisplay(RenderPanel renderer, ForecastProvider forecastProvider, long ticks, int iconTicks) { public void initDisplay(RenderPanel renderer, ForecastProvider forecastProvider, long ticks, int iconTicks) {
String test = "*IMPORTANT NOTICE*\n*POWER OUTAGE POSSIBLE*\n*DUE TO EXTREME WINDS*\n\nHurricane-force winds capable of reaching 127km/h will be hitting the east coast around noon tomorrow. Keep windows and doors barricaded to prevent"; ForecastDetails details = forecastProvider != null ? forecastProvider.getForecast() : null;
renderer.setCurrentForecast("36 Hour Detailed Forecast");
townIndex = -1;
if(details == null || details.getTownForecast() == null || details.getTownForecast().length <= 0)
{
renderer.nextDisplay();
return;
}
else
{
townForecasts = details.getTownForecast();
if(!setNextTown(renderer))
{
renderer.nextDisplay();
return;
}
}
}
public boolean setNextTown(RenderPanel renderer)
{
townIndex++;
if(townIndex >= townForecasts.length)
return false;
TownForecast town = townForecasts[townIndex];
if(!town.isDisplaySupported(getDisplayName()) || town.getDetailedForecast() == null || town.getDetailedForecast().length <= 0)
{
return setNextTown(renderer);
}
ticksBeforeChange = 200;
stringOffset = 0;
StringBuilder forecastBuilder = new StringBuilder();
for(int i = 0; i < town.getDetailedForecast().length; i++)
{
if(i > 0)
forecastBuilder.append("\n\n");
forecastBuilder.append(town.getDetailedForecast()[i].title + ":\n");
forecastBuilder.append(town.getDetailedForecast()[i].status);
}
ArrayList<String> linesList = new ArrayList<String>(); ArrayList<String> linesList = new ArrayList<String>();
renderer.setCurrentTown(town.getTownName());
BufferedImage disposableImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY); BufferedImage disposableImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = disposableImage.createGraphics(); Graphics2D g = disposableImage.createGraphics();
FontMetrics f = g.getFontMetrics(font); FontMetrics f = g.getFontMetrics(font);
System.out.println("yas2"); String[] lines = forecastBuilder.toString().split("\n");
String[] lines = test.split("\n");
for (int i = 0; i < lines.length; i++) for (int i = 0; i < lines.length; i++)
{ {
splitText(lines[i], W - 150 - STROKE_WIDTH, f, linesList); splitText(lines[i], W - 150 - STROKE_WIDTH, f, linesList);
@@ -59,9 +131,10 @@ public class ThirtySixHourDisplay implements Display {
g.dispose(); g.dispose();
disposableImage.flush(); disposableImage.flush();
System.out.println("yas"); redrawRegionlost(renderer);
this.lines = linesList.toArray(new String[0]); this.lines = linesList.toArray(new String[0]);
return true;
} }
private void splitText(String text, int maxWidth, FontMetrics fontMetrics, ArrayList<String> lineList) { private void splitText(String text, int maxWidth, FontMetrics fontMetrics, ArrayList<String> lineList) {
@@ -120,36 +193,40 @@ public class ThirtySixHourDisplay 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) {
DrawingUtil.drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, BG_BLUE.brighter(), BG_BLUE.darker()); DrawingUtil.drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, BG_BLUE.darker(), BG_BLUE.brighter());
g2d.setFont(font); g2d.setFont(font);
FontMetrics fontMetrics = g2d.getFontMetrics(); FontMetrics fontMetrics = g2d.getFontMetrics();
g2d.setColor(BG_BLUE.brighter()); g2d.setColor(BG_BLUE.darker());
g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH); g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH);
for(int i = 0; i < lines.length; i++) for (int i = 0; i < Math.min(9, lines.length - this.stringOffset); i++)
{ {
if(lines[i].startsWith("*") && lines[i].endsWith("*")) if (lines[i + stringOffset].startsWith("*") && lines[i].endsWith("*"))
{ {
String line = lines[i].substring(1, lines[i].length()-1); String line = lines[i + stringOffset].substring(1, lines[i + stringOffset].length() - 1);
DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, "*", Color.WHITE, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, "*", Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET + (W - 150 - STROKE_WIDTH) / 2 - fontMetrics.stringWidth(line) / 2, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, line, Color.WHITE, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET + (W - 150 - STROKE_WIDTH) / 2 - fontMetrics.stringWidth(line) / 2, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, line, Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, W - 95 - STROKE_WIDTH, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, "*", Color.WHITE, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, W - 95 - STROKE_WIDTH, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, "*", Color.WHITE, Color.BLACK, 2);
} }
else if(lines[i].startsWith("[") && lines[i].endsWith("]")) else if (lines[i + stringOffset].startsWith("[") && lines[i].endsWith("]"))
{ {
String line = lines[i].substring(1, lines[i].length()-1); String line = lines[i + stringOffset].substring(1, lines[i + stringOffset].length() - 1);
DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET + (W - 150 - STROKE_WIDTH) / 2 - fontMetrics.stringWidth(line) / 2, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, line, Color.WHITE, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET + (W - 150 - STROKE_WIDTH) / 2 - fontMetrics.stringWidth(line) / 2, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, line, Color.WHITE, Color.BLACK, 2);
} }
else else DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i * 30, lines[i + stringOffset], Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, 60 + 20 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET + 40 + i*30, lines[i], Color.WHITE, Color.BLACK, 2);
} }
} }
@Override @Override
public void redrawRegionlost(RenderPanel renderer) { public void redrawRegionlost(RenderPanel renderer) {
renderer.addRedrawBound(TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20);
} }
@Override @Override
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) { public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
} }
@Override
public String getDisplayName() {
return "36-hour";
}
} }

View File

@@ -0,0 +1,20 @@
package com.flaremicro.visualforecast.forecast;
import java.util.Date;
public class CurrentConditions {
String station;
String stationCode;
Date timeObserved;
String condition;
byte icon;
byte temperature;
byte dewPoint;
short pressure;
short visibility;
float relativeHumidity;
short windSpeed;
short windGust;
float windBearing;
String windDirection;
}

View File

@@ -0,0 +1,12 @@
package com.flaremicro.visualforecast.forecast;
public class DetailedForecast {
public final String title;
public final String status;
public DetailedForecast(String title, String status)
{
this.title = title;
this.status = status;
}
}

View File

@@ -6,17 +6,21 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class TownForecast { public class TownForecast {
private String townName;
private DayForecast[] dayForecast;
private Set<String> displays = new HashSet<String>();
private HourlyForecast[] hourlyForecast;
private DetailedForecast[] detailedForecast;
public TownForecast(String townName, DayForecast[] dayForecast) { public TownForecast(String townName, DayForecast[] dayForecast) {
this.townName = townName; this.townName = townName;
this.dayForecast = dayForecast; this.dayForecast = dayForecast;
} }
private final String townName; public void setDayForecast(DayForecast[] dayForecast){
private final DayForecast[] dayForecast; this.dayForecast = dayForecast;
private Set<String> displays = new HashSet<String>(); }
private HourlyForecast[] hourlyForecast;
public boolean isDisplaySupported(String displayName) public boolean isDisplaySupported(String displayName)
{ {
@@ -47,4 +51,12 @@ public class TownForecast {
public String getTownName() { public String getTownName() {
return townName; return townName;
} }
public DetailedForecast[] getDetailedForecast() {
return detailedForecast;
}
public void setDetailedForecast(DetailedForecast[] detailedForecast) {
this.detailedForecast = detailedForecast;
}
} }

View File

@@ -53,7 +53,7 @@ public class IconProvider {
public static final Icon BUTTER_RAIN = registerIcon(new BlizzardIcon(26, CLOUD, BUTTER)); public static final Icon BUTTER_RAIN = registerIcon(new BlizzardIcon(26, CLOUD, BUTTER));
public static final Icon RAIN_STORM = registerIcon(new LightningOverlay(27, SMALL_CLOUD, LIGHTNING_BOLT, RAIN_HEAVY)); public static final Icon RAIN_STORM = registerIcon(new LightningOverlay(27, SMALL_CLOUD, LIGHTNING_BOLT, RAIN_HEAVY));
//public static final Icon INVALID_RAIN = registerIcon(new LightningOverlay(27, SUN, BUTTER, new BlizzardIcon(-1, LIGHTNING_BOLT, INVALID))); public static final Icon INVALID_RAIN = registerIcon(new LightningOverlay(28, SUN, BUTTER, new BlizzardIcon(-1, LIGHTNING_BOLT, INVALID)));
private static Icon registerIcon(Icon icon) private static Icon registerIcon(Icon icon)
{ {

View File

@@ -21,6 +21,7 @@ public class ButterIcon extends Icon {
}; };
Color[] iceShineAnimation = new Color[] { Color[] iceShineAnimation = new Color[] {
new Color(0xFFFFFF), new Color(0xFFFFFF),
new Color(0xFFFFFF),
}; };
public ButterIcon(int id) { public ButterIcon(int id) {

View File

@@ -19,6 +19,7 @@ public class InvalidIcon extends Icon {
@Override @Override
public void drawIcon(Graphics2D g2d, float scale, int animationStep) { public void drawIcon(Graphics2D g2d, float scale, int animationStep) {
g2d.getTransform();
g2d.setFont(fnt.deriveFont(0.8F)); g2d.setFont(fnt.deriveFont(0.8F));
g2d.translate(0.2F, 0.8F); g2d.translate(0.2F, 0.8F);
DrawingUtil.drawOutlinedString(g2d, 0, 0, "X", Color.YELLOW, Color.BLACK, 1, 2/scale); DrawingUtil.drawOutlinedString(g2d, 0, 0, "X", Color.YELLOW, Color.BLACK, 1, 2/scale);

View File

@@ -1,3 +1,7 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Fri Mar 15 19:46:22 PDT 2024 #Sat Nov 23 19:50:15 PST 2024
announcement-dir=Announcements
display-selection=36-hour,7-day,hourly
music-dir=./Music
current-display-version=1
forecast-provider-jar=CanadaDatamartProvider.jar forecast-provider-jar=CanadaDatamartProvider.jar