From b6b1acbd91837bc586f5ff3d0b6ad172d906fce1 Mon Sep 17 00:00:00 2001 From: Lyle Johnson <lyle@lylejohnson.name> Date: Mon, 2 Feb 2009 15:10:03 -0600 Subject: [PATCH] checked in changes from the RB-1.6 branch (through r2945) --- .gitignore | 23 + Rakefile | 146 +- doc/Makefile | 8 +- doc/book.xml | 8 +- doc/build.xml | 65 +- doc/changes.xml | 434 ++++++ doc/clipboardtut.xml | 22 +- doc/custom-fo.xsl | 2 +- doc/custom-html.xsl | 2 +- doc/dragdroptut.xml | 232 ++- doc/gems.xml | 22 +- doc/goals.xml | 15 +- doc/infosources.xml | 6 +- doc/scintilla.xml | 10 +- doc/style.css | 248 +++- examples/WhatAQuietStiff.rb | 1 - examples/babelfish.rb | 66 +- examples/bounce.rb | 1 - examples/button.rb | 1 - examples/charts.rb | 35 + examples/custom_table_item.rb | 170 +++ examples/datatarget.rb | 1 - examples/dialog.rb | 1 - examples/dilbert.rb | 14 +- examples/dirlist.rb | 1 - examples/dragdrop.rb | 1 - examples/dragsource.rb | 1 - examples/dropsite.rb | 3 +- examples/foursplit.rb | 1 - examples/gdchart.rb | 1 - examples/gembrowser.rb | 2 +- examples/gltest.rb | 37 +- examples/glviewer.rb | 1 - examples/groupbox.rb | 103 +- examples/header.rb | 1 - examples/iconlist.rb | 1 - examples/image.rb | 1 - examples/imageviewer.rb | 3 +- examples/inputs.rb | 3 +- examples/mditest.rb | 1 - examples/pig.rb | 1 - examples/raabrowser.rb | 1 - examples/ratio.rb | 1 - examples/rmagick.rb | 44 + examples/rulerview.rb | 1 - examples/scribble.rb | 1 - examples/shutter.rb | 1 - examples/splitter.rb | 1 - examples/styledtext.rb | 16 +- examples/tabbook.rb | 1 - examples/table.rb | 1 - ext/fox16/FXRbApp.cpp | 9 +- ext/fox16/FXRbDataTarget.cpp | 4 +- ext/fox16/FXRuby.cpp | 230 +-- ext/fox16/extconf.rb.in | 56 +- ext/fox16/include/FXRbApp.h | 16 +- ext/fox16/include/FXRbDC.h | 2 +- ext/fox16/markfuncs.cpp | 16 +- ext/fox16/unregisterOwnedObjects.cpp | 4 +- install.rb | 1957 ++++++++++++++++---------- lib/fox16/aliases.rb | 17 + lib/fox16/chore.rb | 38 +- lib/fox16/core.rb | 98 +- lib/fox16/exceptions_for_fxerror.rb | 17 + lib/fox16/input.rb | 21 +- lib/fox16/iterators.rb | 119 +- lib/fox16/pseudokeyboard.rb | 18 +- lib/fox16/pseudomouse.rb | 25 +- lib/fox16/responder2.rb | 69 +- lib/fox16/signal.rb | 17 +- lib/fox16/timeout.rb | 42 +- pre-config.rb.in | 7 +- rdoc-sources/FXButton.rb | 2 +- rdoc-sources/FXComboBox.rb | 3 + rdoc-sources/FXCursor.rb | 2 +- rdoc-sources/FXGroupBox.rb | 3 + rdoc-sources/FXHeader.rb | 3 + rdoc-sources/FXIconDict.rb | 2 +- rdoc-sources/FXIconList.rb | 3 + rdoc-sources/FXImage.rb | 94 +- rdoc-sources/FXImageFrame.rb | 14 + rdoc-sources/FXInputDialog.rb | 3 + rdoc-sources/FXLabel.rb | 3 + rdoc-sources/FXList.rb | 8 +- rdoc-sources/FXMDIChild.rb | 6 - rdoc-sources/FXMDIClient.rb | 6 - rdoc-sources/FXMenuCaption.rb | 3 + rdoc-sources/FXMessageBox.rb | 1 + rdoc-sources/FXPacker.rb | 1 + rdoc-sources/FXTable.rb | 77 +- rdoc-sources/FXText.rb | 22 +- rdoc-sources/FXToggleButton.rb | 1 + rdoc-sources/FXToolTip.rb | 3 + rdoc-sources/FXVec2d.rb | 2 +- rdoc-sources/FXVec2f.rb | 2 +- rdoc-sources/FXVec3d.rb | 9 +- rdoc-sources/FXVec3f.rb | 9 +- rdoc-sources/FXVec4d.rb | 14 +- rdoc-sources/FXVec4f.rb | 14 +- rdoc-sources/FXWindow.rb | 1 + scripts/FXRuby.iss.in | 5 - scripts/generate_kwargs_lib.rb | 170 ++- swig-interfaces/FXApp.i | 12 +- swig-interfaces/FXDialogBox.i | 9 +- swig-interfaces/FXFileDialog.i | 6 +- swig-interfaces/FXFileSelector.i | 6 +- swig-interfaces/FXFoldingList.i | 5 +- swig-interfaces/FXImage.i | 4 +- swig-interfaces/FXMainWindow.i | 5 +- swig-interfaces/FXMemoryStream.i | 6 +- swig-interfaces/FXMessageBox.i | 8 +- swig-interfaces/FXPoint.i | 3 +- swig-interfaces/FXRanged.i | 4 + swig-interfaces/FXRangef.i | 14 +- swig-interfaces/FXScintilla.i | 4 +- swig-interfaces/FXSettings.i | 2 + swig-interfaces/FXTable.i | 44 +- swig-interfaces/FXText.i | 41 +- swig-interfaces/FXVec2d.i | 7 +- swig-interfaces/FXVec2f.i | 7 +- swig-interfaces/FXVec3d.i | 6 +- swig-interfaces/FXVec3f.i | 6 +- swig-interfaces/FXVec4d.i | 6 +- swig-interfaces/FXVec4f.i | 6 +- swig-interfaces/FXWindow.i | 10 +- swig-interfaces/FXXPMIcon.i | 2 +- swig-interfaces/Makefile | 6 +- swig-interfaces/macros.i | 6 +- swig-interfaces/ruby-typemaps.i | 88 +- tests/TC_FXApp.rb | 15 +- tests/TC_FXButton.rb | 6 + tests/TC_FXComboBox.rb | 11 + tests/TC_FXDC.rb | 2 +- tests/TC_FXDCPrint.rb | 7 +- tests/TC_FXDialogBox.rb | 12 + tests/TC_FXExtentd.rb | 21 + tests/TC_FXExtentf.rb | 21 + tests/TC_FXFileStream.rb | 3 +- tests/TC_FXFoldingList.rb | 32 + tests/TC_FXHiliteStyle.rb | 23 + tests/TC_FXId.rb | 6 +- tests/TC_FXMainWindow.rb | 19 + tests/TC_FXMessageBox.rb | 25 + tests/TC_FXQuatf.rb | 32 +- tests/TC_FXRanged.rb | 42 + tests/TC_FXRangef.rb | 30 +- tests/TC_FXTable.rb | 193 +++ tests/TC_FXText.rb | 17 +- tests/TC_FXTreeList.rb | 43 +- tests/TC_FXTreeListBox.rb | 24 +- tests/stress1.rb | 12 +- tests/testcase.rb | 14 +- web/community.html | 94 ++ web/css/style.css | 407 ++++++ web/documentation.html | 100 ++ web/downloads.html | 207 +-- web/images/bullet.gif | Bin 0 -> 281 bytes web/images/button-bg.jpg | Bin 0 -> 345 bytes web/images/comment.gif | Bin 0 -> 364 bytes web/images/content.jpg | Bin 0 -> 542 bytes web/images/dots.jpg | Bin 0 -> 326 bytes web/images/footer.jpg | Bin 0 -> 4633 bytes web/images/fxruby-book.jpg | Bin 0 -> 22622 bytes web/images/header.png | Bin 0 -> 14644 bytes web/images/menu.jpg | Bin 0 -> 366 bytes web/images/page.gif | Bin 0 -> 393 bytes web/images/quote.gif | Bin 0 -> 346 bytes web/images/square-green.png | Bin 0 -> 193 bytes web/index.html | 97 ++ 169 files changed, 5013 insertions(+), 1856 deletions(-) create mode 100644 .gitignore create mode 100644 examples/charts.rb create mode 100644 examples/custom_table_item.rb create mode 100755 examples/rmagick.rb create mode 100644 lib/fox16/exceptions_for_fxerror.rb create mode 100644 tests/TC_FXDialogBox.rb create mode 100755 tests/TC_FXExtentd.rb create mode 100755 tests/TC_FXExtentf.rb create mode 100755 tests/TC_FXFoldingList.rb create mode 100755 tests/TC_FXHiliteStyle.rb create mode 100644 tests/TC_FXMainWindow.rb create mode 100755 tests/TC_FXMessageBox.rb create mode 100755 tests/TC_FXRanged.rb create mode 100644 web/community.html create mode 100644 web/css/style.css create mode 100644 web/documentation.html mode change 100755 => 100644 web/downloads.html create mode 100644 web/images/bullet.gif create mode 100644 web/images/button-bg.jpg create mode 100644 web/images/comment.gif create mode 100644 web/images/content.jpg create mode 100644 web/images/dots.jpg create mode 100644 web/images/footer.jpg create mode 100644 web/images/fxruby-book.jpg create mode 100644 web/images/header.png create mode 100644 web/images/menu.jpg create mode 100644 web/images/page.gif create mode 100644 web/images/quote.gif create mode 100644 web/images/square-green.png create mode 100644 web/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bed3115 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.config +InstalledFiles +FXRuby.spec +scripts/make-installers.rb +*.iss +*.iss.in +doap.rdf +Makefile +*.tmproj +doc/api +doc/*.html +ext/fox16/*_wrap.cpp +ext/fox16/*.o +ext/fox16/conftest.dSYM +ext/fox16/include/inlinestubs.h +ext/fox16/librb.c +ext/fox16/extconf.rb +ext/fox16/fox16.bundle +ext/fox16/mkmf.log +lib/fox16/version.rb +lib/fox16/kwargs.rb +pre-config.rb +swig-interfaces/dependencies diff --git a/Rakefile b/Rakefile index 34bbe01..9483fc6 100755 --- a/Rakefile +++ b/Rakefile @@ -1,13 +1,16 @@ -require 'hoe' +require 'date' +require 'rake/gempackagetask' +require 'rake/rdoctask' +require 'rake/testtask' # FXRuby version number -PKG_VERSION = "1.6.6" +PKG_VERSION = "1.6.18" # Minimum version of FOX required for compatibility FOX_VERSION = "1.6.0" # Path to local installation of FOX (Windows only) -FOX_INSTALL_DIR = "c:\\src\\fox-1.6.20" +FOX_INSTALL_DIR = "e:\\src\\fox-1.6.33" # Path to local installation of FXScintilla (Windows only) FXSCINTILLA_INSTALL_DIR = "c:\\src\\fxscintilla" @@ -15,32 +18,6 @@ FXSCINTILLA_INSTALL_DIR = "c:\\src\\fxscintilla" # Path to local installation of InnoSetup command-line compiler ISCC = "C:\\Progra~1\\InnoSe~1\\ISCC.exe" -# Generate Hoe tasks -=begin -Hoe.new('FXRuby', PKG_VERSION) do |p| - p.url = "http://www.fxruby.org/" - p.author = "Lyle Johnson" - p.email = "lyle@rubyforge.org" - p.changes = "See the change history at http://www.fxruby.org/doc/changes.html" - p.description = "FXRuby is the Ruby binding to the FOX GUI toolkit." - p.summary = "FXRuby is the Ruby binding to the FOX GUI toolkit." - p.clean_globs = %w{config.save InstalledFiles ext/**/*.o ext/**/*.bundle} - p.test_globs = ['tests/**/TC_*.rb'] - p.rdoc_pattern = /^(lib|bin)|txt$/ - p.extra_deps = [] - p.spec_extras = {} - p.need_tar = true - p.need_zip = false - p.spec_extras = { - 'require_paths' => ['ext/fox16', 'lib'], - 'rdoc_options' => ['--main', File.join('rdoc-sources', 'README.rdoc'), '--exclude', 'ext/fox16'], - 'extensions' => ["ext/fox16/extconf.rb"], - 'extra_rdoc_files' => ['rdoc-sources', File.join('rdoc-sources', 'README.rdoc')], - 'test_suite_file' => "tests/TS_All.rb" - } -end -=end - DISTFILES = [ "ANNOUNCE", "LICENSE", @@ -49,10 +26,7 @@ DISTFILES = [ "pre-config.rb", "install.rb", "doap.rdf", - "FXRuby-ruby1.6-i586-mswin32.iss", - "FXRuby-ruby1.8.2-i386-msvcrt.iss", - "FXRuby-ruby1.8.4-i386-msvcrt.iss", - "FXRuby-ruby1.8.5-i386-msvcrt.iss", + "FXRuby-ruby1.8.6-i386-msvcrt.iss", "Rakefile", "index.html", "doc/*.css", @@ -77,10 +51,6 @@ DISTFILES = [ "tests/README", "tests/*.rb", "tests/*.ps", - "web/*.html", - "web/*.css", - "web/art/*.png", - "web/art/*.gif", "rdoc-sources/*.rb", "rdoc-sources/README.rdoc", "scripts/make-installers.rb" @@ -90,7 +60,7 @@ def distdir "FXRuby-#{PKG_VERSION}" end -task :distdir => [:swig, :docs, :setversions] do +task :distdir => [:swig, :docs, :setversions, :generate_kwargs_lib] do rm_rf "#{distdir}" mkdir "#{distdir}" chmod(0777, distdir) @@ -111,6 +81,7 @@ task :distdir => [:swig, :docs, :setversions] do rm_f "#{distdir}/examples/rapt-gui.rb" rm_f "#{distdir}/examples/WhatAQuietStiff.rb" rm_f "#{distdir}/examples/gembrowser.rb" + rm_f "#{distdir}/examples/rmagick.rb" rm_f "#{distdir}/examples/tablenew.rb" end @@ -141,9 +112,12 @@ task :website => [:doap] do system %{scp -Cq doc/*.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby/1.6/doc} system %{scp -Cq doc/images/*.png lyle@rubyforge.org:/var/www/gforge-projects/fxruby/1.6/doc/images} system %{scp -Cq examples/*.rb lyle@rubyforge.org:/var/www/gforge-projects/fxruby/1.6/examples} - system %{scp -Cq index.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby} - system %{scp -Cq web/*.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby/web} - system %{scp -Cq web/art/*.gif web/art/*.png lyle@rubyforge.org:/var/www/gforge-projects/fxruby/web/art} + system %{scp -Cq web/index.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby} + system %{scp -Cq web/community.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby} + system %{scp -Cq web/documentation.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby} + system %{scp -Cq web/downloads.html lyle@rubyforge.org:/var/www/gforge-projects/fxruby} + system %{scp -Cq web/images/* lyle@rubyforge.org:/var/www/gforge-projects/fxruby/images} + system %{scp -Cq web/css/*.css lyle@rubyforge.org:/var/www/gforge-projects/fxruby/css} end desc "Upload the DOAP file to the Web site" @@ -153,7 +127,40 @@ end desc "Upload the RDocs" task :upload_rdoc do - system %{scp -Cqr doc/api lyle@rubyforge.org:/var/www/gforge-projects/fxruby/1.6/doc} +# system %{scp -Cqr doc/api lyle@rubyforge.org:/var/www/gforge-projects/fxruby/1.6/doc} + host = "lyle@rubyforge.org" + remote_dir = "/var/www/gforge-projects/fxruby/doc/api" + local_dir = 'doc/api' + sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}} +end + +desc "Upload release files to RubyForge" +task :rubyforge do + require 'rubyforge' + rubyforge = RubyForge.new + rubyforge.login + if PLATFORM =~ /mswin32/ + rubyforge.userconfig['processor_id'] = 'i386' + rubyforge.add_file "fxruby", "FXRuby 1.6", PKG_VERSION, "fxruby-#{PKG_VERSION}-mswin32.gem" + rubyforge.add_file "fxruby", "FXRuby 1.6", PKG_VERSION, "FXRuby-#{PKG_VERSION}-ruby186.exe" + else + rubyforge.add_release "fxruby", "FXRuby 1.6", PKG_VERSION, "FXRuby-#{PKG_VERSION}.tar.gz" + rubyforge.add_file "fxruby", "FXRuby 1.6", PKG_VERSION, "fxruby-#{PKG_VERSION}.gem" + end +# rubyforge add_release fxruby "FXRuby 1.6" "1.6.9" FXRuby-1.6.9.tar.gz +# rubyforge add_file fxruby "FXRuby 1.6" "1.6.9" fxruby-1.6.9.gem +# rubyforge add_file -o i386 fxruby "FXRuby 1.6" "1.6.9" fxruby-1.6.9-mswin32.gem +# rubyforge add_file -o i386 fxruby "FXRuby 1.6" "1.6.9" FXRuby-1.6.9-ruby186.exe +end + +desc "Tag this release in Subversion" +task :tag do + require 'rexml/document' + doc = REXML::Document.new(`svn info --xml`) + branch = doc.get_elements("/info/entry/url").first.text + root = doc.get_elements("/info/entry/repository/root").first.text + tag = root + "/tags/REL-#{PKG_VERSION}" + sh %{svn copy -m "Created tag for version #{PKG_VERSION}" #{branch} #{tag}} end desc "Generate all of the documentation files." @@ -180,6 +187,7 @@ Rake::RDocTask.new do |rdoc| "lib/fox16/glshapes.rb", "lib/fox16/input.rb", "lib/fox16/iterators.rb", + "lib/fox16/keys.rb", "lib/fox16/responder2.rb", "lib/fox16/scintilla.rb", "lib/fox16/signal.rb", @@ -200,6 +208,11 @@ end desc "Clean" task :clean do + rm_rf "ext/fox16/Makefile" + rm_rf FileList["ext/fox16/*.o"] + rm_rf FileList["ext/fox16/*.bundle"] + rm_rf "ext/fox16/mkmf.log" + rm_rf "ext/fox16/conftest.dSYM" ruby "install.rb clean" end @@ -210,10 +223,11 @@ def make_impl end task :configure => [:scintilla, :setversions, :generate_kwargs_lib] do - unless File.exist?("config.save") + unless File.exist?(".config") # ruby "install.rb config -- --with-fxscintilla-include=/usr/include/fxscintilla --with-fxscintilla-lib=/usr/lib" # ruby "install.rb config -- --without-fxscintilla" - ruby "install.rb config" +# ruby "install.rb config -- --with-fox-include=/opt/local/include/fox-1.6 --with-fox-lib=/opt/local/lib --with-fxscintilla-include=/opt/local/include/fxscintilla --with-fxscintilla-lib=/opt/local/lib" + ruby "install.rb config -- --with-fox-include=/usr/local/include/fox-1.6 --with-fox-lib=/usr/local/lib --with-fxscintilla-include=/usr/local/include/fxscintilla --with-fxscintilla-lib=/usr/local/lib" make_impl end end @@ -253,10 +267,7 @@ task :setversions => [ :create_installer_scripts ] do setversions("Makefile") setversions("pre-config.rb") setversions("ext/fox16/extconf.rb") - setversions("FXRuby-ruby1.6-i586-mswin32.iss") - setversions("FXRuby-ruby1.8.2-i386-msvcrt.iss") - setversions("FXRuby-ruby1.8.4-i386-msvcrt.iss") - setversions("FXRuby-ruby1.8.5-i386-msvcrt.iss") + setversions("FXRuby-ruby1.8.6-i386-msvcrt.iss") setversions("lib/fox16/version.rb") setversions("doap.rdf") setversions("scripts/make-installers.rb") @@ -265,10 +276,7 @@ end desc "Create INNO Setup Installer Scripts from Template" task :create_installer_scripts do output_filenames = { - "FXRuby-ruby1.6-i586-mswin32.iss.in" => ["1.6", "ruby168", "i586-mswin32"], - "FXRuby-ruby1.8.2-i386-msvcrt.iss.in" => ["1.8", "ruby182", "i386-msvcrt"], - "FXRuby-ruby1.8.4-i386-msvcrt.iss.in" => ["1.8", "ruby184", "i386-msvcrt"], - "FXRuby-ruby1.8.5-i386-msvcrt.iss.in" => ["1.8", "ruby185", "i386-msvcrt"] + "FXRuby-ruby1.8.6-i386-msvcrt.iss.in" => ["1.8", "ruby186", "i386-msvcrt"] } output_filenames.each do |output_filename, info| @@ -285,15 +293,15 @@ task :create_installer_scripts do end # These library files aren't ready for distribution yet. -COOKER_LIBS = %w{acceltable.rb bitmapview.rb canvas.rb html.rb sugar.rb tkcompat.rb} +COOKER_LIBS = %w{acceltable.rb bitmapview.rb canvas.rb html.rb tkcompat.rb} # These example programs aren't ready for distribution yet. -COOKER_EXAMPLES = %w{canvasdemo.rb WhatAQuietStiff.rb examples.rb gdchart.rb gembrowser.rb rapt-gui.rb tablenew.rb} +COOKER_EXAMPLES = %w{canvasdemo.rb WhatAQuietStiff.rb examples.rb gdchart.rb gembrowser.rb rapt-gui.rb rmagick.rb tablenew.rb} # Return the Gem specification for the source Gem def create_gemspec pkg_files = [ - "ANNOUNCE", + "ANNOUNCE", "LICENSE", "README", "index.html", @@ -337,7 +345,8 @@ def create_gemspec s.has_rdoc = true s.rdoc_options = [ '--main', File.join('rdoc-sources', 'README.rdoc'), - '--exclude', 'ext/fox16' + '--exclude', 'ext/fox16', + '--exclude', %r{acceltable|aliases|bitmapview|canvas|html|kwargs|missingdep|responder|tkcompat} ] s.extra_rdoc_files = [ 'rdoc-sources', @@ -347,7 +356,7 @@ def create_gemspec s.test_suite_file = "tests/TS_All.rb" s.author = "Lyle Johnson" - s.email = "lyle@knology.net" + s.email = "lyle.johnson@gmail.com" s.homepage = "http://www.fxruby.org" end end @@ -370,7 +379,7 @@ end # Given the distribution tarball, build the installer for Win32 desc "Build Win32 installer" task :build_win32 do - if File.exist? "config.save" + if File.exist? ".config" ruby "install.rb clean" end ruby "install.rb config --make-prog=nmake -- --with-fox-include=#{FOX_INSTALL_DIR}\\include --with-fox-lib=#{FOX_INSTALL_DIR}\\lib --with-fxscintilla-include=#{FXSCINTILLA_INSTALL_DIR}\\include --with-fxscintilla-lib=#{FXSCINTILLA_INSTALL_DIR}\\lib" @@ -382,14 +391,14 @@ desc "Build Win32 installer using INNO Setup" task :build_win32_installer => [:build_win32] do iss_script_name = nil case VERSION - when /1.6/ - iss_script_name = "FXRuby-ruby1.6-i586-mswin32.iss" when /1.8.2/ iss_script_name = "FXRuby-ruby1.8.2-i386-msvcrt.iss" when /1.8.4/ iss_script_name = "FXRuby-ruby1.8.4-i386-msvcrt.iss" when /1.8.5/ iss_script_name = "FXRuby-ruby1.8.5-i386-msvcrt.iss" + when /1.8.6/ + iss_script_name = "FXRuby-ruby1.8.6-i386-msvcrt.iss" end system(ISCC, iss_script_name) end @@ -397,7 +406,7 @@ end desc "Build Win32 binary Gem" task :build_win32_gem => [:build_win32] do spec = create_gemspec - spec.platform = Gem::Platform::WIN32 + spec.platform = Gem::Platform::CURRENT spec.files += ["ext/fox16/fox16.so"] Gem::Builder.new(spec).build end @@ -406,10 +415,25 @@ desc "Build Win32 binary installer and Gem" task :release_win32 => [:build_win32_installer, :build_win32_gem] do end +desc "Build Mac OS X binary Gem" +task :build_macosx_gem do + raise RuntimeError, "remove libFOX*.dylib and recompile before building gem" unless Dir.glob("/usr/local/lib/libFOX*.dylib").empty? + spec = create_gemspec + spec.platform = Gem::Platform::CURRENT + spec.files += ["ext/fox16/fox16.bundle"] + Gem::Builder.new(spec).build +end + task :generate_kwargs_lib do ruby 'scripts/generate_kwargs_lib.rb' end +Rake::TestTask.new do |t| + t.libs << "tests" + t.test_files = FileList["tests/TC_*.rb"] + t.verbose = true +end + # Default task is build task :default => [:build] do end diff --git a/doc/Makefile b/doc/Makefile index 00c4df5..b4fefeb 100755 --- a/doc/Makefile +++ b/doc/Makefile @@ -4,10 +4,12 @@ # ######################################################################## -SAXON = java -jar /Users/lyle/saxon-6.5.3/saxon.jar +#SAXON = java -jar /Users/lyle/saxon-8.9/saxon8.jar +SAXON = java -jar /Users/lyle/saxon-6.5.5/saxon.jar HTML_STYLESHEET = custom-html.xsl -FO_STYLESHEET = custom-fo.xsl -FOP = /Users/lyle/fop-0.20.4/fop.sh +#FO_STYLESHEET = custom-fo.xsl +FO_STYLESHEET = /Users/lyle/docbook/docbook5-xsl-1.72.0/fo/docbook.xsl +FOP = /Users/lyle/fop-0.93/fop all: html diff --git a/doc/book.xml b/doc/book.xml index 53522ed..e36a552 100755 --- a/doc/book.xml +++ b/doc/book.xml @@ -1,7 +1,7 @@ <?xml version='1.0'?> <!DOCTYPE book - PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" - "file:/Users/lyle/docbook/xml/4.4/docbookx.dtd" [ + PUBLIC "-//OASIS//DTD DocBook V5.0//EN" + "file:/Users/lyle/docbook/xml/5.0/dtd/docbook.dtd" [ <!ENTITY bookinfo.xml SYSTEM "bookinfo.xml"> <!ENTITY build.xml SYSTEM "build.xml"> <!ENTITY changes.xml SYSTEM "changes.xml"> @@ -19,11 +19,10 @@ <!ENTITY library.xml SYSTEM "library.xml"> <!ENTITY opengl.xml SYSTEM "opengl.xml"> <!ENTITY scintilla.xml SYSTEM "scintilla.xml"> -<!ENTITY todo.xml SYSTEM "todo.xml"> <!ENTITY tutorial1.xml SYSTEM "tutorial1.xml"> <!ENTITY unicode.xml SYSTEM "unicode.xml"> ]> -<book id="book" lang="en"> +<book id="book" lang="en" xmlns="http://docbook.org/ns/docbook"> &bookinfo.xml; <part label="I"> <title>The Basics</title> @@ -37,7 +36,6 @@ &examples.xml; &events.xml; <!--&layout.xml;--> -&todo.xml; &infosources.xml; &changes.xml; </part> diff --git a/doc/build.xml b/doc/build.xml index 0db1915..7eec0f5 100755 --- a/doc/build.xml +++ b/doc/build.xml @@ -2,9 +2,11 @@ <chapter id="build"> <title>Building from Source Code</title> - <para>A few words of advice, before getting started:</para> + <para>This chapter provides instructions for building and installing FXRuby + directly from source, and not using some more direct means (such as + installing a gem, or via some package manager).</para> - <itemizedlist mark="bullet"> + <itemizedlist> <listitem> <para>If you're planning to use FXRuby on Windows, with the standard <ulink url="http://rubyinstaller.rubyforge.org">Ruby Installer for @@ -14,12 +16,9 @@ </listitem> <listitem> - <para>If you're planning to use FXRuby on Mac OS X, you may want to - consult <ulink - url="http://www.fox-toolkit.net/cgi-bin/wiki.pl?Mac_OS_X">this - page</ulink> from the <ulink url="http://www.fox-toolkit.net">FOX - Community Wiki</ulink>, in addition to the standard build instructions - listed below.</para> + <para>If you're already using the <ulink + url="http://www.macports.org/">MacPorts</ulink> version of ruby, you may + wish to just install the <filename>rb-fxruby</filename> port.</para> </listitem> </itemizedlist> @@ -30,10 +29,10 @@ and installed FOX. Next, you'll need to download the FXRuby source code tarball and unpack it by typing:</para> - <screen>$ <command>tar xzf FXRuby-1.6.0.tar.gz</command></screen> + <screen>$ <command>tar xzf FXRuby-1.6.13.tar.gz</command></screen> <para>This will create a new directory called <filename - class="directory">FXRuby-1.6.0</filename>. Change to the top-level + class="directory">FXRuby-1.6.13</filename>. Change to the top-level directory and configure the build by typing:</para> <screen>$ <command>ruby install.rb config</command></screen> @@ -46,8 +45,8 @@ <filename>install.rb</filename> during this step, e.g.</para> <screen>$ <command>ruby install.rb config -- \ - --with-fox-include=/home/lyle/fox-1.6.3/include \ - --with-fox-lib=/home/lyle/fox-1.6.3/src/.libs</command></screen> + --with-fox-include=/home/lyle/fox-1.6.32/include \ + --with-fox-lib=/home/lyle/fox-1.6.32/src/.libs</command></screen> <para>Once the build has been configured, you can start the build by typing:</para> @@ -68,7 +67,7 @@ probably fire up <filename>irb</filename> and try to import FXRuby:</para> <screen>$ <command>irb</command> -irb(main):001:0> <userinput>require 'fox'</userinput> +irb(main):001:0> <userinput>require 'fox16'</userinput> true irb(main):002:0></screen> @@ -91,16 +90,16 @@ irb(main):002:0></screen> instructions and build files distributed with the standard Ruby source code. To review, you should have started by unpacking the source code tarball, changing into the top-level source code directory (e.g. <filename - class="directory">C:\ruby-1.8.4</filename>) and then typing:</para> + class="directory">C:\ruby-1.8.6</filename>) and then typing:</para> - <screen>C:\ruby-1.8.4><command>win32\configure</command> + <screen>C:\ruby-1.8.6><command>win32\configure</command> type 'nmake' to make ruby for mswin32. -C:\ruby-1.8.4><command>nmake</command></screen> +C:\ruby-1.8.6><command>nmake</command></screen> <para>After the compilation finished, you installed Ruby somewhere by typing, e.g.,</para> - <screen>C:\ruby-1.8.4><command>nmake DESTDIR=C:\ruby install</command></screen> + <screen>C:\ruby-1.8.6><command>nmake DESTDIR=C:\ruby install</command></screen> <para>Similarly, I'm assuming that you built the FOX library using the Developer Studio project files distributed with the standard FOX source @@ -108,14 +107,14 @@ C:\ruby-1.8.4><command>nmake</command></screen> <para>Now you can configure the FXRuby build by typing:</para> - <screen>C:\FXRuby-1.6.0><command>ruby install.rb config --make-prog=nmake -- \ - --with-fox-include=C:\fox-1.6.3\include \ - --with-fox-lib=C:\fox-1.6.3\lib</command></screen> + <screen>C:\FXRuby-1.6.13><command>ruby install.rb config --make-prog=nmake -- \ + --with-fox-include=C:\fox-1.6.32\include \ + --with-fox-lib=C:\fox-1.6.32\lib</command></screen> <para>Once the build has been configured, you can start the build by typing:</para> - <screen>C:\FXRuby-1.6.0> <command>ruby install.rb setup</command></screen> + <screen>C:\FXRuby-1.6.13> <command>ruby install.rb setup</command></screen> <para>It will take quite awhile to build FXRuby, even on a fast machine, so this might be a good time to take a coffee break. Because Visual C++ is @@ -129,12 +128,12 @@ C:\ruby-1.8.4><command>nmake</command></screen> <para>Once it's finished compiling, install FXRuby by typing:</para> - <screen>C:\FXRuby-1.6.0> <command>ruby install.rb install</command></screen> + <screen>C:\FXRuby-1.6.13> <command>ruby install.rb install</command></screen> <para>As a quick sanity check, to make sure that all is well, you should probably fire up <filename>irb</filename> and try to import FXRuby:</para> - <screen>C:\FXRuby-1.6.0> <command>irb</command> + <screen>C:\FXRuby-1.6.13> <command>irb</command> irb(main):001:0> <userinput>require 'fox16'</userinput> true irb(main):002:0></screen> @@ -232,34 +231,34 @@ core_wrap.cpp:108596: virtual memory exhausted</screen> <para>On Linux and other Unix systems that support shared libraries, FOX is typically installed as a shared library named - <filename>libFOX-1.4.so</filename>. After all of the source files for + <filename>libFOX-1.6.so</filename>. After all of the source files for FXRuby are compiled, the last step is to link all of the FXRuby object files together with the FOX library (and possibly other system libraries) - to produce a new shared library, named <filename>fox14.so</filename>, that + to produce a new shared library, named <filename>fox16.so</filename>, that Ruby can import as an extension module.</para> <para>There are a few things that can go wrong when you try to import this extension into Ruby. A common problem is that the operating system cannot - locate the FOX shared library (<filename>libFOX-1.4.so</filename>) when it + locate the FOX shared library (<filename>libFOX-1.6.so</filename>) when it tries to dynamically load the FXRuby extension module; when this happens, the error message will look something like:</para> <screen>$ <command>irb</command> -irb(main):001:0> <userinput>require 'fox'</userinput> -LoadError: libFOX-0.99.so.173: cannot open shared object file: No such file or directory - /usr/local/lib/ruby/1.6/i586-linux/fox.so +irb(main):001:0> <userinput>require 'fox16'</userinput> +LoadError: libFOX-1.6.so: cannot open shared object file: No such file or directory - /usr/local/lib/ruby/1.8/i686-linux/fox16.so from (irb):1:in 'require' from (irb):1 </screen> <para>One workaround for this problem is to modify the <constant>LD_LIBRARY_PATH</constant> environment variable to include the - directory where <filename>libFOX.so</filename> is installed. For example, - if <filename>libFOX-1.4.so</filename> is installed in <filename + directory where <filename>libFOX-1.6.so</filename> is installed. For + example, if <filename>libFOX-1.6.so</filename> is installed in <filename class="directory">/usr/local/lib</filename>, try setting:</para> <screen>$ <command>export LD_LIBRARY_PATH=/usr/local/lib</command> $ <command>irb</command> -irb(main):001:0> <userinput>require 'fox'</userinput> +irb(main):001:0> <userinput>require 'fox16'</userinput> </screen> <para>If this works, you can of course permanently add the @@ -273,7 +272,7 @@ irb(main):001:0> <userinput>require 'fox'</userinput> <orderedlist numeration="arabic" spacing="compact"> <listitem> <para>Edit your <filename>/etc/ld.so.conf</filename> file and add the - directory where <filename>libFOX.so</filename> is installed; + directory where <filename>libFOX-1.6.so</filename> is installed; and,</para> </listitem> @@ -294,4 +293,4 @@ irb(main):001:0> <userinput>require 'fox'</userinput> <filename>Makefile</filename> and add <option>-lgcc</option> to the <constant>LIBS</constant> line.</para> </simplesect> -</chapter> +</chapter> \ No newline at end of file diff --git a/doc/changes.xml b/doc/changes.xml index d62e6dd..80c3c07 100755 --- a/doc/changes.xml +++ b/doc/changes.xml @@ -2,6 +2,440 @@ <chapter id="changes"> <title>Change History</title> + <simplesect> + <title>Changes For Version 1.6.18 (December 29, 2008)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Some users were having trouble building FXRuby on 64-bit operating systems + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=23375&group_id=300&atid=1223">RubyForge + Bug #23375</ulink>). This problem has been corrected.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.17 (December 24, 2008)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>The Ruby interpreter was generating a large number of warning messages about redefined methods + in the <filename>kwargs.rb</filename> library + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=19231&group_id=300&atid=1223">RubyForge + Bug #19231</ulink> and elsewhere). This problem has been corrected.</para> + </listitem> + + <listitem> + Due to recent changes in Ruby's garbage collection algorithm, FXRuby applications could under some circumstances + crash for large numbers of table items + (see RubyForge bugs <ulink url="http://rubyforge.org/tracker/index.php?func=detail&aid=21983&group_id=300&atid=1223">21983</ulink> and <ulink url="http://rubyforge.org/tracker/index.php?func=detail&aid=23188&group_id=300&atid=1223">23188</ulink>). + This bug has been fixed. + </listitem> + + <listitem> + <para>The documentation for the <classname>FXTable</classname> class referred to the non-existent <methodname>setColumnX</methodname> + and <methodname>setRowY</methodname> instance methods + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=21987&group_id=300&atid=1223">RubyForge + Bug #21987</ulink>). These entries have been removed from the documentation.</para> + </listitem> + + <listitem> + <para>A number of instance methods for the <classname>FXTable</classname> class could crash an application if they + were passed out-of-bounds index arguments + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=21987&group_id=300&atid=1223">RubyForge + Bug #21987</ulink>). These methods now raise <classname>IndexError</classname> when they're passed out-of-bounds + indexes.</para> + </listitem> + + <listitem> + <para>Due to a change in the URL scheme for the Dilbert web site, the <filename>dilbert.rb</filename> example + program was no longer working properly + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=21538&group_id=300&atid=1223">RubyForge + Bug #21538</ulink>). This has been fixed.</para> + </listitem> + + <listitem> + <para>The <methodname>lower</methodname> method for the <classname>FXRangef</classname> was returning + <constant>self</constant> instead of an <classname>FXVec3f</classname> instance for the range's low + bound + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=22488&group_id=300&atid=1223">RubyForge + Bug #22488</ulink>). This has been fixed.</para> + </listitem> + + <listitem> + <para>Made a number of minor fixes for compatibility with Ruby 1.9.1.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.16 (July 3, 2008)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Historically, if you called <methodname>create</methodname> on a + window before its parent window was created, your application would + crash (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=20702&group_id=300&atid=1223">RubyForge + Bug #20702</ulink> and elsewhere). Now, the code should raise a + <constant>RuntimeError</constant> with a message indicating the + problem.</para> + </listitem> + + <listitem> + <para>The message data that the <classname>FXPicker</classname> widget + sends along with its <constant>SEL_CHANGED</constant> and + <constant>SEL_COMMAND</constant> messages wasn't being handled + properly, and as a result, applications using this widget could crash + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=20780&group_id=300&atid=1223">RubyForge + Bug #20780</ulink>). This problem has been fixed.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.15 (June 4, 2008)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>FXRuby applications could crash (with a segmentation fault) if + <constant>nil</constant> was passed in as the first argument to + <methodname>FXDialogBox.new</methodname> or + <methodname>FXMainWindow.new</methodname> (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=14642&group_id=300&atid=1223">RubyForge + Bug #14642</ulink>). These methods now raise an + <constant>ArgumentError</constant> if <constant>nil</constant> is + passed as the first argument.</para> + </listitem> + + <listitem> + <para>You should only ever construct one <classname>FXApp</classname> + object per application, but there was no protection against doing so + in the code (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=16275&group_id=300&atid=1223">RubyForge + Bug #16275</ulink>). Now, <methodname>FXApp.new</methodname> will + raise a <classname>RuntimeException</classname> if an + <classname>FXApp</classname> object already exists.</para> + </listitem> + + <listitem> + <para>The <filename>babelfish.rb</filename> example program, which + previously depended on an external web service to perform translation + between languages, was broken since that web service no longer exists + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=16962&group_id=300&atid=1223">RubyForge + Bug #16962</ulink>). The example has now been updated to use Dr. Nic's + <ulink url="http://tranexp.rubyforge.org/">Tranexp</ulink> library + instead.</para> + </listitem> + + <listitem> + <para>The value of the <constant>MBOX_SAVE_CANCEL_DONTSAVE</constant> + option (for the <classname>FXMessageBox</classname> class) wasn't + wrapped properly and was unusable (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=17094&group_id=300&atid=1223">RubyForge + Bug #17094</ulink>). There was also no constant corresponding to the + <constant>MBOX_CLICKED_DONTSAVE</constant> return value. Both of these + problems have been fixed.</para> + </listitem> + + <listitem> + <para>The fields for new <classname>FXHiliteStyle</classname> objects + were uninitialized and as a result sometimes gave unpredictable + results (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=19637&group_id=300&atid=1223">RubyForge + Bug #19637</ulink>). This has been fixed.</para> + </listitem> + + <listitem> + <para>The <methodname>columnHeaderFont</methodname> and + <methodname>rowHeaderFont</methodname> attributes for + <classname>FXTable</classname> weren't implemented properly (see + <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=20142&group_id=300&atid=1223">RubyForge + Bug #20142</ulink>). This has been fixed.</para> + </listitem> + + <listitem> + <para>Ruby 1.8.7 adds a new <methodname>first</methodname> method to + the <classname>Enumerable</classname> module, and this conflicts with + the existing <methodname>first</methodname> method defined in the + <classname>FXWindow</classname> base class for a number of FXRuby + classes which mix in <classname>Enumerable</classname> (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=20418&group_id=300&atid=1223">RubyForge + Bug #20418</ulink>). This problem has been resolved.</para> + </listitem> + + <listitem> + <para>Due to a bug in the <filename>extconf.rb</filename> script, the + build was failing for Ruby 1.9.0 (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=20426&group_id=300&atid=1223">RubyForge + Bug #20426</ulink>). This has been fixed.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.14 (March 29, 2008)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Updated the documentation for the <classname>FXImage</classname> + class to indicate which methods call <methodname>render</methodname> + after they're finished, and which ones do not.</para> + </listitem> + + <listitem> + <para>Corrected a little typo in the + <filename>gembrowser.rb</filename> example program.</para> + </listitem> + + <listitem> + <para>Updated the <filename>dilbert.rb</filename> example program to + use the more popular-and-likely-to-be-installed <ulink + url="http://code.whytheluckystiff.net/hpricot/">Hpricot</ulink> HTML + parser library instead of <ulink + url="http://www.crummy.com/software/RubyfulSoup/">Rubyful + Soup</ulink>.</para> + </listitem> + + <listitem> + <para>Re-added the documentation for the + <constant>TOGGLEBUTTON_KEEPSTATE</constant> option, which had + mysteriously disappeared (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=2286&group_id=300&atid=1223">RubyForge + Bug #2286</ulink>).</para> + </listitem> + + <listitem> + <para>Made a number of minor fixes to support building FXRuby against + Ruby 1.9.</para> + </listitem> + + <listitem> + <para>Added a binary gem for OS X. This works with the Ruby that's + included with OS X (Leopard).</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.32 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.13 (November 9, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Calls to the <methodname>extractText</methodname> method for the + <classname>FXTable</classname> class were causing various + memory-related errors on certain platforms (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=15444group_id=300&atid=1223">RubyForge + Bug #15444</ulink>). This problem has been fixed.</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.28 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.12 (October 19, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>The API documentation for <classname>FXMDIClient</classname> + referred to the non-existent instance method + <methodname>activeChild=</methodname> (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=10259&group_id=300&atid=1223">RubyForge + Bug #10259</ulink>). This method has been added.</para> + </listitem> + + <listitem> + <para>The API documentation for <classname>FXMDIClient</classname> + also referred to the non-existent instance methods + <methodname>getMDIChildFirst</methodname> and + <methodname>getMDIChildLast</methodname>. These entries have been + removed.</para> + </listitem> + + <listitem> + <para>The API documentation for <classname>FXMDIChild</classname> + referred to non-existent instance methods + <methodname>getMDINext</methodname> and + <methodname>getMDIPrev</methodname> (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=10436&group_id=300&atid=1223">RubyForge + Bug #10436</ulink>). The documentation has been corrected.</para> + </listitem> + + <listitem> + <para>Added the <parameter>:repeat</parameter> parameter for the + <methodname>addChore</methodname> and + <methodname>addTimeout</methodname> methods. See the documentation for + more details, and <filename>gltest.rb</filename> for an example of its + use.</para> + </listitem> + + <listitem> + <para>Corrected a number of minor typos in the API + documentation.</para> + </listitem> + + <listitem> + <para>Corrected a typo in the <filename>imageviewer.rb</filename> + example.</para> + </listitem> + + <listitem> + <para>Modified the <filename>inputs.rb</filename> example program to + use <methodname>Pipe.read_nonblock()</methodname> instead of + <methodname>Pipe.read()</methodname>.</para> + </listitem> + + <listitem> + <para>Fixed a bug in the implementation of the + <methodname>findText</methodname> method for the + <classname>FXText</classname> class, when used with the + <constant>SEARCH_REGEX</constant> option.</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.28 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.11 (April 18, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Added <methodname>editable</methodname> as an alias for + <methodname>FXTextField#editable?</methodname>.</para> + </listitem> + + <listitem> + <para>Added <methodname>each_child_recursive</methodname> instance + method for the <classname>FXWindow</classname> class. This method + performs a depth-first traversal of the widget tree starting at the + receiver window.</para> + </listitem> + + <listitem> + <para>Corrected some errors in the keyword arguments support for the + <classname>FXVec2d</classname>, <classname>FXVec2f</classname>, + <classname>FXVec3d</classname>, <classname>FVec3f</classname>, + <classname>FXVec4d</classname> and <classname>FXVec4f</classname> + classes.</para> + </listitem> + + <listitem> + <para>Corrected an error in the keyword arguments support for the + <classname>FXIconDict</classname> class.</para> + </listitem> + + <listitem> + <para>Modified the gem specification so that the RDoc generated during + a gem install is consistent with that generated by other methods (see + <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=10035&group_id=300&atid=1223">RubyForge + Bug #10035</ulink>).</para> + </listitem> + + <listitem> + <para>Changes to the <filename>iterators</filename> library in version + 1.6.6 introduced a bug in the <methodname>each</methodname> method for + the <classname>FXFoldingList</classname>, + <classname>FXTreeList</classname> and + <classname>FXTreeListBox</classname> classes (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=10175&group_id=300&atid=1223">RubyForge + Bug #10175</ulink>). This problem has been fixed.</para> + </listitem> + + <listitem> + <para>Applied submitted patches for building FXRuby against Ruby 1.9 + (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=10181&group_id=300&atid=1223">RubyForge + Bug #10181</ulink>). Please note that building FXRuby against the Ruby + 1.9 code base is still officially unsupported; however, I'm glad to + accept patches that will help make this possible.</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.25 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.9 (April 8, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>A bug was discovered in the keyword arguments library support + for the <classname>FXMenuBar</classname> class (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=9927&group_id=300&atid=1223">RubyForge + Bug #9927</ulink>). This problem has been fixed.</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.25 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.8 (April 5, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>Due to an internal bookkeeping error, applications like the + <filename>glviewer.rb</filename> example program which create multiple + <classname>FXGLViewer</classname> instances could cause an assertion + to fail. When this assertion fails on Windows, the program simply + crashes (see <ulink + url="http://rubyforge.org/tracker/index.php?func=detail&aid=9775&group_id=300&atid=1223">RubyForge + Bug #9775</ulink>). This problem has been fixed.</para> + </listitem> + + <listitem> + <para>The keyword arguments library, introduced in version 1.6.5, is + now included automatically when you load FXRuby; it is no longer + necessary to explicitly require it.</para> + </listitem> + + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.25 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + + <simplesect> + <title>Changes For Version 1.6.7 (March 31, 2007)</title> + + <itemizedlist mark="bullet"> + <listitem> + <para>The binary gem for Windows was built with FOX version 1.6.25 and + FXScintilla version 1.71.</para> + </listitem> + </itemizedlist> + </simplesect> + <simplesect> <title>Changes For Version 1.6.6 (February 10, 2007)</title> diff --git a/doc/clipboardtut.xml b/doc/clipboardtut.xml index eb32f71..92836a0 100755 --- a/doc/clipboardtut.xml +++ b/doc/clipboardtut.xml @@ -21,8 +21,7 @@ doesn't yet provide any clipboard support. This application simply presents a list of customers (from some external source).</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' require 'customer' include Fox @@ -30,14 +29,14 @@ include Fox class ClipMainWindow < FXMainWindow def initialize(anApp) # Initialize base class first - super(anApp, "Clipboard Example", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Clipboard Example", :opts => DECOR_ALL, :width => 400, :height => 300) # Place the list in a sunken frame - sunkenFrame = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, - 0, 0, 0, 0, 0, 0, 0, 0) + sunkenFrame = FXVerticalFrame.new(self, + LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding => 0) # Customer list - customerList = FXList.new(sunkenFrame, nil, 0, LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y) + customerList = FXList.new(sunkenFrame, :opts => LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y) $customers.each do |customer| customerList.appendItem(customer.name, nil, customer) end @@ -89,8 +88,7 @@ $customers << Customer.new("Johnny Storm", "123 Maple, Anytown, NC", 12345 <para>Let's begin by augmenting the GUI to include a row of buttons along the bottom of the main window for copying and pasting:</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' require 'customer' include Fox @@ -98,7 +96,7 @@ include Fox class ClipMainWindow < FXMainWindow def initialize(anApp) # Initialize base class first - super(anApp, "Clipboard Example", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Clipboard Example", :opts => DECOR_ALL, :width => 400, :height => 300) <emphasis role="bold"> # Horizontal frame contains buttons buttons = FXHorizontalFrame.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH) @@ -108,11 +106,11 @@ class ClipMainWindow < FXMainWindow pasteButton = FXButton.new(buttons, "Paste") </emphasis> # Place the list in a sunken frame - sunkenFrame = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, - 0, 0, 0, 0, 0, 0, 0, 0) + sunkenFrame = FXVerticalFrame.new(self, + LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding => 0) # Customer list - customerList = FXList.new(sunkenFrame, nil, 0, LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y) + customerList = FXList.new(sunkenFrame, :opts => LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y) $customers.each do |customer| customerList.appendItem(customer.name, nil, customer) end diff --git a/doc/custom-fo.xsl b/doc/custom-fo.xsl index 563fc05..039868c 100755 --- a/doc/custom-fo.xsl +++ b/doc/custom-fo.xsl @@ -3,7 +3,7 @@ version='1.0' xmlns="http://www.w3.org/TR/xhtml1/transitional" exclude-result-prefixes="#default"> -<xsl:import href="/usr/local/docbook/docbook-xsl-1.61.2/fo/docbook.xsl"/> +<xsl:import href="/Users/lyle/docbook/docbook5-xsl-1.72.0/fo/docbook.xsl"/> <!--xsl:param name="use.extensions" select="1"/--> <xsl:param name="fop.extensions" select="1"/> <xsl:param name="shade.verbatim" select="1"/> diff --git a/doc/custom-html.xsl b/doc/custom-html.xsl index 3cbb41b..aa8dd7f 100755 --- a/doc/custom-html.xsl +++ b/doc/custom-html.xsl @@ -4,7 +4,7 @@ xmlns="http://www.w3.org/TR/xhtml1/transitional" exclude-result-prefixes="#default"> -<xsl:import href="/Users/lyle/docbook/docbook-xsl-1.68.1/html/chunk.xsl"/> +<xsl:import href="/Users/lyle/docbook/docbook5-xsl-1.72.0/html/chunk.xsl"/> <xsl:variable name="root.filename">book</xsl:variable> <xsl:param name="html.stylesheet.type">text/css</xsl:param> diff --git a/doc/dragdroptut.xml b/doc/dragdroptut.xml index 31a93b5..5db5d2f 100755 --- a/doc/dragdroptut.xml +++ b/doc/dragdroptut.xml @@ -15,18 +15,17 @@ of a main window widget (a <classname>DropSite</classname> instance) that parents an <classname>FXCanvas</classname> widget:</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DropSite < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drop Site", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) end def create @@ -55,26 +54,25 @@ end that by adding a handler that clears the canvas to its current background color:</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DropSite < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drop Site", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) <emphasis role="bold"> # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - }</emphasis> + end + end</emphasis> end def create @@ -95,23 +93,23 @@ end from some other window, such as an <classname>FXColorWell</classname> widget, and drop it onto the canvas in order to change the canvas' background color. In order for a FOX widget to be able to accept drops at - all, we need to first call its <methodname>dropEnable()</methodname> + all, we need to first call its <methodname>dropEnable</methodname> method:</para> <programlisting format="linespecific">def initialize(anApp) # Initialize base class - super(anApp, "Drop Site", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end <emphasis role="bold"> # Enable canvas for drag-and-drop messages @canvas.dropEnable @@ -141,39 +139,39 @@ end that the canvas isn't accepting drops of color data yet.</para> <para>To correct this problem, we need to use the canvas' - <methodname>acceptDrop()</methodname> method to indicate whether or not + <methodname>acceptDrop</methodname> method to indicate whether or not we'll accept certain kinds of drops. You can call - <methodname>acceptDrop()</methodname> any time after receiving the initial + <methodname>acceptDrop</methodname> any time after receiving the initial <constant>SEL_DND_ENTER</constant> message, but it's usually done in response to a <constant>SEL_DND_MOTION</constant> message. Let's add a handler for <constant>SEL_DND_MOTION</constant> messages from the canvas - in DropSite's initialize() method. For now, we'll unconditionally accept + in DropSite's <methodname>initialize</methodname> method. For now, we'll unconditionally accept drops from any drag source, regardless of what kind of data they're offering:</para> <programlisting format="linespecific">def initialize(anApp) # Initialize base class - super(anApp, "Drop Site", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end # Enable canvas for drag-and-drop messages @canvas.dropEnable <emphasis role="bold"> # Handle SEL_DND_MOTION messages from the canvas - @canvas.connect(SEL_DND_MOTION) { + @canvas.connect(SEL_DND_MOTION) do # Accept drops unconditionally (for now) @canvas.acceptDrop - } + end </emphasis>end </programlisting> @@ -195,7 +193,7 @@ end <para>Drag types (even the standard ones) must be registered before they can be used, and so we'll start by adding a few lines to - <classname>DropSite</classname>'s <methodname>create()</methodname> method + <classname>DropSite</classname>'s <methodname>create</methodname> method to register the drag type for color data:</para> <programlisting format="linespecific">def create @@ -211,49 +209,49 @@ end </programlisting> <para>Note that the first time that - <methodname>registerDragType()</methodname> is called for a particular + <methodname>registerDragType</methodname> is called for a particular drag type name (such as <methodname>FXWindow.colorTypeName</methodname>) it will generate a unique identifier for that drag type. Subsequent calls - to <methodname>registerDragType()</methodname> for the same drag type name + to <methodname>registerDragType</methodname> for the same drag type name will just return the previously-generated drag type. Now, we want to modify our <constant>SEL_DND_MOTION</constant> handler so that it's a little more picky about which kinds of drops it will accept:</para> <programlisting format="linespecific"># Handle SEL_DND_MOTION messages from the canvas -@canvas.connect(SEL_DND_MOTION) { +@canvas.connect(SEL_DND_MOTION) do <emphasis role="bold"> if @canvas.offeredDNDType?(FROM_DRAGNDROP, FXWindow.colorType) @canvas.acceptDrop end -</emphasis>} +</emphasis>end </programlisting> <para>Here, we call the canvas' <methodname>offeredDNDType?</methodname> method to ask if the drag source can provide its data in the requested format. Only if <methodname>offeredDNDType?</methodname> returns true will - we call <methodname>acceptDrop()</methodname> as before.</para> + we call <methodname>acceptDrop</methodname> as before.</para> <para>The last step is to actually handle the drop, and for that we add a handler for the <constant>SEL_DND_DROP</constant> message:</para> <programlisting format="linespecific"><emphasis role="bold"># Handle SEL_DND_DROP message from the canvas -@canvas.connect(SEL_DND_DROP) { +@canvas.connect(SEL_DND_DROP) do # Try to obtain the data as color values first data = @canvas.getDNDData(FROM_DRAGNDROP, FXWindow.colorType) unless data.nil? # Update canvas background color @canvas.backColor = Fox.fxdecodeColorData(data) end -}</emphasis></programlisting> +end</emphasis></programlisting> <para>Assuming that the drag source is able to provide its data in the - requested format, the <methodname>getDNDData()</methodname> method will - return a String (which for our purposes is just a byte buffer). If you've + requested format, the <methodname>getDNDData</methodname> method will + return a string (which for our purposes is just a byte buffer). If you've defined your own application-specific drag types, this data can of course be anything, and we'll see examples of this in a later tutorial. But the data for standard drag types like <methodname>FXWindow.colorType</methodname> can be decoded using the appropriate built-in library functions. In this case, we use the - <methodname>fxdecodeColorData()</methodname> method to convert the bytes + <methodname>fxdecodeColorData</methodname> method to convert the bytes into a color value that we can use.</para> <para>Now comes the moment of truth. Try running your test program again @@ -265,46 +263,45 @@ end <filename class="directory">examples</filename> directory under the file name <filename>dropsite.rb</filename>.</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DropSite < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drop Site", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end # Enable canvas for drag-and-drop messages @canvas.dropEnable # Handle SEL_DND_MOTION messages from the canvas - @canvas.connect(SEL_DND_MOTION) { + @canvas.connect(SEL_DND_MOTION) do if @canvas.offeredDNDType?(FROM_DRAGNDROP, FXWindow.colorType) @canvas.acceptDrop end - } + end # Handle SEL_DND_DROP message from the canvas - @canvas.connect(SEL_DND_DROP) { + @canvas.connect(SEL_DND_DROP) do # Try to obtain the data as color values first data = @canvas.getDNDData(FROM_DRAGNDROP, FXWindow.colorType) unless data.nil? # Update canvas background color @canvas.backColor = Fox.fxdecodeColorData(data) end - } + end end def create @@ -336,27 +333,26 @@ end consisting of a main window widget (a <classname>DragSource</classname> instance) that parents an <classname>FXCanvas</classname> widget:</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DragSource < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drag Source", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drag Source", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) @canvas.backColor = "red" # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end end def create @@ -397,7 +393,7 @@ end <listitem> <para>The drag type for colors (<constant>FXWindow.colorType</constant>) is registered in the - <classname>DragSource</classname>'s <methodname>create()</methodname> + <classname>DragSource</classname>'s <methodname>create</methodname> method.</para> </listitem> </itemizedlist> @@ -412,7 +408,7 @@ end handler for the <constant>SEL_LEFTBUTTONPRESS</constant> message from the canvas:</para> - <programlisting format="linespecific">@canvas.connect(SEL_LEFTBUTTONPRESS) { + <programlisting format="linespecific">@canvas.connect(SEL_LEFTBUTTONPRESS) do # # Capture (grab) the mouse when the button goes down, so that all future # mouse events will be reported to this widget, even if those events occur @@ -423,13 +419,13 @@ end # Advertise which drag types we can offer dragTypes = [FXWindow.colorType] @canvas.beginDrag(dragTypes) -} +end </programlisting> <para>Note that there are usually two things you're going to want to do in the <constant>SEL_LEFTBUTTONPRESS</constant> handler for a drag source. - The first is to call <methodname>grab()</methodname> on the window that - acts as the drag source. Calling <methodname>grab()</methodname> + The first is to call <methodname>grab</methodname> on the window that + acts as the drag source. Calling <methodname>grab</methodname> "captures" the mouse in the sense that subsequent mouse motion events will be reported as if they occurred inside the grab window. This is important, since in our case we're going to be dragging from this window to some @@ -438,7 +434,7 @@ end <para>The second thing you'll want to do in the <constant>SEL_LEFTBUTTONPRESS</constant> handler for a drag source is to - call <methodname>beginDrag()</methodname>. This not only kicks the + call <methodname>beginDrag</methodname>. This not only kicks the application into drag-and-drop mode, but also provides a way for you to inform the system about the formats of data (i.e. the drag types) that this drag source is able to provide. For this example, the drag source is @@ -448,22 +444,22 @@ end it's important to also add a handler for the <constant>SEL_LEFTBUTTONRELEASE</constant> message:</para> - <programlisting format="linespecific">@canvas.connect(SEL_LEFTBUTTONRELEASE) { + <programlisting format="linespecific">@canvas.connect(SEL_LEFTBUTTONRELEASE) do @canvas.ungrab @canvas.endDrag -} +end </programlisting> <para>This is pretty much the mirror image of our <constant>SEL_LEFTBUTTONPRESS</constant> handler. We call - <methodname>ungrab()</methodname> to release the mouse capture, and - <methodname>endDrag()</methodname> to clean up the drag-and-drop + <methodname>ungrab</methodname> to release the mouse capture, and + <methodname>endDrag</methodname> to clean up the drag-and-drop state.</para> <para>The next change is to add a <constant>SEL_MOTION</constant> handler, to handle mouse motion events during the drag operation:</para> - <programlisting format="linespecific">@canvas.connect(SEL_MOTION) { |sender, sel, event| + <programlisting format="linespecific">@canvas.connect(SEL_MOTION) do |sender, sel, event| if @canvas.dragging? @canvas.handleDrag(event.root_x, event.root_y) unless @canvas.didAccept == DRAG_REJECT @@ -472,23 +468,23 @@ end @canvas.dragCursor = getApp().getDefaultCursor(DEF_DNDSTOP_CURSOR) end end -} +end </programlisting> <para>The <methodname>dragging?</methodname> method returns true if we're in the middle of a drag-and-drop operation for the drag source window, - i.e. after the call to <methodname>beginDrag()</methodname> but before the - call to <methodname>endDrag()</methodname>. If we're not currently + i.e. after the call to <methodname>beginDrag</methodname> but before the + call to <methodname>endDrag</methodname>. If we're not currently processing a drag operation, we're not really interested in mouse motion events for the canvas.</para> <para>If we <emphasis>are</emphasis> processing a drag operation, however, - we need to call <methodname>handleDrag()</methodname> on the drag source + we need to call <methodname>handleDrag</methodname> on the drag source window. FOX uses this information to send drag-and-drop messages (such as <constant>SEL_DND_ENTER</constant>, <constant>SEL_DND_MOTION</constant> and <constant>SEL_DND_LEAVE</constant>) to the window that the mouse is currently over. Note that the coordinates passed to - <methodname>handleDrag()</methodname> are root window coordinates, and not + <methodname>handleDrag</methodname> are root window coordinates, and not window-local coordinates.</para> <para>Another good thing to consider doing here is to change the shape of @@ -530,16 +526,16 @@ end <para>The last (and most important) step is to actually complete the data transfer. At any time during a drag-and-drop operation, a drop site may request a copy of the drag-and-drop data by calling the - <methodname>getDNDData()</methodname> method (as described in the previous + <methodname>getDNDData</methodname> method (as described in the previous section). When this happens, FOX sends a <constant>SEL_DND_REQUEST</constant> message to the current drag source window, and so we now add a handler for that message:</para> - <programlisting format="linespecific">@canvas.connect(SEL_DND_REQUEST) { |sender, sel, event| + <programlisting format="linespecific">@canvas.connect(SEL_DND_REQUEST) do |sender, sel, event| if event.target == FXWindow.colorType @canvas.setDNDData(FROM_DRAGNDROP, FXWindow.colorType, Fox.fxencodeColorData(@canvas.backColor)) end -} +end </programlisting> <para>The first important thing to note here is that the @@ -553,8 +549,8 @@ end <para>Assuming that the drag type is as expected, the last step is send the data to the drop site by calling - <methodname>setDNDData()</methodname>. As with the call to - <methodname>getDNDData()</methodname> for our previous drop site program, + <methodname>setDNDData</methodname>. As with the call to + <methodname>getDNDData</methodname> for our previous drop site program, you want to be sure to specify the origin of the data (<constant>FROM_DRAGNDROP</constant>), the drag type (<constant>FXWindow.colorType</constant>) and the data itself as a binary @@ -569,30 +565,29 @@ end <filename class="directory">examples</filename> directory under the file name <filename>dragsource.rb</filename>.</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DragSource < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drag Source", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drag Source", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) @canvas.backColor = "red" # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end # Handle left button press - @canvas.connect(SEL_LEFTBUTTONPRESS) { + @canvas.connect(SEL_LEFTBUTTONPRESS) do # # Capture (grab) the mouse when the button goes down, so that all future # mouse events will be reported to this widget, even if those events occur @@ -603,10 +598,10 @@ class DragSource < FXMainWindow # Advertise which drag types we can offer dragTypes = [FXWindow.colorType] @canvas.beginDrag(dragTypes) - } + end # Handle mouse motion events - @canvas.connect(SEL_MOTION) { |sender, sel, event| + @canvas.connect(SEL_MOTION) do |sender, sel, event| if @canvas.dragging? @canvas.handleDrag(event.root_x, event.root_y) unless @canvas.didAccept == DRAG_REJECT @@ -615,20 +610,20 @@ class DragSource < FXMainWindow @canvas.dragCursor = getApp().getDefaultCursor(DEF_DNDSTOP_CURSOR) end end - } + end # Handle left button release - @canvas.connect(SEL_LEFTBUTTONRELEASE) { + @canvas.connect(SEL_LEFTBUTTONRELEASE) do @canvas.ungrab @canvas.endDrag - } + end # Handle request for DND data - @canvas.connect(SEL_DND_REQUEST) { |sender, sel, event| + @canvas.connect(SEL_DND_REQUEST) do |sender, sel, event| if event.target == FXWindow.colorType @canvas.setDNDData(FROM_DRAGNDROP, FXWindow.colorType, Fox.fxencodeColorData(@canvas.backColor)) end - } + end end def create @@ -671,7 +666,7 @@ end <itemizedlist> <listitem> - <para>A call to <methodname>dropEnable()</methodname>, to make + <para>A call to <methodname>dropEnable</methodname>, to make <classname>DragSource</classname>'s canvas drop-enabled;</para> </listitem> @@ -702,33 +697,32 @@ end <filename class="directory">examples</filename> directory under the file name <filename>dragdrop.rb</filename>.</para> - <programlisting format="linespecific">require 'rubygems' -require_gem 'fxruby' + <programlisting format="linespecific">require 'fox16' include Fox class DragDropWindow < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drag and Drop", nil, nil, DECOR_ALL, 0, 0, 400, 300) + super(anApp, "Drag and Drop", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas - @canvas = FXCanvas.new(self, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) + @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) @canvas.backColor = "red" # Enable canvas for drag-and-drop messages @canvas.dropEnable # Handle expose events on the canvas - @canvas.connect(SEL_PAINT) { |sender, sel, event| - FXDCWindow.new(@canvas, event) { |dc| + @canvas.connect(SEL_PAINT) do |sender, sel, event| + FXDCWindow.new(@canvas, event) do |dc| dc.foreground = @canvas.backColor dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h) - } - } + end + end # Handle left button press - @canvas.connect(SEL_LEFTBUTTONPRESS) { + @canvas.connect(SEL_LEFTBUTTONPRESS) do # # Capture (grab) the mouse when the button goes down, so that all future # mouse events will be reported to this widget, even if those events occur @@ -739,10 +733,10 @@ class DragDropWindow < FXMainWindow # Advertise which drag types we can offer dragTypes = [FXWindow.colorType] @canvas.beginDrag(dragTypes) - } + end # Handle mouse motion events - @canvas.connect(SEL_MOTION) { |sender, sel, event| + @canvas.connect(SEL_MOTION) do |sender, sel, event| if @canvas.dragging? @canvas.handleDrag(event.root_x, event.root_y) unless @canvas.didAccept == DRAG_REJECT @@ -751,37 +745,37 @@ class DragDropWindow < FXMainWindow @canvas.dragCursor = getApp().getDefaultCursor(DEF_DNDSTOP_CURSOR) end end - } + end # Handle SEL_DND_MOTION messages from the canvas - @canvas.connect(SEL_DND_MOTION) { + @canvas.connect(SEL_DND_MOTION) do if @canvas.offeredDNDType?(FROM_DRAGNDROP, FXWindow.colorType) @canvas.acceptDrop end - } + end # Handle left button release - @canvas.connect(SEL_LEFTBUTTONRELEASE) { + @canvas.connect(SEL_LEFTBUTTONRELEASE) do @canvas.ungrab @canvas.endDrag - } + end # Handle SEL_DND_DROP message from the canvas - @canvas.connect(SEL_DND_DROP) { + @canvas.connect(SEL_DND_DROP) do # Try to obtain the data as color values first data = @canvas.getDNDData(FROM_DRAGNDROP, FXWindow.colorType) unless data.nil? # Update canvas background color @canvas.backColor = Fox.fxdecodeColorData(data) end - } + end # Handle request for DND data - @canvas.connect(SEL_DND_REQUEST) { |sender, sel, event| + @canvas.connect(SEL_DND_REQUEST) do |sender, sel, event| if event.target == FXWindow.colorType @canvas.setDNDData(FROM_DRAGNDROP, FXWindow.colorType, Fox.fxencodeColorData(@canvas.backColor)) end - } + end end def create diff --git a/doc/gems.xml b/doc/gems.xml index 4df9d22..b9db616 100755 --- a/doc/gems.xml +++ b/doc/gems.xml @@ -5,9 +5,9 @@ <simplesect> <title>Introduction</title> - <para>Starting with FXRuby version 1.2, FXRuby uses <ulink - url="http://rubygems.rubyforge.org">RubyGems</ulink> as its packaging and - distribution method. The code is available both as</para> + <para>FXRuby uses <ulink + url="http://rubygems.rubyforge.org">RubyGems</ulink> as its preferred + packaging and distribution method. The code is available both as</para> <itemizedlist mark="bullet"> <listitem> @@ -28,7 +28,7 @@ <para>If you've already downloaded the source gem, you can install it by typing:</para> - <screen>$ <command>sudo gem install fxruby-1.6.0.gem</command></screen> + <screen>$ <command>sudo gem install fxruby-1.6.13.gem</command></screen> <para>Note the use of the <command>sudo</command> command to invoke superuser privileges, since you'll typically need superuser privileges to @@ -39,12 +39,12 @@ under some other directory (for example, in your home directory) you might need to pass some additional arguments on the command line, e.g.</para> - <screen>$ <command>sudo gem install fxruby-1.6.0.gem --force -- --with-fox-include=/home/lyle/include/fox-1.6 --with-fox-lib=/home/lyle/lib</command></screen> + <screen>$ <command>sudo gem install fxruby-1.6.13.gem --force -- --with-fox-include=/home/lyle/include/fox-1.6 --with-fox-lib=/home/lyle/lib</command></screen> <para>If you're installing a source gem on a Windows box, you'd instead type something like:</para> - <screen>C:\> <command>gem install fxruby-1.6.0.gem --force -- --with-fox-include=C:\include\fox-1.6 --with-fox-lib=C:\lib</command></screen> + <screen>C:\> <command>gem install fxruby-1.6.13.gem --force -- --with-fox-include=C:\include\fox-1.6 --with-fox-lib=C:\lib</command></screen> <para>If you're installing a source gem, it can take quite awhile to build FXRuby, so this might be a good time to take a coffee break. You won't see @@ -75,7 +75,7 @@ true</screen> <para>To install a binary gem for Windows, just type:</para> - <screen>C:\> <command>gem install fxruby-1.6.0-mswin32.gem</command></screen> + <screen>C:\> <command>gem install fxruby-1.6.13-mswin32.gem</command></screen> <para>As a quick sanity check, to make sure that all is well, you should probably fire up <filename>irb</filename> and try to require the FXRuby @@ -115,8 +115,8 @@ true</screen> the error message will look something like:</para> <screen>$ <command>irb</command> -irb(main):001:0> <userinput>require 'fox'</userinput> -LoadError: libFOX-0.99.so.173: cannot open shared object file: No such file or directory - /usr/local/lib/ruby/1.8/i686-linux/fox.so +irb(main):001:0> <userinput>require 'fox16'</userinput> +LoadError: libFOX-1.6.so: cannot open shared object file: No such file or directory - /usr/local/lib/ruby/1.8/i686-linux/fox16.so from (irb):1:in 'require' from (irb):1 </screen> @@ -145,7 +145,7 @@ irb(main):001:0> <userinput>require 'fox16'</userinput> <orderedlist numeration="arabic" spacing="compact"> <listitem> <para>Edit your <filename>/etc/ld.so.conf</filename> file and add the - directory where <filename>libFOX.so</filename> is installed; + directory where <filename>libFOX-1.6.so</filename> is installed; and,</para> </listitem> @@ -155,4 +155,4 @@ irb(main):001:0> <userinput>require 'fox16'</userinput> </listitem> </orderedlist> </simplesect> -</chapter> +</chapter> \ No newline at end of file diff --git a/doc/goals.xml b/doc/goals.xml index 6bdfb9d..8d79c9e 100755 --- a/doc/goals.xml +++ b/doc/goals.xml @@ -16,7 +16,7 @@ of its maturity and availability on a number of platforms (including the Macintosh). But Tk is also showing its age in many ways and it has failed to keep pace with some of the "younger" cross-platform GUI toolkits like - FOX, wxWindows, FLTK, Qt and GTK+. Of the latter five, only Qt and GTK+ + FOX, wxWidgets, FLTK, Qt and GTK+. Of the latter five, only Qt and GTK+ appeared (at the time) to have usable Ruby interfaces and there are some problems associated with these as well; for Qt, it's the restrictive license for the Windows platform version, and for GTK+ it's a Windows @@ -41,11 +41,18 @@ Ruby Developer's Guide</citetitle> and <citetitle pubwork="book">The Ruby Way</citetitle>) feature FXRuby as a Ruby GUI development option.</para> </listitem> + <listitem><para>FXRuby is used as the GUI for <ulink url="http://freeride.rubyforge.org/wiki/wiki.pl"> + FreeRIDE</ulink> and a number of other Ruby-based projects.</para></listitem> </itemizedlist> <para>Most recently, work has focused on keeping FXRuby up-to-date with the still evolving FOX library while looking for new ways to make Ruby GUI - development fun. For example, FXRuby is under consideration for use as a - GUI front-end to the fledgling <ulink url="http://freeride.rubyforge.org/wiki/wiki.pl"> - FreeRIDE</ulink> project. If you have suggestions about where you'd like to + development fun. If you have suggestions about where you'd like to see things go, feel free to drop me an e-mail.</para> + <simplesect> + <title>About this Document</title> + <para>The contents of this document were written using <ulink url="http://docbook.org/whatis">DocBook</ulink> version 5.0. + The HTML version of this document uses the CSS stylesheet originally developed for the + HTML version of the book <ulink url="http://svnbook.red-bean.com/">Version Control with Subversion</ulink>, + which is licensed under the <ulink url="http://creativecommons.org/licenses/by/2.0/">Creative Commons Attribution License</ulink>.</para> + </simplesect> </preface> diff --git a/doc/infosources.xml b/doc/infosources.xml index 27dcbc1..6fb8ec1 100755 --- a/doc/infosources.xml +++ b/doc/infosources.xml @@ -67,7 +67,7 @@ <para>The fxruby-users@rubyforge.org mailing list is a higher-volume list for FXRuby-related discussions. To subscribe to this list, follow the instructions at <ulink - url="http://rubyforge.org/mailman/listinfo/fxruby-announce">http://rubyforge.org/mailman/listinfo/fxruby-announce</ulink></para> + url="http://rubyforge.org/mailman/listinfo/fxruby-users">http://rubyforge.org/mailman/listinfo/fxruby-users</ulink></para> </listitem> <listitem> @@ -85,10 +85,10 @@ </listitem> <listitem> - <para>The ruby-talk@ruby-lang.org mailing list (or its mirror, the + <para>The Ruby-Talk mailing list (or its mirror, the comp.lang.ruby newsgroup) is a high-volume list for Ruby-related discussions. To subscribe to this list, follow the instructions at - <ulink url="http://www.ruby-lang.org/en/ml.html">http://www.ruby-lang.org/en/ml.html</ulink></para> + <ulink url="http://www.ruby-lang.org/en/community/mailing-lists/">http://www.ruby-lang.org/en/community/mailing-lists/</ulink></para> </listitem> </itemizedlist> </simplesect> diff --git a/doc/scintilla.xml b/doc/scintilla.xml index 324dce0..2b51505 100755 --- a/doc/scintilla.xml +++ b/doc/scintilla.xml @@ -16,10 +16,10 @@ <para><ulink url="http://savannah.gnu.org/projects/fxscintilla">FXScintilla </ulink> is a FOX widget that wraps around the Scintilla component, or, if you wish, - the FOX "port" of Scintilla. It is being developed by Gilles Filippini, + the FOX "port" of Scintilla. Until recently it was developed by Gilles Filippini, and as of this writing the latest release is available for download from <ulink - url="http://savannah.nongnu.org/download/fxscintilla/fxscintilla-1.63.tar.gz">http://savannah.nongnu.org/download/fxscintilla/fxscintilla-1.63.tar.gz</ulink>.</para> + url="http://download.savannah.gnu.org/releases/fxscintilla/fxscintilla-1.71.tar.gz">http://download.savannah.gnu.org/releases/fxscintilla/fxscintilla-1.71.tar.gz</ulink>.</para> </simplesect> <simplesect> @@ -30,7 +30,7 @@ applications. That is to say, you do not have to separately download the Scintilla source code from the Scintilla home page. When you unpack the FXScintilla tarball, you should get a new <filename class="directory"> - fxscintilla-1.63</filename> directory containing the source code for the + fxscintilla-1.71</filename> directory containing the source code for the FOX port of the Scintilla widget.</para> <para>As of the 1.46 release of FXScintilla, the build process has been @@ -61,13 +61,13 @@ typing:</para> <screen> -$ <command>sudo gem install fxruby-1.2.0.gem --force -- --with-fxscintilla-include=/usr/local/include/fxscintilla --with-fxscintilla-lib=/usr/local/lib</command> +$ <command>sudo gem install fxruby-1.6.7.gem --force -- --with-fxscintilla-include=/usr/local/include/fxscintilla --with-fxscintilla-lib=/usr/local/lib</command> </screen> <para>or, when compiling with Microsoft Visual C++, by typing:</para> <screen> -C:\> <command>gem install fxruby-1.2.0.gem --force -- --with-fox-include=C:\fox-1.2.7\include --with-fox-lib=C:\fox-1.2.7\lib --with-fxscintilla-include=C:\fxscintilla-1.63\include --with-fxscintilla-lib=C:\fxscintilla-1.63\lib</command> +C:\> <command>gem install fxruby-1.6.7.gem --force -- --with-fox-include=C:\fox-1.6.25\include --with-fox-lib=C:\fox-1.6.25\lib --with-fxscintilla-include=C:\fxscintilla-1.71\include --with-fxscintilla-lib=C:\fxscintilla-1.71\lib</command> </screen> <para>Past this point, the build and installation process for either diff --git a/doc/style.css b/doc/style.css index 97f9605..a584e5d 100644 --- a/doc/style.css +++ b/doc/style.css @@ -1,3 +1,247 @@ -pre.programlisting { background-color: #E0E0E0; } -pre.screen { background-color: #E0E0E0; } +/************************************************************************/ +/* Custom style-sheet stuffs for the Subversion book in HTML form. */ +/************************************************************************/ +/* + * Copyright (c) 2003-2007 + * Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato. + * + * This work is licensed under the Creative Commons Attribution License. + * To view a copy of this license, visit + * http://creativecommons.org/licenses/by/2.0/ or send a letter to + * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, + * USA. + */ + +body +{ + background: white; + margin: 0.5in; + font-family: arial,helvetica,sans-serif; +} + +p, li, ul, ol, dd, dt +{ + font-style: normal; + font-weight: normal; + color: black; +} + +tt, pre +{ + font-family: courier new,courier,fixed; +} + +a +{ + color: blue; + text-decoration: underline; +} + +a:hover +{ + background: rgb(75%,75%,100%); + color: blue; + text-decoration: underline; +} + +a:visited +{ + color: purple; + text-decoration: underline; +} + +img +{ + border: none; +} + +h1.title +{ + font-size: 250%; + font-style: normal; + font-weight: bold; + color: black; +} + +h2.subtitle +{ + font-size: 150%; + font-style: italic; + color: black; +} + +h2.title +{ + font-size: 150%; + font-style: normal; + font-weight: bold; + color: black; +} + +h3.title +{ + font-size: 125%; + font-style: normal; + font-weight: bold; + color: black; +} + +h4.title +{ + font-size: 100%; + font-style: normal; + font-weight: bold; + color: black; +} + +.toc b +{ + font-size: 125%; + font-style: normal; + font-weight: bold; + color: black; +} + +.command, .screen, .programlisting, .structname +{ + font-family: courier new,courier,fixed; + font-style: normal; + font-weight: normal; +} + +.filename +{ + font-family: arial,helvetica,sans-serif; + font-style: italic; +} + +.figure, .example, .table +{ + margin: 0.125in 0.25in; +} + +.table table +{ + border-width: 1px; + border-style: solid; + border-color: black; + border-spacing: 0; + background: rgb(240,240,240); +} + +.table td +{ + border: none; + border-right: 1px black solid; + border-bottom: 1px black solid; + padding: 2px; +} + +.table th +{ + background: rgb(180,180,180); + border: none; + border-right: 1px black solid; + border-bottom: 1px black solid; + padding: 2px; +} + +.table p.title, .figure p.title, .example p.title +{ + text-align: left !important; + font-size: 100% !important; +} + +.author, .pubdate +{ + margin: 0; + font-size: 100%; + font-style: italic; + font-weight: normal; + color: black; +} + +.preface div.author, .preface .pubdate +{ + font-size: 80%; +} + +.sidebar +{ + border-top: dotted 1px black; + border-left: dotted 1px black; + border-right: solid 2px black; + border-bottom: solid 2px black; + background: rgb(240,220,170); + padding: 0 0.12in; + margin: 0.25in; +} + +.note .programlisting, .note .screen, +.tip .programlisting, .tip .screen, +.warning .programlisting, .warning .screen, +.sidebar .programlisting, .sidebar .screen +{ + border: none; + background: none; +} + +.sidebar p.title +{ + text-align: center; + font-size: 125%; +} + +.note +{ + border: black solid 1px; + background: url(./images/note.png) no-repeat rgb(252,246,220); + margin: 0.125in 0; + padding: 0 55px; +} + +.tip +{ + border: black solid 1px; + background: url(./images/tip.png) no-repeat rgb(224,244,255); + margin: 0.125in 0; + padding: 0 55px; +} + +.warning +{ + border: black solid 1px; + background: url(./images/warning.png) no-repeat rgb(255,210,210); + margin: 0.125in 0; + padding: 0 55px; +} + +.note .title, .tip .title, .warning .title +{ + display: none; +} + +.programlisting, .screen +{ + font-size: 90%; + color: black; + margin: 1em 0.25in; + padding: 0.5em; + background: rgb(240,240,240); + border-top: black dotted 1px; + border-left: black dotted 1px; + border-right: black solid 2px; + border-bottom: black solid 2px; +} + +.navheader, .navfooter +{ + border: black solid 1px; + background: rgb(180,180,200); +} + +.navheader hr, .navfooter hr +{ + display: none; +} diff --git a/examples/WhatAQuietStiff.rb b/examples/WhatAQuietStiff.rb index 1d5f380..35b504c 100755 --- a/examples/WhatAQuietStiff.rb +++ b/examples/WhatAQuietStiff.rb @@ -11,7 +11,6 @@ # require 'fox16' -require 'fox16/kwargs' require 'open-uri' begin diff --git a/examples/babelfish.rb b/examples/babelfish.rb index 79527f7..81b4d2b 100755 --- a/examples/babelfish.rb +++ b/examples/babelfish.rb @@ -1,57 +1,41 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' -require 'soap/rpc/driver' +require 'tranexp' include Fox TRANSLATIONS = { - "English to French" => "en_fr", - "English to German" => "en_de", - "English to Italian" => "en_it", - "English to Japanese" => "en_jp", - "English to Korean" => "en_kr", - "English to Portugese" => "en_pt", - "English to Spanish" => "en_es", - "French to English" => "fr_en", - "German to English" => "de_en", - "Italian to English" => "it_en", - "Japanese to English" => "jp_en", - "Korean to English" => "kr_en", - "Portugese to English" => "pt_en", - "Spanish to English" => "es_en", - "Russian to English" => "ru_en", - "German to French" => "de_fr", - "French to German" => "fr_de" + "x" => "y" } class Babelfish < FXMainWindow def initialize(app) # Invoke base class initialize first - super(app, "Babelfish", nil, nil, DECOR_ALL, - 0, 0, 600, 400, 0, 0) - - # Initialize the SOAP driver - @drv = SOAP::RPC::Driver.new('http://services.xmethods.net/perl/soaplite.cgi', 'urn:xmethodsBabelFish') - @drv.add_rpc_method_with_soapaction('BabelFish', - 'urn:xmethodsBabelFish#BabelFish', 'translationmode', 'sourcedata') + super(app, "Babelfish", :opts => DECOR_ALL, :width => 600, :height => 400) + @translator = Tranexp::Http.new + # Controls area along the bottom controlsFrame = FXHorizontalFrame.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X) FXLabel.new(controlsFrame, "Translate from:") - @transModeCombo = FXComboBox.new(controlsFrame, 15, :opts => COMBOBOX_STATIC|FRAME_SUNKEN|FRAME_THICK) - @transModeCombo.numVisible = 6 - TRANSLATIONS.keys.each do |key| - @transModeCombo.appendItem(key, TRANSLATIONS[key]) + @fromCombo = FXComboBox.new(controlsFrame, 15, :opts => COMBOBOX_STATIC|FRAME_SUNKEN|FRAME_THICK) + @fromCombo.numVisible = 6 + FXLabel.new(controlsFrame, " to:") + @toCombo = FXComboBox.new(controlsFrame, 15, :opts => COMBOBOX_STATIC|FRAME_SUNKEN|FRAME_THICK) + @toCombo.numVisible = 6 + Tranexp::Codes.constants.each do |lang| + @fromCombo.appendItem(lang) + @toCombo.appendItem(lang) end - btn = FXButton.new(controlsFrame, "Translate", :opts => BUTTON_NORMAL|LAYOUT_SIDE_RIGHT) + btn = FXButton.new(controlsFrame, "Translate", :opts => BUTTON_NORMAL|LAYOUT_RIGHT) btn.connect(SEL_COMMAND) do - transMode = @transModeCombo.getItemData(@transModeCombo.currentItem) + from = @fromCombo.getItemText(@fromCombo.currentItem) + to = @toCombo.getItemText(@toCombo.currentItem) getApp().beginWaitCursor() do - @translatedText.text = @drv.BabelFish(transMode, @sourceText.text) + @translatedText.text = @translator.translate(@sourceText.text, from, to) end end @@ -80,15 +64,9 @@ class Babelfish < FXMainWindow end if __FILE__ == $0 - # Make application - application = FXApp.new("Babelfish", "FoxTest") - - # Make window - window = Babelfish.new(application) - - # Create it - application.create - - # Run - application.run + FXApp.new("Babelfish", "FoxTest") do |app| + Babelfish.new(app) + app.create + app.run + end end diff --git a/examples/bounce.rb b/examples/bounce.rb index 44cab45..f93cf95 100755 --- a/examples/bounce.rb +++ b/examples/bounce.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/button.rb b/examples/button.rb index 149d6ac..0da7e88 100755 --- a/examples/button.rb +++ b/examples/button.rb @@ -1,7 +1,6 @@ #/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/charts.rb b/examples/charts.rb new file mode 100644 index 0000000..dfb42d4 --- /dev/null +++ b/examples/charts.rb @@ -0,0 +1,35 @@ +require 'fox16' +require 'google_chart' +require 'open-uri' + +include Fox + +class ChartsWindow < FXMainWindow + def initialize(app) + super(app, "Google Charts Demo", :width => 650, :height => 250) + FXImageFrame.new(self, nil, :opts => LAYOUT_FILL) do |f| + f.image = FXPNGImage.new(app, open(bar_chart.to_escaped_url, "rb").read) + end + end + + def bar_chart + GoogleChart::BarChart.new('600x200', 'My Chart', :vertical) do |bc| + bc.data 'Trend 1', [5,4,3,1,3,5], '0000ff' + bc.data 'Trend 2', [1,2,3,4,5,6], 'ff0000' + bc.data 'Trend 3', [6,5,4,4,5,6], '00ff00' + end + end + + def create + super + show(PLACEMENT_SCREEN) + end +end + +if __FILE__ == $0 + FXApp.new do |app| + ChartsWindow.new(app) + app.create + app.run + end +end \ No newline at end of file diff --git a/examples/custom_table_item.rb b/examples/custom_table_item.rb new file mode 100644 index 0000000..acbf7cb --- /dev/null +++ b/examples/custom_table_item.rb @@ -0,0 +1,170 @@ +require 'fox16' + +include Fox + +class CustomTableItem < FXTableItem + def drawContent(table, dc, x, y, w, h) + puts "in drawContent()" + hg = table.horizontalGridShown? + vg = table.verticalGridShown? + ml = table.marginLeft + (vg ? 1 : 0) + mt = table.marginTop + (hg ? 1 : 0) + mr = table.marginRight + mb = table.marginBottom + font = dc.font + lbl = text + icn = icon + + # Text width and height + beg, tw, th = 0, 0, 0 + begin + _end = beg; + _end += 1 while _end < lbl.length && lbl[_end].chr != '\n' + t = font.getTextWidth(lbl[beg..._end]) + tw = t if t > tw + th += font.fontHeight + beg = _end + 1 + end while _end < lbl.length + + # Icon size + iw, ih = 0, 0 + unless icn.nil? + iw = icn.width + ih = icn.height + end + + # Icon-text spacing + s = 0 + s = 4 if (iw > 0 && tw > 0) + + # Fix x coordinate + if justify & LEFT == 1 + case iconPosition + when BEFORE + ix = x + ml + tx = ix + iw + s + when AFTER + tx = x + ml + ix = tx + tw + s + else + ix = x + ml + tx = x + ml + end + elsif justify & RIGHT == 1 + case iconPosition + when BEFORE + tx = x + w - mr - tw + ix = tx - iw - s + when AFTER + ix = x + w - mr - iw + tx = ix - tw - s + else + ix = x + w - mr - iw + tx = x + w - mr - tw + end + else + case iconPosition + when BEFORE + ix = x + (ml + w - mr)/2 - (tw + iw + s)/2 + tx = ix + iw + s + when AFTER + tx = x + (ml + w - mr)/2 - (tw + iw + s)/2 + ix = tx + tw + s + else + ix = x + (ml + w - mr)/2 - iw/2 + tx = x + (ml + w - mr)/2 -tw/2 + end + end + + # Fix y coordinate + if justify & TOP == 1 + case iconPosition + when ABOVE + iy = y + mt + ty = iy + ih + when BELOW + ty = y + mt + iy = ty + th + else + iy = y + mt + ty = y + mt + end + elsif justify & BOTTOM == 1 + case iconPosition + when ABOVE + ty = y + h - mb - th + iy = ty - ih + when BELOW + iy = y + h - mb - ih + ty = iy - th + else + iy = y + h - mb - ih + ty = y + h - mb - th + end + else + case iconPosition + when ABOVE + iy = y + (mt + h - mb)/2 - (th + ih)/2 + ty = iy + ih + when BELOW + ty = y + (mt + h - mb)/2 - (th + ih)/2 + iy = ty + th + else + iy = y + (mt + h - mb)/2 - ih/2 + ty = y + (mt + h - mb)/2 - th/2 + end + end + + # Paint icon + dc.drawIcon(icn, ix, iy) unless icn.nil? + + # Text color + if selected? + dc.foreground = table.selTextColor + else + dc.foreground = table.textColor + end + puts "dc.foreground = (#{FXREDVAL(dc.foreground)}, #{FXGREENVAL(dc.foreground)}, #{FXBLUEVAL(dc.foreground)})" + + # Draw text + yy = ty + font.fontAscent + beg = 0 + begin + _end = beg + _end += 1 while _end < lbl.length && lbl[_end].chr != '\n' + if justify & LEFT == 1 + xx = tx + elsif justify & RIGHT == 1 + xx = tx + tw - font.getTextWidth(lbl[beg..._end]) + else + xx = tx + (tw - font.getTextWidth(lbl[beg..._end]))/2 + end + dc.drawText(xx, yy, lbl[beg..._end]) + yy += font.fontHeight + beg = _end + 1 + end while _end < lbl.length + end +end + +class CustomTable < FXTable + def createItem *parameters + CustomTableItem.new *parameters + end +end + +app = FXApp.new +main = FXMainWindow.new app, 'Test' + +table = CustomTable.new main +table.setTableSize 2, 2 +table.visibleRows = 2 +table.visibleColumns = 2 + +table.setItemText 0, 0, 'one' +table.setItemText 0, 1, 'two' +table.setItemText 1, 0, 'three' +table.setItemText 1, 1, 'four' + +app.create +main.show PLACEMENT_SCREEN +app.run diff --git a/examples/datatarget.rb b/examples/datatarget.rb index b49f509..816ce42 100755 --- a/examples/datatarget.rb +++ b/examples/datatarget.rb @@ -2,7 +2,6 @@ require 'fox16' require 'fox16/colors' -require 'fox16/kwargs' include Fox diff --git a/examples/dialog.rb b/examples/dialog.rb index 33e841e..c352c0d 100755 --- a/examples/dialog.rb +++ b/examples/dialog.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/dilbert.rb b/examples/dilbert.rb index aafd5ac..955c6be 100755 --- a/examples/dilbert.rb +++ b/examples/dilbert.rb @@ -1,16 +1,15 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' require 'open-uri' begin - require 'rubyful_soup' + require 'hpricot' rescue LoadError require 'fox16/missingdep' MSG = <<EOM - Sorry, this example depends on the RubyfulSoup extension. Please - check the Ruby Application Archives for an appropriate - download site. + Sorry, this example depends on the Hpricot extension. Please + see http://code.whytheluckystiff.net/hpricot/ for instructions + on how to install Hpricot. EOM missingDependency(MSG) end @@ -41,9 +40,8 @@ class DailyDilbert < FXMainWindow end def image_data - src = open("http://www.dilbert.com/").read - soup = BeautifulSoup.new(src) - url = soup.find('img', { :attrs => { 'alt' => /Today's Comic/ } }) + doc = Hpricot(open("http://www.dilbert.com/")) + url = doc.search("img").find { |e| e['src'] =~ /\/dyn\/str_strip\/.*\.gif/ } open("http://www.dilbert.com" + url['src'], "rb").read end diff --git a/examples/dirlist.rb b/examples/dirlist.rb index d8871df..3c7f38f 100755 --- a/examples/dirlist.rb +++ b/examples/dirlist.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/dragdrop.rb b/examples/dragdrop.rb index fb664b7..08f0d60 100755 --- a/examples/dragdrop.rb +++ b/examples/dragdrop.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/dragsource.rb b/examples/dragsource.rb index a1c54aa..f7406b0 100755 --- a/examples/dragsource.rb +++ b/examples/dragsource.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/dropsite.rb b/examples/dropsite.rb index 070ca0d..fd2ba48 100755 --- a/examples/dropsite.rb +++ b/examples/dropsite.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox @@ -7,7 +6,7 @@ class DropSite < FXMainWindow def initialize(anApp) # Initialize base class - super(anApp, "Drop Site",:opts => DECOR_ALL, :width => 400, :height => 300) + super(anApp, "Drop Site", :opts => DECOR_ALL, :width => 400, :height => 300) # Fill main window with canvas @canvas = FXCanvas.new(self, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y) diff --git a/examples/foursplit.rb b/examples/foursplit.rb index 80fbd73..3761c05 100755 --- a/examples/foursplit.rb +++ b/examples/foursplit.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/gdchart.rb b/examples/gdchart.rb index 1be7a1b..5375826 100755 --- a/examples/gdchart.rb +++ b/examples/gdchart.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' require 'tempfile' begin require 'GDChart' diff --git a/examples/gembrowser.rb b/examples/gembrowser.rb index 14a61f4..04d9fef 100755 --- a/examples/gembrowser.rb +++ b/examples/gembrowser.rb @@ -180,7 +180,7 @@ class GemBrowserWindow < FXMainWindow super(anApp, "Gem Browser", nil, nil, DECOR_ALL) # Menu bar - menubar = FXMenubar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) + menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X) # File menu filemenu = FXMenuPane.new(self) diff --git a/examples/gltest.rb b/examples/gltest.rb index d36ff5d..7333c90 100755 --- a/examples/gltest.rb +++ b/examples/gltest.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' begin require 'opengl' rescue LoadError @@ -22,26 +21,6 @@ class GLTestWindow < FXMainWindow # How often our timer will fire (in milliseconds) TIMER_INTERVAL = 100 - # Rotate the boxes when a timer message is received - def onTimeout(sender, sel, ptr) - @angle += 2.0 - if @angle > 360.0 - @angle -= 360.0 - end - drawScene() - @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout)) - end - - # Rotate the boxes when a chore message is received - def onChore(sender, sel, ptr) - @angle += 2.0 - if @angle > 360.0 - @angle -= 360.0 - end - drawScene() - @chore = getApp().addChore(method(:onChore)) - end - # Draws a simple box using the given corners def drawBox(xmin, ymin, zmin, xmax, ymax, zmax) GL.Begin(GL::TRIANGLE_STRIP) @@ -251,7 +230,13 @@ class GLTestWindow < FXMainWindow spinTimerBtn.padTop, spinTimerBtn.padBottom = 5, 5 spinTimerBtn.connect(SEL_COMMAND) do @spinning = true - @timer = getApp().addTimeout(TIMER_INTERVAL, method(:onTimeout)) + @timer = getApp().addTimeout(TIMER_INTERVAL, :repeat => true) do + @angle += 2.0 + if @angle > 360.0 + @angle -= 360.0 + end + drawScene() + end end spinTimerBtn.connect(SEL_UPDATE) do |sender, sel, ptr| @spinning ? sender.disable : sender.enable @@ -266,7 +251,13 @@ class GLTestWindow < FXMainWindow spinChoreBtn.padTop, spinChoreBtn.padBottom = 5, 5 spinChoreBtn.connect(SEL_COMMAND) do @spinning = true - @chore = getApp().addChore(method(:onChore)) + @chore = getApp().addChore(:repeat => true) do + @angle += 2.0 + if @angle > 360.0 + @angle -= 360.0 + end + drawScene() + end end spinChoreBtn.connect(SEL_UPDATE) do |sender, sel, ptr| @spinning ? sender.disable : sender.enable diff --git a/examples/glviewer.rb b/examples/glviewer.rb index c2f0ebf..6a4c28a 100755 --- a/examples/glviewer.rb +++ b/examples/glviewer.rb @@ -2,7 +2,6 @@ require 'fox16' require 'fox16/responder' -require 'fox16/kwargs' begin require 'fox16/glshapes' rescue LoadError diff --git a/examples/groupbox.rb b/examples/groupbox.rb index b25beb3..f988521 100755 --- a/examples/groupbox.rb +++ b/examples/groupbox.rb @@ -22,7 +22,7 @@ class GroupWindow < FXMainWindow def initialize(app) # Call the base class version of initialize - super(app, "Group Box Test", nil, nil, DECOR_ALL, 0, 0, 0, 0) + super(app, "Group Box Test", :opts => DECOR_ALL) # Some icons we'll use here and there doc = getIcon("minidoc.png") @@ -102,8 +102,7 @@ class GroupWindow < FXMainWindow FXMenuTitle.new(menubar, "&Help", nil, helpmenu, LAYOUT_RIGHT) @popupmenu = FXMenuPane.new(self) - poptext = FXTextField.new(@popupmenu, 10, nil, 0, - FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP, 0, 0, 0, 0) + poptext = FXTextField.new(@popupmenu, 10, :opts => FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP) poptext.setText("Popup with text") # Status bar @@ -129,8 +128,7 @@ class GroupWindow < FXMainWindow 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", 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", @@ -138,94 +136,66 @@ class GroupWindow < FXMainWindow ICON_BEFORE_TEXT|JUSTIFY_LEFT|FRAME_RAISED|FRAME_THICK) pop = FXPopup.new(self) - - FXOption.new(pop, "First\tTip #1\tHelp first", nil, nil, 0, - JUSTIFY_HZ_APART|ICON_AFTER_TEXT).connect(SEL_COMMAND) { - FXMessageBox.information(self, MBOX_OK, "Option Menu", "Chose option 1") - } - FXOption.new(pop, "Second\tTip #2\tHelp second", nil, nil, 0, - JUSTIFY_HZ_APART|ICON_AFTER_TEXT).connect(SEL_COMMAND) { - FXMessageBox.information(self, MBOX_OK, "Option Menu", "Chose option 2") - } - FXOption.new(pop, "Third\tTip #3\tHelp third", nil, nil, 0, - JUSTIFY_HZ_APART|ICON_AFTER_TEXT).connect(SEL_COMMAND) { - FXMessageBox.information(self, MBOX_OK, "Option Menu", "Chose option 3") - } - FXOption.new(pop, "Fourth\tTip #4\tHelp fourth", nil, nil, 0, - JUSTIFY_HZ_APART|ICON_AFTER_TEXT).connect(SEL_COMMAND) { - FXMessageBox.information(self, MBOX_OK, "Option Menu", "Chose option 4") - } + 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", nil, - nil, 0,LAYOUT_TOP|FRAME_RAISED|FRAME_THICK) - FXButton.new(group1, "Te&kstje", nil, nil, 0, - LAYOUT_TOP|FRAME_RAISED|FRAME_THICK).connect(SEL_COMMAND) { + "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", nil, filemenu, - (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) + 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", nil, nil, 0, - FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 30, 30) - FXButton.new(coolpop, "B\tTipB", nil, nil, 0, - FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 30, 30) - FXButton.new(coolpop, "C\tTipC", nil, nil, 0, - FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 30, 30) - FXButton.new(coolpop, "D\tTipD", nil, nil, 0, - FRAME_THICK|FRAME_RAISED|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 30, 30) + 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), 0, 0, 30, 30) + 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", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW) - FXButton.new(matrix, "&Wide button", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X) - FXButton.new(matrix, "A", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X) + 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", nil, nil, 0, (FRAME_RAISED|FRAME_THICK| - LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW|LAYOUT_FILL_COLUMN)) - FXButton.new(matrix, "B", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN) - FXButton.new(matrix, "BB", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN) + 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", nil, nil, 0, - FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y|LAYOUT_CENTER_X|LAYOUT_FILL_ROW) - FXButton.new(matrix, "&wide", nil, nil, 0, FRAME_RAISED|FRAME_THICK) - FXButton.new(matrix, "CC", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT) + 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, nil, 0, - LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL, - 0, 0, 200, 30) + 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, nil, 0, (LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT| - SLIDER_HORIZONTAL|SLIDER_ARROW_UP), 0, 0, 200, 30) + 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, nil, 0, (LAYOUT_TOP|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT| - SLIDER_HORIZONTAL|SLIDER_ARROW_DOWN), 0, 0, 200, 30) + 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, nil, 0, (LAYOUT_TOP|LAYOUT_FILL_X| - LAYOUT_FIX_HEIGHT|SLIDER_HORIZONTAL|SLIDER_INSIDE_BAR), 0, 0, 200, 20) + 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) @@ -252,8 +222,7 @@ class GroupWindow < FXMainWindow 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, nil, 0, (LAYOUT_FILL_X|LAYOUT_FILL_Y| - FRAME_RAISED|FRAME_THICK|ARROW_UP|ARROW_TOOLBAR)) + 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| diff --git a/examples/header.rb b/examples/header.rb index aaf64f2..7f44807 100755 --- a/examples/header.rb +++ b/examples/header.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/iconlist.rb b/examples/iconlist.rb index 6dc8622..399ba95 100755 --- a/examples/iconlist.rb +++ b/examples/iconlist.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/image.rb b/examples/image.rb index a6a38e8..4401036 100755 --- a/examples/image.rb +++ b/examples/image.rb @@ -2,7 +2,6 @@ require 'fox16' require 'fox16/colors' -require 'fox16/kwargs' include Fox diff --git a/examples/imageviewer.rb b/examples/imageviewer.rb index 3a062d3..27d2319 100755 --- a/examples/imageviewer.rb +++ b/examples/imageviewer.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox @@ -87,7 +86,7 @@ class ImageWindow < FXMainWindow # 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) + :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)) diff --git a/examples/inputs.rb b/examples/inputs.rb index e00dde6..7657625 100755 --- a/examples/inputs.rb +++ b/examples/inputs.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox @@ -55,7 +54,7 @@ class InputHandlerWindow < FXMainWindow getApp().addInput(@pipe, INPUT_READ|INPUT_EXCEPT) do |sender, sel, ptr| case FXSELTYPE(sel) when SEL_IO_READ - text = @pipe.read + text = @pipe.read_nonblock(256) if text && text.length > 0 @cmdOutput.appendText(text) else diff --git a/examples/mditest.rb b/examples/mditest.rb index e311104..0899a78 100755 --- a/examples/mditest.rb +++ b/examples/mditest.rb @@ -2,7 +2,6 @@ require 'fox16' require 'fox16/colors' -require 'fox16/kwargs' include Fox diff --git a/examples/pig.rb b/examples/pig.rb index 784238d..2eadc9b 100755 --- a/examples/pig.rb +++ b/examples/pig.rb @@ -5,7 +5,6 @@ # require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/raabrowser.rb b/examples/raabrowser.rb index 7997a6c..ec3ba2a 100755 --- a/examples/raabrowser.rb +++ b/examples/raabrowser.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' require 'cgi' require 'soap/wsdlDriver' diff --git a/examples/ratio.rb b/examples/ratio.rb index be0eb46..6bca0b3 100644 --- a/examples/ratio.rb +++ b/examples/ratio.rb @@ -6,7 +6,6 @@ require 'fox16' require 'fox16/colors' -require 'fox16/kwargs' include Fox diff --git a/examples/rmagick.rb b/examples/rmagick.rb new file mode 100755 index 0000000..7632d2a --- /dev/null +++ b/examples/rmagick.rb @@ -0,0 +1,44 @@ +require 'fox16' +require 'RMagick' + +include Fox + +class RMagickExample < FXMainWindow + + def initialize(app) + super(app, "RMagick Example", :width => 800, :height => 600) + + # Construct an ImageList + dippy = Magick::ImageList.new(File.join("icons", "dippy.png")) + + # Manipulate the image + text = Magick::Draw.new + text.annotate(dippy, 0, 0, 0, 60, "Dippy Duck") do + self.gravity = Magick::SouthGravity + self.pointsize = 24 + self.stroke = 'transparent' + self.fill = '#0000A9' + self.font_weight = Magick::BoldWeight + end + + # Extract image data and use it to construct FXPNGImage + dippy_image = FXPNGImage.new(app, dippy.to_blob) + + # Display it inside an FXImageFrame + FXImageFrame.new(self, dippy_image, :opts => LAYOUT_FILL) + end + + def create + super + show(PLACEMENT_SCREEN) + end + +end + +if __FILE__ == $0 + FXApp.new("RMagick Example", "FXRuby") do |app| + RMagickExample.new(app) + app.create + app.run + end +end \ No newline at end of file diff --git a/examples/rulerview.rb b/examples/rulerview.rb index b636d27..187d674 100644 --- a/examples/rulerview.rb +++ b/examples/rulerview.rb @@ -1,5 +1,4 @@ require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/scribble.rb b/examples/scribble.rb index 52e431f..343e605 100755 --- a/examples/scribble.rb +++ b/examples/scribble.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/shutter.rb b/examples/shutter.rb index ff9af72..aefbac4 100755 --- a/examples/shutter.rb +++ b/examples/shutter.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/splitter.rb b/examples/splitter.rb index 10015d6..f067e52 100755 --- a/examples/splitter.rb +++ b/examples/splitter.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/styledtext.rb b/examples/styledtext.rb index 9c7ee53..a0808b8 100755 --- a/examples/styledtext.rb +++ b/examples/styledtext.rb @@ -40,24 +40,14 @@ class StyledTextWindow < FXMainWindow TEXT_READONLY|TEXT_WORDWRAP|LAYOUT_FILL_X|LAYOUT_FILL_Y) # Construct some hilite styles - hs1 = FXHiliteStyle.new + hs1 = FXHiliteStyle.from_text(text) hs1.normalForeColor = FXColor::Red hs1.normalBackColor = FXColor::Blue - hs1.selectForeColor = text.selTextColor - hs1.selectBackColor = text.selBackColor - hs1.hiliteForeColor = text.hiliteTextColor - hs1.hiliteBackColor = text.hiliteBackColor - hs1.activeBackColor = text.activeBackColor - hs1.style = 0 + hs1.style = FXText::STYLE_BOLD - hs2 = FXHiliteStyle.new + hs2 = FXHiliteStyle.from_text(text) hs2.normalForeColor = FXColor::Blue hs2.normalBackColor = FXColor::Yellow - hs2.selectForeColor = text.selTextColor - hs2.selectBackColor = text.selBackColor - hs2.hiliteForeColor = text.hiliteTextColor - hs2.hiliteBackColor = text.hiliteBackColor - hs2.activeBackColor = text.activeBackColor hs2.style = FXText::STYLE_UNDERLINE # Enable the style buffer for this text widget diff --git a/examples/tabbook.rb b/examples/tabbook.rb index 20517fc..ea6bbe3 100755 --- a/examples/tabbook.rb +++ b/examples/tabbook.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' include Fox diff --git a/examples/table.rb b/examples/table.rb index 78cc30c..c98f1da 100755 --- a/examples/table.rb +++ b/examples/table.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby require 'fox16' -require 'fox16/kwargs' require 'date' include Fox diff --git a/ext/fox16/FXRbApp.cpp b/ext/fox16/FXRbApp.cpp index e819ba6..ba78205 100755 --- a/ext/fox16/FXRbApp.cpp +++ b/ext/fox16/FXRbApp.cpp @@ -21,14 +21,16 @@ ***********************************************************************/ /*********************************************************************** - * $Id: FXRbApp.cpp 2190 2005-08-24 07:58:47Z lyle $ + * $Id: FXRbApp.cpp 2902 2008-12-11 14:09:20Z lyle $ ***********************************************************************/ #include "FXRbCommon.h" +#ifndef RUBY_1_9 extern "C" { #include "rubysig.h" /* For CHECK_INTS */ } +#endif #ifdef HAVE_SYS_TIME_H #include <sys/time.h> /* For struct timeval */ @@ -95,9 +97,14 @@ long FXRbApp::onChoreThreads(FXObject*,FXSelector,void*){ wait.tv_usec=100*sleepTime; // Confirm that this thread can be interrupted, then go to sleep +#ifndef RUBY_1_9 CHECK_INTS; if(!rb_thread_critical) rb_thread_wait_for(wait); +#else + // if(!rb_thread_critical) rb_thread_wait_for(wait); + rb_thread_wait_for(wait); +#endif /* RUBY_1_9 */ // Re-register this chore for next time addChore(this,ID_CHORE_THREADS); diff --git a/ext/fox16/FXRbDataTarget.cpp b/ext/fox16/FXRbDataTarget.cpp index 0880313..d388c9b 100755 --- a/ext/fox16/FXRbDataTarget.cpp +++ b/ext/fox16/FXRbDataTarget.cpp @@ -21,7 +21,7 @@ ***********************************************************************/ /*********************************************************************** - * $Id: FXRbDataTarget.cpp 2190 2005-08-24 07:58:47Z lyle $ + * $Id: FXRbDataTarget.cpp 2713 2007-11-14 15:27:36Z lyle $ ***********************************************************************/ #include "FXRbCommon.h" @@ -57,7 +57,7 @@ void FXRbDataTarget::setValue(VALUE value){ connect(doubleValue); break; case T_STRING: - stringValue=STR2CSTR(value); + stringValue=StringValuePtr(value); connect(stringValue); break; case T_TRUE: diff --git a/ext/fox16/FXRuby.cpp b/ext/fox16/FXRuby.cpp index 81f4d72..650418c 100755 --- a/ext/fox16/FXRuby.cpp +++ b/ext/fox16/FXRuby.cpp @@ -21,7 +21,7 @@ ***********************************************************************/ /*********************************************************************** - * $Id: FXRuby.cpp 2608 2007-02-09 20:34:16Z lyle $ + * $Id: FXRuby.cpp 2933 2008-12-29 20:19:33Z lyle $ ***********************************************************************/ #ifdef _MSC_VER @@ -30,16 +30,18 @@ #include "FXRbCommon.h" +#ifndef RUBY_1_9 #include "version.h" #if RUBY_VERSION_CODE < 167 #define RB_RESCUE2_BROKEN_PROTOTYPE 1 #endif -/* The prototype for st_foreach() changed at Ruby version 1.8.2 */ +// The prototype for st_foreach() changed at Ruby version 1.8.2 #if RUBY_VERSION_CODE < 182 #define ST_BROKEN_PROTOTYPES 1 #endif +#endif /* RUBY_1_9 */ #include "impl.h" @@ -51,15 +53,19 @@ #include <signal.h> // for definitions of SIGINT, etc. #endif +#ifndef RUBY_1_9 extern "C" { #include "rubyio.h" // for GetOpenFile(), etc. } +#else +#include "ruby/io.h" +#endif // Symbol table functions from Ruby. If we included "st.h" directly // we'd be dealing with broken prototypes anyways, so just duplicate // the needed declarations here with the correct prototypes. -#ifdef ST_BROKEN_PROTOTYPES +#if defined(ST_BROKEN_PROTOTYPES) extern "C" { @@ -78,11 +84,19 @@ void st_foreach(st_table *table, int (*func)(st_data_t, st_data_t, st_data_t), s #else +#ifdef RUBY_1_9 + +#include "ruby/st.h" + +#else + extern "C" { #include "st.h" } -#endif +#endif /* RUBY_1_9 */ + +#endif /* ST_BROKEN_PROTOTYPES */ // Opaque type declaration from SWIG runtime struct swig_type_info; @@ -136,13 +150,11 @@ VALUE FXRbNewPointerObj(void *ptr,swig_type_info* ty){ FXASSERT(ty!=0); VALUE obj; FXRubyObjDesc *desc; - int result; if(FXMALLOC(&desc,FXRubyObjDesc,1)){ obj=SWIG_Ruby_NewPointerObj(ptr,ty,1); desc->obj=obj; desc->borrowed=true; - result=st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t>(desc)); - FXASSERT(result==0); + st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t>(desc)); return obj; } else{ @@ -189,9 +201,15 @@ FXbool FXRbCatchExceptions=FALSE; // Returns an FXInputHandle for this Ruby file object FXInputHandle FXRbGetReadFileHandle(VALUE obj) { +#ifdef RUBY_1_9 + rb_io_t *fptr; + GetOpenFile(obj, fptr); + FILE *fpr=fptr->stdio_file; +#else OpenFile *fptr; GetOpenFile(obj, fptr); FILE *fpr=GetReadFile(fptr); +#endif /* RUBY_1_9 */ #ifdef WIN32 #ifdef __CYGWIN__ return (FXInputHandle) get_osfhandle(fileno(fpr)); @@ -206,9 +224,15 @@ FXInputHandle FXRbGetReadFileHandle(VALUE obj) { // Returns an FXInputHandle for this Ruby file object FXInputHandle FXRbGetWriteFileHandle(VALUE obj) { +#ifdef RUBY_1_9 + rb_io_t *fptr; + GetOpenFile(obj, fptr); + FILE *fpw=fptr->stdio_file; +#else OpenFile *fptr; GetOpenFile(obj, fptr); FILE *fpw=GetWriteFile(fptr); +#endif /* RUBY_1_9 */ #ifdef WIN32 #ifdef __CYGWIN__ return (FXInputHandle) get_osfhandle(fileno(fpw)); @@ -226,7 +250,7 @@ void FXRbRegisterRubyObj(VALUE rubyObj,const void* foxObj) { FXASSERT(!NIL_P(rubyObj)); FXASSERT(foxObj!=0); FXRubyObjDesc* desc; - FXTRACE((1,"FXRbRegisterRubyObj(rubyObj=%d,foxObj=0x%08x)\n",rubyObj,foxObj)); + FXTRACE((1,"FXRbRegisterRubyObj(rubyObj=%d,foxObj=%p)\n",static_cast<int>(rubyObj),foxObj)); if(FXMALLOC(&desc,FXRubyObjDesc,1)){ desc->obj=rubyObj; desc->borrowed=false; @@ -527,6 +551,9 @@ static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector s else if(sender->isMemberOf(FXMETACLASS(FXArrowButton))){ if(type==SEL_COMMAND) return to_ruby(static_cast<FXuint>(reinterpret_cast<FXuval>(ptr))); } + else if(sender->isMemberOf(FXMETACLASS(FXPicker))){ + if(type==SEL_COMMAND || type==SEL_CHANGED) return to_ruby(reinterpret_cast<FXPoint*>(ptr)); + } else if(sender->isMemberOf(FXMETACLASS(FXButton))){ if(type==SEL_CLICKED || type==SEL_DOUBLECLICKED || @@ -560,9 +587,7 @@ static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector s type==SEL_CLICKED || type==SEL_DOUBLECLICKED || type==SEL_TRIPLECLICKED) { - fprintf(stderr,"ptr=0x%08x\n",ptr); VALUE v=to_ruby(static_cast<FXColor>(reinterpret_cast<unsigned long>(ptr))); - fprintf(stderr,"v=%d\n",v); return v; } } @@ -654,7 +679,7 @@ static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector s type==SEL_SELECTED || type==SEL_DESELECTED){ VALUE ary=rb_ary_new(); - FXGLObject** objlist=reinterpret_cast<FXGLObject**>(ptr); + // FXGLObject** objlist=reinterpret_cast<FXGLObject**>(ptr); // FIXME: objlist is a NULL-terminated array of pointers to FXGLObject return ary; } @@ -736,9 +761,6 @@ static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector s else if(sender->isMemberOf(FXMETACLASS(FXOptionMenu))){ if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr))); } - else if(sender->isMemberOf(FXMETACLASS(FXPicker))){ - if(type==SEL_COMMAND || type==SEL_CHANGED) return to_ruby(reinterpret_cast<FXPoint*>(ptr)); - } else if(sender->isMemberOf(FXMETACLASS(FXRadioButton))){ if(type==SEL_COMMAND) return to_ruby(static_cast<FXuchar>(reinterpret_cast<FXuval>(ptr))); } @@ -901,7 +923,6 @@ static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector s * the appropriate C++ objects. That's what this function is for. */ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ - FXEvent* ev; void *ptr; static FXint intValue; static FXint intRange[2]; @@ -985,7 +1006,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ case SEL_QUERY_HELP: return NULL; case SEL_VERIFY: - return reinterpret_cast<void*>(STR2CSTR(value)); + return reinterpret_cast<void*>(StringValuePtr(value)); case SEL_CLICKED: case SEL_DOUBLECLICKED: case SEL_TRIPLECLICKED: @@ -1004,10 +1025,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ /* Ignore */ break; } - if(type==SEL_DRAGGED){ - SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1); - return ptr; - } + if(type==SEL_COMMAND){ // Handle FXText-specific messages if(obj->isMemberOf(FXMETACLASS(FXText))){ @@ -1025,7 +1043,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ if(obj->isMemberOf(FXMETACLASS(FXTextField))){ switch(id){ case FXTextField::ID_INSERT_STRING: - return reinterpret_cast<void*>(STR2CSTR(value));; + return reinterpret_cast<void*>(StringValuePtr(value));; default: break; } @@ -1094,14 +1112,14 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ obj->isMemberOf(FXMETACLASS(FXDirList)) || obj->isMemberOf(FXMETACLASS(FXDriveBox)) || obj->isMemberOf(FXMETACLASS(FXFileList))){ - return reinterpret_cast<void*>(STR2CSTR(value)); + return reinterpret_cast<void*>(StringValuePtr(value)); } else if(obj->isMemberOf(FXMETACLASS(FXMenuCheck))){ return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0)); } else if(obj->isMemberOf(FXMETACLASS(FXMenuRadio))){ return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0)); - } + } else if(obj->isMemberOf(FXMETACLASS(FXMenuCommand))){ return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0)); } @@ -1122,7 +1140,7 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ realValue=NUM2DBL(value); return reinterpret_cast<void*>(&realValue); case FXWindow::ID_SETSTRINGVALUE: - stringValue=FXString(STR2CSTR(value)); + stringValue=FXString(StringValuePtr(value)); return reinterpret_cast<void*>(&stringValue); case FXWindow::ID_SETINTRANGE: intRange[0]=NUM2INT(rb_ary_entry(value,0)); @@ -1144,6 +1162,20 @@ void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){ } } } + + if(type==SEL_CHANGED){ + if(obj->isMemberOf(FXMETACLASS(FXPicker))){ + SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXPoint *"),1); + return ptr; + } + return 0; + } + + if(type==SEL_DRAGGED){ + SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1); + return ptr; + } + // Pass through as-is return reinterpret_cast<void*>(value); } @@ -1159,7 +1191,7 @@ static ID id_assocs; * message. */ ID FXRbLookupHandler(FXObject* recv,FXSelector key){ - FXTRACE((100,"FXRbLookupHandler(recv=0x%08x(%s),FXSEL(%d,%d))\n",recv,recv->getClassName(),FXSELTYPE(key),FXSELID(key))); + FXTRACE((100,"FXRbLookupHandler(recv=%p(%s),FXSEL(%d,%d))\n",recv,recv->getClassName(),FXSELTYPE(key),FXSELID(key))); ID id=0; VALUE rubyObj=to_ruby(recv); FXASSERT((recv==0 && rubyObj==Qnil) || (recv!=0 && rubyObj!=Qnil)); @@ -1167,7 +1199,7 @@ ID FXRbLookupHandler(FXObject* recv,FXSelector key){ VALUE assocs=rb_ivar_get(rubyObj,id_assocs); VALUE entry; FXSelector keylo,keyhi; - for(long i=0;i<RARRAY(assocs)->len;i++){ + for(long i=0;i<RARRAY_LEN(assocs);i++){ entry=rb_ary_entry(assocs,i); keylo=NUM2UINT(rb_ary_entry(entry,0)); keyhi=NUM2UINT(rb_ary_entry(entry,1)); @@ -1205,14 +1237,14 @@ static ID id_backtrace; static VALUE handle_rescue(VALUE args,VALUE error){ VALUE info=rb_gv_get("$!"); VALUE errat=rb_funcall(info,id_backtrace,0); - VALUE mesg=RARRAY(errat)->ptr[0]; + VALUE mesg=RARRAY_PTR(errat)[0]; fprintf(stderr,"%s: %s (%s)\n", - STR2CSTR(mesg), - STR2CSTR(rb_obj_as_string(info)), + StringValuePtr(mesg), + RSTRING_PTR(rb_obj_as_string(info)), rb_class2name(CLASS_OF(info))); - for(int i=1;i<RARRAY(errat)->len;i++){ - if(TYPE(RARRAY(errat)->ptr[i])==T_STRING){ - fprintf(stderr,"\tfrom %s\n",STR2CSTR(RARRAY(errat)->ptr[i])); + for(int i=1;i<RARRAY_LEN(errat);i++){ + if(TYPE(RARRAY_PTR(errat)[i])==T_STRING){ + fprintf(stderr,"\tfrom %s\n",StringValuePtr(RARRAY_PTR(errat)[i])); } } return Qnil; @@ -1230,7 +1262,7 @@ long FXRbHandleMessage(FXObject* recv,ID func,FXObject* sender,FXSelector key,vo hArgs.nargs=3; VALUE retval; - FXTRACE((100,"FXRbHandleMessage(recv=0x%08x(%s),FXSEL(%s,%d)\n",recv,recv->getClassName(),FXDebugTarget::messageTypeName[FXSELTYPE(key)],FXSELID(key))); + FXTRACE((100,"FXRbHandleMessage(recv=%p(%s),FXSEL(%s,%d)\n",recv,recv->getClassName(),FXDebugTarget::messageTypeName[FXSELTYPE(key)],FXSELID(key))); if(FXRbCatchExceptions){ #ifdef RB_RESCUE2_BROKEN_PROTOTYPE @@ -1380,11 +1412,11 @@ FXGLObject** FXRbCallGLObjectArrayMethod(FXGLViewer* recv,ID func,FXint x,FXint VALUE result=rb_funcall(obj,func,4,INT2NUM(x),INT2NUM(y),INT2NUM(w),INT2NUM(h)); if(!NIL_P(result)){ Check_Type(result,T_ARRAY); - if(FXMALLOC(&objects,FXGLObject*,RARRAY(result)->len+1)){ - for(long i=0; i<RARRAY(result)->len; i++){ + if(FXMALLOC(&objects,FXGLObject*,RARRAY_LEN(result)+1)){ + for(long i=0; i<RARRAY_LEN(result); i++){ objects[i]=reinterpret_cast<FXGLObject*>(DATA_PTR(rb_ary_entry(result,i))); } - objects[RARRAY(result)->len]=0; + objects[RARRAY_LEN(result)]=0; } } return objects; // caller must free this @@ -1439,8 +1471,13 @@ FXFileAssoc* FXRbCallFileAssocMethod(const FXFileDict* recv,ID func,const char* FXIcon* FXRbCallIconMethod(const FXTableItem* recv,ID func){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); - VALUE result=rb_funcall(obj,func,0,NULL); - return NIL_P(result) ? 0 : reinterpret_cast<FXIcon*>(DATA_PTR(result)); + if(!NIL_P(obj)){ + VALUE result=rb_funcall(obj,func,0,NULL); + return NIL_P(result) ? 0 : reinterpret_cast<FXIcon*>(DATA_PTR(result)); + } + else{ + return 0; + } } //---------------------------------------------------------------------- @@ -1469,7 +1506,7 @@ FXString FXRbCallStringMethod(const FXObject* recv, ID func){ VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,func,0,NULL); - return FXString(STR2CSTR(result)); + return FXString(StringValuePtr(result)); } //---------------------------------------------------------------------- @@ -1479,7 +1516,7 @@ const FXchar* FXRbCallCStringMethod(const FXObject* recv, ID func, const FXchar* VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,func,2,to_ruby(message),to_ruby(hint)); - return NIL_P(result) ? 0 : STR2CSTR(result); + return NIL_P(result) ? 0 : StringValuePtr(result); } // Call functions with const FXchar* return value @@ -1487,7 +1524,7 @@ const FXchar* FXRbCallCStringMethod(const FXObject* recv, ID func, const FXchar* VALUE obj=FXRbGetRubyObj(recv,false); FXASSERT(!NIL_P(obj)); VALUE result=rb_funcall(obj,func,3,to_ruby(context),to_ruby(message),to_ruby(hint)); - return NIL_P(result) ? 0 : STR2CSTR(result); + return NIL_P(result) ? 0 : StringValuePtr(result); } //---------------------------------------------------------------------- @@ -1674,145 +1711,144 @@ FXbool FXRbGLViewer::sortProc(FXfloat*& buffer,FXint& used,FXint& size){ //---------------------------------------------------------------------- -// Copied from the Ruby 1.6.6 sources (signal.c) +// Copied from the Ruby 1.8.6 sources (signal.c) static struct signals { - const char* signm; - FXint signo; - } siglist[]={ + const char *signm; + int signo; +} siglist [] = { + {"EXIT", 0}, #ifdef SIGHUP - { "HUP", SIGHUP }, -#endif -#ifdef SIGINT - { "INT", SIGINT }, + {"HUP", SIGHUP}, #endif + {"INT", SIGINT}, #ifdef SIGQUIT - { "QUIT", SIGQUIT }, + {"QUIT", SIGQUIT}, #endif #ifdef SIGILL - { "ILL", SIGILL }, + {"ILL", SIGILL}, #endif #ifdef SIGTRAP - { "TRAP", SIGTRAP }, + {"TRAP", SIGTRAP}, #endif #ifdef SIGIOT - { "IOT", SIGIOT }, + {"IOT", SIGIOT}, #endif #ifdef SIGABRT - { "ABRT", SIGABRT }, + {"ABRT", SIGABRT}, #endif #ifdef SIGEMT - { "EMT", SIGEMT }, + {"EMT", SIGEMT}, #endif #ifdef SIGFPE - { "FPE", SIGFPE }, + {"FPE", SIGFPE}, #endif #ifdef SIGKILL - { "KILL", SIGKILL }, + {"KILL", SIGKILL}, #endif #ifdef SIGBUS - { "BUS", SIGBUS }, + {"BUS", SIGBUS}, #endif #ifdef SIGSEGV - { "SEGV", SIGSEGV }, + {"SEGV", SIGSEGV}, #endif #ifdef SIGSYS - { "SYS", SIGSYS }, + {"SYS", SIGSYS}, #endif #ifdef SIGPIPE - { "PIPE", SIGPIPE }, + {"PIPE", SIGPIPE}, #endif #ifdef SIGALRM - { "ALRM", SIGALRM }, + {"ALRM", SIGALRM}, #endif #ifdef SIGTERM - { "TERM", SIGTERM }, + {"TERM", SIGTERM}, #endif #ifdef SIGURG - { "URG", SIGURG }, + {"URG", SIGURG}, #endif #ifdef SIGSTOP - { "STOP", SIGSTOP }, + {"STOP", SIGSTOP}, #endif #ifdef SIGTSTP - { "TSTP", SIGTSTP }, + {"TSTP", SIGTSTP}, #endif #ifdef SIGCONT - { "CONT", SIGCONT }, + {"CONT", SIGCONT}, #endif #ifdef SIGCHLD - { "CHLD", SIGCHLD }, + {"CHLD", SIGCHLD}, #endif #ifdef SIGCLD - { "CLD", SIGCLD }, + {"CLD", SIGCLD}, #else # ifdef SIGCHLD - { "CLD", SIGCHLD, }, + {"CLD", SIGCHLD}, # endif #endif #ifdef SIGTTIN - { "TTIN", SIGTTIN }, + {"TTIN", SIGTTIN}, #endif #ifdef SIGTTOU - { "TTOU", SIGTTOU }, + {"TTOU", SIGTTOU}, #endif #ifdef SIGIO - { "IO", SIGIO }, + {"IO", SIGIO}, #endif #ifdef SIGXCPU - { "XCPU", SIGXCPU }, + {"XCPU", SIGXCPU}, #endif #ifdef SIGXFSZ - { "XFSZ", SIGXFSZ }, + {"XFSZ", SIGXFSZ}, #endif #ifdef SIGVTALRM - { "VTALRM", SIGVTALRM }, + {"VTALRM", SIGVTALRM}, #endif #ifdef SIGPROF - { "PROF", SIGPROF }, + {"PROF", SIGPROF}, #endif #ifdef SIGWINCH - { "WINCH", SIGWINCH }, + {"WINCH", SIGWINCH}, #endif #ifdef SIGUSR1 - { "USR1", SIGUSR1 }, + {"USR1", SIGUSR1}, #endif #ifdef SIGUSR2 - { "USR2", SIGUSR2 }, + {"USR2", SIGUSR2}, #endif #ifdef SIGLOST - { "LOST", SIGLOST }, + {"LOST", SIGLOST}, #endif #ifdef SIGMSG - { "MSG", SIGMSG }, + {"MSG", SIGMSG}, #endif #ifdef SIGPWR - { "PWR", SIGPWR }, + {"PWR", SIGPWR}, #endif #ifdef SIGPOLL - { "POLL", SIGPOLL }, + {"POLL", SIGPOLL}, #endif #ifdef SIGDANGER - { "DANGER", SIGDANGER }, + {"DANGER", SIGDANGER}, #endif #ifdef SIGMIGRATE - { "MIGRATE", SIGMIGRATE }, + {"MIGRATE", SIGMIGRATE}, #endif #ifdef SIGPRE - { "PRE", SIGPRE }, + {"PRE", SIGPRE}, #endif #ifdef SIGGRANT - { "GRANT", SIGGRANT }, + {"GRANT", SIGGRANT}, #endif #ifdef SIGRETRACT - { "RETRACT", SIGRETRACT }, + {"RETRACT", SIGRETRACT}, #endif #ifdef SIGSOUND - { "SOUND", SIGSOUND }, + {"SOUND", SIGSOUND}, #endif #ifdef SIGINFO - { "INFO", SIGINFO }, + {"INFO", SIGINFO}, #endif - { NULL, 0 }, + {NULL, 0} }; FXint FXRbSignalNameToNumber(const char* s){ @@ -1849,28 +1885,28 @@ static st_table * appSensitiveDCs; void FXRbRegisterAppSensitiveObject(FXObject* obj){ FXASSERT(obj!=0); - FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(obj=0x%08x(%s))\n",__FILE__,__LINE__,obj,obj->getClassName())); + FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(obj=%p(%s))\n",__FILE__,__LINE__,obj,obj->getClassName())); st_insert(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),(st_data_t)0); FXASSERT(st_lookup(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),reinterpret_cast<st_data_t *>(0))!=0); } void FXRbRegisterAppSensitiveObject(FXDC* dc){ FXASSERT(dc!=0); - FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(dc=0x%08x)\n",__FILE__,__LINE__,dc)); + FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(dc=%p)\n",__FILE__,__LINE__,dc)); st_insert(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),(st_data_t)0); FXASSERT(st_lookup(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),reinterpret_cast<st_data_t *>(0))!=0); } void FXRbUnregisterAppSensitiveObject(FXObject* obj){ FXASSERT(obj!=0); - FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(obj=0x%08x(%s))\n",__FILE__,__LINE__,obj,obj->getClassName())); + FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(obj=%p(%s))\n",__FILE__,__LINE__,obj,obj->getClassName())); st_delete(appSensitiveObjs,reinterpret_cast<st_data_t *>(&obj),reinterpret_cast<st_data_t *>(0)); FXASSERT(st_lookup(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),reinterpret_cast<st_data_t *>(0))==0); } void FXRbUnregisterAppSensitiveObject(FXDC* dc){ FXASSERT(dc!=0); - FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(dc=0x%08x)\n",__FILE__,__LINE__,dc)); + FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(dc=%p)\n",__FILE__,__LINE__,dc)); st_delete(appSensitiveDCs,reinterpret_cast<st_data_t *>(&dc),reinterpret_cast<st_data_t *>(0)); FXASSERT(st_lookup(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),reinterpret_cast<st_data_t *>(0))==0); } @@ -2011,6 +2047,8 @@ extern "C" void Init_fox16(void) { REQUIRE("fox16/glgroup"); REQUIRE("fox16/execute_nonmodal"); REQUIRE("fox16/version"); + REQUIRE("fox16/kwargs"); + REQUIRE("fox16/exceptions_for_fxerror"); id_assocs=rb_intern("@assocs"); id_backtrace=rb_intern("backtrace"); diff --git a/ext/fox16/extconf.rb.in b/ext/fox16/extconf.rb.in index f0b9462..6317045 100755 --- a/ext/fox16/extconf.rb.in +++ b/ext/fox16/extconf.rb.in @@ -1,12 +1,13 @@ #!/bin/env ruby -require 'ftools' +require 'fileutils' require 'mkmf' def find_installed_fox_version stddirs = ["/usr/include/fox-1.6", "/usr/local/include/fox-1.6", - "/sw/include/fox-1.6"] + "/sw/include/fox-1.6", + "/opt/local/include/fox-1.6"] usrdirs = [] ARGV.each do |arg| if arg =~ /--with-fox-include/ @@ -19,7 +20,7 @@ def find_installed_fox_version incdirs.each do |incdir| filename = File.join(incdir, "fxver.h") - if FileTest.exists?(filename) + if FileTest.exist?(filename) idircflag = "-I" + incdir $CPPFLAGS += " " + idircflag unless $CPPFLAGS.split.include?(idircflag) return @@ -35,7 +36,8 @@ $autodetected_fxscintilla = false def find_installed_fxscintilla_version stddirs = ["/usr/include/fxscintilla", "/usr/local/include/fxscintilla", - "/sw/include/fxscintilla"] + "/sw/include/fxscintilla", + "/opt/local/include/fxscintilla"] usrdirs = [] ARGV.each do |arg| if arg =~ /--with-fxscintilla-include/ @@ -48,7 +50,7 @@ def find_installed_fxscintilla_version incdirs.each do |incdir| filename = File.join(incdir, "FXScintilla.h") - if FileTest.exists?(filename) + if FileTest.exist?(filename) $autodetected_fxscintilla = true idircflag = "-I" + incdir $CPPFLAGS += " " + idircflag unless $CPPFLAGS.split.include?(idircflag) @@ -85,11 +87,11 @@ def do_cygwin_setup $libs = append_library($libs, "FOX-1.6") $CFLAGS = $CFLAGS + " -fpermissive -DWIN32 -Iinclude" if is_fxscintilla_build? - File.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exists?('scintilla_wrap.cpp.bak') + FileUtils.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exist?('scintilla_wrap.cpp.bak') $CFLAGS = $CFLAGS + " -DWITH_FXSCINTILLA -DHAVE_FOX_1_6" $libs = append_library($libs, "fxscintilla") else - File.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exists?('scintilla_wrap.cpp') + FileUtils.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exist?('scintilla_wrap.cpp') end end @@ -109,11 +111,11 @@ def do_mswin32_setup $CFLAGS = $CFLAGS + " /DWIN32 /DUNICODE /GR /GX /Iinclude" $LOCAL_LIBS = $LOCAL_LIBS + "FOX-1.6.lib" if is_fxscintilla_build? - File.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exists?('scintilla_wrap.cpp.bak') + FileUtils.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exist?('scintilla_wrap.cpp.bak') $CFLAGS = $CFLAGS + " /DWITH_FXSCINTILLA /DHAVE_FOX_1_6" $libs = append_library($libs, "fxscintilla") else - File.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exists?('scintilla_wrap.cpp') + FileUtils.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exist?('scintilla_wrap.cpp') end end @@ -131,13 +133,40 @@ def do_unix_setup find_library("GL", "glXCreateContext", "/usr/X11R6/lib") find_library("GLU", "gluNewQuadric", "/usr/X11R6/lib") $libs = append_library($libs, "FOX-1.6") + $libs = append_library($libs, "Xrandr") $CFLAGS = $CFLAGS + " -O0 -Iinclude" if is_fxscintilla_build? - File.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exists?('scintilla_wrap.cpp.bak') + FileUtils.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exist?('scintilla_wrap.cpp.bak') $CFLAGS = $CFLAGS + " -DWITH_FXSCINTILLA -DHAVE_FOX_1_6" $libs = append_library($libs, "fxscintilla") else - File.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exists?('scintilla_wrap.cpp') + FileUtils.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exist?('scintilla_wrap.cpp') + end +end + +def do_darwin_setup + $libs = append_library($libs, "stdc++") + have_header("sys/time.h") + have_header("signal.h") + have_library("png", "png_create_read_struct") + have_library("z", "deflate") + have_library("jpeg", "jpeg_mem_init") + have_library("tiff", "TIFFSetErrorHandler") + find_library("Xext", "XShmQueryVersion", "/usr/X11R6/lib") + find_library("X11", "XFindContext", "/usr/X11R6/lib") + find_library("GL", "glXCreateContext", "/usr/X11R6/lib") + find_library("GLU", "gluNewQuadric", "/usr/X11R6/lib") + $libs = append_library($libs, "FOX-1.6") + $libs = append_library($libs, "Xrandr") + $libs = append_library($libs, "Xcursor") + $libs = append_library($libs, "png") + $CFLAGS = $CFLAGS + " -O0 -Iinclude" + if is_fxscintilla_build? + FileUtils.move('scintilla_wrap.cpp.bak', 'scintilla_wrap.cpp') if FileTest.exist?('scintilla_wrap.cpp.bak') + $CFLAGS = $CFLAGS + " -DWITH_FXSCINTILLA -DHAVE_FOX_1_6" + $libs = append_library($libs, "fxscintilla") + else + FileUtils.move('scintilla_wrap.cpp', 'scintilla_wrap.cpp.bak') if FileTest.exist?('scintilla_wrap.cpp') end end @@ -168,9 +197,14 @@ if RUBY_PLATFORM =~ /cygwin/ || RUBY_PLATFORM =~ /mingw/ do_cygwin_setup elsif RUBY_PLATFORM =~ /mswin32/ do_mswin32_setup +elsif RUBY_PLATFORM =~ /darwin/ + do_darwin_setup else do_unix_setup end +# Check for Ruby 1.9 +$CFLAGS += " -DRUBY_1_9" if RUBY_VERSION =~ /1\.9\./ + # Last step: build the makefile create_makefile("fox16") diff --git a/ext/fox16/include/FXRbApp.h b/ext/fox16/include/FXRbApp.h index 559d81b..6ae00c6 100755 --- a/ext/fox16/include/FXRbApp.h +++ b/ext/fox16/include/FXRbApp.h @@ -21,7 +21,7 @@ ***********************************************************************/ /*********************************************************************** - * $Id: FXRbApp.h 2335 2006-01-28 02:33:03Z lyle $ + * $Id: FXRbApp.h 2927 2008-12-29 19:16:57Z lyle $ ***********************************************************************/ #ifndef FXRBAPP_H @@ -41,15 +41,16 @@ inline void cls ## _create(cls *self){ \ static void cls ## _init(cls* self,VALUE ary,bool connect){ \ int i; \ char **argv; \ - int argc=1+RARRAY(ary)->len; \ + int argc=1+RARRAY_LEN(ary); \ if(FXMALLOC(&argv,char*,argc+1)){ \ - argv[0]="foo"; \ + argv[0]=const_cast<char *>("foo"); \ for(i=1;i<argc;i++){ \ - argv[i]=STR2CSTR(RSTRING(rb_ary_entry(ary,i-1))); \ + VALUE e=rb_ary_entry(ary,i-1); \ + argv[i]=StringValuePtr(e); \ } \ argv[argc]=0; \ self->cls::init(argc,argv,connect); \ - while(RARRAY(ary)->len!=0){ \ + while(RARRAY_LEN(ary)!=0){ \ rb_ary_pop(ary); \ } \ for(i=1;i<argc;i++){ \ @@ -97,9 +98,10 @@ inline void cls ## _exit(cls *self,FXint code){ \ rb_ary_push(ary,rb_str_new2(argv[i])); \ } \ FXRbCallVoidMethod(this,rb_intern("init"),ary,connect); \ - argc=RARRAY(ary)->len+1; \ + argc=RARRAY_LEN(ary)+1; \ for(i=1; i<argc; i++){ \ - argv[i]=STR2CSTR(rb_ary_entry(ary,i-1)); \ + VALUE e=rb_ary_entry(ary,i-1); \ + argv[i]=StringValuePtr(e); \ } \ } \ void cls::exit(FXint code){ \ diff --git a/ext/fox16/include/FXRbDC.h b/ext/fox16/include/FXRbDC.h index 8a2ac1a..33cf85a 100755 --- a/ext/fox16/include/FXRbDC.h +++ b/ext/fox16/include/FXRbDC.h @@ -21,7 +21,7 @@ ***********************************************************************/ /*********************************************************************** - * $Id: FXRbDC.h 2372 2006-04-20 00:38:08Z lyle $ + * $Id: FXRbDC.h 2823 2008-03-28 02:04:22Z lyle $ ***********************************************************************/ #ifndef FXRBDC_H diff --git a/ext/fox16/markfuncs.cpp b/ext/fox16/markfuncs.cpp index 1b62c89..bea3a48 100755 --- a/ext/fox16/markfuncs.cpp +++ b/ext/fox16/markfuncs.cpp @@ -1,5 +1,5 @@ /*********************************************************************** - * $Id: markfuncs.cpp 2479 2006-09-08 23:20:52Z lyle $ + * $Id: markfuncs.cpp 2928 2008-12-29 19:16:57Z lyle $ ***********************************************************************/ #include "FXRbCommon.h" @@ -49,7 +49,7 @@ void FXRbAccelTable::markfunc(FXAccelTable* accelTable){ // Mark dependencies for the GC void FXRbObject::markfunc(FXObject* obj){ - FXTRACE((100,"%s::markfunc(0x%08x)\n",obj?obj->getClassName():"FXRbObject",obj)); + FXTRACE((100,"%s::markfunc(%p)\n",obj?obj->getClassName():"FXRbObject",obj)); } @@ -1568,29 +1568,29 @@ void FXRbTGAImage::markfunc(FXTGAImage* self){ void FXRbBitmapFrame::markfunc(FXBitmapFrame* self){ - FXTRACE((100,"start FXRbBitmapFrame::markfunc(0x%08x)\n",self)); + FXTRACE((100,"start FXRbBitmapFrame::markfunc(%p)\n",self)); FXRbFrame::markfunc(self); if(self!=0){ FXRbGcMark(self->getBitmap()); } - FXTRACE((100,"end FXRbBitmapFrame::markfunc(0x%08x)\n",self)); + FXTRACE((100,"end FXRbBitmapFrame::markfunc(%p)\n",self)); } void FXRbImageFrame::markfunc(FXImageFrame* self){ - FXTRACE((100,"start FXRbImageFrame::markfunc(0x%08x)\n",self)); + FXTRACE((100,"start FXRbImageFrame::markfunc(%p)\n",self)); FXRbFrame::markfunc(self); if(self!=0){ FXRbGcMark(self->getImage()); } - FXTRACE((100,"end FXRbImageFrame::markfunc(0x%08x)\n",self)); + FXTRACE((100,"end FXRbImageFrame::markfunc(%p)\n",self)); } void FXRbGradientBar::markfunc(FXGradientBar* self){ - FXTRACE((100,"start FXRbGradientBar::markfunc(0x%08x)\n",self)); + FXTRACE((100,"start FXRbGradientBar::markfunc(%p)\n",self)); FXRbFrame::markfunc(self); - FXTRACE((100,"end FXRbGradientBar::markfunc(0x%08x)\n",self)); + FXTRACE((100,"end FXRbGradientBar::markfunc(%p)\n",self)); } #ifdef WITH_FXSCINTILLA diff --git a/ext/fox16/unregisterOwnedObjects.cpp b/ext/fox16/unregisterOwnedObjects.cpp index 8c14579..ca50c0a 100644 --- a/ext/fox16/unregisterOwnedObjects.cpp +++ b/ext/fox16/unregisterOwnedObjects.cpp @@ -1,5 +1,5 @@ /*********************************************************************** - * $Id: unregisterOwnedObjects.cpp 2305 2005-12-09 14:38:22Z lyle $ + * $Id: unregisterOwnedObjects.cpp 2911 2008-12-11 14:09:45Z lyle $ ***********************************************************************/ /** @@ -88,7 +88,7 @@ void FXRbScrollWindow::unregisterOwnedObjects(FXScrollWindow *self) void FXRbTable::unregisterOwnedObjects(FXTable *self) { - FXint i,r,c; + FXint r,c; FXRbScrollArea::unregisterOwnedObjects(self); FXRbHeader::unregisterOwnedObjects(self->getRowHeader()); FXRbHeader::unregisterOwnedObjects(self->getColumnHeader()); diff --git a/install.rb b/install.rb index 274ab6e..424a5f3 100755 --- a/install.rb +++ b/install.rb @@ -1,1095 +1,1582 @@ # -# This file is automatically generated. DO NOT MODIFY! +# setup.rb # -# install.rb +# Copyright (c) 2000-2005 Minero Aoki # -# Copyright (c) 2000-2003 Minero Aoki <aamine@loveruby.net> +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. # -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2. -# - -### begin compat.rb -module Enumerable - methods = instance_methods() - - unless methods.include?('map') +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 + module Enumerable alias map collect end +end - unless methods.include?('select') - alias select find_all - end - - unless methods.include?('reject') - def reject - result = [] - each do |i| - result.push i unless yield(i) - end - result - end - end - - unless methods.include?('inject') - def inject( result ) - each do |i| - result = yield(result, i) - end - result - end +unless File.respond_to?(:read) # Ruby 1.6 + def File.read(fname) + open(fname) {|f| + return f.read + } end +end - unless methods.include?('any?') - def any? - each do |i| - return true if yield(i) - end - false +unless Errno.const_defined?(:ENOTEMPTY) # Windows? + module Errno + class ENOTEMPTY + # We do not raise this exception, implementation is not needed. end end end -def File.read_all( fname ) - File.open(fname, 'rb') {|f| return f.read } -end - -def File.write( fname, str ) - File.open(fname, 'wb') {|f| f.write str } +def File.binread(fname) + open(fname, 'rb') {|f| + return f.read + } end -### end compat.rb -### begin config.rb - -if i = ARGV.index(/\A--rbconfig=/) - file = $' - ARGV.delete_at(i) - require file -else - require 'rbconfig' +# for corrupted Windows' stat(2) +def File.dir?(path) + File.directory?((path[-1,1] == '/') ? path : path + '/') end class ConfigTable - c = ::Config::CONFIG + include Enumerable - rubypath = c['bindir'] + '/' + c['ruby_install_name'] + def initialize(rbconfig) + @rbconfig = rbconfig + @items = [] + @table = {} + # options + @install_prefix = nil + @config_opt = nil + @verbose = true + @no_harm = false + end - major = c['MAJOR'].to_i - minor = c['MINOR'].to_i - teeny = c['TEENY'].to_i - version = "#{major}.#{minor}" + attr_accessor :install_prefix + attr_accessor :config_opt - # ruby ver. >= 1.4.4? - newpath_p = ((major >= 2) or - ((major == 1) and - ((minor >= 5) or - ((minor == 4) and (teeny >= 4))))) - - re = Regexp.new('\A' + Regexp.quote(c['prefix'])) - subprefix = lambda {|path| - re === path and path.sub(re, '$prefix') - } + attr_writer :verbose - if c['rubylibdir'] - # V < 1.6.3 - stdruby = subprefix.call(c['rubylibdir']) - siteruby = subprefix.call(c['sitedir']) - versite = subprefix.call(c['sitelibdir']) - sodir = subprefix.call(c['sitearchdir']) - elsif newpath_p - # 1.4.4 <= V <= 1.6.3 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = subprefix.call(c['sitedir']) - versite = siteruby + '/' + version - sodir = "$site-ruby/#{c['arch']}" - else - # V < 1.4.4 - stdruby = "$prefix/lib/ruby/#{version}" - siteruby = "$prefix/lib/ruby/#{version}/site_ruby" - versite = siteruby - sodir = "$site-ruby/#{c['arch']}" - end - - DESCRIPTER = [ - [ 'prefix', [ c['prefix'], - 'path', - 'path prefix of target environment' ] ], - [ 'std-ruby', [ stdruby, - 'path', - 'the directory for standard ruby libraries' ] ], - [ 'site-ruby-common', [ siteruby, - 'path', - 'the directory for version-independent non-standard ruby libraries' ] ], - [ 'site-ruby', [ versite, - 'path', - 'the directory for non-standard ruby libraries' ] ], - [ 'bin-dir', [ '$prefix/bin', - 'path', - 'the directory for commands' ] ], - [ 'rb-dir', [ '$site-ruby', - 'path', - 'the directory for ruby scripts' ] ], - [ 'so-dir', [ sodir, - 'path', - 'the directory for ruby extentions' ] ], - [ 'data-dir', [ '$prefix/share', - 'path', - 'the directory for shared data' ] ], - [ 'ruby-path', [ rubypath, - 'path', - 'path to set to #! line' ] ], - [ 'ruby-prog', [ rubypath, - 'name', - 'the ruby program using for installation' ] ], - [ 'make-prog', [ 'make', - 'name', - 'the make program to compile ruby extentions' ] ], - [ 'without-ext', [ 'no', - 'yes/no', - 'does not compile/install ruby extentions' ] ] - ] + def verbose? + @verbose + end - SAVE_FILE = 'config.save' + attr_writer :no_harm - def ConfigTable.each_name( &block ) - keys().each(&block) + def no_harm? + @no_harm end - def ConfigTable.keys - DESCRIPTER.map {|k,*dummy| k } + def [](key) + lookup(key).resolve(self) end - def ConfigTable.each_definition( &block ) - DESCRIPTER.each(&block) + def []=(key, val) + lookup(key).set val end - def ConfigTable.get_entry( name ) - name, ent = DESCRIPTER.assoc(name) - ent + def names + @items.map {|i| i.name } end - def ConfigTable.get_entry!( name ) - get_entry(name) or raise ArgumentError, "no such config: #{name}" + def each(&block) + @items.each(&block) end - def ConfigTable.add_entry( name, vals ) - ConfigTable::DESCRIPTER.push [name,vals] + def key?(name) + @table.key?(name) end - def ConfigTable.remove_entry( name ) - get_entry name or raise ArgumentError, "no such config: #{name}" - DESCRIPTER.delete_if {|n,arr| n == name } + def lookup(name) + @table[name] or setup_rb_error "no such config item: #{name}" end - def ConfigTable.config_key?( name ) - get_entry(name) ? true : false + def add(item) + @items.push item + @table[item.name] = item end - def ConfigTable.bool_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'yes/no' + def remove(name) + item = lookup(name) + @items.delete_if {|i| i.name == name } + @table.delete_if {|name, i| i.name == name } + item end - def ConfigTable.value_config?( name ) - ent = get_entry(name) or return false - ent[1] != 'yes/no' + def load_script(path, inst = nil) + if File.file?(path) + MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path + end end - def ConfigTable.path_config?( name ) - ent = get_entry(name) or return false - ent[1] == 'path' + def savefile + '.config' end - - class << self - alias newobj new - - def new - c = newobj() - c.__send__ :init - c - end - - def load - c = newobj() - raise InstallError, "#{File.basename $0} config first"\ - unless FileTest.file?(SAVE_FILE) - File.foreach(SAVE_FILE) do |line| - k, v = line.split(/=/, 2) - c.instance_eval { - @table[k] = v.strip - } + def load_savefile + begin + File.foreach(savefile()) do |line| + k, v = *line.split(/=/, 2) + self[k] = v.strip end - c + rescue Errno::ENOENT + setup_rb_error $!.message + "\n#{File.basename($0)} config first" end end - def initialize - @table = {} + def save + @items.each {|i| i.value } + File.open(savefile(), 'w') {|f| + @items.each do |i| + f.printf "%s=%s\n", i.name, i.value if i.value? and i.value + end + } end - def init - DESCRIPTER.each do |k, (default, vname, desc, default2)| - @table[k] = default + def load_standard_entries + standard_entries(@rbconfig).each do |ent| + add ent end end - private :init - def save - File.open(SAVE_FILE, 'w') {|f| - @table.each do |k, v| - f.printf "%s=%s\n", k, v if v - end + def standard_entries(rbconfig) + c = rbconfig + + rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) + + major = c['MAJOR'].to_i + minor = c['MINOR'].to_i + teeny = c['TEENY'].to_i + version = "#{major}.#{minor}" + + # ruby ver. >= 1.4.4? + newpath_p = ((major >= 2) or + ((major == 1) and + ((minor >= 5) or + ((minor == 4) and (teeny >= 4))))) + + if c['rubylibdir'] + # V > 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = c['rubylibdir'] + librubyverarch = c['archdir'] + siteruby = c['sitedir'] + siterubyver = c['sitelibdir'] + siterubyverarch = c['sitearchdir'] + elsif newpath_p + # 1.4.4 <= V <= 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = c['sitedir'] + siterubyver = "$siteruby/#{version}" + siterubyverarch = "$siterubyver/#{c['arch']}" + else + # V < 1.4.4 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" + siterubyver = siteruby + siterubyverarch = "$siterubyver/#{c['arch']}" + end + parameterize = lambda {|path| + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') } - end - def []=( k, v ) - ConfigTable.config_key? k or raise InstallError, "unknown config option #{k}" - if ConfigTable.path_config? k - @table[k] = (v[0,1] != '$') ? File.expand_path(v) : v + if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] else - @table[k] = v + makeprog = 'make' + end + + [ + ExecItem.new('installdirs', 'std/site/home', + 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ + {|val, table| + case val + when 'std' + table['rbdir'] = '$librubyver' + table['sodir'] = '$librubyverarch' + when 'site' + table['rbdir'] = '$siterubyver' + table['sodir'] = '$siterubyverarch' + when 'home' + setup_rb_error '$HOME was not set' unless ENV['HOME'] + table['prefix'] = ENV['HOME'] + table['rbdir'] = '$libdir/ruby' + table['sodir'] = '$libdir/ruby' + end + }, + PathItem.new('prefix', 'path', c['prefix'], + 'path prefix of target environment'), + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), + 'the directory for commands'), + PathItem.new('libdir', 'path', parameterize.call(c['libdir']), + 'the directory for libraries'), + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), + 'the directory for shared data'), + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), + 'the directory for man pages'), + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), + 'the directory for system configuration files'), + PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), + 'the directory for local state data'), + PathItem.new('libruby', 'path', libruby, + 'the directory for ruby libraries'), + PathItem.new('librubyver', 'path', librubyver, + 'the directory for standard ruby libraries'), + PathItem.new('librubyverarch', 'path', librubyverarch, + 'the directory for standard ruby extensions'), + PathItem.new('siteruby', 'path', siteruby, + 'the directory for version-independent aux ruby libraries'), + PathItem.new('siterubyver', 'path', siterubyver, + 'the directory for aux ruby libraries'), + PathItem.new('siterubyverarch', 'path', siterubyverarch, + 'the directory for aux ruby binaries'), + PathItem.new('rbdir', 'path', '$siterubyver', + 'the directory for ruby scripts'), + PathItem.new('sodir', 'path', '$siterubyverarch', + 'the directory for ruby extentions'), + PathItem.new('rubypath', 'path', rubypath, + 'the path to set to #! line'), + ProgramItem.new('rubyprog', 'name', rubypath, + 'the ruby program using for installation'), + ProgramItem.new('makeprog', 'name', makeprog, + 'the make program to compile ruby extentions'), + SelectItem.new('shebang', 'all/ruby/never', 'ruby', + 'shebang line (#!) editing mode'), + BoolItem.new('without-ext', 'yes/no', 'no', + 'does not compile/install ruby extentions') + ] + end + private :standard_entries + + def load_multipackage_entries + multipackage_entries().each do |ent| + add ent + end + end + + def multipackage_entries + [ + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', + 'package names that you want to install'), + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', + 'package names that you do not want to install') + ] + end + private :multipackage_entries + + ALIASES = { + 'std-ruby' => 'librubyver', + 'stdruby' => 'librubyver', + 'rubylibdir' => 'librubyver', + 'archdir' => 'librubyverarch', + 'site-ruby-common' => 'siteruby', # For backward compatibility + 'site-ruby' => 'siterubyver', # For backward compatibility + 'bin-dir' => 'bindir', + 'bin-dir' => 'bindir', + 'rb-dir' => 'rbdir', + 'so-dir' => 'sodir', + 'data-dir' => 'datadir', + 'ruby-path' => 'rubypath', + 'ruby-prog' => 'rubyprog', + 'ruby' => 'rubyprog', + 'make-prog' => 'makeprog', + 'make' => 'makeprog' + } + + def fixup + ALIASES.each do |ali, name| + @table[ali] = @table[name] end + @items.freeze + @table.freeze + @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ end - - def []( key ) - @table[key] or return nil - @table[key].gsub(%r<\$([^/]+)>) { self[$1] } + + def parse_opt(opt) + m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" + m.to_a[1,2] end - def set_raw( key, val ) - @table[key] = val + def dllext + @rbconfig['DLEXT'] end - def get_raw( key ) - @table[key] + def value_config?(name) + lookup(name).value? end -end + class Item + def initialize(name, template, default, desc) + @name = name.freeze + @template = template + @value = default + @default = default + @description = desc + end + attr_reader :name + attr_reader :description -module MetaConfigAPI + attr_accessor :default + alias help_default default - def eval_file_ifexist( fname ) - instance_eval File.read_all(fname), fname, 1 if FileTest.file?(fname) - end + def help_opt + "--#{@name}=#{@template}" + end - def config_names - ConfigTable.keys - end + def value? + true + end - def config?( name ) - ConfigTable.config_key? name - end + def value + @value + end + + def resolve(table) + @value.gsub(%r<\$([^/]+)>) { table[$1] } + end + + def set(val) + @value = check(val) + end + + private - def bool_config?( name ) - ConfigTable.bool_config? name + def check(val) + setup_rb_error "config: --#{name} requires argument" unless val + val + end end - def value_config?( name ) - ConfigTable.value_config? name + class BoolItem < Item + def config_type + 'bool' + end + + def help_opt + "--#{@name}" + end + + private + + def check(val) + return 'yes' unless val + case val + when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' + when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' + else + setup_rb_error "config: --#{@name} accepts only yes/no for argument" + end + end end - def path_config?( name ) - ConfigTable.path_config? name + class PathItem < Item + def config_type + 'path' + end + + private + + def check(path) + setup_rb_error "config: --#{@name} requires argument" unless path + path[0,1] == '$' ? path : File.expand_path(path) + end end - def add_config( name, argname, default, desc ) - ConfigTable.add_entry name,[default,argname,desc] + class ProgramItem < Item + def config_type + 'program' + end end - def add_path_config( name, default, desc ) - add_config name, 'path', default, desc + class SelectItem < Item + def initialize(name, selection, default, desc) + super + @ok = selection.split('/') + end + + def config_type + 'select' + end + + private + + def check(val) + unless @ok.include?(val.strip) + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" + end + val.strip + end end - def add_bool_config( name, default, desc ) - add_config name, 'yes/no', default ? 'yes' : 'no', desc + class ExecItem < Item + def initialize(name, selection, desc, &block) + super name, selection, nil, desc + @ok = selection.split('/') + @action = block + end + + def config_type + 'exec' + end + + def value? + false + end + + def resolve(table) + setup_rb_error "$#{name()} wrongly used as option value" + end + + undef set + + def evaluate(val, table) + v = val.strip.downcase + unless @ok.include?(v) + setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" + end + @action.call v, table + end end - def set_config_default( name, default ) - if bool_config? name - ConfigTable.get_entry!(name)[0] = default ? 'yes' : 'no' - else - ConfigTable.get_entry!(name)[0] = default + class PackageSelectionItem < Item + def initialize(name, template, default, help_default, desc) + super name, template, default, desc + @help_default = help_default + end + + attr_reader :help_default + + def config_type + 'package' + end + + private + + def check(val) + unless File.dir?("packages/#{val}") + setup_rb_error "config: no such package: #{val}" + end + val end end - def remove_config( name ) - ent = ConfigTable.get_entry(name) - ConfigTable.remove_entry name - ent + class MetaConfigEnvironment + def initialize(config, installer) + @config = config + @installer = installer + end + + def config_names + @config.names + end + + def config?(name) + @config.key?(name) + end + + def bool_config?(name) + @config.lookup(name).config_type == 'bool' + end + + def path_config?(name) + @config.lookup(name).config_type == 'path' + end + + def value_config?(name) + @config.lookup(name).config_type != 'exec' + end + + def add_config(item) + @config.add item + end + + def add_bool_config(name, default, desc) + @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) + end + + def add_path_config(name, default, desc) + @config.add PathItem.new(name, 'path', default, desc) + end + + def set_config_default(name, default) + @config.lookup(name).default = default + end + + def remove_config(name) + @config.remove(name) + end + + # For only multipackage + def packages + raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer + @installer.packages + end + + # For only multipackage + def declare_packages(list) + raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer + @installer.packages = list + end end -end +end # class ConfigTable -### end config.rb -### begin fileop.rb +# This module requires: #verbose?, #no_harm? module FileOperations - def mkdir_p( dname, prefix = nil ) - dname = prefix + dname if prefix - $stderr.puts "mkdir -p #{dname}" if verbose? + def mkdir_p(dirname, prefix = nil) + dirname = prefix + File.expand_path(dirname) if prefix + $stderr.puts "mkdir -p #{dirname}" if verbose? return if no_harm? - # does not check '/'... it's too abnormal case - dirs = dname.split(%r<(?=/)>) - if /\A[a-z]:\z/i === dirs[0] + # Does not check '/', it's too abnormal. + dirs = File.expand_path(dirname).split(%r<(?=/)>) + if /\A[a-z]:\z/i =~ dirs[0] disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') - Dir.mkdir path unless dir? path + Dir.mkdir path unless File.dir?(path) end end - def rm_f( fname ) - $stderr.puts "rm -f #{fname}" if verbose? + def rm_f(path) + $stderr.puts "rm -f #{path}" if verbose? return if no_harm? - - if File.exist? fname or File.symlink? fname - File.chmod 0777, fname - File.unlink fname - end + force_remove_file path end - def rm_rf( dn ) - $stderr.puts "rm -rf #{dn}" if verbose? + def rm_rf(path) + $stderr.puts "rm -rf #{path}" if verbose? return if no_harm? + remove_tree path + end + + def remove_tree(path) + if File.symlink?(path) + remove_file path + elsif File.dir?(path) + remove_tree0 path + else + force_remove_file path + end + end - Dir.chdir dn - Dir.foreach('.') do |fn| - next if fn == '.' - next if fn == '..' - if dir? fn - verbose_off { - rm_rf fn - } + def remove_tree0(path) + Dir.foreach(path) do |ent| + next if ent == '.' + next if ent == '..' + entpath = "#{path}/#{ent}" + if File.symlink?(entpath) + remove_file entpath + elsif File.dir?(entpath) + remove_tree0 entpath else - verbose_off { - rm_f fn - } + force_remove_file entpath end end - Dir.chdir '..' - Dir.rmdir dn + begin + Dir.rmdir path + rescue Errno::ENOTEMPTY + # directory may not be empty + end end - def mv( src, dest ) - rm_f dest + def move_file(src, dest) + force_remove_file dest begin - File.link src, dest + File.rename src, dest rescue - File.write dest, File.read_all(src) + File.open(dest, 'wb') {|f| + f.write File.binread(src) + } File.chmod File.stat(src).mode, dest + File.unlink src + end + end + + def force_remove_file(path) + begin + remove_file path + rescue end - rm_f src end - def install( from, dest, mode, prefix = nil ) + def remove_file(path) + File.chmod 0777, path + File.unlink path + end + + def install(from, dest, mode, prefix = nil) $stderr.puts "install #{from} #{dest}" if verbose? return if no_harm? - realdest = prefix + dest if prefix - if dir? realdest - realdest += '/' + File.basename(from) - end - str = File.read_all(from) - if diff? str, realdest + realdest = prefix ? prefix + File.expand_path(dest) : dest + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) + str = File.binread(from) + if diff?(str, realdest) verbose_off { - rm_f realdest if File.exist? realdest + rm_f realdest if File.exist?(realdest) + } + File.open(realdest, 'wb') {|f| + f.write str } - File.write realdest, str File.chmod mode, realdest -# File.open(objdir + '/InstalledFiles', 'a') {|f| f.puts realdest } + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| + if prefix + f.puts realdest.sub(prefix, '') + else + f.puts realdest + end + } end end - def diff?( orig, targ ) - return true unless File.exist? targ - orig != File.read_all(targ) + def diff?(new_content, path) + return true unless File.exist?(path) + new_content != File.binread(path) end - def command( str ) - $stderr.puts str if verbose? - system str or raise RuntimeError, "'system #{str}' failed" + def command(*args) + $stderr.puts args.join(' ') if verbose? + system(*args) or raise RuntimeError, + "system(#{args.map{|a| a.inspect }.join(' ')}) failed" end - def ruby( str ) - command config('ruby-prog') + ' ' + str + def ruby(*args) + command config('rubyprog'), *args + end + + def make(task = nil) + command(*[config('makeprog'), task].compact) end - def dir?( dname ) - # for corrupted windows stat() - File.directory?((dname[-1,1] == '/') ? dname : dname + '/') + def extdir?(dir) + File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") end - def all_files_in( dname ) - Dir.open(dname) {|d| - return d.select {|n| FileTest.file? "#{dname}/#{n}" } + def files_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.file?("#{dir}/#{ent}") } } end - REJECT_DIRS = %w( - CVS SCCS RCS CVS.adm .svn - ) + DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) - def all_dirs_in( dname ) - Dir.open(dname) {|d| - return d.select {|n| dir? "#{dname}/#{n}" } - %w(. ..) - REJECT_DIRS + def directories_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT } end end -### end fileop.rb -### begin base.rb - -class InstallError < StandardError; end - -class Installer - - Version = '3.1.4' - Copyright = 'Copyright (c) 2000-2003 Minero Aoki' - - - @toplevel = nil - - def self.declare_toplevel_installer( inst ) - raise ArgumentError, 'two toplevel installers declared' if @toplevel - @toplevel = inst - end - - def self.toplevel_installer - @toplevel - end - - - FILETYPES = %w( bin lib ext data ) - - include FileOperations - - def initialize( config, opt, srcroot, objroot ) - @config = config - @options = opt - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - end - - def inspect - "#<#{self.class} #{__id__}>" - end - - # - # configs/options - # +# This module requires: #srcdir_root, #objdir_root, #relpath +module HookScriptAPI - def get_config( key ) + def get_config(key) @config[key] end alias config get_config - def set_config( key, val ) + # obsolete: use metaconfig to change configuration + def set_config(key, val) @config[key] = val end - def no_harm? - @options['no-harm'] - end - - def verbose? - @options['verbose'] - end - - def verbose_off - save, @options['verbose'] = @options['verbose'], false - yield - @options['verbose'] = save - end - # - # srcdir/objdir + # srcdir/objdir (works only in the package directory) # - attr_reader :srcdir - alias srcdir_root srcdir - alias package_root srcdir - def curr_srcdir - "#{@srcdir}/#{@currdir}" + "#{srcdir_root()}/#{relpath()}" end - attr_reader :objdir - alias objdir_root objdir - def curr_objdir - "#{@objdir}/#{@currdir}" + "#{objdir_root()}/#{relpath()}" end - def srcfile( path ) - curr_srcdir + '/' + path + def srcfile(path) + "#{curr_srcdir()}/#{path}" end - def srcexist?( path ) - File.exist? srcfile(path) + def srcexist?(path) + File.exist?(srcfile(path)) end - def srcdirectory?( path ) - dir? srcfile(path) + def srcdirectory?(path) + File.dir?(srcfile(path)) end - def srcfile?( path ) - FileTest.file? srcfile(path) + def srcfile?(path) + File.file?(srcfile(path)) end - def srcentries( path = '.' ) - Dir.open(curr_srcdir + '/' + path) {|d| - return d.to_a - %w(. ..) - hookfilenames + def srcentries(path = '.') + Dir.open("#{curr_srcdir()}/#{path}") {|d| + return d.to_a - %w(. ..) } end - def srcfiles( path = '.' ) + def srcfiles(path = '.') srcentries(path).select {|fname| - FileTest.file? File.join(curr_srcdir, path, fname) + File.file?(File.join(curr_srcdir(), path, fname)) } end - def srcdirectories( path = '.' ) + def srcdirectories(path = '.') srcentries(path).select {|fname| - dir? File.join(curr_srcdir, path, fname) + File.dir?(File.join(curr_srcdir(), path, fname)) } end - def dive_into( rel ) - return unless dir?("#{@srcdir}/#{rel}") +end - dir = File.basename(rel) - Dir.mkdir dir unless dir?(dir) - prevdir = Dir.pwd - Dir.chdir dir - $stderr.puts '---> ' + rel if verbose? - @currdir = rel - yield - Dir.chdir prevdir - $stderr.puts '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - # - # TASK config - # +class ToplevelInstaller - def exec_config - exec_task_traverse 'config' - end + Version = '3.4.1' + Copyright = 'Copyright (c) 2000-2005 Minero Aoki' - def config_dir_bin( rel ) - end + TASKS = [ + [ 'all', 'do config, setup, then install' ], + [ 'config', 'saves your configurations' ], + [ 'show', 'shows current configuration' ], + [ 'setup', 'compiles ruby extentions and others' ], + [ 'install', 'installs files' ], + [ 'test', 'run all tests in test/' ], + [ 'clean', "does `make clean' for each extention" ], + [ 'distclean',"does `make distclean' for each extention" ] + ] - def config_dir_lib( rel ) + def ToplevelInstaller.invoke + config = ConfigTable.new(load_rbconfig()) + config.load_standard_entries + config.load_multipackage_entries if multipackage? + config.fixup + klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) + klass.new(File.dirname($0), config).invoke end - def config_dir_ext( rel ) - extconf if extdir? curr_srcdir + def ToplevelInstaller.multipackage? + File.dir?(File.dirname($0) + '/packages') end - def extconf - opt = @options['config-opt'].join(' ') - command "#{config('ruby-prog')} #{curr_srcdir}/extconf.rb #{opt}" + def ToplevelInstaller.load_rbconfig + if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } + ARGV.delete(arg) + load File.expand_path(arg.split(/=/, 2)[1]) + $".push 'rbconfig.rb' + else + require 'rbconfig' + end + ::Config::CONFIG end - def config_dir_data( rel ) + def initialize(ardir_root, config) + @ardir = File.expand_path(ardir_root) + @config = config + # cache + @valid_task_re = nil end - # - # TASK setup - # - - def exec_setup - exec_task_traverse 'setup' + def config(key) + @config[key] end - def setup_dir_bin( relpath ) - all_files_in(curr_srcdir()).each do |fname| - add_rubypath "#{curr_srcdir}/#{fname}" - end + def inspect + "#<#{self.class} #{__id__()}>" end - SHEBANG_RE = /\A\#!\s*\S*ruby\S*/ - - def add_rubypath( path ) - $stderr.puts %Q<set #! line to "\#!#{config('ruby-path')}" for #{path} ...> if verbose? - return if no_harm? - - tmpfile = File.basename(path) + '.tmp' - begin - File.open(path) {|r| - File.open(tmpfile, 'w') {|w| - first = r.gets - return unless SHEBANG_RE === first # reject '/usr/bin/env ruby' - - w.print first.sub(SHEBANG_RE, '#!' + config('ruby-path')) - w.write r.read - } } - mv tmpfile, File.basename(path) - ensure - rm_f tmpfile if File.exist? tmpfile + def invoke + run_metaconfigs + case task = parsearg_global() + when nil, 'all' + parsearg_config + init_installers + exec_config + exec_setup + exec_install + else + case task + when 'config', 'test' + ; + when 'clean', 'distclean' + @config.load_savefile if File.exist?(@config.savefile) + else + @config.load_savefile + end + __send__ "parsearg_#{task}" + init_installers + __send__ "exec_#{task}" end end - - def setup_dir_lib( relpath ) - end - - def setup_dir_ext( relpath ) - make if extdir?(curr_srcdir) + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig" end - def setup_dir_data( relpath ) + def init_installers + @installer = Installer.new(@config, @ardir, File.expand_path('.')) end # - # TASK install + # Hook Script API bases # - def exec_install - exec_task_traverse 'install' - end - - def install_dir_bin( rel ) - install_files target_filenames(), config('bin-dir') + '/' + rel, 0755 + def srcdir_root + @ardir end - def install_dir_lib( rel ) - install_files target_filenames(), config('rb-dir') + '/' + rel, 0644 + def objdir_root + '.' end - def install_dir_ext( rel ) - install_dir_ext_main File.dirname(rel) if extdir?(curr_srcdir) + def relpath + '.' end - def install_dir_ext_main( rel ) - install_files allext('.'), config('so-dir') + '/' + rel, 0555 + # + # Option Parsing + # + + def parsearg_global + while arg = ARGV.shift + case arg + when /\A\w+\z/ + setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) + return arg + when '-q', '--quiet' + @config.verbose = false + when '--verbose' + @config.verbose = true + when '--help' + print_usage $stdout + exit 0 + when '--version' + puts "#{File.basename($0)} version #{Version}" + exit 0 + when '--copyright' + puts Copyright + exit 0 + else + setup_rb_error "unknown global option '#{arg}'" + end + end + nil end - def install_dir_data( rel ) - install_files target_filenames(), config('data-dir') + '/' + rel, 0644 + def valid_task?(t) + valid_task_re() =~ t end - def install_files( list, dest, mode ) - mkdir_p dest, @options['install-prefix'] - list.each do |fname| - install fname, dest, mode, @options['install-prefix'] + def valid_task_re + @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ + end + + def parsearg_no_options + unless ARGV.empty? + task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) + setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" end end - def target_filenames - if FileTest.file? "#{curr_srcdir()}/MANIFEST" - mapdir(target_filenames_MANIFEST()) - else - mapdir(target_filenames_AUTO()) + alias parsearg_show parsearg_no_options + alias parsearg_setup parsearg_no_options + alias parsearg_test parsearg_no_options + alias parsearg_clean parsearg_no_options + alias parsearg_distclean parsearg_no_options + + def parsearg_config + evalopt = [] + set = [] + @config.config_opt = [] + while i = ARGV.shift + if /\A--?\z/ =~ i + @config.config_opt = ARGV.dup + break + end + name, value = *@config.parse_opt(i) + if @config.value_config?(name) + @config[name] = value + else + evalopt.push [name, value] + end + set.push name + end + evalopt.each do |name, value| + @config.lookup(name).evaluate value, @config + end + # Check if configuration is valid + set.each do |n| + @config[n] if @config.value_config?(n) end end - def mapdir( filelist ) - filelist.map {|fname| - if File.exist? fname # current objdir == '.' - fname - else - File.join(curr_srcdir(), fname) - end - } + def parsearg_install + @config.no_harm = false + @config.install_prefix = '' + while a = ARGV.shift + case a + when '--no-harm' + @config.no_harm = true + when /\A--prefix=/ + path = a.split(/=/, 2)[1] + path = File.expand_path(path) unless path[0,1] == '/' + @config.install_prefix = path + else + setup_rb_error "install: unknown option #{a}" + end + end end - def target_filenames_MANIFEST - File.read_all("#{curr_srcdir()}/MANIFEST").split + def print_usage(out) + out.puts 'Typical Installation Procedure:' + out.puts " $ ruby #{File.basename $0} config" + out.puts " $ ruby #{File.basename $0} setup" + out.puts " # ruby #{File.basename $0} install (may require root privilege)" + out.puts + out.puts 'Detailed Usage:' + out.puts " ruby #{File.basename $0} <global option>" + out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]" + + fmt = " %-24s %s\n" + out.puts + out.puts 'Global options:' + out.printf fmt, '-q,--quiet', 'suppress message outputs' + out.printf fmt, ' --verbose', 'output messages verbosely' + out.printf fmt, ' --help', 'print this message' + out.printf fmt, ' --version', 'print version and quit' + out.printf fmt, ' --copyright', 'print copyright and quit' + out.puts + out.puts 'Tasks:' + TASKS.each do |name, desc| + out.printf fmt, name, desc + end + + fmt = " %-24s %s [%s]\n" + out.puts + out.puts 'Options for CONFIG or ALL:' + @config.each do |item| + out.printf fmt, item.help_opt, item.description, item.help_default + end + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" + out.puts + out.puts 'Options for INSTALL:' + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' + out.printf fmt, '--prefix=path', 'install path prefix', '' + out.puts end - - # picked up many entries from cvs-1.11.1/src/ignore.c - REJECT_PATTERNS = %w( - core RCSLOG tags TAGS .make.state - .nse_depinfo #* .#* cvslog.* ,* .del-* *.a *.olb *.o *.obj - *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$ - - *.org *.in .* - ).map {|pattern| - Regexp.compile('\A' + pattern.gsub(/[\.\$]/) {|s| '\\' + s }.gsub(/\*/, '.*') + '\z') - } - def target_filenames_AUTO - (existfiles() - hookfiles()).reject {|fname| - REJECT_PATTERNS.any? {|re| re === fname } - } + # + # Task Handlers + # + + def exec_config + @installer.exec_config + @config.save # must be final end - def existfiles - all_files_in(curr_srcdir()) | all_files_in(curr_objdir()) + def exec_setup + @installer.exec_setup end - def hookfiles - %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| - %w( config setup install clean ).map {|t| sprintf(fmt, t) } - }.flatten + def exec_install + @installer.exec_install end - def allext( dir ) - _allext(dir) or raise InstallError, - "no extention exists: Have you done 'ruby #{$0} setup' ?" + def exec_test + @installer.exec_test end - DLEXT = /\.#{ ::Config::CONFIG['DLEXT'] }\z/ + def exec_show + @config.each do |i| + printf "%-20s %s\n", i.name, i.value if i.value? + end + end - def _allext( dir ) - Dir.open(dir) {|d| - return d.select {|fname| DLEXT === fname } - } + def exec_clean + @installer.exec_clean end - # - # TASK clean - # + def exec_distclean + @installer.exec_distclean + end - def exec_clean - exec_task_traverse 'clean' - rm_f 'config.save' - rm_f 'InstalledFiles' +end # class ToplevelInstaller + + +class ToplevelInstallerMulti < ToplevelInstaller + + include FileOperations + + def initialize(ardir_root, config) + super + @packages = directories_of("#{@ardir}/packages") + raise 'no package exists' if @packages.empty? + @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) end - def clean_dir_bin( rel ) + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig", self + @packages.each do |name| + @config.load_script "#{@ardir}/packages/#{name}/metaconfig" + end end - def clean_dir_lib( rel ) + attr_reader :packages + + def packages=(list) + raise 'package list is empty' if list.empty? + list.each do |name| + raise "directory packages/#{name} does not exist"\ + unless File.dir?("#{@ardir}/packages/#{name}") + end + @packages = list end - def clean_dir_ext( rel ) - make 'clean' if FileTest.file?('Makefile') + def init_installers + @installers = {} + @packages.each do |pack| + @installers[pack] = Installer.new(@config, + "#{@ardir}/packages/#{pack}", + "packages/#{pack}") + end + with = extract_selection(config('with')) + without = extract_selection(config('without')) + @selected = @installers.keys.select {|name| + (with.empty? or with.include?(name)) \ + and not without.include?(name) + } + end + + def extract_selection(list) + a = list.split(/,/) + a.each do |name| + setup_rb_error "no such package: #{name}" unless @installers.key?(name) + end + a end - def clean_dir_data( rel ) + def print_usage(f) + super + f.puts 'Inluded packages:' + f.puts ' ' + @packages.sort.join(' ') + f.puts end # - # TASK distclean + # Task Handlers # - def exec_distclean - exec_task_traverse 'distclean' - rm_f 'config.save' - rm_f 'InstalledFiles' + def exec_config + run_hook 'pre-config' + each_selected_installers {|inst| inst.exec_config } + run_hook 'post-config' + @config.save # must be final + end + + def exec_setup + run_hook 'pre-setup' + each_selected_installers {|inst| inst.exec_setup } + run_hook 'post-setup' end - def distclean_dir_bin( rel ) + def exec_install + run_hook 'pre-install' + each_selected_installers {|inst| inst.exec_install } + run_hook 'post-install' end - def distclean_dir_lib( rel ) + def exec_test + run_hook 'pre-test' + each_selected_installers {|inst| inst.exec_test } + run_hook 'post-test' end - def distclean_dir_ext( rel ) - make 'distclean' if FileTest.file?('Makefile') + def exec_clean + rm_f @config.savefile + run_hook 'pre-clean' + each_selected_installers {|inst| inst.exec_clean } + run_hook 'post-clean' + end + + def exec_distclean + rm_f @config.savefile + run_hook 'pre-distclean' + each_selected_installers {|inst| inst.exec_distclean } + run_hook 'post-distclean' end # # lib # - - def make( task = '' ) - command config('make-prog') + ' ' + task - end - def exec_task_traverse( task ) - run_hook 'pre-' + task - FILETYPES.each do |type| - if config('without-ext') == 'yes' and type == 'ext' - $stderr.puts 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, task + '_dir_' + type + def each_selected_installers + Dir.mkdir 'packages' unless File.dir?('packages') + @selected.each do |pack| + $stderr.puts "Processing the package `#{pack}' ..." if verbose? + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") + Dir.chdir "packages/#{pack}" + yield @installers[pack] + Dir.chdir '../..' end - run_hook 'post-' + task end - def traverse( task, rel, mid ) - dive_into(rel) { - run_hook 'pre-' + task - __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') - all_dirs_in(curr_srcdir()).each do |d| - traverse task, rel + '/' + d, mid - end - run_hook 'post-' + task - } + def run_hook(id) + @root_installer.run_hook id end - def run_hook( name ) - try_run_hook curr_srcdir + '/' + name or - try_run_hook curr_srcdir + '/' + name + '.rb' + # module FileOperations requires this + def verbose? + @config.verbose? end - def try_run_hook( fname ) - return false unless FileTest.file?(fname) + # module FileOperations requires this + def no_harm? + @config.no_harm? + end - env = self.dup - begin - env.instance_eval File.read_all(fname), fname, 1 - rescue - raise InstallError, "hook #{fname} failed:\n" + $!.message - end - true +end # class ToplevelInstallerMulti + + +class Installer + + FILETYPES = %w( bin lib ext data conf man ) + + include FileOperations + include HookScriptAPI + + def initialize(config, srcroot, objroot) + @config = config + @srcdir = File.expand_path(srcroot) + @objdir = File.expand_path(objroot) + @currdir = '.' end - def extdir?( dir ) - File.exist? dir + '/MANIFEST' + def inspect + "#<#{self.class} #{File.basename(@srcdir)}>" end -end + def noop(rel) + end -### end base.rb -### begin toplevel.rb + # + # Hook Script API base methods + # -class ToplevelInstaller < Installer + def srcdir_root + @srcdir + end - def self.invoke - new(File.dirname($0)).invoke + def objdir_root + @objdir end + def relpath + @currdir + end - TASKS = [ - [ 'config', 'saves your configurations' ], - [ 'show', 'shows current configuration' ], - [ 'setup', 'compiles extention or else' ], - [ 'install', 'installs files' ], - [ 'clean', "does `make clean' for each extention" ], - [ 'distclean',"does `make distclean' for each extention" ] - ] + # + # Config Access + # + # module FileOperations requires this + def verbose? + @config.verbose? + end - def initialize( root ) - super nil, {'verbose' => true}, root, '.' - Installer.declare_toplevel_installer self + # module FileOperations requires this + def no_harm? + @config.no_harm? end + def verbose_off + begin + save, @config.verbose = @config.verbose?, false + yield + ensure + @config.verbose = save + end + end - def invoke - run_metaconfigs + # + # TASK config + # - case task = parsearg_global() - when 'config' - @config = ConfigTable.new - else - @config = ConfigTable.load - end - parsearg_TASK task + def exec_config + exec_task_traverse 'config' + end + + alias config_dir_bin noop + alias config_dir_lib noop - exectask task + def config_dir_ext(rel) + extconf if extdir?(curr_srcdir()) end - include MetaConfigAPI + alias config_dir_data noop + alias config_dir_conf noop + alias config_dir_man noop - def run_metaconfigs - eval_file_ifexist "#{srcdir_root()}/metaconfig" + def extconf + ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt + end + + # + # TASK setup + # + + def exec_setup + exec_task_traverse 'setup' + end + + def setup_dir_bin(rel) + files_of(curr_srcdir()).each do |fname| + update_shebang_line "#{curr_srcdir()}/#{fname}" + end end + alias setup_dir_lib noop + + def setup_dir_ext(rel) + make if extdir?(curr_srcdir()) + end + + alias setup_dir_data noop + alias setup_dir_conf noop + alias setup_dir_man noop + + def update_shebang_line(path) + return if no_harm? + return if config('shebang') == 'never' + old = Shebang.load(path) + if old + $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 + new = new_shebang(old) + return if new.to_s == old.to_s + else + return unless config('shebang') == 'all' + new = Shebang.new(config('rubypath')) + end + $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? + open_atomic_writer(path) {|output| + File.open(path, 'rb') {|f| + f.gets if old # discard + output.puts new.to_s + output.print f.read + } + } + end - def exectask( task ) - if task == 'show' - exec_show + def new_shebang(old) + if /\Aruby/ =~ File.basename(old.cmd) + Shebang.new(config('rubypath'), old.args) + elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' + Shebang.new(config('rubypath'), old.args[1..-1]) else - try task + return old unless config('shebang') == 'all' + Shebang.new(config('rubypath')) end end - def try( task ) - $stderr.printf "#{File.basename $0}: entering %s phase...\n", task if verbose? + def open_atomic_writer(path, &block) + tmpfile = File.basename(path) + '.tmp' begin - __send__ 'exec_' + task - rescue - $stderr.printf "%s failed\n", task - raise + File.open(tmpfile, 'wb', &block) + File.rename tmpfile, File.basename(path) + ensure + File.unlink tmpfile if File.exist?(tmpfile) + end + end + + class Shebang + def Shebang.load(path) + line = nil + File.open(path) {|f| + line = f.gets + } + return nil unless /\A#!/ =~ line + parse(line) + end + + def Shebang.parse(line) + cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') + new(cmd, args) + end + + def initialize(cmd, args = []) + @cmd = cmd + @args = args + end + + attr_reader :cmd + attr_reader :args + + def to_s + "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") end - $stderr.printf "#{File.basename $0}: %s done.\n", task if verbose? end # - # processing arguments + # TASK install # - def parsearg_global - task_re = /\A(?:#{TASKS.map {|i| i[0] }.join '|'})\z/ + def exec_install + rm_f 'InstalledFiles' + exec_task_traverse 'install' + end - while arg = ARGV.shift - case arg - when /\A\w+\z/ - task_re === arg or raise InstallError, "wrong task: #{arg}" - return arg + def install_dir_bin(rel) + install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 + end - when '-q', '--quiet' - @options['verbose'] = false + def install_dir_lib(rel) + install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 + end - when '--verbose' - @options['verbose'] = true + def install_dir_ext(rel) + return unless extdir?(curr_srcdir()) + install_files rubyextentions('.'), + "#{config('sodir')}/#{File.dirname(rel)}", + 0555 + end - when '-h', '--help' - print_usage $stdout - exit 0 + def install_dir_data(rel) + install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 + end - when '-v', '--version' - puts "#{File.basename $0} version #{Version}" - exit 0 - - when '--copyright' - puts Copyright - exit 0 + def install_dir_conf(rel) + # FIXME: should not remove current config files + # (rename previous file to .old/.org) + install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 + end - else - raise InstallError, "unknown global option '#{arg}'" - end - end + def install_dir_man(rel) + install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 + end - raise InstallError, "No task or global option given. -Typical installation procedure is: - $ ruby #{File.basename $0} config - $ ruby #{File.basename $0} setup - # ruby #{File.basename $0} install (may require root privilege) -" + def install_files(list, dest, mode) + mkdir_p dest, @config.install_prefix + list.each do |fname| + install fname, dest, mode, @config.install_prefix + end end + def libfiles + glob_reject(%w(*.y *.output), targetfiles()) + end - def parsearg_TASK( task ) - mid = "parsearg_#{task}" - if respond_to? mid, true - __send__ mid - else - ARGV.empty? or - raise InstallError, "#{task}: unknown options: #{ARGV.join ' '}" + def rubyextentions(dir) + ents = glob_select("*.#{@config.dllext}", targetfiles()) + if ents.empty? + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" end + ents end - def parsearg_config - re = /\A--(#{ConfigTable.keys.join '|'})(?:=(.*))?\z/ - @options['config-opt'] = [] + def targetfiles + mapdir(existfiles() - hookfiles()) + end - while i = ARGV.shift - if /\A--?\z/ === i - @options['config-opt'] = ARGV.dup - break - end - m = re.match(i) or raise InstallError, "config: unknown option #{i}" - name, value = m.to_a[1,2] - if value - if ConfigTable.bool_config?(name) - /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i === value or raise InstallError, "config: --#{name} allows only yes/no for argument" - value = (/\Ay(es)?|\At(rue)/i === value) ? 'yes' : 'no' - end - else - ConfigTable.bool_config?(name) or raise InstallError, "config: --#{name} requires argument" - value = 'yes' + def mapdir(ents) + ents.map {|ent| + if File.exist?(ent) + then ent # objdir + else "#{curr_srcdir()}/#{ent}" # srcdir end - @config[name] = value - end + } end - def parsearg_install - @options['no-harm'] = false - @options['install-prefix'] = '' - while a = ARGV.shift - case a - when /\A--no-harm\z/ - @options['no-harm'] = true - when /\A--prefix=(.*)\z/ - path = $1 - path = File.expand_path(path) unless path[0,1] == '/' - @options['install-prefix'] = path - else - raise InstallError, "install: unknown option #{a}" - end - end + # picked up many entries from cvs-1.11.1/src/ignore.c + JUNK_FILES = %w( + core RCSLOG tags TAGS .make.state + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ + + *.org *.in .* + ) + + def existfiles + glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) end + def hookfiles + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| + %w( config setup install clean ).map {|t| sprintf(fmt, t) } + }.flatten + end - def print_usage( out ) - out.puts 'Typical Installation Procedure:' - out.puts " $ ruby #{File.basename $0} config" - out.puts " $ ruby #{File.basename $0} setup" - out.puts " # ruby #{File.basename $0} install (may require root privilege)" - out.puts - out.puts 'Detailed Usage:' - out.puts " ruby #{File.basename $0} <global option>" - out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]" + def glob_select(pat, ents) + re = globs2re([pat]) + ents.select {|ent| re =~ ent } + end - fmt = " %-20s %s\n" - out.puts - out.puts 'Global options:' - out.printf fmt, '-q,--quiet', 'suppress message outputs' - out.printf fmt, ' --verbose', 'output messages verbosely' - out.printf fmt, '-h,--help', 'print this message' - out.printf fmt, '-v,--version', 'print version and quit' - out.printf fmt, ' --copyright', 'print copyright and quit' + def glob_reject(pats, ents) + re = globs2re(pats) + ents.reject {|ent| re =~ ent } + end - out.puts - out.puts 'Tasks:' - TASKS.each do |name, desc| - out.printf " %-10s %s\n", name, desc - end + GLOB2REGEX = { + '.' => '\.', + '$' => '\$', + '#' => '\#', + '*' => '.*' + } - out.puts - out.puts 'Options for config:' - ConfigTable.each_definition do |name, (default, arg, desc, default2)| - out.printf " %-20s %s [%s]\n", - '--'+ name + (ConfigTable.bool_config?(name) ? '' : '='+arg), - desc, - default2 || default + def globs2re(pats) + /\A(?:#{ + pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') + })\z/ + end + + # + # TASK test + # + + TESTDIR = 'test' + + def exec_test + unless File.directory?('test') + $stderr.puts 'no test in this package' if verbose? + return + end + $stderr.puts 'Running tests...' if verbose? + begin + require 'test/unit' + rescue LoadError + setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' end - out.printf " %-20s %s [%s]\n", - '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's" + runner = Test::Unit::AutoRunner.new(true) + runner.to_run << TESTDIR + runner.run + end - out.puts - out.puts 'Options for install:' - out.printf " %-20s %s [%s]\n", - '--no-harm', 'only display what to do if given', 'off' - out.printf " %-20s %s [%s]\n", - '--prefix', 'install path prefix', '$prefix' + # + # TASK clean + # - out.puts + def exec_clean + exec_task_traverse 'clean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias clean_dir_bin noop + alias clean_dir_lib noop + alias clean_dir_data noop + alias clean_dir_conf noop + alias clean_dir_man noop + + def clean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'clean' if File.file?('Makefile') end # - # config + # TASK distclean # - def exec_config - super - @config.save + def exec_distclean + exec_task_traverse 'distclean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias distclean_dir_bin noop + alias distclean_dir_lib noop + + def distclean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'distclean' if File.file?('Makefile') end + alias distclean_dir_data noop + alias distclean_dir_conf noop + alias distclean_dir_man noop + # - # show + # Traversing # - def exec_show - ConfigTable.each_name do |k| - v = @config.get_raw(k) - if not v or v.empty? - v = '(not specified)' + def exec_task_traverse(task) + run_hook "pre-#{task}" + FILETYPES.each do |type| + if type == 'ext' and config('without-ext') == 'yes' + $stderr.puts 'skipping ext/* by user option' if verbose? + next end - printf "%-10s %s\n", k, v + traverse task, type, "#{task}_dir_#{type}" end + run_hook "post-#{task}" end -end + def traverse(task, rel, mid) + dive_into(rel) { + run_hook "pre-#{task}" + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') + directories_of(curr_srcdir()).each do |d| + traverse task, "#{rel}/#{d}", mid + end + run_hook "post-#{task}" + } + end + + def dive_into(rel) + return unless File.dir?("#{@srcdir}/#{rel}") + + dir = File.basename(rel) + Dir.mkdir dir unless File.dir?(dir) + prevdir = Dir.pwd + Dir.chdir dir + $stderr.puts '---> ' + rel if verbose? + @currdir = rel + yield + Dir.chdir prevdir + $stderr.puts '<--- ' + rel if verbose? + @currdir = File.dirname(rel) + end -### end toplevel.rb + def run_hook(id) + path = [ "#{curr_srcdir()}/#{id}", + "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } + return unless path + begin + instance_eval File.read(path), path, 1 + rescue + raise if $DEBUG + setup_rb_error "hook #{path} failed:\n" + $!.message + end + end + +end # class Installer + + +class SetupError < StandardError; end + +def setup_rb_error(msg) + raise SetupError, msg +end if $0 == __FILE__ begin ToplevelInstaller.invoke - rescue + rescue SetupError raise if $DEBUG $stderr.puts $!.message $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." diff --git a/lib/fox16/aliases.rb b/lib/fox16/aliases.rb index 4b2d427..a4d08c3 100755 --- a/lib/fox16/aliases.rb +++ b/lib/fox16/aliases.rb @@ -2849,6 +2849,9 @@ module Fox def activeChild(*args) # :nodoc: getActiveChild(*args) end + def activeChild=(*args) # :nodoc: + setActiveChild(*args) + end def cascadeX=(*args) # :nodoc: setCascadeX(*args) end @@ -3571,6 +3574,7 @@ module Fox def position=(*args) # :nodoc: setPosition(*args) end + undef_method(:position) if defined?(:position) def position # :nodoc: getPosition end @@ -4382,6 +4386,18 @@ module Fox def rowHeaderMode=(hint) # :nodoc: setRowHeaderMode(hint) end + def columnHeaderFont # :nodoc: + getColumnHeaderFont + end + def columnHeaderFont=(f) # :nodoc: + setColumnHeaderFont(f) + end + def rowHeaderFont # :nodoc: + getRowHeaderFont + end + def rowHeaderFont=(f) # :nodoc: + setRowHeaderFont(f) + end def columnHeaderHeight # :nodoc: getColumnHeaderHeight() end @@ -4764,6 +4780,7 @@ module Fox def editable?(*args) # :nodoc: isEditable(*args) end + alias :editable :editable? def editable=(*args) # :nodoc: setEditable(*args) end diff --git a/lib/fox16/chore.rb b/lib/fox16/chore.rb index 117d02f..36c744b 100755 --- a/lib/fox16/chore.rb +++ b/lib/fox16/chore.rb @@ -1,4 +1,5 @@ module Fox + class FXApp alias addChoreOrig addChore # :nodoc: @@ -26,29 +27,41 @@ module Fox # # The last form takes a block: # - # app.addChore() { |sender, sel, data| + # app.addChore() do |sender, sel, data| # ... handle the chore ... - # } + # end # # All of these return a reference to an opaque FXChore instance that # can be passed to #removeChore if it is necessary to remove the chore # before it fires. # + # For the last two forms, you can pass in the optional +:repeat+ parameter to + # cause the chore to be re-registered after it fires, e.g. + # + # chore = app.addChore(:repeat => true) do |sender, sel, data| + # ... handle the chore ... + # ... re-add the chore ... + # end + # def addChore(*args, &block) + params = {} + params = args.pop if args.last.is_a? Hash tgt, sel = nil, 0 if args.length > 0 if args[0].respond_to? :call - tgt = FXPseudoTarget.new - tgt.pconnect(SEL_CHORE, args[0], block) + tgt = params[:target] || FXPseudoTarget.new + tgt.pconnect(SEL_CHORE, args[0], params) else - tgt, sel = args[0], args[1] + tgt, sel = args[0], args[1] end else - tgt = FXPseudoTarget.new - tgt.pconnect(SEL_CHORE, nil, block) + tgt = params[:target] || FXPseudoTarget.new + tgt.pconnect(SEL_CHORE, block, params) end addChoreOrig(tgt, sel) - return { :target => tgt, :selector => sel } + params[:target] = tgt + params[:selector] = sel + params end # @@ -60,8 +73,8 @@ module Fox if args.length == 2 removeChoreOrig(args[0], args[1]) else - hsh = args[0] - removeChoreOrig(hsh[:target], hsh[:selector]) + params = args[0] + removeChoreOrig(params[:target], params[:selector]) end end @@ -87,5 +100,6 @@ module Fox end end - end -end + end # class FXApp + +end # module Fox diff --git a/lib/fox16/core.rb b/lib/fox16/core.rb index 1437b41..041a586 100755 --- a/lib/fox16/core.rb +++ b/lib/fox16/core.rb @@ -182,6 +182,25 @@ module Fox end end end + + class FXHiliteStyle + # + # Construct a new FXHiliteStyle instance, with fields initialized from + # an FXText instance. + # + def FXHiliteStyle.from_text(textw) + hs = new + hs.activeBackColor = textw.activeBackColor + hs.hiliteBackColor = textw.hiliteBackColor + hs.hiliteForeColor = textw.hiliteTextColor + hs.normalBackColor = textw.backColor + hs.normalForeColor = textw.textColor + hs.selectBackColor = textw.selBackColor + hs.selectForeColor = textw.selTextColor + hs.style = 0 + hs + end + end class FXScrollArea # Returns a reference to the scroll corner (an FXScrollCorner instance) for this window. @@ -218,6 +237,8 @@ module Fox def to_s to_a.to_s end + + def inspect; to_a.inspect; end end class FXVec2f @@ -226,6 +247,8 @@ module Fox # Convert to string def to_s; to_a.to_s; end + + def inspect; to_a.inspect; end end class FXVec3d @@ -234,6 +257,8 @@ module Fox # Convert to string def to_s; to_a.to_s; end + + def inspect; to_a.inspect; end end class FXVec3f @@ -242,6 +267,8 @@ module Fox # Convert to string def to_s; to_a.to_s; end + + def inspect; to_a.inspect; end end class FXVec4d @@ -250,6 +277,8 @@ module Fox # Convert to string def to_s; to_a.to_s; end + + def inspect; to_a.inspect; end end class FXVec4f @@ -258,20 +287,39 @@ module Fox # Convert to string def to_s; to_a.to_s; end + + def inspect; to_a.inspect; end end class FXWindow # # Iterate over the child windows for this window. + # Note that this only reaches the direct child windows for this window + # and no deeper descendants. To traverse the entire widget tree, + # use #each_child_recursive. # - def each_child + def each_child # :yields: child child = self.first while child next_child = child.next yield child - child = next_child + child = next_child + end + end + + # + # Traverse the widget tree starting from this window + # using depth-first traversal. + # + def each_child_recursive # :yields: child + each_child do |child| + yield child + child.each_child_recursive do |subchild| + yield subchild + end end end + # Returns an array containing all child windows of this window def children @@ -447,9 +495,7 @@ module Fox # Create input control for editing this item def getControlFor(table) - combo = FXComboBox.new(table, 1, nil, 0, COMBOBOX_STATIC, 0, 0, 0, 0, - table.marginLeft, table.marginRight, - table.marginTop, table.marginBottom) + combo = FXComboBox.new(table, 1, :opts => COMBOBOX_STATIC, :padLeft => table.marginLeft, :padRight => table.marginRight, :padTop => table.marginTop, :padBottom => table.marginBottom) combo.create justify = 0 justify |= JUSTIFY_LEFT if (self.justify & FXTableItem::LEFT) != 0 @@ -539,6 +585,13 @@ module Fox self.checkState == MAYBE end end + + class FXObject + require 'enumerator' + def self.subclasses + ObjectSpace.enum_for(:each_object, class << self; self; end).to_a + end + end class FXDC # @@ -607,6 +660,41 @@ module Fox def selectItem(row, col, notify=false) selectRange(row, row, col, col, notify) end + +=begin + + # Deselect cell at (_row_, _col_). + # If _notify_ is +true+, a +SEL_DESELECTED+ message is sent to the table's message target + # after the item is deselected. + # Raises IndexError if either _row_ or _col_ is out of bounds. + # + def deselectItem(row, col, notify=false) + raise IndexError, "row index out of bounds" if row < 0 || row >= numRows + raise IndexError, "column index out of bounds" if col < 0 || col >= numColumns + deselectRange(row, row, col, col, notify) + end + + # Deselect range. + # If _notify_ is +true+, a +SEL_DESELECTED+ message is sent to the table's message + # target for each previously selected cell that becomes deselected as a result of + # this operation. + # Raises IndexError if _startRow_, _endRow_, _startColumn_ or _endColumn_ is out of bounds. + def deselectRange(startRow, endRow, startColumn, endColumn, notify=false) + raise IndexError, "starting row index out of bounds" if startRow < 0 || startRow >= numRows + raise IndexError, "ending row index out of bounds" if endRow < 0 || endRow >= numRows + raise IndexError, "starting column index out of bounds" if startColumn < 0 || startColumn >= numColumns + raise IndexError, "ending column index out of bounds" if endColumn < 0 || endColumn >= numColumns + changes = false + for row in startRow..endRow + for col in startColumn..endColumn + changes |= deselectItem(row, col, notify) + end + end + changes + end + +=end + end end diff --git a/lib/fox16/exceptions_for_fxerror.rb b/lib/fox16/exceptions_for_fxerror.rb new file mode 100644 index 0000000..5cc5561 --- /dev/null +++ b/lib/fox16/exceptions_for_fxerror.rb @@ -0,0 +1,17 @@ +module Fox + FXWindow.subclasses.each do |klass| + klass.send(:alias_method, :create_without_parent_created_check, :create) + klass.send(:define_method, :create) do + unless parent.created? + raise RuntimeError, "trying to create window before creating parent window" + end + if owner && !owner.created? + raise RuntimeError, "trying to create window before creating owner window" + end + if visual.nil? + raise RuntimeError, "trying to create window without a visual" + end + create_without_parent_created_check + end + end +end diff --git a/lib/fox16/input.rb b/lib/fox16/input.rb index 55fa059..4fbd87b 100755 --- a/lib/fox16/input.rb +++ b/lib/fox16/input.rb @@ -1,4 +1,5 @@ module Fox + class FXApp alias addInputOrig addInput # :nodoc: @@ -31,24 +32,28 @@ module Fox # def addInput(fd, mode, *args, &block) + params = {} + params = args.pop if args.last.is_a? Hash tgt, sel = nil, 0 if args.length > 0 if args[0].respond_to? :call tgt = FXPseudoTarget.new - tgt.pconnect(SEL_IO_READ, args[0], block) - tgt.pconnect(SEL_IO_WRITE, args[0], block) - tgt.pconnect(SEL_IO_EXCEPT, args[0], block) + tgt.pconnect(SEL_IO_READ, args[0], params) + tgt.pconnect(SEL_IO_WRITE, args[0], params) + tgt.pconnect(SEL_IO_EXCEPT, args[0], params) else # it's some other kind of object tgt = args[0] sel = args[1] end else tgt = FXPseudoTarget.new - tgt.pconnect(SEL_IO_READ, nil, block) - tgt.pconnect(SEL_IO_WRITE, nil, block) - tgt.pconnect(SEL_IO_EXCEPT, nil, block) + tgt.pconnect(SEL_IO_READ, block, params) + tgt.pconnect(SEL_IO_WRITE, block, params) + tgt.pconnect(SEL_IO_EXCEPT, block, params) end addInputOrig(fd, mode, tgt, sel) end - end -end + + end # class FXApp + +end # module Fox diff --git a/lib/fox16/iterators.rb b/lib/fox16/iterators.rb index e521c43..0135075 100755 --- a/lib/fox16/iterators.rb +++ b/lib/fox16/iterators.rb @@ -4,6 +4,13 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each item in the list, passing the item's text and # user data as parameters. @@ -25,7 +32,7 @@ module Fox # reference to that item as a parameter. # def each # :yields: aFoldingItem - current = first + current = firstItem while current != nil next_current = current.next yield current @@ -58,6 +65,13 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each item in the list, passing a reference to that # item as a parameter. @@ -90,6 +104,13 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each item in the list, passing a reference to that # item as a parameter. @@ -106,6 +127,13 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each item in the list, passing the item's text, # icon and user data as parameters. @@ -122,6 +150,13 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each row in the table, passing an array of # references (one element per column) as a parameter. @@ -178,12 +213,19 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each root-level tree item, passing a # reference to that item as a parameter. # def each # :yields: aTreeItem - current = first + current = firstItem while current != nil next_current = current.next yield current @@ -197,12 +239,19 @@ module Fox include Enumerable + # + # Override Enumerable#first with FXWindow#first for backwards compatibility. + # + def first + getFirst + end + # # Calls block once for each root-level tree item, passing a # reference to that item as a parameter. # def each # :yields: aTreeItem - current = first + current = firstItem while current != nil next_current = current.next yield current @@ -234,18 +283,18 @@ module Fox def FXFileStream.open(filename, save_or_load, size=8192, container=nil) # :yields: theFileStream fstream = FXFileStream.new(container) if fstream.open(filename, save_or_load, size) - if block_given? - begin - yield fstream - ensure - fstream.close - end - else - fstream - end + if block_given? + begin + yield fstream + ensure + fstream.close + end + else + fstream + end else # FXFileStream#open returned false, so report error - raise FXStreamError.makeStreamError(fstream.status) + raise FXStreamError.makeStreamError(fstream.status) end end end @@ -272,18 +321,18 @@ module Fox def FXMemoryStream.open(save_or_load, data, cont=nil) # :yields: theMemoryStream stream = FXMemoryStream.new(cont) if stream.open(save_or_load, data) - if block_given? - begin - yield stream - ensure - stream.close - end - else - stream - end + if block_given? + begin + yield stream + ensure + stream.close + end + else + stream + end else # FXFileStream#open returned false, so report error - raise FXStreamError.makeStreamError(stream.status) + raise FXStreamError.makeStreamError(stream.status) end end end @@ -318,10 +367,10 @@ module Fox beginWaitCursor0 if block_given? begin - yield - ensure - endWaitCursor - end + yield + ensure + endWaitCursor + end end end end @@ -339,10 +388,10 @@ module Fox result = beginPrint0(job) if block_given? begin - yield self - ensure - endPrint - end + yield self + ensure + endPrint + end else result end @@ -359,10 +408,10 @@ module Fox result = beginPage0(page) if block_given? begin - yield self - ensure - endPage - end + yield self + ensure + endPage + end else result end diff --git a/lib/fox16/pseudokeyboard.rb b/lib/fox16/pseudokeyboard.rb index 4a52e32..40792e8 100755 --- a/lib/fox16/pseudokeyboard.rb +++ b/lib/fox16/pseudokeyboard.rb @@ -1,11 +1,17 @@ module Fox # - # Based on a suggestion from Hugh Sasse on the fxruby-users mailing list, - # an FXPseudoKeyboard object provides a simple means to operate widgets + # An FXPseudoKeyboard object provides a simple means to operate widgets # programmatically, to aid test driven design. An FXPseudoKeyboard instance # can be pointed at an FXObject and will manage the sending of events to # it. # + # For example: + # + # textfield = FXTextField.new(...) + # pk = FXPseudoKeyboard.new(textfield) + # pk.doKeyPress # sends a SEL_KEYPRESS message to the textfield + # pk.doKeyRelease # sends a SEL_KEYRELEASE message to the textfield + # class FXPseudoKeyboard attr_accessor :target @@ -17,16 +23,16 @@ module Fox def doKeyPress unless @target.nil? evt = FXEvent.new - evt.type = Fox::SEL_KEYPRESS - @target.handle(self, Fox.MKUINT(0, Fox::SEL_KEYPRESS), evt) + evt.type = Fox::SEL_KEYPRESS + @target.handle(self, Fox.FXSEL(Fox::SEL_KEYPRESS, 0), evt) end end def doKeyRelease unless @target.nil? evt = FXEvent.new - evt.type = Fox::SEL_KEYRELEASE - @target.handle(self, Fox.MKUINT(0, Fox::SEL_KEYRELEASE), evt) + evt.type = Fox::SEL_KEYRELEASE + @target.handle(self, Fox.FXSEL(Fox::SEL_KEYRELEASE, 0), evt) end end end diff --git a/lib/fox16/pseudomouse.rb b/lib/fox16/pseudomouse.rb index 545dcc0..471524c 100755 --- a/lib/fox16/pseudomouse.rb +++ b/lib/fox16/pseudomouse.rb @@ -1,11 +1,16 @@ module Fox # - # Based on a suggestion from Hugh Sasse on the fxruby-users mailing list, - # an FXPseudoMouse object provides a simple means to operate widgets + # An FXPseudoMouse object provides a simple means to operate widgets # programmatically, to aid test driven design. An FXPseudoMouse instance # can be pointed at an FXObject and will manage the sending of events to # it. # + # For example: + # + # canvas = FXCanvas.new(...) + # pm = FXPseudoMouse.new(canvas) + # pm.doLeftButtonPress # sends a SEL_LEFTBUTTONPRESS message to the canvas + # class FXPseudoMouse < FXObject attr_accessor :target @@ -18,7 +23,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_MOTION - @target.handle(self, Fox.MKUINT(0, Fox::SEL_MOTION), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_MOTION, 0), evt) end end @@ -26,7 +31,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_MOUSEWHEEL - @target.handle(self, Fox.MKUINT(0, Fox::SEL_MOUSEWHEEL), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_MOUSEWHEEL, 0), evt) end end @@ -34,7 +39,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_LEFTBUTTONPRESS - @target.handle(self, Fox.MKUINT(0, Fox::SEL_LEFTBUTTONPRESS), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_LEFTBUTTONPRESS, 0), evt) end end @@ -42,7 +47,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_LEFTBUTTONRELEASE - @target.handle(self, Fox.MKUINT(0, Fox::SEL_LEFTBUTTONRELEASE), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_LEFTBUTTONRELEASE, 0), evt) end end @@ -50,7 +55,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_MIDDLEBUTTONPRESS - @target.handle(self, Fox.MKUINT(0, Fox::SEL_MIDDLEBUTTONPRESS), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_MIDDLEBUTTONPRESS, 0), evt) end end @@ -58,7 +63,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_MIDDLEBUTTONRELEASE - @target.handle(self, Fox.MKUINT(0, Fox::SEL_MIDDLEBUTTONRELEASE), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_MIDDLEBUTTONRELEASE, 0), evt) end end @@ -66,7 +71,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_RIGHTBUTTONPRESS - @target.handle(self, Fox.MKUINT(0, Fox::SEL_RIGHTBUTTONPRESS), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_RIGHTBUTTONPRESS, 0), evt) end end @@ -74,7 +79,7 @@ module Fox unless @target.nil? evt = FXEvent.new evt.type = Fox::SEL_RIGHTBUTTONRELEASE - @target.handle(self, Fox.MKUINT(0, Fox::SEL_RIGHTBUTTONRELEASE), evt) + @target.handle(self, Fox.FXSEL(Fox::SEL_RIGHTBUTTONRELEASE, 0), evt) end end end diff --git a/lib/fox16/responder2.rb b/lib/fox16/responder2.rb index b10c454..a73a2f7 100755 --- a/lib/fox16/responder2.rb +++ b/lib/fox16/responder2.rb @@ -21,30 +21,25 @@ module Fox # def initialize super - @blocks = {} + @context = {} end # # Store an association between a message of type - # _messageType_ with a callable object or a block. + # _message_type_ with a callable object. # - def pconnect(messageType, callableObject, block) - if callableObject.nil? - @blocks[messageType] = block - else - @blocks[messageType] = callableObject - end - FXMAPTYPE(messageType, :onHandleMsg) - - case messageType - when SEL_TIMEOUT - @@targets_of_pending_timers[self] = self - when SEL_CHORE - @@targets_of_pending_chores[self] = self - when SEL_SIGNAL - @@targets_of_pending_signals[self] = self - when SEL_IO_READ, SEL_IO_WRITE, SEL_IO_EXCEPT - @@targets_of_pending_inputs[self] = self + def pconnect(message_type, callable_object, params={}) + @context[message_type] = { :callable => callable_object, :params => params } + FXMAPTYPE(message_type, :onHandleMsg) + case message_type + when SEL_TIMEOUT + @@targets_of_pending_timers[self] = self + when SEL_CHORE + @@targets_of_pending_chores[self] = self + when SEL_SIGNAL + @@targets_of_pending_signals[self] = self + when SEL_IO_READ, SEL_IO_WRITE, SEL_IO_EXCEPT + @@targets_of_pending_inputs[self] = self end end @@ -53,18 +48,31 @@ module Fox # message data _ptr_. # def onHandleMsg(sender, sel, ptr) - messageType = Fox.FXSELTYPE(sel) - result = @blocks[messageType].call(sender, sel, ptr) - case messageType - when SEL_TIMEOUT - @@targets_of_pending_timers.delete(self) - when SEL_CHORE - @@targets_of_pending_chores.delete(self) + message_type = Fox.FXSELTYPE(sel) + ctx = @context[message_type] + callable_object = ctx[:callable] + params = ctx[:params] + result = callable_object.call(sender, sel, ptr) + case message_type + when SEL_TIMEOUT + if params[:repeat] + FXApp.instance.addTimeout(params[:delay], callable_object, params) + else + @@targets_of_pending_timers.delete(self) + end + when SEL_CHORE + if params[:repeat] + FXApp.instance.addChore(callable_object, params) + else + @@targets_of_pending_chores.delete(self) + end end result end - end -end + + end # class FXPseudoTarget + +end # module Fox # # The Responder2 module provides the #connect method, @@ -95,13 +103,14 @@ module Responder2 # will be "called" with three arguments (the sender, selector and # message data). # - def connect(messageType, callableObject=nil, &block) + def connect(message_type, callable_object=nil, &block) unless instance_variables.include?('@pseudoTarget') @pseudoTarget = Fox::FXPseudoTarget.new self.target = @pseudoTarget end - @pseudoTarget.pconnect(messageType, callableObject, block) + @pseudoTarget.pconnect(message_type, callable_object ? callable_object : block) end + end module Fox diff --git a/lib/fox16/signal.rb b/lib/fox16/signal.rb index 8c9a243..513f706 100755 --- a/lib/fox16/signal.rb +++ b/lib/fox16/signal.rb @@ -1,4 +1,5 @@ module Fox + class FXApp alias addSignalOrig addSignal # :nodoc: @@ -18,7 +19,7 @@ module Fox # the message to be sent when this signal is raised. # If _sendImmediately_ is +true+, the message will be sent to the target right away; # this should be used with extreme care as the application is interrupted - # at an unknown point it its execution. + # at an unknown point in its execution. # The _flags_ are to be set as per POSIX definitions. # # A second form of #addSignal takes a Method instance as its second argument: @@ -38,16 +39,18 @@ module Fox # def addSignal(sig, *args, &block) + params = {} + params = args.pop if args.last.is_a? Hash tgt, sel, immediate, flags = nil, 0, false, 0 if args.length > 0 if args[0].respond_to? :call tgt = FXPseudoTarget.new - tgt.pconnect(SEL_SIGNAL, args[0], block) + tgt.pconnect(SEL_SIGNAL, args[0], params) immediate = (args.length > 1) ? args[1] : false flags = (args.length > 2) ? args[2] : 0 elsif (args[0].kind_of? TrueClass) || (args[0].kind_of? FalseClass) tgt = FXPseudoTarget.new - tgt.pconnect(SEL_SIGNAL, nil, block) + tgt.pconnect(SEL_SIGNAL, block, params) immediate = args[0] flags = (args.length > 1) ? args[1] : 0 else # it's some other kind of object @@ -58,9 +61,11 @@ module Fox end else tgt = FXPseudoTarget.new - tgt.pconnect(SEL_SIGNAL, nil, block) + tgt.pconnect(SEL_SIGNAL, block, params) end addSignalOrig(sig, tgt, sel, immediate, flags) end - end -end + + end # class FXApp + +end # module Fox diff --git a/lib/fox16/timeout.rb b/lib/fox16/timeout.rb index ddead09..6aae9b6 100755 --- a/lib/fox16/timeout.rb +++ b/lib/fox16/timeout.rb @@ -1,4 +1,5 @@ module Fox + class FXApp alias addTimeoutOrig addTimeout # :nodoc: @@ -7,8 +8,8 @@ module Fox alias remainingTimeoutOrig remainingTimeout # :nodoc: # - # Add a timeout message to be sent to target object in _ms_ milliseconds; - # the timer fires only once after the interval expires. The last argument + # Add a timeout message to be sent to target object in _ms_ milliseconds. + # By default, the timer fires only once after the interval expires. The last argument # is optional user data which will be passed along as the _ptr_ argument of # the message handler. If a timer with the same target and message already exists, # it will be rescheduled. @@ -34,30 +35,43 @@ module Fox # # The last form of #addTimeout takes a block: # - # timeout = app.addTimeout(delay) { |sender, sel, data| + # timeout = app.addTimeout(delay) do |sender, sel, data| # ... handle the timeout ... - # } + # end # # All of these return a reference to an opaque object (actually, a hash) that # can be passed to #removeTimeout if it is necessary to remove the timeout # before it fires. # + # For the last two forms, you can pass in the optional +:repeat+ parameter to + # cause the timeout to be re-registered after it fires, e.g. + # + # timeout = app.addTimeout(delay, :repeat => true) do |sender, sel, data| + # ... handle the timeout ... + # ... re-add the timeout with the same delay ... + # end + # def addTimeout(ms, *args, &block) + params = {} + params = args.pop if args.last.is_a? Hash + params[:delay] = ms tgt, sel = nil, 0 if args.length > 0 if args[0].respond_to? :call - tgt = FXPseudoTarget.new - tgt.pconnect(SEL_TIMEOUT, args[0], nil) + tgt = params[:target] || FXPseudoTarget.new + tgt.pconnect(SEL_TIMEOUT, args[0], params) else # it's some other kind of object tgt = args[0] sel = args[1] end else - tgt = FXPseudoTarget.new - tgt.pconnect(SEL_TIMEOUT, nil, block) + tgt = params[:target] || FXPseudoTarget.new + tgt.pconnect(SEL_TIMEOUT, block, params) end addTimeoutOrig(tgt, sel, ms) - return { :target => tgt, :selector => sel } + params[:target] = tgt + params[:selector] = sel + params end # @@ -69,8 +83,8 @@ module Fox if args.length == 2 removeTimeoutOrig(args[0], args[1]) else - hsh = args[0] - removeTimeoutOrig(hsh[:target], hsh[:selector]) + params = args[0] + removeTimeoutOrig(params[:target], params[:selector]) end end @@ -116,5 +130,7 @@ module Fox remainingTimeoutOrig(hsh[:target], hsh[:selector]) end end - end -end + + end # class FXApp + +end # module Fox diff --git a/pre-config.rb.in b/pre-config.rb.in index 0040fbe..dd9c276 100755 --- a/pre-config.rb.in +++ b/pre-config.rb.in @@ -3,7 +3,8 @@ def search_directories dirs = [ "/usr/include/fox-1.6", "/usr/local/include/fox-1.6", - "/sw/include/fox-1.6" + "/sw/include/fox-1.6", + "/opt/local/include/fox-1.6" ] ARGV.each do |arg| if arg =~ /--with-fox-include/ @@ -19,7 +20,7 @@ end def fox_include_files_found? search_directories.each do |path| filename = File.join(path, "fxver.h") - return true if FileTest.exists?(filename) + return true if FileTest.exist?(filename) end false end @@ -43,7 +44,7 @@ end def installed_fox_version search_directories.each do |path| filename = File.join(path, "fxver.h") - if FileTest.exists?(filename) + if FileTest.exist?(filename) foxMajor, foxMinor, foxLevel = read_fox_version(filename) return [foxMajor, foxMinor, foxLevel].join('.') end diff --git a/rdoc-sources/FXButton.rb b/rdoc-sources/FXButton.rb index 85b333b..71da51f 100755 --- a/rdoc-sources/FXButton.rb +++ b/rdoc-sources/FXButton.rb @@ -14,7 +14,7 @@ module Fox # The option <tt>BUTTON_AUTOGRAY</tt> (<tt>BUTTON_AUTOHIDE</tt>) causes the button to be grayed # out (hidden) if its handler does not respond to the <tt>SEL_UPDATE</tt> message. # This is useful when messages are delegated, for example when using a - # multiple document interface, where the ultimaye destination of a message + # multiple document interface, where the ultimate destination of a message # can be changed. # # === Events diff --git a/rdoc-sources/FXComboBox.rb b/rdoc-sources/FXComboBox.rb index 1b5d3e3..42daa6a 100755 --- a/rdoc-sources/FXComboBox.rb +++ b/rdoc-sources/FXComboBox.rb @@ -106,6 +106,9 @@ module Fox def initialize(p, cols, target=nil, selector=0, opts=COMBOBOX_NORMAL, x=0, y=0, width=0, height=0, padLeft=DEFAULT_PAD, padRight=DEFAULT_PAD, padTop=DEFAULT_PAD, padBottom=DEFAULT_PAD) # :yields: theComboBox end + # Return the combo box text + def to_s; end + # Return +true+ if combobox is editable def editable?() ; end diff --git a/rdoc-sources/FXCursor.rb b/rdoc-sources/FXCursor.rb index 2afb7b8..591d405 100755 --- a/rdoc-sources/FXCursor.rb +++ b/rdoc-sources/FXCursor.rb @@ -48,7 +48,7 @@ module Fox # # Make cursor from FXColor pixels; cursor size should be 32x32 for portability! # - def initialize(a, src, msk, width=32, height=32, hotX=-1, hotY=-1) # :yields: theCursor + def initialize(a, pixels, width=32, height=32, hotX=-1, hotY=-1) # :yields: theCursor end # diff --git a/rdoc-sources/FXGroupBox.rb b/rdoc-sources/FXGroupBox.rb index 76b89dc..7941789 100755 --- a/rdoc-sources/FXGroupBox.rb +++ b/rdoc-sources/FXGroupBox.rb @@ -28,6 +28,9 @@ module Fox # Construct group box layout manager def initialize(parent, text, opts=GROUPBOX_NORMAL, x=0, y=0, width=0, height=0, padLeft=DEFAULT_SPACING, padRight=DEFAULT_SPACING, padTop=DEFAULT_SPACING, padBottom=DEFAULT_SPACING, hSpacing=DEFAULT_SPACING, vSpacing=DEFAULT_SPACING) # :yields: theGroupBox end + + # Return the group box's title text + def to_s; text; end end end diff --git a/rdoc-sources/FXHeader.rb b/rdoc-sources/FXHeader.rb index 04ccfae..052a6b0 100755 --- a/rdoc-sources/FXHeader.rb +++ b/rdoc-sources/FXHeader.rb @@ -57,6 +57,9 @@ module Fox def initialize(text, ic=nil, s=0, ptr=nil) # :yields: theHeaderItem end + # Return the header item's text label + def to_s; text; end + # Return the item's content width in the header. def getWidth(header); end diff --git a/rdoc-sources/FXIconDict.rb b/rdoc-sources/FXIconDict.rb index c758a51..3d6f3e5 100644 --- a/rdoc-sources/FXIconDict.rb +++ b/rdoc-sources/FXIconDict.rb @@ -21,7 +21,7 @@ module Fox # Construct icon dictionary, and set initial search path; also # creates a default icon source object. # - def initialize(app, path=defaultIconPath); + def initialize(app, path=FXIconDict.defaultIconPath); # Change icon source to _src_ (an FXIconSource instance). def iconSource=(src); end diff --git a/rdoc-sources/FXIconList.rb b/rdoc-sources/FXIconList.rb index 1f9051c..50f6d5f 100755 --- a/rdoc-sources/FXIconList.rb +++ b/rdoc-sources/FXIconList.rb @@ -28,6 +28,9 @@ module Fox # Constructor def initialize(text, bigIcon=nil, miniIcon=nil, data=nil) # :yields: theIconItem end + + # Return the icon item's text + def to_s; text; end # Set the focused state for this item (where _focus_ is either +true+ or +false+) def setFocus(focus); end diff --git a/rdoc-sources/FXImage.rb b/rdoc-sources/FXImage.rb index 0c4d6f0..771fc3f 100755 --- a/rdoc-sources/FXImage.rb +++ b/rdoc-sources/FXImage.rb @@ -113,7 +113,8 @@ module Fox def release(); end # - # Rescale pixels image to the specified width and height. Note that this + # Rescale pixels image to the specified width and height and then + # re-render the server-side image from the client-side pixel buffer. Note that this # serves a slightly different purpose than the base class resize() method, # which simply resizes the client-side pixel data buffer but doesn't # transform the image. @@ -132,7 +133,8 @@ module Fox def scale(w, h, quality=0) ; end # - # Mirror image horizontally and/or vertically. + # Mirror image horizontally and/or vertically and then re-render the + # server-side image from the client-side pixel buffer. # # ==== Parameters: # @@ -142,7 +144,8 @@ module Fox def mirror(horizontal, vertical) ; end # - # Rotate image counter-clockwise by some number of degrees. + # Rotate image counter-clockwise by some number of degrees and then + # re-render the server-side image from the client-side pixel buffer. # # ==== Parameters: # @@ -151,7 +154,8 @@ module Fox def rotate(degrees) ; end # - # Crop image to given rectangle; this calls resize() to adjust the client + # Crop image to given rectangle and then re-render the server-side image + # from the client-side pixel buffer. This method calls resize() to adjust the client # and server side representations. The new image may be smaller or larger # than the old one; blank areas are filled with color. There must be at # least one pixel of overlap between the old and the new image. @@ -165,6 +169,88 @@ module Fox # +color+:: fill color for blank areas after crop [FXColor] # def crop(x, y, w, h, color=0) ; end + + # Fill image with uniform color. + def fill(color); end + + # + # Fade an image to a certain color by a certain factor. The _factor_ is + # some integer value between 0 and 255 inclusive, where a factor of 255 indicates no fading and a factor + # of zero indicates that the image is completely faded to the fade _color_. + # + # ==== Parameters: + # + # +color+:: the fade color [FXColor] + # +factor+:: fading factor [Integer] + # + def fade(color, factor=255); end + + # + # Shear image horizontally and then re-render the server-side image + # from the client-side pixel buffer. The number of pixels is equal to the + # _shear_ parameter times 256. The area outside the image is filled + # with transparent black, unless another _color_ is specified. + # + # ==== Parameters: + # + # +shear+:: how far to shear [Integer] + # +color+:: fill color for areas outside the sheared image [FXColor] + # + def xshear(shear, color=0); end + + # + # Shear image verticallyand then re-render the server-side image + # from the client-side pixel buffer. The number of pixels is equal to the + # _shear_ parameter times 256. The area outside the image is filled + # with transparent black, unless another _color_ is specified. + # + # ==== Parameters: + # + # +shear+:: how far to shear [Integer] + # +color+:: fill color for areas outside the sheared image [FXColor] + # + def yshear(shear, color=0); end + + # + # Fill image using a horizontal gradient. + # + # ==== Parameters: + # + # +left+:: starting color, for leftmost pixels [FXColor] + # +right+:: ending color, for rightmost pixels [FXColor] + # + def hgradient(left, right); end + + # + # Fill image using a vertical gradient. + # + # ==== Parameters: + # + # +top+:: starting color, for topmost pixels [FXColor] + # +bottom+:: ending color, for bottommost pixels [FXColor] + # + def vgradient(top, bottom); end + + # + # Fill image using a bilinear gradient. + # + # ==== Parameters: + # + # +topleft+:: pixel color for top-left corner [FXColor] + # +topright+:: pixel color for top-right corner [FXColor] + # +bottomleft+:: pixel color for bottom-left corner [FXColor] + # +bottomright+:: pixel color for bottom-right corner [FXColor] + # + def gradient(topleft, topright, bottomleft, bottomright); end + + # + # Blend image over uniform color. + # + # ==== Parameters: + # + # +color+:: the blended color [FXColor] + # + def blend(color); end # # Save pixel data to a stream. diff --git a/rdoc-sources/FXImageFrame.rb b/rdoc-sources/FXImageFrame.rb index 7dd0a05..ec84360 100755 --- a/rdoc-sources/FXImageFrame.rb +++ b/rdoc-sources/FXImageFrame.rb @@ -16,6 +16,20 @@ module Fox # # Return an initialized FXImageFrame instance. # + # ==== Parameters: + # + # +p+:: the parent window for this image frame [FXComposite] + # +img+:: the image to display [FXImage] + # +opts+:: frame options [Integer] + # +x+:: initial x-position [Integer] + # +y+:: initial y-position [Integer] + # +width+:: initial width [Integer] + # +height+:: initial height [Integer] + # +padLeft+:: internal padding on the left side, in pixels [Integer] + # +padRight+:: internal padding on the right side, in pixels [Integer] + # +padTop+:: internal padding on the top side, in pixels [Integer] + # +padBottom+:: internal padding on the bottom side, in pixels [Integer] + # def initialize(p, img, opts=FRAME_SUNKEN|FRAME_THICK, x=0, y=0, width=0, height=0, padLeft=0, padRight=0, padTop=0, padBottom=0) # :yields: theImageFrame end end diff --git a/rdoc-sources/FXInputDialog.rb b/rdoc-sources/FXInputDialog.rb index b7bbe25..42dc800 100755 --- a/rdoc-sources/FXInputDialog.rb +++ b/rdoc-sources/FXInputDialog.rb @@ -26,6 +26,9 @@ module Fox # def initialize(owner, caption, label, icon=nil, opts=INPUTDIALOG_STRING, x=0, y=0, width=0, height=0) # :yields: theInputDialog end + + # Return the input dialog's input string text + def to_s; text; end # # Change limits (where _lo_ and _hi_ are numbers). diff --git a/rdoc-sources/FXLabel.rb b/rdoc-sources/FXLabel.rb index abbe0bd..ebf456f 100755 --- a/rdoc-sources/FXLabel.rb +++ b/rdoc-sources/FXLabel.rb @@ -65,5 +65,8 @@ module Fox # Construct label with given text and icon def initialize(parent, text, icon=nil, opts=LABEL_NORMAL, x=0, y=0, width=0, height=0, padLeft=DEFAULT_PAD, padRight=DEFAULT_PAD, padTop=DEFAULT_PAD, padBottom=DEFAULT_PAD) # :yields: theLabel end + + # Return the label's text + def to_s; text; end end end diff --git a/rdoc-sources/FXList.rb b/rdoc-sources/FXList.rb index a91929d..949ae6c 100755 --- a/rdoc-sources/FXList.rb +++ b/rdoc-sources/FXList.rb @@ -29,6 +29,9 @@ module Fox def initialize(text, icon=nil, data=nil) # :yields: theListItem end + # Return the list item's text + def to_s; text; end + # Returns +true+ if this item has the focus def hasFocus?() ; end @@ -288,8 +291,9 @@ module Fox def findItem(text, start=-1, flags=SEARCH_FORWARD|SEARCH_WRAP) ; end # - # Search items by associated user _data_, beginning from item _start_. If the - # start item is -1 the search will start at the first item in the list. + # Search items by associated user _data_, beginning from item _start_. + # Returns the integer index of the matching item, or -1 if no match is + # found. If the start item is -1 the search will start at the first item in the list. # Flags may be +SEARCH_FORWARD+ or +SEARCH_BACKWARD+ to control the # search direction; this can be combined with +SEARCH_NOWRAP+ or +SEARCH_WRAP+ # to control whether the search wraps at the start or end of the list. diff --git a/rdoc-sources/FXMDIChild.rb b/rdoc-sources/FXMDIChild.rb index f9d18d7..30a741f 100755 --- a/rdoc-sources/FXMDIChild.rb +++ b/rdoc-sources/FXMDIChild.rb @@ -116,12 +116,6 @@ module Fox def initialize(p, name, ic=nil, pup=nil, opts=0, x=0, y=0, width=0, height=0) # :yields: theMDIChild end - # Get next MDI Child - def getMDINext(); end - - # Get previous MDI Child - def getMDIPrev(); end - # # Minimize this window. # If _notify_ is +true+, ... diff --git a/rdoc-sources/FXMDIClient.rb b/rdoc-sources/FXMDIClient.rb index 2553cd9..5303b66 100755 --- a/rdoc-sources/FXMDIClient.rb +++ b/rdoc-sources/FXMDIClient.rb @@ -38,12 +38,6 @@ module Fox def initialize(p, opts=0, x=0, y=0, width=0, height=0) # :yields: theMDIClient end - # Get first MDI Child - def getMDIChildFirst(); end - - # Get last MDI Child - def getMDIChildLast(); end - # # Pass message to all MDI windows, stopping when one of # the MDI windows fails to handle the message. diff --git a/rdoc-sources/FXMenuCaption.rb b/rdoc-sources/FXMenuCaption.rb index 5482670..128ba6d 100755 --- a/rdoc-sources/FXMenuCaption.rb +++ b/rdoc-sources/FXMenuCaption.rb @@ -45,6 +45,9 @@ module Fox # def initialize(parent, text, icon=nil, opts=0) # :yields: theMenuCaption end + + # Return the menu caption's text + def to_s; text; end end end diff --git a/rdoc-sources/FXMessageBox.rb b/rdoc-sources/FXMessageBox.rb index ccd4043..c77b132 100755 --- a/rdoc-sources/FXMessageBox.rb +++ b/rdoc-sources/FXMessageBox.rb @@ -29,6 +29,7 @@ module Fox # +MBOX_CLICKED_SAVE+:: The *Save* button was clicked # +MBOX_CLICKED_SKIP+:: The *Skip* button was clicked # +MBOX_CLICKED_SKIPALL+:: The *Skip All* button was clicked + # +MBOX_CLICKED_DONTSAVE+:: The *Don't Save* button was clicked (same as +MBOX_CLICKED_NO+) # class FXMessageBox < FXDialogBox # diff --git a/rdoc-sources/FXPacker.rb b/rdoc-sources/FXPacker.rb index bae1fc3..7472dff 100755 --- a/rdoc-sources/FXPacker.rb +++ b/rdoc-sources/FXPacker.rb @@ -58,5 +58,6 @@ module Fox # def initialize(parent, opts=0, x=0, y=0, width=0, height=0, padLeft=DEFAULT_SPACING, padRight=DEFAULT_SPACING, padTop=DEFAULT_SPACING, padBottom=DEFAULT_SPACING, hSpacing=DEFAULT_SPACING, vSpacing=DEFAULT_SPACING) # :yields: thePacker end + end end diff --git a/rdoc-sources/FXTable.rb b/rdoc-sources/FXTable.rb index 1ea4332..7ce4065 100755 --- a/rdoc-sources/FXTable.rb +++ b/rdoc-sources/FXTable.rb @@ -155,7 +155,42 @@ module Fox def destroy; end end - # Table Widget + # + # The FXTable widget displays a table of items, each with some text and optional + # icon. A column Header control provide captions for each column, and a row + # Header control provides captions for each row. Columns are resizable by + # means of the column Header control if the TABLE_COL_SIZABLE option is passed. + # Likewise, rows in the table are resizable if the TABLE_ROW_SIZABLE option is + # specified. An entire row (column) can be selected by clicking on the a button + # in the row (column) Header control. Passing TABLE_NO_COLSELECT disables column + # selection, and passing TABLE_NO_ROWSELECT disables column selection. + # When TABLE_COL_RENUMBER is specified, columns are automatically renumbered when + # columns are added or removed. Similarly, TABLE_ROW_RENUMBER will cause row numbers + # to be recalculated automatically when rows are added or removed. + # To disable editing of cells in the table, the TABLE_READONLY can be specified. + # Cells in the table may or may not have items in them. When populating a cell + # for the first time, an item will be automatically created if necessary. Thus, + # a cell in the table takes no space unless it has actual contents. + # Moreover, a contiguous, rectangular region of cells in the table may refer to + # one single item; in that case, the item will be stretched to cover all the + # cells in the region, and no grid lines will be drawn interior to the spanning + # item. + # + # The Table widget issues SEL_SELECTED or SEL_DESELECTED when cells are selected + # or deselected, respectively. The table position affected is passed along as the + # 3rd parameter of these messages. + # Whenever the current (focus) item is changed, a SEL_CHANGED message is sent with + # the new table position as a parameter. + # When items are added to the table, a SEL_INSERTED message is sent, with the table + # range of the newly added cells as the parameter in the message. + # When items are removed from the table, a SEL_DELETED message is sent prior to the + # removal of the items, and the table range of the removed cells is passed as a parameter. + # A SEL_REPLACED message is sent when the contents of a cell are changed, either through + # editing or by other means; the parameter is the range of affected cells. This message + # is sent prior to the change. + # SEL_CLICKED, SEL_DOUBLECLICKED, and SEL_TRIPLECLICKED messages are sent when a cell + # is clicked, double-clicked, or triple-clicked, respectively. + # A SEL_COMMAND is sent when an enabled item is clicked inside the table. # # === Events # @@ -573,18 +608,10 @@ module Fox # Raises IndexError if _row_ is out of bounds. def getRowHeight(row) ; end - # Set x-coordinate for column. - # Raises IndexError if _column_ is out of bounds. - def setColumnX(column, x) ; end - # Get x-coordinate of column. # Raises IndexError if _column_ is out of bounds. def getColumnX(column) ; end - # Set y-coordinate of row. - # Raises IndexError if _row_ is out of bounds. - def setRowY(row, y) ; end - # Get y-coordinate of row. # Raises IndexError if _row_ is out of bounds. def getRowY(row) ; end @@ -610,51 +637,67 @@ module Fox def fitColumnsToContents(col, nc=1); end # Set column header at _index_ to _text_. + # Raises IndexError if _index_ is out of bounds. def setColumnText(index, text); end # Return text of column header at _index_. + # Raises IndexError if _index_ is out of bounds. def getColumnText(index); end # Set row header at _index_ to _text_. + # Raises IndexError if _index_ is out of bounds. def setRowText(index, text); end # Return text of row header at _index_. + # Raises IndexError if _index_ is out of bounds. def getRowText(index); end - # Change column header icon + # Change column header icon. + # Raises IndexError if _index_ is out of bounds. def setColumnIcon(FXint index,FXIcon* icon); - # Return icon of column header at index + # Return icon of column header at _index_. + # Raises IndexError if _index_ is out of bounds. def getColumnIcon(index); end - # Change row header icon + # Change row header icon. + # Raises IndexError if _index_ is out of bounds. def setRowIcon(index, icon); end - # Return icon of row header at index + # Return icon of row header at _index_. + # Raises IndexError if _index_ is out of bounds. def getRowIcon(index); end # Change column header icon position, e.g. FXHeaderItem::BEFORE, etc. + # Raises IndexError if _index_ is out of bounds. def setColumnIconPosition(index, mode); end - # Return icon position of column header at index + # Return icon position of column header at _index_. + # Raises IndexError if _index_ is out of bounds. def getColumnIconPosition(index); end # Change row header icon position, e.g. FXHeaderItem::BEFORE, etc. + # Raises IndexError if _index_ is out of bounds. def setRowIconPosition(index, mode); end - # Return icon position of row header at index + # Return icon position of row header at _index_. + # Raises IndexError if _index_ is out of bounds. def getRowIconPosition(index); end # Change column header justify, e.g. FXHeaderItem::RIGHT, etc. + # Raises IndexError if _index_ is out of bounds. def setColumnJustify(index, justify); end - # Return justify of column header at index + # Return justify of column header at _index_. + # Raises IndexError if _index_ is out of bounds. def getColumnJustify(index); end # Change row header justify, e.g. FXHeaderItem::RIGHT, etc. + # Raises IndexError if _index_ is out of bounds. def setRowJustify(index, justify); end - # Return justify of row header at index + # Return justify of row header at _index_. + # Raises IndexError if _index_ is out of bounds. def getRowJustify(index); end # diff --git a/rdoc-sources/FXText.rb b/rdoc-sources/FXText.rb index 99d48bd..1ffdd7b 100755 --- a/rdoc-sources/FXText.rb +++ b/rdoc-sources/FXText.rb @@ -2,7 +2,7 @@ module Fox # # Highlight style entry # - class FXHiliteStyle + class FXHiliteStyle # Normal text foreground color [FXColor] attr_accessor :normalForeColor @@ -315,7 +315,7 @@ module Fox # +p+:: the parent window for this text widget [FXComposite] # +target+:: the message target, if any, for this text widget [FXObject] # +selector+:: the message identifier for this text widget [Integer] - # +opts+:: tree list options [Integer] + # +opts+:: text options [Integer] # +x+:: initial x-position [Integer] # +y+:: initial y-position [Integer] # +width+:: initial width [Integer] @@ -324,6 +324,9 @@ module Fox def initialize(p, target=nil, selector=0, opts=0, x=0, y=0, width=0, height=0, padLeft=3, padRight=3, padTop=2, padBottom=2) # :yields: theText end + # Return the text buffer's value + def to_s; text; end + # Return +true+ if text was modified def modified? ; end @@ -430,18 +433,19 @@ module Fox # text is inserted. def shiftText(startPos, endPos, amount, notify=false); end - # Search for _string_ in text buffer, returning the extent of - # the string in _beg_ and _end_. The search starts from the given + # + # Search for _string_ in text buffer, and return the extent of + # the string as a two-element array of arrays. + # The first array contains the beginning index (or indices) + # and the second array contains the ending index (or indices). + # The search starts from the given # _start_ position, scans forward (+SEARCH_FORWARD+) or backward # (+SEARCH_BACKWARD+), and wraps around if +SEARCH_WRAP+ has been # specified. The search type is either a plain search (+SEARCH_EXACT+), # case insensitive search (+SEARCH_IGNORECASE+), or regular expression # search (+SEARCH_REGEX+). - # For regular expression searches, capturing parentheses are used if - # _npar_ is greater than 1; in this case, the number of entries in the - # _beg_ and _end_ arrays must be _npar_ also. If either _beg_ or _end_ or - # both are nil, internal arrays are used. - def findText(string, beg=nil, end=nil, start=0, flags=SEARCH_FORWARD|SEARCH_WRAP|SEARCH_EXACT, npar=1); end + # + def findText(string, start=0, flags=SEARCH_FORWARD|SEARCH_WRAP|SEARCH_EXACT); end # Return +true+ if position _pos_ is selected def positionSelected?(pos); end diff --git a/rdoc-sources/FXToggleButton.rb b/rdoc-sources/FXToggleButton.rb index 6207c43..95bd9da 100755 --- a/rdoc-sources/FXToggleButton.rb +++ b/rdoc-sources/FXToggleButton.rb @@ -19,6 +19,7 @@ module Fox # +TOGGLEBUTTON_AUTOGRAY+:: Automatically gray out when not updated # +TOGGLEBUTTON_AUTOHIDE+:: Automatically hide toggle button when not updated # +TOGGLEBUTTON_TOOLBAR+:: Toolbar style toggle button [flat look] + # +TOGGLEBUTTON_KEEPSTATE+:: Draw button according to state # +TOGGLEBUTTON_NORMAL+:: <tt>FRAME_RAISED|FRAME_THICK|JUSTIFY_NORMAL|ICON_BEFORE_TEXT</tt> # class FXToggleButton < FXLabel diff --git a/rdoc-sources/FXToolTip.rb b/rdoc-sources/FXToolTip.rb index 89dd950..a01eaf2 100755 --- a/rdoc-sources/FXToolTip.rb +++ b/rdoc-sources/FXToolTip.rb @@ -32,5 +32,8 @@ module Fox # Set the current tip text color def textColor=(color); end + + # Return the tool tip's text + def to_s; text; end end end diff --git a/rdoc-sources/FXVec2d.rb b/rdoc-sources/FXVec2d.rb index a3f9184..0b1f419 100755 --- a/rdoc-sources/FXVec2d.rb +++ b/rdoc-sources/FXVec2d.rb @@ -7,7 +7,7 @@ module Fox # # Return an initialized FXVec2d instance. # - def initialize(xx, yy); end + def initialize(xx=0.0, yy=0.0); end # # Returns the element at _index_, where _index_ is 0 or 1. diff --git a/rdoc-sources/FXVec2f.rb b/rdoc-sources/FXVec2f.rb index 7706e99..887a4bd 100755 --- a/rdoc-sources/FXVec2f.rb +++ b/rdoc-sources/FXVec2f.rb @@ -7,7 +7,7 @@ module Fox # # Return an initialized FXVec2f instance. # - def initialize(xx, yy); end + def initialize(xx=0.0, yy=0.0); end # # Returns the element at _index_, where _index_ is 0 or 1. diff --git a/rdoc-sources/FXVec3d.rb b/rdoc-sources/FXVec3d.rb index ecfc2cb..637ab0a 100755 --- a/rdoc-sources/FXVec3d.rb +++ b/rdoc-sources/FXVec3d.rb @@ -6,9 +6,14 @@ module Fox attr_accessor :z # - # Return an initialized FXVec3d instance. + # Return an FXVec3d instance with _x_, _y_ and _z_ initialized to zeroes. # - def initialize(xx, yy, zz); end + def initialize; end + + # + # Return an FXVec3d instance initialized from specified component values. + # + def initialize(xx, yy, zz=1.0); end # # Returns the element at _index_, where _index_ is 0, 1 or 2. diff --git a/rdoc-sources/FXVec3f.rb b/rdoc-sources/FXVec3f.rb index 97e9bb8..e3745a8 100755 --- a/rdoc-sources/FXVec3f.rb +++ b/rdoc-sources/FXVec3f.rb @@ -6,9 +6,14 @@ module Fox attr_accessor :z # - # Return an initialized FXVec3f instance. + # Return an FXVec3f instance with _x_, _y_ and _z_ initialized to zeroes. # - def initialize(xx, yy, zz); end + def initialize; end + + # + # Return an FXVec3f instance initialized with specified component values. + # + def initialize(xx, yy, zz=1.0); end # # Returns the element at _index_, where _index_ is 0, 1 or 2. diff --git a/rdoc-sources/FXVec4d.rb b/rdoc-sources/FXVec4d.rb index 527a8f6..f12a40c 100755 --- a/rdoc-sources/FXVec4d.rb +++ b/rdoc-sources/FXVec4d.rb @@ -7,12 +7,22 @@ module Fox attr_accessor :w # - # Return an initialized FXVec4d instance. + # Return an FXVec4d instance with _x_, _y_, _z_ and _w_ initialized to zeroes. + # + def initialize; end + + # + # Return an FXVec4d instance initialized from specified component values. # def initialize(xx, yy, zz, ww=1.0); end + + # + # Return an FXVec4d instance initialized from an FXVec3d instance and optional scalar. + # + def initialize(vec3d, ww=1.0); end # - # Returns the element at _index_, where _index_ is 0, 1 or 2. + # Returns the element at _index_, where _index_ is 0, 1, 2 or 3. # Raises IndexError if _index_ is out of range. # def [](index); end diff --git a/rdoc-sources/FXVec4f.rb b/rdoc-sources/FXVec4f.rb index 0f79b3c..72fddce 100755 --- a/rdoc-sources/FXVec4f.rb +++ b/rdoc-sources/FXVec4f.rb @@ -7,12 +7,22 @@ module Fox attr_accessor :w # - # Return an initialized FXVec4f instance. + # Return an FXVec4f instance with _x_, _y_, _z_ and _w_ initialized to zeroes. + # + def initialize; end + + # + # Return an FXVec4f instance initialized from specified component values. # def initialize(xx, yy, zz, ww=1.0); end + + # + # Return an FXVec4f instance initialized from an FXVec3f instance and optional scalar. + # + def initialize(vec3f, ww=1.0); end # - # Returns the element at _index_, where _index_ is 0, 1 or 2. + # Returns the element at _index_, where _index_ is 0, 1, 2 or 3. # Raises IndexError if _index_ is out of range. # def [](index); end diff --git a/rdoc-sources/FXWindow.rb b/rdoc-sources/FXWindow.rb index 317375e..71ce72c 100755 --- a/rdoc-sources/FXWindow.rb +++ b/rdoc-sources/FXWindow.rb @@ -78,6 +78,7 @@ module Fox # +LAYOUT_MIN_HEIGHT+:: Minimum height is the default # +LAYOUT_FILL_X+:: Stretch or shrink horizontally # +LAYOUT_FILL_Y+:: Stretch or shrink vertically + # +LAYOUT_FILL:: Stretch or shrink in both directions # +LAYOUT_EXPLICIT+:: Explicit placement # +LAYOUT_DOCK_SAME+:: Dock on same galley, if it fits # +LAYOUT_DOCK_NEXT+:: Dock on next galley diff --git a/scripts/FXRuby.iss.in b/scripts/FXRuby.iss.in index 4733829..9bbedf4 100755 --- a/scripts/FXRuby.iss.in +++ b/scripts/FXRuby.iss.in @@ -20,14 +20,9 @@ OutputBaseFilename=FXRuby-@@FXRUBY_VERSION@@-@@RUBYVER@@ Source: "LICENSE"; DestDir: "{app}\doc\FXRuby"; Flags: ignoreversion Source: "README.win32.txt"; DestDir: "{app}\doc\FXRuby"; Flags: ignoreversion Source: "README"; DestDir: "{app}\doc\FXRuby"; Flags: ignoreversion -Source: "index.html"; DestDir: "{app}\doc\FXRuby"; Flags: ignoreversion ; HTML documentation files Source: "doc\*.html"; DestDir: "{app}\doc\FXRuby\doc"; Flags: ignoreversion Source: "doc\images\*.png"; DestDir: "{app}\doc\FXRuby\doc\images"; Flags: ignoreversion -Source: "web\*.html"; DestDir: "{app}\doc\FXRuby\doc\web"; Flags: ignoreversion -Source: "web\*.css"; DestDir: "{app}\doc\FXRuby\doc\web"; Flags: ignoreversion -Source: "web\art\*.gif"; DestDir: "{app}\doc\FXRuby\doc\web\art"; Flags: ignoreversion -Source: "web\art\*.png"; DestDir: "{app}\doc\FXRuby\doc\web\art"; Flags: ignoreversion ; unit tests Source: "tests\README"; DestDir: "{app}\doc\FXRuby\tests"; Flags: ignoreversion Source: "tests\*.rb"; DestDir: "{app}\doc\FXRuby\tests"; Flags: ignoreversion diff --git a/scripts/generate_kwargs_lib.rb b/scripts/generate_kwargs_lib.rb index 712a056..0c9cc8a 100644 --- a/scripts/generate_kwargs_lib.rb +++ b/scripts/generate_kwargs_lib.rb @@ -13,27 +13,91 @@ Known problems (due to overloaded constructors): =end +CLASSES_TO_SKIP = %w{FX4Splitter FXCursor FXDCWindow FXExtentd FXExtentf FXFont FXGLCanvas FXGLShape FXGLViewer FXDockBar FXMenuBar FXToolBar FXQuatd FXQuatf FXRanged FXRangef FXRecentFiles FXRectangle FXRegion FXSize FXSphered FXSpheref FXSplitter FXVec2d FXVec2f FXVec3d FXVec3f FXVec4d FXVec4f FXWindow} + class Arg attr_reader :name attr_reader :value + def initialize(name, value) @name = name @value = value end end -class Desc - - attr_accessor :class_name +class MethodDescription + attr_accessor :method_name attr_accessor :required_args attr_accessor :optional_args - + def initialize - @class_name = nil + @method_name = nil @required_args = [] @optional_args = [] end + + def generate_alias + " alias old_#{method_name} #{method_name}\n" + end + + def generate_body + argument_names = optional_args.map { |arg| arg.name } + defaults_hash = optional_args.map { |arg| ":#{arg.name} => #{arg.value}"} + defaults_hash = "{ #{defaults_hash.join(', ')} }" + required = required_args.join(", ") + optional = optional_args.map { |arg| "params[:#{arg.name}]"} + optional = optional.join(", ") + buffer = "" + buffer << " def #{method_name}(#{required}#{required_args.length > 0 ? ', ' : ''}*args#{expects_block? ? ', &blk' : ''})\n" + buffer << " argument_names = %w{#{argument_names.join(' ')}}\n" + buffer << " default_params = #{defaults_hash}\n" + buffer << " params = {}\n" + buffer << " params = args.pop if args.last.is_a? Hash\n" + buffer << " args.each_with_index { |e, i| params[argument_names[i].intern] = e }\n" + if optional_args.any? { |arg| arg.name == "padLeft" } + buffer << " if params.key? :padding\n" + buffer << " value = params.delete(:padding)\n" + buffer << " [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value }\n" + buffer << " end\n" + end + buffer << " params.keys.each { |key| raise ArgumentError, \"Unrecognized parameter \#{key}\" unless default_params.keys.include?(key) }\n" + buffer << " params = default_params.merge(params)\n" + buffer << " old_#{method_name}(#{required}#{(required_args.length > 0) && (optional_args.length > 0) ? ', ' : ''}#{optional}#{expects_block? ? ', &blk' : ''})\n" + buffer << " end\n" + buffer + end + + def expects_block? + method_name == "initialize" + end +end +class ClassDescription + attr_accessor :class_name + attr_accessor :method_descriptions + + def initialize + @class_name = nil + @method_descriptions = [] + end + + def generate_class_initializer + buffer = "" + buffer << " class #{class_name}\n" + method_descriptions.each do |method_description| + buffer << method_description.generate_alias + buffer << method_description.generate_body + end + buffer << " end\n\n" + buffer + end + + def has_methods_with_optional_arguments? + method_descriptions.each do |m| + return true if m.optional_args.length > 0 + end + false + end end class Generator @@ -46,88 +110,65 @@ class Generator out.puts <<-END require 'fox16' +$VERBOSE = nil + module Fox END out.puts(DATA.read) end - def generate_class_initializer(desc) - argument_names = desc.optional_args.map { |arg| arg.name } - defaults_hash = desc.optional_args.map { |arg| ":#{arg.name} => #{arg.value}"} - defaults_hash = "{ #{defaults_hash.join(', ')} }" - required_args = desc.required_args.join(", ") - optional_args = desc.optional_args.map { |arg| "params[:#{arg.name}]"} - optional_args = optional_args.join(", ") - buffer = "" - buffer << " class #{desc.class_name}\n" - buffer << " alias old_initialize initialize\n" - buffer << " def initialize(#{required_args}#{desc.required_args.length > 0 ? ', ' : ''}*args, &blk)\n" - buffer << " argument_names = %w{#{argument_names.join(' ')}}\n" - buffer << " default_params = #{defaults_hash}\n" - buffer << " params = {}\n" - buffer << " params = args.pop if args.last.is_a? Hash\n" - buffer << " args.each_with_index { |e, i| params[argument_names[i].intern] = e }\n" - if desc.optional_args.any? { |arg| arg.name == "padLeft" } - buffer << " if params.key? :padding\n" - buffer << " value = params.delete(:padding)\n" - buffer << " [:padLeft, :padRight, :padTop, :padBottom].each { |s| params[s] ||= value }\n" - buffer << " end\n" - end - buffer << " params.keys.each { |key| raise ArgumentError, \"Unrecognized parameter \#{key}\" unless default_params.keys.include?(key) }\n" - buffer << " params = default_params.merge(params)\n" - buffer << " old_initialize(#{required_args}#{(desc.required_args.length > 0) && (desc.optional_args.length > 0) ? ', ' : ''}#{optional_args}, &blk)\n" - buffer << " end\n" - buffer << " end\n\n" - buffer - end - def go(filenames, output_filename) out = File.new(output_filename, "w") - descriptions = [] - filenames.each { |filename| descriptions += scan_for_descriptions(filename) } + class_descriptions = [] + filenames.each { |filename| class_descriptions += scan_for_descriptions(filename) } generate_preamble(out) - descriptions.each do |desc| - out.puts generate_class_initializer(desc) if desc.optional_args.length > 0 + class_descriptions.each do |class_description| + out.puts class_description.generate_class_initializer if class_description.has_methods_with_optional_arguments? end generate_closing(out) end def generate_closing(out) out.puts "end" + out.puts "" + out.puts "$VERBOSE = true" end def scan_for_descriptions(filename) - desc = nil - descriptions = [] + class_description = nil + class_descriptions = [] IO.foreach(filename) do |str| if str =~ /^ class\s*(\w+).*$/ - desc = Desc.new - desc.class_name = $1 - elsif str =~ /def initialize\((.*)\)/ -# args = $1.split(',').map { |x| x.strip } - args = $1.split(', ').map { |x| x.strip } + class_description = ClassDescription.new + class_description.class_name = $1 + elsif str =~ /def (initialize|findText)\((.*)\)/ + method_description = MethodDescription.new + method_description.method_name = $1 +# args = $2.split(',').map { |x| x.strip } + args = $2.split(', ').map { |x| x.strip } args.each do |arg| if arg =~ /(.*)=(.*)/ - desc.optional_args << Arg.new($1, $2) + method_description.optional_args << Arg.new($1, $2) elsif - desc.required_args << arg + method_description.required_args << arg end end - if @known_classes.has_key? desc.class_name - warn "Overloaded initialize method for class: #{desc.class_name}" + if @known_classes.has_key? class_description.class_name + warn "Overloaded initialize method for class: #{class_description.class_name}" end - @known_classes[desc.class_name] = 1 + @known_classes[class_description.class_name] = 1 + class_description.method_descriptions << method_description elsif str =~ /^ end/ - descriptions << desc unless skip?(desc.class_name) - desc = nil + class_descriptions << class_description unless skip?(class_description.class_name) + class_description = nil end end - descriptions + class_descriptions end def skip?(name) - %w{FX4Splitter FXCursor FXDCWindow FXExtentd FXExtentf FXFont FXGLCanvas FXGLShape FXGLViewer FXDockBar FXMenuBar FXToolBar FXQuatd FXQuatf FXRanged FXRangef FXRecentFiles FXRectangle FXRegion FXSize FXSphered FXSpheref FXSplitter FXWindow}.include? name + CLASSES_TO_SKIP.include? name end end @@ -191,7 +232,9 @@ __END__ end class FXFont + alias old_initialize initialize + def initialize(a, arg1, *args, &blk) if args.length > 0 face, size = arg1, args[0] @@ -207,6 +250,22 @@ __END__ old_initialize(a, arg1, &blk) end end + + class << self + alias old_listFonts listFonts + end + + def FXFont.listFonts(face, *args) + argument_names = %w{weight slant setWidth encoding hints} + default_params = { :weight => 0, :slant => 0, :setWidth => 0, :encoding => 0, :hints => 0 } + params = {} + params = args.pop if args.last.is_a? Hash + args.each_with_index { |e, i| params[argument_names[i].intern] = e } + params.keys.each { |key| raise ArgumentError, "Unrecognized parameter #{key}" unless default_params.keys.include?(key) } + params = default_params.merge(params) + old_listFonts(face, params[:weight], params[:slant], params[:setWidth], params[:encoding], params[:hints]) + end + end class FXGLCanvas @@ -261,6 +320,7 @@ __END__ params = {} params = args.pop if args.last.is_a? Hash if args.length > 0 && (args[0].nil? || args[0].is_a?(FXComposite)) + q = args[0] args.each_with_index { |e, i| params[argument_names[i-1].intern] = e if i >= 1 } if params.key? :padding value = params.delete(:padding) diff --git a/swig-interfaces/FXApp.i b/swig-interfaces/FXApp.i index 56d6546..b05387f 100755 --- a/swig-interfaces/FXApp.i +++ b/swig-interfaces/FXApp.i @@ -173,7 +173,13 @@ public: * as keys into the registry database for this application's settings */ FXApp(const FXchar* name="Application",const FXchar* vendor="FoxDefault"){ - return FXRbApp::constructAndInit(name,vendor); + if(FXApp::instance()){ + rb_raise(rb_eRuntimeError,"attempted to create more than one FXApp instance"); + return 0; + } + else{ + return FXRbApp::constructAndInit(name,vendor); + } } } @@ -315,7 +321,7 @@ public: FXint sig; switch(TYPE(sigObj)){ case T_STRING: - s=STR2CSTR(sigObj); + s=StringValuePtr(sigObj); sig=FXRbSignalNameToNumber(s); if(sig==0) rb_raise(rb_eArgError,"unrecognized signal name `%s'",s); break; @@ -335,7 +341,7 @@ public: FXint sig; switch(TYPE(sigObj)){ case T_STRING: - s=STR2CSTR(sigObj); + s=StringValuePtr(sigObj); sig=FXRbSignalNameToNumber(s); if(sig==0) rb_raise(rb_eArgError,"unrecognized signal name `%s'",s); break; diff --git a/swig-interfaces/FXDialogBox.i b/swig-interfaces/FXDialogBox.i index 831f78c..31dcb24 100755 --- a/swig-interfaces/FXDialogBox.i +++ b/swig-interfaces/FXDialogBox.i @@ -20,7 +20,6 @@ * at "lyle@users.sourceforge.net". ***********************************************************************/ - /** * DialogBox window. * When receiving ID_CANCEL or ID_ACCEPT, the DialogBox breaks out of the @@ -44,13 +43,13 @@ public: public: %extend { /// Construct free-floating dialog - FXDialogBox(FXApp* a,const FXString& name,FXuint opts=DECOR_TITLE|DECOR_BORDER,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=10,FXint pr=10,FXint pt=10,FXint pb=10,FXint hs=4,FXint vs=4){ - return new FXRbDialogBox(a,name,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); + FXDialogBox(FXApp* APP,const FXString& name,FXuint opts=DECOR_TITLE|DECOR_BORDER,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=10,FXint pr=10,FXint pt=10,FXint pb=10,FXint hs=4,FXint vs=4){ + return new FXRbDialogBox(APP,name,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); } /// Construct dialog which will always float over the owner window - FXDialogBox(FXWindow* owner,const FXString& name,FXuint opts=DECOR_TITLE|DECOR_BORDER,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=10,FXint pr=10,FXint pt=10,FXint pb=10,FXint hs=4,FXint vs=4){ - return new FXRbDialogBox(owner,name,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); + FXDialogBox(FXWindow* OWNER,const FXString& name,FXuint opts=DECOR_TITLE|DECOR_BORDER,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=10,FXint pr=10,FXint pt=10,FXint pb=10,FXint hs=4,FXint vs=4){ + return new FXRbDialogBox(OWNER,name,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); } } diff --git a/swig-interfaces/FXFileDialog.i b/swig-interfaces/FXFileDialog.i index cf256b8..421f731 100755 --- a/swig-interfaces/FXFileDialog.i +++ b/swig-interfaces/FXFileDialog.i @@ -104,13 +104,13 @@ public: void setPatternList(VALUE ary) { FXString patterns; if(TYPE(ary)==T_STRING){ - patterns=FXString(STR2CSTR(ary)); + patterns=FXString(StringValuePtr(ary)); } else if(TYPE(ary)==T_ARRAY){ - for(long i=0; i<RARRAY(ary)->len; i++){ + for(long i=0; i<RARRAY_LEN(ary); i++){ VALUE obj=rb_ary_entry(ary,i); Check_Type(obj,T_STRING); - patterns+=FXString(STR2CSTR(obj))+FXString("\n"); + patterns+=FXString(StringValuePtr(obj))+FXString("\n"); } } else{ diff --git a/swig-interfaces/FXFileSelector.i b/swig-interfaces/FXFileSelector.i index 90b9efd..1070ba5 100755 --- a/swig-interfaces/FXFileSelector.i +++ b/swig-interfaces/FXFileSelector.i @@ -201,13 +201,13 @@ public: void setPatternList(VALUE ary) { FXString patterns; if(TYPE(ary)==T_STRING){ - patterns=FXString(STR2CSTR(ary)); + patterns=FXString(StringValuePtr(ary)); } else if(TYPE(ary)==T_ARRAY){ - for(long i=0; i<RARRAY(ary)->len; i++){ + for(long i=0; i<RARRAY_LEN(ary); i++){ VALUE obj=rb_ary_entry(ary,i); Check_Type(obj,T_STRING); - patterns+=FXString(STR2CSTR(obj))+FXString("\n"); + patterns+=FXString(StringValuePtr(obj))+FXString("\n"); } } else{ diff --git a/swig-interfaces/FXFoldingList.i b/swig-interfaces/FXFoldingList.i index e35df45..cd33629 100755 --- a/swig-interfaces/FXFoldingList.i +++ b/swig-interfaces/FXFoldingList.i @@ -228,11 +228,12 @@ public: /// Set headers from array of strings void setHeaders(VALUE stringArray,FXint size=1){ Check_Type(stringArray,T_ARRAY); - long len=RARRAY(stringArray)->len; + long len=RARRAY_LEN(stringArray); const FXchar **strings; if(FXMALLOC(&strings,FXchar*,len+1)){ for(long i=0;i<len;i++){ - strings[i]=STR2CSTR(rb_ary_entry(stringArray,i)); + VALUE s=rb_ary_entry(stringArray,i); + strings[i]=StringValuePtr(s); } strings[len]=0; self->setHeaders(strings,size); diff --git a/swig-interfaces/FXImage.i b/swig-interfaces/FXImage.i index fd6fbfa..3ecef04 100755 --- a/swig-interfaces/FXImage.i +++ b/swig-interfaces/FXImage.i @@ -59,8 +59,8 @@ public: FXColor* pix=0; if(!NIL_P(ary)){ Check_Type(ary,T_ARRAY); - if(FXMALLOC(&pix,FXColor,RARRAY(ary)->len)){ - for(long i=0; i<RARRAY(ary)->len; i++){ + if(FXMALLOC(&pix,FXColor,RARRAY_LEN(ary))){ + for(long i=0; i<RARRAY_LEN(ary); i++){ pix[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry(ary,i))); } } diff --git a/swig-interfaces/FXMainWindow.i b/swig-interfaces/FXMainWindow.i index dd59958..08f461a 100755 --- a/swig-interfaces/FXMainWindow.i +++ b/swig-interfaces/FXMainWindow.i @@ -20,7 +20,6 @@ * at "lyle@users.sourceforge.net". ***********************************************************************/ - /** * Main application window. There may be any number of * MainWindows in an application. @@ -36,8 +35,8 @@ protected: public: %extend { /// Construct a main window - FXMainWindow(FXApp* a,const FXString& name,FXIcon *ic=NULL,FXIcon *mi=NULL,FXuint opts=DECOR_ALL,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=0,FXint pr=0,FXint pt=0,FXint pb=0,FXint hs=0,FXint vs=0){ - return new FXRbMainWindow(a,name,ic,mi,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); + FXMainWindow(FXApp* APP,const FXString& name,FXIcon *ic=NULL,FXIcon *mi=NULL,FXuint opts=DECOR_ALL,FXint x=0,FXint y=0,FXint w=0,FXint h=0,FXint pl=0,FXint pr=0,FXint pt=0,FXint pb=0,FXint hs=0,FXint vs=0){ + return new FXRbMainWindow(APP,name,ic,mi,opts,x,y,w,h,pl,pr,pt,pb,hs,vs); } } diff --git a/swig-interfaces/FXMemoryStream.i b/swig-interfaces/FXMemoryStream.i index cf503dd..8f7558e 100755 --- a/swig-interfaces/FXMemoryStream.i +++ b/swig-interfaces/FXMemoryStream.i @@ -36,8 +36,8 @@ public: FXuval size=0; FXuchar *data=0; if(!NIL_P(str)){ - size=RSTRING(str)->len; - data=reinterpret_cast<FXuchar*>(STR2CSTR(str)); + size=RSTRING_LEN(str); + data=reinterpret_cast<FXuchar*>(StringValuePtr(str)); return self->open(save_or_load,size,data); } else{ @@ -59,7 +59,7 @@ public: void giveBuffer(VALUE str){ Check_Type(str,T_STRING); FXuchar* buffer=reinterpret_cast<FXuchar*>(StringValuePtr(str)); - FXuval sp=RSTRING(str)->len; + FXuval sp=RSTRING_LEN(str); self->giveBuffer(buffer,sp); } } diff --git a/swig-interfaces/FXMessageBox.i b/swig-interfaces/FXMessageBox.i index 47c5f31..45250b0 100755 --- a/swig-interfaces/FXMessageBox.i +++ b/swig-interfaces/FXMessageBox.i @@ -28,10 +28,12 @@ enum { MBOX_YES_NO_CANCEL = 0x40000000, /// Message box has YES, NO, and CANCEL buttons MBOX_QUIT_CANCEL = 0x50000000, /// Message box has QUIT and CANCEL buttons MBOX_QUIT_SAVE_CANCEL = 0x60000000, /// Message box has QUIT, SAVE, and CANCEL buttons - MBOX_SKIP_SKIPALL_CANCEL = 0x70000000, /// Message box has SKIP, SKIP ALL, and CANCEL buttons - MBOX_SAVE_CANCEL_DONTSAVE = 0x80000000 /// Message box has DON'T SAVE,CANCEL and SAVE buttons + MBOX_SKIP_SKIPALL_CANCEL = 0x70000000 /// Message box has SKIP, SKIP ALL, and CANCEL buttons }; +/* SWIG doesn't wrap this value correctly without a hint */ +%constant FXuint MBOX_SAVE_CANCEL_DONTSAVE = 0x80000000; // Message box has DON'T SAVE,CANCEL and SAVE buttons + // Return values enum { @@ -45,6 +47,8 @@ enum { MBOX_CLICKED_SKIPALL = 8 /// The SKIP ALL button was clicked }; +/* FOX doesn't define this constant, but we do for consistency */ +%constant MBOX_CLICKED_DONTSAVE = MBOX_CLICKED_NO; /** * A Message Box is a convenience class which provides a dialog for diff --git a/swig-interfaces/FXPoint.i b/swig-interfaces/FXPoint.i index a28bcf8..ad33347 100755 --- a/swig-interfaces/FXPoint.i +++ b/swig-interfaces/FXPoint.i @@ -28,10 +28,9 @@ public: public: /// Constructors - FXPoint(); FXPoint(const FXSize& s); FXPoint(const FXPoint& p); - FXPoint(FXshort xx,FXshort yy); + FXPoint(FXshort xx=0,FXshort yy=0); %extend { /// Equality diff --git a/swig-interfaces/FXRanged.i b/swig-interfaces/FXRanged.i index 9aafeef..5679eb6 100755 --- a/swig-interfaces/FXRanged.i +++ b/swig-interfaces/FXRanged.i @@ -146,6 +146,10 @@ public: } /// Union of two boxes + // This is not a typo. + // We're calling this method "onion" to work around a bug in SWIG + // that mistakes the method name "union" for the C++ keyword of the same + // name. FXRanged onion(const FXRanged& other) const { return FX::unite(*self,other); } diff --git a/swig-interfaces/FXRangef.i b/swig-interfaces/FXRangef.i index 88059ae..c3fde76 100755 --- a/swig-interfaces/FXRangef.i +++ b/swig-interfaces/FXRangef.i @@ -40,9 +40,6 @@ /// Range class FXRangef { -public: - FXVec3f lower; - FXVec3f upper; public: // Default constructor @@ -68,12 +65,21 @@ public: } return (*self)[i]; } + void __setitem__(FXint i,FXVec3f& slice){ if(i<0||1<i){ rb_raise(rb_eIndexError,"index %d out of bounds",i); } (*self)[i]=slice; } + + FXVec3f upper() const { + return self->upper; + } + + FXVec3f lower() const { + return self->lower; + } } // Width of box @@ -151,6 +157,8 @@ public: } /// Union of two boxes + // This is not a typo. We're calling it "onion" here to work around + // a bug in SWIG that thinks "union" is the C++ keyword union. FXRangef onion(const FXRangef& other) const { return FX::unite(*self,other); } diff --git a/swig-interfaces/FXScintilla.i b/swig-interfaces/FXScintilla.i index b896367..cacb749 100755 --- a/swig-interfaces/FXScintilla.i +++ b/swig-interfaces/FXScintilla.i @@ -143,7 +143,7 @@ public: wp=static_cast<uptr_t>(NUM2UINT(wParam)); break; case T_STRING: - wp=static_cast<uptr_t>(reinterpret_cast<long>(RSTRING(wParam)->ptr)); + wp=static_cast<uptr_t>(reinterpret_cast<long>(RSTRING_PTR(wParam))); break; case T_TRUE: case T_FALSE: @@ -161,7 +161,7 @@ public: lp=static_cast<sptr_t>(NUM2UINT(lParam)); break; case T_STRING: - lp=static_cast<sptr_t>(reinterpret_cast<long>(RSTRING(lParam)->ptr)); + lp=static_cast<sptr_t>(reinterpret_cast<long>(RSTRING_PTR(lParam))); break; case T_TRUE: case T_FALSE: diff --git a/swig-interfaces/FXSettings.i b/swig-interfaces/FXSettings.i index 77e0b7d..a8df6c5 100755 --- a/swig-interfaces/FXSettings.i +++ b/swig-interfaces/FXSettings.i @@ -26,6 +26,8 @@ class FXStringDict; %ignore FXSettings::operator=(const FXSettings& orig); %ignore FXSettings::readFormatEntry(const FXchar *section,const FXchar *key,const FXchar *fmt,...); %ignore FXSettings::writeFormatEntry(const FXchar *section,const FXchar *key,const FXchar *fmt,...); +%ignore FXSettings::readBoolEntry(const FXchar *,const FXchar *,FXbool); +%ignore FXSettings::writeBoolEntry(const FXchar *,const FXchar *,FXbool); /** * The Settings class manages a key-value database. This is normally used as diff --git a/swig-interfaces/FXTable.i b/swig-interfaces/FXTable.i index 97464a3..7cf539b 100755 --- a/swig-interfaces/FXTable.i +++ b/swig-interfaces/FXTable.i @@ -554,52 +554,52 @@ public: void fitColumnsToContents(FXint col,FXint nc=1); /// Change column header - void setColumnText(FXint index,const FXString& text); + void setColumnText(FXint TABLE_COLUMN_INDEX,const FXString& text); /// Return text of column header at index - FXString getColumnText(FXint index) const; + FXString getColumnText(FXint TABLE_COLUMN_INDEX) const; /// Change row header - void setRowText(FXint index,const FXString& text); + void setRowText(FXint TABLE_ROW_INDEX,const FXString& text); /// Return text of row header at index - FXString getRowText(FXint index) const; + FXString getRowText(FXint TABLE_ROW_INDEX) const; /// Change column header icon - void setColumnIcon(FXint index,FXIcon* icon); + void setColumnIcon(FXint TABLE_COLUMN_INDEX,FXIcon* icon); /// Return icon of column header at index - FXIcon* getColumnIcon(FXint index) const; + FXIcon* getColumnIcon(FXint TABLE_COLUMN_INDEX) const; /// Change row header icon - void setRowIcon(FXint index,FXIcon* icon); + void setRowIcon(FXint TABLE_ROW_INDEX,FXIcon* icon); /// Return icon of row header at index - FXIcon* getRowIcon(FXint index) const; + FXIcon* getRowIcon(FXint TABLE_ROW_INDEX) const; /// Change column header icon position, e.g. FXHeaderItem::BEFORE, etc. - void setColumnIconPosition(FXint index,FXuint mode); + void setColumnIconPosition(FXint TABLE_COLUMN_INDEX,FXuint mode); /// Return icon position of column header at index - FXuint getColumnIconPosition(FXint index) const; + FXuint getColumnIconPosition(FXint TABLE_COLUMN_INDEX) const; /// Change row header icon position, e.g. FXHeaderItem::BEFORE, etc. - void setRowIconPosition(FXint index,FXuint mode); + void setRowIconPosition(FXint TABLE_ROW_INDEX,FXuint mode); /// Return icon position of row header at index - FXuint getRowIconPosition(FXint index) const; + FXuint getRowIconPosition(FXint TABLE_ROW_INDEX) const; /// Change column header justify, e.g. FXHeaderItem::RIGHT, etc. - void setColumnJustify(FXint index,FXuint justify); + void setColumnJustify(FXint TABLE_COLUMN_INDEX,FXuint justify); /// Return justify of column header at index - FXuint getColumnJustify(FXint index) const; + FXuint getColumnJustify(FXint TABLE_COLUMN_INDEX) const; /// Change row header justify, e.g. FXHeaderItem::RIGHT, etc. - void setRowJustify(FXint index,FXuint justify); + void setRowJustify(FXint TABLE_ROW_INDEX,FXuint justify); /// Return justify of row header at index - FXuint getRowJustify(FXint index) const; + FXuint getRowJustify(FXint TABLE_ROW_INDEX) const; %extend { /// Modify cell text @@ -652,21 +652,19 @@ public: %extend { /// Extract cells from given range as text. VALUE extractText(FXint startrow,FXint endrow,FXint startcol,FXint endcol,const FXchar* cs="\t",const FXchar* rs="\n") const { - FXchar* text; - FXint size; + FXString str; VALUE result; if(startrow<0 || startcol<0 || self->getNumRows()<=endrow || self->getNumColumns()<=endcol) rb_raise(rb_eIndexError,"index out of bounds"); - self->extractText(text,size,startrow,endrow,startcol,endcol,cs,rs); - result=rb_str_new2(text); - FXFREE(&text); + self->extractText(str,startrow,endrow,startcol,endcol,cs,rs); + result=rb_str_new2(str.text()); return result; } /// Overlay text over given cell range void overlayText(FXint startrow,FXint endrow,FXint startcol,FXint endcol,VALUE str,const FXchar* cs="\t",const FXchar* rs="\n",FXbool notify=FALSE){ if(startrow<0 || startcol<0 || self->getNumRows()<=endrow || self->getNumColumns()<=endcol) rb_raise(rb_eIndexError,"index out of bounds"); - const FXchar* text=reinterpret_cast<FXchar*>(STR2CSTR(str)); - FXint size=RSTRING(str)->len; + const FXchar* text=reinterpret_cast<FXchar*>(StringValuePtr(str)); + FXint size=RSTRING_LEN(str); self->overlayText(startrow,endrow,startcol,endcol,text,size,cs,rs,notify); } } diff --git a/swig-interfaces/FXText.i b/swig-interfaces/FXText.i index 0a0d45e..0c3e996 100755 --- a/swig-interfaces/FXText.i +++ b/swig-interfaces/FXText.i @@ -43,7 +43,20 @@ enum FXTextSelectionMode { /// Highlight style entry struct FXHiliteStyle { - FXHiliteStyle(); + %extend { + FXHiliteStyle(){ + FXHiliteStyle *self = new FXHiliteStyle(); + self->normalForeColor = 0; + self->normalBackColor = 0; + self->selectForeColor = 0; + self->selectBackColor = 0; + self->hiliteForeColor = 0; + self->hiliteBackColor = 0; + self->activeBackColor = 0; + self->style = 0; + return self; + } + } FXColor normalForeColor; /// Normal text foreground color FXColor normalBackColor; /// Normal text background color FXColor selectForeColor; /// Selected text foreground color @@ -519,29 +532,25 @@ public: * both are NULL, internal arrays are used. * [This API is still subject to change!!] */ - VALUE findText(const FXString& string,FXint start=0,FXuint flags=SEARCH_FORWARD|SEARCH_WRAP|SEARCH_EXACT,FXint npar=1){ + VALUE findText(const FXString& string,FXint start=0,FXuint flags=SEARCH_FORWARD|SEARCH_WRAP|SEARCH_EXACT){ FXint* beg; FXint* end; VALUE ary=Qnil; - - if(!FXMALLOC(&beg,FXint,npar)){ + FXint ngroups=string.contains('(')+1; // FIXME: is this right? + if(!FXMALLOC(&beg,FXint,ngroups)){ return Qnil; - } - - if(!FXMALLOC(&end,FXint,npar)){ + } + if(!FXMALLOC(&end,FXint,ngroups)){ FXFREE(&beg); - return Qnil; - } - - if(self->findText(string,beg,end,start,flags,npar)){ + return Qnil; + } + if(self->findText(string,beg,end,start,flags,ngroups)){ ary=rb_ary_new(); - rb_ary_push(ary,FXRbMakeArray(beg,npar)); - rb_ary_push(ary,FXRbMakeArray(end,npar)); + rb_ary_push(ary,FXRbMakeArray(beg,ngroups)); + rb_ary_push(ary,FXRbMakeArray(end,ngroups)); } - FXFREE(&beg); FXFREE(&end); - return ary; } } @@ -706,7 +715,7 @@ public: delete [] text->styles; text->numStyles=0; } - text->numStyles=RARRAY(styles)->len; + text->numStyles=RARRAY_LEN(styles); if(text->numStyles>0){ text->styles=new FXHiliteStyle[text->numStyles]; for (long i=0; i<text->numStyles; i++){ diff --git a/swig-interfaces/FXVec2d.i b/swig-interfaces/FXVec2d.i index 3b29672..2544794 100755 --- a/swig-interfaces/FXVec2d.i +++ b/swig-interfaces/FXVec2d.i @@ -27,15 +27,12 @@ public: FXdouble y; public: - /// Default constructor - FXVec2d(); + /// Initialize with components + FXVec2d(FXdouble xx=0.0,FXdouble yy=0.0); /// Copy constructor FXVec2d(const FXVec2d& v); - /// Initialize with components - FXVec2d(FXdouble xx,FXdouble yy); - /// Length and square of length FXdouble length2() const; FXdouble length() const; diff --git a/swig-interfaces/FXVec2f.i b/swig-interfaces/FXVec2f.i index b590a5e..173bbcc 100755 --- a/swig-interfaces/FXVec2f.i +++ b/swig-interfaces/FXVec2f.i @@ -27,8 +27,8 @@ public: FXfloat y; public: - /// Default constructor - FXVec2f(); + /// Initialize with components + FXVec2f(FXfloat xx=0.0f,FXfloat yy=0.0f); /// Copy constructor FXVec2f(const FXVec2f& v); @@ -36,9 +36,6 @@ public: // Initialize from array of floats FXVec2f(const FXfloat v[]); - /// Initialize with components - FXVec2f(FXfloat xx,FXfloat yy); - /// Length and square of length FXfloat length2() const; FXfloat length() const; diff --git a/swig-interfaces/FXVec3d.i b/swig-interfaces/FXVec3d.i index 0ac564b..61d78e6 100755 --- a/swig-interfaces/FXVec3d.i +++ b/swig-interfaces/FXVec3d.i @@ -29,7 +29,11 @@ public: public: /// Default constructor - FXVec3d(); + %extend { + FXVec3d() { + return new FXVec3d(0.0, 0.0, 0.0); + } + } /// Copy constructor FXVec3d(const FXVec3d& v); diff --git a/swig-interfaces/FXVec3f.i b/swig-interfaces/FXVec3f.i index 86ce492..f32b33d 100755 --- a/swig-interfaces/FXVec3f.i +++ b/swig-interfaces/FXVec3f.i @@ -29,7 +29,11 @@ public: public: /// Default constructor - FXVec3f(); + %extend { + FXVec3f() { + return new FXVec3f(0.0f, 0.0f, 0.0f); + } + } /// Copy constructor FXVec3f(const FXVec3f& v); diff --git a/swig-interfaces/FXVec4d.i b/swig-interfaces/FXVec4d.i index 7882ffe..ff3560f 100755 --- a/swig-interfaces/FXVec4d.i +++ b/swig-interfaces/FXVec4d.i @@ -32,7 +32,11 @@ public: public: /// Default constructor - FXVec4d(); + %extend { + FXVec4d() { + return new FXVec4d(0.0, 0.0, 0.0, 0.0); + } + } /// Copy constructor FXVec4d(const FXVec4d& v); diff --git a/swig-interfaces/FXVec4f.i b/swig-interfaces/FXVec4f.i index 0eeaa66..2ba700a 100755 --- a/swig-interfaces/FXVec4f.i +++ b/swig-interfaces/FXVec4f.i @@ -32,7 +32,11 @@ public: public: /// Default constructor - FXVec4f(); + %extend { + FXVec4f() { + return new FXVec4f(0.0f, 0.0f, 0.0f, 0.0f); + } + } /// Copy constructor FXVec4f(const FXVec4f& w); diff --git a/swig-interfaces/FXWindow.i b/swig-interfaces/FXWindow.i index 28aad47..5f24621 100755 --- a/swig-interfaces/FXWindow.i +++ b/swig-interfaces/FXWindow.i @@ -595,7 +595,7 @@ public: bool acquireSelection(VALUE typesArray){ Check_Type(typesArray,T_ARRAY); FXDragType *types=0; - FXuint numtypes=RARRAY(typesArray)->len; + FXuint numtypes=RARRAY_LEN(typesArray); if(numtypes>0){ types=new FXDragType[numtypes]; for(FXuint i=0;i<numtypes;i++){ @@ -619,7 +619,7 @@ public: bool acquireClipboard(VALUE typesArray){ Check_Type(typesArray,T_ARRAY); FXDragType *types=0; - FXuint numtypes=RARRAY(typesArray)->len; + FXuint numtypes=RARRAY_LEN(typesArray); if(numtypes>0){ types=new FXDragType[numtypes]; for(FXuint i=0;i<numtypes;i++){ @@ -646,7 +646,7 @@ public: bool beginDrag(VALUE typesArray){ Check_Type(typesArray,T_ARRAY); FXDragType *types=0; - FXuint numtypes=RARRAY(typesArray)->len; + FXuint numtypes=RARRAY_LEN(typesArray); if(numtypes>0){ types=new FXDragType[numtypes]; for(FXuint i=0;i<numtypes;i++){ @@ -728,9 +728,9 @@ public: void setDNDData(FXDNDOrigin origin, FXDragType type, VALUE str) const { Check_Type(str, T_STRING); FXuchar* data; - FXuint size = RSTRING(str)->len; + FXuint size = RSTRING_LEN(str); if (FXMALLOC(&data, FXuchar, size)) { - memcpy((void *) data, (void *) RSTRING(str)->ptr, size); + memcpy((void *) data, (void *) RSTRING_PTR(str), size); self->setDNDData(origin, type, data, size); } else { rb_raise(rb_eNoMemError, "couldn't copy drag-and-drop data"); diff --git a/swig-interfaces/FXXPMIcon.i b/swig-interfaces/FXXPMIcon.i index cc29a04..e648f46 100755 --- a/swig-interfaces/FXXPMIcon.i +++ b/swig-interfaces/FXXPMIcon.i @@ -86,7 +86,7 @@ DECLARE_FXIMAGE_VIRTUALS(FXXPMIcon) // Confirm that the input is an array of strings Check_Type(strArray,T_ARRAY); - len=RARRAY(strArray)->len; + len=RARRAY_LEN(strArray); for(i=0; i<len; i++){ str=rb_ary_entry(strArray,i); Check_Type(str,T_STRING); diff --git a/swig-interfaces/Makefile b/swig-interfaces/Makefile index ee28aae..a989672 100755 --- a/swig-interfaces/Makefile +++ b/swig-interfaces/Makefile @@ -2,17 +2,17 @@ # This makefile is used to generate the wrapper code from the # SWIG interface files. # -# $Id: Makefile 2300 2005-12-07 14:05:03Z lyle $ +# $Id: Makefile 2827 2008-03-28 16:04:44Z lyle $ # .PHONY: clean -SWIG = swig +SWIG = /usr/local/bin/swig SWIGFLAGS = -fcompact -noruntime -c++ -ruby -no_default -I../fox-includes SRCDIR = ../ext/fox16 SED = sed -f swig.sed RUBY = ruby -SWIGLIB := $(shell swig -swiglib) +SWIGLIB := $(shell /usr/local/bin/swig -swiglib) MODULES = \ $(SRCDIR)/core_wrap.cpp \ diff --git a/swig-interfaces/macros.i b/swig-interfaces/macros.i index 4d251bd..aacc3ff 100755 --- a/swig-interfaces/macros.i +++ b/swig-interfaces/macros.i @@ -433,8 +433,8 @@ /// See if font has glyph for ch virtual FXbool hasChar(VALUE ch) const { if(TYPE(ch)==T_STRING){ - if(RSTRING(ch)->len==1){ - return self->hasChar(*(STR2CSTR(ch))); // FIXME: hasChar() expects an FXwchar + if(RSTRING_LEN(ch)==1){ + return self->hasChar(*(StringValuePtr(ch))); // FIXME: hasChar() expects an FXwchar } else{ rb_raise(rb_eArgError,"expected a string of length one"); @@ -708,7 +708,7 @@ %extend klass { /** * Retrieves pixels from the server-side image. For example, to make - * screen snapshots, or to retrieve an image after it has been drawin + * screen snapshots, or to retrieve an image after it has been drawn * into by various means. */ virtual void restore(); diff --git a/swig-interfaces/ruby-typemaps.i b/swig-interfaces/ruby-typemaps.i index 61ae723..a059b04 100755 --- a/swig-interfaces/ruby-typemaps.i +++ b/swig-interfaces/ruby-typemaps.i @@ -20,9 +20,13 @@ * at "lyle@users.sourceforge.net". ***********************************************************************/ -/*********************************************************************** - * $Id: ruby-typemaps.i 2460 2006-07-09 23:38:59Z lyle $ - ***********************************************************************/ +%include constraints.i + +%apply Pointer NONNULL { + FXApp* APP, + FXComposite* PARENT, + FXWindow* OWNER +} /* Type-checking rules */ %typecheck(SWIG_TYPECHECK_STRING) const FXString&, FXuchar *data { @@ -61,7 +65,7 @@ inline FXColor to_FXColor(VALUE obj){ inline FXString to_FXString(VALUE obj){ if(!NIL_P(obj)){ Check_Type(obj,T_STRING); - return FXString(STR2CSTR(obj)); + return FXString(StringValuePtr(obj)); } else{ return FXString::null; @@ -112,7 +116,7 @@ inline FXbool to_FXbool(VALUE obj){ %typemap(in) const void* pix { if ($input != Qnil) { Check_Type($input, T_STRING); - $1 = reinterpret_cast<$1_ltype>(RSTRING($input)->ptr); + $1 = reinterpret_cast<$1_ltype>(RSTRING_PTR($input)); } else { $1 = NULL; } @@ -127,8 +131,8 @@ inline FXbool to_FXbool(VALUE obj){ $1=NULL; if($input!=Qnil){ Check_Type($input,T_ARRAY); - if(FXMALLOC(&$1,FXColor,RARRAY($input)->len)){ - for(long i=0; i<RARRAY($input)->len; i++){ + if(FXMALLOC(&$1,FXColor,RARRAY_LEN($input))){ + for(long i=0; i<RARRAY_LEN($input); i++){ $1[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry($input,i))); } } @@ -149,9 +153,10 @@ inline FXbool to_FXbool(VALUE obj){ $1 = NULL; if ($input != Qnil) { Check_Type($input, T_ARRAY); - if (FXMALLOC(&$1, FXchar *, RARRAY($input)->len)) { - for (long i = 0; i < RARRAY($input)->len; i++) { - $1[i] = (FXchar *) STR2CSTR(rb_ary_entry($input, i)); + if (FXMALLOC(&$1, FXchar *, RARRAY_LEN($input))) { + for (long i = 0; i < RARRAY_LEN($input); i++) { + VALUE e = rb_ary_entry($input, i); + $1[i] = (FXchar *) StringValuePtr(e); } } } @@ -166,7 +171,7 @@ inline FXbool to_FXbool(VALUE obj){ %typecheck(SWIG_TYPECHECK_STRING_ARRAY) const FXchar** strings { $1 = (TYPE($input) == T_ARRAY) ? 1 : 0; if ($1 != 0) { - for (long i = 0; i < RARRAY($input)->len; i++) { + for (long i = 0; i < RARRAY_LEN($input); i++) { if (TYPE(rb_ary_entry($input, i)) != T_STRING) { $1 = 0; break; @@ -179,11 +184,12 @@ inline FXbool to_FXbool(VALUE obj){ $1 = NULL; if(!NIL_P($input)){ Check_Type($input, T_ARRAY); - if (FXMALLOC(&$1, FXchar *, RARRAY($input)->len)+1) { - for (long i = 0; i < RARRAY($input)->len; i++) { - $1[i] = (FXchar *) STR2CSTR(rb_ary_entry($input, i)); + if (FXMALLOC(&$1, FXchar *, RARRAY_LEN($input))+1) { + for (long i = 0; i < RARRAY_LEN($input); i++) { + VALUE e = rb_ary_entry($input, i); + $1[i] = (FXchar *) StringValuePtr(e); } - $1[RARRAY($input)->len] = 0; + $1[RARRAY_LEN($input)] = 0; } } } @@ -195,11 +201,11 @@ inline FXbool to_FXbool(VALUE obj){ $1 = NULL; if(!NIL_P($input)){ Check_Type($input, T_ARRAY); - if (FXMALLOC(&$1, FXColor, RARRAY($input)->len)+1) { - for (long i = 0; i < RARRAY($input)->len; i++) { + if (FXMALLOC(&$1, FXColor, RARRAY_LEN($input))+1) { + for (long i = 0; i < RARRAY_LEN($input); i++) { $1[i] = static_cast<FXColor>(NUM2ULONG(rb_ary_entry($input, i))); } - $1[RARRAY($input)->len] = 0; + $1[RARRAY_LEN($input)] = 0; } } } @@ -231,7 +237,7 @@ inline void* to_FXEvent(VALUE obj){ %typemap(in) void* PTR_COLOR "$1 = reinterpret_cast<void*>(NUM2UINT($input));"; /* Convert a Ruby string to a C string */ -%typemap(in) void* PTR_CSTRING "$1 = static_cast<void*>(STR2CSTR($input));"; +%typemap(in) void* PTR_CSTRING "$1 = static_cast<void*>(StringValuePtr($input));"; /* Convert a Ruby array (of size 2) into an FXdouble array */ %typemap(in) void* PTR_DBLRANGE_IN(FXdouble values[2]) { @@ -320,7 +326,7 @@ inline void* to_FXEvent(VALUE obj){ /* Convert a Ruby string to a pointer to an FXString */ %typemap(in) void* PTR_STRING(FXString value) { - value = FXString(STR2CSTR($input)); + value = FXString(StringValuePtr($input)); $1 = (void *) &value; } @@ -456,6 +462,14 @@ inline void* to_FXEvent(VALUE obj){ } %typemap(out) FXMat4f& "$result = FXRbGetRubyObj($1, \"$1_ltype\");"; +/* Output typemap for FXVec2d instances */ +%typemap(out) FXVec2d* "$result = FXRbGetRubyObj($1, \"$1_ltype\");"; +%typemap(out) FXVec2d& "$result = FXRbGetRubyObj($1, \"$1_ltype\");"; + +/* Output typemap for FXVec2f instances */ +%typemap(out) FXVec2f* "$result = FXRbGetRubyObj($1, \"$1_ltype\");"; +%typemap(out) FXVec2f& "$result = FXRbGetRubyObj($1, \"$1_ltype\");"; + /* Output typemap for FXVec4f instances */ %typemap(out) FXVec4f { FXVec4f* resultptr = new FXVec4f($1); @@ -604,8 +618,8 @@ inline void* to_FXEvent(VALUE obj){ } %typemap(in) (const FXPoint* points, FXuint npoints) { Check_Type($input, T_ARRAY); - $1 = new FXPoint[RARRAY($input)->len]; - $2 = static_cast<FXuint>( RARRAY($input)->len ); + $1 = new FXPoint[RARRAY_LEN($input)]; + $2 = static_cast<FXuint>( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { FXPoint *pPoint; Data_Get_Struct(rb_ary_entry($input, i), FXPoint, pPoint); @@ -619,8 +633,8 @@ inline void* to_FXEvent(VALUE obj){ // Extract a C array (segments) and its length (nsegments) from a Ruby array of FXSegment instances %typemap(in) (const FXSegment* segments, FXuint nsegments) { Check_Type($input, T_ARRAY); - $1 = new FXSegment[RARRAY($input)->len]; - $2 = static_cast<FXuint>( RARRAY($input)->len ); + $1 = new FXSegment[RARRAY_LEN($input)]; + $2 = static_cast<FXuint>( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { FXSegment *pSeg; Data_Get_Struct(rb_ary_entry($input, i), FXSegment, pSeg); @@ -635,8 +649,8 @@ inline void* to_FXEvent(VALUE obj){ // Extract a C array (rectangles) and its length (nrectangles) from a Ruby array of FXRectangle instances %typemap(in) (const FXRectangle* rectangles, FXuint nrectangles) { Check_Type($input, T_ARRAY); - $1 = new FXRectangle[RARRAY($input)->len]; - $2 = static_cast<FXuint>( RARRAY($input)->len ); + $1 = new FXRectangle[RARRAY_LEN($input)]; + $2 = static_cast<FXuint>( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { FXRectangle *pRect; Data_Get_Struct(rb_ary_entry($input, i), FXRectangle, pRect); @@ -651,8 +665,8 @@ inline void* to_FXEvent(VALUE obj){ // Extract a C array (arcs) and its length (narcs) from a Ruby array of FXArc instances %typemap(in) (const FXArc* arcs, FXuint narcs) { Check_Type($input, T_ARRAY); - $1 = new FXArc[RARRAY($input)->len]; - $2 = static_cast<FXuint>( RARRAY($input)->len ); + $1 = new FXArc[RARRAY_LEN($input)]; + $2 = static_cast<FXuint>( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { FXArc *pArc; Data_Get_Struct(rb_ary_entry($input, i), FXArc, pArc); @@ -667,15 +681,15 @@ inline void* to_FXEvent(VALUE obj){ // Extract the C string pointer and string length from a Ruby string %typemap(in) (const FXchar* string, FXuint length) { Check_Type($input, T_STRING); - $1 = STR2CSTR($input); - $2 = RSTRING($input)->len; + $1 = StringValuePtr($input); + $2 = RSTRING_LEN($input); } // Extract a C array (dashpattern) and its length (dashlength) from a Ruby array of Fixnums %typemap(in) (const FXchar* dashpattern, FXuint dashlength) { Check_Type($input, T_ARRAY); - $1 = new FXchar[RARRAY($input)->len]; - $2 = static_cast<FXuint>( RARRAY($input)->len ); + $1 = new FXchar[RARRAY_LEN($input)]; + $2 = static_cast<FXuint>( RARRAY_LEN($input) ); for (FXuint i = 0; i < $2; i++) { $1[i] = NUM2INT(rb_ary_entry($input, i)); } @@ -687,8 +701,8 @@ inline void* to_FXEvent(VALUE obj){ %typemap(in) (FXuint* path, FXint n) { Check_Type($input, T_ARRAY); - FXMALLOC(&$1,FXuint,RARRAY($input)->len); - $2=static_cast<FXint>(RARRAY($input)->len); + FXMALLOC(&$1,FXuint,RARRAY_LEN($input)); + $2=static_cast<FXint>(RARRAY_LEN($input)); for(FXint i=0; i<$2; i++){ $1[i]=NUM2UINT(rb_ary_entry($input,i)); } @@ -701,8 +715,8 @@ inline void* to_FXEvent(VALUE obj){ /* Convert an array of FXColor values (see constructor for FXMemoryBuffer) */ %typemap(in) (FXColor *data,FXuint size) { Check_Type($input, T_ARRAY); - FXMALLOC(&$1,FXColor,RARRAY($input)->len); - $2=static_cast<FXuint>(RARRAY($input)->len); + FXMALLOC(&$1,FXColor,RARRAY_LEN($input)); + $2=static_cast<FXuint>(RARRAY_LEN($input)); for(FXint i=0; i<$2; i++){ $1[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry($input,i))); } @@ -746,7 +760,7 @@ inline void* to_FXEvent(VALUE obj){ /* Convert an FXID to a Ruby Integer (fxid_to_int() is defined in FXRuby.h) */ %typemap(out) FXID "$result = fxid_to_int($1);"; -%typemap(in) FXuchar *data "$1 = NIL_P($input) ? 0 : reinterpret_cast<FXuchar*>(STR2CSTR($input));"; +%typemap(in) FXuchar *data "$1 = NIL_P($input) ? 0 : reinterpret_cast<FXuchar*>(StringValuePtr($input));"; // FXlong values %typemap(in) FXlong "$1 = static_cast<FXlong>(NUM2LONG($input));"; diff --git a/tests/TC_FXApp.rb b/tests/TC_FXApp.rb index a21747c..3c706ec 100755 --- a/tests/TC_FXApp.rb +++ b/tests/TC_FXApp.rb @@ -1,15 +1,16 @@ require 'test/unit' require 'fox16' -require 'testcase' include Fox -class TC_FXApp < TestCase - def setup - super(self.class.name) - end - def test_initialized - assert(app.initialized?) +class TC_FXApp < Test::Unit::TestCase + def test_exception_for_second_app + app = FXApp.new + mainWindow = FXMainWindow.new(app, "") + app.create + assert_raise RuntimeError do + app2 = FXApp.new + end end end diff --git a/tests/TC_FXButton.rb b/tests/TC_FXButton.rb index cc80bd8..ac4484f 100755 --- a/tests/TC_FXButton.rb +++ b/tests/TC_FXButton.rb @@ -69,4 +69,10 @@ class TC_FXButton < TestCase @button.state = STATE_UNCHECKED assert_equal(STATE_UNCHECKED, @button.state) end + + def test_create_for_non_created_parent_window_raises_runtime_error + assert_raise RuntimeError do + @button.create + end + end end diff --git a/tests/TC_FXComboBox.rb b/tests/TC_FXComboBox.rb index 6c2ac89..faaf6ae 100755 --- a/tests/TC_FXComboBox.rb +++ b/tests/TC_FXComboBox.rb @@ -48,5 +48,16 @@ class TC_FXComboBox < TestCase end end + def test_fill_items_returns_num_items_added + assert_equal(3, @comboBox.fillItems(%w{one two three})) + end + + def test_fill_items + @comboBox.fillItems(%w{one two three}) + items = @comboBox.map { |text, data| text } + assert_equal("one", items[0]) + assert_equal("two", items[1]) + assert_equal("three", items[2]) + end end diff --git a/tests/TC_FXDC.rb b/tests/TC_FXDC.rb index bb7a3d7..e4d25c3 100755 --- a/tests/TC_FXDC.rb +++ b/tests/TC_FXDC.rb @@ -79,7 +79,7 @@ class TC_FXDC < Test::Unit::TestCase @dc.fillRectangle(x, y, w, h) end - def testFillRectangles(rectangles) + def testFillRectangles rectangles = [ FXRectangle.new, FXRectangle.new ] @dc.fillRectangles(rectangles) end diff --git a/tests/TC_FXDCPrint.rb b/tests/TC_FXDCPrint.rb index 96907f8..c06fa52 100755 --- a/tests/TC_FXDCPrint.rb +++ b/tests/TC_FXDCPrint.rb @@ -1,7 +1,6 @@ require 'test/unit' require 'fox16' -require 'ftools' include Fox @@ -64,14 +63,14 @@ public def test_beginPrint @dc.beginPrint(printJob) @dc.endPrint - assert_same_file_contents("blankpage.ps", printJob.name) + assert_same_file_contents(File.join(File.dirname(__FILE__), "blankpage.ps"), printJob.name) end def test_beginPrint_with_block @dc.beginPrint(printJob) do |theDC| assert_same(@dc, theDC) end - assert_same_file_contents("blankpage.ps", printJob.name) + assert_same_file_contents(File.join(File.dirname(__FILE__), "blankpage.ps"), printJob.name) end def test_beginPage @@ -96,7 +95,7 @@ public def teardown if File.exists?("output.ps") - File.rm_f("output.ps") + FileUtils.rm_f("output.ps") end end end diff --git a/tests/TC_FXDialogBox.rb b/tests/TC_FXDialogBox.rb new file mode 100644 index 0000000..e65bee6 --- /dev/null +++ b/tests/TC_FXDialogBox.rb @@ -0,0 +1,12 @@ +require 'test/unit' +require 'fox16' + +include Fox + +class TC_FXDialogBox < Test::Unit::TestCase + def test_nil_app_raises_argument_error + assert_raise ArgumentError do + FXDialogBox.new(nil, "title") + end + end +end \ No newline at end of file diff --git a/tests/TC_FXExtentd.rb b/tests/TC_FXExtentd.rb new file mode 100755 index 0000000..64d37b0 --- /dev/null +++ b/tests/TC_FXExtentd.rb @@ -0,0 +1,21 @@ +require 'test/unit' +require 'fox16' + +include Fox + +class TC_FXExtentd < Test::Unit::TestCase + def test_lower_always_returns_same_instance + e = FXExtentd.new(0, 1, 0, 1) + assert_same e.lower, e.lower + end + + def test_upper_always_returns_same_instance + e = FXExtentd.new(0, 1, 0, 1) + assert_same e.upper, e.upper + end + + def test_index_always_returns_same_instance + e = FXExtentd.new(0, 1, 0, 1) + assert_same e[0], e[0] + end +end diff --git a/tests/TC_FXExtentf.rb b/tests/TC_FXExtentf.rb new file mode 100755 index 0000000..87a0db6 --- /dev/null +++ b/tests/TC_FXExtentf.rb @@ -0,0 +1,21 @@ +require 'test/unit' +require 'fox16' + +include Fox + +class TC_FXExtentf < Test::Unit::TestCase + def test_lower_always_returns_same_instance + e = FXExtentf.new(0, 1, 0, 1) + assert_same e.lower, e.lower + end + + def test_upper_always_returns_same_instance + e = FXExtentf.new(0, 1, 0, 1) + assert_same e.upper, e.upper + end + + def test_index_always_returns_same_instance + e = FXExtentf.new(0, 1, 0, 1) + assert_same e[0], e[0] + end +end diff --git a/tests/TC_FXFileStream.rb b/tests/TC_FXFileStream.rb index d331a88..22c9488 100755 --- a/tests/TC_FXFileStream.rb +++ b/tests/TC_FXFileStream.rb @@ -1,6 +1,5 @@ require 'test/unit' require 'fox16' -require 'ftools' require 'tempfile' include Fox @@ -84,7 +83,7 @@ class TC_FXFileStream < Test::Unit::TestCase def teardown if File.exists?("goobers") - File.rm_f("goobers") + FileUtils.rm_f("goobers") end end end diff --git a/tests/TC_FXFoldingList.rb b/tests/TC_FXFoldingList.rb new file mode 100755 index 0000000..056c2b0 --- /dev/null +++ b/tests/TC_FXFoldingList.rb @@ -0,0 +1,32 @@ +require 'test/unit' +require 'testcase' +require 'fox16' + +include Fox + +class TC_FXFoldingList < TestCase + + def setup + super(self.class.name) + @foldingList = FXFoldingList.new(mainWindow) + end + + def test_each_for_empty_list + count = 0 + @foldingList.each { |item| count += 1 } + assert_equal(0, count, "count for empty list should be zero") + end + + def test_each + @foldingList.appendItem(nil, "1") + @foldingList.appendItem(nil, "2") + @foldingList.appendItem(nil, "3") + @foldingList.appendItem(nil, "4") + @foldingList.appendItem(nil, "5") + count = 0 + @foldingList.each { |item| count += 1 } + assert_equal(5, count, "count didn't match expected number of items") + end + +end + diff --git a/tests/TC_FXHiliteStyle.rb b/tests/TC_FXHiliteStyle.rb new file mode 100755 index 0000000..35fe085 --- /dev/null +++ b/tests/TC_FXHiliteStyle.rb @@ -0,0 +1,23 @@ +require 'fox16' +require 'test/unit' + +include Fox + +class TC_FXHiliteStyle < Test::Unit::TestCase + + def setup + @style = FXHiliteStyle.new + end + + def test_new_object_is_initialized + assert_equal(0, @style.normalForeColor) + assert_equal(0, @style.normalBackColor) + assert_equal(0, @style.selectForeColor) + assert_equal(0, @style.selectBackColor) + assert_equal(0, @style.hiliteForeColor) + assert_equal(0, @style.hiliteBackColor) + assert_equal(0, @style.activeBackColor) + assert_equal(0, @style.style) + end +end + diff --git a/tests/TC_FXId.rb b/tests/TC_FXId.rb index a6f4d4d..fae3391 100755 --- a/tests/TC_FXId.rb +++ b/tests/TC_FXId.rb @@ -10,10 +10,10 @@ class TC_FXId < TestCase end def test_created? - assert(!mainWindow.created?) + assert !mainWindow.created? app.create - assert(mainWindow.created?) + assert mainWindow.created?, "main window should be created after call to FXApp#create" mainWindow.destroy - assert(!mainWindow.created?) + assert !mainWindow.created? end end diff --git a/tests/TC_FXMainWindow.rb b/tests/TC_FXMainWindow.rb new file mode 100644 index 0000000..aa88b1d --- /dev/null +++ b/tests/TC_FXMainWindow.rb @@ -0,0 +1,19 @@ +require 'test/unit' +require 'fox16' + +include Fox + +class TC_FXMainWindow < Test::Unit::TestCase + def test_nil_app_raises_argument_error + assert_raise ArgumentError do + FXMainWindow.new(nil, "title") + end + end + + def test_non_created_app_raises_runtime_error + app = FXApp.new + assert_raise RuntimeError do + FXMainWindow.new(app, "title").create + end + end +end \ No newline at end of file diff --git a/tests/TC_FXMessageBox.rb b/tests/TC_FXMessageBox.rb new file mode 100755 index 0000000..f926d29 --- /dev/null +++ b/tests/TC_FXMessageBox.rb @@ -0,0 +1,25 @@ +require 'test/unit' +require 'testcase' +require 'fox16' + +include Fox + +class TC_FXMessageBox < TestCase + def setup + super(self.class.name) + end + + def test_construct_with_save_cancel_dontsave + assert_nothing_raised(RangeError) do + FXMessageBox.new(mainWindow, "Save?", "Save?", :opts => MBOX_SAVE_CANCEL_DONTSAVE) + end + end + + def test_mbox_clicked_dontsave_defined + assert(Fox.const_defined?(:MBOX_CLICKED_DONTSAVE)) + end + + def test_mbox_clicked_dontsave_equal_to_mbox_clicked_no + assert_equal(MBOX_CLICKED_NO, MBOX_CLICKED_DONTSAVE) + end +end diff --git a/tests/TC_FXQuatf.rb b/tests/TC_FXQuatf.rb index c9b99e0..d2a5b62 100755 --- a/tests/TC_FXQuatf.rb +++ b/tests/TC_FXQuatf.rb @@ -7,67 +7,83 @@ class TC_FXQuatf < Test::Unit::TestCase def setup @quat = FXQuatf.new end + def test_default_constructor q = FXQuatf.new end + def test_construct_from_axis_and_angle axis = FXVec3f.new(1.0, 1.0, 1.0) q = FXQuatf.new(axis) q = FXQuatf.new(axis, 0.0) end + def test_construct_from_components x, y, z, w = 1.0, 1.0, 1.0, 1.0 q = FXQuatf.new(x, y, z, w) end + def test_construct_from_roll_pitch_yaw roll, pitch, yaw = 45.0, 45.0, 45.0 q = FXQuatf.new(roll, pitch, yaw) end + def test_adjust! adjusted = @quat.adjust! assert_same(@quat, adjusted) end - def test_setAxisAngle - end - def test_getAxisAngle - end + def test_setRollPitchYaw roll, pitch, yaw = 0.0, 0.0, 0.0 @quat.setRollPitchYaw(roll, pitch, yaw) end + def test_getRollPitchYaw rpy = @quat.getRollPitchYaw() assert_instance_of(Array, rpy) assert_equal(3, rpy.length) end + def test_exp expQuat = @quat.exp assert_instance_of(FXQuatf, expQuat) end + def test_log logQuat = @quat.log assert_instance_of(FXQuatf, logQuat) end + def test_invert invertQuat = @quat.invert assert_instance_of(FXQuatf, invertQuat) end + def test_conj conjQuat = @quat.conj assert_instance_of(FXQuatf, conjQuat) end - def test_mul - anotherQuat = FXQuatf.new - product = @quat*anotherQuat + + def test_multiplication_result_is_another_quat + q1 = FXQuatf.new(1, 2, 3, 4) + q2 = FXQuatf.new(1, 2, 3, 4) + product = q1*q2 assert_instance_of(FXQuatf, product) - assert_equal(product, anotherQuat*@quat) end + + def test_multiplication_is_commutative + q1 = FXQuatf.new(1, 2, 3, 4) + q2 = FXQuatf.new(1, 2, 3, 4) + assert_equal(q1*q2, q2*q1) + end + def test_arc a = FXVec3f.new(0.0, 0.0, 0.0) b = FXVec3f.new(0.0, 0.0, 0.0) q = FXQuatf.arc(a, b) assert_instance_of(FXQuatf, q) end + def test_lerp u = FXQuatf.new v = FXQuatf.new diff --git a/tests/TC_FXRanged.rb b/tests/TC_FXRanged.rb new file mode 100755 index 0000000..1cf193c --- /dev/null +++ b/tests/TC_FXRanged.rb @@ -0,0 +1,42 @@ +require 'test/unit' + +require 'fox16' + +include Fox + +class TC_FXRanged < Test::Unit::TestCase + + WIDTH, HEIGHT, DEPTH = 2, 4, 6 + + def setup + @range = FXRanged.new(0, WIDTH, 0, HEIGHT, 0, DEPTH) + end + + def test_lower_is_a_vector + assert_instance_of(FXVec3d, @range.lower) + end + + def test_upper_is_a_vector + assert_instance_of(FXVec3d, @range.upper) + end + + def test_width + assert_equal(@range.width, WIDTH) + end + + def test_height + assert_equal(@range.height, HEIGHT) + end + + def test_depth + assert_equal(@range.depth, DEPTH) + end + + def test_longest + assert_equal([@range.width, @range.height, @range.depth].max, @range.longest) + end + + def test_shortest + assert_equal([@range.width, @range.height, @range.depth].min, @range.shortest) + end +end diff --git a/tests/TC_FXRangef.rb b/tests/TC_FXRangef.rb index 307f9df..f302d95 100755 --- a/tests/TC_FXRangef.rb +++ b/tests/TC_FXRangef.rb @@ -12,37 +12,31 @@ class TC_FXRangef < Test::Unit::TestCase @range = FXRangef.new(0, WIDTH, 0, HEIGHT, 0, DEPTH) end + def test_lower_is_a_vector + assert_instance_of(FXVec3f, @range.lower) + end + + def test_upper_is_a_vector + assert_instance_of(FXVec3f, @range.upper) + end + def test_width assert_equal(@range.width, WIDTH) end + def test_height assert_equal(@range.height, HEIGHT) end + def test_depth assert_equal(@range.depth, DEPTH) end + def test_longest assert_equal([@range.width, @range.height, @range.depth].max, @range.longest) end + def test_shortest assert_equal([@range.width, @range.height, @range.depth].min, @range.shortest) end - def test_empty? - end - def test_overlaps? - end - def test_contains? - end - def test_include - end - def test_clipTo - end - def test_corners - end - def test_intersects? - end - def test_center - end - def test_diagonal - end end diff --git a/tests/TC_FXTable.rb b/tests/TC_FXTable.rb index 067d722..8cfb169 100755 --- a/tests/TC_FXTable.rb +++ b/tests/TC_FXTable.rb @@ -365,4 +365,197 @@ public assert_equal("(1, 0)", @table.getItemText(1, 0)) assert_equal("(1, 1)", @table.getItemText(1, 1)) end + + def test_set_column_icon_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnIcon(-1, nil) + } + end + + def test_set_column_icon_large_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnIcon(@table.numColumns, nil) + } + end + + def test_get_column_icon_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnIcon(-1) + } + end + + def test_get_column_icon_large_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnIcon(@table.numColumns) + } + end + + def test_set_column_icon_position_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnIconPosition(-1, 0) + } + end + + def test_set_column_icon_position_large_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnIconPosition(@table.numColumns, 0) + } + end + + def test_get_column_icon_position_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnIconPosition(-1) + } + end + + def test_get_column_icon_position_large_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnIconPosition(@table.numColumns) + } + end + + def test_set_column_justify_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnJustify(-1, 0) + } + end + + def test_set_column_justify_large_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnJustify(@table.numColumns, 0) + } + end + + def test_get_column_justify_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnJustify(-1) + } + end + + def test_get_column_justify_large_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnJustify(@table.numColumns) + } + end + + def test_set_column_text_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnText(-1, "") + } + end + + def test_set_column_text_large_index_raises_index_error + assert_raises(IndexError) { + @table.setColumnText(@table.numColumns, "") + } + end + + def test_get_column_text_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnText(-1) + } + end + + def test_get_column_text_large_index_raises_index_error + assert_raises(IndexError) { + @table.getColumnText(@table.numColumns) + } + end + + def test_set_row_icon_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setRowIcon(-1, nil) + } + end + + def test_set_row_icon_large_index_raises_index_error + assert_raises(IndexError) { + @table.setRowIcon(@table.numRows, nil) + } + end + + def test_get_row_icon_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getRowIcon(-1) + } + end + + def test_get_row_icon_large_index_raises_index_error + assert_raises(IndexError) { + @table.getRowIcon(@table.numRows) + } + end + + def test_set_row_icon_position_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setRowIconPosition(-1, 0) + } + end + + def test_set_row_icon_position_large_index_raises_index_error + assert_raises(IndexError) { + @table.setRowIconPosition(@table.numRows, 0) + } + end + + def test_get_row_icon_position_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getRowIconPosition(-1) + } + end + + def test_get_row_icon_position_large_index_raises_index_error + assert_raises(IndexError) { + @table.getRowIconPosition(@table.numRows) + } + end + + def test_set_row_justify_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setRowJustify(-1, 0) + } + end + + def test_set_row_justify_large_index_raises_index_error + assert_raises(IndexError) { + @table.setRowJustify(@table.numRows, 0) + } + end + + def test_get_row_justify_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getRowJustify(-1) + } + end + + def test_get_row_justify_large_index_raises_index_error + assert_raises(IndexError) { + @table.getRowJustify(@table.numRows) + } + end + + def test_set_row_text_negative_index_raises_index_error + assert_raises(IndexError) { + @table.setRowText(-1, "") + } + end + + def test_set_row_text_large_index_raises_index_error + assert_raises(IndexError) { + @table.setRowText(@table.numRows, "") + } + end + + def test_get_row_text_negative_index_raises_index_error + assert_raises(IndexError) { + @table.getRowText(-1) + } + end + + def test_get_row_text_large_index_raises_index_error + assert_raises(IndexError) { + @table.getRowText(@table.numRows) + } + end + end diff --git a/tests/TC_FXText.rb b/tests/TC_FXText.rb index 4edb6df..bd38766 100755 --- a/tests/TC_FXText.rb +++ b/tests/TC_FXText.rb @@ -72,10 +72,25 @@ public assert_equal(SAMPLE, @text.text) end - def test_findText + def test_find_text @text.text = "99 bottles of beer" startIndex, endIndex = @text.findText("bottles") assert_equal([3], startIndex) assert_equal([10], endIndex) end + + def test_find_text_with_startpos + @text.text = "I came, I saw, I conquered" + startIndex, endIndex = @text.findText("I ", 5) + assert_equal([8], startIndex) + assert_equal([10], endIndex) + end + + def test_find_text_with_groups + @text.text = "I came, I saw, I conquered" + startIndex, endIndex = @text.findText("I ([a-z]+)(, )?", 0, SEARCH_REGEX) + assert_equal([0, 2, 6], startIndex) + assert_equal([8, 6, 8], endIndex) + end + end diff --git a/tests/TC_FXTreeList.rb b/tests/TC_FXTreeList.rb index 6a959f4..ef5543c 100755 --- a/tests/TC_FXTreeList.rb +++ b/tests/TC_FXTreeList.rb @@ -14,27 +14,27 @@ class TC_FXTreeList < TestCase def test_firstItem assert_nil(@treeList.firstItem) - item = @treeList.addItemFirst(nil, "first") + item = @treeList.prependItem(nil, "first") assert_same(item, @treeList.firstItem) end def test_lastItem assert_nil(@treeList.lastItem) - item = @treeList.addItemFirst(nil, "first") + item = @treeList.prependItem(nil, "first") assert_same(item, @treeList.lastItem) end def test_reparentItem - rootItem = @treeList.addItemFirst(nil, "Root Item") - childItem = @treeList.addItemFirst(@treeList.firstItem, "Child Item") + rootItem = @treeList.prependItem(nil, "Root Item") + childItem = @treeList.prependItem(@treeList.firstItem, "Child Item") @treeList.reparentItem(childItem, nil) assert_same(rootItem, @treeList.firstItem) assert_same(childItem, @treeList.lastItem) end def test_moveItemBefore - first = @treeList.addItemLast(nil, "first") - second = @treeList.addItemLast(nil, "second") + first = @treeList.appendItem(nil, "first") + second = @treeList.appendItem(nil, "second") assert_same(second, first.next) assert_same(first, second.prev) assert_same(second, @treeList.moveItemBefore(first, second)) @@ -43,8 +43,8 @@ class TC_FXTreeList < TestCase end def test_moveItemAfter - first = @treeList.addItemLast(nil, "first") - second = @treeList.addItemLast(nil, "second") + first = @treeList.appendItem(nil, "first") + second = @treeList.appendItem(nil, "second") assert_same(second, first.next) assert_same(first, second.prev) assert_same(first, @treeList.moveItemAfter(second, first)) @@ -53,9 +53,9 @@ class TC_FXTreeList < TestCase end def test_sortRootItems - @treeList.addItemLast(nil, "B") - @treeList.addItemLast(nil, "A") - @treeList.addItemLast(nil, "C") + @treeList.appendItem(nil, "B") + @treeList.appendItem(nil, "A") + @treeList.appendItem(nil, "C") @treeList.sortRootItems assert_equal("A", @treeList.firstItem.text) assert_equal("B", @treeList.firstItem.next.text) @@ -67,12 +67,12 @@ class TC_FXTreeList < TestCase @treeList.connect(SEL_INSERTED) { |sender, sel, ptr| anItem = ptr } - theItem = @treeList.addItemLast(nil, "", nil, nil, nil, true) + theItem = @treeList.appendItem(nil, "", nil, nil, nil, true) assert_same(theItem, anItem) end def test_SEL_DELETED - theItem = @treeList.addItemLast(nil, "") + theItem = @treeList.appendItem(nil, "") anItem = nil @treeList.connect(SEL_DELETED) { |sender, sel, ptr| anItem = ptr @@ -80,4 +80,21 @@ class TC_FXTreeList < TestCase @treeList.removeItem(theItem, true) assert_same(theItem, anItem) end + + def test_each_for_empty_list + count = 0 + @treeList.each { |item| count += 1 } + assert_equal(0, count, "count for empty list should be zero") + end + + def test_each + @treeList.appendItem(nil, "1") + @treeList.appendItem(nil, "2") + @treeList.appendItem(nil, "3") + @treeList.appendItem(nil, "4") + count = 0 + @treeList.each { |item| count += 1 } + assert_equal(4, count, "count didn't match expected number of items") + end + end diff --git a/tests/TC_FXTreeListBox.rb b/tests/TC_FXTreeListBox.rb index 9c92180..b54dbaf 100755 --- a/tests/TC_FXTreeListBox.rb +++ b/tests/TC_FXTreeListBox.rb @@ -5,19 +5,37 @@ require 'fox16' include Fox class TC_FXTreeListBox < TestCase + def setup super(self.class.name) @treeListBox = FXTreeListBox.new(mainWindow) end def test_sortRootItems - @treeListBox.addItemLast(nil, "B") - @treeListBox.addItemLast(nil, "A") - @treeListBox.addItemLast(nil, "C") + @treeListBox.appendItem(nil, "B") + @treeListBox.appendItem(nil, "A") + @treeListBox.appendItem(nil, "C") @treeListBox.sortRootItems assert_equal("A", @treeListBox.firstItem.text) assert_equal("B", @treeListBox.firstItem.next.text) assert_equal("C", @treeListBox.lastItem.text) end + + def test_each_for_empty_list + count = 0 + @treeListBox.each { |item| count += 1 } + assert_equal(0, count, "count for empty list should be zero") + end + + def test_each + @treeListBox.appendItem(nil, "1") + @treeListBox.appendItem(nil, "2") + @treeListBox.appendItem(nil, "3") + @treeListBox.appendItem(nil, "4") + count = 0 + @treeListBox.each { |item| count += 1 } + assert_equal(4, count, "count didn't match expected number of items") + end + end diff --git a/tests/stress1.rb b/tests/stress1.rb index 4c1a71d..405ac2e 100755 --- a/tests/stress1.rb +++ b/tests/stress1.rb @@ -14,13 +14,13 @@ RESTART_FREQUENCY = 20 # Tree # ======================================================================= class DirTree < FXTreeList - def initialize(parent, nvis, tgt = nil, sel = 0, opts = 0, x = 0, y = 0, w = 0, h = 0) - super + def initialize(p) + super(p, :opts => TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_ROOT_BOXES|LAYOUT_FILL_X|LAYOUT_FILL_Y) end def create super - item = addItemLast(nil, "root") + item = appendItem(nil, "root") @currentItem = item expand end @@ -34,7 +34,7 @@ class DirTree < FXTreeList def listSubDir(parentItem) entries = (1..NUMBER_OF_ITEMS).collect { |i| i.to_s } entries.each do |entry| - item = addItemLast(parentItem, entry) + item = appendItem(parentItem, entry) @currentItem = item if entry == "1" end end @@ -57,9 +57,7 @@ class Application < FXApp init(ARGV) @mainWindow = FXMainWindow.new(self, appName, nil, nil, DECOR_ALL, 0, 0, 400, 600) - @dirTree = DirTree.new(@mainWindow, 0, nil, 0, - (TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_ROOT_BOXES| - LAYOUT_FILL_X|LAYOUT_FILL_Y)) + @dirTree = DirTree.new(@mainWindow) @count = 0 end diff --git a/tests/testcase.rb b/tests/testcase.rb index 8d95f8c..3220e25 100755 --- a/tests/testcase.rb +++ b/tests/testcase.rb @@ -10,13 +10,13 @@ module Fox def setup(*args) unless args.empty? appName = args[0] - if FXApp.instance.nil? - @theApp = FXApp.new(appName, 'FXRuby') - @theApp.init([]) - else - @theApp = FXApp.instance - end - @theMainWindow = FXMainWindow.new(@theApp, appName) + if FXApp.instance.nil? + @theApp = FXApp.new(appName, 'FXRuby') + @theApp.init([]) + else + @theApp = FXApp.instance + end + @theMainWindow = FXMainWindow.new(@theApp, appName) end end diff --git a/web/community.html b/web/community.html new file mode 100644 index 0000000..04e6abb --- /dev/null +++ b/web/community.html @@ -0,0 +1,94 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <link rel="stylesheet" href="css/style.css" type="text/css" /> + <link rel="meta" title="DOAP" type="application/rdf+xml" href="http://www.fxruby.org/doap.rdf" /> + <title>Community</title> +</head> + +<body> +<!-- wrap starts here --> +<div id="wrap"> + + <!--header --> + <div id="header"> + + <h1 id="logo-text"><a href="index.html">FXRuby</a></h1> + <p id="slogan">Graphical User Interface Development for Ruby</p> + + </div> + + <!-- menu --> + <div id="menu"> + <ul> + <li ><a href=/ >Home</a></li> + <li id='current'><a href=# >Community</a></li> + <li ><a href=/downloads.html >Downloads</a></li> + <li ><a href=/documentation.html >Documentation</a></li> + </ul> + </div> + + <!-- content-wrap starts here --> + <div id="content-wrap"> + + <div id="sidebar"> + + <h3>Get the Book!</h3> + <a href="http://www.pragprog.com/titles/fxruby"><img src="images/fxruby-book.jpg" alt="FXRuby: Create Lean and Mean GUIs with Ruby" width="175" height="210" /></a> + + <h3>Links</h3> + <ul class="sidemenu"> + <li><a href="http://rubyforge.org/news/?group_id=300">News</a></li> + <li><a href="http://www.fxruby.org/doc/book.html">User's Guide</a></li> + <li><a href="http://www.fxruby.org/doc/api">API Docs</a></li> + <li><a href="http://www.fxruby.org/doc/examples.html">Screenshots</a></li> + <li><a href="http://rubyforge.org/tracker/?atid=1223&group_id=300&func=browse">Report Bugs</a></li> + <li><a href="http://www.gnu.org/copyleft/lesser.html">License</a></li> + </ul> + + </div> + + <div id="main"> + + <h1>Mailing Lists</h1> + + + <h2>Announcements</h2> + + + <p>The announcements list is a low-traffic list on which new releases of FXRuby, as well as software based on FXRuby, will be +announced. Discussions on various topics however should preferably take place in the users list, to prevent swamping people’s +mailboxes. To subscribe, fill out the <a href="http://rubyforge.org/mailman/listinfo/fxruby-announce" title="Announcements List Subscription +Form">web-based subscription form</a>.</p> + + + <h2>General Discussion</h2> + + + <p>The users list is intended for discussion on various FOX and FXRuby topics between developers and/or users of FXRuby and +applications based on it. If you have questions, feel free to post your questions here, as many people are only too happy to +answer them. To subscribe, fill out the <a href="http://rubyforge.org/mailman/listinfo/fxruby-users" title="General Discussion List Subscription +Form">web-based subscription form</a>.</p> + + </div> + + <!-- content-wrap ends here --> + </div> + + <!--footer starts here--> + <div id="footer"> + + <p> + © 2008 Lyle Johnson<br /> + Web Site Generated Using <a href="http://webby.rubyforge.org/" title="Webby">Webby</a> + </p> + + </div> + +<!-- wrap ends here --> +</div> + +</body> +</html> diff --git a/web/css/style.css b/web/css/style.css new file mode 100644 index 0000000..36c1a1b --- /dev/null +++ b/web/css/style.css @@ -0,0 +1,407 @@ +/******************************************** + AUTHOR: Erwin Aligam + WEBSITE: http://www.styleshout.com/ + TEMPLATE NAME: Envision + TEMPLATE CODE: S-0013 + VERSION: 1.1 + LAST MODIFIED Nov-14-2007 + *******************************************/ + +/******************************************** + HTML ELEMENTS +********************************************/ + +/* Top Elements */ +* { margin: 0; padding: 0; outline: 0 } + +body { + background: #CCC; + font: 80%/1.5em Verdana, Tahoma, arial, sans-serif; + color: #555; + text-align: center; +} + +/* links */ +a, a:visited { + text-decoration: none; + color: #2180BC; + background: inherit; +} +a:hover { + color: #88ac0b; + background: inherit; + text-decoration: underline; +} + +/* headers */ +h1, h2, h3 { + font-family: 'Trebuchet MS', Tahoma, Sans-serif; +} +h1 { + font-size: 150%; + font-weight: normal; + color: #006699; +} +h2 { + font-size: 140%; + text-transform: uppercase; + color: #88ac0b; +} +h3 { + font-size: 120%; + color: #666666; +} + +/* images */ +img { + background: #FAFAFA; + border: 1px solid #E5E5E5; + padding: 5px; +} +img.float-right { + margin: 5px 0px 10px 10px; +} +img.float-left { + margin: 5px 10px 10px 0px; +} + +h1, h2, h3, p { + padding: 10px; + margin: 0; +} +ul, ol { + margin: 5px 20px; + padding: 0 20px; +} + +code { + margin: 5px 0; + padding: 10px; + text-align: left; + display: block; + overflow: auto; + font: 500 1em/1.5em 'Lucida Console', 'courier new', monospace ; + /* white-space: pre; */ + background: #FAFAFA; + border: 1px solid #f2f2f2; +} +acronym { + cursor: help; + border-bottom: 1px dotted #777; +} +blockquote { + margin: 10px; + padding: 0 0 0 28px; + border: 1px solid #f2f2f2; + background: #FAFAFA url(../images/quote.gif) no-repeat 5px 5px; +} + +/* start - table */ +table { + border-collapse: collapse; + margin: 10px; +} +th strong { + color: #fff; +} +th { + background: #93BC0C; + height: 29px; + padding-left: 12px; + padding-right: 12px; + color: #FFF; + text-align: left; + border-left: 1px solid #B6D59A; + border-bottom: solid 2px #FFF; +} +tr { + height: 30px; +} +td { + padding-left: 11px; + padding-right: 11px; + border-left: 1px solid #FFF; + border-bottom: solid 1px #ffffff; +} +td.first,th.first { + border-left: 0px; +} +tr.row-a { + background: #F8F8F8; +} +tr.row-b { + background: #EFEFEF; +} +/* end - table */ + +/* form elements */ +form { + margin:10px; padding: 0 5px; + border: 1px solid #f2f2f2; + background-color: #FAFAFA; +} +label { + display:block; + font-weight:bold; + margin:5px 0; +} +input { + padding:2px; + border:1px solid #eee; + font: normal 1em Verdana, sans-serif; + color:#777; +} +textarea { + width:400px; + padding:2px; + font: normal 1em Verdana, sans-serif; + border:1px solid #eee; + height:100px; + display:block; + color:#777; +} +input.button { + font: bold 12px Arial, Sans-serif; + height: 24px; + margin: 0; + padding: 2px 3px; + color: #FFF; + background: #8EB50C url(../images/button-bg.jpg) repeat-x 0 0; + border: none; +} + +/* search form */ +.searchform { + background-color: transparent; + border: none; + margin: 0; padding: 5px 0 15px 0; + width: 190px; +} +.searchform p { margin: 0; padding: 0; } +.searchform input.textbox { + width: 120px; + color: #777; + height: 18px; + padding: 2px; + border: 1px solid #E5E5E5; + vertical-align: top; +} +.searchform input.button { + width: 60px; + height: 24px; + padding: 2px 5px; + vertical-align: top; +} + +/******************************************** + LAYOUT +********************************************/ +#wrap { + width: 820px; + background: #CCC url(../images/content.jpg) repeat-y center top; + margin: 0 auto; + text-align: left; +} +#content-wrap { + clear: both; + width: 760px; + padding: 0; + margin: 10px auto; +} +#header { + width: 820px; + position: relative; + height: 103px; + background: #CCC url(../images/header.png) no-repeat center top; + padding: 0; + color: #FFF; +} +#header h1#logo-text a { + position: absolute; + margin: 0; padding: 0; + font: bolder 44px 'Trebuchet MS', Arial, Sans-serif; + letter-spacing: -2px; + color: #FFF; + text-transform: none; + text-decoration: none; + background: transparent; + + /* change the values of top and left to adjust the position of the logo*/ + top: 20px; left: 110px; +} +#header p#slogan { + position: absolute; + margin: 0; padding: 0; + font: normal 12px 'Trebuchet MS', Arial, Sans-serif; + text-transform: none; + color: #FFF; + + /* change the values of top and left to adjust the position of the slogan*/ + top: 70px; left: 110px; +} + +/* header links */ +#header #header-links { + position: absolute; + top: 20px; right: 30px; + color: #C6DDEE; + font-size: 10px; +} +#header #header-links a { + color: #FFF; + text-decoration: none; +} +#header #header-links a:hover { + color: #D4E59F; +} + +/* Menu */ +#menu { + clear: both; + margin: 0 auto; padding: 0; + background: url(../images/menu.jpg) repeat-x 0 0; + font: bold 12px/37px Verdana, Arial, Tahoma, Sans-serif; + height: 37px; + width: 780px; +} +#menu ul { + float: right; + list-style: none; + margin:0; padding: 0; +} +#menu ul li { + display: inline; +} +#menu ul li a { + display: block; + float: left; + padding: 0 12px; + color: #FFF; + text-decoration: none; +} +#menu ul li.last a { + padding-right: 20px; +} +#menu ul li a:hover { + color: #D4E59F; +} +#menu ul li#current a { + color: #D4E59F; +} + +/* Main Column */ +#main { + float: left; + width: 70%; + padding: 0; margin: 5px 0 0 5px; + display: inline; +} +#main h2 { + margin-top: 10px; + font: Bold 140% 'Trebuchet MS', Tahoma, Sans-serif; + color: #88ac0b; + padding: 5px 0 5px 25px; + border-bottom: 1px solid #EFF0F1; + background: #FFF url(../images/square-green.png) no-repeat 3px 50%; + text-transform: none; +} +#main h2 a { + background: none; + color: #88ac0b; + text-decoration: none; +} + +#main ul li { + list-style-image: url(../images/bullet.gif); +} + +.post-footer { + background-color: #FAFAFA; + padding: 5px; margin: 20px 10px 10px 10px; + border: 1px solid #f2f2f2; + font-size: 95%; +} +.post-footer .date { + background: url(../images/clock.gif) no-repeat left center; + padding-left: 20px; margin: 0 10px 0 5px; +} +.post-footer .comments { + background: url(../images/comment.gif) no-repeat left center; + padding-left: 20px; margin: 0 10px 0 5px; +} +.post-footer .readmore { + background: url(../images/page.gif) no-repeat left center; + padding-left: 20px; margin: 0 10px 0 5px; +} + +/* Sidebar */ +#sidebar { + float: right; + width: 26.5%; + padding: 0; margin: 0; + color: #68774A; +} +#sidebar img { + text-align: center; +} +#sidebar h3 { + margin-top: 10px; + /* padding: 5px 5px; */ + text-align: center; + font: bold 1.4em 'Trebuchet MS', Tahoma, Sans-serif; + color: #728D26; +} +#sidebar ul.sidemenu { + list-style: none; + text-align: left; + margin: 7px 4px 8px 0; padding: 0; + text-decoration: none; + background: url(../images/dots.jpg) repeat-x left top; +} +#sidebar ul.sidemenu li { + list-style: none; + background: url(../images/dots.jpg) repeat-x left bottom; + padding: 4px 0 4px 5px; + margin: 0 2px; + color: #68774A; +} +* html body #sidebar ul.sidemenu li { + height: 1%; +} +#sidebar ul.sidemenu li a { + text-decoration: none; + background-image: none; + color: #666666; +} +#sidebar ul.sidemenu li a:hover { + color: #1773BC; +} +#sidebar ul.sidemenu ul { margin: 0 0 0 5px; padding: 0; } +#sidebar ul.sidemenu ul li { background: none; } + + +/* Footer */ +#footer { + color: #C6DDEE; + background: #CCC url(../images/footer.jpg) no-repeat center top; + clear: both; + width: 820px; + height: 65px; + text-align: center; + font-size: 92%; +} +#footer a { + color: #FFF; + text-decoration: none; +} + +/* alignment classes */ +.float-left { float: left; } +.float-right { float: right; } +.align-left { text-align: left; } +.align-right { text-align: right; } + +/* display and additional classes */ +.clear { clear: both; } + + diff --git a/web/documentation.html b/web/documentation.html new file mode 100644 index 0000000..9f570fd --- /dev/null +++ b/web/documentation.html @@ -0,0 +1,100 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <link rel="stylesheet" href="css/style.css" type="text/css" /> + <link rel="meta" title="DOAP" type="application/rdf+xml" href="http://www.fxruby.org/doap.rdf" /> + <title>Documentation</title> +</head> + +<body> +<!-- wrap starts here --> +<div id="wrap"> + + <!--header --> + <div id="header"> + + <h1 id="logo-text"><a href="index.html">FXRuby</a></h1> + <p id="slogan">Graphical User Interface Development for Ruby</p> + + </div> + + <!-- menu --> + <div id="menu"> + <ul> + <li ><a href=/ >Home</a></li> + <li ><a href=/community.html >Community</a></li> + <li ><a href=/downloads.html >Downloads</a></li> + <li id='current'><a href=# >Documentation</a></li> + </ul> + </div> + + <!-- content-wrap starts here --> + <div id="content-wrap"> + + <div id="sidebar"> + + <h3>Get the Book!</h3> + <a href="http://www.pragprog.com/titles/fxruby"><img src="images/fxruby-book.jpg" alt="FXRuby: Create Lean and Mean GUIs with Ruby" width="175" height="210" /></a> + + <h3>Links</h3> + <ul class="sidemenu"> + <li><a href="http://rubyforge.org/news/?group_id=300">News</a></li> + <li><a href="http://www.fxruby.org/doc/book.html">User's Guide</a></li> + <li><a href="http://www.fxruby.org/doc/api">API Docs</a></li> + <li><a href="http://www.fxruby.org/doc/examples.html">Screenshots</a></li> + <li><a href="http://rubyforge.org/tracker/?atid=1223&group_id=300&func=browse">Report Bugs</a></li> + <li><a href="http://www.gnu.org/copyleft/lesser.html">License</a></li> + </ul> + + </div> + + <div id="main"> + + <h1>Books</h1> + + + <p>The book <cite>FXRuby: Create Lean and Mean GUIs with Ruby</cite> (available from the <a href="http://www.pragmaticprogrammer.com/titles/fxruby/">Pragmatic +Programmers</a> and other booksellers) is the best print source of documentation +for FXRuby. It’s also available as a PDF.</p> + + + <p>Several other books, including <cite>Ruby Developer’s Guide</cite> and <cite>The Ruby Way</cite>, include chapters or sections +on GUI development with FXRuby.</p> + + + <h1>Online</h1> + + + <p>The <a href="http://www.fxruby.org/doc/book.html">FXRuby User’s Guide</a> provides detailed installation instructions as well +as a handful of tutorial exercises to get you started with FXRuby development.</p> + + + <p>If you’re looking for API reference documentation, all of the classes and methods for FXRuby are documented +<a href="http://www.fxruby.org/doc/api/">here</a>.</p> + + + <p>Other good sources of documentation include the <a href="http://www.fox-toolkit.org/">FOX home page</a> and the <a href="http://www.fox-toolkit.net/">FOX Community +Wiki</a> site.</p> + + </div> + + <!-- content-wrap ends here --> + </div> + + <!--footer starts here--> + <div id="footer"> + + <p> + © 2008 Lyle Johnson<br /> + Web Site Generated Using <a href="http://webby.rubyforge.org/" title="Webby">Webby</a> + </p> + + </div> + +<!-- wrap ends here --> +</div> + +</body> +</html> diff --git a/web/downloads.html b/web/downloads.html old mode 100755 new mode 100644 index 688eac6..80610f5 --- a/web/downloads.html +++ b/web/downloads.html @@ -1,93 +1,114 @@ -<html> -<head> -<link rel="stylesheet" href="page.css" type="text/css"> -<title>Downloads</title> -</head> -<body bgcolor=#ffffff link=#990033 vlink=#990033 alink=#990033 text=#000000> - - -<!--- TOPIC TITLE --> -<p> -<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id="HEADLINE"><b> -Downloads -<br><img src='art/line.gif' width='100%' height=1></b></td></tr></table> -</p> -<!--- TOPIC TITLE --> -<blockquote> -The latest version of FXRuby is always available -from the <a href="http://rubyforge.org/projects/fxruby" target=_top>RubyForge -project page</a>. The RubyForge releases should always have accompanying -release notes describing the changes for that release. A cumulative -<tt>ChangeLog</tt> file is also included in the FXRuby source code distribution. - -As of the FOX 1.0 release, any FXRuby version 1.0.x release should be compatible with any FOX 1.0.x release. -Similarly, any FXRuby 1.2.x release should be compatible with any FOX 1.2.x release, and -any FXRuby 1.4.x release should be compatible with any FOX 1.4.x release.<p> -</blockquote> - -<!--- TOPIC TITLE --> -<p> -<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id="HEADLINE"><b> -Source Code -<br><img src='art/line.gif' width='100%' height=1></b></td></tr></table> -</p> -<!--- TOPIC TITLE --> -<blockquote> -The FXRuby source code is distributed as a gzipped tar archive, and is available for -download from the <a href="http://rubyforge.org/projects/fxruby" target=_top>RubyForge -project page</a>. -</blockquote> - -<!--- TOPIC TITLE --> -<p> -<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id="HEADLINE"><b> -Binaries for Unix/Linux -<br><img src='art/line.gif' width='100%' height=1></b></td></tr></table> -</p> -<!--- TOPIC TITLE --> -<blockquote> -Precompiled binaries for FOX, FXScintilla and FXRuby are available for various Unix/Linux platforms, -but not in any centralized way.<p> -Both the <a href="http://www.fox-toolkit.net">FOX -Community Wiki site</a> and the <a href="http://www.fox-toolkit.com">main FOX web site</a> -list a number of independent sources for package downloads for various Linux distributions, but -many of these are for older FOX releases. You may have better luck using a RPM search engine like -<a href="http://rpmfind.net">rpmfind.net</a> to find the most recent packages for your distribution. -</blockquote> - -<!--- TOPIC TITLE --> -<p> -<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id="HEADLINE"><b> -Binaries for Microsoft Windows -<br><img src='art/line.gif' width='100%' height=1></b></td></tr></table> -</p> -<!--- TOPIC TITLE --> -<blockquote> -Windows installers for FXRuby are available for download from -the <a href="http://rubyforge.org/projects/fxruby" target=_top>RubyForge -project page</a>. -<b>The FOX and FXScintilla libraries are built into the Windows installers for FXRuby, and -you should not need to download and install those packages separately.</b> -These binaries are also compatible with the standard Ruby -installers for Windows that are available for download from -<a href="http://rubyforge.org/projects/rubyinstaller" target=_top>RubyForge</a>.<p> -Note that the precompiled binaries for Windows are built with OpenGL support, and -thus depend on the OpenGL runtime libraries (<tt>opengl32.dll</tt> and -<tt>glu32.dll</tt>). These libraries were <i>not</i> included with Windows 95 -(earlier than OSR2), so if you're using Ruby and FXRuby on a Windows 95 machine, -you may need to download the <a href="http://download.microsoft.com/download/win95upg/info/1/W95/EN-US/Opengl95.exe">OpenGL runtime libraries</a>. -You must have these libraries installed even if you don't plan to do anything -OpenGL-related with FXRuby. -</blockquote> - -<!--- COPYRIGHT --> -<p> -<table width=100% cellpadding=0 cellspacing=0><tr><td width=100% valign=top id=HEADLINE align=right> -<img src='art/line.gif' width=100% height=1><font size=-1> -Copyright © 2001-2004 Lyle Johnson</font> -</td></tr></table> -</p> -<!--- COPYRIGHT --> - -</body> -</html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <link rel="stylesheet" href="css/style.css" type="text/css" /> + <link rel="meta" title="DOAP" type="application/rdf+xml" href="http://www.fxruby.org/doap.rdf" /> + <title>Downloads</title> +</head> + +<body> +<!-- wrap starts here --> +<div id="wrap"> + + <!--header --> + <div id="header"> + + <h1 id="logo-text"><a href="index.html">FXRuby</a></h1> + <p id="slogan">Graphical User Interface Development for Ruby</p> + + </div> + + <!-- menu --> + <div id="menu"> + <ul> + <li ><a href=/ >Home</a></li> + <li ><a href=/community.html >Community</a></li> + <li id='current'><a href=# >Downloads</a></li> + <li ><a href=/documentation.html >Documentation</a></li> + </ul> + </div> + + <!-- content-wrap starts here --> + <div id="content-wrap"> + + <div id="sidebar"> + + <h3>Get the Book!</h3> + <a href="http://www.pragprog.com/titles/fxruby"><img src="images/fxruby-book.jpg" alt="FXRuby: Create Lean and Mean GUIs with Ruby" width="175" height="210" /></a> + + <h3>Links</h3> + <ul class="sidemenu"> + <li><a href="http://rubyforge.org/news/?group_id=300">News</a></li> + <li><a href="http://www.fxruby.org/doc/book.html">User's Guide</a></li> + <li><a href="http://www.fxruby.org/doc/api">API Docs</a></li> + <li><a href="http://www.fxruby.org/doc/examples.html">Screenshots</a></li> + <li><a href="http://rubyforge.org/tracker/?atid=1223&group_id=300&func=browse">Report Bugs</a></li> + <li><a href="http://www.gnu.org/copyleft/lesser.html">License</a></li> + </ul> + + </div> + + <div id="main"> + + <p>The latest version of FXRuby is always available from the <a href="http://rubyforge.org/projects/fxruby/">RubyForge project page</a>. The +RubyForge releases should always have accompanying release notes describing the changes for that release. A cumulative ChangeLog +file is also included in the FXRuby source code distribution. Note that any FXRuby 1.6.x release should be compatible with any +FOX 1.6.x release, but won’t be compatible with earlier (or later) versions of FOX.</p> + + + <h1>Source Code</h1> + + + <p>The FXRuby source code is distributed as a gzipped tar archive, and is available for download from the <a href="http://rubyforge.org/projects/fxruby/">RubyForge project +page</a>.</p> + + + <h1>Binaries for Unix/Linux</h1> + + + <p>Precompiled binaries for FOX, FXScintilla and FXRuby are available for various Unix/Linux platforms, but not in any +centralized way.</p> + + + <p>Both the <a href="http://www.fox-toolkit.net/">FOX Community Wiki</a> site and the main <a href="http://www.fox-toolkit.org/">FOX web site</a> list a +number of independent sources for package downloads for various Linux distributions, but many of these are for older FOX +releases. You may have better luck using a RPM search engine like <a href="http://rpmfind.net/">rpmfind.net</a> to find the most recent +packages for your distribution.</p> + + + <h1>Binaries for Microsoft Windows</h1> + + + <p>Windows installers for FXRuby are available for download from the <a href="http://rubyforge.org/projects/fxruby/">RubyForge project +page</a>. The FOX and FXScintilla libraries are built into the Windows installers for FXRuby, +and you should not need to download and install those packages separately. These binaries are also compatible with the standard +Ruby installer for Windows that are available for download from RubyForge.</p> + + + <p>Note that the precompiled binaries for Windows are built with OpenGL support, and thus depend on the OpenGL runtime libraries +(opengl32.dll and glu32.dll). These libraries were not included with Windows 95 (earlier than OSR2), so if you’re using Ruby and +FXRuby on a Windows 95 machine, you may need to download the OpenGL runtime libraries. You must have these libraries installed +even if you don’t plan to do anything OpenGL-related with FXRuby.</p> + + </div> + + <!-- content-wrap ends here --> + </div> + + <!--footer starts here--> + <div id="footer"> + + <p> + © 2008 Lyle Johnson<br /> + Web Site Generated Using <a href="http://webby.rubyforge.org/" title="Webby">Webby</a> + </p> + + </div> + +<!-- wrap ends here --> +</div> + +</body> +</html> diff --git a/web/images/bullet.gif b/web/images/bullet.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ba2421a9240d1b20d8a383d3f63dff3864dbf3d GIT binary patch literal 281 zcmZ?wbhEHb<YeGsxXQpVb+_z_<L*1I=Po(wF!zAr+(QPNFDETHV)o<Lhd+OR{`~!U z@p1cq|NdNkynM-VyTAYbEIwv4b&uT1+kLYSXfHfsF=e;RuRmYE|9U@lxBRUAn%ADJ zUU1Ot#I5dAclv+-`EmRCmaXSgwp>YFebR675!+oiivIuq_v_EMgV$>JTrS*xA>;r5 z{|uA?#h)x-19U(n$WIJxW)4#eJanY`Pb8j9(u(t2%y`_`#Z^qe!M#Jl!lTJqVPQ~? ahN83M7XdG=$vkexDJBjp{evV}7_0%82yhGl literal 0 HcmV?d00001 diff --git a/web/images/button-bg.jpg b/web/images/button-bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c59ae2faa7c6ccf31cb83555c44599138161ad6 GIT binary patch literal 345 zcmY+9y-Gtt5QWd|?9bhso7@ckfSo>oHa>s~A)r;1U@MqwC6da*-p8=A^eKX*5NxzF z+L&H_g>@1o<bDgYJ7>=fGwCgTqJ7jo?1BtX=|TE}bgl=NHy~I5J(YgYI;e){7pO+6 zQ2M|v%mUUITa9d;o#DKj<9!HO2tLL<kFlsj%<Qa--p6JmHkxHiDa*O(|0@2ndfg&R zBS?k~5R<?Nu}~W03}DhBm+&EyigndG&f2<lSTgErQ*(09{k3%=7_NV<$nk1=N1^SF guwV}_S9iNx&!?Ny{Cha)k9Q`o4^NNV`yow!0cP1PH~;_u literal 0 HcmV?d00001 diff --git a/web/images/comment.gif b/web/images/comment.gif new file mode 100644 index 0000000000000000000000000000000000000000..951082f93a4bb0b7401e9cabdaaea9606cadb3f2 GIT binary patch literal 364 zcmZ?wbhEHb6krfwxT?<Z|Ns9dPo8}J`n9^c`sU4>&!0cPef##kd-q<xeEIO<!}sss zfB*jd>eZ`j)~xC4>$`UC+N4R7+S=N_eEG6t$Bw5@pPoN|{?VgH4<0-?apJ_|$B*yd zzkl%H!QS59zkmN$RaM=(b?e8EA9Lo+$<NRK_wV0_4<9~#`m}oWYM`YIR04`WSr{1@ z)ERU@=7Idgz}9(Sa)F1A5aWp@n>Z8<v}T-5xn$7FaCn)}g~%x)Tzq057!}U7Iwi;| zG%B3vlAIV9E!24UP~(xFOROS{lAPk~Y}FpZ+>A}F?QAS8T!J3FOpN6dCh_oaF;8P^ zk!qjB&%-}Ic{<ZtCLw+nA*Kb90s?%3f^ut_l_K1unT58x`7j?n=6>>2<N<X@25SIl CNRXcZ literal 0 HcmV?d00001 diff --git a/web/images/content.jpg b/web/images/content.jpg new file mode 100644 index 0000000000000000000000000000000000000000..23b605f8a1017c479a6f095c0d84c2753ece9e2c GIT binary patch literal 542 zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5JQfgu1W^p1hgF(p4Kl_BK- zP=xXSZH5*GCOBXQvY1(bBr^*u3ka~Xv4Q~`8#_A(J3AXECl?ndCl4xMWM*b&WntxH zW8>uI=H%w(=K}(Mey}1a#RK7?>VxzCA7BvVU|?i6VP+I$U=n0x7G(T?grOSfY$j$# zpfllsofGIH4n{@>RAB~IHg;wKph`wgc2>Az2F5}rBW7cu4tB%FjYWsc%uQOhY~>IH zs$*tjM>3a@X;Tw(u?Z`ip=0C0L(Zn`|8Fty0Bv9rWENzwXV~=PO^4;3xN}C#N34Fo z+Vp<!3;o~H_mfY~%fIisU-aOM<Lz4(Z!XYZzaqpm=jk_<tFA?tjKU>~f?1~Ydo&<i zLnMn=%rLv;$=b(;>}x(wUY{=g&NoQ#2&P`v(7Gp|&c(mgUVd)>cKI{^a-ZpBPMrDP c=E;tNRVjz3Y53k*w6$evpqmi0g8cuR0326r(f|Me literal 0 HcmV?d00001 diff --git a/web/images/dots.jpg b/web/images/dots.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7f082d2ae29cf5f9b68abf3b6974a04ad001eec GIT binary patch literal 326 zcmZ9GyNUuq5JhiIb@xo`IAi~X!6t%%nfPG9jm$P*$4J3w12cE=n~YWTAABUnBH|zP zwhx5%6x8E#iz>UdN0dLaZUzc~+y(3zrt{MuPCyU<dQQ3^Y3Aea0rG`Y$R035@Pb{( z!etgx+>lD%Q7R0hFjQI>3R=fL#LQAit&}bmb+MEtjx@cSo+W-v{@!b{3z!H21d~Bv zhz;2_zTDeBn&?dustl5zE5r4#wlN^Vo_?)1e_N}z-6LjlSJ<F|!8)3M)GNtkbeb;h F?jH<lDb)Y~ literal 0 HcmV?d00001 diff --git a/web/images/footer.jpg b/web/images/footer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..097d99a9803609f67e65288e8d35af0248db3f19 GIT binary patch literal 4633 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 literal 0 HcmV?d00001 diff --git a/web/images/fxruby-book.jpg b/web/images/fxruby-book.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f53e20707ff02cd5350c062219a78e8332838a1b GIT binary patch literal 22622 zcmc$_WmFwO*DiRlAR#yecXxMp_k+8;yChg}JGi^MI|O%kIJgFP2tIjd&7HaTn{Q@* zPCdO=b$9LFyQ-zSwtcRC?f_6^C1oT55D*Xm>3;xxUI6HotsLDPU9B9Qh}jsK0o<Z8 z3Q!k-{}hz}PyitQ;s2;V!2q%UT>Jl7AR!?j{%sJD|D*h0dyxNO@;@>7U&#Ik`TuAA z*$Y601Iz<zp&(EJkf;z)s1Ton0HXhN77FIy;Qr473kQz?2?Y)F<?DY4#8Ci%FAz}w zPCz3<!9o3JbpLxJEC3D_jRYQ@1%p&X1p(9884HJuoK;ja5R|fbonJrq9b45TD4}nc zLhR-r7lMBRAfTcCCn<n0&@ixY|9HXwYnJ`jqkl4>p`gAXz`{cRlk%?t0F4Us1s08j z1zki1gVY#~)j1H9kA+Pps#@PSH-C-!U0uT@F^QZ_%+#e|Hz=Y1hFvZAa~**APYNU| z6e>UnFtabKEEbPKBy!HHS{HxwF=!Z|I~Du8(c;@a>xV#C25UqZd^v|6&<b9KC4d_< zB%F;Wc;%O@5QDM(v*nJ>nbY^Lp4jAZoQ7^Ib4m%1o$piw&u$}$8TJU5(sjP!N03?{ zfjP$a(LPI2?fal-K-}g2@4q&vx-@EVJMv}4KUil7G&FwD>XAjST-$?Xo_4b8EntE! zP07@GFTnrW?U|JaPhd<^<@>)7pVn#Vr!A|8kH)OhAUe6mMlJfy^Le8ls_eGk1KV?^ zZRhOy@i(?un`FKD1&s)LHO$e5owII7tG;{_ugT~zIUJxWqg?_^Bsm;59I)E9>Z8MB zN|;RpXe!i_gnI>g#d^x&Xr;-ZJqeS4#EK`QNw4xdK&bMeNQ%Htn$AqOa142tB$Xsp z2LIJGMSiUP?cdQy8<AoR<-~C-56CuCsHO-`PdTN=hl3E+0(F0w;Ktkg8rrU~|DBnV zIu?3?Wq!TUs*Ld&xu-&G)t_&n=m^j$H7KspH|72W%uU<=aZ=s^z%Bv+Kb>ri=nl<) zoXA@LKVZc61k?Bv&@a%w=QloAj&y}{V5&)>NdrBBh42Z$cSB_jLzX<59*|1S6=wSc zJU7R+{jxG&sAfX%Zu+J52?!N=lNDTFpGgSqKKE_a1>druo?+$Cn@$WhJB<*bW5neK zEt9RzThtqNtsF5r2eW9IbT(5IibQFXc!Bnbh}VeC?){3Pi7IB_r4G<<J6;qiAo0-G zyHqwL?`rvF6(!kn!U#UNt5230t{9sp+Ss4{b8aOJq>ingrQONzn7Z$v5D_i8M=u!@ zTQYm_#-|O23Waz=@PXyYmP|_6w|#ihcUcO!-xeV-@Mr_(QMJ!50?L!w(=gEL+SLnG zxVdE2N|h`<laFoL&?ud>q;eb#3}WWIi;NHNBK~S%Y~ecW%%SmQtP2dMwxYuzk@#l8 zy@}8e!X3p+*rSp+l``iM?`L<yf=&9-Q+b-dMPAU=n_F9KNnH5sWL(!u0<B?5h#rbc z<e3}%9(gE_W6(*{aEy2z5H?C6lsZp5SQSV(Yk=60!1t}9_;%KNdf3icvtweU!fAoS zc7~=`bA1QQ3~B6w2?z10-Cy`aXp^q=jv!_vr#6~t-+u2*yDF-k-P}EX3lyd;nXbES zq59qt(XP1oI$mt7hs7vAugsiKwAqU+0+T9tEa=HivpJ-|{O$#)0*>m^&}l^_)?a<5 z6BEypGopFNJluVdMY^6|6V|T0w(BEJL%0A`<KzP*5Cl!qE4zft=w+a6K>M+VL$i|M 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 literal 0 HcmV?d00001 diff --git a/web/images/header.png b/web/images/header.png new file mode 100644 index 0000000000000000000000000000000000000000..6f79ed3735b6ac9a50b9eff96bd880a79bdfc128 GIT binary patch literal 14644 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 D<04Ba literal 0 HcmV?d00001 diff --git a/web/images/menu.jpg b/web/images/menu.jpg new file mode 100644 index 0000000000000000000000000000000000000000..daaa8bb3a6129ed037d33f9e34b001bdbf232843 GIT binary patch literal 366 zcmex=<NpH&0WUXCHwH!~28I+MWcdGvLC~c%IlGd9k%5JQfgu1W^p1hgF(p4Kl_BK- zP=xXSZH5*GCOBXQvY1(bBr^*u3ka~Xv4Q~`8#_A(J3AXECl?ndCl4xMWM*b&WntxH zW8>uI=H%w(=K}(Mey}1a#RK7?>VxzCA7BvVU{GaXWM&j(U=n0x7G(T?gdvTAff?vV zB*4tV#>l|T$cQ8a^aB$+hX4a3BP%DeFwl_6EFu?~LY7=%4NX-OWCZ#W#WcY{#zZC| zrT@1Wc$k5bg3N*p_6!Zns!!w=s(nfO^?cr*oLNl?rWul2FKv=%OwW~CY_j%S?X?vC JYxn=(1OTwrH|_uc literal 0 HcmV?d00001 diff --git a/web/images/page.gif b/web/images/page.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c49ba877f0cdd497b308ee97f14aea8a7ea2448 GIT binary patch literal 393 zcmZ?wbhEHb6krfwxT?nR|NsA6w{AUr`0&S%A6KtleevSO!Gi}se*F0L>({+|_Z~QK z;NHD^ZEbB86%|jOJlVQ+>*L3dPn<ZheEITs@7~?Ldp9vLao@gu+1c6W&!4|=;exZX z^Ut3@BO@cDqN3iuef#?L>*L3dfBN+4%a<?j-@nhw%38K;8PG-s>H)={EQ|~cY79Cc zBSC&*U|Z(UP~agmtFOUd!QnsyPk)9dlLMO_yNj5hm5h_1o2Y<=$hq{6!-gF#tu2lR z7p#ze(Ol!)F>$>jQ)8nDb2Wp4G^-?6IhPnGCu6G<TTv5}2sgJkvx*ackwkevr<h=> z_<W8AChnQuKJ23Nl?1w%Ob}#I-pnAhdhKj)mLqa9PD0XrGY%a&!XfL#lM}@*d|g<M agHh@P&wXBAadA;mSsAG|*VitN4AuZG+l}=A literal 0 HcmV?d00001 diff --git a/web/images/quote.gif b/web/images/quote.gif new file mode 100644 index 0000000000000000000000000000000000000000..43cbdb3fa50f973d5a45a1686545758168ebaf0b GIT binary patch literal 346 zcmZ?wbhEHblw*)%IKsg2>Ep*s7cPAN{{7n3tM~8SyK?#R`*-hd-njAV<;zD8A3k~f z`1!MEU%q^K`{vE>-@otNzJ31e*<ZhYF%S(Df3kqp>VQa)oeZqk7YO&JWX@aBG0RD5 z&C{d<OAH)%Wd#EkF>jaiInd0L(ZG;W8F6!(cZ84>!-9DMN3wRUiEH-O?c)Bp=zzdS z&fRkscAaMBS!<@bK!8c7v3?Ct1*^VBLrAlZS3sTyYlU5Yg}ZinMVNYPq+e&OHhYD@ zG<ELzzUn;l1q^x{HEQPbB(GSYzPh4l(WWX@hE1#!Hf>Ph*p#V0Z>Q>%75mhVuV6fR zWV7nI6&H_mD_@;|ebY_Bb(>UqFWp~$LUrpJ^~3WS+m%xSEH!wyvV2fsILCb7>c4gf L1Ir5q76xkouvm@d literal 0 HcmV?d00001 diff --git a/web/images/square-green.png b/web/images/square-green.png new file mode 100644 index 0000000000000000000000000000000000000000..82f2dd357b8c5b180aa157fcf4ed611018ff8baa GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<w6XvX4FM)i?64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E<Mpwz^a%EFVWHb6!E0X`wFJGQSanPGkCVfwr8SN{M1 zul_}a4JgH0666;Q<o;*)y^RlKfx4%QV@SoVqy$H1o(L9+i3~0cl6)&P4zRF?h&Ys6 hF$*1d6y3nU%+Pm*X}hEN+cuyU22WQ%mvv4FO#n~CJKF#N literal 0 HcmV?d00001 diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..ca245b8 --- /dev/null +++ b/web/index.html @@ -0,0 +1,97 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <meta name="verify-v1" content="oJj9+cXtpch0MSVjYgtyvC+Y57yYC6Cz9zFOd1+FXSw=" /> + <link rel="stylesheet" href="css/style.css" type="text/css" /> + <link rel="meta" title="DOAP" type="application/rdf+xml" href="http://www.fxruby.org/doap.rdf" /> + <title>FXRuby</title> +</head> + +<body> +<!-- wrap starts here --> +<div id="wrap"> + + <!--header --> + <div id="header"> + + <h1 id="logo-text"><a href="index.html">FXRuby</a></h1> + <p id="slogan">Graphical User Interface Development for Ruby</p> + + </div> + + <!-- menu --> + <div id="menu"> + <ul> + <li id='current' ><a href=# >Home</a></li> + <li ><a href=/community.html >Community</a></li> + <li ><a href=/downloads.html >Downloads</a></li> + <li ><a href=/documentation.html >Documentation</a></li> + </ul> + </div> + + <!-- content-wrap starts here --> + <div id="content-wrap"> + + <div id="sidebar"> + + <h3>Get the Book!</h3> + <a href="http://www.pragprog.com/titles/fxruby"><img src="images/fxruby-book.jpg" alt="FXRuby: Create Lean and Mean GUIs with Ruby" width="175" height="210" /></a> + + <h3>Links</h3> + <ul class="sidemenu"> + <li><a href="http://rubyforge.org/news/?group_id=300">News</a></li> + <li><a href="http://www.fxruby.org/doc/book.html">User's Guide</a></li> + <li><a href="http://www.fxruby.org/doc/api">API Docs</a></li> + <li><a href="http://www.fxruby.org/doc/examples.html">Screenshots</a></li> + <li><a href="http://rubyforge.org/tracker/?atid=1223&group_id=300&func=browse">Report Bugs</a></li> + <li><a href="http://www.gnu.org/copyleft/lesser.html">License</a></li> + </ul> + + </div> + + <div id="main"> + + <p>FXRuby is a library for developing powerful and sophisticated cross-platform graphical user interfaces (GUIs) for your Ruby +applications. It’s based on the <a href="http://www.fox-toolkit.org/" title="FOX Home Page">FOX Toolkit</a>, a popular open source +C++ library developed by Jeroen van der Zijp. What that means for you as an application developer is that you’re able to +write code in the <a href="http://www.ruby-lang.org/" title="Ruby Home Page">Ruby</a> programming language that you already know and love, +while at the same time taking advantage of the performance and functionality of a featureful, highly optimized C++ toolkit.</p> + + + <h1>Projects Using FXRuby</h1> + + + <p>Projects using FXRuby include:</p> + + + <ul> + <li><a href="http://www.insula.cz/dbtalk">DbTalk</a> is an interactive GUI-based tool for database querying, programming, administration, etc. It is developed by Dalibor Sramek.</li> + <li><a href="http://freeride.rubyforge.org/wiki/wiki.pl">FreeRIDE</a> is an IDE for the Ruby programming language.</li> + <li><a href="http://www.fisica.uniud.it/~glast/FRED">FRED</a> is a high energy physics event display built out of Ruby and FOX by Riccardo Giannitrapani and Marco Frailis.</li> + <li><a href="http://www.mondrian-ide.com/">Mondrian</a> is a cross-platform project-manager and editor for the Ruby language. Written in 100% native Ruby using the FOX GUI toolkit, Mondrian has the familiar look and feel of a modern IDE while remaining dedicated to the uniqueness of the Ruby language and its community.</li> + <li><a href="http://fox-tool.rubyforge.org/">foxGUIb</a> is an interactive gui builder and codegenerator for FXRuby. This tool makes it easy to quickly build complex and good looking graphical user interfaces for Ruby. +If your project uses FXRuby for its user interface, and you’d like to see it listed here, please send me an e-mail with the information.</li> + </ul> + + </div> + + <!-- content-wrap ends here --> + </div> + + <!--footer starts here--> + <div id="footer"> + + <p> + © 2008 Lyle Johnson<br /> + Web Site Generated Using <a href="http://webby.rubyforge.org/" title="Webby">Webby</a> + </p> + + </div> + +<!-- wrap ends here --> +</div> + +</body> +</html> -- GitLab