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 17package com.badlogic.gdx.scenes.scene2d.ui; 18 19import com.badlogic.gdx.graphics.g2d.Batch; 20import com.badlogic.gdx.scenes.scene2d.Actor; 21import com.badlogic.gdx.scenes.scene2d.Group; 22import com.badlogic.gdx.scenes.scene2d.Stage; 23import com.badlogic.gdx.scenes.scene2d.Touchable; 24import com.badlogic.gdx.scenes.scene2d.utils.Layout; 25import 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 */ 37public 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