/***********************************************************************
* mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* 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 org.mt4j.components.visibleComponents.widgets.keyboard;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import org.mt4j.components.MTComponent;
import org.mt4j.components.StateChange;
import org.mt4j.components.StateChangeEvent;
import org.mt4j.components.StateChangeListener;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.components.visibleComponents.shapes.AbstractShape;
import org.mt4j.components.visibleComponents.widgets.MTTextArea;
import org.mt4j.components.visibleComponents.widgets.MTTextArea.ExpandDirection;
import org.mt4j.components.visibleComponents.widgets.buttons.MTSvgButton;
import org.mt4j.input.gestureAction.DefaultDragAction;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.lassoProcessor.LassoProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.MTColor;
import org.mt4j.util.math.Matrix;
import org.mt4j.util.math.Vector3D;
import processing.core.PApplet;
/**
* A multitouch keyboard with an attached textfield that can be written to.
*
* @author Christopher Ruff
*/
public class MTTextKeyboard extends MTKeyboard {
/** The font for text field. */
private IFont fontForTextField;
/** The parent to add new text area to. */
private MTComponent parentToAddNewTextAreaTo;
/** The clustering gesture analyzer. */
private LassoProcessor lassoProcessor;
//Gesture Actions
/** The default drag action. */
private DefaultDragAction defaultDragAction;
// private DefaultRotateAction defaultRotateAction;
// private DefaultScaleAction defaultScaleAction;
/** The drag from keyb action. */
private DragTextAreaFromKeyboardAction dragFromKeybAction;
/** The pa. */
private PApplet pa;
private ITextInputListener textInputListener;
/**
* Creates a new keyboard with a default font for its textarea.
*
* @param pApplet the applet
*/
public MTTextKeyboard(PApplet pApplet) {
this(pApplet, FontManager.getInstance().createFont(pApplet,
"arial.ttf", 35, new MTColor(0,0,0,255), new MTColor(0,0,0,255)));
// this(pApplet, FontManager.getInstance().createFont(pApplet, "Eureka90.vlw", 35, new Color(0,0,0,255), new Color(0,0,0,255)));
// this(pApplet, FontManager.getInstance().createFont(pApplet, "arial", 35, new Color(0,0,0,255), new Color(0,0,0,255)));
}
/**
* Creates a new keyboard with the specified font for its textarea.
*
* @param pApplet the applet
* @param fontForTextField the font for text field
*/
public MTTextKeyboard(PApplet pApplet, IFont fontForTextField) {
super(pApplet);
this.pa = pApplet;
this.fontForTextField = fontForTextField;
lassoProcessor = null;
//Set up gesture actions
defaultDragAction = new DefaultDragAction();
// defaultRotateAction = new DefaultRotateAction();
// defaultScaleAction = new DefaultScaleAction();
dragFromKeybAction = new DragTextAreaFromKeyboardAction();
MTSvgButton newTextFieldSvg = new MTSvgButton(MT4jSettings.getInstance().getDefaultSVGPath()
+ "keybNewTextField.svg", pa);
newTextFieldSvg.setBoundsPickingBehaviour(AbstractShape.BOUNDS_ONLY_CHECK);
newTextFieldSvg.scale(0.8f, 0.8f, 1, new Vector3D(0,0,0));
newTextFieldSvg.translate(new Vector3D(10,5,0));
newTextFieldSvg.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (arg0.getSource() instanceof MTComponent){
MTComponent clickedComp = (MTComponent)arg0.getSource();
switch (arg0.getID()) {
case TapEvent.BUTTON_CLICKED:
//should always be keyboard
MTComponent parent = clickedComp.getParent();
if (parent instanceof MTTextKeyboard){
MTTextKeyboard keyboard = (MTTextKeyboard)parent;
//Remove old Textfield from keyboard if there is any
if (textInputListener != null){
if (textInputListener instanceof MTTextArea){
MTTextArea ta = (MTTextArea)textInputListener;
ta.setGestureAllowance(DragProcessor.class, true);
ta.setGestureAllowance(RotateProcessor.class, true);
ta.setGestureAllowance(ScaleProcessor.class, true);
ta.setEnableCaret(false);
//Add to clusteranylyzer for clustering the tarea
if (getLassoProcessor() != null){
getLassoProcessor().addClusterable(ta);
}
// keyboard.setTextInputAcceptor(null);
removeTextInputListener(textInputListener);
textInputListener = null;
ta.removeAllGestureEventListeners(DragProcessor.class);
ta.addGestureListener(DragProcessor.class, defaultDragAction);
// ta.unassignGestureClassAndAction(DragGestureAnalyzer.class);
// ta.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);
//The direction, in which the textarea will float off
Vector3D v = new Vector3D(0,-100, 0);
//Add the textarea to the set parent
if (getParentToAddNewTextAreaTo() != null){
//Transform the textarea so it appears at the same world coords after its added to another parent
Matrix m = MTComponent.getTransformToDestinationParentSpace(ta, getParentToAddNewTextAreaTo());
ta.transform(m);
//Transform the direction vector for the translation animation
//to preserve the direction from the old reference frame to the new parents one
// v.transformNormal(m);
v.transformDirectionVector(m);
ta.tweenTranslate(v, 500, 0.3f, 0.7f);
getParentToAddNewTextAreaTo().addChild(ta);
}else{
//If that isnt set, try to add it to the keyboards parent
if (getParent() != null){
/////////////////////////
// Transform the textarea so it appears at the same place after its added to another parent
Matrix m = MTComponent.getTransformToDestinationParentSpace(ta, getParent());
ta.transform(m);
//Transform the direction vector to preserve the global direction
//from the old reference frame to the new parents one
//The translation part has to be removed from the matrix because we're transforming
//a translation vector not a point vector
v.transformDirectionVector(m);
ta.tweenTranslate(v, 500, 0.3f, 0.7f);
/////////////////////
getParent().addChild(ta);
}else{
//do nothing..?
throw new RuntimeException("Dont know where to add text area to!");
}
}
}//if (text instanceof MTTextArea){
}//if (keyboard.getTextInputAcceptor() != null){
//Create a new textarea
keyboard.createNewTextArea();
}//if (parent instanceof MTTextKeyboard){
break;
default:
break;
}
}
}
});
this.addChild(newTextFieldSvg);
}
// @Override
// protected void keyboardButtonDown(MTKey clickedKey, boolean shiftPressed){
// ITextInputAcceptor textArea = getTextInputAcceptor();
// if (textArea != null){
// if (clickedKey.getCharacterToWrite().equals("back")){
// textArea.removeLastCharacter();
// }else if (clickedKey.getCharacterToWrite().equals("shift")){
// //no nothing
// }else{
// String charToAdd = shiftPressed ? clickedKey.getCharacterToWriteShifted() : clickedKey.getCharacterToWrite();
// textArea.appendCharByUnicode(charToAdd);
// }
// }
// }
/**
* Creates a new textarea at the keyboard.
* Fails if there is still one attached to it.
*/
public void createNewTextArea(){
if (this.textInputListener == null){
final MTTextArea t = new MTTextArea(pa, fontForTextField);
this.textInputListener = t;
t.setExpandDirection(ExpandDirection.UP);
t.setStrokeColor(new MTColor(0,0 , 0, 255));
t.setFillColor(new MTColor(205,200,177, 255));
t.setGestureAllowance(DragProcessor.class, true);
t.setGestureAllowance(RotateProcessor.class, false);
t.setGestureAllowance(ScaleProcessor.class, false);
t.removeAllGestureEventListeners(DragProcessor.class);
t.addGestureListener(DragProcessor.class, dragFromKeybAction);
t.setEnableCaret(true);
t.snapToKeyboard(this);
this.addTextInputListener(this.textInputListener);
//Remove textarea from listening if destroyed
t.addStateChangeListener(StateChange.COMPONENT_DESTROYED, new StateChangeListener() {
public void stateChanged(StateChangeEvent evt) {
removeTextInputListener(t);
}
});
}else{
System.err.println("Cant create new textarea - Keyboard still has a textarea attached.");
}
}
/**
* Gets the parent to add new text area to.
*
* @return the parent to add new text area to
*/
public MTComponent getParentToAddNewTextAreaTo() {
return parentToAddNewTextAreaTo;
}
/**
* Determines to which parent the textarea of the keyboard will be added to after
* decoupling it from the keyboard.
*
* @param parentToAddNewTextAreaTo the parent to add new text area to
*/
public void setParentToAddNewTextAreaTo(MTComponent parentToAddNewTextAreaTo) {
this.parentToAddNewTextAreaTo = parentToAddNewTextAreaTo;
}
/**
* Gets the clustering gesture analyzer.
*
* @return the clustering gesture analyzer
*/
public LassoProcessor getLassoProcessor() {
return lassoProcessor;
}
/**
* Sets the clustering gesture analyzer.
*
* @param clusteringGestureAnalyzer the new clustering gesture analyzer
*/
public void setLassoProcessor(LassoProcessor clusteringGestureAnalyzer) {
this.lassoProcessor = clusteringGestureAnalyzer;
}
/**
* Gesture action class to be used when a textarea is dragged away from the keyboard.
*
* @author C.Ruff
*/
private class DragTextAreaFromKeyboardAction extends DefaultDragAction {
/* (non-Javadoc)
* @see com.jMT.input.gestureAction.DefaultDragAction#processGesture(com.jMT.input.inputAnalyzers.GestureEvent)
*/
public boolean processGestureEvent(MTGestureEvent g) {
super.processGestureEvent(g);
if (g.getId() == MTGestureEvent.GESTURE_ENDED){
if (g instanceof DragEvent){
DragEvent dragEvent = (DragEvent)g;
if (dragEvent.getTargetComponent() instanceof MTTextArea){
MTTextArea text = (MTTextArea)dragEvent.getTargetComponent();
//Add default gesture actions to textfield
// text.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);
// text.assignGestureClassAndAction(ScaleGestureAnalyzer.class, defaultScaleAction);
// text.assignGestureClassAndAction(RotateGestureAnalyzer.class, defaultRotateAction);
text.setGestureAllowance(DragProcessor.class, true);
text.setGestureAllowance(RotateProcessor.class, true);
text.setGestureAllowance(ScaleProcessor.class, true);
//Disable caret showing
text.setEnableCaret(false);
//Add to clusteranylyzer for clustering the tarea
if (getLassoProcessor() != null){
getLassoProcessor().addClusterable(text);
}
removeTextInputListener(textInputListener);
textInputListener = null;
text.removeAllGestureEventListeners(DragProcessor.class);
text.addGestureListener(DragProcessor.class, defaultDragAction);
// text.unassignGestureClassAndAction(DragGestureAnalyzer.class);
// text.assignGestureClassAndAction(DragGestureAnalyzer.class, defaultDragAction);
// /*
//Add the textare to the set parent
if (getParentToAddNewTextAreaTo() != null){
text.transform(MTComponent.getTransformToDestinationParentSpace(text, getParentToAddNewTextAreaTo()));
getParentToAddNewTextAreaTo().addChild(text);
}else{
//If that isnt set, try to add it to the keyboards parent
if (getParent() != null){
text.transform(MTComponent.getTransformToDestinationParentSpace(text, getParent()));
getParent().addChild(text);
}else{
//do nothing..
// throw new RuntimeException("Dont know where to add text area to!");
System.err.println("Dont know where to add text area to!");
}
}
// */
}
}
}
return false;
}
}
}