001package org.vishia.gral.base; 002 003 004import java.util.Map; 005 006import org.vishia.gral.ifc.GralColor; 007import org.vishia.gral.ifc.GralFont; 008import org.vishia.gral.ifc.GralRectangle; 009import org.vishia.gral.ifc.GralTextFieldUser_ifc; 010import org.vishia.gral.ifc.GralUserAction; 011import org.vishia.gral.ifc.GralTextField_ifc; 012import org.vishia.gral.ifc.GralWidget_ifc; 013import org.vishia.util.CalculatorExpr; 014import org.vishia.util.DataAccess; 015import org.vishia.util.Removeable; 016import org.vishia.util.StringFunctions; 017 018/**This is the base class for all widgets which represents a simple text. 019 * @author Hartmut Schorrig 020 * 021 */ 022public class GralTextField extends GralWidget implements GralTextField_ifc 023{ 024 /**Version, history and license . 025 * <ul> 026 * <li>2015-05-04 Hartmut new: {@link #setBorderWidth(int)} to show the text field with a border. 027 * <li>2015-05-04 Hartmut chg: {@link #setLongValue(long)} is more complexly, a calculation can result in a float value. Fixed. 028 * <li>2015-05-02 Hartmut chg: Calculation of the {@link GraphicImplAccess#posPrompt} and ...posField is processed 029 * in this class commonly for SWT and AWT implementation. 030 * <li>2014-02-10 Hartmut chg: Constructor with Parameter {@link Type}, supports password field. 031 * <li>2013-12-22 Hartmut chg: Now {@link GralTextField} uses the new concept of instantiation: It is not 032 * the super class of the implementation class. But it provides {@link GralTextField.GraphicImplAccess} 033 * as the super class. 034 * <li>2013-03-13 Hartmut new {@link #setText(CharSequence, int)}: supports {@link GralWidget_ifc#isNotEditableOrShouldInitialize()} to support 035 * edit field handling. 036 * <li>2013-03-04 Hartmut chg: The {@link #setText(CharSequence, int)} overwriting concept is faulty. 037 * Because an accidentally change of text prevents setting the correct text. Check of {@link #bTextChg} 038 * removed. The preventing of overwriting an edit field should be prevented outside as condition of 039 * call of {@link #setText(CharSequence)}. 040 * <li>2013-02-22 GralTextField: edit field now works with GralShowMethods syncVariableOnFocus, 041 * {@link #bTextChg} detects whether any input is taken. {@link #isChanged(boolean)} returns this information 042 * and resets {@link #bTextChg}. {@link #setText(CharSequence, int)} only sets if the text is unchanged. 043 * Therefore a changed text won't be over-written by an setText(). 044 * <li>2012-09-24 Hartmut new: {@link #setValue(double)} and {@link #setValue(Object[])} for double values. 045 * <li>2012-04-17 Hartmut new: {@link #sFormat2} etc: Now format "int16AngleDegree" etc. are recognized 046 * as special format. Improved calling {@link #calculator} in {@link #setValue(float)}. 047 * <li>2012-04-16 Hartmut new: {@link #isChanged()}, {@link #setUser(GralTextFieldUser_ifc)} 048 * <li>2012-04-01 Hartmut new: {@link #setValue(float)} now supports formatting view. 049 * This algorithm was used for the {@link org.vishia.guiInspc.InspcGui} before. 050 * <li>2011-11-18 Hartmut new {@link #setMouseAction(GralUserAction)}. This method should be 051 * an abstract method of all {@link GralWidget} but it is used yet only here. 052 * <li>2011-09-00 Hartmut Creation to build a platform-indenpenden representation of text field. 053 * </ul> 054 * 055 * <b>Copyright/Copyleft</b>: 056 * For this source the LGPL Lesser General Public License, 057 * published by the Free Software Foundation is valid. 058 * It means: 059 * <ol> 060 * <li> You can use this source without any restriction for any desired purpose. 061 * <li> You can redistribute copies of this source to everybody. 062 * <li> Every user of this source, also the user of redistribute copies 063 * with or without payment, must accept this license for further using. 064 * <li> But the LPGL ist not appropriate for a whole software product, 065 * if this source is only a part of them. It means, the user 066 * must publish this part of source, 067 * but don't need to publish the whole source of the own product. 068 * <li> You can study and modify (improve) this source 069 * for own using or for redistribution, but you have to license the 070 * modified sources likewise under this LGPL Lesser General Public License. 071 * You mustn't delete this Copyright/Copyleft inscription in this source file. 072 * </ol> 073 * If you are intent to use this sources without publishing its usage, you can get 074 * a second license subscribing a special contract with the author. 075 * 076 * @author Hartmut Schorrig = hartmut.schorrig@vishia.de 077 */ 078 //@SuppressWarnings("hiding") 079 public static final String version = "2015-09-12"; 080 081 082 public enum Type{ password, editable}; 083 084 protected int caretPos; 085 086 /**The width of an extra border arround the text field to mark it. 087 * 0: initially, no border. Note: The color of the border is the {@link GralWidget.DynamicData#lineColor} 088 */ 089 protected int borderwidth; 090 091 /**The prompt to the text field. */ 092 protected String sPrompt, sPromptStylePosition; 093 094 //protected GralColor colorBack = GralColor.getColor("wh"), colorText = GralColor.getColor("bk"); 095 096 //protected GralFont fontText; 097 098 /**A calculator to show calculated float values. It is null if it isn't used. */ 099 private CalculatorExpr calculator; 100 101 private String sFormat2; 102 103 protected GralTextFieldUser_ifc user; 104 105 /**It is used for some operations. */ 106 protected final GralGraphicThread windowMng; 107 108 final boolean bPassword; 109 110 /**Constructs a text field with given properties 111 * @param posName Position and Name of the field. Maybe null if it is not need in management by name 112 * See {@link GralWidget#GralWidget(String, char)}. 113 * @param property password, editable, maybe left empty. 114 */ 115 public GralTextField(String posName, Type... property){ 116 super(posName, 't'); 117 boolean bPassword1 = false; 118 if(property !=null){ 119 for(int ii=0; ii<property.length; ++ii){ 120 switch(property[ii]){ 121 case password: bPassword1 = true; break; 122 case editable: setEditable(true); 123 } 124 } 125 } 126 bPassword = bPassword1; 127 windowMng = null; 128 setBackColor(GralColor.getColor("wh"),0); 129 setTextColor(GralColor.getColor("bk")); 130 } 131 132 /**Constructs a text field with given properties 133 * @param name Name of the field. Maybe null if it is not need in management by name 134 * @param property password, editable, maybe left empty. 135 * @deprecated since 2016-09,use {@link GralTextField#GralTextField(String, Type...)} with "@pos=name" 136 */ 137 public GralTextField(String pos, String name, Type... property){ 138 this(pos !=null ? (pos.startsWith("@") ? "" : "@" + pos + "=" + name) : name, property); 139 } 140 141 142 @Deprecated public GralTextField(String name, char whatis, GralMng mng){ 143 super(name, whatis, mng); 144 bPassword = false; 145 setBackColor(GralColor.getColor("wh"),0); 146 setTextColor(GralColor.getColor("bk")); 147 this.windowMng = mng.gralDevice; 148 } 149 150 151 152 public void setPrompt(String sPrompt){ 153 this.sPrompt = sPrompt; 154 if(_wdgImpl !=null){ 155 dyda.setChanged(GraphicImplAccess.chgPrompt); 156 repaint(); 157 } else { 158 this.sPromptStylePosition = "t"; 159 } 160 } 161 162 163 public void setPrompt(String sPrompt, String sPromptPos){ 164 this.sPrompt = sPrompt; 165 this.sPromptStylePosition = sPromptPos; 166 if(_wdgImpl !=null){ 167 throw new IllegalStateException("setPrompt(prompt, style) can only applied on creation, use setPrompt(text) to change the prompt."); 168 } 169 } 170 171 172 public void setUser(GralTextFieldUser_ifc user){ 173 this.user = user; 174 } 175 176 177 178 @Override public void setFormat(String sFormat){ 179 super.setFormat(sFormat); 180 calculator = null; //set it on first usage. 181 sFormat2 = null; 182 } 183 184 185 186 187 /**Sets a float value into a text field. 188 * The float value may be calculated and formatted: 189 * <ul> 190 * <li>If the {@link #setFormat(String)} of this widget starts with '!' and contains a second '!', 191 * the String between that is used as expression to calculate the float value 192 * using {@link CalculatorExpr}. Therewith any calculation can be done. 193 * <li>The rest after the "!expression!" or the given format is used for String.format(sFormat, value) 194 * to determine the output appearance. 195 * <li>If no format is given, the value will be shown in proper readable appearance. That assures 196 * that the value is able to present in a short text field, using maximal 9 digits. 197 * <li>If no format is given and the absolute of the value is less 0.000001 but not 0, 198 * a "0.000001" with the correct sign will be shown. It shows, there is a less value, but not null. 199 * <li>If no format is given and the value is in range up to 1 Billion, it is shown with "k", "M" 200 * for kilo and Mega with max 3 digits before dot and 3 digits after the dot. 201 * <li>if no format is given and the value is greater than 1 Billion, it is shown with exponent. 202 * <ul> 203 * 204 * @see org.vishia.gral.base.GralWidget#setValue(float) 205 */ 206 @Override public void setValue(final float valueP){ 207 final String sFormat1; 208 float value; 209 String sShow; 210 if(calculator !=null){ 211 try { 212 CalculatorExpr.Value value1 = calculator.calcDataAccess(null, valueP); 213 value = value1.floatValue(); 214 } catch (Exception e) { 215 value = 7777777.777f; 216 } 217 sFormat1 = this.sFormat2; 218 } else if(sFormat !=null){ 219 if(sFormat.startsWith("!")){ 220 final String sFormat3; 221 if(sFormat.startsWith("!16hi!") || sFormat.startsWith("!16lo!")) { 222 sFormat3 = sFormat.substring(5); //from ! 223 } else { 224 sFormat3 = this.sFormat; 225 } 226 int posEnd = sFormat3.indexOf('!',1); 227 if(posEnd >=0){ 228 String sExpr = sFormat3.substring(1, posEnd); 229 this.sFormat2 = sFormat1 = sFormat3.substring(posEnd+1); 230 if(calculator ==null){ 231 calculator = new CalculatorExpr(); 232 String sError = calculator.setExpr(sExpr); 233 if(sError !=null){ 234 //console.writeError(sError); 235 calculator = null; 236 } 237 } 238 if(calculator !=null){ 239 value = calculator.calc(valueP); 240 } else { 241 value = valueP; 242 } 243 } else { 244 sFormat1 = sFormat; 245 value = valueP; 246 } 247 } else if(sFormat.startsWith("int16AngleDegree")){ 248 this.calculator = new CalculatorAngle16(); 249 sFormat1 = this.sFormat2 = "%3.3f"; 250 value = calculator.calc(valueP); 251 } else if(sFormat.startsWith("int32AngleDegree")){ 252 this.calculator = new CalculatorAngle32(); 253 sFormat1 = this.sFormat2 = "%3.3f"; 254 value = calculator.calc(valueP); 255 } else { 256 sFormat1 = sFormat; 257 value = valueP; 258 } 259 260 } else { //sFormat == null 261 sFormat1 = null; //no expression 262 value = valueP; 263 } 264 if(sFormat1 !=null && sFormat.length() >0){ 265 try{ sShow = String.format(sFormat1, new Float(value)); } 266 catch(java.util.IllegalFormatException exc){ 267 sShow = null; //maybe integer 268 } 269 if(sShow == null){ 270 long value1; 271 if(sFormat.startsWith("+")){ 272 if(value <0){ 273 value1 = (long)(((int)value) + 0x80000000L); 274 } else { 275 value1 = (int)value; 276 } 277 //if(value1 <0) { value1 += 0x8000000000000000L; } 278 } else { 279 value1 = (int)value; 280 } 281 try{ sShow = String.format(sFormat, new Long(value1)); } 282 catch(java.util.IllegalFormatException exc){ 283 sShow = "?format"; 284 } 285 } 286 } else { //no format given 287 float valueAbs = Math.abs(value); 288 if(value == 0.0f){ sShow = "0.0"; } 289 else if(valueAbs < 1.0e-7f){ sShow = value < 0 ? "-0.0000001" : "0.0000001"; } //shorten output, don't show exponent. 290 else if(valueAbs < 1.0f){ sShow = String.format("%1.7f", new Float(value)); } //shorten output, don't show exponent. 291 else if(valueAbs < 1.0e3f){ sShow = String.format("%3.4f", new Float(value)); } //shorten output, don't show exponent. 292 else if(valueAbs < 1.0e6f){ sShow = String.format("%3.3f k", new Float(value/1000)); } //shorten output, don't show exponent. 293 else if(valueAbs < 1.0e9f){ sShow = String.format("%3.3f M", new Float(value/1000000)); } //shorten output, don't show exponent. 294 else if(valueAbs >= 1.0e9f){ sShow = String.format("%3.3g", new Float(value)); } //shorten output, don't show exponent. 295 //else if(valueAbs >= 1e6){ sShow = Float.toString(value/1000000) + " M"; } //shorten output, don't show exponent. 296 else { sShow = Float.toString(value); } 297 298 } 299 setText(sShow); 300 } 301 302 303 304 /**Sets a long value into a text field. 305 * The long value may be calculated and may be formatted: 306 * <ul> 307 * <li>If the {@link #setFormat(String)} of this widget starts with '!' and contains a second '!', 308 * the String between that is used as expression to calculate the long value 309 * using {@link CalculatorExpr}. Therewith any calculation can be done. The result may be a float or double. 310 * <li>The rest after the "!expression!" or the given format is used for String.format(sFormat, value) 311 * to determine the output appearance. 312 * <li>If The sFormat has the form "!16lo!expr!format" ("!16lo" as prefix), then additional to the expression the 16 lo-Bits are filtered firstly. 313 * Adequate starting with "!!16hi.." filteres the Bits 31..16 to bit 15..0 before calculate the expression. 314 * This is especially if 2 * 16 bit for different values are accessed in one 32 bit address position of an processor which can only access 32 bit. 315 * <li>As special feature a format <code>int32AngleDegree</code> and <code>int16AngleDegree</code> 316 * is supported, if that text is contained in the format string. The value should come from an integer, 317 * which contains an angle value with wrap-around-presentation: 0x7fffffff (32 bit) or 0x7fff (16 bit) and 318 * 0x80000000 which is exactly 180 degree. This format helps to calculate with angle values in range 319 * of -180...+179.99999 degree. The presentation in the text field is shown as degree angle value. 320 * <li>If no format is given, the value will be shown as normal decimal long value. 321 * <ul> 322 * 323 * @see org.vishia.gral.base.GralWidget#setValue(float) 324 */ 325 @Override public void setLongValue(final long valueP){ 326 final String sFormat1; 327 //final long value; 328 CalculatorExpr.Value value1; 329 String sShow; 330 if(sFormat !=null && (sFormat.startsWith("!") || sFormat.startsWith("int"))) { //should have a calculator. 331 if(calculator == null){ 332 if(sFormat !=null && sFormat.startsWith("int16AngleDegree")){ 333 this.calculator = new CalculatorAngle16(); 334 sFormat1 = this.sFormat2 = "%3.3f"; 335 } else if(sFormat !=null && sFormat.startsWith("int32AngleDegree")){ 336 this.calculator = new CalculatorAngle32(); 337 sFormat1 = this.sFormat2 = "%3.3f"; 338 } else { 339 final String sFormat3; 340 if(sFormat.startsWith("!16hi!") || sFormat.startsWith("!16lo!")) { 341 sFormat3 = sFormat.substring(5); //from ! 342 } else { 343 sFormat3 = this.sFormat; 344 } 345 int posEnd = sFormat3.indexOf('!',1); 346 if(posEnd >=0){ 347 String sExpr = sFormat3.substring(1, posEnd); 348 sFormat1 = this.sFormat2 = sFormat3.substring(posEnd+1); 349 if(calculator ==null){ 350 calculator = new CalculatorExpr(); 351 String sError = calculator.setExpr(sExpr); 352 if(sError !=null){ 353 //console.writeError(sError); 354 calculator = null; 355 } 356 } 357 } else { 358 sFormat1 = this.sFormat2 = sFormat; //!...error 359 } 360 } 361 } //create calculator. 362 else { 363 sFormat1 = this.sFormat2; //Should be correct 364 } 365 } else { 366 sFormat1 = this.sFormat2 = sFormat; //maybe null or a normal format string 367 //value = valueP; 368 } 369 370 if(calculator !=null){ //use it. 371 try { 372 if(sFormat.startsWith("!16hi!")) { 373 value1 = calculator.calcDataAccess(null, (float)(((int)valueP) >>16)); 374 } 375 else if(sFormat.startsWith("!16lo!")) { 376 value1 = calculator.calcDataAccess(null, (float)((short)valueP)); 377 } else { 378 value1 = calculator.calcDataAccess(null, valueP); 379 } 380 //value = (long)value1.doubleValue(); 381 } catch (Exception e) { 382 value1 = new CalculatorExpr.Value(777777L); //a long value 383 //value = 7777777L; 384 } 385 } else { 386 value1 = new CalculatorExpr.Value(valueP); //a long value 387 } 388 389 if(sFormat1 !=null && sFormat.length() >0){ 390 char type = value1.type(); 391 if(type == 'J') { 392 long value = value1.longValue(); 393 if(sFormat1.startsWith("+") && value <0) { //special handling. It is an unsigned int, convert it to long 394 value = (value + 0x8000000000000000L) & 0x0ffffffffL; 395 //sFormat1 = sFormat1.substring(1); 396 } 397 try{ sShow = String.format(sFormat1, new Long(value)); } 398 catch(java.util.IllegalFormatException exc){ 399 sShow = "?format"; 400 } 401 } else { 402 double value = value1.doubleValue(); 403 try{ sShow = String.format(sFormat1, new Double(value)); } 404 catch(java.util.IllegalFormatException exc){ 405 sShow = "?format"; 406 } 407 } 408 409 } else { //no format given 410 sShow = String.format("%d", new Long(value1.intValue())); 411 } 412 setText(sShow); 413 } 414 415 416 417 /**Sets a float value into a text field. 418 * The float value may be formatted: 419 * <ul> 420 * <li>If the {@link #setFormat(String)} of this widget starts with '!' and contains a second '!', 421 * the String between that is used as expression to calculate the float value 422 * using {@link CalculatorExpr}. Therewith any calculation can be done. 423 * <li>The rest after the "!expression!" or the given format is used for String.format(sFormat, value) 424 * to determine the output appearance. 425 * <li>If no format is given, the value will be shown in proper readable appearance. That assures 426 * that the value is able to present in a short text field, using maximal 9 digits. 427 * <li>If no format is given and the absolute of the value is less 0.000001 but not 0, 428 * a "0.000001" with the correct sign will be shown. It shows, there is a less value, but not null. 429 * <li>If no format is given and the value is in range up to 1 Billion, it is shown with "k", "M" 430 * for kilo and Mega with max 3 digits before dot and 3 digits after the dot. 431 * <li>if no format is given and the value is greater than 1 Billion, it is shown with exponent. 432 * <ul> 433 * 434 * @see org.vishia.gral.base.GralWidget#setValue(float) 435 */ 436 public void setValue(final double valueP){ 437 final String sFormat1; 438 double value; 439 String sShow; 440 if(calculator !=null){ 441 try { 442 CalculatorExpr.Value value1 = calculator.calcDataAccess(null, valueP); 443 value = value1.doubleValue(); 444 } catch (Exception e) { 445 value = 7777777.777f; 446 } 447 sFormat1 = this.sFormat2; 448 } else if(sFormat !=null){ 449 if(sFormat.startsWith("!")){ 450 int posEnd = sFormat.indexOf('!',1); 451 if(posEnd >=0){ 452 String sExpr = sFormat.substring(1, posEnd); 453 this.sFormat2 = sFormat1 = sFormat.substring(posEnd+1); 454 if(calculator ==null){ 455 calculator = new CalculatorExpr(); 456 String sError = calculator.setExpr(sExpr); 457 if(sError !=null){ 458 //console.writeError(sError); 459 calculator = null; 460 } 461 } 462 if(calculator !=null){ 463 try { 464 CalculatorExpr.Value value1 = calculator.calcDataAccess(null, valueP); 465 value = value1.doubleValue(); 466 } catch (Exception e) { 467 value = 7777777.777f; 468 } 469 } else { 470 value = valueP; 471 } 472 } else { 473 sFormat1 = sFormat; 474 value = valueP; 475 } 476 } else { 477 sFormat1 = sFormat; 478 value = valueP; 479 } 480 481 } else { //sFormat == null 482 sFormat1 = null; //no expression 483 value = valueP; 484 } 485 if(sFormat1 !=null && sFormat.length() >0){ 486 try{ sShow = String.format(sFormat1, new Double(value)); } 487 catch(java.util.IllegalFormatException exc){ 488 sShow = null; //maybe integer 489 } 490 if(sShow == null){ 491 try{ sShow = String.format(sFormat, new Integer((int)value)); } 492 catch(java.util.IllegalFormatException exc){ 493 sShow = "?format"; 494 } 495 } 496 } else { //no format given 497 double valueAbs = Math.abs(value); 498 if(value == 0.0f){ sShow = "0.0"; } 499 else if(valueAbs < 1.0e-7f){ sShow = value < 0 ? "-0.0000001" : "0.0000001"; } //shorten output, don't show exponent. 500 else if(valueAbs < 1.0f){ sShow = String.format("%1.12f", new Double(value)); } //shorten output, don't show exponent. 501 else if(valueAbs < 1.0e3f){ sShow = String.format("%3.9f", new Double(value)); } //shorten output, don't show exponent. 502 else if(valueAbs < 1.0e6f){ sShow = String.format("%3.8f k", new Double(value/1000)); } //shorten output, don't show exponent. 503 else if(valueAbs < 1.0e9f){ sShow = String.format("%3.8f M", new Double(value/1000000)); } //shorten output, don't show exponent. 504 else if(valueAbs >= 1.0e9f){ sShow = String.format("%3.8g", new Double(value)); } //shorten output, don't show exponent. 505 //else if(valueAbs >= 1e6){ sShow = Float.toString(value/1000000) + " M"; } //shorten output, don't show exponent. 506 else { sShow = Double.toString(value); } 507 508 } 509 setText(sShow); 510 } 511 512 513 514 515 @Override public void setValue(Object[] value){ 516 if(value !=null && value.length ==1 && value[0] instanceof Double){ 517 double val = ((Double)value[0]).doubleValue(); 518 setValue(val); 519 } else { 520 setText("?" + value); 521 } 522 } 523 524 525 526 527 @Override public void setText(CharSequence arg) 528 { setText(arg, 0); 529 } 530 531 /**Sets the textual content. This method sets the text and invokes a {@link #repaint(int, int)} in 100 ms 532 * if the content is changed in another thread than the graphical thread. It invokes a {@link #repaintGthread()} 533 * if the content was changed in the graphical thread. 534 * Note: If the current content is equals with the new one, a repaint request is not forced. 535 * Therewith the cursor can be positioned inside. But if the content is changed, it is set with this given one. 536 * @see org.vishia.gral.ifc.GralTextField_ifc#setText(java.lang.CharSequence, int) 537 */ 538 @Override public void setText(CharSequence arg, int caretPos) 539 { 540 bShouldInitialize= false; //it is done. 541 if( dyda.displayedText == null //set the text if no text is stored. Initially! 542 //|| !bTextChanged //don't set the text if it is changed by user yet. 543 //&& 544 || ( !dyda.bTouchedField //don't change the text if the field is in focus and anything was moved. Either any copy to clipboard is pending, or it is in editing. 545 && !StringFunctions.equals(dyda.displayedText,arg) || caretPos != this.caretPos) //set the text only if it is changed. Prevent effort. 546 ){ //prevent invocation of setText() on non changed values to help move cursor, select etc. 547 dyda.displayedText = arg.toString(); 548 this.caretPos = caretPos; 549 dyda.setChanged(GralWidget.ImplAccess.chgText); 550 repaint(); 551 } //else: no change, do nothing. Therewith the field is able to edit on unchanged texts. 552 } 553 554 555 556 557 /**Sets the action which is invoked while a mouse button is pressed or release on this widget. 558 * Implementation hint: It installs a mouse listener. 559 * TODO: use GralMouseWidgetAction_ifc instead GralUserAction, use another action for mouse than change. 560 */ 561 //abstract public void setMouseAction(GralUserAction action); 562 563 /**Gets the current value of the text field thread-independent. 564 * It is the value stored in the {@link GralWidget.DynamicData#displayedText} which is updated while typing the text 565 * or if the focus is changed (depending on implementation). 566 * @return The value in String representation. 567 */ 568 @Override public String getValue() { return dyda.displayedText; } 569 570 571 572 573 @Override 574 public int getCursorPos(){ return caretPos; } 575 576 577 @Override 578 public int setCursorPos(int pos) 579 { int pos9 = caretPos; 580 if(pos != caretPos){ 581 caretPos = pos; 582 dyda.setChanged(GraphicImplAccess.chgCursor); 583 repaint(repaintDelay, repaintDelayMax); 584 } 585 return pos9; //the old 586 } 587 588 589 @Override public void setTextStyle(GralColor color, GralFont font) 590 { 591 dyda.textFont = font; 592 dyda.textColor = color; 593 dyda.setChanged(GralWidget.ImplAccess.chgColorText); 594 if(_wdgImpl !=null){ 595 repaint(); 596 } 597 } 598 599 600 601 /**Sets a new border width and returns the old one. 602 * If the width is the same as the old one, nothing else is done. 603 * If the widht is another, a repaint request is registered to show it in graphic. 604 * This routine can be invoked in any thread. 605 * @param width 0: No border, 1... number of pixel for border. 606 * @return last width to quest, store and restore. 607 */ 608 public int setBorderWidth(int width){ 609 if(borderwidth == width) return width; //no action if nothing is change. 610 int widthLast = width; 611 borderwidth = width; 612 dyda.setChanged(GralWidget.ImplAccess.chgColorLine); 613 if(_wdgImpl !=null){ 614 repaint(); 615 } 616 return widthLast; 617 } 618 619 620 621 /**Returns the Label for a prompt or null if there isn't used a prompt 622 */ 623 public final String getPromptLabelImpl(){ return sPrompt; } 624 625 626 627 private static class CalculatorAngle16 extends CalculatorExpr 628 { CalculatorAngle16(){} 629 @Override public float calc(float input){ 630 return input * (180.0f / 32768.0f); 631 } 632 @Override public Value calcDataAccess(Map<String, DataAccess.Variable<Object>> javaVariables, Object... args) throws Exception{ 633 Float value; 634 if(args[0] instanceof Float){ 635 value = (Float)args[0]; 636 } else { 637 Long lval = (Long)args[0]; 638 value = new Float((int)(lval.longValue())); //really an int if it is an angle. 639 } 640 CalculatorExpr.Value valueRet = new CalculatorExpr.Value(calc(value.floatValue())); 641 return valueRet; 642 } 643 } //class CalculatorAngle16 644 645 646 private static class CalculatorAngle32 extends CalculatorExpr 647 { CalculatorAngle32(){} 648 @Override public float calc(float input){ 649 return input * (180.0f / 0x7fffffff); 650 } 651 @Override public Value calcDataAccess(Map<String, DataAccess.Variable<Object>> javaVariables, Object... args) throws Exception{ 652 Float value; 653 if(args[0] instanceof Float){ 654 value = (Float)args[0]; 655 } else { 656 Long lval = (Long)args[0]; 657 value = new Float((int)(lval.longValue())); //really an int if it is an angle. 658 } 659 //TODO use long value or int for calculation 660 CalculatorExpr.Value valueRet = new CalculatorExpr.Value(calc(value.floatValue())); 661 return valueRet; 662 } 663 664 } //class CalculatorAngle32 665 666 667 668 protected GralKeyListener gralKeyListener = new GralKeyListener(itsMng) 669 { 670 @Override public boolean specialKeysOfWidgetType(int key, GralWidget_ifc widgg, Object widgImpl){ return false; } 671 }; 672 673 674 675 public abstract class GraphicImplAccess extends GralWidget.ImplAccess 676 implements GralWidgImpl_ifc 677 { 678 679 public static final int chgPrompt = 0x100, chgCursor = 0x200; 680 681 /**The {@link GralWidget#pos()} is the summary position for prompt and field. 682 * This is the part for field and prompt. 683 */ 684 protected final GralPos posPrompt, posField; 685 686 687 688 protected GraphicImplAccess(GralWidget widgg) 689 { 690 super(widgg); 691 if(prompt() != null && promptStylePosition() !=null && promptStylePosition().startsWith("t")) { 692 //mng.setNextPosition(); //deprecated, done in Widget constructor. 693 char sizeFontPrompt; 694 posPrompt = new GralPos(); 695 posField = new GralPos(); 696 697 //boundsAll = mng.calcWidgetPosAndSize(this.pos, 800, 600, 100, 20); 698 float ySize = widgg.pos().height(); 699 //float xSize = pos.width(); 700 //posPrompt from top, 701 float yPosPrompt, heightPrompt, heightText; 702 //switch(promptStylePosition){ 703 //case 't':{ 704 if(ySize <= 2.5){ //it is very small for top-prompt: 705 yPosPrompt = 1.0f; //no more less than 1/2 normal line. 706 heightPrompt = 1.0f; 707 heightText = ySize - 0.7f; //max. 1.8 708 if(heightText < 1.0f){ heightText = 1.0f; } 709 } else if(ySize <=3.3){ //it is normally 2.5..4 710 heightPrompt = ySize - 2.0f + 0.5f; //1 to 1.8 711 yPosPrompt = ySize - heightPrompt - 0.1f; //no more less than 1/2 normal line. 712 heightText = 2.0f; 713 } else if(ySize <=4.0){ //it is normally 2.5..4 714 heightPrompt = ySize - 2.0f + (4.0f - ySize) * 0.5f; 715 if(heightPrompt < 1.0f){ heightPrompt = 1.0f; } 716 yPosPrompt = ySize - heightPrompt + 0.2f; //no more less than 1/2 normal line. 717 heightText = 2.0f; 718 } else { //greater then 4.0 719 yPosPrompt = ySize * 0.5f; 720 heightPrompt = ySize * 0.4f;; 721 heightText = ySize * 0.5f; 722 } 723 //from top, size of prompt 724 posPrompt.setPosition(widgg.pos(), GralPos.same - ySize + yPosPrompt, GralPos.size - heightPrompt, GralPos.same, GralPos.same, 0, '.'); 725 //from bottom line, size of text 726 posField.setPosition(widgg.pos(), GralPos.same, GralPos.size - heightText, GralPos.same, GralPos.same, 0, '.'); 727 //} break; 728 //} 729 730 } else { //no prompt given 731 posPrompt = null; 732 posField = widgg.pos(); 733 } 734 } 735 736 //protected GralFont fontText(){ return GralTextField.this.fontText; } 737 738 protected String prompt(){ return GralTextField.this.sPrompt; } 739 740 protected String promptStylePosition(){ return GralTextField.this.sPromptStylePosition; } 741 742 protected int borderwidth(){ return GralTextField.this.borderwidth; } 743 744 protected int caretPos(){ return GralTextField.this.caretPos; } 745 746 protected void caretPos(int newPos){ GralTextField.this.caretPos = newPos; } 747 748 protected GralTextFieldUser_ifc user(){ return GralTextField.this.user; } 749 750 protected boolean isPasswordField(){ return GralTextField.this.bPassword; } 751 752 protected void setTouched(boolean bTouched) { widgg.dyda.bTouchedField = bTouched; } 753 754 } 755 756 757}