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}