/* * Copyright 2013 eWidgetFX. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.thehecklers.ticker; import javafx.animation.AnimationTimer; import javafx.geometry.Bounds; import javafx.geometry.Rectangle2D; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.shape.SVGPath; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.stage.Screen; import javafx.stage.Stage; import org.ewidgetfx.core.DefaultWidget; import org.ewidgetfx.core.LaunchInfo; import org.ewidgetfx.core.TextIconOverlay; import org.ewidgetfx.core.WidgetIcon; import org.ewidgetfx.util.Demo; import org.thehecklers.feed.Feed; import org.thehecklers.feed.TwitterFeed; /** * * @author Mark Heckler <mark.heckler@gmail.com> * Twitter: @MkHeck * * */ public class Ticker extends DefaultWidget { // The icon overlay or badge indicator TextIconOverlay tio = new TextIconOverlay(); Thread backgroundThread; // Runnable worker; private boolean border = true; private double xCoord; private double yCoord; private String message; private Feed msgFeed; private Color color = Color.YELLOW; private Dimension messageBounds; private AnimationTimer timer; public Ticker() { } @Override public WidgetIcon buildWidgetIcon() { // create an icon SVGPath svgPath = new SVGPath(); // Twitter icon svgPath.setContent("M26.492,9.493c-0.771,0.343-1.602,0.574-2.473,0.678c0.89-0.533,1.562-1.376,1.893-2.382c-0.832,0.493-1.753,0.852-2.734,1.044c-0.785-0.837-1.902-1.359-3.142-1.359c-2.377,0-4.306,1.928-4.306,4.306c0,0.337,0.039,0.666,0.112,0.979c-3.578-0.18-6.75-1.894-8.874-4.499c-0.371,0.636-0.583,1.375-0.583,2.165c0,1.494,0.76,2.812,1.915,3.583c-0.706-0.022-1.37-0.216-1.95-0.538c0,0.018,0,0.036,0,0.053c0,2.086,1.484,3.829,3.454,4.222c-0.361,0.099-0.741,0.147-1.134,0.147c-0.278,0-0.547-0.023-0.81-0.076c0.548,1.711,2.138,2.955,4.022,2.99c-1.474,1.146-3.33,1.842-5.347,1.842c-0.348,0-0.69-0.021-1.027-0.062c1.905,1.225,4.168,1.938,6.6,1.938c7.919,0,12.248-6.562,12.248-12.25c0-0.187-0.002-0.372-0.01-0.557C25.186,11.115,25.915,10.356,26.492,9.493"); // Facebook icon //svgPath.setContent("M25.566,2.433H6.433c-2.2,0-4,1.8-4,4v19.135c0,2.199,1.8,4,4,4h19.135c2.199,0,4-1.801,4-4V6.433C29.566,4.232,27.768,2.433,25.566,2.433zM25.309,16.916h-3.218v11.65h-4.819v-11.65h-2.409V12.9h2.409v-2.411c0-3.275,1.359-5.224,5.229-5.224h3.218v4.016h-2.011c-1.504,0-1.604,0.562-1.604,1.608L22.091,12.9h3.644L25.309,16.916z"); svgPath.autosize(); svgPath.setFill(Color.web("#00acee")); WidgetIcon widgetIcon = new WidgetIcon(svgPath, tio); widgetIcon.setBadgePosition(WidgetIcon.BADGE_POS.SE); return widgetIcon; } @Override public void startBackground() { // worker = new Runnable() { // @Override // public void run() { // } // }; } @Override public void init() { System.out.println("decoration: " + getDecoration()); // Determine and configure widget screen real estate final Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds(); Dimension widgetBounds = new Dimension(screenBounds.getWidth(), 25); setPrefSize(widgetBounds.getWidth(), widgetBounds.getHeight()); setMaxSize(widgetBounds.getWidth(), widgetBounds.getHeight()); Rectangle backRect = createBackground(widgetBounds.getWidth(), widgetBounds.getHeight()); getChildren().add(backRect); Canvas canvas = new Canvas(widgetBounds.getWidth(), widgetBounds.getHeight()); final GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFont(Font.getDefault()); gc.setFill(color); gc.setStroke(color); getChildren().add(canvas); // commented out please see start() method. getParentStage().setX(screenBounds.getMinX()); getParentStage().setWidth(screenBounds.getWidth()); getParentStage().setY(screenBounds.getHeight() - widgetBounds.getHeight()); msgFeed = new TwitterFeed(); //msgFeed = new FacebookFeed(); formatNextMessage(); final Bounds canvasBounds = canvas.getBoundsInLocal(); // The x coordinate for ticker content begins at right edge of screen, minus border xCoord = canvasBounds.getMaxX() - 1; // Center the y coordinate on the canvas for the text yCoord = canvasBounds.getMaxY() - (canvasBounds.getMaxY() - canvasBounds.getMinY() - messageBounds.getHeight()); // above is not known until nodes and text has been rendered. // since the ticker's height is already defined take the center (baseline) add two pixels to avoid the yellow border //yCoord = (widgetBounds.getHeight() / 2) + 2; timer = new AnimationTimer() { @Override public void handle(long now) { // update gc.clearRect(xCoord, canvasBounds.getMinY() + 2, messageBounds.getWidth(), canvasBounds.getHeight() - 4); if (border) { gc.strokeRect(canvasBounds.getMinX(), canvasBounds.getMinY(), canvasBounds.getMaxX(), canvasBounds.getMaxY()); } gc.fillText(message, xCoord -= 2, yCoord); if (xCoord < -messageBounds.getWidth()) { xCoord = canvasBounds.getMaxX() - 1; formatNextMessage(); } } }; timer.start(); } @Override public void start() { //timer.start(); } @Override public void pause() { timer.stop(); } @Override public void resume() { timer.start(); } @Override public void stop() { if (timer != null) { timer.stop(); } } @Override public void stopBackground() { if (backgroundThread != null && backgroundThread.isAlive()) { backgroundThread.interrupt(); } } /** * The main() method is ignored in correctly deployed JavaFX application. main() serves only as fallback in case the * application can not be launched through deployment artifacts, e.g., in IDEs with limited FX support. NetBeans * ignores main(). * * @param args the command line arguments */ public static void main(String[] args) { Ticker widget = new Ticker(); widget.setDecoration(DECORATION.STAGED_UNDECORATED); LaunchInfo info = new LaunchInfo(); info.setLaunchType(LaunchInfo.LaunchType.WIDGET); info.setExecutionLine(widget.getClass().getName()); info.setWidget(widget); widget.setLaunchInfo(info); Demo.newInstance() .setWidget(widget) .setSceneColor(new Color(0, 0, 0, .70)) .run(args); } private void formatNextMessage() { // Retrieve next message from the live feed message = msgFeed.getMessage(); // Format the message for scrolling movement. Inelegant, but functional. Text text = new Text(message); text.snapshot(null, null); messageBounds = new Dimension(text.getLayoutBounds().getWidth(), text.getLayoutBounds().getHeight()); } private Rectangle createBackground(double w, double h) { Rectangle bg = new Rectangle(); //bg.setArcWidth(20); //bg.setArcHeight(20); bg.setHeight(h); bg.setWidth(w); //bg.setFill(Color.rgb(0, 0, 0, .70)); bg.setFill(Color.BLACK); return bg; } }