Skip to content
Snippets Groups Projects
imageviewer.rb 19.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/env ruby
    
    require 'fox16'
    
    include Fox
    
    class ImageWindow < FXMainWindow
    
      include Responder
    
      def initialize(app)
        # Invoke base class initialize first
        super(app, "FOX Image Viewer: - untitled", :opts => DECOR_ALL, :width => 850, :height => 600)
    
        # Recently used files list
        @mrufiles = FXRecentFiles.new
    
        # Make some icons
        fileopenicon = getIcon("fileopen.png")
        filesaveicon = getIcon("filesave.png")
        cuticon = getIcon("cut.png")
        copyicon = getIcon("copy.png")
        pasteicon = getIcon("paste.png")
        uplevelicon = getIcon("tbuplevel.png")
        paletteicon = getIcon("colorpal.png")
    
        # Make color dialog
        colordlg = FXColorDialog.new(self, "Color Dialog")
    
        # Make menu bar
        menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|FRAME_RAISED)
    
        # Status bar
        statusbar = FXStatusBar.new(self,
          LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
    
        # Docking sites
        topDockSite = FXDockSite.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
        FXDockSite.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X)
        FXDockSite.new(self, LAYOUT_SIDE_LEFT|LAYOUT_FILL_Y)
        FXDockSite.new(self, LAYOUT_SIDE_RIGHT|LAYOUT_FILL_Y)
    
        # Splitter
        splitter = FXSplitter.new(self, (LAYOUT_SIDE_TOP|LAYOUT_FILL_X|
          LAYOUT_FILL_Y| SPLITTER_TRACKING|SPLITTER_VERTICAL|SPLITTER_REVERSED))
    
        # Tool bar is docked inside the top one for starters
        toolbarShell = FXToolBarShell.new(self)
        toolbar = FXToolBar.new(topDockSite, toolbarShell,
          PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT|FRAME_RAISED|LAYOUT_FILL_X)
        FXToolBarGrip.new(toolbar, toolbar, FXToolBar::ID_TOOLBARGRIP, TOOLBARGRIP_DOUBLE)
    
        # 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)
    
        # Sunken border for image widget
        imagebox = FXHorizontalFrame.new(splitter,
          FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,
          :padLeft => 0, :padRight => 0, :padTop => 0, :padBottom => 0)
    
        # Make image widget
        @imageview = FXImageView.new(imagebox, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y)
    
        # Sunken border for file list
        @filebox = FXHorizontalFrame.new(splitter,
          LAYOUT_FILL_X|LAYOUT_FILL_Y,
          :padLeft => 0, :padRight => 0, :padTop => 0, :padBottom => 0)
    
        # Make file list
        fileframe = FXHorizontalFrame.new(@filebox,
          FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,
    
          :padLeft => 0, :padRight => 0, :padTop => 0, :padBottom => 0, :hSpacing => 0, :vSpacing => 0)
    
        @filelist = FXFileList.new(fileframe,
          :opts => 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,
          :opts => ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
        openBtn.connect(SEL_COMMAND, method(:onCmdOpen))
        saveBtn = FXButton.new(toolbar, "&Save\tSave Image\tSave image file.", filesaveicon,
          :opts => ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
        saveBtn.connect(SEL_COMMAND, method(:onCmdSave))
    
        # Toobar buttons: Editing
        FXButton.new(toolbar, "Cut\tCut", cuticon,
          :opts => ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
        FXButton.new(toolbar, "Copy\tCopy", copyicon,
          :opts => ICON_ABOVE_TEXT|BUTTON_TOOLBAR|FRAME_RAISED)
        FXButton.new(toolbar, "Paste\tPaste", pasteicon,
          :opts => 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)
        FXMenuCommand.new(editmenu, "C&ut\tCtl-X\tCut selection to clipboard.", cuticon)
        FXMenuCommand.new(editmenu, "&Paste\tCtl-V\tPaste from clipboard.", pasteicon)
        FXMenuCommand.new(editmenu, "&Delete\t\tDelete selection.")
    
        # 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
        FXMenuCheck.new(viewmenu, "File list\t\tDisplay file list.",
          @filebox, FXWindow::ID_TOGGLESHOWN)
        FXMenuCheck.new(viewmenu,
          "Show hidden files\t\tShow hidden files and directories.",
          @filelist, FXFileList::ID_TOGGLE_HIDDEN)
        FXMenuSeparator.new(viewmenu)
        FXMenuRadio.new(viewmenu,
          "Show small icons\t\tDisplay directory with small icons.",
          @filelist, FXFileList::ID_SHOW_MINI_ICONS)
        FXMenuRadio.new(viewmenu,
          "Show big icons\t\tDisplay directory with big icons.",
          @filelist, FXFileList::ID_SHOW_BIG_ICONS)
        FXMenuRadio.new(viewmenu,
          "Show details view\t\tDisplay detailed directory listing.",
          @filelist, FXFileList::ID_SHOW_DETAILS)
        FXMenuSeparator.new(viewmenu)
        FXMenuRadio.new(viewmenu, "Rows of icons\t\tView row-wise.",
          @filelist, FXFileList::ID_ARRANGE_BY_ROWS)
        FXMenuRadio.new(viewmenu, "Columns of icons\t\tView column-wise.",
          @filelist,FXFileList::ID_ARRANGE_BY_COLUMNS)
        FXMenuSeparator.new(viewmenu)
        FXMenuCheck.new(viewmenu, "Toolbar\t\tDisplay toolbar.",
          toolbar, FXWindow::ID_TOGGLESHOWN)
    
        FXMenuCommand.new(viewmenu, "Float toolbar\t\tUndock the toolbar.", nil, toolbar, FXToolBar::ID_DOCK_FLOAT)
        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)
    
        FXMenuSeparator.new(viewmenu)
    
        FXMenuCheck.new(viewmenu, "Status line\t\tDisplay status line.",
          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.fox-toolkit.org)\n\n" +
            "Copyright (C) 2000 Jeroen van der Zijp (jeroen@fox-toolkit.org)", nil,
            MBOX_OK|DECOR_TITLE|DECOR_BORDER).execute
        }
    
        # Make a tool tip
        FXToolTip.new(getApp(), TOOLTIP_NORMAL)
    
        # Recent files
        @mrufiles.connect(SEL_COMMAND) do |sender, sel, filename|
          @filename = filename
          @filelist.currentFile = @filename
          loadImage(@filename)
        end
    
        # Initialize file name and pattern for file dialog
        @filename = "untitled"
        @preferredFileFilter = 0
      end
    
      # Convenience function to construct a PNG icon
      def getIcon(filename)
    
    Lars Kanis's avatar
    Lars Kanis committed
        filename = File.expand_path("../icons/#{filename}", __FILE__)
        File.open(filename, "rb") do |f|
          FXPNGIcon.new(getApp(), f.read)
    
        end
      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.nil?
          FXMessageBox.error(self, MBOX_OK, "Error loading image",
            "Unsupported image type: #{file}")
          return
        end
    
        # Load it...
        getApp().beginWaitCursor do
          FXFileStream.open(file, FXStreamLoad) { |stream| img.loadPixels(stream) }
          img.create
          @imageview.image = img
        end
      end
    
      # Save image to named file
      def saveImage(file)
        getApp().beginWaitCursor do
          FXFileStream.open(file, FXStreamSave) { |stream| @imageview.image.savePixels(stream) }
        end
      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 File.exists? saveDialog.filename
            if MBOX_CLICKED_NO == FXMessageBox.question(self, MBOX_YES_NO,
              "Overwrite Image", "Overwrite existing image?")
              return 1
            end
          end
          @filename = saveDialog.filename
          @filelist.currentFile = @filename
          @mrufiles.appendFile(@filename)
          saveImage(@filename)
        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().writeBoolEntry("SETTINGS", "filesshown", @filebox.shown)
    
        # 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
    
      # 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,
          :padLeft => 20, :padRight => 20, :padTop => 4, :padBottom => 4)
        FXButton.new(frame, "OK", nil, scalepanel, FXDialogBox::ID_ACCEPT,
          LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,
          :padLeft => 30, :padRight => 30, :padTop => 4, :padBottom => 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,
          :padLeft => 20, :padRight => 20, :padTop => 4, :padBottom => 4)
        FXButton.new(frame, "OK", nil, croppanel, FXDialogBox::ID_ACCEPT,
          LAYOUT_CENTER_Y|FRAME_RAISED|FRAME_THICK,
          :padLeft => 30, :padRight => 30, :padTop => 4, :padBottom => 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, FXSEL(SEL_COMMAND, FXWindow::ID_ENABLE), nil)
        else
          sender.handle(self, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), 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().readBoolEntry("SETTINGS", "filesshown", true)
    
        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
          @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(PLACEMENT_SCREEN)
      end
    end
    
    if __FILE__ == $0
      # Make application
      application = FXApp.new("ImageViewer", "FoxTest")
    
      # 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