OSDN Git Service

・コードダイアグラム周りの改善
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / chorddiagram / ChordDiagram.java
1 package camidion.chordhelper.chorddiagram;
2 import java.awt.Color;
3 import java.awt.Dimension;
4 import java.awt.Insets;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.AdjustmentEvent;
8 import java.awt.event.AdjustmentListener;
9 import java.awt.event.ItemEvent;
10 import java.awt.event.ItemListener;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.EnumMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Objects;
17
18 import javax.swing.Box;
19 import javax.swing.BoxLayout;
20 import javax.swing.ButtonGroup;
21 import javax.swing.JPanel;
22 import javax.swing.JRadioButton;
23 import javax.swing.JScrollBar;
24 import javax.swing.JToggleButton;
25 import javax.swing.SwingConstants;
26
27 import camidion.chordhelper.ButtonIcon;
28 import camidion.chordhelper.ChordDisplayLabel;
29 import camidion.chordhelper.music.Chord;
30 import camidion.chordhelper.music.Note;
31
32 /**
33  * ChordDiagram class for MIDI Chord Helper
34  *
35  * @auther
36  *      Copyright (C) 2004-2017 Akiyoshi Kamide
37  *      http://www.yk.rim.or.jp/~kamide/music/chordhelper/
38  */
39 public class ChordDiagram extends JPanel {
40         /** コードダイアグラムの対象楽器を示す値 */
41         public static enum Instrument {
42                 Ukulele("A,E,C,G"),
43                 Guitar("E,B,G,D,A,E");
44                 /**
45                  * コードダイアグラムの対象楽器を示す値を構築します。
46                  * @param defaultOpenNotes 解放弦の音名(カンマ区切り)
47                  */
48                 private Instrument(String defaultOpenNotes) {
49                         List<Integer> notes = new ArrayList<>();
50                         for( String note : defaultOpenNotes.split(",") )
51                                 notes.add(Note.mod12(Note.toggleCo5(Note.co5Of(note))));
52                         this.defaultOpenNotes = Collections.unmodifiableList(notes);
53                 }
54                 /**
55                  * デフォルトの開放弦の音階を表す、変更不可能なノート番号リストを返します。
56                  * @return 開放弦の音階(固定値)を表すノート番号リスト
57                  */
58                 public List<Integer> getDefaultOpenNotes() { return defaultOpenNotes; }
59                 private List<Integer> defaultOpenNotes;
60                 /**
61                  * 開放弦の音階を表す、変更(チューニング)可能な ノート番号の配列を生成します。
62                  *
63                  * @return 開放弦の音階(デフォルト値)を表すノート番号の配列
64                  */
65                 public int[] createTunableOpenNotes() {
66                         int[] r = new int[defaultOpenNotes.size()];
67                         int i=0;
68                         for(int note : defaultOpenNotes) r[i++] = note;
69                         return r;
70                 }
71         }
72         /**
73          * コードダイアグラムを構築します。
74          * @param capoComboBoxModel カポ値選択コンボボックスのデータモデル
75          */
76         public ChordDiagram(CapoComboBoxModel capoComboBoxModel) {
77                 capoSelecterView.valueSelecter.setModel(capoComboBoxModel);
78                 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
79                 add(new JPanel() {
80                         {
81                                 setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
82                                 setOpaque(false);
83                                 add(Box.createHorizontalStrut(2));
84                                 add(recordTextButton);
85                                 add(Box.createHorizontalStrut(2));
86                                 add(capoSelecterView);
87                         }
88                 });
89                 add(Box.createHorizontalStrut(5));
90                 add(new JPanel() {
91                         {
92                                 setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
93                                 setOpaque(false);
94                                 add(new JPanel() {
95                                         {
96                                                 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
97                                                 setOpaque(false);
98                                                 add(new JPanel() {
99                                                         {
100                                                                 add(titleLabel);
101                                                                 setOpaque(false);
102                                                                 setAlignmentY((float)0);
103                                                         }
104                                                 });
105                                                 add(diagramDisplay);
106                                                 fretRangeScrollbar.setAlignmentY((float)1.0);
107                                                 add(fretRangeScrollbar);
108                                                 add(new JPanel() {
109                                                         {
110                                                                 setOpaque(false);
111                                                                 for(JRadioButton rb : instButtons.values())
112                                                                         add(rb);
113                                                                 setAlignmentY((float)1.0);
114                                                         }
115                                                 });
116                                         }
117                                 });
118                                 add(variationScrollbar);
119                         }
120                 });
121         }
122         /**
123          * コードをテキストに記録するボタン
124          */
125         public JToggleButton recordTextButton =
126                 new JToggleButton("REC", new ButtonIcon(ButtonIcon.REC_ICON)) {
127                         {
128                                 setMargin(new Insets(0,0,0,0));
129                                 setToolTipText("Record to text ON/OFF");
130                         }
131                 };
132         /**
133          * コードダイアグラムのタイトルラベル
134          */
135         public ChordDisplayLabel titleLabel =
136                 new ChordDisplayLabel("Chord Diagram",null,null) {
137                         {
138                                 setHorizontalAlignment(SwingConstants.CENTER);
139                                 setVerticalAlignment(SwingConstants.BOTTOM);
140                         }
141                 };
142         /**
143          * コードダイアグラム表示部
144          */
145         private ChordDiagramDisplay diagramDisplay =
146                 new ChordDiagramDisplay(Instrument.Ukulele) {
147                         {
148                                 setOpaque(false);
149                                 setPreferredSize(new Dimension(120,120));
150                         }
151                 };
152         /**
153          * 対象楽器選択ボタンのマップ
154          */
155         private Map<Instrument,JRadioButton> instButtons =
156                 new EnumMap<Instrument,JRadioButton>(Instrument.class) {
157                         {
158                                 ButtonGroup buttonGroup = new ButtonGroup();
159                                 for( final Instrument instrument : Instrument.values() ) {
160                                         String label = instrument.toString();
161                                         JRadioButton radioButton = new JRadioButton(label) {
162                                                 {
163                                                         setOpaque(false);
164                                                         addActionListener(new ActionListener() {
165                                                                 @Override
166                                                                 public void actionPerformed(ActionEvent e) {
167                                                                         diagramDisplay.tune(instrument);
168                                                                 }
169                                                         });
170                                                 }
171                                         };
172                                         buttonGroup.add(radioButton);
173                                         put(instrument, radioButton);
174                                 }
175                                 get(Instrument.Ukulele).setSelected(true);
176                         }
177                 };
178
179         private JScrollBar variationScrollbar = new JScrollBar(JScrollBar.VERTICAL) {
180                 {
181                         setModel(diagramDisplay.chordVariations.indexModel);
182                         addAdjustmentListener(
183                                 new AdjustmentListener() {
184                                         @Override
185                                         public void adjustmentValueChanged(AdjustmentEvent e) {
186                                                 setToolTipText(diagramDisplay.chordVariations.getIndexDescription());
187                                         }
188                                 }
189                         );
190                 }
191         };
192         private JScrollBar fretRangeScrollbar = new JScrollBar(JScrollBar.HORIZONTAL) {
193                 {
194                         setModel(diagramDisplay.fretViewIndexModel);
195                         setBlockIncrement(diagramDisplay.fretViewIndexModel.getExtent());
196                 }
197         };
198         /**
199          * カポ位置選択コンボボックス
200          */
201         public CapoSelecterView capoSelecterView = new CapoSelecterView() {
202                 {
203                         checkbox.addItemListener(new ItemListener() {
204                                 @Override
205                                 public void itemStateChanged(ItemEvent e) { clear(); }
206                         });
207                 }
208         };
209         @Override
210         public void setBackground(Color bgColor) {
211                 super.setBackground(bgColor);
212                 if( diagramDisplay == null ) return;
213                 diagramDisplay.setBackground(bgColor);
214                 capoSelecterView.setBackground(bgColor);
215                 capoSelecterView.valueSelecter.setBackground(bgColor);
216                 variationScrollbar.setBackground(bgColor);
217                 fretRangeScrollbar.setBackground(bgColor);
218         }
219         /**
220          * コード(和音)をクリアします。
221          *
222          * <p>{@link #setChord(Chord)} の引数に null を指定して呼び出しているだけです。
223          * </p>
224          */
225         public void clear() { setChord(null); }
226         /**
227          * コード(和音)を設定します。
228          * 表示中でない場合、指定のコードに関係なく null が設定されます。
229          *
230          * @param chord コード(クリアする場合は null)
231          */
232         public void setChord(Chord chord) {
233                 if( ! isVisible() ) chord = null;
234                 titleLabel.setChord(chord);
235                 diagramDisplay.setChord(chord);
236         }
237         /**
238          * 対象楽器を切り替えます。
239          * @param instrument 対象楽器
240          * @throws NullPointerException 対象楽器がnullの場合
241          */
242         public void setTargetInstrument(Instrument instrument) {
243                 instButtons.get(Objects.requireNonNull(instrument)).doClick();
244         }
245 }