001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.graphics.Color;
004import squidpony.panel.IColoredString;
005
006import java.util.ArrayList;
007import java.util.Collection;
008import java.util.Iterator;
009import java.util.List;
010
011/**
012 * A screen designed to write some text in full screen. This class supports text
013 * alignment (left, center, right) and text wrapping (see {@link #wrap(int)}).
014 * 
015 * <p>
016 * If you use libgdx {@link Color} as your type of color, you can use a less
017 * abstract subtype: {@link TextScreen}.
018 * </p>
019 * 
020 * @author smelC
021 * 
022 * @see TextScreen
023 */
024public abstract class AbstractTextScreen<T extends Color> extends AbstractSquidScreen<T> {
025
026        /** Can contain null members (denoting empty lines) */
027        protected List<IColoredString<T>> text;
028        protected /* @Nullable */ int[] alignment;
029
030        /**
031         * @param ssi
032         *            See super class
033         * @param text
034         *            The text to display. From top to bottom. Use {@code null}
035         *            members to jump lines.
036         * 
037         *            <p>
038         *            Give {@code null} if you wanna set it later (using
039         *            {@link #init(List, int[])}).
040         *            </p>
041         * @param alignment
042         *            How to alignment members of {@code text}. -1 for left, 0 for
043         *            center, 1 for right. The default is to align left
044         * 
045         *            <p>
046         *            Give {@code null} if you wanna set it later (using
047         *            {@link #init(List, int[])}).
048         *            </p>
049         */
050        public AbstractTextScreen(SquidScreenInput<T> ssi, /* @Nullable */ List<IColoredString<T>> text,
051                        /* @Nullable */ int[] alignment) {
052                super(ssi);
053                this.text = text;
054                this.alignment = alignment;
055        }
056
057        /**
058         * You should call this method at most once. You should call this method
059         * only before rendering this screen.
060         * 
061         * @param text
062         *            The text to display. From top to bottom. Use {@code null}
063         *            members to jump lines.
064         * @param alignment
065         *            How to alignment members of {@code text}. -1 for left, 0 for
066         *            center, 1 for right. The default is to align left
067         */
068        public void init(List<IColoredString<T>> text, /* @Nullable */ int[] alignment) {
069                this.text = text;
070                this.alignment = alignment;
071        }
072
073        /**
074         * Wraps the text inside {@code this} according to {@code width}. This
075         * screen's text must have been set already. This, of course, preserves the
076         * text alignment (if any).
077         * 
078         * @param width
079         * 
080         * @throws IllegalStateException
081         *             If {@code this}'s text hasn't been initialized yet.
082         */
083        public void wrap(int width) {
084                if (text == null)
085                        throw new IllegalStateException("Cannot wrap an unitialized " + getClass().getSimpleName());
086
087                final List<IColoredString<T>> tsave = text;
088                text = new ArrayList<>(tsave.size() * 2);
089                final int[] asave = alignment;
090                final /* @Nullable */ List<Integer> newAlignments = asave == null ? null
091                                : new ArrayList<Integer>(asave.length * 2);
092                int i = 0;
093                for (IColoredString<T> t : tsave) {
094                        /* Wrap line */
095                        if (t == null) {
096                                /* An empty line */
097                                text.add(null);
098                                if (newAlignments != null)
099                                        newAlignments.add(/* doesn't matter */ 0);
100                        } else {
101                                final List<IColoredString<T>> wrapped = t.wrap(width);
102                                final /* @Nullable */Integer alignment = asave == null || asave.length <= i ? null : asave[i];
103                                for (IColoredString<T> line : wrapped) {
104                                        /* Add wrapped */
105                                        text.add(line);
106                                        if (newAlignments != null && alignment != null)
107                                                /* Keep alignment */
108                                                newAlignments.add(alignment);
109                                }
110                        }
111                        i++;
112                }
113                alignment = newAlignments == null ? null : toIntArray(newAlignments);
114        }
115
116        protected int[] toIntArray(Collection<Integer> l) {
117                final int[] result = new int[l.size()];
118                int j = 0;
119                for (int i : l)
120                        result[j++] = i;
121                return result;
122        }
123
124        @Override
125        public String toString() {
126                final StringBuilder buf = new StringBuilder();
127                buf.append(getClass().getSimpleName());
128                if (text != null) {
129                        /* Show text */
130                        final Iterator<? extends IColoredString<?>> it = text.iterator();
131                        final String eol = System.getProperty("line.separator");
132                        buf.append(eol);
133                        while (it.hasNext()) {
134                                final IColoredString<?> ics = it.next();
135                                buf.append(ics == null ? "" : ics.present());
136                                if (it.hasNext())
137                                        buf.append(eol);
138                        }
139                }
140                return buf.toString();
141        }
142
143}