package org.mt4jx.components.visibleComponents.widgets; import java.util.ArrayList; import java.util.List; import org.mt4j.AbstractMTApplication; import org.mt4j.components.StateChange; import org.mt4j.components.StateChangeEvent; import org.mt4j.components.StateChangeListener; import org.mt4j.components.TransformSpace; import org.mt4j.components.css.style.CSSStyle; import org.mt4j.components.visibleComponents.shapes.MTPolygon; import org.mt4j.components.visibleComponents.shapes.MTRectangle; import org.mt4j.components.visibleComponents.widgets.MTTextArea; import org.mt4j.components.visibleComponents.widgets.keyboard.MTKeyboard; import org.mt4j.input.inputProcessors.IGestureEventListener; import org.mt4j.input.inputProcessors.MTGestureEvent; import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent; import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapProcessor; import org.mt4j.util.MTColor; import org.mt4j.util.font.IFont; import org.mt4j.util.math.Tools3D; import org.mt4j.util.math.Vector3D; import processing.core.PGraphics; /** * The Class MTSuggestionTextArea. */ public class MTSuggestionTextArea extends MTTextArea { /** The available suggestions. */ private List<String> availableValues; /** The MTApplication. */ private AbstractMTApplication app; /** The suggestion box. */ private MTTextArea suggestionBox; /** The keyboard. */ private MTKeyboard keyboard; /** The width. */ private float width = -1f; /** The current suggestions. */ private List<String> currentSuggestions = new ArrayList<String>(); /** The o (Counting Variable). */ private int o = 0; /** The p (Counting Variable). */ private int p = 0; /** * Instantiates a new MTSuggestionTextArea. * * @param app * the MTApplication * @param width * the width */ public MTSuggestionTextArea(AbstractMTApplication app, float width) { this(app, width, new ArrayList<String>()); } /** * Instantiates a new MTSuggestionTextArea. * * @param app * the MTApplication * @param width * the width of the text input box * @param suggestions * the suggestions as List<String> */ public MTSuggestionTextArea(AbstractMTApplication app, float width, List<String> suggestions) { // Instantiate with default font, can be changed using CSS super(app); this.init(app, width, suggestions); } /** * Instantiates a new MTSuggestionTextArea. * * @param app * the MTApplication * @param font * the font * @param width * the width of the text input box */ public MTSuggestionTextArea(AbstractMTApplication app, IFont font, float width) { this(app, font, width, new ArrayList<String>()); } /** * Instantiates a new MTSuggestionTextArea. * * @param app * the MTApplication * @param font * the font * @param width * the width of the text input box * @param suggestions * the suggestions as List<String> */ public MTSuggestionTextArea(AbstractMTApplication app, IFont font, float width, List<String> suggestions) { super(app, font); this.init(app, width, suggestions); } /* * (non-Javadoc) * * @see * org.mt4j.components.visibleComponents.widgets.MTTextArea#drawComponent * (processing.core.PGraphics) */ @Override public void drawComponent(PGraphics g) { super.drawComponent(g); if (keyboard != null) { if (o++ > 30) { o = 0; drawSuggestionBox(); } if (p++ > 4) { this.setWidthLocal(width); } } else { if (suggestionBox.isVisible() == true) suggestionBox.setVisible(false); } } /** * Gets the relevant strings (for the current content of the TextArea). * * @return the relevant strings */ public List<String> getRelevantStrings() { List<String> newList = new ArrayList<String>(); if (!availableValues.isEmpty()) { String currentText = this.getText(); for (String s : availableValues) { if (currentText != "") { if (s.toUpperCase().contains(currentText.toUpperCase())) { newList.add(s.replaceAll("\n", " ")); } } else { newList.add(s.replace("\n", "")); } } } return newList; } /** * Style suggestion box. */ public void styleSuggestionBox() { suggestionBox.setNoFill(this.isNoFill()); suggestionBox.setNoStroke(this.isNoStroke()); suggestionBox.setFillColor(this.getFillColor()); suggestionBox.setStrokeColor(new MTColor(this.getStrokeColor().getR(), this.getStrokeColor().getG(), this.getStrokeColor().getG(), this.getStrokeColor().getAlpha() * 0.75f)); suggestionBox.setStrokeWeight(0.25f); } /** * Calculate the Coordinates needed for placing the Rectangle. * * @param rect * the Rectangle * @param ta * the TextArea * @param xo * the x-offset * @param yo * the y-offset * @return the position as Vector3D */ private Vector3D calcPos(MTRectangle rect, MTPolygon ta, float xo, float yo) { return new Vector3D((ta.getWidthXY(TransformSpace.LOCAL) / 2) + rect.getVerticesLocal()[0].getX() + xo, (ta.getHeightXY(TransformSpace.LOCAL) / 2) + rect.getVerticesLocal()[0].getY() + yo); } /** * Draw suggestion box. */ private void drawSuggestionBox() { String suggestions = ""; int i = 0; List<String> strings = this.getRelevantStrings(); if (strings.size() > 0) { suggestionBox.setVisible(true); currentSuggestions.clear(); for (String s : strings) { if (i != 0 && i < 5) suggestions += "\n"; if (i++ < 5) { suggestions += s; currentSuggestions.add(s); } else { break; } } suggestionBox.setText(suggestions); suggestionBox.setWidthLocal(width); suggestionBox.setPositionRelativeToParent(calcPos(this, suggestionBox, 0, this.getHeightXY(TransformSpace.LOCAL))); } else { suggestionBox.setVisible(false); } if (keyboard == null) suggestionBox.setVisible(false); } /** * Inits the MTSuggestionTextArea * * @param app * the app * @param width * the width * @param suggestions * the suggestions as List<String> */ private void init(AbstractMTApplication app, float width, List<String> suggestions) { this.width = width; this.availableValues = suggestions; this.app = app; this.setFont(this.getCssHelper().getVirtualStyleSheet().getFont()); this.setWidthLocal(width); this.removeAllChildren(); this.removeAllGestureEventListeners(TapProcessor.class); // Add Tap listener to evoke Keyboard this.setGestureAllowance(TapProcessor.class, true); this.registerInputProcessor(new TapProcessor(app)); this.addGestureListener(TapProcessor.class, new EditListener(this)); // Create Suggestion Box suggestionBox = new MTTextArea(app, this.getFont()); suggestionBox.setWidthLocal(width); suggestionBox.setCssForceDisable(true); styleSuggestionBox(); suggestionBox.removeAllGestureEventListeners(); suggestionBox.setGestureAllowance(TapProcessor.class, true); suggestionBox.registerInputProcessor(new TapProcessor(app)); suggestionBox.addGestureListener(TapProcessor.class, new SuggestionBoxListener()); this.addChild(suggestionBox); drawSuggestionBox(); } public void init() { if (app != null && width != -1f && this.availableValues != null) { init(app, width, this.availableValues); } } @Override protected void applyStyleSheetCustom(CSSStyle virtualStyleSheet) { super.applyStyleSheetCustom(virtualStyleSheet); this.init(); } /** * The listener interface for receiving suggestionBox events. The class that * is interested in processing a suggestionBox event implements this * interface, and the object created with that class is registered with a * component using the component's * <code>addSuggestionBoxListener<code> method. When * the suggestionBox event occurs, that object's appropriate * method is invoked. * * @see SuggestionBoxEvent */ public class SuggestionBoxListener implements IGestureEventListener { /* * (non-Javadoc) * * @see * org.mt4j.input.inputProcessors.IGestureEventListener#processGestureEvent * (org.mt4j.input.inputProcessors.MTGestureEvent) */ public boolean processGestureEvent(MTGestureEvent ge) { if (ge instanceof TapEvent) { TapEvent te = (TapEvent) ge; if (te.getTapID() == TapEvent.TAPPED) { Vector3D w = Tools3D.project(app, app.getCurrentScene() .getSceneCam(), te.getLocationOnScreen()); Vector3D x = suggestionBox.globalToLocal(w); float zero = suggestionBox.getVerticesLocal()[0].y; float heightPerLine = suggestionBox .getHeightXY(TransformSpace.LOCAL) / (float) (suggestionBox.getLineCount() + 1); int line = (int) ((x.y - zero) / heightPerLine); if (currentSuggestions.size() > line) { setText(currentSuggestions.get(line)); } } } return false; } } /** * The listener interface for receiving keyboard events. The class that is * interested in processing a keyboard event implements this interface, and * the object created with that class is registered with a component using * the component's <code>addKeyboardListener<code> method. When * the keyboard event occurs, that object's appropriate * method is invoked. * * @see KeyboardEvent */ public class KeyboardListener implements StateChangeListener { /* * (non-Javadoc) * * @see * org.mt4j.components.StateChangeListener#stateChanged(org.mt4j.components * .StateChangeEvent) */ public void stateChanged(StateChangeEvent evt) { if (evt.getState() == StateChange.COMPONENT_DESTROYED) { keyboard = null; } } } /** * The listener interface for receiving edit events. The class that is * interested in processing a edit event implements this interface, and the * object created with that class is registered with a component using the * component's <code>addEditListener<code> method. When * the edit event occurs, that object's appropriate * method is invoked. * * @see EditEvent */ public class EditListener implements IGestureEventListener { /** The ta. */ private MTTextArea ta; /** * Instantiates a new edits the listener. * * @param ta * the ta */ public EditListener(MTTextArea ta) { this.ta = ta; } /* * (non-Javadoc) * * @see * org.mt4j.input.inputProcessors.IGestureEventListener#processGestureEvent * (org.mt4j.input.inputProcessors.MTGestureEvent) */ public boolean processGestureEvent(MTGestureEvent ge) { if (ge instanceof TapEvent) { TapEvent te = (TapEvent) ge; if (te.getTapID() == TapEvent.TAPPED) { System.out.println(ta.getText() + ": " + te.getTapID() + " (" + te.getId() + ")"); if (keyboard == null && te.getTapID() == TapEvent.TAPPED) { keyboard = new MTKeyboard(app); addChild(keyboard); keyboard.addTextInputListener(ta); keyboard.addStateChangeListener( StateChange.COMPONENT_DESTROYED, new KeyboardListener()); keyboard.setCssForceDisable(true); keyboard.setNoFill(ta.isNoFill()); keyboard.setNoStroke(ta.isNoStroke()); keyboard.setFillColor(ta.getFillColor()); keyboard.setStrokeColor(new MTColor(ta.getStrokeColor().getR(), ta.getStrokeColor().getG(), ta.getStrokeColor().getG(), ta.getStrokeColor().getAlpha() * 0.75f)); keyboard.setStrokeWeight(ta.getStrokeWeight()); keyboard.setPositionRelativeToParent(calcPos( ta, keyboard, 0, ta.getHeightXY(TransformSpace.LOCAL) + suggestionBox .getHeightXY(TransformSpace.LOCAL))); } } } return false; } } }