Package jpianotrain.gui

Source Code of jpianotrain.gui.CircleOfFifths$CirclePane

/* License see bottom */
package jpianotrain.gui;

import static jpianotrain.util.ResourceKeys.LABEL_CHORD;
import static jpianotrain.util.ResourceKeys.LABEL_DOM_SUB;
import static jpianotrain.util.ResourceKeys.LABEL_LEFT;
import static jpianotrain.util.ResourceKeys.LABEL_NOTES_ENGLISH;
import static jpianotrain.util.ResourceKeys.LABEL_PENTATONIC;
import static jpianotrain.util.ResourceKeys.LABEL_RENDER;
import static jpianotrain.util.ResourceKeys.LABEL_RIGHT;
import static jpianotrain.util.ResourceKeys.LABEL_SCALE;
import static jpianotrain.util.ResourceKeys.LABEL_SCALE_MAJOR;
import static jpianotrain.util.ResourceKeys.LABEL_SCALE_MINOR;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

import jpianotrain.Constants;
import jpianotrain.font.MusiQwikB;
import jpianotrain.staff.Chord;
import jpianotrain.staff.Note;
import jpianotrain.staff.NoteName;
import jpianotrain.staff.Scale;
import jpianotrain.staff.ScaleName;
import jpianotrain.util.ResourceFactory;

import org.apache.log4j.Logger;

/**
* Multifunctional visualization of notes, scales and chords.
* Instead of rendering chords and scales as a table one
* can use this class to draw common music theory aspects.
*
* @since 0
* @author Alexander Methke
*/
public class CircleOfFifths extends JPanel
               implements ActionListener,
                       ItemListener {
  private static final Logger log=Logger.getLogger(CircleOfFifths.class);

  public CircleOfFifths() {
    createUI();
  }

  protected void createUI() {
    setLayout(new BorderLayout());
    circlePane=new CirclePane();
    add(circlePane, BorderLayout.CENTER);

    JPanel p=new JPanel();
    GridBagLayout gbl=new GridBagLayout();
    GridBagConstraints gbc=new GridBagConstraints();
    gbc.insets=new Insets(0,1,0,1);
    gbc.gridy=0;

    p.setLayout(gbl);
    maJcb=new JComboBox(Note.MAJOR_NAMES);
    maJcb.addItemListener(this);
    gbc.gridx=0;
    p.add(new JLabel(ResourceFactory.getString(LABEL_SCALE_MAJOR)+": "), gbc);
    gbc.gridx=1;
    p.add(maJcb, gbc);
    miJcb=new JComboBox(Note.MINOR_NAMES);
    miJcb.addItemListener(this);
    gbc.gridx=2;
    p.add(new JLabel(ResourceFactory.getString(LABEL_SCALE_MINOR)+": "), gbc);
    gbc.gridx=3;
    p.add(miJcb, gbc);

    scaleGroup=new ButtonGroup();
    scaleRadio=new JRadioButton(ResourceFactory.getString(LABEL_SCALE));
    scaleRadio.addActionListener(this);
    pentRadio=new JRadioButton(ResourceFactory.getString(LABEL_PENTATONIC));
    pentRadio.addActionListener(this);
    domSubRadio=new JRadioButton(ResourceFactory.getString(LABEL_DOM_SUB));
    domSubRadio.addActionListener(this);
    scaleGroup.add(scaleRadio);
    scaleGroup.add(pentRadio);
    scaleGroup.add(domSubRadio);
    gbc.gridx=4;
    p.add(domSubRadio, gbc);
    gbc.gridx=5;
    p.add(scaleRadio, gbc);
    gbc.gridx=6;
    p.add(pentRadio, gbc);

    enCheck=new JCheckBox(ResourceFactory.getString(LABEL_NOTES_ENGLISH));
    enCheck.addActionListener(this);
    gbc.gridwidth=GridBagConstraints.REMAINDER;
    gbc.gridx=7;
    p.add(enCheck, gbc);

    add(p, BorderLayout.NORTH);

    p=new JPanel();
    gbl=new GridBagLayout();
    p.setLayout(gbl);
    gbc=new GridBagConstraints();
    gbc.insets=new Insets(1,0,1,0);
    gbc.gridx=0;
    gbc.gridy=0;
    gbc.gridwidth=GridBagConstraints.REMAINDER;
    p.add(new JLabel(ResourceFactory.getString(LABEL_CHORD)), gbc);
    gbc.gridwidth=1;
    quadChordCheck=new JCheckBox();
    quadChordCheck.addActionListener(this);

    gbc.gridx=1;
    gbc.gridy=1;
    gbc.fill=GridBagConstraints.HORIZONTAL;
    c1b=new JComboBox(Note.MAJOR_NAMES);
    c2b=new JComboBox(Note.MAJOR_NAMES);
    c3b=new JComboBox(Note.MAJOR_NAMES);
    c4b=new JComboBox(Note.MAJOR_NAMES);
    c4b.setEnabled(false);
    p.add(c1b, gbc);
    gbc.gridy++;
    p.add(c2b, gbc);
    gbc.gridy++;
    p.add(c3b, gbc);
    gbc.gridy++;
    p.add(c4b, gbc);
    gbc.gridx=0;
    p.add(quadChordCheck, gbc);
    gbc.gridx=1;
    drawButton=new JButton(ResourceFactory.getString(LABEL_RENDER));
    drawButton.addActionListener(this);
    gbc.gridy++;
    p.add(drawButton, gbc);
    gbc.gridy++;
    lrotateButton=new JButton(ResourceFactory.getString(LABEL_LEFT));
    lrotateButton.addActionListener(this);
    p.add(lrotateButton, gbc);
    gbc.gridy++;
    rrotateButton=new JButton(ResourceFactory.getString(LABEL_RIGHT));
    rrotateButton.addActionListener(this);
    p.add(rrotateButton, gbc);

    majMinGroup=new ButtonGroup();
    majorRadio=new JRadioButton(ResourceFactory.getString(LABEL_SCALE_MAJOR));
    majorRadio.addActionListener(this);
    minorRadio=new JRadioButton(ResourceFactory.getString(LABEL_SCALE_MINOR));
    minorRadio.addActionListener(this);
    majMinGroup.add(majorRadio);
    majMinGroup.add(minorRadio);
    gbc.gridy++;
    p.add(majorRadio, gbc);
    gbc.gridy++;
    gbc.gridheight=GridBagConstraints.REMAINDER;
    p.add(minorRadio, gbc);

    add(p, BorderLayout.EAST);
  }

  /**
   * Shows Dominant and Subdominat according
   * to the given note. This note is treated
   * like a scale's base note. It's <i>value</i>
   * must be in 12-tone-range.
   *
   * @return Signals if the operation
   *         could be performed.
   */
  public boolean showDomSub(Note n) {
    circlePane.setCenter(n.getName());
    return true;
  }

  /**
   * Shows Dominant and Subdominant of
   * the given scale. Take care, that
   * this scale is either major or
   * minor.
   *
   * @return Signals if the operation
   *         could be performed.
   */
  public boolean showDomSub(Scale s) {
    int len=s.getLength();
    if (len<ScaleName.MAJOR.getMapping().length ||
      len>ScaleName.MAJOR.getMapping().length) {
      // better return instead of
      // throwing Exception(s)
      return false;
    }
    return showDomSub(s.getRoot());
  }

// ItemListener
  public void itemStateChanged(ItemEvent e) {
    Object src=e.getSource();
    boolean update=false;
    if (src==maJcb) {
      lastSelection=(NoteName)maJcb.getSelectedItem();
      update=true;
    } else if (src==miJcb) {
      lastSelection=(NoteName)miJcb.getSelectedItem();
      update=true;
    }
    if (update) {
      // initial phase, if none is selected,
      // select dominant/subdominant
      if (!domSubRadio.isSelected() &&
        !pentRadio.isSelected() &&
        !scaleRadio.isSelected()) {
        domSubRadio.setSelected(true);
      }
      circlePane.setCenter(lastSelection);
    }
  }
// ActionListener
  public void actionPerformed(ActionEvent e) {
    Object src=e.getSource();
    boolean enState=enCheck.isSelected();
    Chord c;
    if (quadChordCheck.isSelected()) {
      c=new Chord((NoteName)c1b.getSelectedItem(),
            (NoteName)c2b.getSelectedItem(),
            (NoteName)c3b.getSelectedItem(),
            (NoteName)c4b.getSelectedItem());
    } else {
      c=new Chord((NoteName)c1b.getSelectedItem(),
            (NoteName)c2b.getSelectedItem(),
            (NoteName)c3b.getSelectedItem());
    }

    if (lastSelection==null) {
      lastSelection=(NoteName)maJcb.getSelectedItem();
    }
    if (src==drawButton) {
      if (!minorRadio.isSelected() &&
        !majorRadio.isSelected()) {
        majorRadio.setSelected(true);
      }
      circlePane.renderChord(c);
    } else if (src==lrotateButton) {
      circlePane.rotateChord(false);
    } else if (src==rrotateButton) {
      circlePane.rotateChord(true);
    } else if (src==majorRadio) {
      circlePane.renderMajorChord(true);
      circlePane.renderChord(c);
    } else if (src==minorRadio) {
      circlePane.renderMajorChord(false);
      circlePane.renderChord(c);
    } else if (src==scaleRadio) {
      circlePane.setRenderMode(CirclePane.RENDER_SCALE);
      circlePane.setCenter(lastSelection);
    } else if (src==domSubRadio) {
      circlePane.setRenderMode(CirclePane.RENDER_DOM_SUB);
      circlePane.setCenter(lastSelection);
    } else if (src==pentRadio) {
      circlePane.setRenderMode(CirclePane.RENDER_PENTATONIC);
      circlePane.setCenter(lastSelection);
    } else if (src==enCheck) {
      circlePane.useEnglish(enCheck.isSelected());
      // only do something if «classic» is already
      // selected
      if (enState) {
        maJcb.setModel(new DefaultComboBoxModel(Note.MAJOR_NAMES_EN));
        miJcb.setModel(new DefaultComboBoxModel(Note.MINOR_NAMES_EN));
      } else {
        maJcb.setModel(new DefaultComboBoxModel(Note.MAJOR_NAMES));
        miJcb.setModel(new DefaultComboBoxModel(Note.MINOR_NAMES));
      }
    } else if (src==quadChordCheck) {
      c4b.setEnabled(quadChordCheck.isSelected());
    }
  }

  public class CirclePane extends JPanel {
    public static final int RENDER_DOM_SUB=1;
    public static final int RENDER_SCALE=2;
    public static final int RENDER_PENTATONIC=4;

    public CirclePane() {
      setOpaque(false);
      majorNameMap=new HashMap<NoteName, Integer>();
      minorNameMap=new HashMap<NoteName, Integer>();
      int len=Scale.MAJOR_SCALES_CLASSIC.length;
      for (int i=0;i<len;i++) {
        majorNameMap.put(majArr[i], i);
        minorNameMap.put(minArr[i], i);
        majPointList.add(p1);
        minPointList.add(p2);
      }
    }

    public void useClassicNames(boolean b) {
      if (b==classicFlag) {
        return;
      }

      classicFlag=b;

      if (enFlag) {
        majArr=Scale.MAJOR_SCALES_CLASSIC_EN;
        minArr=Scale.MINOR_SCALES_CLASSIC_EN;
      } else {
        majArr=Scale.MAJOR_SCALES_CLASSIC;
        minArr=Scale.MINOR_SCALES_CLASSIC;
      }
      majorNameMap.clear();
      minorNameMap.clear();
      for (int i=0;i<majArr.length;i++) {
        majorNameMap.put(majArr[i], i);
        minorNameMap.put(minArr[i], i);
      }
      repaint();
    }

    public void useEnglish(boolean b) {
      if (b==enFlag) {
        return;
      }
      enFlag=b;
      if (enFlag) {
        majArr=Scale.MAJOR_SCALES_CLASSIC_EN;
        minArr=Scale.MINOR_SCALES_CLASSIC_EN;
      } else {
        majArr=Scale.MAJOR_SCALES_CLASSIC;
        minArr=Scale.MINOR_SCALES_CLASSIC;
      }
      majorNameMap.clear();
      minorNameMap.clear();
      for (int i=0;i<majArr.length;i++) {
        majorNameMap.put(majArr[i], i);
        minorNameMap.put(minArr[i], i);
      }
      repaint();
    }

    /**
     * Center the dom/sub rendering around
     * note's name.
     *
     * @param n Note's name, maybe <code>null</code>
     *          to reset rendering.
     * @return If operation was successfull.
     */
    public boolean setCenter(NoteName n) {
      if (n==null) {
        centerIdx=-1;
        repaint();
        return true;
      }

      Integer i=-1;
      if (n.isMajor()) {
        i=majorNameMap.get(n);
      } else {
        i=minorNameMap.get(n);
      }
      if (i==null) {
        if (n.isMajor()) {
          i=majorNameMap.get(Scale.getEnharmonicInScale(enFlag, n));
          majorNameMap.put(n, i);
        } else {
          i=minorNameMap.get(Scale.getEnharmonicInScale(enFlag, n));
          minorNameMap.put(n, i);
        }
      }
      centerIdx=i.intValue();
      repaint();
      return true;
    }

    /**
     * Determines if dominant and sub dominant,
     * the full scale or only the pentatonic
     * part will be highlited.
     */
    public void setRenderMode(int key) {
      switch (key) {
        case RENDER_SCALE:
        case RENDER_PENTATONIC:
        case RENDER_DOM_SUB: {
          scaleCode=key;
        }break;
        default: {
          scaleCode=RENDER_DOM_SUB;
        }
      }
      repaint();
    }

    /**
     * Determines if the major or minor
     * chord should be rendered.
     */
    public void renderMajorChord(boolean f) {
      majorFlag=f;
    }

    public void renderChord(Chord c) {
      if (c==null) {
        cIdx1=-1;
        cIdx2=-1;
        cIdx3=-1;
        cIdx4=-1;
        repaint();
        return;
      }
      Map<NoteName, Integer> map;
      if (majorFlag) {
        map=majorNameMap;
      } else {
        map=minorNameMap;
      }
      cIdx1=getIndexOfName(c.getNote1().getName(), map);
      cIdx2=getIndexOfName(c.getNote2().getName(), map);
      cIdx3=getIndexOfName(c.getNote3().getName(), map);
      if (c.getLength()>3) {
        cIdx4=getIndexOfName(c.getNote4().getName(), map);
      } else {
        cIdx4=-1;
      }
      repaint();
    }

    public void rotateChord(boolean clockWise) {
      int ofs=-1;
      if (clockWise) {
        ofs=1;
      }
      cIdx1=(((cIdx1+ofs)%12)+12)%12;
      cIdx2=(((cIdx2+ofs)%12)+12)%12;
      cIdx3=(((cIdx3+ofs)%12)+12)%12;
      if (cIdx4!=-1) {
        cIdx4=(((cIdx4+ofs)%12)+12)%12;
      }
      repaint();
    }

    public void revalidate() {
      // always the same
      majPointList=new ArrayList<Point>();
      minPointList=new ArrayList<Point>();
      double pRad;
      int idx=1;
      int aIdx=0;
      for (int i=0;i<12;i++) {
        majPointList.add(p1);
        minPointList.add(p2);
      }
      for (int i=30;i<91;i+=30) {
        pRad=radF*(i);
        // center weight points of each
        // sector
        x1=(int)Math.round(Math.sin(pRad)*125);
        x2=(int)Math.round(Math.sin(pRad)*175);
        y1=(int)Math.round(Math.cos(pRad)*125);
        y2=(int)Math.round(Math.cos(pRad)*175);
        // maybe buffering 250+ and 250- saves
        // another 2 adds per iteration
        p1=new Point(250+x1, 250-y1);
        p2=new Point(250+x2, 250-y2);
        minPointList.set(idx, p1);
        majPointList.set(idx, p2);

        p1=new Point(250+y1, 250+x1);
        p2=new Point(250+y2, 250+x2);
        aIdx=idx+3;
        minPointList.set(aIdx, p1);
        majPointList.set(aIdx, p2);

        p1=new Point(250-x1, 250+y1);
        p2=new Point(250-x2, 250+y2);
        aIdx=idx+6;
        minPointList.set(aIdx, p1);
        majPointList.set(aIdx, p2);

        p1=new Point(250-y1, 250-x1);
        p2=new Point(250-y2, 250-x2);
        // avoid index out of bounds
        // and make sector 12=sector 0
        aIdx=idx+9;
        minPointList.set(aIdx%12, p1);
        majPointList.set(aIdx%12, p2);
        idx++;
      }
      Dimension d=new Dimension(500, 510);
      setBounds(0,0, d.width, d.height);
      setPreferredSize(d);
      setMinimumSize(d);
    }

    public void paintComponent(Graphics g) {
      g=g.create();
      Graphics2D g2d=(Graphics2D)g;
      g2d.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
      g2d.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
      try {
        Font sf=ResourceFactory.getNotationFont();
        sf=sf.deriveFont(Font.PLAIN, Constants.NOTATION_FONT_SIZE_SMALL);
        g.setFont(sf);
        g.drawString(MusiQwikB.ONE_SHARP,350,70);
        g.drawString(MusiQwikB.TWO_SHARPS,430,150);
        g.drawString(MusiQwikB.THREE_SHARPS,460,270);
        g.drawString(MusiQwikB.FOUR_SHARPS,430,375);
        g.drawString(MusiQwikB.FIVE_SHARPS,350,470);
        g.drawString(MusiQwikB.SIX_SHARPS, 257, 495);
        g.drawLine(250, 460, 250, 500);
        g.drawString(MusiQwikB.ONE_FLAT,120,70);
        g.drawString(MusiQwikB.TWO_FLATS,25,150);
        g.drawString(MusiQwikB.THREE_FLATS,0,270);
        g.drawString(MusiQwikB.FOUR_FLATS,25,375);
        g.drawString(MusiQwikB.FIVE_FLATS,120,470);
        g.drawString(MusiQwikB.SIX_FLATS, 195, 495);
      } catch (Exception ex) {
        log.error("error while rendering scale markers", ex);
      }

      if (centerIdx>-1) {
        startArc=75-(centerIdx*30);
        g.setColor(lightYellow);
        switch (scaleCode) {
          case RENDER_DOM_SUB: {
            // start at 75° and spin clockwise
            g.fillArc(50,50,400,400,startArc,-30);
            // start at 75°+30° and spin counter clockwise
            g.fillArc(50,50,400,400,startArc+30,30);
          }break;
          case RENDER_SCALE: {
            g.fillArc(50,50,400,400, startArc+60, -210);
            g.setColor(getBackground());
            g.fillOval(100,100,300,300);
            g.setColor(lightYellow);
            g.fillArc(100,100,300,300, startArc+150, -210);
            g.setColor(getBackground());
            g.fillOval(150,150,200,200);
          }break;
          case RENDER_PENTATONIC: {
            g.fillArc(50,50,400,400, startArc+30, -150);
            g.setColor(getBackground());
            g.fillOval(100,100,300,300);
            g.setColor(lightYellow);
            g.fillArc(100,100,300,300, startArc+120, -150);
            g.setColor(getBackground());
            g.fillOval(150,150,200,200);
          }break;
          default: {
          }
        }
        g.setColor(Color.yellow);
        g.fillArc(50,50,400,400,startArc,30);
      }
      g.setColor(Color.black);

      g.drawOval(150,150,200,200);
      g.drawOval(100,100,300,300);
      g.drawOval(50,50,400,400);

      double rad;

      for (int i=15;i<90;i+=30) {
        rad=radF*i;
        x1=(int)Math.round(Math.cos(rad)*100);
        y1=(int)Math.round(Math.sin(rad)*100);
        x2=x1<<1;
        y2=y1<<1;

        g.drawLine(250+x1, 250+y1, 250+x2, 250+y2);
        g.drawLine(250+x1, 250-y1, 250+x2,250-y2);
        g.drawLine(250-x1, 250+y1, 250-x2,250+y2);
        g.drawLine(250-x1, 250-y1, 250-x2,250-y2);
      }

      if (cIdx1!=-1) {
        if (majorFlag) {
          g.setColor(Color.blue);
          p=majPointList.get(cIdx1);
          p1=majPointList.get(cIdx2);
          p2=majPointList.get(cIdx3);
          if (cIdx4!=-1) {
            p3=majPointList.get(cIdx4);
          } else {
            p3=null;
          }
        } else {
          g.setColor(Color.red);
          p=minPointList.get(cIdx1);
          p1=minPointList.get(cIdx2);
          p2=minPointList.get(cIdx3);
          if (cIdx4!=-1) {
            p3=minPointList.get(cIdx4);
          } else {
            p3=null;
          }
        }
        g.drawLine(p.x, p.y, p1.x, p1.y);
        g.drawLine(p1.x, p1.y, p2.x, p2.y);
        if (p3!=null) {
          g.drawLine(p2.x, p2.y, p3.x, p3.y);
          g.drawLine(p3.x, p3.y, p.x, p.y);
        } else {
          g.drawLine(p2.x, p2.y, p.x, p.y);
        }
      }
      g.setColor(Color.black);
      AffineTransform at=AffineTransform.getTranslateInstance(240,91);
      Font font = new Font("SansSerif", Font.PLAIN, 32);
      FontRenderContext frc=new FontRenderContext(at, true, true);
      // sub-panel's coordinate system is not relative
      // to parent by default
      //g2d.setTransform(at);
      g2d.transform(at);
      AffineTransform defStat=g2d.getTransform();
      GlyphVector gv=font.createGlyphVector(frc, majArr[0].toString());
      g2d.drawGlyphVector(gv, 0, 0);

      at=AffineTransform.getTranslateInstance(82,15);
      double rot=30*radF;
      at.rotate(rot);
      int count=majArr.length;
      for (int i=1;i<count;i++) {
        g2d.transform(at);
        gv=font.createGlyphVector(frc, majArr[i].toString());
        g2d.drawGlyphVector(gv, 0, 0);
      }

      // move char's height down
      at=AffineTransform.getTranslateInstance(0, 45);
      // but stay at default transformation (see above)
      g2d.setTransform(defStat);
      g2d.transform(at);
      gv=font.createGlyphVector(frc, minArr[0].toString());
      g2d.drawGlyphVector(gv, 0, 0);

      at=AffineTransform.getTranslateInstance(58,10);
      rot=30*radF;
      at.rotate(rot);
      for (int i=1;i<count;i++) {
        g2d.transform(at);
        gv=font.createGlyphVector(frc, minArr[i].toString());
        g2d.drawGlyphVector(gv, 0, 0);
      }
    }

    private int getIndexOfName(NoteName n,
      Map<NoteName, Integer> m) {
      Integer idx=m.get(n);
      if (idx==null) {
        idx=m.get(Scale.getEnharmonicInScale(
          enFlag, n));
        m.put(n, idx);
      }
      return idx.intValue();
    }

    private boolean classicFlag;
    private boolean enFlag;
    private boolean majorFlag=true;

    private int scaleCode=RENDER_DOM_SUB;
    private int x1;
    private int y1;
    private int x2;
    private int y2;
    private int centerIdx=-1;
    private int startArc;
    private int cIdx1=-1;
    private int cIdx2=-1;
    private int cIdx3=-1;
    private int cIdx4=-1;

    private static final double radF=Math.PI/180;

    private NoteName[] majArr=Scale.MAJOR_SCALES_CLASSIC;
    private NoteName[] minArr=Scale.MINOR_SCALES_CLASSIC;

    private Point p=new Point(0,0);
    private Point p1=new Point(0,0);
    private Point p2=new Point(0,0);
    private Point p3=new Point(0,0);

    private Color lightYellow=new Color(255,255,150);
    private List<Point> majPointList;
    private List<Point> minPointList;

    private HashMap<NoteName, Integer> majorNameMap;
    private HashMap<NoteName, Integer> minorNameMap;
  }

  private NoteName lastSelection;

  private ButtonGroup majMinGroup;
  private ButtonGroup scaleGroup;

  private JButton drawButton;
  private JButton lrotateButton;
  private JButton rrotateButton;

  private JCheckBox enCheck;
  private JCheckBox quadChordCheck;

  private JComboBox c1b;
  private JComboBox c2b;
  private JComboBox c3b;
  private JComboBox c4b;
  private JComboBox maJcb;
  private JComboBox miJcb;

  private JRadioButton domSubRadio;
  private JRadioButton pentRadio;
  private JRadioButton scaleRadio;
  private JRadioButton majorRadio;
  private JRadioButton minorRadio;
  private CirclePane circlePane;
}
/*
    Copyright (C) 2008  Alexander Methke

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program (gplv3.txt).
*/
TOP

Related Classes of jpianotrain.gui.CircleOfFifths$CirclePane

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.