/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad 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 2 of the License, or * (at your option) any later version. * * Nomad 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 Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Created on Jan 21, 2007 */ package net.sf.nmedit.jtheme.component.plaf; import java.awt.Color; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.EventObject; import javax.swing.AbstractAction; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import net.sf.nmedit.jpatch.PParameter; import net.sf.nmedit.jtheme.JTContext; import net.sf.nmedit.jtheme.component.JTComponent; import net.sf.nmedit.jtheme.component.JTControl; import net.sf.nmedit.nmutils.Platform; import net.sf.nmedit.nmutils.swing.NMLazyActionMap; public abstract class JTBasicControlUI extends JTControlUI { protected static final String INCREASE = "increase"; protected static final String DECREASE = "decrease"; protected static final String INCREASE_FAST = "increase.fast"; protected static final String DECREASE_FAST = "decrease.fast"; protected static final String DEFAULTVALUE = "default.value"; protected static final String MOVE_UP = "move.up"; protected static final String MOVE_DOWN = "move.down"; protected static final String MOVE_RIGHT = "move.right"; protected static final String MOVE_LEFT = "move.left"; public static final String knobActionMapKey = "knob.actionMap"; private boolean defaultsInitialized = false; protected static final String CONTROL_LISTENER_CLASS_KEY = JTBasicControlUI.class.getName() +".CONTROL_LISTENER_CLASS"; private JTControl control; public void installUI(JComponent c) { control = (JTControl) c; if (!defaultsInitialized) { initUIDefaults(control.getContext().getUIDefaults()); defaultsInitialized = true; } installDefaults(control); BasicControlListener listener; listener = createControlListener(control); if (listener != null) { installListeners(listener, control); installKeyboardActions(listener, control); } c.setFocusable(true); } protected void initUIDefaults(UIDefaults defaults) { // read the defaults here } public void uninstallUI(JComponent c) { JTControl control = (JTControl) c; uninstallDefaults(control); BasicControlListener listener = getControlListener(c); if (listener != null) { uninstallListeners(listener, control); uninstallKeyboardActions(listener, control); } } protected void installDefaults( JTControl control ) { } protected void uninstallDefaults( JTControl control ) { // no op } private void installListeners( BasicControlListener listener, JTControl c ) { c.addMouseListener(listener); c.addMouseMotionListener(listener); c.addFocusListener(listener); // component repaints itself c.addChangeListener(listener); } private void uninstallListeners( BasicControlListener listener, JTControl c ) { c.removeMouseListener(listener); c.removeMouseMotionListener(listener); c.removeFocusListener(listener); // omponent repaints itself c.removeChangeListener(listener); } private void installKeyboardActions( BasicControlListener listener, JTControl control ) { listener.installKeyboardActions(control); } protected void uninstallKeyboardActions( BasicControlListener listener, JTControl b) { listener.uninstallKeyboardActions(b); } protected Color getExtensionColor(PParameter parameter) { JTContext context = control.getContext(); UIDefaults defaults = (context != null) ? context.getUIDefaults() : null; if (defaults != null) { String colorKey = "morph.color$"+parameter.getMorphGroup(); Color color = defaults.getColor(colorKey); //System.out.println(color.toString()); if (color != null) return color; else return Color.magenta; } else return Color.magenta; //return Helper.getMorphColor(parameter, c); } public void paintStaticLayer(Graphics2D g, JTComponent c) { // no op } public void paintDynamicLayer(Graphics2D g, JTComponent c) { // no op } protected static double getDouble(UIDefaults defaults, String key, double defaultValue) { Object obj = defaults.get(key); if (obj != null) { if (obj instanceof Float) return (Float) obj; if (obj instanceof Double) return (Double) obj; } return defaultValue; } /** * Returns the KnobListener for the passed in Knob, or null if one * could not be found. */ private BasicControlListener getControlListener(JComponent b) { MouseMotionListener[] listeners = b.getMouseMotionListeners(); if (listeners != null) { for (int counter = 0; counter < listeners.length; counter++) { if (listeners[counter] instanceof BasicControlListener) { return (BasicControlListener)listeners[counter]; } } } return null; } protected static final String CONTROL_LISTENER_KEY = JTBasicControlUI.class.getName() +".CONTROL_LISTENER"; private transient BasicControlListener bclInstance; //protected <T extends BasicControlListener > BasicControlListener createControlListener( JTControl control) throws JTException protected BasicControlListener createControlListener( JTControl control) { if (bclInstance != null) return bclInstance; JTContext context = control.getContext(); UIDefaults defaults = (context != null) ? context.getUIDefaults() : null; if (defaults != null) { Object l = defaults.get(CONTROL_LISTENER_KEY); if ((l != null) && (l instanceof BasicControlListener)) { bclInstance = (BasicControlListener) l; } else { bclInstance = new BasicControlListener(); defaults.put(CONTROL_LISTENER_KEY, bclInstance); } } else { bclInstance = new BasicControlListener(); } return bclInstance; } public static class BasicControlListener implements MouseListener, MouseMotionListener, FocusListener { protected double pressedNormalizedValue; protected int pressedModifier; protected boolean selectExtensionAdapter = false; public static void loadActionMap(NMLazyActionMap map) { map.put(new Actions(INCREASE)); map.put(new Actions(DECREASE)); map.put(new Actions(INCREASE_FAST)); map.put(new Actions(DECREASE_FAST)); map.put(new Actions(DEFAULTVALUE)); map.put(new Actions(MOVE_UP)); map.put(new Actions(MOVE_DOWN)); map.put(new Actions(MOVE_RIGHT)); map.put(new Actions(MOVE_LEFT)); } public void mouseClicked( MouseEvent e ) { // no op } protected int getValueModifier(JTControl control, MouseEvent e) { return getValueModifier(control, e.getX(), e.getY()); } private int getValueModifier(JTControl control, int x, int y) { return control.getOrientation() != SwingConstants.VERTICAL ? x : y; } private transient InputMap inputMapWhenFocused ; private int pressedValue; protected InputMap createInputMapWhenFocused() { if (inputMapWhenFocused == null) { inputMapWhenFocused = new InputMap(); fillInputMap(inputMapWhenFocused); } return inputMapWhenFocused; } protected void fillInputMap(InputMap map) { KeyStroke increaseValue = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0); map.put(increaseValue, INCREASE); KeyStroke decreaseValue = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0); map.put(decreaseValue, DECREASE); KeyStroke increaseValueFast = KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_MASK); map.put(increaseValueFast, INCREASE_FAST); KeyStroke decreaseValueFast = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.SHIFT_MASK); map.put(decreaseValueFast, DECREASE_FAST); addEditAction(map); addDefaultValueKS(map); } protected void addEditAction(InputMap map) { KeyStroke moveUp = KeyStroke.getKeyStroke(KeyEvent.VK_U, 0); map.put(moveUp, MOVE_UP); KeyStroke moveDown = KeyStroke.getKeyStroke(KeyEvent.VK_J, 0); map.put(moveDown, MOVE_DOWN); KeyStroke moveRight = KeyStroke.getKeyStroke(KeyEvent.VK_K, 0); map.put(moveRight, MOVE_RIGHT); KeyStroke moveLeft = KeyStroke.getKeyStroke(KeyEvent.VK_H, 0); map.put(moveLeft, MOVE_LEFT); } protected void addDefaultValueKS(InputMap map) { KeyStroke defaultValue = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); map.put(defaultValue, DEFAULTVALUE); } public void installKeyboardActions( JTControl control ) { NMLazyActionMap.installLazyActionMap(control.getContext().getUIDefaults(), control, BasicControlListener.class, knobActionMapKey); InputMap im = createInputMapWhenFocused(); SwingUtilities.replaceUIInputMap(control, JComponent.WHEN_FOCUSED, im); } public void uninstallKeyboardActions(JTControl control) { SwingUtilities.replaceUIInputMap(control, JComponent.WHEN_IN_FOCUSED_WINDOW, null); SwingUtilities.replaceUIInputMap(control, JComponent.WHEN_FOCUSED, null); // TODO this line shouldn't be necessary, but if setUI() was called twice // each time with a new ui instance then the input map will cause a StackOverflowError // if a key was pressed control.setInputMap(JComponent.WHEN_FOCUSED, new InputMap()); SwingUtilities.replaceUIActionMap(control, null); } public boolean isExtensionSelected(MouseEvent e) { if (Platform.isFlavor(Platform.OS.UnixFlavor)) return e.isControlDown(); return e.isAltDown(); } public void mousePressed( MouseEvent e ) { selectExtensionAdapter = false; JTControl control = controlFor(e); if (control == null) return; if (Platform.isPopupTrigger(e)) { control.showControlPopup(e); } else if (Platform.isLeftMouseButtonOnly(e)) { selectExtensionAdapter = isExtensionSelected(e); pressedNormalizedValue = selectExtensionAdapter ? control.getExtNormalizedValue() : control.getNormalizedValue(); pressedValue = control.getValue(); pressedModifier = getValueModifier(control, e); } if (!control.hasFocus()) control.requestFocus(); } public void mouseReleased( MouseEvent e ) { JTControl control = controlFor(e); if (control.getControlAdapter() != null) { PParameter parameter = control.getControlAdapter().getParameter(); int newValue = control.getValue(); if (newValue != pressedValue && parameter.isUndoableEditSupportEnabled()) { parameter.postEdit(parameter.createParameterValueEdit(pressedValue, newValue)); } } if (Platform.isPopupTrigger(e)) { control.showControlPopup(e); } else if (e.getClickCount()>=2 && control != null) { if (selectExtensionAdapter) control.setExtensionValue(control.getExtDefaultValue()); else control.setValue(control.getDefaultValue()); } } public void mouseEntered( MouseEvent e ) { // no op } public void mouseExited( MouseEvent e ) { // no op } public void mouseDragged( MouseEvent e ) { JTControl control = controlFor(e); if (Platform.isLeftMouseButtonOnly(e) && control != null) { int currentModifier = getValueModifier(control, e); try { control.getControlAdapter().getParameter().disableUndo(); if (control.getOrientation()!=SwingConstants.VERTICAL) updateValue(control, currentModifier, pressedModifier, pressedNormalizedValue); else // horizontal updateValue(control, pressedModifier, currentModifier, pressedNormalizedValue); } finally { control.getControlAdapter().getParameter().enableUndo(); } } } public void updateValue(JTControl control, double currentModifier, double pressedModifier, double pressedValue) { double modifier = (currentModifier-pressedModifier)/128d; // assure value in range [0..1] double nvalue = Math.max(0, Math.min(pressedValue+modifier, 1)); if (selectExtensionAdapter) { control.setExtNormalizedValue(nvalue); } else { control.setNormalizedValue(nvalue); } } public void mouseMoved( MouseEvent e ) { // no op } public void focusGained( FocusEvent e ) { e.getComponent().repaint(); } public void focusLost( FocusEvent e ) { e.getComponent().repaint(); } public static class Actions extends AbstractAction { // private String action; /** * */ private static final long serialVersionUID = -2104045982638755995L; public Actions(String name) { super(name); } public String getName() { return (String) super.getValue(NAME); } public void actionPerformed(ActionEvent e) { JTControl control = (JTControl) e.getSource(); String key = getName(); if (key == INCREASE) control.setValue(control.getValue()+1); else if (key == DECREASE) control.setValue(control.getValue()-1); else if (key == INCREASE_FAST) control.setValue(control.getValue()+5); else if (key == DECREASE_FAST) control.setValue(control.getValue()-5); else if (key == DEFAULTVALUE) control.setValue(control.getDefaultValue()); // else if (key == MOVE_UP){ // Element docEl = control.getDocumentElement(); // Integer y = control.getLocation().y -1; // control.setLocation(control.getLocation().x, y); // docEl.setAttribute("y",y.toString()); // } // else if (key == MOVE_DOWN){ // Element docEl = control.getDocumentElement(); // Integer y = control.getLocation().y + 1; // control.setLocation(control.getLocation().x, y); // docEl.setAttribute("y",y.toString()); // } // else if (key == MOVE_RIGHT){ // Element docEl = control.getDocumentElement(); // Integer x = control.getLocation().x +1; // control.setLocation(x,control.getLocation().y); // docEl.setAttribute("x",x.toString()); // } // else if (key == MOVE_LEFT){ // Element docEl = control.getDocumentElement(); // Integer x = control.getLocation().x -1; // control.setLocation(x,control.getLocation().y); // docEl.setAttribute("x",x.toString()); // } } public boolean isEnabled(Object sender) { if (sender != null && (sender instanceof JTControl) && !((JTControl)sender).isEnabled()) { return false; } else { return true; } } } /* public void stateChanged(ChangeEvent e) { JTControl c = controlFor(e); if (c != null) c.repaint(); } */ protected JTControl controlFor(EventObject e) { return castControl(e.getSource()); } private JTControl castControl(Object src) { return (src instanceof JTControl) ? (JTControl) src : null; } /* // should be in UIDefaults public static final int MOUSE_WHEEL_INCREMENT = 2; public void mouseWheelMoved(MouseWheelEvent e) { int rotation = e.getWheelRotation() * MOUSE_WHEEL_INCREMENT; int newvalue = control.getValue()-rotation; newvalue = Math.max(control.getMinValue(), Math.min(newvalue, control.getMaxValue())); control.setValue(newvalue); } */ } }