#!/usr/bin/env ruby

require 'fox'
require 'fox/responder'

include Fox

class ImageWindow < FXMainWindow

  include Responder

  def initialize(app)
    # Invoke base class initialize first
    super(app, "FOX Image Viewer: - untitled", nil, nil, DECOR_ALL,
      0, 0, 850, 600, 0, 0)

    # Message identifiers for this class
    identifier :ID_RECENTFILE

    # Set up message map for this class
    FXMAPFUNC(SEL_COMMAND,       ID_RECENTFILE, "onCmdRecentFile")

    # Recently used files list
    @mrufiles = FXRecentFiles.new

    # Make some icons
    fileopenicon = getIcon("fileopen.gif")
    filesaveicon = getIcon("filesave.gif")
    cuticon = getIcon("cut.gif")
    copyicon = getIcon("copy.gif")
    pasteicon = getIcon("paste.gif")
    uplevelicon = getIcon("tbuplevel.gif")
    paletteicon = getIcon("colorpal.gif")

    # Make color dialog
    colordlg = FXColorDialog.new(self, "Color Dialog")
  
    # Make menu bar
    dragshell1 = FXToolbarShell.new(self, 0)
    menubar = FXMenubar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED)
    FXToolbarGrip.new(menubar, menubar, FXMenubar::ID_TOOLBARGRIP,
      TOOLBARGRIP_DOUBLE)
  
    # Tool bar
    dragshell2 = FXToolbarShell.new(self, 0)
    toolbar = FXToolbar.new(self, dragshell2, (LAYOUT_SIDE_TOP|
      PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT|FRAME_RAISED|LAYOUT_FILL_X))
    FXToolbarGrip.new(toolbar, toolbar, FXToolbar::ID_TOOLBARGRIP,
      TOOLBARGRIP_DOUBLE)
  
    # Status bar
    statusbar = FXStatusbar.new(self,
      LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
  
    # File menu
    filemenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&File", nil, filemenu)
    
    # Edit Menu
    editmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Edit", nil, editmenu)
  
    # Manipulation Menu
    manipmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar,"&Manipulation", nil, manipmenu)
  
    # View menu
    viewmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&View", nil, viewmenu)
    
    # Help menu
    helpmenu = FXMenuPane.new(self)
    FXMenuTitle.new(menubar, "&Help", nil, helpmenu, LAYOUT_RIGHT)

    # Splitter
    splitter = FXSplitter.new(self, (LAYOUT_SIDE_TOP|LAYOUT_FILL_X|
      LAYOUT_FILL_Y| SPLITTER_TRACKING|SPLITTER_VERTICAL|SPLITTER_REVERSED))
  
    # Sunken border for image widget
    imagebox = FXHorizontalFrame.new(splitter,
      FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,
      0, 0, 0, 0, 0, 0, 0, 0)
  
    # Make image widget
    @imageview = FXImageView.new(imagebox, nil, nil, 0,
      LAYOUT_FILL_X|LAYOUT_FILL_Y)
    
    # Sunken border for file list
    @filebox = FXHorizontalFrame.new(splitter, LAYOUT_FILL_X|LAYOUT_FILL_Y,
      0, 0, 0, 0, 0, 0, 0, 0)
  
    # Make file list
    fileframe = FXHorizontalFrame.new(@filebox,
      FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    @filelist = FXFileList.new(fileframe, nil, 0,
      LAYOUT_FILL_X|LAYOUT_FILL_Y|ICONLIST_MINI_ICONS|ICONLIST_AUTOSIZE)
    @filelist.connect(SEL_DOUBLECLICKED, method(:onCmdFileList))
    FXButton.new(@filebox, "\tUp one level\tGo up to higher directory.",
      uplevelicon, @filelist, FXFileList::ID_DIRECTORY_UP,
      BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_FILL_Y)
  
    # Toobar buttons: File manipulation
    openBtn = FXButton.new(toolbar, "&Open\tOpen Image\tOpen image file.", fileopenicon,
      nil, 0, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
    openBtn.connect(SEL_COMMAND, method(:onCmdOpen))
    saveBtn = FXButton.new(toolbar, "&Save\tSave Image\tSave image file.", filesaveicon,
      nil, 0, ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
    saveBtn.connect(SEL_COMMAND, method(:onCmdSave))
  
    # Toobar buttons: Editing
    FXButton.new(toolbar, "Cut\tCut", cuticon, nil, 0,
      ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
    FXButton.new(toolbar, "Copy\tCopy", copyicon, nil, 0,
      ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
    FXButton.new(toolbar, "Paste\tPaste", pasteicon, nil, 0,
      ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
  
    # Color
    FXButton.new(toolbar, "&Colors\tColors\tDisplay color dialog.", paletteicon,
      colordlg, FXWindow::ID_SHOW,
      ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED|LAYOUT_RIGHT)
  
    # File Menu entries
    FXMenuCommand.new(filemenu, "&Open...\tCtl-O\tOpen image file.", fileopenicon).connect(SEL_COMMAND, method(:onCmdOpen))
    FXMenuCommand.new(filemenu, "&Save...\tCtl-S\tSave image file.", filesaveicon).connect(SEL_COMMAND, method(:onCmdSave))
    FXMenuCommand.new(filemenu, "Dump", nil, getApp(), FXApp::ID_DUMP)
  
    # Recent file menu; this automatically hides if there are no files
    sep1 = FXMenuSeparator.new(filemenu)
    sep1.target = @mrufiles
    sep1.selector = FXRecentFiles::ID_ANYFILES
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_1)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_2)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_3)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_4)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_5)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_6)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_7)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_8)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_9)
    FXMenuCommand.new(filemenu, nil, nil, @mrufiles, FXRecentFiles::ID_FILE_10)
    FXMenuCommand.new(filemenu, "&Clear Recent Files", nil,
      @mrufiles, FXRecentFiles::ID_CLEAR)
    sep2 = FXMenuSeparator.new(filemenu)
    sep2.target = @mrufiles
    sep2.selector = FXRecentFiles::ID_ANYFILES
    FXMenuCommand.new(filemenu, "&Quit\tCtl-Q").connect(SEL_COMMAND, method(:onCmdQuit))
  
    # Edit Menu entries
    FXMenuCommand.new(editmenu, "&Undo\tCtl-Z\tUndo last change.")
    FXMenuCommand.new(editmenu, "&Redo\tCtl-R\tRedo last undo.")
    FXMenuCommand.new(editmenu, "&Copy\tCtl-C\tCopy selection to clipboard.",
      copyicon, nil, 0)
    FXMenuCommand.new(editmenu, "C&ut\tCtl-X\tCut selection to clipboard.",
      cuticon, nil, 0)
    FXMenuCommand.new(editmenu, "&Paste\tCtl-V\tPaste from clipboard.",
      pasteicon, nil, 0)
    FXMenuCommand.new(editmenu, "&Delete\t\tDelete selection.", nil, nil, 0)
  
    # Manipulation Menu entries
    rotate90Cmd = FXMenuCommand.new(manipmenu, "Rotate 90\t\tRotate 90 degrees.")
    rotate90Cmd.connect(SEL_COMMAND) { @imageview.image.rotate(90) }
    rotate90Cmd.connect(SEL_UPDATE, method(:onUpdImage))
    
    rotate180Cmd = FXMenuCommand.new(manipmenu, "Rotate 180\t\tRotate 180 degrees.")
    rotate180Cmd.connect(SEL_COMMAND) { @imageview.image.rotate(180) }
    rotate180Cmd.connect(SEL_UPDATE, method(:onUpdImage))
    
    rotate270Cmd = FXMenuCommand.new(manipmenu, "Rotate -90\t\tRotate -90 degrees.")
    rotate270Cmd.connect(SEL_COMMAND) { @imageview.image.rotate(270) }
    rotate270Cmd.connect(SEL_UPDATE, method(:onUpdImage))

    mirrorHorCmd = FXMenuCommand.new(manipmenu, "Mirror Hor.\t\tMirror Horizontally.")
    mirrorHorCmd.connect(SEL_COMMAND) { @imageview.image.mirror(true, false) }
    mirrorHorCmd.connect(SEL_UPDATE, method(:onUpdImage))
    
    mirrorVerCmd = FXMenuCommand.new(manipmenu, "Mirror Ver.\t\tMirror Vertically.")
    mirrorVerCmd.connect(SEL_COMMAND) { @imageview.image.mirror(false, true) }
    mirrorVerCmd.connect(SEL_UPDATE, method(:onUpdImage))
    
    scaleCmd = FXMenuCommand.new(manipmenu, "Scale...\t\tScale image.")
    scaleCmd.connect(SEL_COMMAND, method(:onCmdScale))
    scaleCmd.connect(SEL_UPDATE, method(:onUpdImage))
    
    cropCmd = FXMenuCommand.new(manipmenu, "Crop...\t\tCrop image.")
    cropCmd.connect(SEL_COMMAND, method(:onCmdCrop))
    cropCmd.connect(SEL_UPDATE, method(:onUpdImage))
  
    # View Menu entries
    FXMenuCommand.new(viewmenu, "File list\t\tDisplay file list.", nil,
      @filebox, FXWindow::ID_TOGGLESHOWN)
    FXMenuCommand.new(viewmenu,
      "Show hidden files\t\tShow hidden files and directories.", nil,
      @filelist, FXFileList::ID_TOGGLE_HIDDEN)
    FXMenuCommand.new(viewmenu,
      "Show small icons\t\tDisplay directory with small icons.", nil,
      @filelist, FXFileList::ID_SHOW_MINI_ICONS)
    FXMenuCommand.new(viewmenu,
      "Show big icons\t\tDisplay directory with big icons.", nil,
      @filelist, FXFileList::ID_SHOW_BIG_ICONS)
    FXMenuCommand.new(viewmenu,
      "Show details view\t\tDisplay detailed directory listing.", nil,
      @filelist, FXFileList::ID_SHOW_DETAILS)
    FXMenuCommand.new(viewmenu, "Rows of icons\t\tView row-wise.", nil,
      @filelist, FXFileList::ID_ARRANGE_BY_ROWS)
    FXMenuCommand.new(viewmenu, "Columns of icons\t\tView column-wise.", nil,
      @filelist,FXFileList::ID_ARRANGE_BY_COLUMNS)
    FXMenuCommand.new(viewmenu, "Toolbar\t\tDisplay toolbar.", nil,
      toolbar, FXWindow::ID_TOGGLESHOWN)
    FXMenuCommand.new(viewmenu, "Float toolbar\t\tUndock the toolbar.", nil,
      toolbar, FXToolbar::ID_UNDOCK)
    FXMenuCommand.new(viewmenu,
      "Dock toolbar top\t\tDock the toolbar on the top.", nil,
      toolbar, FXToolbar::ID_DOCK_TOP)
    FXMenuCommand.new(viewmenu,
      "Dock toolbar left\t\tDock the toolbar on the left.", nil,
      toolbar, FXToolbar::ID_DOCK_LEFT)
    FXMenuCommand.new(viewmenu,
      "Dock toolbar right\t\tDock the toolbar on the right.", nil,
      toolbar, FXToolbar::ID_DOCK_RIGHT)
    FXMenuCommand.new(viewmenu,
      "Dock toolbar bottom\t\tDock the toolbar on the bottom.", nil,
      toolbar, FXToolbar::ID_DOCK_BOTTOM)
    FXMenuCommand.new(viewmenu, "Status line\t\tDisplay status line.", nil,
      statusbar, FXWindow::ID_TOGGLESHOWN)
 
    # Help Menu entries
    FXMenuCommand.new(helpmenu, "&About FOX...").connect(SEL_COMMAND) {
      FXMessageBox.new(self, "About Image Viewer",
        "Image Viewer demonstrates the FOX ImageView widget.\n\n" +
        "Using the FOX C++ GUI Library (http://www.cfdrc.com/FOX/fox.html)\n\n" +
        "Copyright (C) 2000 Jeroen van der Zijp (jvz@cfdrc.com)", nil,
        MBOX_OK|DECOR_TITLE|DECOR_BORDER).execute
    }
  
    # Make a tool tip
    FXTooltip.new(getApp(), TOOLTIP_NORMAL)
  
    # Recent files
    @mrufiles.target = self
    @mrufiles.selector = ID_RECENTFILE

    # Initialize file name and pattern for file dialog
    @filename = "untitled"
    @preferredFileFilter = 0
  end

  # Convenience function to construct a GIF icon
  def getIcon(filename)
    filename = "icons/" + filename
    FXGIFIcon.new(getApp(), File.open(filename, "rb").read)
  end

  def hasExtension(filename, ext)
    File.basename(filename, ext) != File.basename(filename)
  end

  # Load the named image file
  def loadImage(file)
    img = nil
    if hasExtension(file, ".gif")
      img = FXGIFImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".bmp")
      img = FXBMPImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".xpm")
      img = FXXPMImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".png")
      img = FXPNGImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".jpg")
      img = FXJPGImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".pcx")
      img = FXPCXImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".tif")
      img = FXTIFImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".tga")
      img = FXTGAImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    elsif hasExtension(file, ".ico")
      img = FXICOImage.new(getApp(), nil, IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP)
    end

    # Perhaps failed?
    if !img
      FXMessageBox.error(self, MBOX_OK, "Error loading image",
        "Unsupported type: #{ext}")
      return
    end

    # Load it...
    getApp().beginWaitCursor
    FXFileStream.open(file, FXStreamLoad) { |stream|
      img.loadPixels(stream)
    }
    img.create
    old = @imageview.image
    @imageview.image = img
    old = nil
    getApp().endWaitCursor
  end

  # Save image to named file
  def saveImage(file)
    getApp().beginWaitCursor
    FXFileStream.open(file, FXStreamSave) { |stream|
      img = @imageview.image
      img.savePixels(stream)
    }
    getApp().endWaitCursor
  end

  # Open a new file
  def onCmdOpen(sender, sel, ptr)
    openDialog = FXFileDialog.new(self, "Open Image")
    openDialog.filename = @filename
    patterns = ["All Files (*)",
                "GIF Image (*.gif)",
                "BMP Image (*.bmp)",
                "XPM Image (*.xpm)",
                "PCX Image (*.pcx)",
                "ICO Image (*.ico)",
                "PNG Image (*.png)",
                "JPEG Image (*.jpg)",
                "TIFF Image (*.tif)",
                "TARGA Image (*.tga)"
    ]
    openDialog.patternList = patterns
    openDialog.currentPattern = @preferredFileFilter
    if openDialog.execute != 0
      @preferredFileFilter = openDialog.currentPattern
      @filename = openDialog.filename
      @filelist.currentFile = @filename
      @mrufiles.appendFile(@filename)
      loadImage(@filename)
    end
    return 1
  end

  # Save this file
  def onCmdSave(sender, sel, ptr)
    saveDialog = FXFileDialog.new(self, "Save Image")
    if saveDialog.execute != 0
      if fxexists(saveDialog.filename)
        if MBOX_CLICKED_NO == FXMessageBox.question(self, MBOX_YES_NO,
          "Overwrite Image", "Overwrite existing image?")
          return 1
        end
        @filename = saveDialog.filename
        @filelist.currentFile = @filename
        @mrufiles.appendFile(@filename)
        saveImage(@filename)
      end
    end
    return 1
  end

  # Quit the application
  def onCmdQuit(sender, sel, ptr)
    # Write new window size back to registry
    getApp().reg().writeIntEntry("SETTINGS", "x", x)
    getApp().reg().writeIntEntry("SETTINGS", "y", y)
    getApp().reg().writeIntEntry("SETTINGS", "width", width)
    getApp().reg().writeIntEntry("SETTINGS", "height", height)

    # Height of file list
    getApp().reg().writeIntEntry("SETTINGS", "fileheight", @filebox.height)

    # Was file box shown?
    getApp().reg().writeIntEntry("SETTINGS", "filesshown",
      @filebox.shown() ? 1 : 0)

    # Current directory
    getApp().reg().writeStringEntry("SETTINGS", "directory", @filelist.directory)

    # Quit
    getApp().exit(0)
  end

  # Command message from the file list
  def onCmdFileList(sender, sel, index)
    if index >= 0
      if @filelist.isItemDirectory(index)
        @filelist.directory = @filelist.getItemPathname(index)
      elsif @filelist.isItemFile(index)
        @filename = @filelist.getItemPathname(index)
        @mrufiles.appendFile(@filename)
        loadImage(@filename)
      end
    end
    return 1
  end

  # Open recently used file
  def onCmdRecentFile(sender, sel, filename)
    @filename = filename
    @filelist.currentFile = @filename
    loadImage(@filename)
  end

  # Scale
  def onCmdScale(sender, sel, ptr)
    image = @imageview.image
    sx = FXDataTarget.new(image.width)
    sy = FXDataTarget.new(image.height)
    scalepanel = FXDialogBox.new(self, "Scale Image To Size")
    frame = FXHorizontalFrame.new(scalepanel,
      LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
    FXLabel.new(frame, "W:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, sx, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXLabel.new(frame, "H:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, sy, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXButton.new(frame, "Cancel", nil, scalepanel, FXDialogBox::ID_CANCEL,
      LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK, 0, 0, 0, 0, 20, 20, 4, 4)
    FXButton.new(frame, "OK", nil, scalepanel, FXDialogBox::ID_ACCEPT,
      LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK, 0, 0, 0, 0, 30, 30, 4, 4)
    return 1 if (scalepanel.execute == 0)
    return 1 if (sx.value < 1 || sy.value < 1)
    image.scale(sx.value, sy.value)
    @imageview.image = image
  end

  # Crop
  def onCmdCrop(sender, sel, ptr)
    image = @imageview.image
    cx = FXDataTarget.new(0)
    cy = FXDataTarget.new(0)
    cw = FXDataTarget.new(image.width)
    ch = FXDataTarget.new(image.height)
    croppanel = FXDialogBox.new(self, "Crop image")
    frame = FXHorizontalFrame.new(croppanel,
      LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
    FXLabel.new(frame, "X:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, cx, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXLabel.new(frame, "Y:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, cy, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXLabel.new(frame, "W:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, cw, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXLabel.new(frame, "H:", nil, LAYOUT_CENTER_Y)
    FXTextField.new(frame, 5, ch, FXDataTarget::ID_VALUE,
      LAYOUT_CENTER_Y|FRAME_SUNKEN|FRAME_THICK|JUSTIFY_RIGHT)
    FXButton.new(frame, "Cancel", nil, croppanel, FXDialogBox::ID_CANCEL,
      LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK, 0, 0, 0, 0, 20, 20, 4, 4)
    FXButton.new(frame, "OK", nil, croppanel, FXDialogBox::ID_ACCEPT,
      LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK, 0, 0, 0, 0, 30, 30, 4, 4)
    return 1 if (croppanel.execute == 0)
    return 1 if (cx.value < 0 || cy.value < 0 ||
        cx.value+cw.value > image.width ||
        cy.value+ch.value > image.height)
    image.crop(cx.value, cy.value, cw.value, ch.value)
    @imageview.image = image
  end

  # Update image
  def onUpdImage(sender, sel, ptr)
    if @imageview.image
      sender.handle(self, MKUINT(FXWindow::ID_ENABLE, SEL_COMMAND), nil)
    else
      sender.handle(self, MKUINT(FXWindow::ID_DISABLE, SEL_COMMAND), nil)
    end
  end

  # Create and show window
  def create
    # Get size, etc. from registry
    xx = getApp().reg().readIntEntry("SETTINGS", "x", 0)
    yy = getApp().reg().readIntEntry("SETTINGS", "y", 0)
    ww = getApp().reg().readIntEntry("SETTINGS", "width", 850)
    hh = getApp().reg().readIntEntry("SETTINGS", "height", 600)

    fh = getApp().reg().readIntEntry("SETTINGS", "fileheight", 100)
    fs = getApp().reg().readIntEntry("SETTINGS", "filesshown", 1)

    dir = getApp().reg().readStringEntry("SETTINGS", "directory", "~")

    # Starting directory for the files list
    @filelist.directory = dir

    # Height of files list
    @filebox.height = fh

    # Is it visible right now?
    if fs != 1
      @filebox.hide
    end
 
    # Reposition window to specified x, y, w and h
    position(xx, yy, ww, hh)

    # Create and show
    super   # i.e. FXMainWindow::create()
    show
  end
end

def run
  # Make application
  application = FXApp.new("ImageViewer", "FoxTest")

  # Open display
  application.init(ARGV)

  # Make window
  window = ImageWindow.new(application)

  # Handle interrupts to terminate program gracefully
  application.addSignal("SIGINT", window.method(:onCmdQuit))

  # Create it
  application.create

  # Passed image file?
  if ARGV.length > 0
    window.loadImage(ARGV[0])
  end

  # Run
  application.run
end

run
