001package squidpony.panel;
002
003import squidpony.IColorCenter;
004import squidpony.annotation.Beta;
005
006/**
007 * The combination of two panels, one to color the background, the other to
008 * write characters on the foreground.
009 * 
010 * <p>
011 * <ul>
012 * <li>
013 * There is a very generic implementation in this file: {@link Impl} that you
014 * should use if you're combining generic things.
015 * </li>
016 * <li>
017 * There is a libgdx-{@code Group} based implementation that offers more
018 * features and that you should likely use if you're a new user (in
019 * squidlib-gdx).
020 * </li>
021 * </ul>
022 * 
023 * @author smelC
024 * 
025 * @param <T>
026 *            The type of colors.
027 */
028@Beta
029public interface ICombinedPanel<T> {
030
031        /**
032         * Puts the character {@code c} at {@code (x, y)}.
033         * 
034         * @param x
035         * @param y
036         * @param c
037         */
038        void putFG(int x, int y, char c);
039
040        /**
041         * Puts the character {@code c} at {@code (x, y)} with some {@code color}.
042         * 
043         * @param x
044         * @param y
045         * @param c
046         * @param color
047         */
048        void putFG(int x, int y, char c, T color);
049
050        /**
051         * Puts the given string horizontally with the first character at the given
052         * offset.
053         *
054         * Does not word wrap. Characters that are not renderable (due to being at
055         * negative offsets or offsets greater than the grid size) will not be shown
056         * but will not cause any malfunctions.
057         *
058         * @param x
059         *            the x coordinate of the first character
060         * @param y
061         *            the y coordinate of the first character
062         * @param string
063         *            the characters to be displayed
064         * @param color
065         *            the color to draw the characters
066         */
067        void putFG(int x, int y, String string, T color);
068
069        /**
070         * Puts the given string horizontally with the first character at the given
071         * offset.
072         *
073         * Does not word wrap. Characters that are not renderable (due to being at
074         * negative offsets or offsets greater than the grid size) will not be shown
075         * but will not cause any malfunctions.
076         *
077         * @param x
078         *            the x coordinate of the first character
079         * @param y
080         *            the y coordinate of the first character
081         * @param cs
082         *            the text to be displayed, with its color.
083         */
084        void putFG(int x, int y, IColoredString<T> cs);
085
086        /**
087         * Puts the color {@code c} at {@code (x, y)}.
088         * 
089         * @param x
090         * @param y
091         * @param color
092         */
093        void putBG(int x, int y, T color);
094
095        /**
096         * Puts {@code c} at (x, y), using {@code fgc} for {@code c} and {@code bgc}
097         * for the background.
098         */
099        void put(int x, int y, char c, T bgc, T fgc);
100
101    /**
102     * Put {@code cs} at (x,y) using {@code bgc} for the background.
103     */
104        void put(int x, int y, T bgc, IColoredString<T> cs);
105
106        /**
107         * Put {@code cs} at (x,y) using {@code bgc} for the background and
108         * {@code fgc} for the foreground.
109         */
110        void put(int x, int y, String s, T bgc, T fgc);
111
112        /**
113         * @param what
114         *                        What to fill
115         * @param color
116         *            The color to put within this panel.
117         */
118        void fill(What what, T color);
119
120        /**
121         * @return Returns true if there are animations running when this method is
122         *         called.
123         */
124        boolean hasActiveAnimations();
125
126        /**
127         * Changes the underlying {@link IColorCenter}.
128         * 
129         * @param icc
130         */
131        void setColorCenter(IColorCenter<T> icc);
132
133        /**
134         * What to fill
135         * 
136         * @author smelC
137         */
138        enum What {
139                BG,
140                FG,
141                BG_AND_FG;
142
143                /**
144                 * @return {@code true} if {@code this} contains the background.
145                 */
146                public boolean hasBG() {
147                        switch (this) {
148                        case BG:
149                        case BG_AND_FG:
150                                return true;
151                        case FG:
152                                return false;
153                        }
154                        throw new IllegalStateException("Unmatched value: " + this);
155                }
156
157                /**
158                 * @return {@code true} if {@code this} contains the foreground.
159                 */
160                public boolean hasFG() {
161                        switch (this) {
162                        case FG:
163                        case BG_AND_FG:
164                                return true;
165                        case BG:
166                                return false;
167                        }
168                        throw new IllegalStateException("Unmatched value: " + this);
169                }
170        }
171
172        /**
173         * A generic implementation of {@link ICombinedPanel}. Useful to combine
174         * things. If you're a new user, you likely would prefer the more specific
175         * implementation using libGDX, GroupCombinedPanel, instead.
176         * 
177         * @author smelC
178         * 
179         * @param <T>
180         *            The type of colors.
181         */
182        @Beta
183        class Impl<T> implements ICombinedPanel<T> {
184
185                protected final ISquidPanel<T> bg;
186                protected final ISquidPanel<T> fg;
187
188                protected final int width;
189                protected final int height;
190
191                /**
192                 * @param bg
193                 *            The backing background panel.
194                 * @param fg
195                 *            The backing foreground panel.
196                 * @param width
197                 *            The width of this panel, used for {@link #fillBG(Object)}
198                 *            (so that it fills within {@code [0, width)}).
199                 * @param height
200                 *            The height of this panel, used for {@link #fillBG(Object)}
201                 *            (so that it fills within {@code [0, height)}).
202                 * @throws IllegalStateException
203                 *             In various cases of errors regarding sizes of panels.
204                 */
205                public Impl(ISquidPanel<T> bg, ISquidPanel<T> fg, int width, int height) {
206                        if (bg.gridWidth() != fg.gridWidth())
207                                throw new IllegalStateException(
208                                                "Cannot build a combined panel with backers of different widths");
209                        if (bg.gridHeight() != fg.gridHeight())
210                                throw new IllegalStateException(
211                                                "Cannot build a combined panel with backers of different heights");
212
213                        this.bg = bg;
214                        this.fg = fg;
215                        if (width < 0)
216                                throw new IllegalStateException("Cannot create a panel with a negative width");
217                        this.width = width;
218                        if (height < 0)
219                                throw new IllegalStateException("Cannot create a panel with a negative height");
220                        this.height = height;
221                }
222
223                @Override
224                public void putFG(int x, int y, char c) {
225                        fg.put(x, y, c);
226                }
227
228                @Override
229                public void putFG(int x, int y, char c, T color) {
230                        fg.put(x, y, c, color);
231                }
232
233                @Override
234                public void putFG(int x, int y, String string, T foreground) {
235                        fg.put(x, y, string, foreground);
236                }
237
238                @Override
239                public void putFG(int x, int y, IColoredString<T> cs) {
240                        fg.put(x, y, cs);
241                }
242
243                @Override
244                public void putBG(int x, int y, T color) {
245                        bg.put(x, y, color);
246                }
247
248                @Override
249                public void put(int x, int y, char c, T bgc, T fgc) {
250                        bg.put(x, y, bgc);
251                        fg.put(x, y, c, fgc);
252                }
253
254                @Override
255                public void put(int x, int y, T bgc, IColoredString<T> cs) {
256                        final int l = cs.length();
257                        for (int i = x; i < l && i < width; i++)
258                                bg.put(i, y, bgc);
259                        fg.put(x, y, cs);
260                }
261
262                @Override
263                public void put(int x, int y, String s, T bgc, T fgc) {
264                        final int l = s.length();
265                        for (int i = x; i < l && i < width; i++)
266                                bg.put(i, y, bgc);
267                        fg.put(x, y, s, fgc);
268                }
269
270                @Override
271                public void fill(What what, T color) {
272                        /* Nope, not Doom's Big Fucking Gun */
273                        final boolean bfg = what.hasFG();
274                        final boolean bbg = what.hasBG();
275                        for (int x = 0; x < width; x++) {
276                                for (int y = 0; y < height; y++) {
277                                        if (bfg)
278                                                putFG(x, y, ' ', color);
279                                        if (bbg)
280                                                putBG(x, y, color);
281                                }
282                        }
283                }
284
285                @Override
286                public boolean hasActiveAnimations() {
287                        return bg.hasActiveAnimations() || fg.hasActiveAnimations();
288                }
289
290                @Override
291                public void setColorCenter(IColorCenter<T> icc) {
292                        bg.setColorCenter(icc);
293                        fg.setColorCenter(icc);
294                }
295
296        }
297
298}