Subversion Repositories svn.mios

Rev

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