Codebase list ruby-fxruby / master examples / groupbox.rb
master

Tree @master (Download .tar.gz)

groupbox.rb @masterraw · history · blame

#!/usr/bin/env ruby

require 'fox16'

include Fox

class GroupWindow < FXMainWindow

  # Convenience function to load & construct an icon
  def getIcon(filename)
    filename = File.expand_path("../icons/#{filename}", __FILE__)
    File.open(filename, "rb") do |f|
      FXPNGIcon.new(getApp(), f.read)
    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