/extensions/org/mt4jx/components/visibleComponents/widgets/MTSuggestionTextArea.java

http://mt4j.googlecode.com/ · Java · 428 lines · 222 code · 52 blank · 154 comment · 42 complexity · 47774bae63fd9caa9f38d3db792ab28d MD5 · raw file

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