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