// Copyright 2013 Patrick Forhan.
package wannabe.swing;

import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.ListModel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import wannabe.grid.Grid;
import wannabe.projection.Projection;
import wannabe.projection.Projections;
import wannabe.util.SampleGrids;

public class SettingsPanel extends JPanel {

  private static final long serialVersionUID = 1L;
  private final JList<Projection> projection;
  private final JList<RenderType> renderType;
  private final JList<Grid> grid;
  private Listener listener;
  private boolean reacting;

  public SettingsPanel() {
    super(new GridLayout(4,1));
    setBackground(Color.WHITE);
    setBorder(new EmptyBorder(5, 5, 5, 5));

    // Set up components:
    JTextArea help = new JTextArea("Arrow keys - move"
        + "\nSpace - toggle move camera / player"
        + "\nZ - lower camera"
        + "\nX - raise camera"
        + "\nG - change Grid"
        + "\nA - toggle player grid"
        + "\nR - change renderer"
        + "\nP - change projection"
        + "\n1 - set pixel size to 1"
        + "\n2 - set pixel size to 2"
        + "\n` - set pixel size to default"
        );
    help.setFocusable(false);
    help.setEditable(false);
    help.setBorder(new TitledBorder("Help"));

    projection = new JList<>(createProjectionModel());
    projection.setFocusable(false);
    projection.setBorder(new TitledBorder("Projection"));
    renderType = new JList<>(createRenderTypeModel());
    renderType.setFocusable(false);
    renderType.setBorder(new TitledBorder("Render Type"));
    grid = new JList<>(createGridModel());
    grid.setFocusable(false);
    grid.setBorder(new TitledBorder("Available Grids"));

    // Listen for list changes and fire events accordingly.
    projection.addListSelectionListener(new ListSelectionListener() {
      @Override public void valueChanged(ListSelectionEvent e) {
        if (!reacting && listener != null) {
          listener.onProjectionChanged(Projections.PROJECTIONS.get(projection.getSelectedIndex()));
        }
      }
    });
    renderType.addListSelectionListener(new ListSelectionListener() {
      @Override public void valueChanged(ListSelectionEvent e) {
        if (!reacting && listener != null) {
          listener.onRenderTypeChanged(RenderType.values()[renderType.getSelectedIndex()]);
        }
      }
    });
    grid.addListSelectionListener(new ListSelectionListener() {
      @Override public void valueChanged(ListSelectionEvent e) {
        if (!reacting && listener != null) {
          listener.onGridChanged(SampleGrids.GRIDS.get(grid.getSelectedIndex()));
        }
      }
    });

    // Add all components together:
    add(help);
    add(projection);
    add(renderType);
    add(grid);
  }

  public void setListener(Listener listener) {
    this.listener = listener;
  }

  private ListModel<Grid> createGridModel() {
    DefaultListModel<Grid> model = new DefaultListModel<>();
    for (Grid grid : SampleGrids.GRIDS) {
      model.addElement(grid);
    }
    return model;
  }

  private ListModel<RenderType> createRenderTypeModel() {
    DefaultListModel<RenderType> model = new DefaultListModel<>();
    for (RenderType render : RenderType.values()) {
      model.addElement(render);
    }
    return model;
  }

  protected ListModel<Projection> createProjectionModel() {
    DefaultListModel<Projection> model = new DefaultListModel<>();
    for (Projection projection : Projections.PROJECTIONS) {
      model.addElement(projection);
    }
    return model;
  }

  public interface Listener {
    void onRenderTypeChanged(RenderType newType);
    void onProjectionChanged(Projection newProjection);
    void onGridChanged(Grid newGrid);
  }

  public void gridSelected(Grid grid) {
    reacting = true;
    this.grid.setSelectedValue(grid, true);
    reacting = false;
  }

  public void projectionSelected(Projection projection) {
    reacting = true;
    this.projection.setSelectedValue(projection, true);
    reacting = false;
  }

  public void renderTypeSelected(RenderType renderType) {
    reacting = true;
    this.renderType.setSelectedValue(renderType, true);
    reacting = false;
  }
}

@@ -188,24 +188,56 @@
 ing.JPanel;%0A
+import javax.swing.JScrollPane;%0A
 import javax
@@ -3001,13 +3001,30 @@
 add(
+new JScrollPane(
 help)
+)
 ;%0A  
@@ -3029,16 +3029,32 @@
     add(
+new JScrollPane(
 projecti
@@ -3052,24 +3052,25 @@
 (projection)
+)
 ;%0A    add(re
@@ -3067,16 +3067,32 @@
     add(
+new JScrollPane(
 renderTy
@@ -3090,24 +3090,25 @@
 (renderType)
+)
 ;%0A    add(gr
@@ -3105,21 +3105,38 @@
     add(
+new JScrollPane(
 grid)
+)
 ;%0A  %7D%0A%0A 

Add scrollpanes