OSDN Git Service

33bdadba0ba0659681f3babe07aa27fb6d418268
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / JTXTButton.java
1 package tainavi;\r
2 \r
3 import java.awt.AlphaComposite;\r
4 import java.awt.Color;\r
5 import java.awt.Dimension;\r
6 import java.awt.Font;\r
7 import java.awt.FontMetrics;\r
8 import java.awt.Graphics;\r
9 import java.awt.Graphics2D;\r
10 import java.awt.Rectangle;\r
11 import java.awt.RenderingHints;\r
12 import java.awt.font.FontRenderContext;\r
13 import java.awt.font.GlyphMetrics;\r
14 import java.awt.font.GlyphVector;\r
15 import java.awt.font.TextAttribute;\r
16 import java.awt.geom.Point2D;\r
17 import java.awt.image.BufferedImage;\r
18 import java.util.ArrayList;\r
19 import java.util.HashMap;\r
20 import java.util.Map;\r
21 \r
22 import javax.swing.JButton;\r
23 import javax.swing.JLabel;\r
24 \r
25 \r
26 public class JTXTButton extends JLabel {\r
27 \r
28         private static final long serialVersionUID = 1L;\r
29 \r
30         /*******************************************************************************\r
31          * 定数\r
32          ******************************************************************************/\r
33         \r
34         /**\r
35          *  フォントスタイル\r
36          */\r
37         public static enum FontStyle {\r
38                 BOLD            ("太字"),\r
39                 ITALIC          ("斜体"),\r
40                 UNDERLINE       ("下線");\r
41                 \r
42                 private String name;\r
43                 \r
44                 private FontStyle(String name) {\r
45                         this.name = name;\r
46                 }\r
47                 \r
48                 @Override\r
49                 public String toString() {\r
50                         return name;\r
51                 }\r
52                 \r
53                 \r
54                 public String getId() {\r
55                         return super.toString();\r
56                 }\r
57                 \r
58                 public static FontStyle get(String id) {\r
59                         for ( FontStyle fs : FontStyle.values() ) {\r
60                                 if ( fs.getId().equals(id) ) {\r
61                                         return fs;\r
62                                 }\r
63                         }\r
64                         return null;\r
65                 }\r
66         };\r
67         \r
68         private static final float DRAWTAB = 2.0F; \r
69         \r
70         \r
71         /*******************************************************************************\r
72          * 部品\r
73          ******************************************************************************/\r
74         \r
75         // 描画バッファ\r
76         private BufferedImage image = null;             // ビットマップ\r
77         \r
78         private int vrow;                                               // 仮想座標縦位置\r
79         private int vcolumn;                                    // 仮想座標横位置\r
80         private int vheight;                                    // 仮想座標高さ\r
81         private int vwidth;                                             // 仮想座標幅\r
82         \r
83         // 番組情報\r
84         private ProgDetailList tvd = null;              // 番組情報そのまま\r
85         \r
86         // 表示設定\r
87         private static boolean showStart = true;\r
88         private static boolean splitEpno = false;\r
89         private static boolean showDetail = true;\r
90         private static float detailTab = 2.0F;\r
91         \r
92         private static Font defaultFont = new JLabel().getFont();\r
93         \r
94         private static Font titleFont = defaultFont;\r
95         private static int titleFontSize = defaultFont.getSize();\r
96         private static Color titleFontColor = Color.BLUE;\r
97         private static int titleFontStyle = Font.BOLD;\r
98         \r
99         private static Font detailFont = defaultFont;\r
100         private static int detailFontSize = defaultFont.getSize();\r
101         private static Color detailFontColor = Color.DARK_GRAY;\r
102         private static int detailFontStyle = defaultFont.getStyle();\r
103         \r
104         private static Font startFont = defaultFont;\r
105         \r
106         private static FontRenderContext frc = new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_ON, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
107 \r
108         private static int columnWidth = 0;\r
109         private static float heightMultiplier = 0;\r
110         \r
111         \r
112         /*******************************************************************************\r
113          * コンストラクタ\r
114          ******************************************************************************/\r
115         \r
116         // ないよ\r
117         \r
118         \r
119         /*******************************************************************************\r
120          * メソッド\r
121          ******************************************************************************/\r
122         \r
123         // 内容をリセットする\r
124         // setVisible(false)するとリソースが解放されてしまうのか再描画に時間がかかるようになるので表示範囲外に出して隠してしまう\r
125         public void clean() {\r
126                 tvd = null;\r
127                 image = null;\r
128                 setBounds(-1,-1,0,0);\r
129         }\r
130         \r
131         // フラグを変えた後に再描画させる\r
132         public void forceRepaint() {\r
133                 image = null;\r
134                 super.repaint();\r
135         }\r
136         \r
137         // 仮想位置の変更\r
138         //public void setVRow(int n) { vrow = n; }\r
139         public int getVRow() { return vrow; }\r
140         //public void setVColumn(int n) { vcolumn = n; }\r
141         public int getVColumn() { return vcolumn; }\r
142         //public void setVHeight(int n) { vheight = n; }\r
143         public int getVHeight() { return vheight; }\r
144         \r
145         public static void setColumnWidth(int n) { columnWidth = n; }\r
146         public static void setHeightMultiplier(float f) { heightMultiplier = f; }\r
147         \r
148         public void setVBounds(int x, int y, int width, int height) {\r
149                 vrow = y;\r
150                 vcolumn = x;\r
151                 vheight = height;\r
152                 vwidth = width;\r
153                 super.setBounds(\r
154                                 vcolumn*columnWidth,\r
155                                 (int) Math.ceil(((float)vrow)*heightMultiplier),\r
156                                 vwidth*columnWidth,\r
157                                 (int) Math.ceil(((float)vheight)*heightMultiplier));\r
158         }\r
159         \r
160         public void reVBounds() {\r
161                 super.setBounds(\r
162                                 vcolumn*columnWidth,\r
163                                 (int) Math.ceil(((float)vrow)*heightMultiplier),\r
164                                 vwidth*columnWidth,\r
165                                 (int) Math.ceil(((float)vheight)*heightMultiplier));\r
166         }\r
167         \r
168         // 番組情報のやりとり\r
169         public void setInfo(ProgDetailList tvd) {\r
170                 this.tvd = tvd;\r
171                 this.setText(null);     // 簡易表示時代の名残\r
172                 \r
173                 this.setVerticalAlignment(JButton.TOP);\r
174                 this.setHorizontalAlignment(JButton.LEFT);\r
175                 //this.setBorder(new LineBorder(Color.BLACK,1));\r
176                 this.setOpaque(true);\r
177         }\r
178         public ProgDetailList getInfo() {\r
179                 return tvd;\r
180         }\r
181         \r
182         // 予約待機枠を表示するかどうかの確認\r
183         public boolean isStandby() { return tvd.marked && tvd.showinstandby; }\r
184         \r
185         // 表示スタイル\r
186         public static void setShowStart(boolean b) {\r
187                 showStart = b;\r
188         }\r
189         public static void setSplitEpno(boolean b) {\r
190                 splitEpno = b;\r
191         }\r
192         public static void setShowDetail(boolean b) {\r
193                 showDetail = b;\r
194         }\r
195         public static void setDetailTab(float n) {\r
196                 detailTab = n;\r
197         }\r
198         \r
199         // フォントスタイル\r
200         public static void setTitleFont(String fn) {\r
201                 if ( fn != null && ! fn.equals("") ) {\r
202                         Font f = new Font(fn,titleFontStyle,titleFontSize);\r
203                         if ( f != null ) {\r
204                                 titleFont = f;\r
205                                 return;\r
206                         }\r
207                 }\r
208                 //titleFont = this.getFont();\r
209         }\r
210         public static void setTitleFontSize(int n) {\r
211                 titleFontSize = n;\r
212                 titleFont = titleFont.deriveFont((float)titleFontSize);\r
213         }\r
214         public static void setTitleFontColor(Color c) {\r
215                 titleFontColor = c;\r
216         }\r
217         public static void setDetailFont(String fn) {\r
218                 if ( fn != null && ! fn.equals("") ) {\r
219                         Font f = new Font(fn,detailFontStyle,detailFontSize);\r
220                         if ( f != null ) {\r
221                                 detailFont = f;\r
222                                 startFont = f.deriveFont(Font.BOLD);\r
223                                 return;\r
224                         }\r
225                 }\r
226                 //detailFont = new JLabel().getFont();\r
227         }\r
228         public static void setDetailFontSize(int n) {\r
229                 detailFontSize = n;\r
230                 detailFont = detailFont.deriveFont((float)detailFontSize);\r
231                 startFont = startFont.deriveFont((float)detailFontSize);\r
232         }\r
233         public static void setDetailFontColor(Color c) {\r
234                 detailFontColor = c;\r
235         }\r
236         \r
237         // フォントスタイルの変更\r
238         public static void setTitleFontStyle(ArrayList<FontStyle> fsa) {\r
239                 titleFont = setFontStyle(titleFont, (float)titleFontSize, fsa);\r
240         }\r
241         public static void setDetailFontStyle(ArrayList<FontStyle> fsa) {\r
242                 detailFont = setFontStyle(detailFont, (float)detailFontSize, fsa);\r
243         }\r
244         \r
245         private static Font setFontStyle(Font f, float size, ArrayList<FontStyle> fsa) {\r
246                 Map<TextAttribute, Object>  attributes = new HashMap<TextAttribute, Object>();\r
247                 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);\r
248                 attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);\r
249                 attributes.remove(TextAttribute.UNDERLINE);\r
250                 for ( FontStyle fs : fsa ) {\r
251                         switch (fs) {\r
252                         case BOLD:\r
253                                 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);\r
254                                 break;\r
255                         case ITALIC:\r
256                                 attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);\r
257                                 break;\r
258                         case UNDERLINE:\r
259                                 attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);//LOW_ONE_PIXEL);\r
260                                 break;\r
261                         }\r
262                 }\r
263                 attributes.put(TextAttribute.SIZE, size);\r
264                 return f.deriveFont(attributes);\r
265         }\r
266         \r
267         // フォントエイリアスの変更\r
268         public static void setAAHint(Object o) {\r
269                 frc = new FontRenderContext(null, o, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
270         }\r
271         \r
272         \r
273         /*******************************************************************************\r
274          * メソッド\r
275          ******************************************************************************/\r
276         \r
277         /**\r
278          * ビットマップの描画処理\r
279          */\r
280         @Override\r
281         protected void paintComponent(Graphics g) { \r
282                 \r
283                 super.paintComponent(g);\r
284                 \r
285                 // 初回描画時\r
286                 if (image == null) {\r
287                         //\r
288                         Dimension  d  = getSize();\r
289                         int imgw = d.width;\r
290                         int imgh = d.height;\r
291 \r
292                         float draww = (float)imgw-DRAWTAB*2.0F;\r
293                         float drawh = (float)imgh;\r
294 \r
295                         image = new BufferedImage(imgw, imgh, BufferedImage.TYPE_INT_ARGB);\r
296                         Graphics2D g2 = (Graphics2D)image.createGraphics();\r
297                         \r
298                         g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);\r
299                         g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));\r
300                         \r
301                         float baseline = 0.0F;\r
302                         \r
303                         // 開始時刻と延長警告の描画\r
304                         if (showStart && tvd.start != null && tvd.start.length() > 0) {\r
305                                 FontMetrics fm = g2.getFontMetrics(startFont);\r
306                                 float hi = Float.valueOf(fm.getHeight());\r
307                                 float as = Float.valueOf(fm.getAscent());\r
308                                 \r
309                                 float startx = Float.valueOf(DRAWTAB);\r
310                                 float startw = draww;\r
311                                 float xposstartx = 0.0F;\r
312                                 \r
313                                 baseline = as;  // 初期垂直位置 \r
314                                 \r
315                                 {\r
316                                         WrappedGlyphVector wgv = getWrappedGlyphVector(tvd.start, startw, xposstartx, startFont, as, frc);\r
317                                         GlyphVector gv = wgv.getGv();\r
318                                         g2.setPaint(Color.BLACK);\r
319                                         g2.drawGlyphVector(gv, startx, baseline);\r
320                                         \r
321                                         xposstartx = wgv.getLastX();    // 後続有り\r
322                                         baseline += wgv.getLastY();\r
323                                 }\r
324                                 \r
325                                 {\r
326                                         WrappedGlyphVector wgv = getWrappedGlyphVector(" "+tvd.extension_mark, startw, xposstartx, startFont, as, frc);\r
327                                         GlyphVector gv = wgv.getGv();\r
328                                         g2.setPaint(Color.RED);\r
329                                         g2.drawGlyphVector(gv, startx, baseline);\r
330                                         \r
331                                         baseline += wgv.getLastY();\r
332                                 }\r
333                                 \r
334                                 baseline += hi;\r
335                         }\r
336                         \r
337                         // タイトルの描画\r
338                         String title = ( splitEpno ) ? tvd.splitted_title : tvd.title;\r
339                         if ( title.length() > 0 ) {\r
340                                 //\r
341                                 String aMark;\r
342                                 if (showStart && tvd.start.length() > 0) {\r
343                                         aMark = tvd.prefix_mark + tvd.newlast_mark;\r
344                                 }\r
345                                 else {\r
346                                         if (tvd.start.length() > 0) {\r
347                                                 aMark = tvd.extension_mark + tvd.prefix_mark + tvd.newlast_mark;\r
348                                         }\r
349                                         else {\r
350                                                 aMark = tvd.prefix_mark + tvd.newlast_mark;\r
351                                         }\r
352                                 }\r
353                                 \r
354                                 FontMetrics fm = g2.getFontMetrics(titleFont);\r
355                                 float hi = Float.valueOf(fm.getHeight());\r
356                                 float as = Float.valueOf(fm.getAscent());\r
357                                 \r
358                                 float titlex = Float.valueOf(DRAWTAB);\r
359                                 float titlew = draww;\r
360                                 float xpos = 0.0F;\r
361                                 \r
362                                 if ( baseline == 0.0F ) {\r
363                                         baseline = as;  // 初期垂直位置\r
364                                 }\r
365                                 \r
366                                 if ( aMark.length() > 0 ) {\r
367                                         WrappedGlyphVector wgv = getWrappedGlyphVector(aMark, titlew, xpos, titleFont, as, frc);\r
368                                         GlyphVector gv = wgv.getGv();\r
369                                         g2.setPaint(Color.RED);\r
370                                         g2.drawGlyphVector(gv, titlex, baseline);\r
371                                         \r
372                                         xpos = wgv.getLastX();  // 後続有り\r
373                                         baseline += wgv.getLastY();\r
374                                 }\r
375                                 \r
376                                 {\r
377                                         WrappedGlyphVector wgv = getWrappedGlyphVector(title+tvd.postfix_mark, titlew, xpos, titleFont, as, frc);\r
378                                         GlyphVector gv = wgv.getGv();\r
379                                         g2.setPaint(titleFontColor);\r
380                                         \r
381                                         drawString(g2, wgv, titlex, baseline);\r
382 \r
383                                         baseline += wgv.getLastY();\r
384                                 }\r
385                                 \r
386                                 baseline += hi;\r
387                         }\r
388                         \r
389                         // 番組詳細の描画\r
390                         if ( showDetail ) {\r
391                                 String detail;\r
392                                 if ( splitEpno ) {\r
393                                         detail = tvd.splitted_detail;\r
394                                 }\r
395                                 else {\r
396                                         detail = tvd.detail;\r
397                                 }\r
398                                 \r
399                                 FontMetrics fm = g2.getFontMetrics(detailFont);\r
400                                 float as = Float.valueOf(fm.getAscent());\r
401                                 float detailx = Float.valueOf(DRAWTAB+detailTab);\r
402                                 float detailw = draww-detailTab;\r
403                                 \r
404                                 if ( baseline == 0.0F ) {\r
405                                         baseline = as;  // 初期垂直位置\r
406                                 }\r
407                                 \r
408                                 WrappedGlyphVector wgv = getWrappedGlyphVector(detail, detailw, 0.0f, detailFont, as, frc);\r
409                                 g2.setPaint(detailFontColor);\r
410                                 \r
411                                 drawString(g2, wgv, detailx, baseline);\r
412                         }\r
413                 }\r
414                 \r
415                 // 反映\r
416                 g.drawImage(image, 0, 0, this);\r
417         }\r
418         \r
419         /**\r
420          * \r
421          */\r
422         private void drawString(Graphics2D g2, WrappedGlyphVector wgv, float x, float y) {\r
423                 g2.drawGlyphVector(wgv.getGv(), x, y);\r
424                 \r
425                 if ( wgv.getGv().getFont().getAttributes().get(TextAttribute.UNDERLINE) != null ) {\r
426                         for ( Rectangle r : wgv.getLinePositions() ) {\r
427                                 g2.drawLine((int)x+r.x, (int)y+r.y+1, (int)x+r.x+r.width-1, (int)y+r.y+1);\r
428                         }\r
429                 }\r
430         }\r
431         \r
432         /**\r
433          * 参考:てんぷらメモ/JTableのセル幅で文字列を折り返し  ( http://terai.xrea.jp/Swing/TableCellRenderer.html )\r
434          * @param str                   描画する文字列\r
435          * @param width                 描画領域の幅\r
436          * @param height                描画領域の高さ \r
437          * @param xstart                1行目の描画開始位置\r
438          * @param lineCountMax  最大描画行数\r
439          * @param font                  描画フォント\r
440          * @param lineHeight    1行あたりの高さ\r
441          * @param frc                   FontRenderContext\r
442          * @return\r
443          */\r
444     private WrappedGlyphVector getWrappedGlyphVector(String str, float width, float xstart, Font font, float lineHeight, FontRenderContext frc) {\r
445         Point2D gmPos    = new Point2D.Double(0.0d, 0.0d);\r
446         GlyphVector gv   = font.createGlyphVector(frc, str);\r
447         WrappedGlyphVector wgv = new WrappedGlyphVector(gv);\r
448         float xpos       = xstart;\r
449         float ypos       = 0.0F;\r
450         float advance    = 0.0F;\r
451         GlyphMetrics gm;\r
452         for( int i=0; i <= gv.getNumGlyphs(); i++ ) {\r
453                 if ( i == gv.getNumGlyphs() ) {\r
454                         int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
455                         int y = (int) ypos;\r
456                         int w = (int) (xpos - x);\r
457                         wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
458                         break;\r
459                 }\r
460             gm = gv.getGlyphMetrics(i);\r
461             advance = gm.getAdvance();\r
462             if( xpos < width && width <= xpos+advance ) {\r
463                         int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
464                         int y = (int) ypos;\r
465                         int w = (int) (xpos - x);\r
466                         wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
467                 ypos += lineHeight;\r
468                 xpos = 0.0f;\r
469             }\r
470             gmPos.setLocation(xpos, ypos);\r
471             gv.setGlyphPosition(i, gmPos);\r
472             xpos = xpos + advance;\r
473             \r
474             wgv.setLastX(xpos);\r
475             wgv.setLastY(ypos);\r
476         }\r
477         return wgv;\r
478     }\r
479     \r
480     private class WrappedGlyphVector {\r
481         \r
482         public WrappedGlyphVector(GlyphVector gv) {\r
483                 super();\r
484                 this.gv = gv;\r
485         }\r
486         \r
487         private GlyphVector gv;\r
488         \r
489         public GlyphVector getGv() { return gv; }\r
490         \r
491         private float lastx;\r
492         private float lasty;\r
493         \r
494         public void setLastX(float x) { lastx = x; }\r
495         public float getLastX() { return lastx; }\r
496         public void setLastY(float y) { lasty = y; }\r
497         public float getLastY() { return lasty; }\r
498         \r
499         private ArrayList<Rectangle> linePositions = new ArrayList<Rectangle>();\r
500         public ArrayList<Rectangle> getLinePositions() { return linePositions; }\r
501         public void addLinePosition(Rectangle r) { linePositions.add(r); }\r
502     }\r
503 }\r