/* * MainFrame.java * Eisenkraut * * Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved. * * This software is published under the GNU General Public License v3+ * * * For further information, please contact Hanns Holger Rutz at * contact@sciss.de */ package de.sciss.eisenkraut.gui; import de.sciss.app.AbstractApplication; import de.sciss.app.AbstractWindow; import de.sciss.app.Application; import de.sciss.common.AppWindow; import de.sciss.common.BasicApplication; import de.sciss.eisenkraut.Main; import de.sciss.eisenkraut.net.SuperColliderClient; import de.sciss.gui.CoverGrowBox; import de.sciss.gui.LogTextArea; import de.sciss.gui.TreeExpanderButton; import de.sciss.jcollider.Server; import de.sciss.jcollider.ServerEvent; import de.sciss.jcollider.ServerListener; import javax.swing.*; import javax.swing.border.AbstractBorder; import java.awt.*; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.Locale; public class MainFrame extends AppWindow implements de.sciss.jcollider.Constants, ServerListener { protected boolean booted = false; private final ActionBoot actionBoot; private final JLabel lbStatus1; private final JLabel lbStatus2; private final MessageFormat msgStatus1; private final MessageFormat msgStatus2; private final Object[] argsStatus = new Object[ 5 ]; private final String unknownStatus; private final Box boxStatus2; private final SuperColliderClient superCollider; @SuppressWarnings("serial") private class TH extends TransferHandler { TH() { super(); } @Override public boolean canImport(TransferSupport support) { return support.isDataFlavorSupported(DataFlavor.javaFileListFlavor); } @Override public boolean importData(TransferSupport support) { if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { try { java.util.List<?> fs = (java.util.List<?>) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); for (Object f1 : fs) { File f = (File) f1; // System.out.println(f); final Application app = AbstractApplication.getApplication(); ((BasicApplication) app).getMenuFactory().openDocument(f); } return true; } catch (IOException e) { return false; } catch (UnsupportedFlavorException e) { return false; } } else { return false; } } } @SuppressWarnings("serial") private static class DropBorder extends AbstractBorder { private final Color colr; DropBorder(Color colr) { super(); this.colr = colr; } @Override public Insets getBorderInsets(Component c, Insets insets) { insets.top = insets.bottom = 5; insets.left = insets.right = 8; return insets; } private final Stroke strk = new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER, 10.0f, new float[] { 3f, 3f }, 0.0f); @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2 = (Graphics2D) g; g2.setColor(colr); // Color.darkGray); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); g2.setStroke(strk); g2.drawRoundRect(x + 1, y + 1, width - 3, height - 3, 8, 8); } } public MainFrame() { super( REGULAR ); final Application app = AbstractApplication.getApplication(); superCollider = SuperColliderClient.getInstance(); if( app.getWindowHandler().usesInternalFrames() ) { setTitle( app.getResourceString( "frameMain" )); ((JInternalFrame) getWindow()).setClosable( false ); } else { setTitle( app.getName() + " : " + app.getResourceString( "frameMain" )); } final Container cp = getContentPane(); final Box boxStatus1 = Box.createHorizontalBox(); final JPanel bottomPane = new JPanel( new BorderLayout( 4, 2 )); final JScrollPane ggScroll; final AbstractWindow.Listener winListener; final TreeExpanderButton ggStatusExp; // String[] cfgNames = null; final String[] fntNames; LogTextArea lta = new LogTextArea(16, 40, false, null); ggScroll = lta.placeMeInAPane(); lta.makeSystemOutput(); actionBoot = new ActionBoot(); final JButton ggBoot = new JButton(actionBoot); ggBoot.setFocusable(false); // prevent user from accidentally starting/stopping server actionBoot.booted(); final Dimension dBoot1 = ggBoot.getPreferredSize(); actionBoot.terminated(); final Dimension dBoot2 = ggBoot.getPreferredSize(); final ActionDumpOSC actionDumpOSC = new ActionDumpOSC(); final JButton ggDumpOSC = new JButton(actionDumpOSC); ggDumpOSC.setFocusable(false); actionDumpOSC.setState(1); final Dimension dMaxBut = ggDumpOSC.getPreferredSize(); actionDumpOSC.setState(2); final Dimension dDump2 = ggDumpOSC.getPreferredSize(); actionDumpOSC.setState(0); final Dimension dDump3 = ggDumpOSC.getPreferredSize(); dMaxBut.width = Math.max(dMaxBut.width , Math.max(dDump2.width , Math.max(dDump3.width , Math.max(dBoot1.width , dBoot2.width )))); dMaxBut.height = Math.max(dMaxBut.height, Math.max(dDump2.height, Math.max(dDump3.height, Math.max(dBoot1.height, dBoot2.height)))); ggBoot .setPreferredSize(dMaxBut); ggDumpOSC.setPreferredSize(dMaxBut); final boolean isDark = UIManager.getBoolean("dark-skin"); final Color colrDrop = isDark ? Color.gray : Color.darkGray; JLabel ggImport = new JLabel("<html><body><i>Drop</i></body>", null, SwingConstants.CENTER); ggImport.setForeground(colrDrop); ggImport.setTransferHandler(new TH()); ggImport.setToolTipText("Drop audio files here to open them"); ggImport.setBorder(new DropBorder(colrDrop)); Dimension importPref = ggImport.getPreferredSize(); importPref.width = Math.max(importPref.width , 56); importPref.height = Math.max(importPref.height, 20); ggImport.setPreferredSize(importPref); ggImport.setMaximumSize (importPref); boxStatus2 = Box.createHorizontalBox(); msgStatus1 = new MessageFormat( getResourceString( "ptrnServerStatus1" ), Locale.US ); msgStatus2 = new MessageFormat( getResourceString( "ptrnServerStatus2" ), Locale.US ); unknownStatus = getResourceString( "labelServerNotRunning" ); lbStatus1 = new JLabel( unknownStatus ); lbStatus2 = new JLabel(); ggStatusExp = new TreeExpanderButton(); ggStatusExp.setExpandedToolTip( getResourceString( "buttonExpStatsTT" )); ggStatusExp.setCollapsedToolTip( getResourceString( "buttonCollStatsTT" )); ggStatusExp.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { final Dimension d = getSize(); if( ggStatusExp.isExpanded() ) { boxStatus2.setVisible( true ); setSize( new Dimension( d.width, d.height + boxStatus2.getPreferredSize().height + 2 )); } else { boxStatus2.setVisible( false ); setSize( new Dimension( d.width, d.height - (boxStatus2.getPreferredSize().height + 2) )); } } }); lbStatus1.setPreferredSize(new Dimension(192, lbStatus1.getPreferredSize().height)); lbStatus2.setPreferredSize(new Dimension(226, lbStatus1.getPreferredSize().height)); boxStatus1.add(new JLabel(new ImageIcon(getClass().getResource("sc-icon.png")))); boxStatus1.add(Box.createHorizontalStrut(2)); boxStatus1.add(ggStatusExp); boxStatus1.add(lbStatus1); boxStatus1.add(ggBoot); boxStatus1.add(Box.createHorizontalStrut(4)); boxStatus1.add(ggImport); boxStatus1.add(Box.createHorizontalGlue()); boxStatus2.add(lbStatus2); boxStatus2.add(ggDumpOSC); boxStatus2.add(Box.createHorizontalGlue()); boxStatus2.setVisible(false); boxStatus1.add(CoverGrowBox.create()); boxStatus2.add(CoverGrowBox.create()); bottomPane.add(boxStatus1, BorderLayout.NORTH); bottomPane.add(boxStatus2, BorderLayout.SOUTH); bottomPane.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); cp.add(ggScroll, BorderLayout.CENTER); cp.add(bottomPane, BorderLayout.SOUTH); fntNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); final Font fntMonoSpaced; if (contains(fntNames, "DejaVu Sans Mono")) { // Linux fntMonoSpaced = new Font("DejaVu Sans Mono", Font.PLAIN, 10); } else if (contains(fntNames, "Monaco")) { // Mac fntMonoSpaced = new Font("Monaco", Font.PLAIN, 9); // looks bigger than it is } else if (contains(fntNames, "Lucida Sans Unicode")) { // Windows XP fntMonoSpaced = new Font("Lucida Sans Unicode", Font.PLAIN, 9); } else { fntMonoSpaced = new Font("Monospaced", Font.PLAIN, 10); } lbStatus1.setFont(fntMonoSpaced); lbStatus2.setFont(fntMonoSpaced); lta.setFont(fntMonoSpaced); // ---- menus and actions ---- ((BasicApplication) app).getMenuBarRoot().putMimic("edit.clear", this, lta.getClearAction()); // ---- listeners ----- winListener = new AbstractWindow.Adapter() { public void windowClosing(AbstractWindow.Event e) { app.quit(); } }; addListener(winListener); superCollider.addServerListener(this); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); init(); app.addComponent(Main.COMP_MAIN, this); setVisible(true); } protected boolean autoUpdatePrefs() { return true; } protected Point2D getPreferredLocation() { return new Point2D.Float(0f, 0f); } public void dispose() { AbstractApplication.getApplication().removeComponent(Main.COMP_MAIN); super.dispose(); } private static boolean contains(String[] array, String name) { for (String anArray : array) { if (anArray.equals(name)) return true; } return false; } private String getResourceString(String key) { return AbstractApplication.getApplication().getResourceString(key); } private void updateStatus() { final Server.Status s = superCollider.getStatus(); if( s != null ) { argsStatus[0] = (float) s.sampleRate; argsStatus[1] = s.avgCPU; lbStatus1.setText( msgStatus1.format( argsStatus )); if( boxStatus2.isVisible() ) { argsStatus[ 0 ] = s.numUGens; argsStatus[ 1 ] = s.numSynths; argsStatus[ 2 ] = s.numGroups; argsStatus[ 3 ] = s.numSynthDefs; lbStatus2.setText( msgStatus2.format( argsStatus )); } } else { lbStatus1.setText( unknownStatus ); } } // ------------- ServerListener interface ------------- public void serverAction( ServerEvent e ) { switch( e.getID() ) { case ServerEvent.RUNNING: actionBoot.booted(); break; case ServerEvent.STOPPED: actionBoot.terminated(); updateStatus(); break; case ServerEvent.COUNTS: updateStatus(); break; default: break; } } // ------------- internal classes ------------- @SuppressWarnings("serial") private class ActionBoot extends AbstractAction { ActionBoot() { super(); } public void actionPerformed(ActionEvent e) { if (booted) { superCollider.stop(); } else { superCollider.boot(); } } protected void terminated() { booted = false; putValue(NAME, getResourceString("buttonBoot")); } protected void booted() { booted = true; putValue(NAME, getResourceString("buttonTerminate")); } } @SuppressWarnings("serial") private class ActionDumpOSC extends AbstractAction { private int state = 0; private String[] labels = { "labelDumpOff", "labelDumpText", "labelDumpHex" }; public int getState() { return state; } public void setState(int state) { this.state = state; putValue(NAME, getResourceString(labels[state])); } public void actionPerformed(ActionEvent e) { setState((state + 1) % 3); superCollider.dumpOSC(state); } } }