commit f7f24dfbe5123119f199f081e65a9ad3de1a51f6 Author: Flare Microsystems Date: Sun Mar 3 00:02:00 2024 -0800 Initial commit diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..5c59d7a --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2be9ec5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +#Compiled binary directory +bin/ + +# Package Files # +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +*.dat diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..fef13ef --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,13 @@ +# You can override the included template(s) by including variable overrides +# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings +# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings +# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings +# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings +# Note that environment variables can be set in several places +# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence +stages: +- test +sast: + stage: test +include: +- template: Security/SAST.gitlab-ci.yml diff --git a/.project b/.project new file mode 100644 index 0000000..91fb489 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + VisualForecast 1000 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/resources/Star 4 Radar.ttf b/resources/Star 4 Radar.ttf new file mode 100644 index 0000000..3b52590 Binary files /dev/null and b/resources/Star 4 Radar.ttf differ diff --git a/resources/Star4000 Extended.ttf b/resources/Star4000 Extended.ttf new file mode 100644 index 0000000..0f8c962 Binary files /dev/null and b/resources/Star4000 Extended.ttf differ diff --git a/resources/Star4000 Large Compressed Numbers.ttf b/resources/Star4000 Large Compressed Numbers.ttf new file mode 100644 index 0000000..17459e0 Binary files /dev/null and b/resources/Star4000 Large Compressed Numbers.ttf differ diff --git a/resources/Star4000 Large Compressed.ttf b/resources/Star4000 Large Compressed.ttf new file mode 100644 index 0000000..936d759 Binary files /dev/null and b/resources/Star4000 Large Compressed.ttf differ diff --git a/resources/Star4000 Large.ttf b/resources/Star4000 Large.ttf new file mode 100644 index 0000000..60400ec Binary files /dev/null and b/resources/Star4000 Large.ttf differ diff --git a/resources/Star4000 Small.ttf b/resources/Star4000 Small.ttf new file mode 100644 index 0000000..f4428e4 Binary files /dev/null and b/resources/Star4000 Small.ttf differ diff --git a/resources/Star4000.ttf b/resources/Star4000.ttf new file mode 100644 index 0000000..638855c Binary files /dev/null and b/resources/Star4000.ttf differ diff --git a/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java new file mode 100644 index 0000000..38cecda --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/RenderPanel.java @@ -0,0 +1,250 @@ +package com.flaremicro.flaretv.visualforecast; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Polygon; +import java.awt.image.VolatileImage; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.concurrent.locks.LockSupport; + +import javax.swing.JPanel; + +import com.flaremicro.flaretv.visualforecast.icons.IconProvider; + +public class RenderPanel extends JPanel implements Runnable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private VolatileImage frameBuffer = null; + + /** + * Create the panel. + */ + + private Color backgroundPurple = new Color(0x2b29b3); + private Color backgroundOrange = new Color(0xff8c00); + private Color backgroundBlue = new Color(0x394aa8); + + private Font font = null; + + float fontMult = 20F; + + private int animationTick = 0; + + private String[] testString; + + public RenderPanel() { + try + { + font = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getResourceAsStream("/Star4000.ttf")); + } + catch (FontFormatException e) + { + e.printStackTrace(); + } + catch (IOException e) + { + e.printStackTrace(); + } + testString = "The sandwiches at gas stations\nare disgusting, we advise you\ndo not eat them".split("\n"); + new Thread(this).start(); + } + + private static final int W = 640, H = 480; + private static final int INFOBAR_HEIGHT = 80; + private static final int TOPBAR_HEIGHT = 80; + private static final int MAINBAR_HEIGHT = H - INFOBAR_HEIGHT - TOPBAR_HEIGHT; + + private static final int HEADERBAR_Y = 20; + private static final double HEADERBAR_SHEAR = 0.2; + private static final int HEADERBAR_OFFSET = 20; + private static final int HEADERBAR_WIDTH = 400 + HEADERBAR_OFFSET; + private static final int HEADERBAR_HEIGHT = TOPBAR_HEIGHT - HEADERBAR_Y; + + private static final int TIMEBAR_Y = 40; + private static final int TIMEBAR_OFFSET = 20; + private static final int TIMEBAR_WIDTH = 230 + HEADERBAR_OFFSET; + private static final int TIMEBAR_HEIGHT = TOPBAR_HEIGHT - TIMEBAR_Y; + + private static final int STROKE_WIDTH = 2; + private static final int STROKE_OFFSET = STROKE_WIDTH / 2; + + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMMM d"); + private static final DateFormat TIME_FORMAT = new SimpleDateFormat("hh:mm:ss a"); + + public Graphics2D prepareFrameBuffer() { + GraphicsConfiguration gc = this.getGraphicsConfiguration(); + if (frameBuffer == null || frameBuffer.validate(gc) != VolatileImage.IMAGE_INCOMPATIBLE) + { + frameBuffer = gc.createCompatibleVolatileImage(W, H); + } + return (Graphics2D) frameBuffer.getGraphics(); + } + + private static String getDayOfMonthSuffix() { + int n = Calendar.getInstance().get(Calendar.DAY_OF_MONTH); + if (n >= 11 && n <= 13) + { + return "th"; + } + switch (n % 10) { + case 1: + return "st"; + case 2: + return "nd"; + case 3: + return "rd"; + default: + return "th"; + } + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2d = prepareFrameBuffer(); + if (font == null) + font = g2d.getFont(); + g2d.setFont(font.deriveFont(24F)); + + g2d.setStroke(new BasicStroke(2)); + + g2d.setColor(this.backgroundPurple); + g2d.fillRect(0, 0, W, TOPBAR_HEIGHT); + + g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, backgroundOrange, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), backgroundPurple)); + g2d.shear(HEADERBAR_SHEAR, 0); + g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT); + + g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, backgroundPurple.brighter().brighter().brighter(), 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), backgroundPurple)); + g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); + g2d.shear(-HEADERBAR_SHEAR, 0); + + g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, backgroundPurple, 0, MAINBAR_HEIGHT, backgroundOrange)); + g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); + + g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); + + g2d.setColor(this.backgroundBlue); + g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT); + + g2d.setColor(Color.DARK_GRAY); + g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_OFFSET); + + g2d.setColor(Color.WHITE); + g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET); + + drawGradientRect(g2d, 60, TOPBAR_HEIGHT, W - 120, MAINBAR_HEIGHT, 20, backgroundBlue.brighter(), backgroundBlue.darker()); + g2d.setColor(backgroundBlue.brighter()); + g2d.drawRect(60 + STROKE_OFFSET, TOPBAR_HEIGHT + STROKE_OFFSET, W - 120 - STROKE_WIDTH, MAINBAR_HEIGHT - STROKE_WIDTH); + // g2d.setColor(Color.GRAY); + // g2d.drawRect(60, TOPBAR_HEIGHT+2, W-120, MAINBAR_HEIGHT-4); + + String dateString = DATE_FORMAT.format(System.currentTimeMillis()) + getDayOfMonthSuffix(); + String timeString = TIME_FORMAT.format(System.currentTimeMillis()); + + // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + // RenderingHints.VALUE_ANTIALIAS_ON); + drawOutlinedString(g2d, 60, HEADERBAR_Y + 18, "Your local forecast", Color.WHITE, Color.BLACK, 1); + int sw = g2d.getFontMetrics().stringWidth(dateString); + drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 18, dateString, Color.WHITE, Color.BLACK, 1); + sw = g2d.getFontMetrics().stringWidth(timeString); + drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 1); + g2d.setFont(font.deriveFont(36F)); + drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, "New Westminster, BC", Color.YELLOW, Color.BLACK, 2); + + int w2 = g2d.getFontMetrics().stringWidth("EXTREME WEATHER ADVISORY"); + drawOutlinedString(g2d, (W >> 1) - (w2 >> 1), TOPBAR_HEIGHT + 48, "EXTREME WEATHER ADVISORY", Color.RED, Color.BLACK, 2); + + g2d.setFont(font.deriveFont(30F)); + for (int i = 0; i < testString.length; i++) + { + drawOutlinedString(g2d, 90, TOPBAR_HEIGHT + 78 + 25 * i, testString[i], Color.WHITE, Color.BLACK, 1); + } + + // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + // RenderingHints.VALUE_ANTIALIAS_ON); + IconProvider.drawIcon(g2d, IconProvider.SNOWFLAKE, 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.CLOUD, 160, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.PARTLY_CLOUDY, 160 + 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.CLOUDY_CLOUDY, 160 + 160, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.RAIN, 160 + 160 + 80, 300, 80, animationTick); + IconProvider.drawIcon(g2d, IconProvider.SCATTERD_SHOWERS, 160 + 160 + 160, 300, 80, animationTick); + + g2d.dispose(); + g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this); + } + + public void drawGradientRect(Graphics2D g, int x, int y, int w, int h, int borderWidth, Color innerColor, Color outerColor) { + + g.setColor(innerColor); + g.fillRect(x, y, w, h); + + g.setPaint(new GradientPaint(x, 0, outerColor, x + borderWidth, 0, innerColor)); + g.fillRect(x, y, borderWidth, h); + + g.setPaint(new GradientPaint(x + w - borderWidth, 0, innerColor, x + w, 0, outerColor)); + g.fillRect(x + w - borderWidth, y, borderWidth, h); + + g.setPaint(new GradientPaint(0, y, outerColor, 0, y + borderWidth, innerColor)); + g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y, y, y + borderWidth, y + borderWidth }, 4)); + g.fillRect(x, y, w, borderWidth); + + g.setClip(new Polygon(new int[] { x, x + w, x + w - borderWidth, x + borderWidth }, new int[] { y + h, y + h, y + h - borderWidth, y + h - borderWidth }, 4)); + g.setPaint(new GradientPaint(0, y + h - borderWidth, innerColor, 0, y + h, outerColor)); + g.fillRect(x, y + h - borderWidth, w, borderWidth); + + g.setClip(null); + + } + + public void drawOutlinedString(Graphics2D g2d, int x, int y, String text, Color textColor, Color outline, int outlineSize) { + g2d.setColor(outline); + for (int i = 1; i <= outlineSize; i++) + { + g2d.drawString(text, x + i, y); + g2d.drawString(text, x - i, y); + g2d.drawString(text, x, y + i); + g2d.drawString(text, x, y - i); + g2d.drawString(text, x + i, y + i); + g2d.drawString(text, x - i, y - i); + g2d.drawString(text, x - i, y + i); + g2d.drawString(text, x + i, y - i); + } + + g2d.setColor(textColor); + g2d.drawString(text, x, y); + /* + * AffineTransform transform = g2d.getTransform(); + * transform.translate(x, y); g2d.transform(transform); + * g2d.setColor(outline); FontRenderContext frc = + * g2d.getFontRenderContext(); TextLayout tl = new TextLayout(text, + * g2d.getFont(), frc); Shape shape = tl.getOutline(null); + * g2d.setStroke(new BasicStroke(outlineSize)); g2d.draw(shape); + * g2d.setColor(textColor); g2d.fill(shape); + */ + } + + @Override + public void run() { + while (true) + { + this.animationTick++; + repaint(); + LockSupport.parkNanos(125000000); + } + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java b/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java new file mode 100644 index 0000000..56eb452 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/SmallTextInfo.java @@ -0,0 +1,44 @@ +package com.flaremicro.flaretv.visualforecast; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +public class SmallTextInfo extends JFrame { + + /** + * + */ + private static final long serialVersionUID = 1L; + private JPanel contentPane; + + /** + * Create the frame. + */ + public SmallTextInfo(RenderPanel rp) { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 295, 93); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(null); + + JSpinner spinner = new JSpinner(); + spinner.setModel(new SpinnerNumberModel(new Float(rp.fontMult), null, null, new Float(0.5F))); + spinner.setBounds(12, 12, 255, 22); + spinner.addChangeListener(new ChangeListener(){ + + @Override + public void stateChanged(ChangeEvent e) { + rp.fontMult = (Float)spinner.getValue(); + rp.repaint(); + } + + }); + contentPane.add(spinner); + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/TickThread.java b/src/com/flaremicro/flaretv/visualforecast/TickThread.java new file mode 100644 index 0000000..b9037db --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/TickThread.java @@ -0,0 +1,43 @@ +package com.flaremicro.flaretv.visualforecast; + +import com.flaremicro.flaretv.visualforecast.interfaces.Tickable; + +public class TickThread implements Runnable { + private final Tickable tickable; + private boolean running = true; + private final long sleepNanos; + + private long nextTick = 0; + + TickThread(Tickable tickable, long sleepNanos) { + this.tickable = tickable; + this.sleepNanos = sleepNanos; + } + + public void end() { + this.running = false; + } + + public void run() { + while (running) { + while(System.nanoTime() < nextTick) + { + try + { + Thread.sleep(1); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + nextTick = System.nanoTime() + sleepNanos; + tickable.tick(); + /*long nanosLost = System.nanoTime(); + panel.tick(); + nanosLost -= System.nanoTime(); + if(sleepNanos+nanosLost > 0) + LockSupport.parkNanos(sleepNanos+nanosLost);*/ + } + } +} \ No newline at end of file diff --git a/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java b/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java new file mode 100644 index 0000000..4428ca9 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/VisualForecastFrame.java @@ -0,0 +1,45 @@ +package com.flaremicro.flaretv.visualforecast; + +import java.awt.BorderLayout; +import java.awt.EventQueue; + +import javax.swing.JFrame; + +public class VisualForecastFrame extends JFrame { + + /** + * + */ + private static final long serialVersionUID = 1L; + private RenderPanel contentPane; + + /** + * Launch the application. + */ + public static void main(String[] args) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + VisualForecastFrame frame = new VisualForecastFrame(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Create the frame. + */ + public VisualForecastFrame() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 640*2, 480*2); + contentPane = new RenderPanel(); + contentPane.setBorder(null); + contentPane.setLayout(new BorderLayout(0, 0)); + setContentPane(contentPane); + setUndecorated(true); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java new file mode 100644 index 0000000..b47569c --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/CloudIcon.java @@ -0,0 +1,89 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Ellipse2D; + +public class CloudIcon implements Icon { + Ellipse2D.Float[] cloudCircles = new Ellipse2D.Float[]{ + new Ellipse2D.Float(0, 0.5F, 0.28F, 0.325F), + new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F), + new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F), + new Ellipse2D.Float(0.435F, 0.585F, 0.226F, 0.253F), + new Ellipse2D.Float(0.749F, 0.412F, 0.251F, 0.417F), + new Ellipse2D.Float(0.478F, 0.235F, 0.348F, 0.602F), + new Ellipse2D.Float(0.233F, 0.150F, 0.369F, 0.677F), + new Ellipse2D.Float(0.113F, 0.326F, 0.266F, 0.356F), + }; + + + Ellipse2D.Float[] extraStroke = new Ellipse2D.Float[]{ + new Ellipse2D.Float(0.142F, 0.619F, 0.287F, 0.231F), + new Ellipse2D.Float(0.666F, 0.597F, 0.208F, 0.234F) + }; + + + + Ellipse2D.Float[] overStroke = new Ellipse2D.Float[]{ + new Ellipse2D.Float(0.233F, 0.150F, 0.369F, 0.677F), + new Ellipse2D.Float(0.113F, 0.326F, 0.266F, 0.356F), + new Ellipse2D.Float(0.749F, 0.412F, 0.251F, 0.417F), + new Ellipse2D.Float(0.652F, 0.555F, 0.150F, 0.136F), + }; + + Ellipse2D.Float[] lightCircles = new Ellipse2D.Float[]{ + new Ellipse2D.Float(0.309F, 0.173F, 0.209F, 0.235F), + new Ellipse2D.Float(0.554F, 0.276F, 0.204F, 0.314F), + new Ellipse2D.Float(0.770F, 0.440F, 0.204F, 0.235F), + new Ellipse2D.Float(0.141F, 0.348F, 0.260F, 0.235F), + new Ellipse2D.Float(0.259F, 0.460F, 0.314F, 0.235F), + }; + + Ellipse2D.Float[] overLight = new Ellipse2D.Float[]{ + new Ellipse2D.Float(0.328F, 0.188F, 0.209F, 0.235F), + new Ellipse2D.Float(0.573F, 0.296F, 0.204F, 0.314F), + new Ellipse2D.Float(0.789F, 0.456F, 0.204F, 0.235F), + new Ellipse2D.Float(0.155F, 0.369F, 0.260F, 0.235F), + new Ellipse2D.Float(0.288F, 0.476F, 0.314F, 0.235F), + }; + + + @Override + public void drawIcon(Graphics2D g2d, float scale, int animationStep) { + g2d.setColor(Color.BLACK); + g2d.setStroke(new BasicStroke(4/scale)); + for(int i = 0; i < cloudCircles.length; i++) + { + g2d.draw(cloudCircles[i]); + } + g2d.setColor(Color.LIGHT_GRAY); + for(int i = 0; i < cloudCircles.length; i++) + { + g2d.fill(cloudCircles[i]); + } + + g2d.setColor(Color.BLACK); + g2d.setStroke(new BasicStroke(2/scale)); + for(int i = 0; i < extraStroke.length; i++) + { + g2d.draw(extraStroke[i]); + } + + g2d.setColor(Color.LIGHT_GRAY); + for(int i = 0; i < overStroke.length; i++) + { + g2d.fill(overStroke[i]); + } + + for(int i = 0; i < lightCircles.length; i++) + { + g2d.setColor(Color.LIGHT_GRAY.brighter()); + g2d.fill(lightCircles[i]); + g2d.setColor(Color.LIGHT_GRAY); + g2d.fill(overLight[i]); + } + + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java new file mode 100644 index 0000000..380354a --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/Icon.java @@ -0,0 +1,7 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.Graphics2D; + +public interface Icon { + public void drawIcon(Graphics2D g2d, float scale, int animationStep); +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java new file mode 100644 index 0000000..e2b1570 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/IconProvider.java @@ -0,0 +1,42 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; + +public class IconProvider { + + public static int SUN = 0; + public static int CLOUD = 1; + public static int PARTLY_CLOUDY = 2; + public static int CLOUDY_CLOUDY = 3; + public static int RAIN = 4; + public static int SCATTERD_SHOWERS = 5; + public static int SNOWFLAKE = 6; + + + private static final Icon[] CLASS_DEFS = new Icon[64]; + + static{ + CLASS_DEFS[SUN] = new SunIcon(); + CLASS_DEFS[CLOUD] = new CloudIcon(); + CLASS_DEFS[PARTLY_CLOUDY] = new PartlyCloudyIcon(CLASS_DEFS[CLOUD], CLASS_DEFS[SUN]); + CLASS_DEFS[CLOUDY_CLOUDY] = new PartlyCloudyIcon(CLASS_DEFS[CLOUD], CLASS_DEFS[CLOUD]); + CLASS_DEFS[RAIN] = new RainIcon(2, 1F, CLASS_DEFS[CLOUD]); + CLASS_DEFS[SCATTERD_SHOWERS] = new PartlyCloudyIcon(new RainIcon(2, 4F, CLASS_DEFS[CLOUD]), CLASS_DEFS[SUN]); + CLASS_DEFS[SNOWFLAKE] = new SnowflakeIcon(); + } + + public static void drawIcon(Graphics2D g2d, int icon, int x, int y, int scale, int animationStep) + { + if(icon >= 0 && CLASS_DEFS.length > icon) + { + AffineTransform af = g2d.getTransform(); + g2d.translate(x, y); + g2d.scale(scale, scale); + //1g2d.setColor(Color.RED); + //g2d.fill(new Rectangle2D.Float(0, 0, 1F, 1F)); + CLASS_DEFS[icon].drawIcon(g2d, scale, animationStep); + g2d.setTransform(af); + } + } +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java new file mode 100644 index 0000000..0c37cd7 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/PartlyCloudyIcon.java @@ -0,0 +1,28 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.Graphics2D; + +public class PartlyCloudyIcon implements Icon { + private Icon cloud; + private Icon sun; + + public PartlyCloudyIcon(Icon cloud, Icon sun) + { + this.cloud = cloud; + this.sun = sun; + } + + @Override + public void drawIcon(Graphics2D g2d, float scale, int animationStep) { + g2d.translate(0.2F, 0.07F); + g2d.scale(0.8F, 0.8F); + sun.drawIcon(g2d, scale, animationStep); + g2d.scale(1.25F, 1); + g2d.translate(-0.2F, 0.2F); + cloud.drawIcon(g2d, scale, animationStep); + g2d.translate(0, -0.2F); + g2d.scale(1, 1.25F); + g2d.translate(0, -0.07F); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java new file mode 100644 index 0000000..5c9c8c5 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/RainIcon.java @@ -0,0 +1,76 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Path2D; + +public class RainIcon implements Icon { + private final int rainCount; + private final float rainSpace; + private final Icon cloudIcon; + + Path2D.Float[] rainPath = new Path2D.Float[6]; + Color[] aniColors = new Color[]{ + //new Color(0x0000FF), + new Color(0x0022FF), + //new Color(0x0044FF), + new Color(0x0066FF), + //new Color(0x0088FF), + new Color(0x00DDFF), + //new Color(0x00CCFF), + new Color(0xFFFFFF), + //new Color(0x0088FF), + new Color(0x00DDFF), + //new Color(0x0044FF), + new Color(0x0066FF), + }; + + public RainIcon(int rainCount, float rainSpace, Icon cloudIcon) + { + this.rainCount = rainCount; + this.rainSpace = rainSpace * 0.125F; + this.cloudIcon = cloudIcon; + for(int i = 0; i < rainPath.length; i++) + { + float ph = 0.075F; + float pw = 0.1F; + float poff = 0.037F; + float xoff = poff*i; + float yoff = ph*i; + rainPath[i] = new Path2D.Float(); + rainPath[i].moveTo(0F+xoff, 1F-yoff); + rainPath[i].lineTo(poff+xoff, 1F-ph-yoff); + rainPath[i].lineTo(pw+poff+xoff, 1F-ph-yoff); + rainPath[i].lineTo(pw+xoff, 1F-yoff); + rainPath[i].closePath(); + } + } + + @Override + public void drawIcon(Graphics2D g2d, float scale, int animationStep) { + g2d.setStroke(new BasicStroke(4/scale)); + for(int j = 0; j < rainCount; j++) + { + g2d.translate(j*rainSpace, 0F); + g2d.setColor(Color.BLACK); + for(int i = 0; i < rainPath.length; i++) + { + g2d.draw(rainPath[i]); + } + for(int i = 0; i < rainPath.length; i++) + { + + g2d.setColor(aniColors[Math.abs(i-j+animationStep) % aniColors.length]); + g2d.fill(rainPath[i]); + } + g2d.translate(-j*rainSpace, 0F); + } + g2d.translate(0F, -0.10F); + g2d.scale(1F, 0.8F); + cloudIcon.drawIcon(g2d, scale, animationStep); + g2d.scale(1F, 1.25F); + g2d.translate(0F, 0.10F); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java new file mode 100644 index 0000000..5276d04 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/SnowflakeIcon.java @@ -0,0 +1,106 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Path2D; + +public class SnowflakeIcon implements Icon { + Path2D.Float flakePath = new Path2D.Float(); + Path2D.Float gradPath = new Path2D.Float(); + Path2D.Float trianglePath = new Path2D.Float(); + + public SnowflakeIcon() + { + flakePath.moveTo(0.400, 0); + flakePath.lineTo(0.600, 0); + flakePath.lineTo(0.600, 0.327); + flakePath.lineTo(0.883, 0.163); + flakePath.lineTo(0.983, 0.336); + flakePath.lineTo(0.700, 0.500); + flakePath.lineTo(0.983, 0.664); + flakePath.lineTo(0.883, 0.837); + flakePath.lineTo(0.600,0.673); + flakePath.lineTo(0.600,1.000); + flakePath.lineTo(0.400,1.000); + flakePath.lineTo(0.400,0.673); + flakePath.lineTo(0.117,0.847); + flakePath.lineTo(0.017, 0.664); + flakePath.lineTo(0.300,0.500); + flakePath.lineTo(0.017,0.336); + flakePath.lineTo(0.117,0.163); + flakePath.lineTo(0.400,0.327); + flakePath.closePath(); + + gradPath.moveTo(0.433, 0.422); + gradPath.lineTo(0.143, 0.200); + gradPath.lineTo(0.433, 0.375); + gradPath.lineTo(0.429, 0.009); + gradPath.lineTo(0.480, 0.396); + gradPath.lineTo(0.446, 0.395); + gradPath.closePath(); + + gradPath.moveTo(0.533, 0.398); + gradPath.lineTo(0.579, 0.013); + gradPath.lineTo(0.576, 0.371); + gradPath.lineTo(0.875, 0.194); + gradPath.lineTo(0.565, 0.432); + gradPath.lineTo(0.547, 0.397); + gradPath.closePath(); + + gradPath.moveTo(0.591,0.479); + gradPath.lineTo(0.947,0.326); + gradPath.lineTo(0.638,0.500); + gradPath.lineTo(0.959,0.681); + gradPath.lineTo(0.597,0.531); + gradPath.lineTo(0.610,0.510); + gradPath.closePath(); + + gradPath.moveTo(0.569,0.576); + gradPath.lineTo(0.880,0.808); + gradPath.lineTo(0.574,0.628); + gradPath.lineTo(0.577,0.985); + gradPath.lineTo(0.527,0.597); + gradPath.lineTo(0.558,0.598); + gradPath.closePath(); + + gradPath.moveTo(0.473,0.596); + gradPath.lineTo(0.428,0.981); + gradPath.lineTo(0.431,0.626); + gradPath.lineTo(0.122,0.808); + gradPath.lineTo(0.432,0.570); + gradPath.lineTo(0.446,0.597); + gradPath.closePath(); + + gradPath.moveTo(0.407,0.523); + gradPath.lineTo(0.051,0.676); + gradPath.lineTo(0.358,0.502); + gradPath.lineTo(0.060,0.332); + gradPath.lineTo(0.408,0.481); + gradPath.lineTo(0.394,0.503); + gradPath.closePath(); + + trianglePath.moveTo(0.503, 0.421); + trianglePath.lineTo(0.578, 0.551); + trianglePath.lineTo(0.428, 0.551); + trianglePath.closePath();; + } + + @Override + public void drawIcon(Graphics2D g2d, float scale, int animationStep) { + g2d.setStroke(new BasicStroke(4/scale)); + g2d.setColor(Color.BLACK); + g2d.draw(flakePath); + g2d.setColor(Color.WHITE); + g2d.fill(flakePath); + //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setPaint(new Color(0x2288FF)); + g2d.fill(gradPath); + g2d.setStroke(new BasicStroke(1/scale)); + g2d.draw(gradPath); + //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.setPaint(Color.BLACK); + g2d.fill(trianglePath); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java b/src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java new file mode 100644 index 0000000..f603a18 --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/icons/SunIcon.java @@ -0,0 +1,75 @@ +package com.flaremicro.flaretv.visualforecast.icons; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Path2D; + +public class SunIcon implements Icon { + Path2D.Float sunPath = new Path2D.Float(); + Ellipse2D.Float sunCircle1 = new Ellipse2D.Float(0.2F, 0.2F, 0.6F, 0.6F); + Ellipse2D.Float sunInternalCircle1 = new Ellipse2D.Float(0.28F, 0.22F, 0.5F, 0.5F); + Ellipse2D.Float sunInternalCircle2 = new Ellipse2D.Float(0.34F, 0.22F, 0.4F, 0.4F); + Color[] animationColours = new Color[]{ + new Color(255, 100, 0), + new Color(255, 120, 0), + new Color(255, 140, 0), + new Color(255, 160, 0), + new Color(255, 180, 0), + new Color(255, 200, 0), + new Color(255, 220, 0), + new Color(255, 200, 0), + new Color(255, 180, 0), + new Color(255, 160, 0), + new Color(255, 140, 0), + new Color(255, 120, 0), + }; + public SunIcon() + { + sunPath.moveTo(0.5F, 0.0F); + sunPath.lineTo(0.605F, 0.106F); + sunPath.lineTo(0.750F, 0.067F); + sunPath.lineTo(0.789F, 0.211F); + sunPath.lineTo(0.933F, 0.250F); + sunPath.lineTo(0.894F, 0.394F); + sunPath.lineTo(1.0F, 0.5F); + sunPath.lineTo(0.894F, 0.606F); + sunPath.lineTo(0.933F, 0.750F); + sunPath.lineTo(0.789F, 0.789F); + sunPath.lineTo(0.750F, 0.933F); + sunPath.lineTo(0.605F, 0.894F); + sunPath.lineTo(0.5F, 1.0F); + sunPath.lineTo(0.394F, 0.894F); + sunPath.lineTo(0.250F, 0.933F); + sunPath.lineTo(0.211F, 0.789F); + sunPath.lineTo(0.067F, 0.750F); + sunPath.lineTo(0.106F, 0.606F); + sunPath.lineTo(0.0F, 0.5F); + sunPath.lineTo(0.106F, 0.394F); + sunPath.lineTo(0.067F, 0.250F); + sunPath.lineTo(0.211F, 0.211F); + sunPath.lineTo(0.250F, 0.067F); + sunPath.lineTo(0.394F, 0.106F); + sunPath.closePath(); + } + + @Override + public void drawIcon(Graphics2D g2d, float scale, int animationStep) { + g2d.setColor(Color.BLACK); + g2d.setStroke(new BasicStroke(4/scale)); + g2d.draw(sunPath); + g2d.setColor(animationColours[animationStep % animationColours.length]); + g2d.fill(sunPath); + g2d.setColor(new Color(0xFFEE00)); + g2d.fill(sunCircle1); + g2d.setColor(new Color(0xFFFF88)); + g2d.fill(sunInternalCircle1); + g2d.setColor(new Color(0xFFFFDD)); + g2d.fill(sunInternalCircle2); + g2d.setColor(Color.BLACK); + g2d.setStroke(new BasicStroke(2/scale)); + g2d.draw(sunCircle1); + } + +} diff --git a/src/com/flaremicro/flaretv/visualforecast/interfaces/Tickable.java b/src/com/flaremicro/flaretv/visualforecast/interfaces/Tickable.java new file mode 100644 index 0000000..27ce33a --- /dev/null +++ b/src/com/flaremicro/flaretv/visualforecast/interfaces/Tickable.java @@ -0,0 +1,5 @@ +package com.flaremicro.flaretv.visualforecast.interfaces; + +public interface Tickable { + public void tick(); +}