/*******************************************************************************
* Rhythos Editor is a game editor and project management tool for making RPGs on top of the Rhythos Game system.
*
* Copyright (C) 2013 David Maletz
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mrpg.editor;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import mrpg.editor.resource.Media;
import mrpg.editor.resource.Project;
import mrpg.editor.resource.Resource;
import mrpg.media.Audio;
import mrpg.media.FrameListener;
public class MediaPlayer extends JFrame implements TreeSelectionListener, FrameListener, ActionListener {
private static final long serialVersionUID = 6196229623660851300L;
private final mrpg.media.MediaPlayer player; public final JTree tree;
private final JCheckBox shuffle, play_all, repeat;
public MediaPlayer(WorkspaceBrowser browser){
super("Media Player");
tree = new JTree(new FilterTreeModel(null, Media.FILTER));
tree.addTreeSelectionListener(this);
tree.setCellRenderer(browser.getCellRenderer());
tree.setFocusable(false);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setRootVisible(false);
((BasicTreeUI)tree.getUI()).setExpandedIcon(MapEditor.getIcon("expand"));
((BasicTreeUI)tree.getUI()).setCollapsedIcon(MapEditor.getIcon("collapse"));
tree.putClientProperty("JTree.lineStyle", "None");
Container c = getContentPane(); c.setLayout(new BorderLayout());
JPanel inner = new JPanel(new BorderLayout());
player = new mrpg.media.MediaPlayer();
JButton b = new JButton(new NextIcon()); b.addActionListener(this); player.add(b);
player.setFrameListener(this);
inner.add(player, BorderLayout.NORTH);
JPanel settings = new JPanel();
shuffle = new JCheckBox("Shuffle"); settings.add(shuffle);
play_all = new JCheckBox("Play All Folders"); settings.add(play_all);
repeat = new JCheckBox("Repeat Folders"); settings.add(repeat);
inner.add(settings, BorderLayout.SOUTH);
c.add(inner, BorderLayout.NORTH);
JScrollPane sp = new JScrollPane(tree);
sp.setPreferredSize(new Dimension(300, 300)); c.add(sp, BorderLayout.CENTER);
setIconImages(MapEditor.getWindowIcon()); pack(); MapEditor.addFrame("media", this);
}
public void setProject(Project p){
DefaultTreeModel m = (DefaultTreeModel)tree.getModel();
m.setRoot(p); tree.clearSelection(); player.setClip(null);
}
public void valueChanged(TreeSelectionEvent e) {
if(e.getNewLeadSelectionPath() == null) return;
Resource r = (Resource)e.getNewLeadSelectionPath().getLastPathComponent();
if(r instanceof Media){
Audio.Clip c = ((Media)r).getClip();
if(player.getClip() != c){player.setClip(c); player.play();}
}
}
private Resource innerNextSong(Resource r){
while(r != null){
if(r instanceof Media) return r;
else if(play_all.isSelected() && r.getChildCount() > 0){Resource ret = innerNextSong(r.getChild(0)); if(ret != null) return ret;}
r = (Resource)r.getParent().getChildAfter(r);
}
return null;
}
private Resource seqNextSong(Resource r){
Resource ret = innerNextSong((Resource)r.getParent().getChildAfter(r));
if(ret == null){
if(play_all.isSelected() && r != tree.getModel().getRoot()){
if(r.getParent() == null) r = null; else r = seqNextSong(r.getParent());
}else{
if(!play_all.isSelected() && !repeat.isSelected()){player.stop(); return null;}
else r = innerNextSong(r.getParent().getChild(0));
}
} else r = ret;
return r;
}
public void nextSong(){
if(tree.getRowCount() == 0){player.stop(); return;}
TreePath p = tree.getSelectionPath(); if(p == null){
if(play_all.isSelected()) p = new TreePath(new Object[]{tree.getModel().getRoot()}); else p = tree.getPathForRow(0);
}
Resource r = WorkspaceBrowser.getResource(p);
if(r.getParent() == null){if(r.getChildCount() == 0){player.stop(); return;} else r = r.getChild(0);}
if(shuffle.isSelected()){
Random rnd = new Random();
if(play_all.isSelected()) r = (Resource)tree.getModel().getRoot();
Resource ret = null;
for(int i=0; i<100; i++){
ret = r.getParent().getChild(rnd.nextInt(r.getParent().getChildCount()));
if(play_all.isSelected()){
while(ret.getChildCount() > 0)
ret = ret.getChild(rnd.nextInt(ret.getChildCount()));
}
if(ret instanceof Media) break;
ret = null;
}
r = ret;
} else r = seqNextSong(r);
if(r != null){
boolean b = player.getClip() == ((Media)r).getClip();
tree.setSelectionPath(new TreePath(WorkspaceBrowser.getPathToRoot(r, tree.getModel().getRoot())));
if(b){player.setFrame(0); player.play();}
} else player.stop();
}
public void playFrame(long f){if(player.getClip() != null && f >= player.getClip().length()-1) nextSong();}
public void actionPerformed(ActionEvent e) {nextSong();}
private static class NextIcon implements Icon {
public int getIconHeight() {return 12;}
public int getIconWidth() {return 12;}
public void paintIcon(Component c, Graphics g, int x, int y) {g.setColor(c.getForeground()); g.fillPolygon(new int[]{x, x+9, x}, new int[]{y, y+6, y+12}, 3); g.fillRect(x+10, y, 2, 12);}
}
}