1 /***
2 * Ambient - A music player for the Android platform
3 Copyright (C) 2007 Martin Vysny
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package sk.baka.ambient.views;
20
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import sk.baka.ambient.AmbientApplication;
25 import sk.baka.ambient.R;
26 import android.content.Context;
27 import android.content.res.TypedArray;
28 import android.graphics.Paint;
29 import android.util.AttributeSet;
30 import android.view.View;
31 import android.view.animation.Animation;
32 import android.view.animation.AnimationUtils;
33 import android.view.animation.TranslateAnimation;
34 import android.widget.TextSwitcher;
35 import android.widget.TextView;
36 import android.widget.ViewSwitcher;
37
38 /***
39 * Scrolls given text from right to left. Starts from the beginning if no more
40 * text is to be scrolled.
41 *
42 * @author Martin Vysny
43 */
44 public final class TextScroller extends TextSwitcher implements
45 ViewSwitcher.ViewFactory {
46
47 private final long pauseMs;
48
49 /***
50 * @param context
51 * @param attrs
52 */
53 public TextScroller(Context context, AttributeSet attrs) {
54 super(context, attrs);
55 final TypedArray a = getContext().obtainStyledAttributes(attrs,
56 R.styleable.TextScroller);
57 pauseMs = a.getResourceId(R.styleable.TextScroller_pauseMs, 2500);
58 init();
59 }
60
61 /***
62 * @param context
63 * @param pauseMs
64 */
65 public TextScroller(Context context, final long pauseMs) {
66 super(context);
67 this.pauseMs = pauseMs;
68 init();
69 }
70
71 /***
72 * Creates new scroller instance.
73 */
74 private void init() {
75 fadeIn = AnimationUtils.loadAnimation(getContext(),
76 android.R.anim.fade_in);
77 fadeOut = AnimationUtils.loadAnimation(getContext(),
78 android.R.anim.fade_out);
79 slideInRight.setDuration(400);
80 slideOutLeft.setDuration(400);
81 textColor = getContext().getResources().getColor(R.color.textcolor);
82 textParts.add("");
83 textPaint = ((TextView) makeView()).getPaint();
84 setFactory(this);
85 }
86
87 /***
88 * The color of highlighted items in the list.
89 */
90 private int textColor;
91 private Animation fadeIn;
92 private Animation fadeOut;
93 private final Animation slideInRight = new TranslateAnimation(
94 Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f,
95 Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
96 private final Animation slideOutLeft = new TranslateAnimation(
97 Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
98 -1.0f, Animation.RELATIVE_TO_SELF, 0.0f,
99 Animation.RELATIVE_TO_SELF, 0.0f);
100
101 /***
102 * These parts are shown on the switcher.
103 */
104 private final List<String> textParts = new ArrayList<String>();
105
106 /***
107 * Used to paint hint text.
108 */
109 private Paint textPaint;
110
111 private String textToScroll = null;
112
113 /***
114 * Sets new text to the scroller. Resets the scroller to its initial value.
115 *
116 * @param text
117 * the text to set.
118 */
119 public void setScrolledText(final String text) {
120 if (getWidth() < 10) {
121 textToScroll = text;
122 return;
123 }
124 final boolean wasPaused = paused;
125 pause();
126 currentlyShown = 0;
127 String remainingText = text;
128 textParts.clear();
129 while (true) {
130 final int chars = textPaint.breakText(remainingText, true,
131 getWidth(), null);
132 if ((chars == 0) && (remainingText.length() != 0)) {
133 textParts.clear();
134 textToScroll = text;
135 return;
136 }
137 textParts.add(remainingText.substring(0, chars).trim());
138 if (chars >= remainingText.length())
139 break;
140 remainingText = remainingText.substring(chars);
141 }
142 setCurrentText(textParts.get(0));
143 if (!wasPaused) {
144 resume();
145 }
146 }
147
148 @Override
149 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
150 super.onSizeChanged(w, h, oldw, oldh);
151 if ((w > 10) && (textToScroll != null)) {
152 setScrolledText(textToScroll);
153 textToScroll = null;
154 }
155 }
156
157 private boolean paused = false;
158
159 /***
160 * Pauses the scrolling.
161 */
162 public void pause() {
163 if (paused)
164 return;
165 paused = true;
166 AmbientApplication.getHandler().removeCallbacks(rotateText);
167 }
168
169 /***
170 * Resumes the scrolling. Fails if no text was previously set.
171 */
172 public void resume() {
173 if (textParts.isEmpty()) {
174 throw new IllegalArgumentException("No text set");
175 }
176 if (!paused)
177 return;
178 if (textParts.size() > 1) {
179 AmbientApplication.getHandler().postDelayed(rotateText, pauseMs);
180 }
181 paused = false;
182 }
183
184 /***
185 * Currently shown text, index to the {@link #textParts} list.
186 */
187 private int currentlyShown = 0;
188
189 /***
190 * Executed periodically in handler, serves for text rotating.
191 */
192 private final Runnable rotateText = new Runnable() {
193 public void run() {
194 if (currentlyShown == 0) {
195 setInAnimation(slideInRight);
196 setOutAnimation(slideOutLeft);
197 currentlyShown++;
198 } else if (currentlyShown == textParts.size() - 1) {
199 setInAnimation(fadeIn);
200 setOutAnimation(fadeOut);
201 currentlyShown = 0;
202 } else {
203 currentlyShown++;
204 }
205 final String newText = textParts.get(currentlyShown);
206 TextScroller.this.setText(newText);
207 AmbientApplication.getHandler().postDelayed(this, pauseMs);
208 }
209 };
210
211 public View makeView() {
212 final TextView t = new TextView(getContext());
213 t.setTextColor(textColor);
214 return t;
215 }
216 }