    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}