001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.graphics.Color; 004import com.badlogic.gdx.scenes.scene2d.Group; 005import squidpony.panel.IColoredString; 006import squidpony.panel.ICombinedPanel; 007import squidpony.panel.ISquidPanel; 008 009import java.util.LinkedList; 010import java.util.List; 011 012 013/** 014 * An implementation of {@link ICombinedPanel} that extends libGDX's Group. 015 * If you're a new user or need only a foreground and background, it's 016 * likely what you should use. 017 * 018 * this is a concrete implementation of {@link ICombinedPanel} that you should 019 * use if you're concretely in need of a panel to display/write to, without 020 * doing fancy GUI stuff. Because it extends libGDX's {@link Group}, it 021 * offers a lot of features. 022 * 023 * @see SquidLayers for a more advanced Group that supports multiple layers. 024 * @author smelC 025 */ 026public class GroupCombinedPanel<T> extends Group implements ICombinedPanel<T> { 027 028 protected/* @Nullable */ISquidPanel<T> bg; 029 protected/* @Nullable */ISquidPanel<T> fg; 030 031 /** The width, in cell sizes */ 032 protected int gridWidth = -1; 033 034 /** The height, in cell sizes */ 035 protected int gridHeight = -1; 036 037 /** 038 * @param bg 039 * The backing background panel. Typically a SquidPanel from this package. 040 * @param fg 041 * The backing foreground panel. Typically a SquidPanel from this package. 042 * @param gridWidth 043 * The width of this panel, used for {@link #fillBG(Object)} 044 * (so that it fills within {@code [0, width)}). 045 * @param gridHeight 046 * The height of this panel, used for {@link #fillBG(Object)} 047 * (so that it fills within {@code [0, height)}). 048 * @throws IllegalStateException 049 * In various cases of errors regarding sizes of panels. 050 */ 051 public GroupCombinedPanel(ISquidPanel<T> bg, ISquidPanel<T> fg, 052 int gridWidth, int gridHeight) { 053 if (bg.gridWidth() != fg.gridWidth()) 054 throw new IllegalStateException( 055 "Cannot build a combined panel with backers of different widths"); 056 if (bg.gridHeight() != fg.gridHeight()) 057 throw new IllegalStateException( 058 "Cannot build a combined panel with backers of different heights"); 059 060 this.bg = bg; 061 this.fg = fg; 062 if (gridWidth < 0) 063 throw new IllegalStateException("Cannot create a panel with a negative width"); 064 this.gridWidth = gridWidth; 065 if (gridHeight < 0) 066 throw new IllegalStateException("Cannot create a panel with a negative height"); 067 this.gridHeight = gridHeight; 068 069 addActors(); 070 } 071 072 /** 073 * Constructor that defer providing the backing panels. Useful for 074 * subclasses that compute their size after being constructed. Use 075 * {@link #setPanels(ISquidPanel, ISquidPanel)} to set the panels 076 * (required before calling any {@code put} method). 077 * 078 * <p> 079 * Width and height are computed using the provided panels. 080 * </p> 081 */ 082 public GroupCombinedPanel() { 083 } 084 085 /** 086 * Sets the backing panels. 087 * 088 * @param bg Typically a SquidPanel from this package. 089 * @param fg Typically a SquidPanel from this package. 090 */ 091 public void setPanels(ISquidPanel<T> bg, ISquidPanel<T> fg) { 092 if (this.bg != null) 093 throw new IllegalStateException("Cannot change the background panel"); 094 this.bg = bg; 095 096 if (this.fg != null) 097 throw new IllegalStateException("Cannot change the foreground panel"); 098 this.fg = fg; 099 100 if (bg.gridWidth() != fg.gridWidth()) 101 throw new IllegalStateException( 102 "Cannot build a combined panel with backers of different widths"); 103 if (bg.gridHeight() != fg.gridHeight()) 104 throw new IllegalStateException( 105 "Cannot build a combined panel with backers of different heights"); 106 107 this.gridWidth = bg.gridWidth(); 108 this.gridHeight = bg.gridHeight(); 109 110 addActors(); 111 } 112 113 @Override 114 public void putFG(int x, int y, char c) { 115 checkFG(); 116 fg.put(x, y, c); 117 } 118 119 @Override 120 public void putFG(int x, int y, char c, T color) { 121 checkFG(); 122 fg.put(x, y, c, color); 123 } 124 125 @Override 126 public void putFG(int x, int y, String string, T foreground) { 127 checkFG(); 128 fg.put(x, y, string, foreground); 129 } 130 131 @Override 132 public void putFG(int x, int y, IColoredString<? extends T> cs) { 133 checkFG(); 134 fg.put(x, y, cs); 135 } 136 137 @Override 138 public void putBG(int x, int y, T color) { 139 checkBG(); 140 bg.put(x, y, color); 141 } 142 143 public void put(int x, int y, char c, T foreground, T background) 144 { 145 checkFG(); 146 checkBG(); 147 bg.put(x, y, background); 148 fg.put(x, y, c, foreground); 149 } 150 public void put(int x, int y, IColoredString<? extends T> cs, T background) 151 { 152 checkFG(); 153 checkBG(); 154 for (int i = x; i < cs.length() && i < gridWidth; i++) { 155 bg.put(i, y, background); 156 } 157 fg.put(x, y, cs); 158 } 159 public void put(int x, int y, String s, T foreground, T background) 160 { 161 checkFG(); 162 checkBG(); 163 for (int i = x; i < s.length() && i < gridWidth; i++) { 164 bg.put(i, y, background); 165 } 166 fg.put(x, y, s, foreground); 167 } 168 169 @Override 170 public void fillBG(T color) { 171 if (gridWidth < 0 || gridHeight < 0) 172 throw new IllegalStateException("Width and height must be set before calling fillBG"); 173 for (int x = 0; x < gridWidth; x++) { 174 for (int y = 0; y < gridHeight; y++) 175 putBG(x, y, color); 176 } 177 } 178 179 @Override 180 public void refresh() { 181 bg.refresh(); 182 fg.refresh(); 183 } 184 185 @Override 186 public List<ISquidPanel<?>> getBackers() { 187 final List<ISquidPanel<?>> backers = new LinkedList<ISquidPanel<?>>(); 188 backers.add(fg.getBacker()); 189 backers.add(bg.getBacker()); 190 return backers; 191 } 192 193 protected void addActors() { 194 addActor((SquidPanel) bg.getBacker()); 195 addActor((SquidPanel) fg.getBacker()); 196 } 197 198 protected void checkFG() { 199 if (fg == null) 200 throw new NullPointerException("The foreground panel must be set before writing to it"); 201 } 202 203 protected void checkBG() { 204 if (bg == null) 205 throw new NullPointerException("The background panel must be set before writing to it"); 206 } 207 208 @Override 209 public String toString() { 210 return String.format("%s@%s", this.getClass().getSimpleName(), Integer.toHexString(hashCode())); 211 } 212 213}