Home | History | Annotate | Download | only in ui
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.scenes.scene2d.ui;
     18 
     19 import com.badlogic.gdx.graphics.g2d.Batch;
     20 import com.badlogic.gdx.scenes.scene2d.Actor;
     21 import com.badlogic.gdx.scenes.scene2d.Group;
     22 import com.badlogic.gdx.scenes.scene2d.Stage;
     23 import com.badlogic.gdx.scenes.scene2d.Touchable;
     24 import com.badlogic.gdx.scenes.scene2d.utils.Layout;
     25 import com.badlogic.gdx.utils.SnapshotArray;
     26 
     27 /** A {@link Group} that participates in layout and provides a minimum, preferred, and maximum size.
     28  * <p>
     29  * The default preferred size of a widget group is 0 and this is almost always overridden by a subclass. The default minimum size
     30  * returns the preferred size, so a subclass may choose to return 0 for minimum size if it wants to allow itself to be sized
     31  * smaller than the preferred size. The default maximum size is 0, which means no maximum size.
     32  * <p>
     33  * See {@link Layout} for details on how a widget group should participate in layout. A widget group's mutator methods should call
     34  * {@link #invalidate()} or {@link #invalidateHierarchy()} as needed. By default, invalidateHierarchy is called when child widgets
     35  * are added and removed.
     36  * @author Nathan Sweet */
     37 public class WidgetGroup extends Group implements Layout {
     38 	private boolean needsLayout = true;
     39 	private boolean fillParent;
     40 	private boolean layoutEnabled = true;
     41 
     42 	public WidgetGroup () {
     43 	}
     44 
     45 	/** Creates a new widget group containing the specified actors. */
     46 	public WidgetGroup (Actor... actors) {
     47 		for (Actor actor : actors)
     48 			addActor(actor);
     49 	}
     50 
     51 	public float getMinWidth () {
     52 		return getPrefWidth();
     53 	}
     54 
     55 	public float getMinHeight () {
     56 		return getPrefHeight();
     57 	}
     58 
     59 	public float getPrefWidth () {
     60 		return 0;
     61 	}
     62 
     63 	public float getPrefHeight () {
     64 		return 0;
     65 	}
     66 
     67 	public float getMaxWidth () {
     68 		return 0;
     69 	}
     70 
     71 	public float getMaxHeight () {
     72 		return 0;
     73 	}
     74 
     75 	public void setLayoutEnabled (boolean enabled) {
     76 		if (layoutEnabled == enabled) return;
     77 		layoutEnabled = enabled;
     78 		setLayoutEnabled(this, enabled);
     79 	}
     80 
     81 	private void setLayoutEnabled (Group parent, boolean enabled) {
     82 		SnapshotArray<Actor> children = parent.getChildren();
     83 		for (int i = 0, n = children.size; i < n; i++) {
     84 			Actor actor = children.get(i);
     85 			if (actor instanceof Layout)
     86 				((Layout)actor).setLayoutEnabled(enabled);
     87 			else if (actor instanceof Group) //
     88 				setLayoutEnabled((Group)actor, enabled);
     89 		}
     90 	}
     91 
     92 	public void validate () {
     93 		if (!layoutEnabled) return;
     94 
     95 		Group parent = getParent();
     96 		if (fillParent && parent != null) {
     97 			float parentWidth, parentHeight;
     98 			Stage stage = getStage();
     99 			if (stage != null && parent == stage.getRoot()) {
    100 				parentWidth = stage.getWidth();
    101 				parentHeight = stage.getHeight();
    102 			} else {
    103 				parentWidth = parent.getWidth();
    104 				parentHeight = parent.getHeight();
    105 			}
    106 			if (getWidth() != parentWidth || getHeight() != parentHeight) {
    107 				setWidth(parentWidth);
    108 				setHeight(parentHeight);
    109 				invalidate();
    110 			}
    111 		}
    112 
    113 		if (!needsLayout) return;
    114 		needsLayout = false;
    115 		layout();
    116 	}
    117 
    118 	/** Returns true if the widget's layout has been {@link #invalidate() invalidated}. */
    119 	public boolean needsLayout () {
    120 		return needsLayout;
    121 	}
    122 
    123 	public void invalidate () {
    124 		needsLayout = true;
    125 	}
    126 
    127 	public void invalidateHierarchy () {
    128 		invalidate();
    129 		Group parent = getParent();
    130 		if (parent instanceof Layout) ((Layout)parent).invalidateHierarchy();
    131 	}
    132 
    133 	protected void childrenChanged () {
    134 		invalidateHierarchy();
    135 	}
    136 
    137 	protected void sizeChanged () {
    138 		invalidate();
    139 	}
    140 
    141 	public void pack () {
    142 		setSize(getPrefWidth(), getPrefHeight());
    143 		validate();
    144 		// Some situations require another layout. Eg, a wrapped label doesn't know its pref height until it knows its width, so it
    145 		// calls invalidateHierarchy() in layout() if its pref height has changed.
    146 		if (needsLayout) {
    147 			setSize(getPrefWidth(), getPrefHeight());
    148 			validate();
    149 		}
    150 	}
    151 
    152 	public void setFillParent (boolean fillParent) {
    153 		this.fillParent = fillParent;
    154 	}
    155 
    156 	public void layout () {
    157 	}
    158 
    159 	/** If this method is overridden, the super method or {@link #validate()} should be called to ensure the widget group is laid
    160 	 * out. */
    161 	public void draw (Batch batch, float parentAlpha) {
    162 		validate();
    163 		super.draw(batch, parentAlpha);
    164 	}
    165 }
    166