/* * Copyright (C) 2008-2009, Uwe Schmidt * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * The Software uses a third-party library (WiiRemoteJ) which is not part of * the Software and is subject to its own license. */ package org.uweschmidt.wiimote.whiteboard.gui; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Point; import java.awt.SystemColor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.util.Map; import java.util.logging.Level; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JSeparator; import javax.swing.SwingConstants; import net.miginfocom.swing.MigLayout; import org.jdesktop.application.Action; import org.jdesktop.application.Application; import org.jdesktop.application.ResourceMap; import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler; import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard; import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener; import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration; import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent; import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener; import org.uweschmidt.wiimote.whiteboard.ds.IRDot; import org.uweschmidt.wiimote.whiteboard.ds.Wiimote; import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences; import org.uweschmidt.wiimote.whiteboard.util.Util; @SuppressWarnings("serial") public class MainPanel extends JPanel implements WiimoteDataListener, CalibrationEventListener { private static final ImageIcon CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/ok.png")); private static final ImageIcon NOT_CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/warning.png")); private static final WWPreferences prefs = WWPreferences.getPreferences(); private DotLabel[] dotLabel = new DotLabel[4]; private JProgressBar[] batteryLevel = new JProgressBar[WWPreferences.WIIMOTES]; private JButton[] resetButton = new JButton[WWPreferences.WIIMOTES]; private WiimoteIcon[] wiimoteIcon = new WiimoteIcon[WWPreferences.WIIMOTES]; private JLabel[] statusLabel = new JLabel[WWPreferences.WIIMOTES]; private JCheckBox cursorControl; private JRadioButton moveMouse, leftClick; private JButton calibrationButton, cameraButton /*,warpedButton, calibrationInfoButton*/; private ScreenSelector screenSelector; private boolean notifiedLowBattery = false; // private boolean donePack = false; private Wiimote[] wiimotes = new Wiimote[WWPreferences.WIIMOTES]; private WiimoteDataHandler dh; private WiimoteCalibration calibration; private ResourceMap r = Util.getResourceMap(MainPanel.class); public MainPanel(WiimoteDataHandler dh, WiimoteCalibration calibration) { this.dh = dh; this.calibration = calibration; dh.addWiimoteDataListener(this); calibration.addCalibrationEventListener(this); createComponents(); getValues(); update(); } public void getValues() { cursorControl.setSelected(dh.isCursorControl()); // rightClick.setSelected(prefs.isRightClick()); leftClick.setSelected(prefs.isLeftClick()); moveMouse.setSelected(!prefs.isLeftClick()); } public void calibrationEvent(CalibrationEvent e) { switch (e) { case FINISHED: case LOADED: cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); case STARTED: case SCREEN_CHANGED: case ABORTED: update(); break; } } public void batteryLevel(Wiimote wiimote, double level) { batteryLevel[wiimote.getId()-1].setValue((int) Math.round(level * 100)); batteryLevel[wiimote.getId()-1].setString(r.getString("batteryLevel", level * 100)); if (!notifiedLowBattery && prefs.isLowBatteryWarning() && dh.isConnected(wiimote) && level <= .05) { notifiedLowBattery = true; WiimoteWhiteboard.getLogger().log(Level.WARNING, r.getString("lowBattery")); new Thread(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, r.getString("lowBattery"), WiimoteWhiteboard.getProperty("id"), JOptionPane.WARNING_MESSAGE); } }).start(); } } public void irLights(Wiimote wiimote, IRDot[] lights) { for (int i = 0; i < lights.length; i++) { dotLabel[i].update(wiimote, lights[i] != null); } } public void irWarped(Map data, Point[] warped) { } public void wiimoteConnected(Wiimote wiimote) { wiimotes[wiimote.getId()-1] = wiimote; if (wiimote.getId() > 1) { for (int i = 0; i < wiimote.getId(); i++) { wiimoteIcon[i].setVisible(true); } } statusLabel[wiimote.getId()-1].setVisible(true); // Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); batteryLevel[wiimote.getId()-1].setVisible(true); resetButton[wiimote.getId()-1].setVisible(true); cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION); update(); } public void wiimoteDisconnected(Wiimote wiimote) { if (wiimote.getId() != 1) batteryLevel[wiimote.getId()-1].setVisible(false); if (wiimote.getId() != 1) wiimoteIcon[wiimote.getId()-1].setVisible(false); if (wiimote.getId() != 1) resetButton[wiimote.getId()-1].setVisible(false); if (wiimote.getId() != 1) statusLabel[wiimote.getId()-1].setVisible(false); update(); // Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); // WiimoteWhiteboard.getLogger().log(Level.SEVERE, r.getString("disconnected", id)); JOptionPane.showMessageDialog(null, r.getString("disconnected", wiimote.getId()), WiimoteWhiteboard.getProperty("id"), JOptionPane.ERROR_MESSAGE); Application.getInstance(WiimoteWhiteboard.class).exit(); } /* * UPDATE UI WIDGETS */ @Action public void update() { calibrationButton.setEnabled(dh.isConnected()); for (int i = 0; i < WWPreferences.WIIMOTES; i++) { resetButton[i].setEnabled(dh.isConnected(wiimotes[i])); wiimoteIcon[i].displayConnected(dh.isConnected(wiimotes[i])); if (dh.isConnected(wiimotes[i])) { boolean calibrated = calibration.isCalibrated(wiimotes[i]); statusLabel[i].setText(r.getString(calibrated ? "calibrated" : "notCalibrated")); statusLabel[i].setIcon(calibrated ? CALIBRATED : NOT_CALIBRATED); } } cameraButton.setEnabled(dh.isConnected()); // warpedButton.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes())); screenSelector.setEnabled(dh.isConnected() && !calibration.inProgress()); if (!dh.isConnected()) { batteryLevel[0].setString(r.getString("searching")); batteryLevel[0].setValue(0); batteryLevel[0].setToolTipText(Util.getResourceMap(MainPanel.class).getString("batteryLevelBar.toolTipText")); } else { batteryLevel[0].setToolTipText(null); } cursorControl.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes())); if (!cursorControl.isEnabled()) cursorControl.setSelected(false); moveMouse.setEnabled(cursorControl.isSelected()); leftClick.setEnabled(cursorControl.isSelected()); // rightClick.setEnabled(cursorControl.isSelected() && leftClick.isSelected()); dh.setCursorControl(cursorControl.isSelected()); prefs.setLeftClick(leftClick.isSelected()); // prefs.setRightClick(/*rightClick.isEnabled() && */rightClick.isSelected()); } /* * MAIN PANEL */ private void createComponents() { setLayout(new MigLayout("nocache, hidemode 3, gap 0", "[fill]")); addHeadline(r.getString("wiimoteHeadline"), false); for (int i = 0; i < WWPreferences.WIIMOTES; i++) { add(wiimoteIcon[i] = new WiimoteIcon(i+1), "split"); if (i > 0) wiimoteIcon[i].setVisible(false); } for (int i = 0; i < WWPreferences.WIIMOTES; i++) { add(batteryLevel[i] = Util.newComponent(JProgressBar.class, "batteryLevelBar"), (i == 0 ? "newline related/2, " : "") + "split"); if (i > 0) batteryLevel[i].setVisible(false); } for (int i = 0; i < WWPreferences.WIIMOTES; i++) { add(statusLabel[i] = Util.newComponent(JLabel.class, "statusLabel"), (i == 0 ? "newline related/2, split, " : "") + "sg, h 16!, center"); statusLabel[i].setFont(statusLabel[i].getFont().deriveFont(10f)); if (i > 0) statusLabel[i].setVisible(false); } String gap = Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "0" : "related/2"; for (int i = 0; i < WWPreferences.WIIMOTES; i++) { final int j = i; add(resetButton[i] = Util.newComponent(JButton.class, "resetCameraButton"), (i == 0 ? "newline "+gap+", split, " : "") + ""); resetButton[i].putClientProperty("JButton.buttonType", "textured"); resetButton[i].putClientProperty("JComponent.sizeVariant", "small"); resetButton[i].addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { dh.enableIR(wiimotes[j]); } catch (Exception e1) { e1.printStackTrace(); } } }); if (i > 0) resetButton[i].setVisible(false); } add(new JSeparator(), String.format("newline %s, span, growx, wrap related", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "related/3" : "related")); add(Util.newComponent(JLabel.class, "visibleDotsLabel"), "split" + (Util.MAC_OS_X ? ", gapleft 4" : "")); add(dotLabel[0] = new DotLabel("1"), "w 18, h 18"); add(dotLabel[1] = new DotLabel("2"), "w 18, h 18"); add(dotLabel[2] = new DotLabel("3"), "w 18, h 18"); add(dotLabel[3] = new DotLabel("4"), "w 18, h 18, wrap related" + (Util.MAC_OS_X ? ", gapright 4" : "")); add(cameraButton = new JButton(Util.getAction(new CameraMonitor(dh), "monitor")), ""); cameraButton.putClientProperty("JButton.buttonType", "textured"); // CALIBRATION addHeadline(r.getString("calibrationHeadline")); // add(warpedButton = new JButton(SC.getAction(new WarpedMonitor(dh, calibration), "monitor")), "wrap"); final JButton infoButton = new JButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info")); // final JToggleButton infoButton = new JToggleButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info")); infoButton.putClientProperty("JButton.buttonType", "textured"); infoButton.putClientProperty("JComponent.sizeVariant", "small"); add(infoButton, "wrap related"); // add(new JSeparator(), "span, growx, wrap"); add(screenSelector = new ScreenSelector(calibration, dh), "align center, grow 0, wrap related"); add(calibrationButton = Util.newComponent(JButton.class, "calibrationButton"), ""); calibrationButton.putClientProperty("JButton.buttonType", "textured"); calibrationButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { calibration.start(dh.getConnectedWiimotes()); } }); // MOUSE CONTROL addHeadline(r.getString("mouseControlHeadline")); add(cursorControl = Util.newComponent(JCheckBox.class, "cursorControl"), "wrap related"); add(moveMouse = Util.newComponent(JRadioButton.class, "moveMouse"), "pad 0 20 0 0, wmin pref+20, wrap related"); add(leftClick = Util.newComponent(JRadioButton.class, "leftClick"), "pad 0 20 0 0, wmin pref+20, wrap"); // add(rightClick = SC.newComponent(JCheckBox.class, "rightClick"), "pad 0 20 0 0, wrap"); // add(new JSeparator(), "wrap"); // final JButton exitButton = new JButton(SC.getAction(Application.getInstance(), "quitApp")); // add(exitButton, "wrap"); ButtonGroup group = new ButtonGroup(); group.add(moveMouse); group.add(leftClick); cursorControl.addActionListener(Util.getAction(this, "update")); moveMouse.addActionListener(Util.getAction(this, "update")); leftClick.addActionListener(Util.getAction(this, "update")); // rightClick.addActionListener(SC.getAction(this, "update")); // fixes issue that components stay grayed out although they're enabled // (mac os x), only happens when mainFrame doesn't have focus on connect // workaround for windows: pack() once frame gains focus, due to // incorrect height apparently caused by non-resizability Application.getInstance(WiimoteWhiteboard.class).getMainFrame().addWindowFocusListener(new WindowFocusListener() { public void windowGainedFocus(WindowEvent e) { updateUI(); // if (!Util.MAC_OS_X && !donePack) { // donePack = true; // Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack(); // } } public void windowLostFocus(WindowEvent e) {} }); Util.getResourceMap(MainPanel.class).injectComponents(this); } private JLabel addHeadline(String name) { return addHeadline(name, true); } private JLabel addHeadline(String name, boolean newline) { final JLabel label = new JLabel(name); label.setFont(label.getFont().deriveFont(Font.BOLD, 18f)); add(label, (newline ? "newline unrelated, " : "") + "split, span"); add(new JSeparator(), "growx, wrap related"); return label; } private class DotLabel extends JLabel { private boolean[] state = new boolean[WWPreferences.WIIMOTES]; public DotLabel(String name) { setText(name); setHorizontalAlignment(SwingConstants.CENTER); setBorder(BorderFactory.createLineBorder(Color.lightGray)); } public void update(Wiimote wiimote, boolean state) { if (this.state[wiimote.getId() - 1] != state) { this.state[wiimote.getId() - 1] = state; repaint(); } } @Override protected void paintComponent(Graphics g) { final int n = Math.max(1, dh.getNumberOfConnectedWiimotes()); for (int i = 1; i <= n; i++) { g.setColor(state[i-1] ? WiimoteIcon.COLORS[i-1] : SystemColor.textInactiveText); g.fillRect(0, (i-1)*this.getHeight()/n, this.getWidth(), this.getHeight()/n); // g.fillRect((i-1)*this.getWidth()/n, 0, this.getWidth()/n, this.getHeight()); } super.paintComponent(g); } } }