/extensions/org/mt4jx/components/visibleComponents/widgets/MTSuggestionTextArea.java
Java | 428 lines | 222 code | 52 blank | 154 comment | 42 complexity | 47774bae63fd9caa9f38d3db792ab28d MD5 | raw file
1package org.mt4jx.components.visibleComponents.widgets; 2 3import java.util.ArrayList; 4import java.util.List; 5 6import org.mt4j.MTApplication; 7import org.mt4j.components.StateChange; 8import org.mt4j.components.StateChangeEvent; 9import org.mt4j.components.StateChangeListener; 10import org.mt4j.components.TransformSpace; 11import org.mt4j.components.css.style.CSSStyle; 12import org.mt4j.components.visibleComponents.font.IFont; 13import org.mt4j.components.visibleComponents.shapes.MTPolygon; 14import org.mt4j.components.visibleComponents.shapes.MTRectangle; 15import org.mt4j.components.visibleComponents.widgets.MTTextArea; 16import org.mt4j.components.visibleComponents.widgets.keyboard.MTKeyboard; 17import org.mt4j.input.inputProcessors.IGestureEventListener; 18import org.mt4j.input.inputProcessors.MTGestureEvent; 19import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent; 20import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapProcessor; 21import org.mt4j.util.MTColor; 22import org.mt4j.util.math.Tools3D; 23import org.mt4j.util.math.Vector3D; 24import processing.core.PGraphics; 25 26/** 27 * The Class MTSuggestionTextArea. 28 */ 29public class MTSuggestionTextArea extends MTTextArea { 30 31 /** The available suggestions. */ 32 private List<String> availableValues; 33 34 /** The MTApplication. */ 35 private MTApplication app; 36 37 /** The suggestion box. */ 38 private MTTextArea suggestionBox; 39 40 /** The keyboard. */ 41 private MTKeyboard keyboard; 42 43 /** The width. */ 44 private float width = -1f; 45 46 /** The current suggestions. */ 47 private List<String> currentSuggestions = new ArrayList<String>(); 48 49 /** The o (Counting Variable). */ 50 private int o = 0; 51 52 /** The p (Counting Variable). */ 53 private int p = 0; 54 55 /** 56 * Instantiates a new MTSuggestionTextArea. 57 * 58 * @param app 59 * the MTApplication 60 * @param width 61 * the width 62 */ 63 public MTSuggestionTextArea(MTApplication app, float width) { 64 this(app, width, new ArrayList<String>()); 65 } 66 67 /** 68 * Instantiates a new MTSuggestionTextArea. 69 * 70 * @param app 71 * the MTApplication 72 * @param width 73 * the width of the text input box 74 * @param suggestions 75 * the suggestions as List<String> 76 */ 77 public MTSuggestionTextArea(MTApplication app, float width, 78 List<String> suggestions) { 79 // Instantiate with default font, can be changed using CSS 80 super(app); 81 this.init(app, width, suggestions); 82 } 83 84 /** 85 * Instantiates a new MTSuggestionTextArea. 86 * 87 * @param app 88 * the MTApplication 89 * @param font 90 * the font 91 * @param width 92 * the width of the text input box 93 */ 94 public MTSuggestionTextArea(MTApplication app, IFont font, float width) { 95 this(app, font, width, new ArrayList<String>()); 96 } 97 98 /** 99 * Instantiates a new MTSuggestionTextArea. 100 * 101 * @param app 102 * the MTApplication 103 * @param font 104 * the font 105 * @param width 106 * the width of the text input box 107 * @param suggestions 108 * the suggestions as List<String> 109 */ 110 public MTSuggestionTextArea(MTApplication app, IFont font, float width, 111 List<String> suggestions) { 112 super(app, font); 113 this.init(app, width, suggestions); 114 } 115 116 /* 117 * (non-Javadoc) 118 * 119 * @see 120 * org.mt4j.components.visibleComponents.widgets.MTTextArea#drawComponent 121 * (processing.core.PGraphics) 122 */ 123 @Override 124 public void drawComponent(PGraphics g) { 125 super.drawComponent(g); 126 if (keyboard != null) { 127 if (o++ > 30) { 128 o = 0; 129 drawSuggestionBox(); 130 131 } 132 if (p++ > 4) { 133 this.setWidthLocal(width); 134 } 135 } else { 136 if (suggestionBox.isVisible() == true) 137 suggestionBox.setVisible(false); 138 } 139 140 } 141 142 /** 143 * Gets the relevant strings (for the current content of the TextArea). 144 * 145 * @return the relevant strings 146 */ 147 public List<String> getRelevantStrings() { 148 List<String> newList = new ArrayList<String>(); 149 if (!availableValues.isEmpty()) { 150 String currentText = this.getText(); 151 for (String s : availableValues) { 152 if (currentText != "") { 153 if (s.toUpperCase().contains(currentText.toUpperCase())) { 154 newList.add(s.replaceAll("\n", " ")); 155 } 156 } else { 157 newList.add(s.replace("\n", "")); 158 } 159 } 160 } 161 return newList; 162 } 163 164 /** 165 * Style suggestion box. 166 */ 167 public void styleSuggestionBox() { 168 suggestionBox.setNoFill(this.isNoFill()); 169 suggestionBox.setNoStroke(this.isNoStroke()); 170 suggestionBox.setFillColor(this.getFillColor()); 171 suggestionBox.setStrokeColor(new MTColor(this.getStrokeColor().getR(), 172 this.getStrokeColor().getG(), this.getStrokeColor().getG(), 173 this.getStrokeColor().getAlpha() * 0.75f)); 174 suggestionBox.setStrokeWeight(0.25f); 175 } 176 177 /** 178 * Calculate the Coordinates needed for placing the Rectangle. 179 * 180 * @param rect 181 * the Rectangle 182 * @param ta 183 * the TextArea 184 * @param xo 185 * the x-offset 186 * @param yo 187 * the y-offset 188 * @return the position as Vector3D 189 */ 190 private Vector3D calcPos(MTRectangle rect, MTPolygon ta, float xo, float yo) { 191 return new Vector3D((ta.getWidthXY(TransformSpace.LOCAL) / 2) 192 + rect.getVerticesLocal()[0].getX() + xo, 193 (ta.getHeightXY(TransformSpace.LOCAL) / 2) 194 + rect.getVerticesLocal()[0].getY() + yo); 195 } 196 197 /** 198 * Draw suggestion box. 199 */ 200 private void drawSuggestionBox() { 201 String suggestions = ""; 202 int i = 0; 203 List<String> strings = this.getRelevantStrings(); 204 if (strings.size() > 0) { 205 suggestionBox.setVisible(true); 206 currentSuggestions.clear(); 207 for (String s : strings) { 208 if (i != 0 && i < 5) 209 suggestions += "\n"; 210 211 if (i++ < 5) { 212 suggestions += s; 213 currentSuggestions.add(s); 214 } else { 215 break; 216 } 217 218 } 219 suggestionBox.setText(suggestions); 220 suggestionBox.setWidthLocal(width); 221 suggestionBox.setPositionRelativeToParent(calcPos(this, 222 suggestionBox, 0, this.getHeightXY(TransformSpace.LOCAL))); 223 } else { 224 suggestionBox.setVisible(false); 225 } 226 if (keyboard == null) 227 suggestionBox.setVisible(false); 228 } 229 230 /** 231 * Inits the MTSuggestionTextArea 232 * 233 * @param app 234 * the app 235 * @param width 236 * the width 237 * @param suggestions 238 * the suggestions as List<String> 239 */ 240 private void init(MTApplication app, float width, List<String> suggestions) { 241 this.width = width; 242 243 this.availableValues = suggestions; 244 this.app = app; 245 this.setFont(this.getCssHelper().getVirtualStyleSheet().getFont()); 246 this.setWidthLocal(width); 247 248 this.removeAllChildren(); 249 this.removeAllGestureEventListeners(TapProcessor.class); 250 251 // Add Tap listener to evoke Keyboard 252 this.setGestureAllowance(TapProcessor.class, true); 253 this.registerInputProcessor(new TapProcessor(app)); 254 this.addGestureListener(TapProcessor.class, new EditListener(this)); 255 256 // Create Suggestion Box 257 suggestionBox = new MTTextArea(app, this.getFont()); 258 suggestionBox.setWidthLocal(width); 259 suggestionBox.setCssForceDisable(true); 260 styleSuggestionBox(); 261 262 suggestionBox.removeAllGestureEventListeners(); 263 suggestionBox.setGestureAllowance(TapProcessor.class, true); 264 suggestionBox.registerInputProcessor(new TapProcessor(app)); 265 suggestionBox.addGestureListener(TapProcessor.class, 266 new SuggestionBoxListener()); 267 268 this.addChild(suggestionBox); 269 drawSuggestionBox(); 270 } 271 272 public void init() { 273 if (app != null && width != -1f && this.availableValues != null) { 274 init(app, width, this.availableValues); 275 } 276 } 277 278 279 @Override 280 protected void applyStyleSheetCustom(CSSStyle virtualStyleSheet) { 281 super.applyStyleSheetCustom(virtualStyleSheet); 282 this.init(); 283 } 284 285 286 /** 287 * The listener interface for receiving suggestionBox events. The class that 288 * is interested in processing a suggestionBox event implements this 289 * interface, and the object created with that class is registered with a 290 * component using the component's 291 * <code>addSuggestionBoxListener<code> method. When 292 * the suggestionBox event occurs, that object's appropriate 293 * method is invoked. 294 * 295 * @see SuggestionBoxEvent 296 */ 297 public class SuggestionBoxListener implements IGestureEventListener { 298 299 /* 300 * (non-Javadoc) 301 * 302 * @see 303 * org.mt4j.input.inputProcessors.IGestureEventListener#processGestureEvent 304 * (org.mt4j.input.inputProcessors.MTGestureEvent) 305 */ 306 public boolean processGestureEvent(MTGestureEvent ge) { 307 if (ge instanceof TapEvent) { 308 TapEvent te = (TapEvent) ge; 309 if (te.getTapID() == TapEvent.TAPPED) { 310 Vector3D w = Tools3D.project(app, app.getCurrentScene() 311 .getSceneCam(), te.getLocationOnScreen()); 312 Vector3D x = suggestionBox.globalToLocal(w); 313 float zero = suggestionBox.getVerticesLocal()[0].y; 314 float heightPerLine = suggestionBox 315 .getHeightXY(TransformSpace.LOCAL) 316 / (float) (suggestionBox.getLineCount() + 1); 317 int line = (int) ((x.y - zero) / heightPerLine); 318 319 if (currentSuggestions.size() > line) { 320 setText(currentSuggestions.get(line)); 321 } 322 323 } 324 } 325 return false; 326 } 327 328 } 329 330 /** 331 * The listener interface for receiving keyboard events. The class that is 332 * interested in processing a keyboard event implements this interface, and 333 * the object created with that class is registered with a component using 334 * the component's <code>addKeyboardListener<code> method. When 335 * the keyboard event occurs, that object's appropriate 336 * method is invoked. 337 * 338 * @see KeyboardEvent 339 */ 340 public class KeyboardListener implements StateChangeListener { 341 342 /* 343 * (non-Javadoc) 344 * 345 * @see 346 * org.mt4j.components.StateChangeListener#stateChanged(org.mt4j.components 347 * .StateChangeEvent) 348 */ 349 public void stateChanged(StateChangeEvent evt) { 350 if (evt.getState() == StateChange.COMPONENT_DESTROYED) { 351 keyboard = null; 352 } 353 354 } 355 356 } 357 358 /** 359 * The listener interface for receiving edit events. The class that is 360 * interested in processing a edit event implements this interface, and the 361 * object created with that class is registered with a component using the 362 * component's <code>addEditListener<code> method. When 363 * the edit event occurs, that object's appropriate 364 * method is invoked. 365 * 366 * @see EditEvent 367 */ 368 public class EditListener implements IGestureEventListener { 369 370 /** The ta. */ 371 private MTTextArea ta; 372 373 /** 374 * Instantiates a new edits the listener. 375 * 376 * @param ta 377 * the ta 378 */ 379 public EditListener(MTTextArea ta) { 380 this.ta = ta; 381 } 382 383 /* 384 * (non-Javadoc) 385 * 386 * @see 387 * org.mt4j.input.inputProcessors.IGestureEventListener#processGestureEvent 388 * (org.mt4j.input.inputProcessors.MTGestureEvent) 389 */ 390 public boolean processGestureEvent(MTGestureEvent ge) { 391 if (ge instanceof TapEvent) { 392 TapEvent te = (TapEvent) ge; 393 if (te.getTapID() == TapEvent.TAPPED) { 394 System.out.println(ta.getText() + ": " + te.getTapID() + " (" + te.getId() + ")"); 395 if (keyboard == null 396 && te.getTapID() == TapEvent.TAPPED) { 397 keyboard = new MTKeyboard(app); 398 addChild(keyboard); 399 keyboard.addTextInputListener(ta); 400 keyboard.addStateChangeListener( 401 StateChange.COMPONENT_DESTROYED, 402 new KeyboardListener()); 403 404 keyboard.setCssForceDisable(true); 405 406 keyboard.setNoFill(ta.isNoFill()); 407 keyboard.setNoStroke(ta.isNoStroke()); 408 keyboard.setFillColor(ta.getFillColor()); 409 keyboard.setStrokeColor(new MTColor(ta.getStrokeColor().getR(), 410 ta.getStrokeColor().getG(), ta.getStrokeColor().getG(), 411 ta.getStrokeColor().getAlpha() * 0.75f)); 412 keyboard.setStrokeWeight(ta.getStrokeWeight()); 413 414 keyboard.setPositionRelativeToParent(calcPos( 415 ta, 416 keyboard, 417 0, 418 ta.getHeightXY(TransformSpace.LOCAL) 419 + suggestionBox 420 .getHeightXY(TransformSpace.LOCAL))); 421 } 422 } 423 } 424 return false; 425 } 426 427 } 428}