1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package tsukuba_bunko.peko.canvas.text;
20
21 import java.awt.AlphaComposite;
22 import java.awt.Dimension;
23 import java.awt.Graphics;
24 import java.awt.Graphics2D;
25 import java.awt.Insets;
26 import java.awt.Point;
27 import java.awt.RenderingHints;
28
29 import java.awt.font.FontRenderContext;
30
31 import java.util.List;
32
33 import javax.swing.BorderFactory;
34 import javax.swing.JComponent;
35
36 import javax.swing.border.Border;
37
38 import tsukuba_bunko.peko.Logger;
39
40
41 /***
42 * テキストを表示するキャンバスです。
43 * @author $Author: ppoi $
44 * @version $Revision: 1.3 $
45 */
46 public class TextCanvas extends JComponent {
47
48 /***
49 * serial version UID
50 */
51 private static final long serialVersionUID = 2600492357487531048L;
52
53
54 /***
55 * Page
56 */
57 private Page _page = null;
58
59
60 /***
61 * Lines
62 */
63 private List _lines = null;
64
65 /***
66 * alpha-composite
67 */
68 private AlphaComposite _alphaComposite = AlphaComposite.getInstance( AlphaComposite.DST_OVER, 0.5f );
69
70 /***
71 * page size
72 */
73 private Dimension _size = new Dimension();
74
75 /***
76 * location
77 */
78 private Point _location = new Point( 0, 0 );
79
80 /***
81 * padding
82 */
83 private Insets _padding = new Insets( 0, 0, 0, 0 );
84
85
86 /***
87 * cached FontRenderContext
88 */
89 private FontRenderContext _frc = null;
90
91
92 /***
93 * marker
94 */
95 private Marker _marker = null;
96
97
98 /***
99 * <code>TextCanvas</code> のインスタンスを作成します。
100 */
101 public TextCanvas()
102 {
103 super();
104 initialize();
105 }
106
107
108 /***
109 * ページに文字を描画するのに使用する <code>FontRenderContext</code> を取得します。
110 * @return ページに文字を描画するのに使用する <code>FontRenderContext</code>
111 */
112 public FontRenderContext getFontRenderContext()
113 {
114 if( _frc == null ) {
115 synchronized( this ) {
116 if( _frc == null ) {
117 try {
118 Logger.debug( "[canvas.text] waiting for create cached FontRenderContext." );
119 wait();
120 Logger.debug( "[canvas.text] creating cached FontRenderContext done." );
121 }
122 catch( InterruptedException ie ) {
123 Logger.error( "[canvas.text] interrupted." );
124 }
125 }
126 }
127 }
128 return _frc;
129 }
130
131 /***
132 * 背景色を描画する際に使用する AlphaComposite を取得します。
133 * @return 背景色を描画する際に使用する AlphaComposite インスタンス
134 */
135 public AlphaComposite getAlphaComposite()
136 {
137 return _alphaComposite;
138 }
139
140 /***
141 * キャンバスを最新の状態に更新します。
142 */
143 public void updateCanvas()
144 {
145 if( !isEnabled() ) {
146 return;
147 }
148
149 Logger.debug( "[canvas.text] update TextCanvas view" );
150 _lines = null;
151 _page.getSize( _size );
152 _page.getLocation( _location );
153 _page.getPadding( _padding );
154 setForeground( _page.getForeground() );
155 setBackground( _page.getBackground() );
156 float trans = _page.getTransparency();
157 if( (_alphaComposite == null) || (_alphaComposite.getAlpha() != trans) ) {
158 _alphaComposite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, trans );
159 }
160 _marker.setText( "▼", _page );
161 }
162
163 /***
164 * キャンバスに描画するテキストを最新の状態に更新します。
165 */
166 public void updateText()
167 {
168 if( !isEnabled() ) {
169 return;
170 }
171
172 Logger.debug( "[canvas.text] update texts." );
173 _marker.setVisible( false );
174
175 List lines = _page.getLines();
176 int size = lines.size();
177 for( int i = 0; i < size; ++i ) {
178 ((Line)lines.get(i)).prepare( _page );
179 }
180 _lines = lines;
181
182
183 tsukuba_bunko.peko.PekoSystem.getInstance().getCanvasManager().showTextCanvas();
184 repaint();
185
186 try {
187 synchronized( this ) {
188 wait( 100 );
189 }
190 }
191 catch( Exception e ) {
192 }
193 _marker.setVisible( true );
194 }
195
196
197 /***
198 * このキャンバスで描画するページを設定します。
199 * @param page このキャンバスで描画するページ
200 */
201 public void setPage( Page page )
202 {
203 _page = page;
204 _page.setTextCanvas( this );
205 }
206
207 /***
208 * 現在このキャンバスで描画中のページを取得します。
209 * @return 現在このキャンバスで描画中のページ
210 */
211 public Page getPage()
212 {
213 return _page;
214 }
215
216 public void paintPageBackground( Graphics g )
217 {
218 Dimension size = _size;
219 Point location = _location;
220
221 Graphics2D g2 = (Graphics2D)g.create( location.x, location.y, size.width, size.height );
222 g2.setComposite( _alphaComposite );
223 g2.setColor( getBackground() );
224 g2.fillRect( 0, 0, size.width, size.height );
225 g2.dispose();
226 }
227
228 /***
229 * TextCanvas を初期化します。
230 */
231 private void initialize()
232 {
233 setLayout( null );
234 setDoubleBuffered( false );
235 setBorder( BorderFactory.createEtchedBorder() );
236
237 _marker = new Marker();
238 add( _marker );
239 _marker.setLocation( 0, 0 );
240 _marker.setVisible( false );
241 }
242
243
244
245
246
247 public void setVisible( boolean visibility )
248 {
249 Logger.debug( "[canvas.text] set visibility :" + visibility );
250 if( visibility ) {
251 _marker.start();
252 }
253 super.setVisible( visibility );
254 }
255
256 public void addNotify()
257 {
258 super.addNotify();
259 Logger.debug( "[canvas.text] added notify to TextCavas" );
260 if( _frc == null ) {
261 Logger.debug( "[canvas.text] try create new font render context." );
262 synchronized( this ) {
263 if( _frc == null ) {
264 Graphics2D g2 = (Graphics2D)getGraphics();
265 g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
266 _frc = g2.getFontRenderContext();
267 Logger.debug( "[canvas] notify all thread waiting at TextCanvas" );
268 notifyAll();
269 }
270 }
271 }
272 }
273
274 public void paint( Graphics g )
275 {
276 List lines = _lines;
277 if( (lines == null) || lines.isEmpty() ) {
278 return;
279 }
280 else {
281 super.paint( g );
282 }
283 }
284
285 public void paintBorder( Graphics g )
286 {
287 Border border = getBorder();
288 if( border != null ) {
289 border.paintBorder( this, g, _location.x, _location.y, _size.width, _size.height );
290 }
291 }
292
293 public void paintComponent( Graphics g )
294 {
295 List lines = _lines;
296
297 Point location = _location;
298 Insets padding = _padding;
299
300
301
302 Graphics2D g2 = (Graphics2D)g;
303 float x = (float)(location.x + padding.left);
304 float y = (float)(location.y + padding.top);
305 float tail = 0f;
306 int length = lines.size();
307 Line line = null;
308 for( int i = 0; i < length; ++i ) {
309 line = (Line)lines.get( i );
310 y += line.getAscent();
311 line.draw( g2, x, y );
312 y += line.getDescent();
313 tail = line.getAdavance();
314 }
315 _marker.setPosition( (int)(tail + 5f + x), (int)y );
316 }
317 }