Subversion Repositories svn.mios

Rev

Rev 250 | Rev 259 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
213 tk 1
/*
2
 * @(#)SIDV2librarian.java  beta1   2008/01/21
3
 *
4
 * Copyright (C) 2008    Rutger Vlek (rutgervlek@hotmail.com)
5
 *
6
 * This application is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This application is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this application; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
package org.midibox.sidedit.gui;
21
 
22
import java.awt.Dimension;
23
import javax.swing.event.*;
245 rutgerv 24
import java.awt.Graphics;
213 tk 25
import java.awt.event.*;
245 rutgerv 26
import java.util.Vector;
213 tk 27
import javax.swing.table.TableModel;
28
import javax.swing.*;
29
import java.util.Observable;
30
import java.util.Observer;
31
import java.util.EventObject;
32
import org.midibox.sidlibr.SIDLibController;
245 rutgerv 33
import java.awt.Color;
250 rutgerv 34
 
35
import javax.swing.BoxLayout;
213 tk 36
import javax.swing.JMenu;
37
import javax.swing.JMenuItem;
38
import javax.swing.JPanel;
39
import javax.swing.JScrollPane;
40
import javax.swing.JTable;
41
import javax.swing.KeyStroke;
42
import javax.swing.ListSelectionModel;
43
import org.midibox.sidlibr.Bank;
44
import java.awt.Font;
245 rutgerv 45
import org.midibox.sidedit.*;
46
import javax.swing.table.*;
47
import java.awt.Component;
213 tk 48
 
250 rutgerv 49
public class WTTable extends JPanel implements TableModelListener, Observer, MouseListener, MouseMotionListener, ActionListener {
213 tk 50
    JTable table;
51
    JPopupMenu popupMenu;
52
    int bankNumber;
53
    int selectedBeforeDrag = 0;
54
    private int wtNumber;
245 rutgerv 55
    private Vector midiParams;
56
    private SIDSysexParameterControl[][] config;
57
    private boolean refreshing = false;
255 rutgerv 58
    public int decHexNote = 0;
246 rutgerv 59
    private boolean valueDragging = false;
60
    private int rowDragging = 0;
61
    private int dragpos = -1;
62
    private float DRAG_SPEED = 1.5F;// 0.01F;
63
    private float startVal = 0;
255 rutgerv 64
    private String[] noteString;
250 rutgerv 65
    private JRadioButton decButton;
66
    private JRadioButton hexButton;
255 rutgerv 67
    private JRadioButton noteButton;
250 rutgerv 68
 
245 rutgerv 69
    public WTTable(int wtNumber, Vector midiParams, SIDSysexParameterControl[][] config) {
213 tk 70
        this.wtNumber = wtNumber;
245 rutgerv 71
        this.midiParams = midiParams;
246 rutgerv 72
        this.config = config;
213 tk 73
 
250 rutgerv 74
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
75
        setOpaque(false);
76
 
245 rutgerv 77
        table = new JTable(new WTTableModel(wtNumber));
213 tk 78
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
246 rutgerv 79
        table.getModel().addTableModelListener(this);
80
        table.addMouseListener(this);
81
        table.addMouseMotionListener(this);
213 tk 82
 
83
        table.getColumnModel().getColumn(0).setPreferredWidth(30);
84
        for (int c=0;c<wtNumber;c++) {
245 rutgerv 85
            table.getColumnModel().getColumn(c+1).setCellRenderer(new ColorCellRenderer());
213 tk 86
            table.getColumnModel().getColumn(c+1).setPreferredWidth(10);
87
        }
88
 
246 rutgerv 89
        table.getColumnModel().getColumn(wtNumber+1).setCellRenderer(new ColorCellRenderer());     
90
        table.getColumnModel().getColumn(wtNumber+1).setPreferredWidth(150);
91
 
245 rutgerv 92
        table.setPreferredScrollableViewportSize(new Dimension(table.getPreferredSize().width, Math.round(table.getPreferredSize().height/10)));
247 tk 93
        // TK: temporary commented out - not available under MacOS, we need a replacement
94
        // table.setFillsViewportHeight(true);
213 tk 95
 
96
        JScrollPane scrollPane = new JScrollPane(table);
97
        scrollPane.setPreferredSize(new Dimension(table.getPreferredSize().width, Math.round(table.getPreferredSize().height/4)));
98
 
245 rutgerv 99
        for(int row=0;row<midiParams.size();row++) {       
100
            ((SIDSysexParameterControl)midiParams.elementAt(row)).addObserver(this);
101
        }  
102
        for(int i=0;i<config.length;i++) { 
103
            for(int j=0;j<config[i].length;j++) {
104
                config[i][j].addObserver(this);
105
            }
106
        }  
255 rutgerv 107
        createNotes();
245 rutgerv 108
        refreshTable();
213 tk 109
        add(scrollPane);
250 rutgerv 110
 
255 rutgerv 111
        decButton = new JRadioButton("Dec view");
250 rutgerv 112
        decButton.setOpaque(false);
255 rutgerv 113
        hexButton = new JRadioButton("Hex view");
250 rutgerv 114
        hexButton.setOpaque(false);
255 rutgerv 115
        noteButton = new JRadioButton("Note view");
116
        noteButton.setOpaque(false);
117
 
250 rutgerv 118
        decButton.setSelected(true);
119
        decButton.addActionListener(this);
120
        hexButton.addActionListener(this);
255 rutgerv 121
        noteButton.addActionListener(this);
122
 
250 rutgerv 123
        JPanel buttonPanel = new JPanel();
124
        buttonPanel.setOpaque(false);
125
        buttonPanel.add(decButton);
126
        buttonPanel.add(hexButton);
255 rutgerv 127
        buttonPanel.add(noteButton);
128
 
250 rutgerv 129
        ButtonGroup bg = new ButtonGroup();
130
        bg.add(decButton);
131
        bg.add(hexButton);
255 rutgerv 132
        bg.add(noteButton);
133
 
250 rutgerv 134
        add(buttonPanel);
245 rutgerv 135
    }  
136
 
137
    public void refreshTable() {       
138
        refreshing = true;
139
        TableModel m = table.getModel();
140
        for(int row=0;row<midiParams.size();row++) {   
141
            String newval = interpret(((SIDSysexParameterControl)midiParams.elementAt(row)).getMidiValue());
142
            m.setValueAt(newval, row, wtNumber+1);
143
 
144
            // Set loop indicator
145
            for(int col=1;col<wtNumber+1;col++) {
146
                if (config[col-1][2].getMidiValue()==row) {
147
                    m.setValueAt("128",row,col);
148
                } else {
149
                    m.setValueAt("",row,col);
150
                }
151
            }
152
        }
153
        refreshing = false;
213 tk 154
    }
155
 
245 rutgerv 156
    private int parseHexDec(String s) {
255 rutgerv 157
        int v = 0;
158
        switch (decHexNote) {
159
            case 0: // Decimal
160
                v = Integer.parseInt(s);
161
                break;         
162
            case 1: // Hexadecimal
163
                v = Integer.parseInt(s, 16);
164
                break;
165
            case 2: // Note view (only lower part)
166
                v = Integer.parseInt(s);
167
                break;
168
            default: throw new NumberFormatException("Input not recognized!");
169
        }
245 rutgerv 170
        return v;
171
    }
213 tk 172
 
255 rutgerv 173
    private int findNote(String s) {
174
        int v = 0;
175
        for(int c=0;c<128;c++) {               
176
            if (noteString[c].equalsIgnoreCase(s)) {
177
                v = c;
178
                break;
179
            }
180
            if (c==127) {
181
                throw new NumberFormatException("Note string not recognized");
182
            }
183
        }
184
        return v;
185
    }
186
 
187
    private void createNotes() {
188
        noteString = new String[256];
189
        String[] notes = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};       
190
        for (int i = 0; i < 128; i++) {
191
            if (i == 0) {
192
                noteString[i] = "---";
193
            }
194
            else if (i == 1) {
195
                noteString[i] = "+++";
196
            }
197
            else if (i < 124) {
198
                int octave = (int) Math.floor((i)/12)-2;
199
                if (octave < 0) {
200
                    noteString[i] = notes[(i)%12] + octave;
201
                }
202
                else {
203
                    noteString[i] = notes[(i)%12] + octave;
204
                }
205
            }
206
            else if (i < 128) {
207
                noteString[i] = "Ky" + Integer.toString(i-123);
208
            }
209
        }
210
    }
211
 
245 rutgerv 212
    private void parseInput(String value, int row) {
213
        int v = ((SIDSysexParameterControl)midiParams.elementAt(row)).getMidiValue();
214
        try {  
215
            if (value.equals("---")) {
216
                v = 128;
217
            } else if (value.equals("+++")) {
218
                v = 129;
219
            } else if (value.substring(0,1).equals("-")) {          // Relative negative value                  
220
                int temp = parseHexDec(value.substring(1));                
221
                if (-temp < -64) {
222
                    v = 0;                     
223
                } else if (-temp > 0) {
224
                    v = 64;                    
225
                } else {
226
                    v = -temp+64;
227
                }
228
            } else if (value.substring(0,1).equals("+")) {          // Relative positive value
229
                int temp = parseHexDec(value.substring(1));
230
                if (temp < 0) {
231
                    v = 63;
232
                } else if (temp > 63) {
233
                    v = 127;                       
234
                } else {
235
                    v = temp+64;
236
                }
255 rutgerv 237
            } else {                                                // Absolute value
238
                int temp;
239
                if (decHexNote==2) {
240
                    temp = findNote(value);
241
                } else {
242
                    temp = parseHexDec(value);
243
                }                  
245 rutgerv 244
                if (temp < 0) {
245
                    v = 128;
246
                } else if (temp > 127) {
247
                    v = 255;                       
248
                } else {
249
                    v = temp+128;
250
                }
213 tk 251
            }
245 rutgerv 252
        } catch (NumberFormatException e) {
253
            // Revert!                              
213 tk 254
        }
245 rutgerv 255
        ((SIDSysexParameterControl)midiParams.elementAt(row)).setMidiValue(v, true);
256
    }
257
 
258
    private String interpretHexDec(int i) {
255 rutgerv 259
        String s = null;
260
        switch (decHexNote) {
261
        case 0: // Decimal
262
            s = Integer.toString(i);
263
            break;         
264
        case 1: // Hexadecimal
245 rutgerv 265
            s = Integer.toHexString(i);
255 rutgerv 266
            break;
267
        case 2: // Note view
268
            s = Integer.toString(i);       
269
            break; 
270
        }
245 rutgerv 271
        return s;
272
    }
273
 
274
    private String interpret(int i) {
275
        String s = "";
276
        if (i < 64) {
277
            s = "-" + interpretHexDec(-i+64);
278
        } else if (i < 128) {
279
            s = "+" + interpretHexDec(i-64);
280
        } else {
255 rutgerv 281
            if (decHexNote==2) {
282
                s = noteString[i-128];             
283
            } else {
284
                s = interpretHexDec(i-128);
285
            }  
213 tk 286
        }
245 rutgerv 287
        return s;
213 tk 288
    }
289
 
245 rutgerv 290
    public void tableChanged(TableModelEvent e) {
291
        if (!refreshing) {
292
            int row = e.getFirstRow();
293
            int column = e.getColumn();
294
            TableModel model = (TableModel)e.getSource();
295
            Object data = model.getValueAt(row, column);
296
            if (column == wtNumber+1) {
297
                parseInput((String)data,row);
298
            }  
299
        }            
300
    }
301
 
302
    public void update(Observable observable, Object object) {
303
        refreshTable();
304
    }
305
 
250 rutgerv 306
    public void actionPerformed(ActionEvent e) {
255 rutgerv 307
        if ((e.getSource()==decButton)||(e.getSource()==hexButton)||(e.getSource()==noteButton)) {
308
            if (decButton.isSelected()) {
309
                decHexNote = 0;
310
            } else if (hexButton.isSelected()) {
311
                decHexNote = 1;
312
            } else if (noteButton.isSelected()) {
313
                decHexNote = 2;
314
            }
250 rutgerv 315
            refreshTable();
316
        }
317
    }
318
 
213 tk 319
    public int getSelectedRow() {
320
        return table.getSelectedRow();
321
    }
245 rutgerv 322
 
246 rutgerv 323
    public void mousePressed(MouseEvent e) {
324
        if (table.getSelectedColumn()==wtNumber+1) {
325
            valueDragging = true;
326
            rowDragging = table.getSelectedRow();
327
            startVal = (float)((SIDSysexParameterControl)midiParams.elementAt(rowDragging)).getMidiValue();
328
            dragpos = e.getX() - e.getY();                     
329
        }          
330
    }
331
 
332
    public void mouseReleased(MouseEvent e) {valueDragging = false;}
333
 
334
    public void mouseEntered(MouseEvent e) {}
335
 
336
    public void mouseExited(MouseEvent e) {}
337
 
338
    public void mouseClicked(MouseEvent e) {}
339
 
340
    public void mouseMoved(MouseEvent me) {}
341
 
342
    public void mouseDragged(MouseEvent me) {
343
        if (valueDragging) {
344
            float f = DRAG_SPEED * (float) ((me.getX() - me.getY()) - dragpos);
255 rutgerv 345
            int newval = Math.round(startVal + f);
346
            if (newval<0) {
347
                newval = 0;
348
            } else if (newval>255) {
349
                newval = 255;
350
            }
351
            table.getModel().setValueAt(interpret(newval), rowDragging, wtNumber+1);           
246 rutgerv 352
        }
353
    }
354
 
245 rutgerv 355
    public class ColorCellRenderer extends JComponent implements TableCellRenderer {
356
        Color curColor;
357
        String curSymbol;
246 rutgerv 358
        int val;
359
 
245 rutgerv 360
        public Component getTableCellRendererComponent(JTable table, Object value,
361
                boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {
362
 
246 rutgerv 363
            if (vColIndex == wtNumber+1) {
364
                curColor = Color.RED;              
365
                val = ((SIDSysexParameterControl)midiParams.elementAt(rowIndex)).getMidiValue();
366
                curSymbol = (String)value;
367
            }
368
 
245 rutgerv 369
            if ((vColIndex > 0) && (vColIndex < wtNumber+1)) {
370
                int b = config[vColIndex-1][0].getMidiValue();
371
                int e = config[vColIndex-1][1].getMidiValue();
372
                int l = config[vColIndex-1][2].getMidiValue();
373
 
374
                if ((rowIndex <= e) && (rowIndex >= b)) {
375
                    curColor = Color.BLACK;
376
                } else {
377
                    curColor = table.getBackground();
378
                }
379
                if (rowIndex==l) {
380
                    curSymbol = "O";
381
                } else {
382
                    curSymbol = "";
383
                }
384
            }
385
            return this;
386
        }
387
 
246 rutgerv 388
        public void paint(Graphics g) {            
389
            if (curColor == Color.RED) {    // Red value indicator
390
                g.setColor(curColor);
391
                g.fillRect(0, 0, Math.round(((float)val/255)*(getWidth()-1)), getHeight()-1);
245 rutgerv 392
            } else {
246 rutgerv 393
                g.setColor(curColor);       // Fill color
394
                g.fillRect(0, 0, getWidth()-1, getHeight()-1);
395
            }            
396
            if (curColor==Color.BLACK) {    // Swap text color to contrast with background
397
                g.setColor(Color.WHITE);               
398
            } else {
245 rutgerv 399
                g.setColor(Color.BLACK);
246 rutgerv 400
            }            
401
            g.drawString(curSymbol, 2, 12); // Add loop symbol (if required)
245 rutgerv 402
        }    
213 tk 403
    }
404
}