1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package tsukuba_bunko.peko.canvas.select;
20
21 import java.awt.AlphaComposite;
22 import java.awt.Color;
23 import java.awt.Dimension;
24 import java.awt.Font;
25 import java.awt.Graphics;
26 import java.awt.Graphics2D;
27 import java.awt.RenderingHints;
28
29 import java.awt.event.MouseEvent;
30 import java.awt.event.MouseListener;
31
32 import java.awt.font.LineBreakMeasurer;
33 import java.awt.font.TextAttribute;
34
35 import java.text.AttributedString;
36
37 import java.util.List;
38 import java.util.Map;
39
40 import javax.swing.BorderFactory;
41 import javax.swing.JComponent;
42
43 import tsukuba_bunko.peko.Logger;
44 import tsukuba_bunko.peko.PekoSystem;
45
46 import tsukuba_bunko.peko.canvas.text.Line;
47
48
49 /***
50 * 選択肢をユーザーに選択させるためのボタンです。
51 * @author $Author: ppoi $
52 * @version $Revision: 1.3 $
53 */
54 public class SelectItemButton extends JComponent implements MouseListener {
55
56 /***
57 * serial version UID
58 */
59 private static final long serialVersionUID = -3568148242179176104L;
60
61 /***
62 * ボタンスタイル:幅
63 */
64 public static final String STYLE_WIDTH = "select.button.witdth";
65
66 /***
67 * ボタンスタイル:背景色
68 */
69 public static final String STYLE_BACKGROUND_COLOR = "select.button.background.color";
70
71 /***
72 * ボタンスタイル:背景透明度
73 */
74 public static final String STYLE_BACKGROUND_TRANSPARENCY = "select.button.background.transparency";
75
76 /***
77 * ボタンスタイル:前景色(選択時)
78 */
79 public static final String STYLE_FOREGROUND_SELECTED = "select.button.foreground.selected";
80
81 /***
82 * ボタンスタイル:前景色(非選択時)
83 */
84 public static final String STYLE_FOREGROUND_UNSELECTED = "select.button.foreground.unselected";
85
86 /***
87 * ボタンスタイル:影
88 */
89 public static final String STYLE_FOREGROUND_SHADOW = "select.button.foreground.shadow";
90
91 /***
92 * ボタンスタイル:フォント
93 */
94 public static final String STYLE_FONT = "select.button.font";
95
96
97 /***
98 * owner
99 */
100 private SelectCanvas _owner = null;
101
102
103 /***
104 * 選択肢
105 */
106 private SelectItem _item = null;
107
108 /***
109 * lines
110 */
111 private List _lines = null;
112
113 /***
114 * active foreground color
115 */
116 private Color _foregroundActive = null;
117
118 /***
119 * non-active foreground color
120 */
121 private Color _foregroundNonActive = null;
122
123 /***
124 * 影
125 */
126 private Color _shadow = null;
127
128 /***
129 * 背景色を塗りつぶす際に使用する AlphaComposite
130 */
131 private AlphaComposite _alphaComposite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f );
132
133 /***
134 * 選択状態フラグ
135 */
136 private boolean _selected = false;
137
138 /***
139 * size cache
140 */
141 private Dimension _size = new Dimension();
142
143
144 /***
145 * <code>SelectItemButton</code> のインスタンスを作成します。
146 */
147 public SelectItemButton( SelectCanvas owner )
148 {
149 super();
150 setBorder( BorderFactory.createLoweredBevelBorder() );
151 addMouseListener( this );
152 _owner = owner;
153 }
154
155
156 public void addNotify()
157 {
158 super.addNotify();
159 synchronized( this ) {
160 notify();
161 }
162 }
163
164 /***
165 * 選択肢を設定します。
166 * @param item 選択肢
167 */
168 public void setSelectItem( SelectItem item )
169 {
170 _item = item;
171 }
172
173 /***
174 * 選択肢を取得します。
175 * @return 選択肢
176 */
177 public SelectItem getSelectItem()
178 {
179 return _item;
180 }
181
182
183 public void prepare( Map style )
184 {
185 Color colorValue = (Color)style.get( SelectItemButton.STYLE_FOREGROUND_SELECTED );
186 if( colorValue != null ) {
187 _foregroundActive = colorValue;
188 }
189 else {
190 _foregroundActive = Color.white;
191 }
192
193 colorValue = (Color)style.get( SelectItemButton.STYLE_FOREGROUND_UNSELECTED );
194 if( colorValue != null ) {
195 _foregroundNonActive = colorValue;
196 }
197 else {
198 _foregroundNonActive = Color.darkGray;
199 }
200
201 colorValue = (Color)style.get( SelectItemButton.STYLE_BACKGROUND_COLOR );
202 if( colorValue != null ) {
203 setBackground( colorValue );
204 }
205 else {
206 setBackground( Color.black );
207 }
208
209 colorValue = (Color)style.get( SelectItemButton.STYLE_FOREGROUND_SHADOW );
210 if( colorValue != null ) {
211 _shadow = colorValue;
212 }
213 else {
214 _shadow = Color.black;
215 }
216
217 setForeground( _foregroundNonActive );
218
219 Float fv = (Float)style.get( SelectItemButton.STYLE_BACKGROUND_TRANSPARENCY );
220 if( fv != null ) {
221 if( fv.floatValue() != _alphaComposite.getAlpha() ) {
222 _alphaComposite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, fv.floatValue() );
223 }
224 }
225 else {
226 if( _alphaComposite.getAlpha() != 0.5f ) {
227 _alphaComposite = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f );
228 }
229 }
230
231 float width = 320f;
232 Integer intValue = (Integer)style.get( SelectItemButton.STYLE_WIDTH );
233 if( intValue != null ) {
234 width = intValue.floatValue();
235 }
236
237 Font fontValue = (Font)style.get( SelectItemButton.STYLE_FONT );
238 if( fontValue != null ) {
239 setFont( fontValue );
240 }
241
242 prepareLabel( width, 2 );
243 }
244
245 /***
246 * 選択肢を表示する準備を行います。
247 * @param width 1行の最大幅
248 * @param maxRows 最大行数
249 */
250 public void prepareLabel( float width, int maxRows )
251 {
252 if( _item == null ) {
253 Logger.error( "[canvas.text] not specified corresponding SelectItem." );
254 return;
255 }
256
257 Graphics2D g2 = (Graphics2D)PekoSystem.getInstance().getMainWindow().getGraphics();
258 g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
259
260 List lines = new java.util.ArrayList();
261 float lineHeight = 0f;
262
263 String text = _item.getText();
264 AttributedString astring = new AttributedString( text );
265 astring.addAttribute( TextAttribute.FONT, getFont() );
266 LineBreakMeasurer lbm = new LineBreakMeasurer( astring.getIterator(), g2.getFontRenderContext() );
267 int length = text.length();
268 Line line = null;
269 for( int i = 0; (i < maxRows) && (lbm.getPosition() < length); ++i ) {
270 line = new Line();
271 line.setTextLayout( lbm.nextLayout(width) );
272 line.setShadowColor( _shadow );
273 lines.add( line );
274 lineHeight += line.getAscent();
275 lineHeight += line.getDescent();
276 }
277 _lines = lines;
278
279 Dimension componentSize = new Dimension( (int)width, (int)lineHeight + 10 );
280 setPreferredSize( componentSize );
281 setSize( componentSize );
282 }
283
284 /***
285 * この選択肢ボタンの選択状態を設定します。
286 * @param selected 選択されている場合 <code>true</code>、選択されていない場合 <code>false</code>
287 */
288 public void setSelected( boolean selected )
289 {
290 if( _selected == selected ) {
291 return;
292 }
293
294 if( selected ) {
295 setForeground( _foregroundActive );
296 _owner.itemSelecting( this );
297 }
298 else {
299 setForeground( _foregroundNonActive );
300 _owner.itemDeselected( this );
301 }
302 _selected = selected;
303 repaint();
304 }
305
306
307
308
309
310 public void paintComponent( Graphics g )
311 {
312 Graphics2D g2 = (Graphics2D)g.create();
313 g2.setComposite( _alphaComposite );
314 g2.setColor( getBackground() );
315 Dimension size = getSize( _size );
316 g2.fillRect( 0, 0, size.width, size.height );
317
318 List lines = _lines;
319 if( lines != null ) {
320 g2 = (Graphics2D)g;
321 int length = lines.size();
322 float x = 5f;
323 float y = 5f;
324 Line line = null;
325 for( int i = 0; i < length; ++i ) {
326 line = (Line)lines.get( i );
327 line.setForeground( getForeground() );
328 y += line.getAscent();
329 line.draw( g2, x, y );
330 y += line.getDescent();
331 }
332 }
333 }
334
335
336
337
338 public void mousePressed( MouseEvent ev )
339 {
340 }
341
342 public void mouseReleased( MouseEvent ev )
343 {
344 }
345
346 public void mouseEntered( MouseEvent ev )
347 {
348 setSelected( true );
349 }
350
351 public void mouseExited( MouseEvent ev )
352 {
353 setSelected( false );
354 }
355
356 public void mouseClicked( MouseEvent ev )
357 {
358 if( _selected && (ev.getModifiers() == MouseEvent.BUTTON1_MASK) ) {
359 _owner.itemSelected( this );
360 }
361 }
362
363 }