//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.ui.layout;

import playn.core.Asserts;

import pythagoras.f.Dimension;
import pythagoras.f.IDimension;
import pythagoras.f.IPoint;
import pythagoras.f.Point;
import pythagoras.f.Rectangle;

import tripleplay.ui.Element;
import tripleplay.ui.Elements;
import tripleplay.ui.Layout;

/**
 * A layout that positions elements at absolute coordinates (at either their preferred size or at a
 * manually specified size). Constraints are specified like so:
 * <pre>{@code
 * Group group = new Group(new AbsoluteLayout()).add(
 *     AbsoluteLayout.at(new Label("+50+50"), 50, 50),
 *     AbsoluteLayout.at(new Button("100x50+25+25"), 25, 25, 100, 50)
 * );
 * }</pre>
 */
public class AbsoluteLayout extends Layout
{
    /** Defines absolute layout constraints. */
    public static final class Constraint extends Layout.Constraint {
        public final IPoint position;
        public final IDimension size;

        public Constraint (IPoint position, IDimension size) {
            this.position = position;
            this.size = size;
        }
    }

    /**
     * Constrains {@code elem} to the specified position, in its preferred size.
     */
    public static <T extends Element<?>> T at (T elem, float x, float y) {
        return at(elem, new Point(x, y));
    }

    /**
     * Constraints {@code elem} to the specified position, in its preferred size.
     */
    public static <T extends Element<?>> T at (T elem, IPoint position) {
        return at(elem, position, new Dimension(0, 0));
    }

    /**
     * Constrains {@code elem} to the specified position and size.
     */
    public static <T extends Element<?>> T at (T elem, float x, float y, float width, float height) {
        return at(elem, new Point(x, y), new Dimension(width, height));
    }

    /**
     * Constrains {@code elem} to the specified position and size.
     */
    public static <T extends Element<?>> T at (T elem, IPoint position, IDimension size) {
        elem.setConstraint(new Constraint(position, size));
        return elem;
    }

    @Override public Dimension computeSize (Elements<?> elems, float hintX, float hintY) {
        // report a size large enough to contain all of our elements
        Rectangle bounds = new Rectangle();
        for (Element<?> elem : elems) {
            if (!elem.isVisible()) continue;
            Constraint c = constraint(elem);
            IDimension psize = preferredSize(elem, c.size.width(), c.size.height());
            bounds.add(new Rectangle(c.position, c.size.width() == 0 ? psize : c.size));
        }
        return new Dimension(bounds.width, bounds.height);
    }

    @Override public void layout (Elements<?> elems,
                                  float left, float top, float width, float height) {
        for (Element<?> elem : elems) {
            if (!elem.isVisible()) continue;
            Constraint c = constraint(elem);
            if (c.size.width() == 0) {
                // this should return a cached size
                IDimension psize = preferredSize(elem, 0, 0);
                setBounds(elem, c.position.x(), c.position.y(), psize.width(), psize.height());
            } else {
                setBounds(elem, c.position.x(), c.position.y(), c.size.width(), c.size.height());
            }
        }
    }

    protected static Constraint constraint (Element<?> elem) {
        return (Constraint)Asserts.checkNotNull(
            elem.constraint(), "Elements in AbsoluteLayout must have a constraint.");
    }
}

@@ -3096,51 +3096,8 @@
 m);%0A
-            if (c.size.width() == 0) %7B%0A    
     
@@ -3144,36 +3144,32 @@
 ize%0A            
-    
 IDimension psize
@@ -3162,32 +3162,54 @@
 imension psize =
+ c.size.width() == 0 ?
  preferredSize(e
@@ -3218,22 +3218,27 @@
 m, 0, 0)
-;%0A    
+ : c.size;%0A
         
@@ -3248,32 +3248,39 @@
  setBounds(elem,
+ left +
  c.position.x(),
@@ -3271,32 +3271,38 @@
  c.position.x(),
+ top +
  c.position.y(),
@@ -3305,128 +3305,32 @@
 y(),
- psize.width(), psize.height());%0A            %7D else %7B%0A                setBounds(elem, c.position.x(), c.position.y(), c.
+%0A                      p
 size
@@ -3331,34 +3331,33 @@
  psize.width(), 
-c.
+p
 size.height());%0A
@@ -3360,22 +3360,8 @@
 ));%0A
-            %7D%0A
     

Use background insets