View Javadoc

1   /*
2    * "Peko" Visual Novel System
3    *
4    * All Rights Reserved.
5    * Copyright (c) 1999-2003 Tsukuba Bunko.
6    *
7    * $Id: TextCoordinator.java,v 1.2 2005/07/11 14:27:50 ppoi Exp $
8    */
9   package tsukuba_bunko.peko.scenario.text;
10  
11  import	java.awt.Dimension;
12  
13  import	java.awt.font.LineBreakMeasurer;
14  import	java.awt.font.TextAttribute;
15  import	java.awt.font.TextLayout;
16  
17  import	java.text.AttributedString;
18  
19  import	tsukuba_bunko.peko.Logger;
20  
21  import	tsukuba_bunko.peko.canvas.text.Line;
22  import	tsukuba_bunko.peko.canvas.text.Page;
23  
24  import	tsukuba_bunko.peko.resource.ResourceManager;
25  
26  import	tsukuba_bunko.peko.scenario.Coordinator;
27  import	tsukuba_bunko.peko.scenario.SceneContext;
28  
29  
30  /***
31   * TextCanvas への操作を取り持つコーディネータモジュールです。
32   * @author	$Author: ppoi $
33   * @version	$Revision: 1.2 $
34   */
35  public class TextCoordinator	extends Coordinator	{
36  
37  	/***
38  	 * Page の設定を行ったかどうか
39  	 */
40  	protected boolean	_pageConfigured = false;
41  
42  	/***
43  	 * 行間隔
44  	 */
45  	protected float	_lineSpan = 0f;
46  
47  	/***
48  	 * 最終行
49  	 */
50  	protected Line	_lastLine = null;
51  
52  
53  	/***
54  	 * Dimension cache
55  	 */
56  	protected Dimension	_sizeCache = new Dimension();
57  
58  
59  	/***
60  	 * <code>TextCoordinator</code> のインスタンスを生成します。
61  	 */
62  	public TextCoordinator()
63  	{
64  		super();
65  	}
66  
67  
68  	public void prepare( SceneContext context, Thread activeThread )
69  	{
70  		super.prepare( context, activeThread );
71  		_pageConfigured = false;
72  		_lastLine = null;
73  	}
74  
75  
76  	/***
77  	 * TextCanvas への操作を開始します。
78  	 */
79  	public void begin()
80  	{
81  		if( isActiveThread() )	{
82  			_lastLine = null;
83  			getActionControler().setSaveEnabled( true );
84  		}
85  	}
86  
87  	/***
88  	 * TextCanvas への操作を終了し、キャンバスの状態を確定します。
89  	 */
90  	public void commit()
91  	{
92  		if( isActiveThread() )	{
93  			getActionControler().setSaveEnabled( false );
94  			getCurrentPage().commit();
95  		}
96  	}
97  
98  	/***
99  	 * 表示する文章を TextCanvsa に送信します。
100 	 * @param	text	表示する文章
101 	 */
102 	public void pushText( String text )
103 	{
104 		if( !isActiveThread() )	{
105 			return;
106 		}
107 
108 		Page	page = getCurrentPage();
109 		if( !_pageConfigured )	{
110 			PageConfigurator.configure( page, getSceneContext() );
111 			_pageConfigured = true;
112 			_lineSpan = getLineSpan();
113 		}
114 
115 		int	length = text.length();
116 		if( length == 0 )	{
117 			Logger.debug( "[scnario.text] empty string is pecified." );
118 			return;
119 		}
120 
121 		if( _lastLine != null )	{
122 			text = _lastLine.getText() + text;
123 			length = text.length();
124 		}
125 		Logger.debug( text );
126 
127 		AttributedString	astring = new AttributedString( text );
128 		astring.addAttribute( TextAttribute.FONT, page.getDefaultFont() );
129 		astring.addAttribute( TextAttribute.FOREGROUND, page.getForeground() );
130 
131 		LineBreakMeasurer	lbm = new LineBreakMeasurer( astring.getIterator(), page.getFontRenderContext() );
132 		float	maxWidth = page.getMaxLineWidth();
133 		float	lineSpan = _lineSpan;
134 		boolean	conflictWait = false;
135 		TextLayout	layout = null;
136 		Line	line = null;
137 
138 		layout = lbm.nextLayout( maxWidth );
139 		line = new Line();
140 		line.setTextLayout( layout );
141 		line.setText( text.substring(0, lbm.getPosition()) );
142 		line.setForeground( page.getForeground() );
143 		line.setShadowColor( page.getShadow() );
144 
145 		if( _lastLine == null )	{
146 			if( isActiveThread() )	{
147 				line.setLineSpan( lineSpan );	//	ホントはここで margin-top を設定するデス。
148 				if( !page.isAdaptive(line) )	{
149 					page = advancesNewPage();
150 				}
151 				page.addLine( line );
152 			}
153 			else	{
154 				return;
155 			}
156 		}
157 		else	{
158 			line.setLineSpan( lineSpan );
159 			if( isActiveThread() )	{
160 				page.setLine( (page.getLineCount() - 1), line );
161 				if( _lastLine.getText().equals(line.getText()) )	{
162 					conflictWait = true;
163 				}
164 			}
165 			else	{
166 				return;
167 			}
168 		}
169 		_lastLine = line;
170 
171 		int	lastLinePosition = 0;
172 		while( (lastLinePosition = lbm.getPosition()) < length )	{
173 			line = new Line();
174 			line.setTextLayout( lbm.nextLayout(maxWidth) );
175 			line.setLineSpan( lineSpan );
176 			line.setText( text.substring(lastLinePosition, lbm.getPosition()) );
177 			line.setForeground( page.getForeground() );
178 			line.setShadowColor( page.getShadow() );
179 			if( isActiveThread() )	{
180 				if( !page.isAdaptive(line) )	{
181 					if( conflictWait )	{
182 						conflictWait = false;
183 					}
184 					else	{
185 						page.updateContents();
186 						stop();	//	ここー!
187 					}
188 					page = advancesNewPage();
189 				}
190 				if( page != null )	{
191 					page.addLine( line );
192 					conflictWait = false;
193 				}
194 				else	{
195 					return;
196 				}
197 				_lastLine = line;
198 			}
199 			else	{
200 				return;
201 			}
202 		}
203 		if( isActiveThread() )	{
204 			page.updateContents();
205 		}
206 	}
207 
208 	/***
209 	 * 現在表示中のページを取得します。
210 	 * @return	現在表示中のページ
211 	 */
212 	public Page getCurrentPage()
213 	{
214 		return getCanvasManager().getCurrentPage();
215 	}
216 
217 	/***
218 	 * 新しいページに切り替え、新しいページを取得します。
219 	 * @return	新しいページ
220 	 */
221 	public Page advancesNewPage()
222 	{
223 		if( isActiveThread() )	{
224 			return getCanvasManager().advancesNewPage();
225 		}
226 		else	{
227 			return null;
228 		}
229 	}
230 
231 	/***
232 	 * 処理を一時停止します。
233 	 */
234 	protected void stop()
235 	{
236 		if( isActiveThread() )	{
237 			getActionControler().stop();
238 		}
239 	}
240 
241 	/***
242 	 * 行間隔を取得します。
243 	 * @return	行間隔
244 	 */
245 	protected float getLineSpan()
246 	{
247 		SceneContext	context = getSceneContext();
248 		String	value = context.getProperty( PropertyIDs.CANVAS_TEXT_LINESPAN );
249 		if( value != null )	{
250 			try	{
251 				return Float.parseFloat( value );
252 			}
253 			catch( Exception e )	{
254 				Logger.warn( MessageIDs.SCN2002W, e );
255 			}
256 		}
257 
258 		ResourceManager	resources = ResourceManager.getInstance();
259 		Float	lineSpan = (Float)resources.getResource( ResourceIDs.CANVAS_TEXT_LINESPAN );
260 		if( lineSpan != null )	{
261 			return lineSpan.floatValue();
262 		}
263 		else	{
264 			Logger.warn( MessageIDs.SCN2001W, new Object[]{"20.0"} );
265 			return 20f;
266 		}
267 	}
268 }