Skip to content
Snippets Groups Projects
groupbox.rb 17 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/env ruby
    
    require 'fox16'
    
    include Fox
    
    class GroupWindow < FXMainWindow
    
      # Convenience function to load & construct an icon
      def getIcon(filename)
        begin
          filename = File.join("icons", filename)
          icon = nil
          File.open(filename, "rb") { |f|
            icon = FXPNGIcon.new(getApp(), f.read)
          }
          icon
        rescue
          raise RuntimeError, "Couldn't load icon: #{filename}"
        end
      end
    
      def initialize(app)
        # Call the base class version of initialize
    
        super(app, "Group Box Test", :opts => DECOR_ALL)
    
    
        # Some icons we'll use here and there
        doc = getIcon("minidoc.png")
        folder_open = getIcon("minifolderopen.png")
        folder_closed = getIcon("minifolder.png")
    
        # Menubar
        menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
        filemenu = FXMenuPane.new(self)
        FXMenuCommand.new(filemenu, "Open any", folder_open).connect(SEL_COMMAND) {
          file = FXFileDialog.getSaveFilename(self, "Save file",
            "../examples/groupbox.rb", @sourcefiles, 1)
        }
        FXMenuCommand.new(filemenu, "Open existing", folder_open).connect(SEL_COMMAND) {
          file = FXFileDialog.getOpenFilename(self, "Open file",
            "../examples/groupbox.rb", @sourcefiles, 3)
        }
        FXMenuCommand.new(filemenu, "Open multiple", folder_open).connect(SEL_COMMAND) do
          files = FXFileDialog.getOpenFilenames(self, "Open file",
            "../examples/groupbox.rb", @sourcefiles)
          FXMessageBox.information(self, MBOX_OK, "Selected Files", files.join("\n"))
        end
        FXMenuCommand.new(filemenu, "Open directory", folder_open).connect(SEL_COMMAND) {
          dir = FXFileDialog.getOpenDirectory(self, "Open directory", "../examples")
        }
        FXMenuCommand.new(filemenu, "Open directory dialog", folder_open).connect(SEL_COMMAND) {
          dirDialog = FXDirDialog.new(self, "Choose a directory")
          if dirDialog.execute != 0
            FXMessageBox.information(self, MBOX_OK, "Selected Directory", dirDialog.directory)
          end
        }
        radio1 = FXMenuRadio.new(filemenu, "Radio&1")
        radio1.connect(SEL_COMMAND, method(:onCmdRadio))
        radio1.connect(SEL_UPDATE,  method(:onUpdRadio))
    
        radio2 = FXMenuRadio.new(filemenu, "Radio&2")
        radio2.connect(SEL_COMMAND, method(:onCmdRadio))
        radio2.connect(SEL_UPDATE,  method(:onUpdRadio))
    
        radio3 = FXMenuRadio.new(filemenu, "Radio&3")
        radio3.connect(SEL_COMMAND, method(:onCmdRadio))
        radio3.connect(SEL_UPDATE,  method(:onUpdRadio))
    
        FXMenuCommand.new(filemenu, "Delete\tCtl-X").connect(SEL_COMMAND) {
          @group2 = nil
        }
        FXMenuCommand.new(filemenu,
          "Downsize\tF5\tResize to minimum").connect(SEL_COMMAND) {
          resize(getDefaultWidth(), getDefaultHeight())
        }
        FXMenuCommand.new(filemenu, "&Size").connect(SEL_COMMAND) {
          resize(getDefaultWidth(), getDefaultHeight())
        }
        FXMenuCommand.new(filemenu, "Dump Widgets", nil, getApp(), FXApp::ID_DUMP)
      
        # Make edit popup menu
        editmenu = FXMenuPane.new(self)
          FXMenuCommand.new(editmenu, "Undo")
          FXMenuCommand.new(editmenu, "Cut")
          submenu1 = FXMenuPane.new(self)
            FXMenuCommand.new(submenu1, "&One")
            FXMenuCommand.new(submenu1, "&Two")
            FXMenuCommand.new(submenu1, "Th&ree")
            FXMenuCommand.new(submenu1, "&Four")
          FXMenuCascade.new(editmenu, "&Submenu1", nil, submenu1)
      
        FXMenuCascade.new(filemenu, "&Edit", nil, editmenu)
        FXMenuCommand.new(filemenu, "&Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT)
        FXMenuTitle.new(menubar, "&File", nil, filemenu)
        
        helpmenu = FXMenuPane.new(self)
        FXMenuCommand.new(helpmenu, "&About FOX...").connect(SEL_COMMAND) {
          FXMessageBox.information(self, MBOX_OK,
            "About FOX:- An intentionally long title",
            "FOX is a really, really cool C++ library!\nExample written by Jeroen")
        }
        FXMenuTitle.new(menubar, "&Help", nil, helpmenu, LAYOUT_RIGHT)
      
        @popupmenu = FXMenuPane.new(self)
    
          poptext = FXTextField.new(@popupmenu, 10, :opts => FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
    
          poptext.setText("Popup with text")
        
        # Status bar
        status = FXStatusBar.new(self,
          LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
        @clockLabel = FXLabel.new(status, Time.now().strftime("%I:%M:%S %p"), nil,
          LAYOUT_FILL_Y|LAYOUT_RIGHT|FRAME_SUNKEN)
      
        # Content
        contents = FXHorizontalFrame.new(self,
          LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y)
      
        group1 = FXGroupBox.new(contents, "Title Left",
          GROUPBOX_TITLE_LEFT|FRAME_RIDGE|LAYOUT_FILL_X|LAYOUT_FILL_Y)
        group2 = FXGroupBox.new(contents, "Slider Tests",
          GROUPBOX_TITLE_CENTER|FRAME_RIDGE|LAYOUT_FILL_X|LAYOUT_FILL_Y)
        group3 = FXGroupBox.new(contents, "Title Right",
          GROUPBOX_TITLE_RIGHT|FRAME_RIDGE|LAYOUT_FILL_X|LAYOUT_FILL_Y)
        
        testlabel = FXLabel.new(group1,
          "&This is a multi-line\nlabel widget\nwith a big font", nil,
          LAYOUT_CENTER_X|JUSTIFY_CENTER_X)
        testlabel.setFont(FXFont.new(getApp(), "helvetica", 24, FONTWEIGHT_BOLD,
                                     FONTSLANT_ITALIC, FONTENCODING_DEFAULT))
        FXButton.new(group1, "Small &Button", nil, nil, 0, FRAME_RAISED|FRAME_THICK)
    
        FXButton.new(group1, "Big Fat Wide Button\nComprising\nthree lines", :opts => FRAME_RAISED|FRAME_THICK)
    
        FXToggleButton.new(group1,
          "C&losed\tTooltip for closed\tHelp for closed",
          "O&pen\nState\tTooltip for open\tHelp for open",
          folder_closed, folder_open, nil, 0,
          ICON_BEFORE_TEXT|JUSTIFY_LEFT|FRAME_RAISED|FRAME_THICK)
      
        pop = FXPopup.new(self)
    
        numbers =%w{first second third fourth}
        0.upto(3) do |idx|
          FXOption.new(pop, "#{numbers[idx].capitalize}\tTip #{idx+1}\tHelp #{numbers[idx]}", :opts => JUSTIFY_HZ_APART|ICON_AFTER_TEXT).connect(SEL_COMMAND) {
              FXMessageBox.information(self, MBOX_OK, "Option Menu", "Chose option #{idx+1}")
          }
        end
    
        
        FXOptionMenu.new(group1, pop,
          LAYOUT_TOP|FRAME_RAISED|FRAME_THICK|JUSTIFY_HZ_APART|ICON_AFTER_TEXT)
      
        FXLabel.new(group1, "Te&kstje", nil, LAYOUT_TOP|JUSTIFY_LEFT)
        FXButton.new(group1,
    
          "Add an `&&' by doubling\tTooltip\tHelp text for status", :opts => LAYOUT_TOP|FRAME_RAISED|FRAME_THICK)
        FXButton.new(group1, "Te&kstje", :opts => LAYOUT_TOP|FRAME_RAISED|FRAME_THICK).connect(SEL_COMMAND) {
    
          x, y, buttons = getRoot().getCursorPosition()
          @popupmenu.popup(nil, x, y)
        }
        
    
        FXMenuButton.new(group1, "&Menu", :opts => MENUBUTTON_ATTACH_BOTH|MENUBUTTON_DOWN|JUSTIFY_HZ_APART|LAYOUT_TOP|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT)
        FXMenuButton.new(group1, "&Menu", nil, filemenu, MENUBUTTON_UP|LAYOUT_TOP|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT)
    
      
        coolpop = FXPopup.new(self, POPUP_HORIZONTAL)
    
        FXButton.new(coolpop, "A\tTipA",
          :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, :width => 30, :height => 30)
        FXButton.new(coolpop, "B\tTipB",
          :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, :width => 30, :height => 30)
        FXButton.new(coolpop, "C\tTipC",
          :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, :width => 30, :height => 30)
        FXButton.new(coolpop, "D\tTipD",
          :opts => FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, :width => 30, :height => 30)
    
        FXMenuButton.new(group1, "&S\tSideways", nil, coolpop,
          (MENUBUTTON_ATTACH_BOTH|MENUBUTTON_LEFT|MENUBUTTON_NOARROWS|LAYOUT_TOP|
    
           FRAME_RAISED|FRAME_THICK|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT), :width => 30, :height => 30)
    
        
        matrix = FXMatrix.new(group1, 3,
          FRAME_RAISED|LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
        
    
        FXButton.new(matrix, "A", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW)
        FXButton.new(matrix, "&Wide button", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X)
        FXButton.new(matrix, "A", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X)
    
        FXButton.new(matrix, "BBBB", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW|LAYOUT_FILL_COLUMN)
        FXButton.new(matrix, "B", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
        FXButton.new(matrix, "BB", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN)
    
        FXButton.new(matrix, "C", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y|LAYOUT_CENTER_X|LAYOUT_FILL_ROW)
        FXButton.new(matrix, "&wide", :opts => FRAME_RAISED|FRAME_THICK)
        FXButton.new(matrix, "CC", :opts => FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT)
    
        
        FXLabel.new(group2, "No Arrow")
    
        FXSlider.new(group2, :opts => LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL, :width => 200, :height => 30)
    
        
        FXLabel.new(group2, "Up Arrow")
    
        FXSlider.new(group2, :opts => LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL|SLIDER_ARROW_UP, :width => 200, :height => 30)
    
        
        FXLabel.new(group2, "Down Arrow")
    
        FXSlider.new(group2, :opts => LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL|SLIDER_ARROW_DOWN, :width => 200, :height => 30)
    
        
        FXLabel.new(group2, "Inside Bar")
    
        slider = FXSlider.new(group2, :opts => LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL|SLIDER_INSIDE_BAR, :width => 200, :height => 20)  
    
        slider.range = 0..3
        
        frame = FXHorizontalFrame.new(group2, LAYOUT_FILL_X|LAYOUT_FILL_Y)
        
        FXSlider.new(frame, nil, 0,
          LAYOUT_FIX_HEIGHT|SLIDER_VERTICAL, 0, 0, 30, 200)
        FXSlider.new(frame, nil, 0,
          LAYOUT_FIX_HEIGHT|SLIDER_VERTICAL|SLIDER_ARROW_RIGHT, 0, 0, 30, 200)
        FXSlider.new(frame, nil, 0,
          LAYOUT_FIX_HEIGHT|SLIDER_VERTICAL|SLIDER_ARROW_LEFT, 0, 0, 30, 200)
        FXSlider.new(frame, nil, 0,
          LAYOUT_FIX_HEIGHT|SLIDER_VERTICAL|SLIDER_INSIDE_BAR, 0, 0, 20, 200)
        FXScrollBar.new(frame, nil, 0,
          SCROLLBAR_VERTICAL|LAYOUT_FIX_HEIGHT|LAYOUT_FIX_WIDTH, 0, 0, 20, 300)
      
        vframe1 = FXVerticalFrame.new(frame, LAYOUT_FILL_X|LAYOUT_FILL_Y)
        FXArrowButton.new(vframe1, nil, 0,
          LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_UP)
        FXArrowButton.new(vframe1, nil, 0,
          LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_DOWN)
        FXArrowButton.new(vframe1, nil, 0,
          LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_LEFT)
        FXArrowButton.new(vframe1, nil, 0,
          LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_RIGHT)
      
        vframe2 = FXVerticalFrame.new(frame, LAYOUT_FILL_X|LAYOUT_FILL_Y)
    
        FXArrowButton.new(vframe2, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK|ARROW_UP|ARROW_TOOLBAR)
    
        FXArrowButton.new(vframe2, nil, 0, (LAYOUT_FILL_X|LAYOUT_FILL_Y|
          FRAME_RAISED|FRAME_THICK|ARROW_DOWN|ARROW_TOOLBAR))
        FXArrowButton.new(vframe2, nil, 0, (LAYOUT_FILL_X|LAYOUT_FILL_Y|
          FRAME_RAISED|FRAME_THICK|ARROW_LEFT|ARROW_TOOLBAR))
        FXArrowButton.new(vframe2, nil, 0, (LAYOUT_FILL_X|LAYOUT_FILL_Y|
          FRAME_RAISED|FRAME_THICK|ARROW_RIGHT|ARROW_TOOLBAR))
      
        gp_datatarget = FXDataTarget.new(0)
        gp = FXGroupBox.new(group3, "Group Box",
          LAYOUT_SIDE_TOP|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
        FXRadioButton.new(gp, "Hilversum &1", gp_datatarget, FXDataTarget::ID_OPTION+0,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXRadioButton.new(gp, "Hilversum &2", gp_datatarget, FXDataTarget::ID_OPTION+1,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXRadioButton.new(gp, "One multi-line\nRadiobox Widget", gp_datatarget, FXDataTarget::ID_OPTION+2,
          JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXRadioButton.new(gp, "Radio Stad Amsterdam", gp_datatarget, FXDataTarget::ID_OPTION+3,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        
        vv = FXGroupBox.new(group3, "Group Box",
          LAYOUT_SIDE_TOP|FRAME_GROOVE|LAYOUT_FILL_X, 0, 0, 0, 0)
        FXCheckButton.new(vv, "Hilversum 1", nil, 0,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXCheckButton.new(vv, "Hilversum 2", nil, 0,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXCheckButton.new(vv, "One multi-line\nCheckbox Widget", nil, 0,
          JUSTIFY_LEFT|JUSTIFY_TOP|ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        FXCheckButton.new(vv, "Radio Stad Amsterdam", nil, 0,
          ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
        
        spinner = FXSpinner.new(group3, 20, nil, 0,
          SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        spinner.range = 1..20
        
        combobox = FXComboBox.new(group3, 5, nil, 0,
          COMBOBOX_INSERT_LAST|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        combobox.appendItem("Very Wide Item")
        for i in 0...3
          combobox.appendItem("%04d" % i)
        end
        
        treebox = FXTreeListBox.new(group3, nil, 0,
          FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP, 0, 0, 200, 0)
      
        topmost = treebox.appendItem(nil, "Top", folder_open, folder_closed)
        topmost2 = treebox.appendItem(nil, "Top2", folder_open, folder_closed)
                 treebox.appendItem(topmost2, "First", doc, doc)
      
        treebox.appendItem(topmost, "First", doc, doc)
        treebox.appendItem(topmost, "Second", doc, doc)
        treebox.appendItem(topmost, "Third", doc, doc)
        branch = treebox.appendItem(topmost, "Fourth", folder_open, folder_closed)
          treebox.appendItem(branch, "Fourth-First", doc, doc)
          treebox.appendItem(branch, "Fourth-Second", doc, doc)
          twig = treebox.appendItem(branch, "Fourth-Third", folder_open, folder_closed)
            treebox.appendItem(twig, "Fourth-Third-First", doc, doc)
            treebox.appendItem(twig, "Fourth-Third-Second", doc, doc)
            treebox.appendItem(twig, "Fourth-Third-Third", doc, doc)
            leaf = treebox.appendItem(twig, "Fourth-Third-Fourth", folder_open, folder_closed)
              treebox.appendItem(leaf, "Fourth-Third-Fourth-First", doc, doc)
              treebox.appendItem(leaf, "Fourth-Third-Fourth-Second", doc, doc)
              treebox.appendItem(leaf, "Fourth-Third-Fourth-Third", doc, doc)
          twig = treebox.appendItem(branch, "Fourth-Fourth", folder_open, folder_closed)
            treebox.appendItem(twig, "Fourth-Fourth-First", doc, doc)
            treebox.appendItem(twig, "Fourth-Fourth-Second", doc, doc)
            treebox.appendItem(twig, "Fourth-Fourth-Third", doc, doc)
        
        FXLabel.new(group3, "H&it the hotkey", nil,
          LAYOUT_CENTER_X|JUSTIFY_CENTER_X|FRAME_RAISED)
        textfield1 = FXTextField.new(group3, 20, nil, 0,
          JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        textfield1.text = "Normal Text Field"
        textfield2 = FXTextField.new(group3, 20, nil, 0,
          JUSTIFY_RIGHT|TEXTFIELD_PASSWD|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        textfield2.text = "Password"
        textfield3 = FXTextField.new(group3, 20, nil, 0,
          TEXTFIELD_READONLY|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        textfield3.text = "Read Only"
        textfield4 = FXTextField.new(group3, 20, nil, 0,
          TEXTFIELD_READONLY|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
        textfield4.text = "Grayed out"
        textfield4.disable
        
        realnumber = FXTextField.new(group3, 20, nil, 0,
          TEXTFIELD_REAL|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP|LAYOUT_FIX_HEIGHT,
          0, 0, 0, 30)
        realnumber.text = "1.0E+3"
        intnumber = FXTextField.new(group3, 20, nil, 0,
          TEXTFIELD_INTEGER|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP|LAYOUT_FIX_HEIGHT,
          0, 0, 0, 30)
        intnumber.text = "1000"
        
        dial2 = FXDial.new(group3, nil, 0, (DIAL_CYCLIC|DIAL_HAS_NOTCH|
          DIAL_HORIZONTAL|LAYOUT_FILL_X|FRAME_RAISED|FRAME_THICK), 0, 0, 120, 0)
        FXScrollBar.new(group3, nil, 0,
          SCROLLBAR_HORIZONTAL|LAYOUT_FIX_HEIGHT|LAYOUT_FIX_WIDTH, 0, 0, 300, 20)
        
        pbar = FXProgressBar.new(group3, nil, 0,
          LAYOUT_FILL_X|FRAME_SUNKEN|FRAME_THICK|PROGRESSBAR_PERCENTAGE)
        pbar.progress = 48
        pbar.total = 360
        pbar2 = FXProgressBar.new(group3, nil, 0, (LAYOUT_FILL_Y|FRAME_SUNKEN|
          FRAME_THICK|PROGRESSBAR_VERTICAL|PROGRESSBAR_PERCENTAGE|LAYOUT_SIDE_LEFT))
        pbar2.total = 360
        dial1 = FXDial.new(group3, nil, 0, (DIAL_CYCLIC|DIAL_HAS_NOTCH|
          DIAL_VERTICAL|FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y|LAYOUT_SIDE_LEFT))
        pbar2.progress = 48
        dial1.target = pbar2
        dial1.selector = FXWindow::ID_SETVALUE
        dial2.target = pbar
        dial2.selector = FXWindow::ID_SETVALUE
      
        # Currently selected choice from the radio buttons
        @choice = 0
    
        # File filter for file dialogs
        @sourcefiles = "All Files (*)\n" +
                       "C++ Source Files (*.cpp,*.cxx,*.cc)\n" +
                       "C Source Files (*.c)\n" +
                       "C++ Header Files (*.hpp,*.hxx,*.hh,*.h)\n" +
                       "*.o\n" +
                       "Any Extension (*.*)\n" +
                       "Three Letter (*.???)\n" +
                       "README*"
      end
    
      # Set choice
      def onCmdRadio(sender, sel, ptr)
        @choice = FXSELID(sel)
        return 1
      end
    
      # Update menu based on choice
      def onUpdRadio(sender, sel, ptr)
        sender.check = (FXSELID(sel) == @choice)
        return 1
      end
    
      # Create the main window and show it
      def create
        super
        show(PLACEMENT_SCREEN)
    
        # Create a thread to update the clock
        @clockThread = Thread.new(@clockLabel) { |clockLabel|
          while true
            clockLabel.text = Time.now.strftime("%I:%M:%S %p")
            sleep(1)
          end
        }
      end
    end
    
    if __FILE__ == $0
      # Make application
      application = FXApp.new("Groupbox", "FoxTest")
      
      # Make window
      GroupWindow.new(application)
      
      # Create app
      application.create
      
      # Run
      application.run
    end