001package org.vishia.gral.base;
002
003import java.text.ParseException;
004
005import org.vishia.bridgeC.IllegalArgumentExceptionJc;
006import org.vishia.gral.ifc.GralRectangle;
007import org.vishia.util.Assert;
008import org.vishia.util.StringPart;
009import org.vishia.util.StringPartScan;
010
011
012/*Test with Jbat: call Jbat with this java file with its full path:
013D:/vishia/Java/srcJava_vishiaGui/org/vishia/gral/base/GralPos.java
014==JZcmd==
015java org.vishia.gral.base.GralPos.testScanSize();
016==endJZcmd==
017*/
018
019
020/**This class describes a position in a gral panel. 
021   * <br><br>
022   * <b>Concept of positioning</b>:<br>
023   * The position are never given as pixel positions. They are user-oriented positions. The calculation
024   * of pixel units are done from the implementing graphic layer depending on the graphic device properties
025   * and the requested size appearance. The same graphic elements can be presented in several sizes
026   * on the display.
027   * <br><br>
028   * A normal text with a font in the standard proper read-able size is presented by 2 units of the Gral-position
029   * in vertical direction (line) and approximately 1 unit per character in horizontal direction.
030   * Of course the horizontal character size depends on the font properties.
031   * A text can be presented in a smaller or larger font.  
032   * The text height depends on the height given in the position of the text. A very small font is presented by 1 vertical gral-unit.
033   * Such a text can be used as short title for text input fields (prompt) or adequate.
034   * <br>
035   * A button is able to proper present with 3 or 2 vertical gral units. A small check box may be presented 
036   * with 1 x 1 gral unit.
037   * <br><br>
038   * A gral unit should be have the same distance in vertical as in horizontal direction. It depends on the 
039   * graphical implementation. One gral unit may have approximately 6 to 30 pixel, 
040   * depending on the requested size of appearance in comparison with the given display pixel size. 
041   * Any graphic can be shown in several sizes of appearance, given with a start parameter of the application
042   * (see {@link org.vishia.gral.area9.GuiCallingArgs#sSize}) respectively the parameter size of {@link GralGridProperties#GralGridProperties(char size)}.
043   * <br><br>
044   * <b>Fine positions</b>:<br>
045   * Either the positions are given with 2 integer values as 'fundamental positions'. 
046   * That are the position described above.
047   * Or they can be given with a float value or a second int named 'fractional part'. From the float value
048   * only the first digit after point is used, a fractional part can be given
049   * with a value from 0 to 9. 
050   * <br><br>
051   * The fine position divides one gral position into 5 or into 6 fine positions. 
052   * The odd numbers divide into 6 positions. In this kind a gral position is able to divide by 2, 3 and 6:
053   * <ul>
054   * <li>1: 1/6 = 0.1333
055   * <li>3: 1/3 = 0.3333
056   * <li>5: 1/2 = 0.5
057   * <li>7: 2/3 = 0.6667
058   * <li>9: 5/6 = 0.8667
059   * </ul>
060   * The even numbers divide into 5 positions: 
061   * <ul>
062   * <li>2: 1/5 = 0.2
063   * <li>4: 2/5 = 0.4
064   * <li>6: 3/5 = 0.6
065   * <li>8: 4/5 = 0.8
066   * </ul>
067   * The fine positioning enables a fine positioning of widgets in respect to the fundamental positions.
068   * <br><br>
069   * <b>Positions as user arguments</b>:<br>
070   * Positions may be given with absolute values of grid units regarded to the actual panel or in related to the 
071   * last or parent position. In that cases the constant values are added to the number, see the following list.
072   * The position is given in form 'from..to' for the line and column or in form 'from' and 'size'. 
073   * The size may be given positive or negative. A positive size is counted from top or left to bottom or right.
074   * It means that the 'from' position is top or left. But a negative size is counted from right or bottom
075   * and the 'from' position is the right or bottom column and line.
076   * <br><br>
077   * <b>Position writing style in a gral script:</b><br>
078   * The appearance of a graphic can be given with a script using {@link org.vishia.gral.cfg.GralCfgZbnf}.
079   * The writing style of positions in the script regards a stinting short style to give positions,
080   * because a hand written script should not cause a lot of calculations for positions by the writer.
081   * It should be simple. The syntax of a position in the gral script is given in the variable {@link #syntaxZbnf}.
082   * The method {@link #setPosition(CharSequence, GralPos)} uses that syntax.
083   * <ul>
084   * <li>@myPanel, 5..7, 8..18: This is a full given absolute position. The element should be placed from line 5 to line 7 
085   *   and from column 8 to 18. The vertical position 7 is the bottom line, the column 18 is the right column exclusive. 
086   *   The horizontal size is 10, the vertical size is 2.
087   * <li>@myPanel, 5..7, 8..-1: This is a full given absolute position. The end column is given with a negative value.
088   *   It means that the end column is related to the right border of the panel.
089   * <li>@myPanel, 5+2, 8+10: This is a full given position using the size. The element should be placed from line 5 
090   *   to line 7 and from column 8 to 18. The range is given as size. 
091   * <li>@7-2, 18-10: The panel isn't given, so the panel of the last position, in the script in order of text,
092   *   is used. The positions are exactly the same, from 5 to 7 and from 10 to 18. But because the size is given
093   *   as negative value, the position value is the bottom line and the right column. A user may place elements
094   *   with a common bottom line. The this form can be used.
095   * <li>@7-2, 10+18++1: This is the same position too. The '++' operator after size means, that the next element
096   *   is positioning right side after the current in distance of 1 unit (distance feature TODO).
097   * <li>@-3,+4: The position isn't given yet. It means, the position of the last element is used. Because
098   *   the size is negative, the bottom position of the last element is used. Because the last position is
099   *   designated with '++' for column, the column value of position is the right value and the current element 
100   *   is placed right hand from the last one. This is an example of a button right from a text. The button is
101   *   some times greater (3 units) in relation to the text (2 units), but they have the same button line.
102   * <li>@,+5: Here the line isn't specified. It is taken from the last position: bottom line 7
103   *   and height 3. The column isn't given, it is taken form the last: Because the column position is cumulated,
104   *   it is the 22 yet.
105   * <li>If no position is given, the position is the next position. In this example @7-3,27+5.
106   * <li>@,&2+10: The ampersand determines a relative position related to the last one. In this example
107   *   the new column is 24 to 34. There is 2 units space.
108   * <li>@ $2-2,$+20: The dollar determines a relative position related to the last absolute given position. 
109   *   In this example it is line 7 and column 10. The new position is calculated with that values to line 9. 
110   *   The column 10 is the same column related to the last given absolute.
111   *   This kind of specification allows determining some positions in lines and columns, 
112   *   whereby the absolute position is given only one time. (feature TODO)
113   * <li>@ %50-2,%10..%90: The positions are calculated from the size of the panel in percent. (feature TODO)  
114   * </ul>
115   * <br><br>
116   * <b>Ranges and Designation of position parameter</b>:
117   * <ul>
118   * <li>Positive number in range 0...about 100..200 up to 1000: Grid Unit from left or top.
119   * <li>Negative number in range 0, -1...about -200..-200 up to 1000: Gral Unit from right or bottom.
120   *   0 for lineEnd or columnEnd means the right or bottom.
121   * <li>{@link #same} or {@link #refer} added with a number in range of -1000..1000: This given position 
122   *   refers to the parent position with the given distance. same and refer is equate, the difference 
123   *   is in semantic only. Use {@link #same} without distance, use {@link #refer} +/- distance.
124   *   If {@link #same} or {@link #refer} is used for the line or column, and the second position is given
125   *   with '{@link #size} - size' then the bottom or right value of the parent is referred.
126   *  
127   * <li>{@link #size} + number applied at lineEnd or columnEnd: 
128   *   The size is given instead from..to. Because the size value is positive, the line and column value is left or top. 
129   * <li>{@link #size} - number applied at lineEnd or columnEnd: The size is given negative.  
130   *   The absolute value is the size. Because the size is negative it is measured from right to left
131   *   respectively bottom to top. It means the given line and column is the right or the bottom line. 
132   *   If the position is given using {@link #same} or {@link #refer}, the related end position
133   *   is used. 
134   * <li> {@link GralPos#next} and {@link GralPos#nextBlock}   
135   * <li>as width or height or as percent value from the panel size.
136   * </ul>
137   * Fine positions are given always from left or top of the fundamental positions. 
138   * For example a value -1.3 means, the widget is placed 1 unit from right, and then 1/3 inside this unit.
139   * This is 2/3 unit from right. A value for example -0.3 is not admissible, because -0 is not defined. 
140   * <br><br>
141   * <b>The position values in this class</b>:<br>
142   * Though the position parameters may be given as size, with bottom line etc the position values are stored
143   * as absolute positions anyway. That are the elements {@link #x}, and {@link #y} with its values in
144   * {@link Coordinate}.
145   * The x and y is the lesser value, left and top, and the xEnd and yEnd is the greater value, right or bottom.
146   * This form of storing is better to calculate the pixel position while building the graphic and it is better
147   * to calculate related position too.    
148   * <br><br>
149   * 
150 * @author Hartmut Schorrig
151 *
152 */
153public class GralPos implements Cloneable
154{
155  /**Version, history and license.
156   * <ul>
157   * <li>2013-05-24 Hartmut bugfix fine position can be greater 20 if positions are add and sizes are add too. 
158   * <li>2011-10-01 Hartmut corr: Calculation of next position or refer + value if the size was negative and sameSize is selected.
159   *                Then the new input value should calculate from the bottom or left value because the size is negative furthermore.
160   * <li>2011-10-01 Hartmut bugfix: if(qf >= 10)... instead >10 
161   * <li>2011-09-23 Hartmut chg: The methods {@link #setPosition(GralPos, float, float, float, float, int, char)} etc
162   *     are moved from the GralGridMngBase to this. It are methods of this class functionally. The GralGridMngBase wrappes it
163   *     because that methods should be able to call there.
164   * <li>2011-08-31 Hartmut new: constants {@link #same} etc. as adding values for setPosition-methods.
165   *     It prevents the necessity of a lot of special set methods. The parameter for positions may be relative, referred etc.
166   *     to the previous position or to a frame.
167   * <li>2011-08-31 Hartmut new: method {@link #toString()} to see values of instance in debug
168   * <li>2011-08-14 Hartmut new: creation of this class. Beforehand this values are stored inside the GralGridMngBase as main position.
169   *     But a position in this kind is necessary in other contexts too, and the position values should be pooled in one class.                       
170   * </ul>
171   * <ul>
172   * <li>2011-06-00 Hartmut created
173   * </ul>
174   * 
175   * <b>Copyright/Copyleft</b>:<br>
176   * For this source the LGPL Lesser General Public License,
177   * published by the Free Software Foundation is valid.
178   * It means:
179   * <ol>
180   * <li> You can use this source without any restriction for any desired purpose.
181   * <li> You can redistribute copies of this source to everybody.
182   * <li> Every user of this source, also the user of redistribute copies
183   *    with or without payment, must accept this license for further using.
184   * <li> But the LPGL is not appropriate for a whole software product,
185   *    if this source is only a part of them. It means, the user
186   *    must publish this part of source,
187   *    but doesn't need to publish the whole source of the own product.
188   * <li> You can study and modify (improve) this source
189   *    for own using or for redistribution, but you have to license the
190   *    modified sources likewise under this LGPL Lesser General Public License.
191   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
192   * </ol>
193   * If you intent to use this source without publishing its usage, you can get
194   * a second license subscribing a special contract with the author. 
195   * 
196   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
197   */
198  public static final int version = 20120317;
199
200  
201  /**This adding value applied at any coordinate parameter of any setPosition- method means, that the value is 
202   * referred to the position of the previous or given position. The referred value may be given as positive or negative number.
203   * Adding this constant a value in range 0x7000...0x8000 to 0x8fff results for positions -4096...4095 (usual -100..100)
204   * Hint: If only the fractional part is changed, the non-fractional part should be given as refer.
205   */
206  public final static int refer = 0x8000;
207  
208  /**This value applied at any coordinate parameter of any setPosition- method means, that the value is 
209   * the same as the previous or given position.
210   * Hint: The constant is equal to {@link #refer}. This constant regards the semantic.
211   */
212  public final static int same = 0x8000;
213  
214  /**Use the next value for the coordinate in relation to the last one for the given direction
215   * but the same value for the other coordinate. It is the typical value for both coordinates
216   * if a quasi-float layout is desired. 
217   * This value can be applied to x, xEnd, y, yEnd or to the float given arguments of any setPosition- method. 
218   * It uses xEnd for x and yEnd for y with the adequate fractional parts. 
219   * The new value for xEnd or yEnd is calculated using the size if this value is applied to them. 
220   */
221  public final static int next = 0xdffe;
222  
223  /**Use the next value for the coordinate in relation to the last one. 
224   * This value can be applied to x, xEnd, y, yEnd or to the float given arguments of any setPosition- method. 
225   * It uses xEnd for x and yEnd for y with the adequate fractional parts. 
226   * The new value for xEnd or yEnd is calculated using the size if this value is applied to them. 
227   */
228  public final static int nextBlock = 0xdffd;
229  
230  
231  /**This value at xEnd or yEnd means, that the native size of a widget should be used.
232   * It is especially to draw images with its native size.
233   * This is a bit mask. The nature size is stored in the bits 12..0, that is maximal 8191 pixel 
234   */
235  public final static int useNatSize = 0xc000;
236  
237  
238  /**This bit at all coordinates means, that the value is given as ratio from the size.
239   * The bit {@link useNatSize} have to be 0. The ratio is stored as a value from 0 to 999
240   * in the bits 9..0. The other bits should be 0.
241   */
242  public final static int ratio = 0xa000;
243  
244  
245  /**This adding value at xEnd or yEnd or the float presentations of the calling argument of any
246   * setPosition- method means, that the value is the size, not the position.
247   * A size can be positive or negative. A negative size determines, that the origin point for
248   * further elements or inner elements is on bottom line or right line of the current widget.
249   */
250  public final static int size = 0x4000;  //Note: Bit is contained in useNatSize, (pos = useNatSize | size) == useNatSize
251  
252  
253  /**Use the same size.
254   * 
255   */
256  public final static int samesize = 0x6000;
257  
258
259  /**Bits in an integer position value for range and size.
260   * of relative position values for size, percent and refer. The mask for the value is 0x1fff.
261   * The range of any value is from 0x0 to 0x0fff for positive values and from 0x1fff downto 0x1000
262   * for negative values. The value == 0 is designated with 0x0 after mask. */
263  private final static int mValueRange_ = 0x1fff, mValueNegative = 0x1000;
264  
265  /**Bits in an integer position value for the type. 
266   * If the type should be tested, the mTypwAdd_ should be added before masking. That is because
267   * the negative values for a specific type are disposed type - value */
268  private final static int mType_ = 0xe000, kTypAdd_ = 0x1000;
269  
270  /**Bit masks for the special types {@link #next}, {@link #nextBlock}, {@link #useNatSize}. */
271  private final static int  mSpecialType = 0xff00, kSpecialType=0xdf00; 
272  
273  /**Mask to check ratio. This bits should be mask and the ratio value should compare with them. */
274  private final static int XXXmCheckRatio_ = 0xf000;
275  
276  /**Mask for value of natural size. The maximum size is 16383 pixel. */
277  private final static int XXXmNatSize_ = 0xf001;
278  
279  /**Mask bits to designate related position, related end position and size.
280   * 
281   */
282  private final static int mBitRel = 0x1, mBitSize = 0x2, mBitRelEnd = 0x4, mBitSizeNeg = 8;
283  
284  /**Position and mask of bits to designate kind of parameter. See {@link #parameterDesignation} */ 
285  private final static int kBitParamDesignator_x = 0, kBitParamDesignator_y = 8, mParamDesignator = 0xff; 
286  
287  
288  /**Syntax of a position. It is
289   * <pre>
290  position::= @ [<$?panel> ,]
291       [<?yPosRelative> &+] [<#?yPos>[\\.<#?yPosFrac>]]
292     [ [+] <#-?ySizeDown>[\\.<#?ySizeFrac>]| +* <?yOwnSize> |] 
293   [ , [<?xPosRelative> &+] [<#?xPos>[\\.<#?xPosFrac>]]
294     [ [+] <#-?xWidth>[\\.<#?xSizeFrac>]| +* <?xOwnSize> |] [ <?xIncr> ++]
295   ].
296   * </pre>
297   * The semantic identifier match to the elements in {@link org.vishia.gral.cfg.GralCfgPosition}.
298   * */
299  public final static String syntaxZbnf = null; //not used because the syntax is evaluated by hard code.
300  /*
301  "position::= @ [<$?panel> ,]"
302  + "     [<?yPosRelative> &+] [<#?yPos>[\\.<#?yPosFrac>]]"
303  + "   [ [+] <#-?ySizeDown>[\\.<#?ySizeFrac>]| +* <?yOwnSize> |] ##| - <#?ySizeUp>|][ <?yIncr> ++]"
304  + " [ , [<?xPosRelative> &+] [<#?xPos>[\\.<#?xPosFrac>]]"
305  + "   [ [+] <#-?xWidth>[\\.<#?xSizeFrac>]| +* <?xOwnSize> |] [ <?xIncr> ++]"
306  + " ] :";
307  */
308  
309  
310  
311  /**The Property for the input parameter to use same, next etc. 
312   * This value is used to generate an adequate config file from given input values.
313   * The coordinates don't carry the information about that input values.
314   */
315  //public int parameterDesignation;
316  
317  /**Position of any widget.
318   * Generally: There are coordinates in a grid, not in pixel. 
319   * Positive value is from top or left, negative value is from right or bottom.
320   * {@link GralGridPos#useNatSize} on xEnd, yEnd means, that the natural size of the object should be used.
321   * 
322   */
323  //public int x, xEnd, y, yEnd;
324
325  
326  
327  /**Fractional part of position.
328   * Generally: It is a number from 0 to 9 as part of 1 grid unit.
329   */
330  //public int xFrac, xEndFrac, yFrac, yEndFrac;
331  
332  /**The values for x and y positions. Note: should be private! Don't use in application furthermore. */
333  public final Coordinate x = new Coordinate(), y = new Coordinate();
334  
335  /**A GralPos should never create as instance from the application. It is created only from the GralMng which accesses package private.
336   * It is copied inside the GralMng for any widget.  
337   * The position can be changed after them with {@link #setPosition(float, float)} etc.
338   */
339  protected GralPos(){}
340  
341  
342  /**A GralPos should never create as instance from the application. It is created only from the GralMng which accesses package private.
343   * It is copied inside the GralMng for any widget. The position can be changed after them with {@link #setPosition(float, float)} etc. 
344   * @param src the src position to copy all values.
345   */
346  protected GralPos(GralPos src){ set(src); }
347  
348  /**The border to the next element. */
349  //public int xyBorder, xyBorderFrac;
350
351  /**Origin of widget, use l, m, r for xOrigin and t, m, b for yOrigin. */
352  //public char xOrigin, yOrigin;
353  
354  /**direction of the next element. Use r, d, l, u. */
355  //public char dirNext;
356  
357  /**Relation of x and y left and top to any separation line. 0 - relation to left and top border. */
358  //public int xSepLine, ySepLine;
359  
360  public GralPanelContent panel;
361  
362  /**Sets all values of this with the values of pos (copy values)
363   * @param pos The src pos
364   */
365  public void set(GralPos pos)
366  { x.attr = pos.x.attr; y.attr = pos.y.attr; 
367    x.p1 = pos.x.p1; x.p2 = pos.x.p2; y.p1 = pos.y.p1; y.p2 = pos.y.p2;
368    x.p1Frac = pos.x.p1Frac; x.p2Frac = pos.x.p2Frac; y.p1Frac = pos.y.p1Frac; y.p2Frac = pos.y.p2Frac;
369    x.origin = pos.x.origin; y.origin = pos.y.origin; x.sepLine = pos.x.sepLine; y.sepLine = pos.y.sepLine;
370    x.dirNext = pos.x.dirNext; y.dirNext = pos.y.dirNext;
371    panel = pos.panel;
372  }
373  
374  
375  
376  public void setPosition(float line, float column)
377  {
378    setPosition(this, line, size + same, column, size + same, 0, '.');
379  }
380  
381  
382  
383  
384  /* (non-Javadoc)
385   * @see org.vishia.gral.gridPanel.GuiPanelMngBuildIfc#setPosition(int, int, int, int, char)
386   */
387  public void setPositionSize(int line, int column, int height, int width, char direction, GralPos posFrame)
388  { setFinePosition(line, 0, height + GralPos.size, 0, column, 0, width + GralPos.size, 0, 1, direction, 0, 0, posFrame);
389  }
390
391  
392  /**Sets the position with the given string representation.
393   * @param sPos The syntax of the string see description of this class, starting with "@panel, ..." etc.
394   *   for example "@windowA, 3..5, 16+20" for absolute line 3 and 4 (exclusive 5) and from absolute column 16, size-x=20. 
395   *   The position can be given without panel designation or relative, then the posParent argument is necessary.
396   * @param posParent necessary to build the absolute position from relative given sPos, maybe null if not necessary.
397   * @throws ParseException on errors of sPos or missing posParent if necessary.
398   */
399  public void setPosition(CharSequence sPos, GralPos posParent) throws ParseException {
400    GralPos posParent1;
401    //int line =0, yPosFrac =0, ye =0, yef =0, column =0, xPosFrac =0, xe =0, xef =0, origin =0, border =0, borderFrac =0;
402    Coordinate line = new Coordinate(), col = new Coordinate();
403    int  origin =0, border =0, borderFrac =0;
404    char direction = 'r';
405    if(sPos ==null) {
406      //position text not given, use refer and same size
407      line.p1 = refer;
408      line.p2 = samesize;
409      //all other values of line and col remain 0. It is default.
410      col.p1 = refer;
411      col.p2 = samesize;
412      posParent1 = posParent; 
413    } else {
414      //position given as text
415      StringPartScan spPos = new StringPartScan(sPos);
416      spPos.setIgnoreWhitespaces(true);
417      try {
418        spPos.scan("@").scanStart();  //skip over a first @
419        if(spPos.scanIdentifier().scan(",").scanOk()) {  //ckeck if a panel is given:
420          String sPanel = spPos.getLastScannedString().toString();
421          GralMng mng = GralMng.get();  //singleton.
422          GralPanelContent panel = mng.getPanel(sPanel);
423          if(panel == null) {
424            spPos.close();
425            throw new IllegalArgumentException("GralPos.setPosition - unknown panel, " + sPanel);
426          }
427          if(posParent !=null && panel == posParent.panel) {
428            posParent1 = posParent;
429          } else {
430            //only if it is another panel, remove the given parent.
431            posParent1 = new GralPos();
432          }
433        } else {
434          posParent1 = posParent;  //the parent is valid. Because no other panel. Use the current panel.
435        }
436        scanPosition(spPos, line);
437        if(spPos.scan(",").scanOk()) {
438          scanPosition(spPos, col);
439        } else {
440          col.p1 = refer;
441          col.p2 = samesize;
442        }
443      } finally {
444        spPos.close();
445      }
446    }
447    setFinePosition(line.p1, line.p1Frac, line.p2, line.p2Frac, col.p1, col.p1Frac, col.p2, col.p2Frac,  origin, direction, border, borderFrac, posParent1);
448  }
449  
450  
451  
452  /**Scans one coordinate.
453   * <pre>
454   * [[<refer>+|-]<#?p1>[.<#p2Frac>] [..|<?size>]] <#?p2>[.<#p2Frac>]
455   * </pre>
456   * If only the right number is given, p1 is {@link #refer}
457   * @param spPos
458   * @param co
459   * @throws ParseException
460   */
461  private void scanPosition(StringPartScan spPos, Coordinate co) throws ParseException {
462    char sign = spPos.seekNoWhitespace().getCurrentChar();
463    int size1; //maybe size for end element, converted to refer for start element.
464    co.p1 = next; //default, next line or next column depending on parent.
465    co.p1Frac = 0;
466    co.p2 = samesize;
467    co.p2Frac = 0;
468    //
469    if("+-".indexOf(sign) >=0){
470      size1 = size;
471      spPos.seek(1);  //skip + or -
472    } else if(sign == '%'){
473      size1 = ratio;
474      spPos.seek(1);  //skip + or -
475    } else {
476      size1 = 0;
477    }
478    if(spPos.scanInteger().scanOk()) {
479      int pos1 = (int)spPos.getLastScannedIntegerNumber();
480      if(sign == '-'){ pos1 = -pos1; }
481      co.p2 = size1 + pos1;  
482      if(spPos.scan(".").scanInteger().scanOk()) {
483        co.p2Frac = (int)(spPos.getLastScannedIntegerNumber() % 10);  //should be 0..9
484      }
485    }
486    int size2;
487    if(spPos.scan("..").scanOk()) {  //position for end is given
488      size2 = 0;  
489    } else {
490      size2 = size;
491      spPos.scan("+").scanStart();  //skip over '+', it is the separator, 
492    }
493    if(spPos.scanInteger().scanOk()) { //can start with '-' but not with '+'
494      //between 2. number is given, first is p1
495      if(size1 == size){
496        co.p1 = co.p2 - size; //stored as size for end element, but it is negative for first element.  
497      } else {
498        co.p1 = co.p2;   //ratio or absolute
499      }
500      co.p1Frac = co.p2Frac;
501      //
502      co.p2Frac = 0;  //default
503      co.p2 = size2 + (int)spPos.getLastScannedIntegerNumber();  //positive or negative. Negative means from left or bottom.
504      if(spPos.scan(".").scanInteger().scanOk()) {
505        co.p2Frac = (int)(spPos.getLastScannedIntegerNumber() % 10);  //should be 0..9
506      }
507    }
508    
509  }
510  
511  
512  
513  /**Sets the position to the given panel as container.
514   * @param panel The panel which is used as container. Its current {@link GralPanelContent#pos()} is used for relative positions
515   * @param line The line. If the parameter lineEndOrSize is designated with {@link #size} with a negative value,
516   *   it is the bottom line for the position. 
517   *   If it is designated with {@link #same} without offset and the lineEndOrSize is designated with {@link #size} 
518   *   with a negative value, the framePos {@link GralPos#y.p2} is used. If it is designated
519   *   with {@link #same} but with any offset, the {@link GralPos#y} is used as refer position, it is the top line position.
520   *   Elsewhere it is the top position.
521   * 
522   * @param lineEndOrSize Maybe designated with {@link #size} or {@link #samesize}
523   * @param column
524   * @param columnEndOrSize
525   * @param origin
526   * @param direction
527   */
528  public void setPosition(GralPanelContent panel, float line, float lineEndOrSize, float column, float columnEndOrSize
529      , int origin, char direction, float border)
530  {
531    this.panel = panel;
532    int[] pos = new int[10];
533    frac(line, pos, 0);
534    frac(lineEndOrSize, pos, 2);
535    frac(column, pos, 4);
536    frac(columnEndOrSize, pos, 6);
537    frac(border, pos, 8);
538    setFinePosition(pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6], pos[7], origin, direction, pos[8], pos[9], panel.pos());
539    /*
540    int y1 = (int)(line);
541    int y1f = frac(y1, line);
542    int y2 = (int)(lineEndOrSize);
543    int y2f = frac(y2, lineEndOrSize);
544    int x1 = (int)(column);
545    int x1f = frac(x1, column);  
546    int x2 = (int)(columnEndOrSize);
547    int x2f = frac(x2, columnEndOrSize); 
548    setFinePosition(y1, y1f, y2, y2f, x1, x1f, x2, x2f, origin, direction, framePos);
549    */
550  }
551
552  
553  
554  
555  /**Sets the position
556   * @param framePos The frame or last pos for relative positions.
557   * @param line The line. If the parameter lineEndOrSize is designated with {@link #size} with a negative value,
558   *   it is the bottom line for the position. 
559   *   If it is designated with {@link #same} without offset and the lineEndOrSize is designated with {@link #size} 
560   *   with a negative value, the framePos {@link GralPos#y.p2} is used. If it is designated
561   *   with {@link #same} but with any offset, the {@link GralPos#y} is used as refer position, it is the top line position.
562   *   Elsewhere it is the top position.
563   * 
564   * @param lineEndOrSize Maybe designated with {@link #size} or {@link #samesize}
565   * @param column
566   * @param columnEndOrSize
567   * @param origin
568   * @param direction
569   */
570  public void setPosition(GralPos framePos, float line, float lineEndOrSize, float column, float columnEndOrSize
571      , int origin, char direction, float border)
572  {
573    int[] pos = new int[10];
574    frac(line, pos, 0);
575    frac(lineEndOrSize, pos, 2);
576    frac(column, pos, 4);
577    frac(columnEndOrSize, pos, 6);
578    frac(border, pos, 8);
579    setFinePosition(pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6], pos[7], origin, direction, pos[8], pos[9], framePos);
580    /*
581    int y1 = (int)(line);
582    int y1f = frac(y1, line);
583    int y2 = (int)(lineEndOrSize);
584    int y2f = frac(y2, lineEndOrSize);
585    int x1 = (int)(column);
586    int x1f = frac(x1, column);  
587    int x2 = (int)(columnEndOrSize);
588    int x2f = frac(x2, columnEndOrSize); 
589    setFinePosition(y1, y1f, y2, y2f, x1, x1f, x2, x2f, origin, direction, framePos);
590    */
591  }
592  
593  
594  /**Returns true if this position is from right or bottom, so that a resize of the panel needs new positions for this widget.
595   */
596  public boolean toResize(){ return x.p1 < 0 || x.p2 <= 0 || y.p1< 0 || y.p2 <=0; }
597  
598  private void frac(float v, int[] pos, int ix){
599    int i, f;
600    i = (int)v;
601    if((i & mValueNegative) !=0){
602      f = (int)((v-i)*10 + 0.5f);
603      if( f == 10){ f = 0; }
604    } else {
605      f = (int)((v - i)*10 + 0.5f);
606    }
607    if(f < 0){
608      i -=1; f +=10;
609    }
610    assert(f >=0 && f <= 9);
611    pos[ix] = i; pos[ix+1]= f;
612    //return f;
613  }
614
615
616  
617  
618  
619  public void setPosition(GralPos framePos, float line, float lineEndOrSize, float column, float columnEndOrSize
620    , int origin, char direction)
621  {
622    setPosition(framePos, line, lineEndOrSize, column, columnEndOrSize, origin, direction, 0);
623  }
624  
625  
626  /**Sets the position for the next widget to add in the container.
627   * Implementation note: This is the core function to calculate positions. It is called from all other ones.
628   * @param line y-Position in y-Units, count from top of the box. It is the bottom line of the widget.
629   *              If <0, then it counts from bottom of the parent.
630   * @param column x-Position in x-Units, count from left of the box. 
631   *              If <0, then the previous position is valid still.
632   *              It < 0 then line = 0 is not a proper value. To show a text in the first line, use line=2.
633   * @param heigth: The height of the line. If <0, then the param line is the bottom line of the widget, 
634   *                and (line-height) is the top line. If 0 then the last value of height is not changed. 
635   * @param length: The number of columns. If <0, then the param column is the right column, 
636   *                and column-length is the left column. If 0 then the last value of length is not changed.
637   * @param direction: direction for a next widget, use 'r', 'l', 'u', 'd' for right, left, up, down
638   * @param parent 
639   */
640  public void setFinePosition(int line, int yPosFrac, int ye, int yef
641      , int column, int xPosFrac, int xe, int xef, int origin, char direction
642      , int border, int borderFrac
643      , GralPos parent)
644  {
645    //
646    if(yPosFrac < 0 || yPosFrac >9){
647      throw new IllegalArgumentExceptionJc("GralPos - yPosFrac error", yPosFrac);
648    }
649    if(xPosFrac < 0 || xPosFrac >9) {
650      throw new IllegalArgumentExceptionJc("GralPos - xPosFrac error", xPosFrac);
651    }
652    //
653    if(ye == (size -1) && yef == 5)
654      stop();
655    if(ye == useNatSize)
656      stop();
657    //
658    if(parent == null){ parent = this; }
659    if(origin >0 && origin <=9){
660      int yOrigin = (origin-1) /3;
661      int xOrigin = origin - yOrigin -1; //0..2
662      this.x.origin = "lmr".charAt(xOrigin);
663      this.y.origin = "tmb".charAt(yOrigin);
664    }
665    
666    y.set(line, yPosFrac, ye, yef, parent.y);
667    x.set(column, xPosFrac, xe, xef, parent.x);
668    
669    if("rl".indexOf(direction)>=0 ){
670      this.x.dirNext = direction;
671      this.y.dirNext = '.';
672      this.x.pb = border;
673      this.x.pbf = borderFrac;
674      this.y.pb = this.y.pbf = 0;
675    } else if("ud".indexOf(direction)>=0 ){
676      this.y.dirNext = direction;
677      this.x.dirNext = '.';
678      this.y.pb = border;
679      this.y.pbf = borderFrac;
680      this.x.pb = this.x.pbf = 0;
681    } else {
682      this.x.dirNext = parent.x.dirNext;
683      this.y.dirNext = parent.y.dirNext;
684      this.x.pb = parent.x.pb; this.x.pbf = parent.x.pbf;
685      this.y.pb = parent.y.pb; this.y.pbf = parent.y.pbf;
686    }
687    assert(x.p1Frac >=0 && x.p1Frac < 10 && y.p1Frac >=0 && y.p1Frac < 10 );
688    assert(x.p2Frac >=0 && x.p2Frac < 10 && y.p2Frac >=0 && y.p2Frac < 10 );
689  }
690  
691  
692  
693  
694  public void setSize(int height, int ySizeFrac, int width, int xSizeFrac)
695  {
696    if(height !=0){
697      //ySize = height >0 ? height : -height;
698      //this.ySizeFrac = ySizeFrac;
699    }
700    if(width !=0){
701      //xSize = width >0 ? width: -width;
702      //this.xSizeFrac = xSizeFrac;
703    }
704    if(height >0){ this.y.origin = 't'; }
705    else if(height < 0){ this.y.origin = 'b'; }
706    else; //let it unchanged if height == 0
707    if(width >0){ this.x.origin = 'l'; }
708    else if(width < 0){ this.x.origin = 'r'; }
709    else; //let it unchanged if width == 0
710  }
711  
712  
713  public void setSize(float height, float width, GralPos frame)
714  { 
715    int y2 = (int)(height);
716    int y2f = y2 >=0 ? (int)((height - y2)* 10.001F) : (int)((height - y2)* -10.001F);  
717    int x2 = (int)(width);
718    int x2f = x2 >=0 ? (int)((width - x2)* 10.001F) : (int)((width - x2)* -10.001F); 
719    setFinePosition(GralPos.next, 0,  y2 + GralPos.size, y2f, GralPos.next, 0, x2 + GralPos.size, x2f, 0, '.', 0, 0, frame);
720  }
721  
722  
723  /**Sets the position to the next adequate the {@link #pos.dirNext}. */
724  public void setNextPosition()
725  {
726    setPosition(this, next, samesize, next, samesize, 0, '.', 0 );
727    /*
728    float dx3 = this.width();
729    float dy3 = this.height();
730    int dx = (int)dx3;
731    int dxf = (int)((dx3 - dx) * 10.001F) + this.x.p2Frac;
732    if(dxf >= 10){ dxf -=10; dx +=1; }
733    int dy = (int)dy3;
734    int dyf = (int)((dy3 - dy) * 10.001F) + this.y.p2Frac;
735    if(dyf >= 10){ dyf -=10; dy +=1; }
736    switch(this.dirNext){
737    case 'r': this.x = this.x.p2; this.x.p1Frac = this.x.p2Frac; this.x.p2 = this.x + dx; this.x.p2Frac = dxf; break;
738    case 'd': this.y = this.y.p2; this.y.p1Frac = this.y.p2Frac; this.y.p2 = this.y + dy; this.y.p2Frac = dyf; break;
739    }
740    */
741  }
742  
743
744  
745  
746  
747  
748  
749  public float height()
750  { float height;
751    if(y.p1 * y.p2 >= 0){
752      height = y.p2 - y.p1;
753      if((y.attr & mBitSizeNeg)!=0) {
754        height = -height;
755      }
756    }
757    else{ 
758      height = 2.0F;  //not able to determine, use default.
759    }
760    height += (y.p2Frac - y.p1Frac) * 0.1F;
761    return height;
762  }
763  
764  
765  public float width()
766  { float width;
767    if(y.p1 > 0 && x.p2 > 0){ width = x.p2 - y.p1 + (x.p2Frac - x.p1Frac) * 0.1F; }
768    else if(x.p1 < 0 && x.p2 < 0){ width = x.p2 - x.p1 + (x.p2Frac - x.p1Frac) * 0.1F; }
769    else { width = 0.0F; } //not able to determine, use default.
770    return width;
771  }
772  
773  
774  
775  
776  
777  
778  @Override public GralPos clone(){
779    //Hint: Object.clone() can't be used because it clones the references of x and y and not its values. 
780    GralPos newObj = new GralPos();
781    newObj.x.set(x);
782    newObj.y.set(y);
783    newObj.panel = panel;
784    //try{ newObj = (GralGridPos)super.clone(); 
785    //} catch(CloneNotSupportedException exc){ assert(false); }
786    return newObj; 
787  }
788  
789  
790  
791  
792  public GralPos setNextPos(String posString) throws ParseException {
793    if(posString.equals("!")) {  //new window, initialize the position without panel because it is top.
794      panel = null;
795      setFinePosition(0,0,0,0,0,0,0,0,0,'d', 0,0, null);
796    } else {
797      setPosition(posString, this);
798      //TODO change pos:
799    }
800    return clone();  //return the pos as clone, to use as posWidg  
801  }
802  
803  
804  
805  
806  
807
808  
809  
810  /**Calculates the position and size of a widget from this given Pos.
811   * @param propertiesGui The properties for presentation.
812   * @param widthParentPixel width of the container. This value will be used if the position is given 
813   *   from right with negative numbers.
814   * @param heightParentPixel height of the container. This value will be used if the position is given 
815   *   from bottom with negative numbers.
816   * @param widthWidgetNat natural width of the component which will be positioning. 
817   *   This value is used only if the pos parameter contains {@link GralPos#useNatSize} for the xe-value
818   * @param heightWidgetNat natural height of the component which will be positioning. 
819   *   This value is used only if the pos parameter contains {@link GralPos#useNatSize} for the ye-value
820   * @return A rectangle for setBounds.
821   */
822  public GralRectangle calcWidgetPosAndSize(GralGridProperties propertiesGui,
823      int widthParentPixel, int heightParentPixel,
824      int widthWidgetNat, int heightWidgetNat
825  )
826  {
827    int xPixelUnit = propertiesGui.xPixelUnit();
828    int yPixelUnit = propertiesGui.yPixelUnit();
829    //calculate pixel
830    final int x1,y1, x2, y2;
831    ///
832    
833    x1 = xPixelUnit * this.x.p1 + propertiesGui.xPixelFrac(this.x.p1Frac)  //negative if from right
834       + (this.x.p1 < 0 ? widthParentPixel : 0);  //from right
835    y1 = yPixelUnit * this.y.p1 + propertiesGui.yPixelFrac(this.y.p1Frac)  //negative if from right
836       + (this.y.p1 < 0 ? heightParentPixel : 0);  //from right
837    if(this.x.p2 == GralPos.useNatSize){
838      x2 = x1 + widthWidgetNat; 
839    } else {
840      x2 = xPixelUnit * this.x.p2 + propertiesGui.xPixelFrac(this.x.p2Frac)  //negative if from right
841         + (this.x.p2 < 0 || this.x.p2 == 0 && this.x.p2Frac == 0 ? widthParentPixel : 0);  //from right
842    }
843    if(this.x.p2 == GralPos.useNatSize){
844      y2 = y1 + heightWidgetNat; 
845    } else {
846      y2 = yPixelUnit * this.y.p2 + propertiesGui.yPixelFrac(this.y.p2Frac)  //negative if from right
847         + (this.y.p2 < 0  || this.y.p2 == 0 && this.y.p2Frac == 0 ? heightParentPixel : 0);  //from right
848    }
849    GralRectangle rectangle = new GralRectangle(x1, y1, x2-x1-1, y2-y1-1);
850    return rectangle;
851  }
852
853
854
855
856  private static void appendPos(StringBuilder b, int p, int pFrac)
857  {
858    if(pFrac >0) {
859      if(p < 0) { b.append(p-1); } else { b.append(p); }
860      b.append('.').append(pFrac);
861    } else {
862      b.append(p);
863    }
864  }
865
866
867  
868  
869  public String posString() 
870  { StringBuilder b = new StringBuilder(16);
871    b.append('@');
872    if(panel != null) {
873      b.append(panel.name).append(", ");
874    }
875    appendPos(b, y.p1, y.p1Frac);
876    b.append("..");
877    appendPos(b, y.p2, y.p2Frac);
878    b.append(",");
879    appendPos(b, x.p1, x.p1Frac);
880    b.append("..");
881    appendPos(b, x.p2, x.p2Frac);
882    return b.toString();
883  }
884  
885  /**Use especially for debug.
886   * @see java.lang.Object#toString()
887   */
888  @Override public String toString()
889  { return "panel=" + (panel == null ? "?" : panel.toString()) + ", "
890    +"line=" + y.p1 + "." + y.p1Frac + ".." + y.p2 + "." + y.p2Frac + " col=" + x.p1 + "." + x.p1Frac + ".." + x.p2 + "." + x.p2Frac + " " + x.dirNext + y.dirNext + y.origin + x.origin;
891  }
892
893  
894  
895  void stop(){}
896
897  
898  /**Class holds values for either x or y. Both values are calculated with adequate algorithms,
899   * so that algorithm is written only one time but called 2 times for x and for y.
900   * 
901   *
902   */
903  public static class Coordinate
904  {
905    /**The start position for the spread. 
906     * If there are positive numbers, they count from left to right respectively top to bottom. 
907     * If the value is negative, the absolute is the distance from right respectively bottom. 
908     */
909    public int p1;
910    
911    /**The end position for the spread. 
912     * If there are positive numbers, they count from left to right respectively top to bottom. 
913     * If the value is negative or 0, the absolute is the distance from right respectively bottom. 
914     */
915    public int p2;
916    
917    /**Start Position in percent. If -1 then not used.
918     * 
919     */
920    int n1 = -1;
921    ///
922    /**End Position in percent. */
923    int n2;
924    
925    /**Fractional parts of position. Use 0..9 only. 
926     * The fractional part counts from left to right respectively top to bottom 
927     * independent of the sign of p1, p2.
928     */
929    public int p1Frac, p2Frac;
930    
931    /**Additional border value for {@link GralPos#next}. */
932    public int pb, pbf;
933    
934    /**Attributes of this coordinate. */
935    public int attr;
936    
937    char origin;
938    
939    /**direction of the next element. Use r, d, l, u. */
940    public char dirNext;
941
942    
943    /**Relation of x and y left and top to any separation line. 0 - relation to left and top border. 
944     * TODO the sepLine is planned but not used yet. 2012-01-31 */
945    public int sepLine;
946    /**Relation of xEnd and yEnd right and bottom to any separation line. 
947     * 0 - relation to left and top border. 
948     * positive Index: separation line with this index is left or top. Typical it may be the same index
949     * then for left top position.
950     * negative Index: separation line with negate value as index is right or bottom. */
951    public int endSepLine;
952
953    /**Sets the new position for this coordinate.
954     * @param z1
955     * @param z1Frac
956     * @param z2
957     * @param z2Frac
958     * @param parent The refer position. Note that parent may be == this because the new position based on the current.
959     */
960    public Coordinate set(final int z1, final int z1Frac, final int z2, final int z2Frac, final Coordinate parent)
961    {
962      /**User final local variable to set p, pf, pe, pef to check whether all variants are regarded. */
963      final int q1, q1Frac, q2, q2Frac;
964
965      //check input parameter ze of size and negative size
966      
967      //The type of input parameter.
968      final boolean zNeg =  (z1 & mValueNegative) !=0;
969      final int zType = (z1 & mSpecialType) == kSpecialType ? z1 : (z1 + kTypAdd_) & mType_;
970      final boolean zeNeg =  (z2 & mValueNegative) !=0;
971      final int zeType = (z2 & mSpecialType) == kSpecialType ? z2 : (z2 + kTypAdd_) & mType_;
972      final int testCase;
973      final int testType = (zType<<16) + zeType;
974      if(parent !=this){
975        pb = parent.pb; pbf = parent.pbf;
976      }
977      switch(testType){
978        //
979        case 0: {
980          testCase = 1;
981          q1 = z1; q1Frac = z1Frac;                         //q = z
982          q2 = z2; q2Frac = z2Frac;                     //qe = ze
983        } break;
984        //
985        case 0 + refer: {
986          testCase = 2;                           //q = z
987          q1 = z1; q1Frac = z1Frac;                         //qe = pe + refer
988          q2 = parent.p2 + (z2 - refer); q2Frac = parent.p2Frac + z2Frac;
989        } break;
990        //
991        case 0 + size: {
992          testCase = 3;
993          if(zeNeg){ 
994            q2 = z1; q2Frac = z1Frac;                    //qe = z
995            q1 = q2 + (z2 - size); q1Frac = q2Frac + z2Frac;   //q = qe + size
996          } else {
997            q1 = z1; q1Frac = z1Frac;                       //q = z
998            q2 = q1 + (z2 - size); q2Frac = q1Frac +z2Frac;  //qe = q + size
999          }
1000        } break;
1001        //
1002        case 0 + samesize: {
1003          testCase = 4;
1004          if( (attr & mBitSizeNeg) !=0){     //was the last size negative? the qe is base
1005            q2 = z1; q2Frac = z1Frac;                     //qe = z
1006            q1 = q2 - (parent.p2 - parent.p1) + (z2 - samesize);  //q = qe - lastsize + sizediff 
1007            q1Frac = q2Frac + (parent.p2Frac - parent.p1Frac) + z2Frac;
1008          } else {
1009            q1 = z1; q1Frac = z1Frac;                       //q = z 
1010            q2 = q1 + (parent.p2 - parent.p1) + (z2 - samesize);  //qe = q + lastsize + sizediff 
1011            q2Frac = q1Frac + (parent.p2Frac - parent.p1Frac) + z2Frac;
1012          }
1013        } break;
1014        //
1015        case 0 + useNatSize: {
1016          testCase = 11;
1017          q1 = z1; q1Frac = z1Frac;
1018          q2 = z2;  q2Frac = 0; //store useNatSize
1019        } break;
1020        //
1021        case (refer<<16) + 0: {
1022          testCase = 5;
1023          q1 = parent.p1 + (z1 - refer); q1Frac = parent.p1Frac + z1Frac;      //q = p + refer 
1024          q2 = z2; q2Frac = z2Frac;                     //qe = ze
1025        } break;
1026        //
1027        case (refer<<16) + refer: {
1028          testCase = 1;
1029          q1 = parent.p1 + (z1 - refer); q1Frac = parent.p1Frac + z1Frac;        //q = parent.p + refer
1030          q2 = parent.p2 + (z2 - refer); q2Frac = parent.p2Frac + z2Frac;  //qe = parent.pe + refer
1031        } break;
1032        //
1033        case (refer<<16) + size: {
1034          testCase = 6;
1035          if(zeNeg){ 
1036            q2 = parent.p2 + (z1 - refer); q2Frac = parent.p2Frac + z1Frac; //qe = parent.pe + refer, z is the bottom/right pos 
1037            q1 = q2 + (z2 - size); q1Frac = q2Frac + z2Frac;     //q = qe - size
1038          } else {
1039            q1 = parent.p1 + z1 - refer; q1Frac = parent.p1Frac + z1Frac;        //q = parent.p + refer
1040            q2 = q1 + (z2 - size); q2Frac = q1Frac + z2Frac;   //qe = q + size
1041          }
1042        } break;
1043        //
1044        case (refer<<16) + samesize: {
1045          testCase = 7;
1046          if( (attr & mBitSizeNeg) !=0){       
1047            q1 = z1 - (parent.p2 - parent.p1) + z2 - samesize; q1Frac = z1Frac - (parent.p2Frac - parent.p1Frac);
1048            q2 = parent.p2 + z1 - refer; q2Frac = z2Frac; 
1049          } else {
1050            q1 = parent.p1 + (z1 - refer); q1Frac = parent.p1Frac + z1Frac;      //q = parent.p + refer
1051            q2 = q1 + (parent.p2 - parent.p1) + (z2 - samesize);    //qe = q + lastsize + sizediff 
1052            q2Frac = q1Frac + (parent.p2Frac - parent.p1Frac) + z2Frac;
1053          }
1054        } break;
1055        //
1056        case (next<<16) + refer: {
1057          testCase = 8;
1058          q1 = parent.p2 + parent.pb; q1Frac = parent.p2Frac + parent.pbf;              //q = parent.pe + parent.pb  the next right/down
1059          q2 = q1 + (parent.p2 - parent.p1) + (z2 - refer); q2Frac = q1Frac + (parent.p2Frac - parent.p1Frac) + z2Frac;     //qe = q + (parent.pe - parent.p) + refer  
1060        } break;
1061        //
1062        case (next<<16) + size: {
1063          testCase = 10;
1064          //switch(dirNext){
1065          switch(parent.dirNext){
1066              case 'r': case 'd': {
1067              if( (attr & mBitSizeNeg) !=0){ 
1068                q2 = parent.p2 + parent.pb; q2Frac = parent.p2Frac + parent.pbf; 
1069                q1 = q2 - (parent.p2 - parent.p1) + (z2 - size); q1Frac = q2Frac - (parent.p2Frac - parent.p1Frac) + z2Frac;
1070              } else {                               //same as next, refer
1071                q1 = parent.p2 + parent.pb; q1Frac = parent.p2Frac + parent.pbf;         //q = parent.pe + parent.pb the next right/down
1072                q2 = q1 + z2 - size; q2Frac = q1Frac + z2Frac; 
1073              }
1074            } break;
1075            //
1076            default: {
1077              q1 = parent.p1; q1Frac = parent.p1Frac; q2 = parent.p2; q2Frac = parent.p2Frac;  //don't change this coordinate. It may be the other one.              
1078            }
1079          }
1080        } break;
1081        //
1082        case (next<<16) + samesize: {  //z1 is next, ze is samesize, means typical next
1083          testCase = 9;
1084          switch(parent.dirNext){
1085            case 'r': case 'd': {
1086              if( (attr & mBitSizeNeg) !=0){ 
1087                q2 = parent.p2 + (parent.p2 - parent.p1) + parent.pb; q2Frac = parent.p2Frac + (parent.p2Frac - parent.p1Frac) + parent.pbf; 
1088                q1 = q2 - (parent.p2 - parent.p1) + (z2 - samesize); q1Frac = q2Frac - (parent.p2Frac - parent.p1Frac) + z2Frac;
1089              } else {                               //same as next, refer
1090                q1 = parent.p2 + parent.pb; q1Frac = parent.p2Frac + parent.pbf;         //q = parent.pe + parent.pb the next right/down
1091                q2 = q1 + (parent.p2 - parent.p1) + z2 - samesize; q2Frac = q1Frac + (parent.p2Frac - parent.p1Frac) + z2Frac; 
1092              }
1093            } break;
1094            //
1095            default: {
1096              q1 = parent.p1; q1Frac = parent.p1Frac; q2 = parent.p2; q2Frac = parent.p2Frac;  //don't change this coordinate. It may be the other one.              
1097            }
1098          }
1099        } break;
1100        default: 
1101          assert(false);
1102          testCase = 12;
1103          q1 = z1; q1Frac = z1Frac; 
1104          q2 = z2; q2Frac = z2Frac;
1105      }
1106      
1107      if(!(q1 <= q2 || q2 <=0)){
1108        throw new IllegalArgumentException("start > end " + q1 + " > " + q2);
1109      }
1110      if(!(q1 > -1000 && q1 < 1000 && ((q2 > -1000 && q2 < 1000) || ((q2 - useNatSize) >=0 && (q2 - useNatSize) < 8192)))){
1111        throw new IllegalArgumentException("positions out of range" + q1 + ", " + q2);
1112      }
1113      if(q1Frac >= 20){  //can be on adding distance
1114        this.p1 = q1 +2; this.p1Frac = q1Frac -20;
1115      } else if(q1Frac >= 10){
1116          this.p1 = q1 +1; this.p1Frac = q1Frac -10;
1117      } else if(q1Frac < 0){
1118        this.p1 = q1 - 1; this.p1Frac = q1Frac +10;
1119      } else {
1120        this.p1 = q1; this.p1Frac = q1Frac;   
1121      }
1122      if(q2Frac >= 20){
1123        this.p2 = q2 +2; this.p2Frac = q2Frac -20;
1124      } else if(q2Frac >= 10){
1125        this.p2 = q2 +1; this.p2Frac = q2Frac -10;
1126      } else if(q2Frac < 0){
1127        this.p2 = q2 - 1; this.p2Frac = q2Frac +10;
1128      } else {
1129        this.p2 = q2; this.p2Frac = q2Frac;   
1130      }
1131      if(!(p1Frac >=0 && p1Frac <=9 && p2Frac >=0 && p2Frac <=9 )){
1132        throw new IllegalArgumentException("Fractional position failure: " + p1Frac + ", " + p2Frac);
1133      }
1134      return this;
1135    }//set
1136
1137
1138    /**Copies all values. Hint: clone isn't able to use because the instance in parent is final.
1139     * @param src
1140     */
1141    void set(Coordinate src){
1142      p1 = src.p1; p1Frac = src.p1Frac; p2 = src.p2; p2Frac = src.p2Frac;
1143      pb = src.pb; pbf = src.pbf; attr = src.attr; origin = src.origin; dirNext = src.dirNext;
1144      sepLine = src.sepLine; endSepLine = src.endSepLine;
1145    }
1146    
1147    
1148    ///
1149    /**Calculate from size to pixel. 
1150     * 
1151     */
1152    void calc(int[] dst, int dparent, int dnat, int xPixelUnit, int[] xPixelFrac){
1153      int x1, x2;  //begin, end
1154      int min, max;
1155      
1156      //maximum of width
1157      x1 = xPixelUnit * p1 + xPixelFrac[p1Frac]  //negative if from right
1158      + (p1 < 0 ? dparent : 0);  //from right
1159      if(p2 == GralPos.useNatSize){
1160        x2 = x1 + dnat; 
1161      } else {
1162       x2 = xPixelUnit * p2 + xPixelFrac[p2Frac]  //negative if from right
1163          + (p2 < 0 || p2 == 0 && p2Frac == 0 ? dparent : 0);  //from right
1164      }
1165     
1166      
1167      if(n1 >=0 && ((1000 * (x2 - x1))/dparent) > (n2 - n1) ){
1168        //The percent size is less then the maximum size, use it.
1169        x1 = n1 * dparent; 
1170        x2 = n2 * dparent;
1171        max = xPixelUnit * p2;
1172        min = xPixelUnit * p1;
1173      }
1174    }
1175    
1176  }
1177  
1178  
1179  public static void testScanSize(){
1180    GralPos posParent = new GralPos();
1181    GralPos posTest = new GralPos();
1182    try{
1183      posParent.setPosition("@3+2, 10+10", null);  //line 3, column 10 + 10
1184      posTest.setPosition(",+12", posParent);       //line 3, column 20 + 12
1185      Assert.checkMsg(posParent.y.p1 == 3 && posParent.y.p2 == 5 && posParent.x.p1 == 10 && posParent.x.p2 == 20 , "posParent failure");
1186      Assert.checkMsg(posTest.y.p1 == 3   && posTest.y.p2 == 5   && posTest.x.p1 == 20   && posTest.x.p2 == 32 , "posTest failure");  //next, size=12
1187    } catch(ParseException exc) {
1188      System.err.println("GralPos.testScanSize - error, " + exc.getMessage());
1189    }
1190    
1191  }
1192}