/* This file is part of JFLICKS. JFLICKS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JFLICKS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JFLICKS. If not, see <http://www.gnu.org/licenses/>. */ package org.jflicks.ui.view.fe; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import javax.swing.JLayeredPane; import javax.swing.JWindow; import javax.swing.Timer; import javax.swing.SwingConstants; import org.jflicks.imagecache.ImageCache; import org.jflicks.nms.Video; import org.jflicks.player.Player; import org.jflicks.player.PlayState; import org.jflicks.util.Util; import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.JXLabel; import org.jdesktop.swingx.painter.ImagePainter; import org.jdesktop.swingx.painter.MattePainter; /** * This is our "banner" window showing the state of the currently running * video. * * The banner is not transparent to allow video bits to come through as * a Java window functionality for this is not available until Java 7, or * at least not in a public API. The second issue with it is that * "compositing" needs to be enabled to use it under Linux which may * clash with VDPAU. * * @author Doug Barnum * @version 1.0 */ public class VideoInfoWindow extends JWindow implements ActionListener { private static final double HGAP = 0.02; private static final double VGAP = 0.02; private JXPanel panel; private JXLabel titleLabel; private JXLabel releasedLabel; private JXLabel descriptionLabel; private TimelinePanel timelinePanel; private Video video; private Player player; private int seconds; private ImageCache imageCache; private Timer timer; private int currentSeconds; /** * Simple constructor with our required arguments. * * @param r The Rectangle defining the location of the main window. * @param seconds the number of seconds to leave the banner visible. * @param normal The text color to match the theme. * @param backlight The background color to match the theme. * @param alpha The translucent level for the window so the back image * shows through. * @param small A small font to use. * @param large A large font to use. */ public VideoInfoWindow(Rectangle r, int seconds, Color normal, Color backlight, float alpha, Font small, Font large) { setCursor(Util.getNoCursor()); setSeconds(seconds); int loffset = (int) (r.width * 0.05); int toffset = (int) (r.height * 0.05); int width = r.width - (2 * loffset); int height = (int) (width / 5.4); setBounds(loffset + r.x, toffset + r.y, width, height); double hgap = width * HGAP; double vgap = height * VGAP; JXPanel p = new JXPanel(new BorderLayout()); p.setOpaque(false); p.setAlpha(alpha); setPanel(p); JXPanel top = new JXPanel(new BorderLayout()); top.setOpaque(false); top.setAlpha(alpha); Color copy = new Color(backlight.getRed(), backlight.getGreen(), backlight.getBlue(), (int) (alpha * 255)); MattePainter mpainter = new MattePainter(copy); top.setBackgroundPainter(mpainter); p.add(top, BorderLayout.CENTER); JLayeredPane pane = new JLayeredPane(); top.add(pane, BorderLayout.CENTER); JXLabel title = new JXLabel(); title.setFont(large); title.setTextAlignment(JXLabel.TextAlignment.LEFT); title.setForeground(normal); setTitleLabel(title); JXLabel released = new JXLabel(); released.setFont(small); released.setTextAlignment(JXLabel.TextAlignment.LEFT); released.setForeground(normal); setReleasedLabel(released); JXLabel description = new JXLabel(); description.setFont(small); description.setTextAlignment(JXLabel.TextAlignment.LEFT); description.setVerticalAlignment(SwingConstants.TOP); description.setForeground(normal); description.setLineWrap(true); setDescriptionLabel(description); TimelinePanel tp = new TimelinePanel(); setTimelinePanel(tp); ClockPanel cpanel = new ClockPanel(large, normal, backlight, alpha); cpanel.setOpaque(false); double halfWidth = ((double) width) / 2.0; double titleHeight = ((double) height) * 0.2; double releasedHeight = ((double) height) * 0.2; double descriptionHeight = ((double) height) * 0.4; double timelineHeight = ((double) height) * 0.2 - vgap; title.setBounds((int) hgap, (int) vgap, (int) halfWidth, (int) titleHeight); released.setBounds((int) hgap, (int) (titleHeight + vgap), (int) halfWidth, (int) releasedHeight); description.setBounds((int) hgap, (int) (vgap + titleHeight + releasedHeight), (int) (width - hgap * 2.0), (int) descriptionHeight); tp.setBounds((int) hgap, (int) (vgap + titleHeight + releasedHeight + descriptionHeight), (int) (width - hgap * 2.0), (int) timelineHeight); pane.add(title, Integer.valueOf(100)); pane.add(released, Integer.valueOf(100)); pane.add(description, Integer.valueOf(100)); pane.add(tp, Integer.valueOf(100)); Dimension cpdim = cpanel.getPreferredSize(); if (cpdim != null) { double x = width - cpdim.getWidth() - hgap - ClockPanel.FUDGE; cpanel.setBounds((int) x, (int) vgap, (int) (cpdim.getWidth() + ClockPanel.FUDGE), (int) cpdim.getHeight()); pane.add(cpanel, Integer.valueOf(120)); } add(p); Timer t = new Timer(1000, this); setTimer(t); // See if we can be translucent... if (Util.isTranslucencySupported()) { Util.setWindowOpacity(this, alpha); } // See if we can shape our window... if (Util.isShapedSupported()) { double dwidth = (double) width; double dheight = (double) height; double arc = dheight / 10.0; RoundRectangle2D.Double rrect = new RoundRectangle2D.Double( 0, 0, (double) width, (double) height, arc, arc); Util.setWindowShape(this, rrect); } } private JXPanel getPanel() { return (panel); } private void setPanel(JXPanel p) { panel = p; } private JXLabel getTitleLabel() { return (titleLabel); } private void setTitleLabel(JXLabel l) { titleLabel = l; } private JXLabel getReleasedLabel() { return (releasedLabel); } private void setReleasedLabel(JXLabel l) { releasedLabel = l; } private JXLabel getDescriptionLabel() { return (descriptionLabel); } private void setDescriptionLabel(JXLabel l) { descriptionLabel = l; } private TimelinePanel getTimelinePanel() { return (timelinePanel); } private void setTimelinePanel(TimelinePanel p) { timelinePanel = p; } private int getSeconds() { return (seconds); } private void setSeconds(int i) { seconds = i; } /** * We use the ImageCache service to get poster images to display. * * @return An ImageCache instance. */ public ImageCache getImageCache() { return (imageCache); } /** * We use the ImageCache service to get poster images to display. * * @param ic An ImageCache instance. */ public void setImageCache(ImageCache ic) { imageCache = ic; } private Timer getTimer() { return (timer); } private void setTimer(Timer t) { timer = t; } private int getCurrentSeconds() { return (currentSeconds); } private void setCurrentSeconds(int i) { currentSeconds = i; } /** * We need a Video instance to be able to draw information useful * to the user. * * @return A given Video instance. */ public Video getVideo() { return (video); } /** * We need a Video instance to be able to draw information useful * to the user. * * @param v A given Video instance. */ public void setVideo(Video v) { video = v; JXPanel p = getPanel(); ImageCache ic = getImageCache(); if ((v != null) && (p != null) && (ic != null)) { BufferedImage bi = ic.getImage(v.getBannerURL()); if (bi != null) { int w = getWidth(); if (w > bi.getWidth()) { bi = Util.scaleLarger(w, bi); } ImagePainter painter = new ImagePainter(bi); painter.setScaleToFit(true); p.setBackgroundPainter(painter); } else { p.setBackgroundPainter(null); } JXLabel l = getTitleLabel(); if (l != null) { l.setText(v.getTitle()); } l = getReleasedLabel(); if (l != null) { String released = v.getReleased(); if (released != null) { l.setText(released); } else { l.setText(""); } } l = getDescriptionLabel(); if (l != null) { String desc = v.getDescription(); if (desc != null) { l.setText(desc); } else { l.setText(""); } } } } /** * We need to communicate with the player to get status of the playing * video. * * @return The Player instance. */ public Player getPlayer() { return (player); } /** * We need to communicate with the player to get status of the playing * video. * * @param p The Player instance. */ public void setPlayer(Player p) { player = p; } /** * Override so we can start a Timer to auto shut off the banner. * * @param b True if the banner is asked to be visible. */ public void setVisible(boolean b) { setCurrentSeconds(0); updateWindow(); super.setVisible(b); if (b) { Timer t = getTimer(); if (t != null) { if (!t.isRunning()) { t.restart(); } } } } private void updateWindow() { TimelinePanel tp = getTimelinePanel(); Player p = getPlayer(); Video v = getVideo(); if ((p != null) && (tp != null) && (v != null)) { PlayState ps = p.getPlayState(); if (ps != null) { double current = ps.getTime(); double length = (double) v.getDuration(); double percentage = current / length * 100.0; tp.setValue((int) percentage); tp.setCurrent((int) current); tp.setLength((int) length); } } } /** * When our timer goes off we set the visiblity to false. * * @param event The given Timer event. */ public void actionPerformed(ActionEvent event) { int current = getCurrentSeconds() + 1; if (current >= getSeconds()) { setCurrentSeconds(0); setVisible(false); Timer t = getTimer(); if (t != null) { t.stop(); } } else { setCurrentSeconds(current); updateWindow(); } } }