Merge branch 'NewPaletteEdit' of ssh://git.code.sf.net/p/suprfractalthng/code into...
[maximus:sft.git] / SuperFractalThing / source / PaletteDialog.java
1 //      PaletteDialog
2 //
3 //    Copyright 2013 Steve Bryson and Kevin Martin
4 //
5 //    This file is part of SuperFractalThing.
6 //
7 //    SuperFractalThing is free software: you can redistribute it and/or modify
8 //    it under the terms of the GNU General Public License as published by
9 //    the Free Software Foundation, either version 3 of the License, or
10 //    any later version.
11 //
12 //    SuperFractalThing is distributed in the hope that it will be useful,
13 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //    GNU General Public License for more details.
16 //
17 //    You should have received a copy of the GNU General Public License
18 //    along with SuperFractalThing.  If not, see <http://www.gnu.org/licenses/>.
19 //
20
21 import java.awt.Color;
22 import java.awt.Component;
23 import java.awt.Dimension;
24 import java.awt.GridBagConstraints;
25 import java.awt.GridBagLayout;
26 import java.awt.Insets;
27 import java.awt.event.*;
28 import java.io.BufferedReader;
29 import java.io.File;
30 import java.io.FileNotFoundException;
31 import java.io.FileReader;
32 import java.io.IOException;
33 import java.text.DecimalFormat;
34 import java.text.NumberFormat;
35
36 import javax.swing.BorderFactory;
37 import javax.swing.JButton;
38 import javax.swing.JColorChooser;
39 import javax.swing.JDialog;
40 import javax.swing.JFormattedTextField;
41 import javax.swing.JFrame;
42 import javax.swing.JLabel;
43 import javax.swing.JMenuBar;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPanel;
46 import javax.swing.JSlider;
47 import javax.swing.JComboBox;
48 import javax.swing.event.*;
49
50 interface PaletteIO
51 {
52         void SavePalette(String str);
53         String LoadPalette();
54 }
55
56 class ColourButton extends JButton implements ActionListener
57 {
58         static final long serialVersionUID = 0;//get rid of warning
59         Color mColour;
60         JFrame mFrame;
61         
62         public ColourButton(String aName, Color col,JFrame aFrame)
63         {
64                 super(aName);
65                 mColour = col;
66                 mFrame = aFrame;
67             setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, mColour));
68             addActionListener(this);
69         }
70         @Override
71         public void actionPerformed(ActionEvent arg0)
72         {
73                 Color c = JColorChooser.showDialog(mFrame, "Pick a Color"
74                 , mColour);     
75                 if (c!=null)
76                         mColour = c;
77                 
78             setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, mColour));
79         }
80
81         public Color GetColour()
82         {
83                 return mColour;
84         }
85         public void SetColour(int r, int g, int b)
86         {
87                 mColour = new Color(r,g,b);
88             setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, mColour));
89         }
90         public void SetColour(Color aColour)
91         {
92                 mColour = aColour;
93             setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, mColour));
94         }
95 }
96
97
98 public class PaletteDialog implements IPaletteDialog, ChangeListener, PaletteLibraryLoader
99 {
100     public static final int NMIXERS = 6;
101
102     JDialog mDialog;
103     JFormattedTextField sFreqScale[];
104     JSlider sFreq[];
105     JLabel freqLabel[];
106     JSlider sAmp[];
107     JLabel ampLabel[];
108     JSlider sPhase[];
109     JLabel phaseLabel[];
110     JSlider sOffset[];
111     JLabel offsetLabel[];
112     JSlider sShape[];
113     JLabel shapeLabel[];
114     
115     JSlider globalPhaseSlider;
116     JLabel globalPhaseLabel;
117     
118     JSlider cMapPhaseSlider;
119     JLabel cMapPhaseLabel;
120     
121     JSlider mixerSlider[];
122     JLabel mixerLabel[];
123     
124     JComboBox<String> cmapNumber;
125     JComboBox<String> hslTypeMenu;
126     JComboBox<?>[] colorComponentTypeMenu;
127     
128     int hslComponentType[][];
129     int hslBaseType[];
130     int prevHslBaseType[];
131
132     //JFormattedTextField mDecay[];
133     JButton mCancel_button;
134     JButton mOK_button;
135     boolean mOK;
136     SFTPalette mPalette;
137     ColourButton mEnd_colour;
138     String mInitial_state;
139     Component mComponent;
140     JFrame mFrame;
141     PaletteIO mPalette_io;
142     boolean paletteLoaded = false;
143     double sliderScale = 1000;
144     
145     PaletteDisplay pDisplay;
146
147         public PaletteDialog (JFrame aFrame, Component aComponent, IPaletteChangeNotify aNotify, PaletteIO aPalette_io)
148         {
149                 mPalette = new SFTPalette(aNotify);
150                 mComponent = aComponent;
151                 mFrame = aFrame;
152                 mPalette_io = aPalette_io;
153                 
154                 mDialog = new JDialog(aFrame, "Edit Palette", false);
155                 
156                 pDisplay = new PaletteDisplay(mPalette, mFrame, mComponent);
157         
158         String[] cComponent = {"Hue", "Saturation", "Luminance"};
159         
160                 colorComponentTypeMenu = new JComboBox[3];
161         sFreqScale = new JFormattedTextField[3];
162         sFreq = new JSlider[3];
163         freqLabel = new JLabel[3];
164         sAmp = new JSlider[3];
165         ampLabel = new JLabel[3];
166         sPhase = new JSlider[3];
167         phaseLabel = new JLabel[3];
168         sOffset = new JSlider[3];
169         offsetLabel = new JLabel[3];
170         sShape = new JSlider[3];
171         shapeLabel = new JLabel[3];
172         
173         mixerSlider = new JSlider[NMIXERS];
174         mixerLabel = new JLabel[NMIXERS];
175         
176         hslComponentType = new int[NMIXERS][3];
177         hslBaseType = new int[NMIXERS];
178         prevHslBaseType = new int[NMIXERS];
179         
180                 JPanel p = new JPanel();
181         JLabel label;
182         mDialog.setSize(new Dimension(550,1000));
183         p.setPreferredSize(new Dimension(540,1000));
184
185         mDialog.setContentPane(p);
186   
187         
188         p.setLayout(new GridBagLayout());
189         GridBagConstraints gbc = new GridBagConstraints();
190
191         NumberFormat format = new DecimalFormat();
192         format.setMaximumFractionDigits(7);
193    
194         gbc.ipady = 0;
195         gbc.gridy=0;
196         gbc.gridwidth=1;
197         gbc.anchor = GridBagConstraints.PAGE_START; //top of space
198         gbc.fill = GridBagConstraints.HORIZONTAL;
199         gbc.gridx=2;
200         mEnd_colour = new ColourButton("M.Set Colour", Color.black, aFrame);
201         mEnd_colour.addChangeListener(this);
202         p.add(mEnd_colour,gbc);       
203         
204         gbc.ipady = 5;
205         
206         gbc.gridx+=2;
207         gbc.fill = GridBagConstraints.HORIZONTAL;
208         gbc.gridwidth=1;
209         JButton help = new JButton("Help");
210         p.add(help,gbc);
211         help.addActionListener(this);
212         
213         gbc.gridy++;
214         
215         gbc.gridx=0;
216         gbc.fill = GridBagConstraints.HORIZONTAL;
217         gbc.gridwidth = 2;
218         String[] options = {"Colormap 1", "Colormap 2", "Colormap 3", "Colormap 4", "Colormap 5", "Colormap 6"};
219         cmapNumber = new JComboBox<String>(options);
220         cmapNumber.setPreferredSize(new Dimension(100,20));
221         cmapNumber.setSelectedIndex(0);
222         cmapNumber.addActionListener(this);
223         p.add(cmapNumber, gbc);
224         
225         gbc.gridx=2;
226         gbc.fill = GridBagConstraints.HORIZONTAL;
227         gbc.gridwidth = 2;
228         String[] typeOptions = SFTPalette.typeNames;
229         hslTypeMenu = new JComboBox<String>(typeOptions);
230         hslTypeMenu.setPreferredSize(new Dimension(100,20));
231         hslTypeMenu.setSelectedIndex(0);
232         hslTypeMenu.addActionListener(this);
233         p.add(hslTypeMenu, gbc);
234
235         gbc.gridy++;
236                 
237         gbc.gridx=0;
238         gbc.gridwidth=3;
239         gbc.fill = GridBagConstraints.HORIZONTAL;
240         label=new JLabel("Phase", null, JLabel.LEFT);
241         p.add(label,gbc);
242         
243         gbc.gridx=1;
244         gbc.fill = GridBagConstraints.HORIZONTAL;
245         gbc.gridwidth = 3;
246         cMapPhaseSlider = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 0);
247         cMapPhaseSlider.setValue(0);
248         cMapPhaseSlider.addChangeListener(this);
249         p.add(cMapPhaseSlider, gbc);
250         
251         gbc.gridx=4;
252         gbc.gridwidth=1;
253         gbc.fill = GridBagConstraints.HORIZONTAL;
254         cMapPhaseLabel=new JLabel("0", null, JLabel.LEFT);
255         p.add(cMapPhaseLabel,gbc);
256         
257         String[] componentTypeOptions = new String[SFTPalette.UNDEFINED];
258         for (int i=0; i<SFTPalette.UNDEFINED; i++)
259                 componentTypeOptions[i] = SFTPalette.typeNames[i];
260         for (int i=0; i<3; i++)
261         {
262             gbc.gridy++;
263             gbc.ipady = 5;
264             gbc.gridx=0;
265             gbc.gridwidth=1;
266             gbc.fill = GridBagConstraints.HORIZONTAL;
267             label=new JLabel(cComponent[i], null, JLabel.LEFT);
268             p.add(label,gbc);
269             gbc.ipady=0;
270
271             gbc.gridx=1;
272             gbc.gridwidth=1;
273             gbc.fill = GridBagConstraints.HORIZONTAL;
274             label=new JLabel("Frequency Scale", null, JLabel.CENTER);
275             p.add(label,gbc);
276
277                 gbc.gridx=2;
278             gbc.gridwidth=1;
279                 gbc.fill = GridBagConstraints.HORIZONTAL;
280                 sFreqScale[i] = new JFormattedTextField(format);
281                 sFreqScale[i].setPreferredSize(new Dimension(80,20));
282                 sFreqScale[i].setValue(1);
283                 p.add(sFreqScale[i], gbc);
284             
285             gbc.gridx=3;
286             gbc.fill = GridBagConstraints.HORIZONTAL;
287             gbc.gridwidth = 2;
288             colorComponentTypeMenu[i] = new JComboBox<String>(componentTypeOptions);
289             colorComponentTypeMenu[i].setPreferredSize(new Dimension(100,20));
290             colorComponentTypeMenu[i].setSelectedIndex(0);
291             colorComponentTypeMenu[i].addActionListener(this);
292             p.add(colorComponentTypeMenu[i], gbc);
293
294             gbc.gridy++;
295             gbc.gridx=0;
296             gbc.gridwidth=1;
297             gbc.fill = GridBagConstraints.HORIZONTAL;
298             label=new JLabel("Frequency", null, JLabel.RIGHT);
299             p.add(label,gbc);
300             
301                 gbc.gridx=1;
302                 gbc.fill = GridBagConstraints.HORIZONTAL;
303             gbc.gridwidth = 3;
304                 sFreq[i] = new JSlider(JSlider.HORIZONTAL, 1, (int) sliderScale, 5);
305                 sFreq[i].setValue(5);
306             sFreq[i].addChangeListener(this);
307                 p.add(sFreq[i], gbc);
308             
309             gbc.gridx=4;
310             gbc.gridwidth=1;
311             gbc.fill = GridBagConstraints.HORIZONTAL;
312             freqLabel[i]=new JLabel("5", null, JLabel.LEFT);
313             p.add(freqLabel[i],gbc);
314            
315             gbc.gridy++;
316             gbc.gridx=0;
317             gbc.gridwidth=1;
318             gbc.fill = GridBagConstraints.HORIZONTAL;
319             label=new JLabel("Amplitude", null, JLabel.RIGHT);
320             p.add(label,gbc);
321             
322                 gbc.gridx=1;
323                 gbc.fill = GridBagConstraints.HORIZONTAL;
324             gbc.gridwidth = 3;
325                 sAmp[i] = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 5);
326                 sAmp[i].setValue(5);
327             sAmp[i].addChangeListener(this);
328                 p.add(sAmp[i], gbc);
329             
330             gbc.gridx=4;
331             gbc.gridwidth=1;
332             gbc.fill = GridBagConstraints.HORIZONTAL;
333             ampLabel[i]=new JLabel("5", null, JLabel.LEFT);
334             p.add(ampLabel[i],gbc);
335             
336             gbc.gridy++;
337             gbc.gridx=0;
338             gbc.gridwidth=1;
339             gbc.fill = GridBagConstraints.HORIZONTAL;
340             label=new JLabel("Phase", null, JLabel.RIGHT);
341             p.add(label,gbc);
342             
343                 gbc.gridx=1;
344                 gbc.fill = GridBagConstraints.HORIZONTAL;
345             gbc.gridwidth = 3;
346                 sPhase[i] = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 5);
347                 sPhase[i].setValue(5);
348             sPhase[i].addChangeListener(this);
349                 p.add(sPhase[i], gbc);
350             
351             gbc.gridx=4;
352             gbc.gridwidth=1;
353             gbc.fill = GridBagConstraints.HORIZONTAL;
354             phaseLabel[i]=new JLabel("5", null, JLabel.LEFT);
355             p.add(phaseLabel[i],gbc);
356             
357             gbc.gridy++;
358             gbc.gridx=0;
359             gbc.gridwidth=1;
360             gbc.fill = GridBagConstraints.HORIZONTAL;
361             label=new JLabel("Offset", null, JLabel.RIGHT);
362             p.add(label,gbc);
363             
364                 gbc.gridx=1;
365                 gbc.fill = GridBagConstraints.HORIZONTAL;
366             gbc.gridwidth = 3;
367                 sOffset[i] = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 5);
368                 sOffset[i].setValue(5);
369             sOffset[i].addChangeListener(this);
370                 p.add(sOffset[i], gbc);
371             
372             gbc.gridx=4;
373             gbc.gridwidth=1;
374             gbc.fill = GridBagConstraints.HORIZONTAL;
375             offsetLabel[i]=new JLabel("5", null, JLabel.LEFT);
376             p.add(offsetLabel[i],gbc);
377             
378             gbc.gridy++;
379             gbc.gridx=0;
380             gbc.gridwidth=1;
381             gbc.fill = GridBagConstraints.HORIZONTAL;
382             label=new JLabel("Shape", null, JLabel.RIGHT);
383             p.add(label,gbc);
384             
385                 gbc.gridx=1;
386                 gbc.fill = GridBagConstraints.HORIZONTAL;
387             gbc.gridwidth = 3;
388                 sShape[i] = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 50);
389                 sShape[i].setValue(50);
390             sShape[i].addChangeListener(this);
391                 p.add(sShape[i], gbc);
392             
393             gbc.gridx=4;
394             gbc.gridwidth=1;
395             gbc.fill = GridBagConstraints.HORIZONTAL;
396             shapeLabel[i]=new JLabel("0", null, JLabel.LEFT);
397             p.add(shapeLabel[i],gbc);
398         }
399   
400
401         
402         gbc.ipady=0;
403         gbc.gridy++;
404
405         gbc.gridx=0;
406         gbc.gridwidth=3;
407         gbc.fill = GridBagConstraints.HORIZONTAL;
408         label=new JLabel("", null, JLabel.LEFT);
409         p.add(label,gbc);
410         gbc.ipady=0;
411         gbc.gridy++;
412         
413         gbc.gridx=0;
414         gbc.gridwidth=3;
415         gbc.fill = GridBagConstraints.HORIZONTAL;
416         label=new JLabel("Mix", null, JLabel.LEFT);
417         p.add(label,gbc);
418         gbc.ipady=0;
419         
420         gbc.gridy++;
421
422         gbc.gridx=0;
423         gbc.gridwidth=3;
424         gbc.fill = GridBagConstraints.HORIZONTAL;
425         label=new JLabel("", null, JLabel.LEFT);
426         p.add(label,gbc);
427         gbc.ipady=0;
428         gbc.gridy++;
429         gbc.gridy++;
430         
431         gbc.gridx=0;
432         gbc.gridwidth=3;
433         gbc.fill = GridBagConstraints.HORIZONTAL;
434         label=new JLabel("Global Phase", null, JLabel.LEFT);
435         p.add(label,gbc);
436         
437         gbc.gridx=1;
438         gbc.fill = GridBagConstraints.HORIZONTAL;
439         gbc.gridwidth = 3;
440         globalPhaseSlider = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 0);
441         globalPhaseSlider.setValue(0);
442         globalPhaseSlider.addChangeListener(this);
443         p.add(globalPhaseSlider, gbc);
444         
445         gbc.gridx=4;
446         gbc.gridwidth=1;
447         gbc.fill = GridBagConstraints.HORIZONTAL;
448         globalPhaseLabel=new JLabel("0", null, JLabel.LEFT);
449         p.add(globalPhaseLabel,gbc);
450         
451         for (int i=0; i<NMIXERS; i++) {
452             gbc.gridy++;
453             gbc.gridx=0;
454             gbc.gridwidth=1;
455             gbc.fill = GridBagConstraints.HORIZONTAL;
456             label=new JLabel("Colormap " + (i+1), null, JLabel.RIGHT);
457             p.add(label,gbc);
458             
459             gbc.gridx=1;
460             gbc.fill = GridBagConstraints.HORIZONTAL;
461             gbc.gridwidth = 3;
462             mixerSlider[i] = new JSlider(JSlider.HORIZONTAL, 0, (int) sliderScale, 0);
463             mixerSlider[i].setValue(0);
464             mixerSlider[i].addChangeListener(this);
465             p.add(mixerSlider[i], gbc);
466             
467             gbc.gridx=4;
468             gbc.gridwidth=1;
469             gbc.fill = GridBagConstraints.HORIZONTAL;
470             mixerLabel[i]=new JLabel("0", null, JLabel.LEFT);
471             p.add(mixerLabel[i],gbc);
472         }
473         
474         gbc.ipady = 0;
475         gbc.insets = new Insets(30,0,0,0);  //top padding
476         gbc.anchor = GridBagConstraints.PAGE_END; //bottom of space
477         gbc.gridx=0;
478         gbc.gridy++;
479         gbc.fill = GridBagConstraints.HORIZONTAL;
480         gbc.gridwidth=1;
481         mCancel_button = new JButton("Load");
482         p.add(mCancel_button,gbc);
483         mCancel_button.addActionListener(this);  
484         
485         gbc.gridx++;
486         gbc.fill = GridBagConstraints.HORIZONTAL;
487         gbc.gridwidth=1;
488         mCancel_button = new JButton("Save");
489         p.add(mCancel_button,gbc);
490         mCancel_button.addActionListener(this); 
491         
492         gbc.gridx++;
493         gbc.gridx++;
494         gbc.fill = GridBagConstraints.HORIZONTAL;
495         gbc.gridwidth=1;
496         mOK_button = new JButton("   Close   ");
497         p.add(mOK_button,gbc);
498         mOK_button.addActionListener(this);             
499
500         }
501         
502         public IPalette GetPalette()
503         {
504                 return mPalette;
505         }
506            
507         public void MakePaletteLibrary(JMenuBar aMenuBar)
508         {
509                 new PaletteLibrary(aMenuBar, this);     
510         }
511
512 /*
513     public void stateChanged(ChangeEvent e) {
514         JSlider source = (JSlider)e.getSource();
515         if (!source.getValueIsAdjusting()) {
516             System.out.format("Slider state change!%n");
517             if (paletteLoaded == true)
518                 SetPaletteValues();
519         }
520     }
521 */
522     public void stateChanged(ChangeEvent e) {
523         //JSlider source = (JSlider)e.getSource();
524         if (paletteLoaded == true) {
525 //              System.out.format("stateChanged%n");                    
526             setCurrentColormap();
527             SetPaletteValues();
528             pDisplay.repaint();
529         }
530     }
531         
532         public boolean Run()
533         {       
534             mDialog.setLocationRelativeTo(mComponent);
535                 mInitial_state = mPalette.ToString();
536                 GetPaletteValues();
537                 mDialog.setVisible(true);
538                 pDisplay.show();
539                 return mOK;
540         }
541
542         @Override
543         public void actionPerformed(ActionEvent event)
544         {
545                 Object source = event.getSource();
546                 String command = event.getActionCommand();
547         int currentCmap = cmapNumber.getSelectedIndex();
548         
549         if (source == cmapNumber) {
550             mPalette.getCmapType(hslBaseType, hslComponentType);
551             hslTypeMenu.setSelectedIndex(hslBaseType[currentCmap]);
552             for (int i=0; i<3; i++)
553                 colorComponentTypeMenu[i].setSelectedIndex(hslComponentType[currentCmap][i]);
554             prevHslBaseType[currentCmap] = hslBaseType[currentCmap];
555         }
556         if (source == hslTypeMenu) {
557 //            System.out.format("HSL menu, command %d%n", hslTypeMenu.getSelectedIndex());
558             hslBaseType[currentCmap] = hslTypeMenu.getSelectedIndex();
559             for (int i=0; i<3; i++)
560                 hslComponentType[currentCmap][i] = hslTypeMenu.getSelectedIndex();
561             
562             mPalette.setCmapType(currentCmap, hslBaseType[currentCmap]);
563 //              System.out.format("changed cmap type%n");               
564             if (!mPalette.getChanged(currentCmap)) {
565                         GetPaletteValues();
566             }
567         }
568         for (int i=0; i<3; i++) {
569                 if (source == colorComponentTypeMenu[i]) {
570                         //            System.out.format("cmap %d Hue menu, command %d%n", currentCmap, colorComponentTypeMenu[0].getSelectedIndex());
571                         hslComponentType[currentCmap][i] = colorComponentTypeMenu[i].getSelectedIndex();
572                         mPalette.setCmapType(currentCmap, i, hslComponentType[currentCmap][i]);
573 //                      System.out.format("changed component %d cmap type%n", i);               
574                         if (!mPalette.getChanged(currentCmap)) 
575                                 GetPaletteValues();
576                         if (hslComponentType[currentCmap][i] != hslBaseType[currentCmap]) {
577                                 hslBaseType[currentCmap] = SFTPalette.UNDEFINED;
578                                 mPalette.setCmapType(currentCmap, hslBaseType[currentCmap]);
579                         }
580                 }
581         }
582         
583                 if (command=="   Close   ")
584                 {
585                         mOK=true;
586                         mDialog.setVisible(false);
587                         SetPaletteValues();
588                 }
589                 else if (command=="Help")
590                 {
591                         JOptionPane.showMessageDialog(mComponent,
592                                         "The palette controls how the color channels change with the iteration count.\n"+
593                                                         "The colors update in real time, and you can see the effect of moving a slider in the Mandelbrot window.\n"+
594                                                         "You can define up to six periodic colormaps of iteration count to color.  These colormaps are combined via the mixer at the bottom.\n"+
595                                                         "Each colormap is defined in terms of its Hue, Saturation and Luminance (HSL) components.\n"+
596                                                         "Each HSL component of each colormap has one of 6 shapes:\n" +
597                                                         "- sinusoid, Gaussian, ramp, two-sided-ramp, exponential ramp, exponential two-sided-ramp and stripe.\n"+
598                                                         "The shape is chosen via the menus.\n"+
599                                                         "The menu on the upper right sets all three HSL comonents to the same shape.\n"+
600                                                         "Each shape is controlled via 5 parameters.  The menu on the upper left controls which colormap is being controlled by the sliders:\n"+
601                                                         "- Frequency: how often the shape repeats.  The frequency scale sets the scale of the frequency slider\n"+
602                                                         "--- Smaller frequency scales are useful when you are deeply zoomed in near the boundary of the Mandelbrot set.\n"+
603                                                         "- Amplitude: the strength of the shape\n"+
604                                                         "- Phase: offset in the period where the repeating shape is defined\n"+
605                                                         "- Offset: The color component value of the zero point of the shape\n"+
606                                                         "- Shape: A parameter the acts differently on the different shapes:\n"+
607                                                         "--- Sine: shape skews the sine curve so the maximum and minimum are moved towards the center of the period.\n"+
608                                                         "--- Gaussian, two-sided-ramp, exponential two-sided-ramp and stripe: shape controls the width of the ramp. Negative values invert the shape\n"+
609                                                         "--- Ramp and exponential ramp: shape controls the length of the ramp. Negative values move the ramp in the opposite direction\n"+
610                                                         "The colormap phase slider at the top controls the phase of all three HSL components for the current colormap.\n"+
611                                                         "The global phase slider above the mixer controls the phase of all HSL components of all colormaps.\n"+
612                                                         "\n"+
613                                                         "Roughly, if f(x) is the shape, where x is (the iteration count mod 10,000) divided by 10,000,\n"+
614                                                         "colormap HSL component = offset + (1-offset)*amplitude*f(x + phase).\n"+
615                                                         "Here phase = global phase + colormap phase + component phase.\n"+
616                                                         "",
617                                                                 "Palette Help",                                 
618                                                                 JOptionPane.PLAIN_MESSAGE);
619         
620                 }
621                 else if (command=="Load")
622                 {
623                         String str = mPalette_io.LoadPalette();
624                         if (str!=null)
625                         {
626                                 mPalette.ParseString(str);
627                                 paletteLoaded = true;
628                                                 
629                         setCurrentColormap();
630                                 GetPaletteValues();
631                         mPalette.setMixRange();
632                                 SetPaletteValues();
633                         pDisplay.repaint();                     
634                         }
635                 }
636                 else if (command=="Save")
637                 {
638                         String str = mPalette.ToString();
639
640                         mPalette_io.SavePalette(str);
641                 }               
642         SetPaletteValues();
643         setCurrentColormap();
644                 GetPaletteValues();
645         }
646         
647         void setCurrentColormap()
648         {
649         int currentCmap = cmapNumber.getSelectedIndex();
650                 mPalette.setCurrentColormap(currentCmap);
651         }
652         
653         void setCmapType()
654         {
655                 mPalette.setCmapType(hslBaseType, hslComponentType);
656         }
657         
658         void getCmapType()
659         {
660                 mPalette.getCmapType(hslBaseType, hslComponentType);
661         }
662         
663         void GetPaletteValues()
664         {
665                 double[] p = new double[NMIXERS];
666                 double[][] s = new double[3][6];
667                 Color cols[] = new Color[2];
668         int currentCmap = cmapNumber.getSelectedIndex();
669                 double cMapPhase = SFTPalette.getCMapPhase(currentCmap);
670                 double globalPhase = SFTPalette.getGlobalPhase();
671                 
672                 mPalette.GetGradientValues(p, s, cols);
673 //      System.out.format("GetPaletteValues: globalPhase = %f, cMapPhase = %f%n", globalPhase, cMapPhase);
674         
675                 mEnd_colour.SetColour(cols[1]);
676                 
677                 for (int i=0; i<3; i++)
678                 {
679 //                      System.out.format("set component %d values: %n", i);
680 //                      for (int j=0; j<6; j++)
681 //                              System.out.format(" %f", s[i][j]);
682 //                      System.out.format("%n");
683                         
684                         sFreqScale[i].setValue(s[i][0]);
685                         sFreq[i].setValue((int) (s[i][1]*sliderScale));
686                         sAmp[i].setValue((int) (s[i][2]*sliderScale));
687                         sPhase[i].setValue((int) (s[i][3]*sliderScale/(2f*Math.PI)));
688                         sOffset[i].setValue((int) (s[i][4]*sliderScale));
689                         sShape[i].setValue((int) (s[i][5]*sliderScale));
690                 }
691         
692                 cMapPhaseSlider.setValue((int) (cMapPhase*sliderScale/(2f*Math.PI)));
693                 globalPhaseSlider.setValue((int) (globalPhase*sliderScale/(2f*Math.PI)));
694
695                 for (int i=0; i<NMIXERS; i++) {
696                         mixerSlider[i].setValue((int) (((p[i]+1)/2)*sliderScale));
697         }
698         
699         mPalette.getCmapType(hslBaseType, hslComponentType);
700 //        System.out.format("GetPaletteValues: currentCmap = %d, hslBaseType = %d, prevHslBaseType = %d%n", currentCmap, hslBaseType[currentCmap], prevHslBaseType[currentCmap]);
701 //              for (int i=0; i<3; i++)
702 //              System.out.format("component %d type = %d%n", i, hslComponentType[currentCmap][i]);
703         if (hslBaseType[currentCmap] != prevHslBaseType[currentCmap]) {
704 //            System.out.format("setting menus%n");
705
706                 hslTypeMenu.setSelectedIndex(hslBaseType[currentCmap]);
707 //              if (hslBaseType[currentCmap] != SFTPalette.UNDEFINED)
708                         for (int i=0; i<3; i++)
709                                 colorComponentTypeMenu[i].setSelectedIndex(hslComponentType[currentCmap][i]);
710             prevHslBaseType[currentCmap] = hslBaseType[currentCmap];
711         } else {
712                 if (hslBaseType[currentCmap] == SFTPalette.UNDEFINED)
713                         for (int i=0; i<3; i++)
714                                 colorComponentTypeMenu[i].setSelectedIndex(hslComponentType[currentCmap][i]);
715         }
716         
717         paletteLoaded = true;
718         pDisplay.repaint();
719         }
720     
721         void SetPaletteValues()
722         {
723                 double[] p = new double[NMIXERS];
724                 double[][] s = new double[3][6];
725                 
726                 for (int i=0; i<3; i++)
727                 {
728                         s[i][0] = (double) Float.parseFloat(sFreqScale[i].getText().replace(",",""));
729                         s[i][1] = (double) (((Number)(sFreq[i].getValue())).floatValue())/sliderScale;
730                         s[i][2] = (double) (((Number)(sAmp[i].getValue())).floatValue())/sliderScale;
731                         s[i][3] = (double) 2f*Math.PI*(((Number)(sPhase[i].getValue())).floatValue())/sliderScale;
732                         s[i][4] = (double) (((Number)(sOffset[i].getValue())).floatValue())/sliderScale;
733                         s[i][5] = (double) (((Number)(sShape[i].getValue())).floatValue())/sliderScale;
734             
735             freqLabel[i].setText(""+round(sFreq[i].getValue()*Float.parseFloat(sFreqScale[i].getText().replace(",",""))/sliderScale, 2));
736             ampLabel[i].setText(""+round(sAmp[i].getValue()/sliderScale, 6));
737             phaseLabel[i].setText(""+round(2f*sPhase[i].getValue()/sliderScale, 2)+"\u03c0");
738             offsetLabel[i].setText(""+round(sOffset[i].getValue()/sliderScale, 2));
739             shapeLabel[i].setText(""+round(2*(sShape[i].getValue()/sliderScale - 0.5), 2));
740                 }
741         
742                 double globalPhase = (double) 2f*Math.PI*(((Number)(globalPhaseSlider.getValue())).floatValue())/sliderScale;
743                 globalPhaseLabel.setText(""+round(2f*globalPhaseSlider.getValue()/sliderScale, 2)+"\u03c0");
744         
745                 double cMapPhase = (double) 2f*Math.PI*(((Number)(cMapPhaseSlider.getValue())).floatValue())/sliderScale;
746                 cMapPhaseLabel.setText(""+round(2f*cMapPhaseSlider.getValue()/sliderScale, 2)+"\u03c0");
747                 
748         for (int i=0; i<NMIXERS; i++) {
749                         p[i] = (double) 2*((((Number)(mixerSlider[i].getValue())).floatValue())/sliderScale - 0.5);
750                         if (Math.abs(p[i]) < 0.005)
751                                 p[i] = 0;
752             mixerLabel[i].setText(""+round(p[i], 2));
753         }
754         
755         SFTPalette.setGlobalPhase(globalPhase);
756         SFTPalette.setCMapPhase(cMapPhase);
757                 mPalette.SetGradientValues(p, s, mEnd_colour.GetColour());
758         }
759                                   
760     double round(double x, int nDecimals) {
761         double decFac = Math.pow(10d,(double)nDecimals+1);
762         return Math.round(x*decFac)/decFac;
763     }
764
765         public void LoadTheFile(File f)
766         {
767                 try
768                 {
769                         FileReader fr = new FileReader(f);
770                         BufferedReader br = new BufferedReader(fr);
771                         LoadTheFile(br);
772                 } catch (FileNotFoundException e) {
773                         // TODO Auto-generated catch block
774                         e.printStackTrace();
775                 }
776         }
777         
778         public void LoadTheFile(BufferedReader br)
779         {
780                 String str;
781                 
782                 char arr[]=new char[2048];
783
784                 try {
785                         br.read(arr, 0,2048);
786                 } catch (IOException e) {
787                         // TODO Auto-generated catch block
788                         e.printStackTrace();
789                         return;
790                 }
791                 str = String.copyValueOf(arr);
792                 
793                 mPalette.ParseString(str);
794                 paletteLoaded = true;
795                                 
796         setCurrentColormap();
797                 GetPaletteValues();
798         mPalette.setMixRange();
799                 SetPaletteValues();
800         pDisplay.repaint();
801         }
802 }