chiark / gitweb /
Fix an amusing cut-and-paste error in the Java drawing code which was
[sgt-puzzles.git] / PuzzleApplet.java
1 /*
2  * PuzzleApplet.java: NestedVM applet for the puzzle collection
3  */
4 import java.awt.*;
5 import java.awt.event.*;
6 import java.awt.image.BufferedImage;
7 import java.util.*;
8 import javax.swing.*;
9 import javax.swing.border.BevelBorder;
10 import javax.swing.Timer;
11 import java.util.List;
12
13 import org.ibex.nestedvm.Runtime;
14
15 public class PuzzleApplet extends JApplet implements Runtime.CallJavaCB {
16
17     private static final long serialVersionUID = 1L;
18
19     private static final int CFG_SETTINGS = 0, CFG_SEED = 1, CFG_DESC = 2,
20             LEFT_BUTTON = 0x0200, MIDDLE_BUTTON = 0x201, RIGHT_BUTTON = 0x202,
21             LEFT_DRAG = 0x203, MIDDLE_DRAG = 0x204, RIGHT_DRAG = 0x205,
22             LEFT_RELEASE = 0x206, CURSOR_UP = 0x209, CURSOR_DOWN = 0x20a,
23             CURSOR_LEFT = 0x20b, CURSOR_RIGHT = 0x20c, MOD_CTRL = 0x1000,
24             MOD_SHFT = 0x2000, MOD_NUM_KEYPAD = 0x4000, ALIGN_VCENTRE = 0x100,
25             ALIGN_HCENTRE = 0x001, ALIGN_HRIGHT = 0x002, C_STRING = 0,
26             C_CHOICES = 1, C_BOOLEAN = 2;
27
28     private JFrame mainWindow;
29
30     private JMenu typeMenu;
31     private JMenuItem solveCommand;
32     private Color[] colors;
33     private JLabel statusBar;
34     private PuzzlePanel pp;
35     private Runtime runtime;
36     private String[] puzzle_args;
37     private Graphics2D  gg;
38     private Timer timer;
39     private int xarg1, xarg2, xarg3;
40     private int[] xPoints, yPoints;
41     private BufferedImage[] blitters = new BufferedImage[512];
42     private ConfigDialog dlg;
43
44     static {
45         try {
46             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
47         } catch (Exception ex) {
48             ex.printStackTrace();
49         }
50     }
51
52     public void init() {
53         try {
54             Container cp = getContentPane();
55             cp.setLayout(new BorderLayout());
56             runtime = (Runtime) Class.forName("PuzzleEngine").newInstance();
57             runtime.setCallJavaCB(this);
58             JMenuBar menubar = new JMenuBar();
59             JMenu jm;
60             menubar.add(jm = new JMenu("Game"));
61             addMenuItemWithKey(jm, "New", 'n');
62             addMenuItemCallback(jm, "Restart", "jcallback_restart_event");
63             addMenuItemCallback(jm, "Specific...", "jcallback_config_event", CFG_DESC);
64             addMenuItemCallback(jm, "Random Seed...", "jcallback_config_event", CFG_SEED);
65             jm.addSeparator();
66             addMenuItemWithKey(jm, "Undo", 'u');
67             addMenuItemWithKey(jm, "Redo", 'r');
68             jm.addSeparator();
69             solveCommand = addMenuItemCallback(jm, "Solve", "jcallback_solve_event");
70             solveCommand.setEnabled(false);
71             if (mainWindow != null) {
72                 jm.addSeparator();
73                 addMenuItemWithKey(jm, "Exit", 'q');
74             }
75             menubar.add(typeMenu = new JMenu("Type"));
76             typeMenu.setVisible(false);
77             menubar.add(jm = new JMenu("Help"));
78             addMenuItemCallback(jm, "About", "jcallback_about_event");
79             setJMenuBar(menubar);
80             cp.add(pp = new PuzzlePanel(), BorderLayout.CENTER);
81             pp.addKeyListener(new KeyAdapter() {
82                 public void keyPressed(KeyEvent e) {
83                     int key = -1;
84                     int shift = e.isShiftDown() ? MOD_SHFT : 0;
85                     int ctrl = e.isControlDown() ? MOD_CTRL : 0;
86                     switch (e.getKeyCode()) {
87                     case KeyEvent.VK_LEFT:
88                     case KeyEvent.VK_KP_LEFT:
89                         key = shift | ctrl | CURSOR_LEFT;
90                         break;
91                     case KeyEvent.VK_RIGHT:
92                     case KeyEvent.VK_KP_RIGHT:
93                         key = shift | ctrl | CURSOR_RIGHT;
94                         break;
95                     case KeyEvent.VK_UP:
96                     case KeyEvent.VK_KP_UP:
97                         key = shift | ctrl | CURSOR_UP;
98                         break;
99                     case KeyEvent.VK_DOWN:
100                     case KeyEvent.VK_KP_DOWN:
101                         key = shift | ctrl | CURSOR_DOWN;
102                         break;
103                     case KeyEvent.VK_PAGE_UP:
104                         key = shift | ctrl | MOD_NUM_KEYPAD | '9';
105                         break;
106                     case KeyEvent.VK_PAGE_DOWN:
107                         key = shift | ctrl | MOD_NUM_KEYPAD | '3';
108                         break;
109                     case KeyEvent.VK_HOME:
110                         key = shift | ctrl | MOD_NUM_KEYPAD | '7';
111                         break;
112                     case KeyEvent.VK_END:
113                         key = shift | ctrl | MOD_NUM_KEYPAD | '1';
114                         break;
115                     default:
116                         if (e.getKeyCode() >= KeyEvent.VK_NUMPAD0 && e.getKeyCode() <=KeyEvent.VK_NUMPAD9) {
117                             key = MOD_NUM_KEYPAD | (e.getKeyCode() - KeyEvent.VK_NUMPAD0+'0');
118                         }
119                     break;
120                     }
121                     if (key != -1) {
122                         runtimeCall("jcallback_key_event", new int[] {0, 0, key});
123                     }
124                 }
125                 public void keyTyped(KeyEvent e) {
126                     runtimeCall("jcallback_key_event", new int[] {0, 0, e.getKeyChar()});
127                 }
128             });
129             pp.addMouseListener(new MouseAdapter() {
130                 public void mouseReleased(MouseEvent e) {
131                     mousePressedReleased(e, true);
132                 }
133                 public void mousePressed(MouseEvent e) {
134                     pp.requestFocus();
135                     mousePressedReleased(e, false);
136                 }
137                 private void mousePressedReleased(MouseEvent e, boolean released) {
138                     int button;
139                     if ((e.getModifiers() & (InputEvent.BUTTON2_MASK | InputEvent.SHIFT_MASK)) != 0)
140                         button = MIDDLE_BUTTON;
141                     else if ((e.getModifiers() & (InputEvent.BUTTON3_MASK | InputEvent.ALT_MASK)) != 0)
142                         button = RIGHT_BUTTON;
143                     else if ((e.getModifiers() & (InputEvent.BUTTON1_MASK)) != 0)
144                         button = LEFT_BUTTON;
145                     else
146                         return;
147                     if (released)
148                         button += LEFT_RELEASE - LEFT_BUTTON;
149                     runtimeCall("jcallback_key_event", new int[] {e.getX(), e.getY(), button});
150                 }
151             });
152             pp.addMouseMotionListener(new MouseMotionAdapter() {
153                 public void mouseDragged(MouseEvent e) {
154                     int button;
155                     if ((e.getModifiers() & (InputEvent.BUTTON2_MASK | InputEvent.SHIFT_MASK)) != 0)
156                         button = MIDDLE_DRAG;
157                     else if ((e.getModifiers() & (InputEvent.BUTTON3_MASK | InputEvent.ALT_MASK)) != 0)
158                         button = RIGHT_DRAG;
159                     else
160                         button = LEFT_DRAG;
161                     runtimeCall("jcallback_key_event", new int[] {e.getX(), e.getY(), button});
162                 }
163             });
164             pp.addComponentListener(new ComponentAdapter() {
165                 public void componentResized(ComponentEvent e) {
166                     handleResized();
167                 }
168             });
169             pp.setFocusable(true);
170             pp.requestFocus();
171             timer = new Timer(20, new ActionListener() {
172                 public void actionPerformed(ActionEvent e) {
173                     runtimeCall("jcallback_timer_func", new int[0]);
174                 }
175             });
176             String gameid;
177             try {
178                 gameid = getParameter("game_id");
179             } catch (java.lang.NullPointerException ex) {
180                 gameid = null;
181             }
182             if (gameid == null) {
183                 puzzle_args = null;
184             } else {
185                 puzzle_args = new String[2];
186                 puzzle_args[0] = "puzzle";
187                 puzzle_args[1] = gameid;
188             }
189             SwingUtilities.invokeLater(new Runnable() {
190                 public void run() {
191                     runtime.start(puzzle_args);
192                     runtime.execute();
193                 }
194             });
195         } catch (Exception ex) {
196             ex.printStackTrace();
197         }
198     }
199
200     public void destroy() {
201         SwingUtilities.invokeLater(new Runnable() {
202             public void run() {
203                 runtime.execute();
204                 if (mainWindow != null) {
205                     mainWindow.dispose();
206                     System.exit(0);
207                 }
208             }
209         });
210     }
211
212     protected void handleResized() {
213         pp.createBackBuffer(pp.getWidth(), pp.getHeight(), colors[0]);
214         runtimeCall("jcallback_resize", new int[] {pp.getWidth(), pp.getHeight()});
215     }
216
217     private void addMenuItemWithKey(JMenu jm, String name, int key) {
218         addMenuItemCallback(jm, name, "jcallback_menu_key_event", key);
219     }
220
221     private JMenuItem addMenuItemCallback(JMenu jm, String name, final String callback, final int arg) {
222         return addMenuItemCallback(jm, name, callback, new int[] {arg});
223     }
224
225     private JMenuItem addMenuItemCallback(JMenu jm, String name, final String callback) {
226         return addMenuItemCallback(jm, name, callback, new int[0]);
227     }
228
229     private JMenuItem addMenuItemCallback(JMenu jm, String name, final String callback, final int[] args) {
230         JMenuItem jmi;
231         if (jm == typeMenu)
232             typeMenu.add(jmi = new JCheckBoxMenuItem(name));
233         else
234         jm.add(jmi = new JMenuItem(name));
235         jmi.addActionListener(new ActionListener() {
236             public void actionPerformed(ActionEvent e) {
237                 runtimeCall(callback, args);
238             }
239         });
240         return jmi;
241     }
242
243     protected void runtimeCall(String func, int[] args) {
244         if (runtimeCallWithResult(func, args) == 42 && mainWindow != null) {
245             destroy();
246         }
247     }
248
249     protected int runtimeCallWithResult(String func, int[] args) {
250         try {
251             return runtime.call(func, args);
252         } catch (Runtime.CallException ex) {
253             ex.printStackTrace();
254             return 42;
255         }
256     }
257
258     private void buildConfigureMenuItem() {
259         if (typeMenu.isVisible()) {
260             typeMenu.addSeparator();
261         } else {
262             typeMenu.setVisible(true);
263         }
264         addMenuItemCallback(typeMenu, "Custom...", "jcallback_config_event", CFG_SETTINGS);
265     }
266
267     private void addTypeItem(String name, final int ptrGameParams) {
268         typeMenu.setVisible(true);
269         addMenuItemCallback(typeMenu, name, "jcallback_preset_event", ptrGameParams);
270     }
271
272     public int call(int cmd, int arg1, int arg2, int arg3) {
273         try {
274             switch(cmd) {
275             case 0: // initialize
276                 if (mainWindow != null) mainWindow.setTitle(runtime.cstring(arg1));
277                 if ((arg2 & 1) != 0) buildConfigureMenuItem();
278                 if ((arg2 & 2) != 0) addStatusBar();
279                 if ((arg2 & 4) != 0) solveCommand.setEnabled(true);
280                 colors = new Color[arg3];
281                 return 0;
282             case 1: // Type menu item
283                 addTypeItem(runtime.cstring(arg1), arg2);
284                 return 0;
285             case 2: // MessageBox
286                 JOptionPane.showMessageDialog(this, runtime.cstring(arg2), runtime.cstring(arg1), arg3 == 0 ? JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE);
287                 return 0;
288             case 3: // Resize
289                 pp.setPreferredSize(new Dimension(arg1, arg2));
290                 if (mainWindow != null) mainWindow.pack();
291                 handleResized();
292                 if (mainWindow != null) mainWindow.setVisible(true);
293                 return 0;
294             case 4: // drawing tasks
295                 switch(arg1) {
296                 case 0:
297                     String text = runtime.cstring(arg2);
298                     if (text.equals("")) text = " ";
299                     System.out.println("status '" + text + "'");
300                     statusBar.setText(text);
301                     break;
302                 case 1:
303                     gg = pp.backBuffer.createGraphics();
304                     if (arg2 != 0 || arg3 != 0 ||
305                         arg2 + xarg2 != getWidth() ||
306                         arg3 + xarg3 != getHeight()) {
307                         int left = arg2, right = arg2 + xarg2;
308                         int top = arg3, bottom = arg3 + xarg3;
309                         int width = getWidth(), height = getHeight();
310                         gg.setColor(colors != null ? colors[0] : Color.black);
311                         gg.fillRect(0, 0, left, height);
312                         gg.fillRect(right, 0, width-right, height);
313                         gg.fillRect(0, 0, width, top);
314                         gg.fillRect(0, bottom, width, height-bottom);
315                         gg.setClip(left, top, right-left, bottom-top);
316                     }
317                     break;
318                 case 2: gg.dispose(); pp.repaint(); break;
319                 case 3: gg.setClip(arg2, arg3, xarg1, xarg2); break;
320                 case 4:
321                     if (arg2 == 0 && arg3 == 0) {
322                         gg.setClip(0, 0, getWidth(), getHeight());
323                     } else {
324                         gg.setClip(arg2, arg3, getWidth()-2*arg2, getHeight()-2*arg3);
325                     }
326                     break;
327                 case 5:
328                     gg.setColor(colors[xarg3]);
329                     gg.fillRect(arg2, arg3, xarg1, xarg2);
330                     break;
331                 case 6:
332                     gg.setColor(colors[xarg3]);
333                     gg.drawLine(arg2, arg3, xarg1, xarg2);
334                     break;
335                 case 7:
336                     xPoints = new int[arg2];
337                     yPoints = new int[arg2];
338                     break;
339                 case 8:
340                     if (arg3 != -1) {
341                         gg.setColor(colors[arg3]);
342                         gg.fillPolygon(xPoints, yPoints, xPoints.length);
343                     }
344                     gg.setColor(colors[arg2]);
345                     gg.drawPolygon(xPoints, yPoints, xPoints.length);
346                     break;
347                 case 9:
348                     if (arg3 != -1) {
349                         gg.setColor(colors[arg3]);
350                         gg.fillOval(xarg1-xarg3, xarg2-xarg3, xarg3*2, xarg3*2);
351                     }
352                     gg.setColor(colors[arg2]);
353                     gg.drawOval(xarg1-xarg3, xarg2-xarg3, xarg3*2, xarg3*2);
354                     break;
355                 case 10:
356                     for(int i=0; i<blitters.length; i++) {
357                         if (blitters[i] == null) {
358                             blitters[i] = new BufferedImage(arg2, arg3, BufferedImage.TYPE_3BYTE_BGR);
359                             return i;
360                         }
361                     }
362                     throw new RuntimeException("No free blitter found!");
363                 case 11: blitters[arg2] = null; break;
364                 case 12:
365                     timer.start(); break;
366                 case 13:
367                     timer.stop(); break;
368                 }
369                 return 0;
370             case 5: // more arguments
371                 xarg1 = arg1;
372                 xarg2 = arg2;
373                 xarg3 = arg3;
374                 return 0;
375             case 6: // polygon vertex
376                 xPoints[arg1]=arg2;
377                 yPoints[arg1]=arg3;
378                 return 0;
379             case 7: // string
380                 gg.setColor(colors[arg2]);
381                 {
382                     String text = runtime.utfstring(arg3);
383                     Font ft = new Font((xarg3 & 0x10) != 0 ? "Monospaced" : "Dialog",
384                             Font.PLAIN, 100);
385                     int height100 = this.getFontMetrics(ft).getHeight();
386                     ft = ft.deriveFont(arg1 * 100 / (float)height100);
387                     FontMetrics fm = this.getFontMetrics(ft);
388                     int asc = fm.getAscent(), desc = fm.getDescent();
389                     if ((xarg3 & ALIGN_VCENTRE) != 0)
390                         xarg2 += asc - (asc+desc)/2;
391                     int wid = fm.stringWidth(text);
392                     if ((xarg3 & ALIGN_HCENTRE) != 0)
393                         xarg1 -= wid / 2;
394                     else if ((xarg3 & ALIGN_HRIGHT) != 0)
395                         xarg1 -= wid;
396                     gg.setFont(ft);
397                     gg.drawString(text, xarg1, xarg2);
398                 }
399                 return 0;
400             case 8: // blitter_save
401                 Graphics g2 = blitters[arg1].createGraphics();
402                 g2.drawImage(pp.backBuffer, 0, 0, blitters[arg1].getWidth(), blitters[arg1].getHeight(),
403                         arg2, arg3, arg2 + blitters[arg1].getWidth(), arg3 + blitters[arg1].getHeight(), this);
404                 g2.dispose();
405                 return 0;
406             case 9: // blitter_load
407                 gg.drawImage(blitters[arg1], arg2, arg3, this);
408                 return 0;
409             case 10: // dialog_init
410                 dlg= new ConfigDialog(this, runtime.cstring(arg1));
411                 return 0;
412             case 11: // dialog_add_control
413                 {
414                     int sval_ptr = arg1;
415                     int ival = arg2;
416                     int ptr = xarg1;
417                     int type=xarg2;
418                     String name = runtime.cstring(xarg3);
419                     switch(type) {
420                     case C_STRING:
421                         dlg.addTextBox(ptr, name, runtime.cstring(sval_ptr));
422                         break;
423                     case C_BOOLEAN:
424                         dlg.addCheckBox(ptr, name, ival != 0);
425                         break;
426                     case C_CHOICES:
427                         dlg.addComboBox(ptr, name, runtime.cstring(sval_ptr), ival);
428                     }
429                 }
430                 return 0;
431             case 12:
432                 dlg.finish();
433                 dlg = null;
434                 return 0;
435             case 13: // tick a menu item
436                 if (arg1 < 0) arg1 = typeMenu.getItemCount() - 1;
437                 for (int i = 0; i < typeMenu.getItemCount(); i++) {
438                     if (typeMenu.getMenuComponent(i) instanceof JCheckBoxMenuItem) {
439                         ((JCheckBoxMenuItem)typeMenu.getMenuComponent(i)).setSelected(arg1 == i);
440                     }
441                 }
442                 return 0;
443             default:
444                 if (cmd >= 1024 && cmd < 2048) { // palette
445                     colors[cmd-1024] = new Color(arg1, arg2, arg3);
446                 }
447             if (cmd == 1024) {
448                 pp.setBackground(colors[0]);
449                 if (statusBar != null) statusBar.setBackground(colors[0]);
450                 this.setBackground(colors[0]);
451             }
452             return 0;
453             }
454         } catch (Throwable ex) {
455             ex.printStackTrace();
456             System.exit(-1);
457             return 0;
458         }
459     }
460
461     private void addStatusBar() {
462         statusBar = new JLabel("test");
463         statusBar.setBorder(new BevelBorder(BevelBorder.LOWERED));
464         getContentPane().add(BorderLayout.SOUTH,statusBar);
465     }
466
467     // Standalone runner
468     public static void main(String[] args) {
469         final PuzzleApplet a = new PuzzleApplet();
470         JFrame jf = new JFrame("Loading...");
471         jf.getContentPane().setLayout(new BorderLayout());
472         jf.getContentPane().add(a, BorderLayout.CENTER);
473         a.mainWindow=jf;
474         a.init();
475         a.start();
476         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
477         jf.addWindowListener(new WindowAdapter() {
478             public void windowClosing(WindowEvent e) {
479                 a.stop();
480                 a.destroy();
481             }
482         });
483         jf.setVisible(true);
484     }
485
486     public static class PuzzlePanel extends JPanel {
487
488         private static final long serialVersionUID = 1L;
489         protected BufferedImage backBuffer;
490
491         public PuzzlePanel() {
492             setPreferredSize(new Dimension(100,100));
493             createBackBuffer(100,100, Color.black);
494         }
495
496         public void createBackBuffer(int w, int h, Color bg) {
497             if (w > 0 && h > 0) {
498                 backBuffer = new BufferedImage(w,h, BufferedImage.TYPE_3BYTE_BGR);
499                 Graphics g = backBuffer.createGraphics();
500                 g.setColor(bg);
501                 g.fillRect(0, 0, w, h);
502                 g.dispose();
503             }
504         }
505
506         protected void paintComponent(Graphics g) {
507             g.drawImage(backBuffer, 0, 0, this);
508         }
509     }
510
511     public static class ConfigComponent {
512         public int type;
513         public int configItemPointer;
514         public JComponent component;
515
516         public ConfigComponent(int type, int configItemPointer, JComponent component) {
517             this.type = type;
518             this.configItemPointer = configItemPointer;
519             this.component = component;
520         }
521     }
522
523     public class ConfigDialog extends JDialog {
524
525         private GridBagConstraints gbcLeft = new GridBagConstraints(
526                 GridBagConstraints.RELATIVE, GridBagConstraints.RELATIVE, 1, 1,
527                 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE,
528                 new Insets(0, 0, 0, 0), 0, 0);
529         private GridBagConstraints gbcRight = new GridBagConstraints(
530                 GridBagConstraints.RELATIVE, GridBagConstraints.RELATIVE,
531                 GridBagConstraints.REMAINDER, 1, 1.0, 0,
532                 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
533                 new Insets(5, 5, 5, 5), 0, 0);
534         private GridBagConstraints gbcBottom = new GridBagConstraints(
535                 GridBagConstraints.RELATIVE, GridBagConstraints.RELATIVE,
536                 GridBagConstraints.REMAINDER, GridBagConstraints.REMAINDER,
537                 1.0, 1.0, GridBagConstraints.CENTER,
538                 GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0);
539
540         private static final long serialVersionUID = 1L;
541         private List components = new ArrayList();
542
543         public ConfigDialog(JApplet parent, String title) {
544             super(JOptionPane.getFrameForComponent(parent), title, true);
545             getContentPane().setLayout(new GridBagLayout());
546         }
547
548         public void addTextBox(int ptr, String name, String value) {
549             getContentPane().add(new JLabel(name), gbcLeft);
550             JComponent c = new JTextField(value, 25);
551             getContentPane().add(c, gbcRight);
552             components.add(new ConfigComponent(C_STRING, ptr, c));
553         }
554
555
556         public void addCheckBox(int ptr, String name, boolean selected) {
557             JComponent c = new JCheckBox(name, selected);
558             getContentPane().add(c, gbcRight);
559             components.add(new ConfigComponent(C_BOOLEAN, ptr, c));
560         }
561
562         public void addComboBox(int ptr, String name, String values, int selected) {
563             getContentPane().add(new JLabel(name), gbcLeft);
564             StringTokenizer st = new StringTokenizer(values.substring(1), values.substring(0,1));
565             JComboBox c = new JComboBox();
566             c.setEditable(false);
567             while(st.hasMoreTokens())
568                 c.addItem(st.nextToken());
569             c.setSelectedIndex(selected);
570             getContentPane().add(c, gbcRight);
571             components.add(new ConfigComponent(C_CHOICES, ptr, c));
572         }
573
574         public void finish() {
575             JPanel buttons = new JPanel(new GridLayout(1, 2, 5, 5));
576             getContentPane().add(buttons, gbcBottom);
577             JButton b;
578             buttons.add(b=new JButton("OK"));
579             b.addActionListener(new ActionListener() {
580                 public void actionPerformed(ActionEvent e) {
581                     save();
582                     dispose();
583                 }
584             });
585             getRootPane().setDefaultButton(b);
586             buttons.add(b=new JButton("Cancel"));
587             b.addActionListener(new ActionListener() {
588                 public void actionPerformed(ActionEvent e) {
589                     dispose();
590                 }
591             });
592             setDefaultCloseOperation(DISPOSE_ON_CLOSE);
593             pack();
594             setLocationRelativeTo(null);
595             setVisible(true);
596         }
597         private void save() {
598             for (int i = 0; i < components.size(); i++) {
599                 ConfigComponent cc = (ConfigComponent) components.get(i);
600                 switch(cc.type) {
601                 case C_STRING:
602                     JTextField jtf = (JTextField)cc.component;
603                     runtimeCall("jcallback_config_set_string", new int[] {cc.configItemPointer, runtime.strdup(jtf.getText())});
604                     break;
605                 case C_BOOLEAN:
606                     JCheckBox jcb = (JCheckBox)cc.component;
607                     runtimeCall("jcallback_config_set_boolean", new int[] {cc.configItemPointer, jcb.isSelected()?1:0});
608                     break;
609                 case C_CHOICES:
610                     JComboBox jcm = (JComboBox)cc.component;
611                     runtimeCall("jcallback_config_set_choice", new int[] {cc.configItemPointer, jcm.getSelectedIndex()});
612                     break;
613                 }
614             }
615             runtimeCall("jcallback_config_ok", new int[0]);
616         }
617     }
618 }