summaryrefslogtreecommitdiffstats
path: root/qtruby/rubylib/examples
diff options
context:
space:
mode:
Diffstat (limited to 'qtruby/rubylib/examples')
-rw-r--r--qtruby/rubylib/examples/base/kicons.rb54
-rw-r--r--qtruby/rubylib/examples/base/rui.rb21
-rw-r--r--qtruby/rubylib/examples/canvastest/canvastest.rb75
-rw-r--r--qtruby/rubylib/examples/killerfilter/killerfilter.rb56
-rw-r--r--qtruby/rubylib/examples/network/clientserver/client/client.rb88
-rw-r--r--qtruby/rubylib/examples/network/clientserver/server/server.rb115
-rw-r--r--qtruby/rubylib/examples/passivepopup/passivepopup.rb39
-rw-r--r--qtruby/rubylib/examples/qt-examples/aclock/aclock.rb113
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/aclock/main.rb15
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/README8
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/canvastext.rb16
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/canvasview.rb53
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform.rb488
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb212
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb102
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/element.rb161
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk256
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm36
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm33
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm115
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm33
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm34
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm31
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm30
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm34
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm27
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm32
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm31
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm27
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/main.rb26
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/optionsform.rb127
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/setdataform.rb184
-rw-r--r--qtruby/rubylib/examples/qt-examples/checklists/checklists.rb147
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/checklists/main.rb15
-rw-r--r--qtruby/rubylib/examples/qt-examples/dclock/dclock.rb67
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/dclock/main.rb12
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb14
-rw-r--r--qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb140
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/forever/forever.rb84
-rw-r--r--qtruby/rubylib/examples/qt-examples/hello/hello.rb78
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/hello/main.rb23
-rw-r--r--qtruby/rubylib/examples/qt-examples/progress/progress.rb275
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/tictac/main.rb13
-rw-r--r--qtruby/rubylib/examples/qt-examples/tictac/tictac.rb311
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/tooltip/main.rb12
-rw-r--r--qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb95
-rw-r--r--qtruby/rubylib/examples/qtscribble/scribble.rb274
-rw-r--r--qtruby/rubylib/examples/ruboids/Manifest26
-rw-r--r--qtruby/rubylib/examples/ruboids/README53
-rw-r--r--qtruby/rubylib/examples/ruboids/TODO29
-rw-r--r--qtruby/rubylib/examples/ruboids/boids.properties33
-rwxr-xr-xqtruby/rubylib/examples/ruboids/generateManifest.rb42
-rw-r--r--qtruby/rubylib/examples/ruboids/index.html147
-rwxr-xr-xqtruby/rubylib/examples/ruboids/release.rb152
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Boid.rb141
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb159
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Camera.rb24
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb213
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb144
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb61
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb54
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Flock.rb47
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb278
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Params.rb87
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Point.rb153
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Thing.rb34
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb21
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/View.rb88
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/World.rb82
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb54
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/info.rb12
-rwxr-xr-xqtruby/rubylib/examples/ruboids/ruboids/ruboids.rb29
-rw-r--r--qtruby/rubylib/examples/testcases/bugs.rb57
-rw-r--r--qtruby/rubylib/examples/testcases/error_reporting.rb85
-rw-r--r--qtruby/rubylib/examples/testcases/opoverloading.rb46
-rw-r--r--qtruby/rubylib/examples/textedit/textedit.rb150
89 files changed, 7097 insertions, 0 deletions
diff --git a/qtruby/rubylib/examples/base/kicons.rb b/qtruby/rubylib/examples/base/kicons.rb
new file mode 100644
index 00000000..0d0a2c01
--- /dev/null
+++ b/qtruby/rubylib/examples/base/kicons.rb
@@ -0,0 +1,54 @@
+class KIconCollection
+ IconInfo = Struct.new(:collection, :id, :filetype)
+ def initialize(icon_collections)
+ @icon_info = {}
+ icon_collections.each_pair {
+ |collection_name, collection|
+ collection.each_pair {
+ |key, value|
+ info = IconInfo.new(collection_name, value, "png")
+ @icon_info[key] = info
+ }
+ }
+ end
+ def dims
+ "32x32"
+ end
+ def kdedir
+ ENV["KDEDIR"]
+ end
+ def get_icon_path(icon_type)
+ info = @icon_info[icon_type]
+ "#{kdedir}/share/icons/default.kde/#{dims}/#{info.collection}/#{info.id}.#{info.filetype}"
+ end
+ def get_icon_set(icon_type)
+ path = get_icon_path(icon_type)
+ pixmap = Qt::Pixmap.new(path)
+ icon_set = Qt::IconSet.new
+ icon_set.setPixmap(pixmap, Qt::IconSet.Small)
+ icon_set
+ end
+ def make_qt_action(parent, text_with_accel, icon_type)
+ act = Qt::Action.new(parent)
+ act.setIconSet(get_icon_set(icon_type))
+ act.setMenuText(text_with_accel)
+ act
+ end
+end
+
+module Icons
+ FILE_NEW, FILE_OPEN, FILE_CLOSE, FILE_SAVE, FILE_SAVE_AS, EXIT = 1,2,3,4,5,6
+end
+
+icon_collections = {
+ "actions" => {
+ Icons::FILE_NEW => "filenew",
+ Icons::FILE_OPEN => "fileopen",
+ Icons::FILE_CLOSE => "fileclose",
+ Icons::FILE_SAVE => "filesave",
+ Icons::FILE_SAVE_AS => "filesaveas",
+ Icons::EXIT => "exit"
+ }
+}
+$kIcons = KIconCollection.new(icon_collections)
+print "Using KDEDIR == ", $kIcons.kdedir, "\n"
diff --git a/qtruby/rubylib/examples/base/rui.rb b/qtruby/rubylib/examples/base/rui.rb
new file mode 100644
index 00000000..ad14bc11
--- /dev/null
+++ b/qtruby/rubylib/examples/base/rui.rb
@@ -0,0 +1,21 @@
+require '../base/kicons.rb'
+
+RAction = Struct.new(:text_with_accel, :icon_type, :rec, :slot, :included_in, :action)
+RSeperator = Struct.new(:included_in, :id)
+
+def build_actions(actions)
+ actions.each { |a|
+ if a.is_a? RSeperator
+ a.included_in.each {
+ |to| a.id = to.insertSeparator()
+ }
+ else
+ qt_action = $kIcons.make_qt_action(self, a.text_with_accel, a.icon_type)
+ connect(qt_action, SIGNAL('activated()'), a.rec, a.slot)
+ a.included_in.each {
+ |to| qt_action.addTo(to)
+ }
+ a.action = qt_action
+ end
+ }
+end
diff --git a/qtruby/rubylib/examples/canvastest/canvastest.rb b/qtruby/rubylib/examples/canvastest/canvastest.rb
new file mode 100644
index 00000000..4187d91d
--- /dev/null
+++ b/qtruby/rubylib/examples/canvastest/canvastest.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+require 'rexml/document'
+
+require '../base/kicons.rb'
+require '../base/rui.rb'
+
+class MyCanvasView < Qt::CanvasView
+ def initialize(canvas, parent)
+ @canvas = canvas
+ super(canvas, parent)
+ end
+ def contentsMousePressEvent(e)
+ super
+ list = canvas.collisions(e.pos)
+ return if list.empty?
+ c = list.first
+ return if c.rtti != Qt::CanvasItem::Rtti_Rectangle
+ c.hide
+ @canvas.update
+ end
+end
+
+class MyWidget < Qt::MainWindow
+ slots 'new()', 'open()', 'save_as()'
+ def make_rect
+ rect = Qt::CanvasRectangle.new(rand(@canvas.width()), rand(@canvas.height()),
+ @canvas.width / 5, @canvas.width / 5, @canvas)
+ z = rand(256)
+ color = Qt::Color.new(z,z,z)
+ rect.setBrush(Qt::Brush.new(color))
+ color = Qt::Color.new(rand(32)*8, rand(32)*8, rand(32)*8)
+ rect.setPen(Qt::Pen.new(color, 6))
+ rect.setZ(z)
+ rect.show
+ @rects << rect
+ end
+ def initialize()
+ super
+
+ fileTools = Qt::ToolBar.new(self, "file operations")
+ fileMenu = Qt::PopupMenu.new(self)
+
+ actions = [
+ RAction.new("&New", Icons::FILE_NEW, self, SLOT('new()'), [fileTools, fileMenu]),
+ RAction.new("&Open...", Icons::FILE_OPEN, self, SLOT('open()'), [fileTools, fileMenu]),
+ @save = RAction.new("Save &As...", Icons::FILE_SAVE_AS, self, SLOT('save_as()'), [fileTools, fileMenu]),
+ RSeperator.new([fileMenu]),
+ RAction.new("E&xit", Icons::EXIT, $qApp, SLOT('quit()'), [fileMenu])
+ ]
+ build_actions(actions)
+
+ menubar = Qt::MenuBar.new(self)
+ menubar.insertItem("&File", fileMenu)
+
+ @canvas = Qt::Canvas.new(640, 480)
+
+ @rects = []
+ 5.times { make_rect }
+
+ @canvas_view = MyCanvasView.new(@canvas, self)
+ self.setCentralWidget(@canvas_view)
+ @canvas.update
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.show
+
+a.setMainWidget(w)
+a.exec()
+exit
diff --git a/qtruby/rubylib/examples/killerfilter/killerfilter.rb b/qtruby/rubylib/examples/killerfilter/killerfilter.rb
new file mode 100644
index 00000000..647dc079
--- /dev/null
+++ b/qtruby/rubylib/examples/killerfilter/killerfilter.rb
@@ -0,0 +1,56 @@
+#!/usr/bin/env ruby -w
+
+# This is the EventFilter example from Chapter 16 of 'Programming with Qt'
+
+require 'Qt'
+
+class KillerFilter < Qt::Object
+
+ def eventFilter( object, event )
+ if event.type() == Qt::Event::MouseButtonPress
+ if event.button() == RightButton
+ object.close(false)
+ return true
+ else
+ return false
+ end
+ else
+ return false
+ end
+ end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+toplevel = Qt::Widget.new
+toplevel.resize(230, 130)
+
+killerfilter = KillerFilter.new
+
+pb = Qt::PushButton.new(toplevel)
+pb.setGeometry( 10, 10, 100, 50 )
+pb.text = "pushbutton"
+pb.installEventFilter(killerfilter)
+
+le = Qt::LineEdit.new(toplevel)
+le.setGeometry( 10, 70, 100, 50 )
+le.text = "Line edit"
+le.installEventFilter(killerfilter)
+
+cb = Qt::CheckBox.new(toplevel)
+cb.setGeometry( 120, 10, 100, 50 )
+cb.text = "Check-box"
+cb.installEventFilter(killerfilter)
+
+rb = Qt::RadioButton.new(toplevel)
+rb.setGeometry( 120, 70, 100, 50 )
+rb.text = "Radio button"
+rb.installEventFilter(killerfilter)
+
+a.mainWidget = toplevel
+toplevel.show
+a.exec
+
+
+ \ No newline at end of file
diff --git a/qtruby/rubylib/examples/network/clientserver/client/client.rb b/qtruby/rubylib/examples/network/clientserver/client/client.rb
new file mode 100644
index 00000000..1f16b0ca
--- /dev/null
+++ b/qtruby/rubylib/examples/network/clientserver/client/client.rb
@@ -0,0 +1,88 @@
+require 'Qt'
+
+class Client < Qt::VBox
+
+ def initialize( host, port )
+ super()
+ # GUI layout
+ @infoText = Qt::TextView.new( self )
+ hb = Qt::HBox.new( self )
+ @inputText = Qt::LineEdit.new( hb )
+ send = Qt::PushButton.new( tr("Send") , hb )
+ close = Qt::PushButton.new( tr("Close connection") , self )
+ quit = Qt::PushButton.new( tr("Quit") , self )
+
+ connect( send, SIGNAL('clicked()'), SLOT('sendToServer()') )
+ connect( close, SIGNAL('clicked()'), SLOT('closeConnection()') )
+ connect( quit, SIGNAL('clicked()'), $qApp, SLOT('quit()') )
+
+ # create the socket and connect various of its signals
+ @socket = Qt::Socket.new( self )
+ connect( @socket, SIGNAL('connected()'),
+ SLOT('socketConnected()') )
+ connect( @socket, SIGNAL('connectionClosed()'),
+ SLOT('socketConnectionClosed()') )
+ connect( @socket, SIGNAL('readyRead()'),
+ SLOT('socketReadyRead()') )
+ connect( @socket, SIGNAL('error(int)'),
+ SLOT('socketError(int)') )
+
+ # connect to the server
+ @infoText.append( tr("Trying to connect to the server\n") )
+ @socket.connectToHost( host, port )
+ end
+
+ slots 'closeConnection()', 'sendToServer()',
+ 'socketReadyRead()', 'socketConnected()',
+ 'socketConnectionClosed()', 'socketClosed()',
+ 'socketError(int)'
+
+ def closeConnection()
+ @socket.close()
+ if @socket.state() == Qt::Socket::Closing
+ # We have a delayed close.
+ connect( @socket, SIGNAL('delayedCloseFinished()'),
+ SLOT('socketClosed()') )
+ else
+ # The socket is closed.
+ socketClosed()
+ end
+ end
+
+ def sendToServer()
+ # write to the server
+ os = Qt::TextStream.new(@socket)
+ os << @inputText.text() << "\n"
+ @inputText.setText( "" )
+ os.dispose()
+ end
+
+ def socketReadyRead()
+ # read from the server
+ while @socket.canReadLine() do
+ @infoText.append( @socket.readLine() )
+ end
+ end
+
+ def socketConnected()
+ @infoText.append( tr("Connected to server\n") )
+ end
+
+ def socketConnectionClosed()
+ @infoText.append( tr("Connection closed by the server\n") )
+ end
+
+ def socketClosed()
+ @infoText.append( tr("Connection closed\n") )
+ end
+
+ def socketError( e )
+ @infoText.append( tr("Error number %d occurred\n" % e) )
+ end
+end
+
+app = Qt::Application.new( ARGV )
+client = Client.new( ARGV.length < 1 ? "localhost" : ARGV[0], 4242 )
+app.mainWidget = client
+client.show
+app.exec
diff --git a/qtruby/rubylib/examples/network/clientserver/server/server.rb b/qtruby/rubylib/examples/network/clientserver/server/server.rb
new file mode 100644
index 00000000..d8a937f4
--- /dev/null
+++ b/qtruby/rubylib/examples/network/clientserver/server/server.rb
@@ -0,0 +1,115 @@
+require 'Qt'
+
+=begin
+ The ClientSocket class provides a socket that is connected with a client.
+ For every client that connects to the server, the server creates a new
+ instance of this class.
+=end
+class ClientSocket < Qt::Socket
+ def initialize(sock, parent=nil, name=nil)
+ super( parent, name )
+ @line = 0
+ connect( self, SIGNAL('readyRead()'),
+ SLOT('readClient()') )
+ connect( self, SIGNAL('connectionClosed()'),
+ SLOT('deleteLater()') )
+ setSocket( sock )
+ end
+
+ signals 'logText(const QString&)'
+
+ slots 'readClient()'
+
+ def readClient()
+ ts = Qt::TextStream.new( self )
+ while canReadLine() do
+ str = ts.readLine()
+ emit logText( tr("Read: '%s'\n" % str) )
+
+ ts << @line << ": " << str
+ # 'endl' needs to be called like this in ruby
+ endl(ts)
+ emit logText( tr("Wrote: '%d: %s'\n" % [@line, str]) )
+
+ @line += 1
+ end
+ ts.dispose()
+ end
+end
+
+
+=begin
+ The SimpleServer class handles new connections to the server. For every
+ client that connects, it creates a new ClientSocket -- that instance is now
+ responsible for the communication with that client.
+=end
+class SimpleServer < Qt::ServerSocket
+ def initialize( parent=nil )
+ super( 4242, 1, parent )
+ if !ok()
+ qWarning("Failed to bind to port 4242")
+ exit(1)
+ end
+ end
+
+ def newConnection( socket )
+ s = ClientSocket.new( socket, self )
+ emit newConnect( s )
+ end
+
+ # The type of the argument is 'QSocket*', not
+ # 'ClientSocket*' as only types in the Smoke
+ # library can be used for types in Signals
+ signals 'newConnect(QSocket*)'
+end
+
+
+=begin
+ The ServerInfo class provides a small GUI for the server. It also creates the
+ SimpleServer and as a result the server.
+=end
+class ServerInfo < Qt::VBox
+ def initialize()
+ super
+ @server = SimpleServer.new( self )
+
+ itext = tr(
+ "This is a small server example.\n" +
+ "Connect with the client now."
+ )
+ lb = Qt::Label.new( itext, self )
+ lb.setAlignment( AlignHCenter )
+ @infoText = Qt::TextView.new( self )
+ quit = Qt::PushButton.new( tr("Quit") , self )
+
+ # See the comment above about why the 'ClientSocket*'
+ # type cannot be used
+ connect( @server, SIGNAL('newConnect(QSocket*)'),
+ SLOT('newConnect(QSocket*)') )
+ connect( quit, SIGNAL('clicked()'), $qApp,
+ SLOT('quit()') )
+ end
+
+ slots 'newConnect(QSocket*)', 'connectionClosed()'
+
+ def newConnect( s )
+ @infoText.append( tr("New connection\n") )
+ connect( s, SIGNAL('logText(const QString&)'),
+ @infoText, SLOT('append(const QString&)') )
+ connect( s, SIGNAL('connectionClosed()'),
+ SLOT('connectionClosed()') )
+ end
+
+ def connectionClosed()
+ @infoText.append( tr("Client closed connection\n") )
+ end
+end
+
+
+app = Qt::Application.new( ARGV )
+info = ServerInfo.new
+app.mainWidget = info
+info.show
+app.exec
+
+
diff --git a/qtruby/rubylib/examples/passivepopup/passivepopup.rb b/qtruby/rubylib/examples/passivepopup/passivepopup.rb
new file mode 100644
index 00000000..37f60c1f
--- /dev/null
+++ b/qtruby/rubylib/examples/passivepopup/passivepopup.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+
+class PassiveWindow < Qt::Frame
+ MARGIN = 20
+
+ def initialize(message)
+ super(nil, "passivedlg",
+ Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop |
+ Qt::WStyle_Tool | Qt::WStyle_NoBorder)
+
+ setFrameStyle(Qt::Frame::Box| Qt::Frame::Plain)
+ setLineWidth(2)
+
+ setMinimumWidth(100)
+ layout=Qt::VBoxLayout.new(self, 6, 11)
+ layout.setAutoAdd(true)
+ Qt::Label.new(message, self)
+
+ quit=Qt::PushButton.new(tr("Close"), self)
+ connect(quit, SIGNAL("clicked()"), SLOT("close()"))
+ end
+
+ def show
+ super
+ move(Qt::Application.desktop().width() - width() - MARGIN,
+ Qt::Application.desktop().height() - height() - MARGIN)
+ end
+end
+
+if (Process.fork != nil)
+ exit
+end
+app = Qt::Application.new(ARGV)
+win = PassiveWindow.new(ARGV[0])
+app.mainWidget = win
+win.show
+app.exec
diff --git a/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb b/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb
new file mode 100644
index 00000000..a2cdc378
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb
@@ -0,0 +1,113 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+# an analog clock widget using an internal QTimer
+class AnalogClock < Qt::Widget
+ slots 'setTime(const QTime&)', 'drawClock(QPainter*)', 'timeout()'
+
+ def initialize(*k)
+ super(*k)
+
+ @time = Qt::Time::currentTime
+ @internalTimer = Qt::Timer.new(self)
+ connect(@internalTimer, SIGNAL('timeout()'), self, SLOT('timeout()'))
+ @internalTimer.start(5000)
+ end
+
+ def mousePressEvent(e)
+ if isTopLevel
+ topLeft = geometry.topLeft - frameGeometry.topLeft
+ @clickPos = e.pos + topLeft
+ end
+ end
+
+ def mouseMoveEvent(e)
+ if isTopLevel
+ move(e.globalPos - @clickPos) unless @clickPos.nil?
+ end
+ end
+
+ def setTime(t)
+ # erm. huh?
+ timeout()
+ end
+
+ # The QTimer::timeout() signal is received by this slot.
+ def timeout
+ new_time = Qt::Time::currentTime
+ @time = @time.addSecs 5
+ unless new_time.minute == @time.minute
+ if autoMask
+ updateMask
+ else
+ update
+ end
+ end
+ end
+
+ def paintEvent(blah)
+ unless autoMask
+ paint = Qt::Painter.new(self)
+ paint.setBrush(colorGroup.foreground)
+ drawClock(paint)
+ paint.end
+ end
+ end
+
+ # If clock is transparent, we use updateMask() instead of paintEvent()
+ def updateMask
+ bm = Qt::Bitmap.new(size)
+ bm.fill(color0) # transparent
+
+ paint = Qt::Painter.new
+ paint.begin(bm, self)
+ paint.setBrush(color1) # use non-transparent color
+ paint.setPen(color1)
+
+ drawClock(paint)
+
+ paint.end
+ setMask(bm)
+ end
+
+ # The clock is painted using a 1000x1000 square coordinate system, in
+ # the centered square, as big as possible. The painter's pen and
+ # brush colors are used.
+ def drawClock(paint)
+ paint.save
+
+ paint.setWindow(-500,-500, 1000,1000)
+
+ v = paint.viewport
+ d = [v.width, v.height].min
+ vpx = (v.left + (v.width-d)) / 2
+ vpy = (v.top - (v.height-d)) / 2
+ paint.setViewport(vpx, vpy, d, d)
+
+ paint.save
+ paint.rotate(30*(@time.hour%12-3) + @time.minute/2)
+ pts = Qt::PointArray.new(4, [-20,0, 0,-20, 300,0, 0,20])
+ paint.drawConvexPolygon(pts)
+ paint.restore
+
+ paint.save
+ paint.rotate((@time.minute-15)*6)
+ pts = Qt::PointArray.new(4, [-10,0, 0,-10, 400,0, 0,10])
+ paint.drawConvexPolygon(pts)
+ paint.restore;
+
+ 12.times {
+ paint.drawLine(440,0, 460,0)
+ paint.rotate(30)
+ }
+
+ paint.restore
+ end
+
+ def setAutoMask(background)
+ setBackgroundMode(background ? PaletteForeground : PaletteBackground)
+ Qt::Widget::setAutoMask(background)
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/aclock/main.rb b/qtruby/rubylib/examples/qt-examples/aclock/main.rb
new file mode 100755
index 00000000..dadbee15
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/aclock/main.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'aclock'
+
+a = Qt::Application.new(ARGV)
+clock = AnalogClock.new
+ARGV.each {|arg|
+ clock.setAutoMask(true) if arg == '-transparent'
+}
+clock.resize(100, 100)
+a.setMainWidget(clock)
+clock.setCaption('QtRuby example - Analog Clock')
+clock.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/chart/README b/qtruby/rubylib/examples/qt-examples/chart/README
new file mode 100644
index 00000000..921437c5
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/README
@@ -0,0 +1,8 @@
+
+A Complete Canvas Application
+
+This is a complete example program with a main window, menus and
+toolbars. The main widget is a Qt::Canvas, and this example
+demonstrates basic canvas usage.
+
+This example is the subject of Qt Tutorial #2
diff --git a/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb b/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb
new file mode 100644
index 00000000..8a298faa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb
@@ -0,0 +1,16 @@
+
+class CanvasText < Qt::CanvasText
+
+ CANVAS_TEXT = 1100
+ attr :index
+
+ def initialize(index, *k)
+ super(*k)
+ @index = index
+ end
+
+ def rtti() return CANVAS_TEXT end
+
+end
+
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb b/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb
new file mode 100644
index 00000000..416b0de7
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb
@@ -0,0 +1,53 @@
+class CanvasView < Qt::CanvasView
+
+ def initialize(canvas, elements, parent = nil, name = "canvas view", f = 0)
+ super(canvas, parent, name, f)
+ @elements = elements
+ @movingItem = nil
+ end
+
+ def contentsContextMenuEvent( e )
+ parent().optionsMenu.exec( Qt::Cursor.pos() )
+ end
+
+
+ def viewportResizeEvent( e )
+ canvas().resize( e.size().width(), e.size().height() )
+ parent().drawElements()
+ end
+
+
+ def contentsMousePressEvent( e )
+ list = canvas().collisions( e.pos() )
+ list.each do |it|
+ if it.rtti() == CanvasText::CANVAS_TEXT
+ @movingItem = it
+ @pos = e.pos()
+ return
+ end
+ end
+ @movingItem = nil
+ end
+
+
+ def contentsMouseMoveEvent( e )
+ if @movingItem
+ offset = e.pos() - @pos
+ @movingItem.moveBy( offset.x(), offset.y() )
+ @pos = e.pos()
+ form = parent()
+ form.changed = true
+ chartType = form.chartType()
+ item = @movingItem
+ i = item.index()
+
+ @elements[i].setProX( chartType, item.x() / canvas().width() )
+ @elements[i].setProY( chartType, item.y() / canvas().height() )
+
+ canvas().update()
+ end
+ end
+
+end
+
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform.rb
new file mode 100644
index 00000000..a649ce12
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform.rb
@@ -0,0 +1,488 @@
+class ChartForm < Qt::MainWindow
+
+ slots 'fileNew()',
+ 'fileOpen()',
+ 'fileOpenRecent( int )',
+ 'fileSave()',
+ 'fileSaveAs()',
+ 'fileSaveAsPixmap()',
+ 'filePrint()',
+ 'fileQuit()',
+ 'optionsSetData()',
+ 'updateChartType( QAction * )',
+ 'optionsSetFont()',
+ 'optionsSetOptions()',
+ 'helpHelp()',
+ 'helpAbout()',
+ 'helpAboutQt()',
+ 'saveOptions()'
+
+ attr_accessor :changed
+ attr_reader :chartType, :optionsMenu
+
+ MAX_ELEMENTS = 100
+ MAX_RECENTFILES = 9 # Must not exceed 9
+
+ PIE = 0
+ VERTICAL_BAR = 1
+ HORIZONTAL_BAR = 2
+
+ NO = 0
+ YES = 1
+ AS_PERCENTAGE = 2
+
+ WINDOWS_REGISTRY = "/Trolltech/QtExamples"
+ APP_KEY = "/Chart/"
+
+ def initialize( filename )
+ super( nil, nil, WDestructiveClose )
+ @filename = filename
+ setIcon( Qt::Pixmap.new( "images/options_piechart.xpm" ) )
+
+ fileNewAction = Qt::Action.new(
+ "New Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_new.xpm" )),
+ "&New", Qt::KeySequence.new(CTRL+Key_N), self, "new" )
+ connect( fileNewAction, SIGNAL( 'activated()' ), self, SLOT( 'fileNew()' ) )
+
+ fileOpenAction = Qt::Action.new(
+ "Open Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_open.xpm" )),
+ "&Open...", Qt::KeySequence.new(CTRL+Key_O), self, "open" )
+ connect( fileOpenAction, SIGNAL( 'activated()' ), self, SLOT( 'fileOpen()' ) )
+
+ fileSaveAction = Qt::Action.new(
+ "Save Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "&Save", Qt::KeySequence.new(CTRL+Key_S), self, "save" )
+ connect( fileSaveAction, SIGNAL( 'activated()' ), self, SLOT( 'fileSave()' ) )
+
+ fileSaveAsAction = Qt::Action.new(
+ "Save Chart As", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "Save &As...", Qt::KeySequence.new(0), self, "save as" )
+ connect( fileSaveAsAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'fileSaveAs()' ) )
+
+ fileSaveAsPixmapAction = Qt::Action.new(
+ "Save Chart As Bitmap", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "Save As &Bitmap...", Qt::KeySequence.new(CTRL+Key_B), self, "save as bitmap" )
+ connect( fileSaveAsPixmapAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'fileSaveAsPixmap()' ) )
+
+ filePrintAction = Qt::Action.new(
+ "Print Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_print.xpm" )),
+ "&Print Chart...", Qt::KeySequence.new(CTRL+Key_P), self, "print chart" )
+ connect( filePrintAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'filePrint()' ) )
+
+ optionsSetDataAction = Qt::Action.new(
+ "Set Data", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setdata.xpm" )),
+ "Set &Data...", Qt::KeySequence.new(CTRL+Key_D), self, "set data" )
+ connect( optionsSetDataAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetData()' ) )
+
+
+ chartGroup = Qt::ActionGroup.new( self ) # Connected later
+ chartGroup.setExclusive( true )
+
+ @optionsPieChartAction = Qt::Action.new(
+ "Pie Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_piechart.xpm" )),
+ "&Pie Chart", Qt::KeySequence.new(CTRL+Key_I), chartGroup, "pie chart" )
+ @optionsPieChartAction.setToggleAction( true )
+
+ @optionsHorizontalBarChartAction = Qt::Action.new(
+ "Horizontal Bar Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_horizontalbarchart.xpm" )),
+ "&Horizontal Bar Chart", Qt::KeySequence.new(CTRL+Key_H), chartGroup,
+ "horizontal bar chart" )
+ @optionsHorizontalBarChartAction.setToggleAction( true )
+
+ @optionsVerticalBarChartAction = Qt::Action.new(
+ "Vertical Bar Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_verticalbarchart.xpm" )),
+ "&Vertical Bar Chart", Qt::KeySequence.new(CTRL+Key_V), chartGroup, "Vertical bar chart" )
+ @optionsVerticalBarChartAction.setToggleAction( true )
+
+
+ optionsSetFontAction = Qt::Action.new(
+ "Set Font", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setfont.xpm" )),
+ "Set &Font...", Qt::KeySequence.new(CTRL+Key_F), self, "set font" )
+ connect( optionsSetFontAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetFont()' ) )
+
+ optionsSetOptionsAction = Qt::Action.new(
+ "Set Options", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setoptions.xpm" )),
+ "Set &Options...", Qt::KeySequence.new(0), self, "set options" )
+ connect( optionsSetOptionsAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetOptions()' ) )
+
+ fileQuitAction = Qt::Action.new( "Quit", "&Quit", Qt::KeySequence.new(CTRL+Key_Q), self, "quit" )
+ connect( fileQuitAction, SIGNAL( 'activated()' ), self, SLOT( 'fileQuit()' ) )
+
+
+ fileTools = Qt::ToolBar.new( self, "file operations" )
+ fileTools.setLabel( "File Operations" )
+ fileNewAction.addTo( fileTools )
+ fileOpenAction.addTo( fileTools )
+ fileSaveAction.addTo( fileTools )
+ fileTools.addSeparator()
+ filePrintAction.addTo( fileTools )
+
+ optionsTools = Qt::ToolBar.new( self, "options operations" )
+ optionsTools.setLabel( "Options Operations" )
+ optionsSetDataAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ @optionsPieChartAction.addTo( optionsTools )
+ @optionsHorizontalBarChartAction.addTo( optionsTools )
+ @optionsVerticalBarChartAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ optionsSetFontAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ optionsSetOptionsAction.addTo( optionsTools )
+
+ @fileMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&File", @fileMenu )
+ fileNewAction.addTo( @fileMenu )
+ fileOpenAction.addTo( @fileMenu )
+ fileSaveAction.addTo( @fileMenu )
+ fileSaveAsAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ fileSaveAsPixmapAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ filePrintAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ fileQuitAction.addTo( @fileMenu )
+
+ @optionsMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&Options", @optionsMenu )
+ optionsSetDataAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ @optionsPieChartAction.addTo( @optionsMenu )
+ @optionsHorizontalBarChartAction.addTo( @optionsMenu )
+ @optionsVerticalBarChartAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ optionsSetFontAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ optionsSetOptionsAction.addTo( @optionsMenu )
+
+ menuBar().insertSeparator()
+
+ helpMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&Help", helpMenu )
+ helpMenu.insertItem( "&Help", self, SLOT('helpHelp()'), Qt::KeySequence.new(Key_F1) )
+ helpMenu.insertItem( "&About", self, SLOT('helpAbout()') )
+ helpMenu.insertItem( "About &Qt", self, SLOT('helpAboutQt()') )
+
+
+ @printer = nil
+ @elements = Array.new(MAX_ELEMENTS)
+
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ windowWidth = settings.readNumEntry( APP_KEY + "WindowWidth", 460 )
+ windowHeight = settings.readNumEntry( APP_KEY + "WindowHeight", 530 )
+ windowX = settings.readNumEntry( APP_KEY + "WindowX", -1 )
+ windowY = settings.readNumEntry( APP_KEY + "WindowY", -1 )
+ setChartType( settings.readNumEntry( APP_KEY + "ChartType", PIE ) )
+ @addValues = settings.readNumEntry( APP_KEY + "AddValues", NO )
+ @decimalPlaces = settings.readNumEntry( APP_KEY + "Decimals", 2 )
+ @font = Qt::Font.new( "Helvetica", 18, Qt::Font::Bold )
+ @font.fromString(
+ settings.readEntry( APP_KEY + "Font", @font.toString() ) )
+ @recentFiles = []
+ for i in 0...MAX_RECENTFILES
+ filename = settings.readEntry( APP_KEY + "File" + ( i + 1 ).to_s )
+ if !filename.nil?
+ @recentFiles.push( filename )
+ end
+ end
+ if @recentFiles.length() > 0
+ updateRecentFilesMenu()
+ end
+
+
+ # Connect *after* we've set the chart type on so we don't call
+ # drawElements() prematurely.
+ connect( chartGroup, SIGNAL( 'selected(QAction*)' ),
+ self, SLOT( 'updateChartType(QAction*)' ) )
+
+ resize( windowWidth, windowHeight )
+ if windowX != -1 || windowY != -1
+ move( windowX, windowY )
+ end
+
+ @canvas = Qt::Canvas.new( self )
+ @canvas.resize( width(), height() )
+ @canvasView = CanvasView.new( @canvas, @elements, self )
+ setCentralWidget( @canvasView )
+ @canvasView.show()
+
+ if ! @filename.nil?
+ load( @filename )
+ else
+ init()
+ @elements[0].set( 20, red, 14, "Red" )
+ @elements[1].set( 70, cyan, 2, "Cyan", darkGreen )
+ @elements[2].set( 35, blue, 11, "Blue" )
+ @elements[3].set( 55, yellow, 1, "Yellow", darkBlue )
+ @elements[4].set( 80, magenta, 1, "Magenta" )
+ drawElements()
+ end
+
+ statusBar().message( "Ready", 2000 )
+ end
+
+
+
+ def init()
+ setCaption( "Chart" )
+ @filename = nil
+ @changed = false
+
+ @elements[0] = Element.new( Element::INVALID, red )
+ @elements[1] = Element.new( Element::INVALID, cyan )
+ @elements[2] = Element.new( Element::INVALID, blue )
+ @elements[3] = Element.new( Element::INVALID, yellow )
+ @elements[4] = Element.new( Element::INVALID, green )
+ @elements[5] = Element.new( Element::INVALID, magenta )
+ @elements[6] = Element.new( Element::INVALID, darkYellow )
+ @elements[7] = Element.new( Element::INVALID, darkRed )
+ @elements[8] = Element.new( Element::INVALID, darkCyan )
+ @elements[9] = Element.new( Element::INVALID, darkGreen )
+ @elements[10] = Element.new( Element::INVALID, darkMagenta )
+ @elements[11] = Element.new( Element::INVALID, darkBlue )
+ for i in 12...MAX_ELEMENTS
+ x = (i.to_f / MAX_ELEMENTS) * 360
+ y = ((x * 256) % 105) + 151
+ z = ((i * 17) % 105) + 151;
+ @elements[i] = Element.new( Element::INVALID, Qt::Color.new( x, y, z, Qt::Color::Hsv ) )
+ end
+ end
+
+ def closeEvent( e )
+ fileQuit()
+ end
+
+
+ def fileNew()
+ if okToClear()
+ init()
+ drawElements()
+ end
+ end
+
+
+ def fileOpen()
+ if !okToClear()
+ return
+ end
+
+ filename = Qt::FileDialog.getOpenFileName(
+ nil, "Charts (*.cht)", self,
+ "file open", "Chart -- File Open" )
+ if !filename.nil?
+ load( filename )
+ else
+ statusBar().message( "File Open abandoned", 2000 )
+ end
+ end
+
+
+ def fileSaveAs()
+ filename = Qt::FileDialog.getSaveFileName(
+ nil, "Charts (*.cht)", self,
+ "file save as", "Chart -- File Save As" )
+ if !filename.nil?
+ answer = 0
+ if Qt::File.exists( filename )
+ answer = Qt::MessageBox.warning(
+ self, "Chart -- Overwrite File",
+ "Overwrite\n\'#{filename}\'?",
+ "&Yes", "&No", nil, 1, 1 )
+ end
+ if answer == 0
+ @filename = filename
+ updateRecentFiles( filename )
+ fileSave()
+ return
+ end
+ end
+ statusBar().message( "Saving abandoned", 2000 )
+ end
+
+
+ def fileOpenRecent( index )
+ if !okToClear()
+ return
+ end
+
+ load( @recentFiles[index] )
+ end
+
+
+ def updateRecentFiles( filename )
+ if @recentFiles.include?( filename )
+ return
+ end
+
+ @recentFiles.push( filename )
+ if @recentFiles.length() > MAX_RECENTFILES
+ @recentFiles.shift()
+ end
+
+ updateRecentFilesMenu()
+ end
+
+
+ def updateRecentFilesMenu()
+ for i in 0...MAX_RECENTFILES
+ if @fileMenu.findItem( i )
+ @fileMenu.removeItem( i )
+ end
+ if i < @recentFiles.length()
+ @fileMenu.insertItem( "&%d %s" % [i + 1, @recentFiles[i]],
+ self, SLOT( 'fileOpenRecent(int)' ),
+ Qt::KeySequence.new(0), i )
+ end
+ end
+ end
+
+
+ def fileQuit()
+ if okToClear()
+ saveOptions()
+ $qApp.exit( 0 )
+ end
+ end
+
+
+ def okToClear()
+ if @changed
+ if @filename.nil?
+ msg = "Unnamed chart "
+ else
+ msg = "Chart '#{@filename}'\n"
+ end
+ msg += "has been changed."
+
+ x = Qt::MessageBox.information( self, "Chart -- Unsaved Changes",
+ msg, "&Save", "Cancel", "&Abandon",
+ 0, 1 )
+ case x
+ when 0 # Save
+ fileSave()
+ when 1 # Cancel
+ when 2 # Abandon
+ else
+ return false
+ end
+ end
+ return true
+ end
+
+
+ def saveOptions()
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ settings.writeEntry( APP_KEY + "WindowWidth", width() )
+ settings.writeEntry( APP_KEY + "WindowHeight", height() )
+ settings.writeEntry( APP_KEY + "WindowX", x() )
+ settings.writeEntry( APP_KEY + "WindowY", y() )
+ settings.writeEntry( APP_KEY + "ChartType", @chartType )
+ settings.writeEntry( APP_KEY + "AddValues", @addValues )
+ settings.writeEntry( APP_KEY + "Decimals", @decimalPlaces )
+ settings.writeEntry( APP_KEY + "Font", @font.toString() )
+ for i in 0...@recentFiles.length
+ settings.writeEntry( APP_KEY + "File" + ( i + 1 ).to_s,
+ @recentFiles[i] )
+ end
+ end
+
+
+ def optionsSetData()
+ setDataForm = SetDataForm.new( @elements, @decimalPlaces, self )
+ if setDataForm.exec()
+ @changed = true
+ drawElements()
+ end
+ end
+
+
+ def setChartType( chartType )
+ @chartType = chartType;
+ case @chartType
+ when PIE
+ @optionsPieChartAction.setOn( true )
+ when VERTICAL_BAR:
+ @optionsVerticalBarChartAction.setOn( true )
+ when HORIZONTAL_BAR:
+ @optionsHorizontalBarChartAction.setOn( true )
+ end
+ end
+
+
+ def updateChartType( action )
+ if action == @optionsPieChartAction
+ @chartType = PIE
+ elsif action == @optionsHorizontalBarChartAction
+ @chartType = HORIZONTAL_BAR
+ elsif action == @optionsVerticalBarChartAction
+ @chartType = VERTICAL_BAR
+ end
+
+ drawElements()
+ end
+
+
+ def optionsSetFont()
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont( ok, @font, self )
+ if !ok.nil?
+ @font = font
+ drawElements()
+ end
+ end
+
+
+ def optionsSetOptions()
+ optionsForm = OptionsForm.new( self )
+ optionsForm.chartTypeComboBox.setCurrentItem( @chartType )
+ optionsForm.font = @font
+ case @addValues
+ when NO
+ optionsForm.noRadioButton.setChecked( true )
+ when YES
+ optionsForm.yesRadioButton.setChecked( true )
+ when AS_PERCENTAGE
+ optionsForm.asPercentageRadioButton.setChecked( true )
+ end
+ optionsForm.decimalPlacesSpinBox.setValue( @decimalPlaces )
+ if optionsForm.exec()
+ setChartType( optionsForm.chartTypeComboBox.currentItem() )
+ @font = optionsForm.font
+ if optionsForm.noRadioButton.isChecked()
+ @addValues = NO
+ elsif optionsForm.yesRadioButton.isChecked()
+ @addValues = YES
+ elsif optionsForm.asPercentageRadioButton.isChecked()
+ @addValues = AS_PERCENTAGE
+ end
+ @decimalPlaces = optionsForm.decimalPlacesSpinBox.value()
+ drawElements()
+ end
+ end
+
+
+ def helpHelp()
+ statusBar().message( "Help is not implemented yet", 2000 )
+ end
+
+
+ def helpAbout()
+ Qt::MessageBox.about( self, "Chart -- About",
+ "<center><h1><font color=blue>Chart<font></h1></center>" +
+ "<p>Chart your data with <i>chart</i>.</p>" )
+ end
+
+
+ def helpAboutQt()
+ Qt::MessageBox.aboutQt( self, "Chart -- About Qt" )
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb
new file mode 100644
index 00000000..86c66f76
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb
@@ -0,0 +1,212 @@
+class ChartForm
+
+ def drawElements()
+ list = @canvas.allItems()
+ list.each do |it|
+ it.dispose
+ end
+
+ # 360 * 16 for pies Qt works with 16ths of degrees
+ scaleFactor = @chartType == PIE ? 5760 :
+ @chartType == VERTICAL_BAR ? @canvas.height() :
+ @canvas.width()
+ biggest = 0.0
+ count = 0
+ total = 0.0
+ scales = Array.new(MAX_ELEMENTS)
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ value = @elements[i].value()
+ count += 1
+ total += value
+ if value > biggest
+ biggest = value
+ end
+ scales[i] = @elements[i].value() * scaleFactor
+ end
+ end
+
+ if count > 0
+ # 2nd loop because of total and biggest
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ if @chartType == PIE
+ scales[i] = (@elements[i].value() * scaleFactor) / total
+ else
+ scales[i] = (@elements[i].value() * scaleFactor) / biggest
+ end
+ end
+ end
+
+ case @chartType
+ when PIE
+ drawPieChart( scales, total, count )
+ when VERTICAL_BAR:
+ drawVerticalBarChart( scales, total, count )
+ when HORIZONTAL_BAR:
+ drawHorizontalBarChart( scales, total, count )
+ end
+ end
+
+ @canvas.update()
+ end
+
+
+ def drawPieChart( scales, total, i )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ size = width > height ? height : width
+ x = width / 2
+ y = height / 2
+ angle = 0
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ arc = Qt::CanvasEllipse.new( size, size, angle, extent, @canvas )
+ arc.setX( x )
+ arc.setY( y )
+ arc.setZ( 0 )
+ arc.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ arc.show()
+ angle += extent
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ proX = @elements[i].proX( PIE ).to_f
+ proY = @elements[i].proY( PIE ).to_f
+ if proX < 0 || proY < 0
+ # Find the centre of the pie segment
+ rect = arc.boundingRect()
+ proX = ( rect.width() / 2 ) + rect.x()
+ proY = ( rect.height() / 2 ) + rect.y()
+ # Centre text over the centre of the pie segment
+ rect = text.boundingRect()
+ proX -= ( rect.width() / 2 )
+ proY -= ( rect.height() / 2 )
+ # Make proportional
+ proX /= width
+ proY /= height
+ end
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( PIE, proX )
+ @elements[i].setProY( PIE, proY )
+ end
+ end
+ end
+ end
+
+
+ def drawVerticalBarChart(scales, total, count )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ prowidth = width / count
+ x = 0
+ pen = Qt::Pen.new
+ pen.style = NoPen
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ y = height - extent
+ rect = Qt::CanvasRectangle.new(x, y, prowidth, extent, @canvas )
+ rect.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ rect.setPen( pen )
+ rect.setZ( 0 )
+ rect.show()
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ proX = @elements[i].proX( VERTICAL_BAR ).to_f
+ proY = @elements[i].proY( VERTICAL_BAR ).to_f
+ if proX < 0 || proY < 0
+ proX = x / width
+ proY = y / height
+ end
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( VERTICAL_BAR, proX )
+ @elements[i].setProY( VERTICAL_BAR, proY )
+ end
+ x += prowidth
+ end
+ end
+ end
+
+
+ def drawHorizontalBarChart(scales, total, count )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ proheight = height / count
+ y = 0
+ pen = Qt::Pen.new
+ pen.style = NoPen
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ rect = Qt::CanvasRectangle.new(0, y, extent, proheight, @canvas )
+ rect.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ rect.setPen( pen )
+ rect.setZ( 0 )
+ rect.show()
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ proX = @elements[i].proX( HORIZONTAL_BAR ).to_f
+ proY = @elements[i].proY( HORIZONTAL_BAR ).to_f
+ if proX < 0 || proY < 0
+ proX = 0
+ proY = y / height
+ end
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( HORIZONTAL_BAR, proX )
+ @elements[i].setProY( HORIZONTAL_BAR, proY )
+ end
+ y += proheight
+ end
+ end
+ end
+
+
+ def valueLabel(label, value, total )
+ if @addValues == NO
+ return label
+ end
+
+ newLabel = label
+ if !label.empty?
+ if @chartType == VERTICAL_BAR
+ newLabel += "\n"
+ else
+ newLabel += ' '
+ end
+ end
+ if @addValues == YES
+ newLabel += "%.#{@decimalPlaces}f" % value
+ elsif @addValues == AS_PERCENTAGE
+ newLabel += "%.#{@decimalPlaces}f%s" % [(value / total) * 100, '%']
+ end
+ return newLabel
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb
new file mode 100644
index 00000000..648aba62
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb
@@ -0,0 +1,102 @@
+class ChartForm
+
+ def load( filename )
+ file = Qt::File.new( filename )
+ if !file.open( Qt::IO_ReadOnly )
+ statusBar().message( "Failed to load \'%s\'" % filename, 2000 )
+ return
+ end
+
+ init() # Make sure we have colours
+ @filename = filename
+ ts = Qt::TextStream.new( file )
+ errors = 0
+ i = 0
+ while !ts.eof()
+ element = Element.new
+ ts >> element
+ if element.isValid()
+ @elements[i] = element
+ i += 1
+ else
+ errors += 1
+ end
+ if i == MAX_ELEMENTS
+ statusBar().message("Read maximum number of elements (%d) discarding others" % i, 2000 )
+ break
+ end
+ end
+
+ file.close()
+
+ bad = ""
+ if errors > 0
+ bad = " skipped %d bad record" % errors
+ if errors > 1
+ bad += "s"
+ end
+ end
+ statusBar().message( "Read %d values from \'%s\'" % [i, filename], 3000 )
+
+ setCaption( "Chart -- %s" % filename )
+ updateRecentFiles( filename )
+
+ drawElements()
+ @changed = false
+ end
+
+
+ def fileSave()
+ if @filename.nil?
+ fileSaveAs()
+ return
+ end
+
+ file = Qt::File.new( @filename )
+ if !file.open( Qt::IO_WriteOnly )
+ statusBar().message( "Failed to save \'%s\'" % @filename, 2000 )
+ return
+ end
+ ts = Qt::TextStream.new( file )
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ ts << @elements[i]
+ end
+ end
+
+ file.close()
+
+ setCaption( "Chart -- %s" % @filename )
+ statusBar().message( "Saved \'%s\'" % @filename, 2000 )
+ @changed = false
+ end
+
+
+ def fileSaveAsPixmap()
+ filename = Qt::FileDialog.getSaveFileName(nil, "Images (*.png *.xpm *.jpg)",
+ self, "file save as bitmap",
+ "Chart -- File Save As Bitmap" )
+ if Qt::Pixmap.grabWidget( @canvasView ).save( filename,
+ filename.sub(/.*\.([^.]*)$/, '\1').upcase() )
+ statusBar().message( "Wrote \'%s\'" % filename, 2000 )
+ else
+ statusBar().message( "Failed to write \'%s\'" % filename, 2000 )
+ end
+ end
+
+ def filePrint()
+ if !@printer
+ @printer = Qt::Printer.new
+ end
+ if @printer.setup()
+ painter = Qt::Painter.new( @printer )
+ @canvas.drawArea( Qt::Rect.new( 0, 0, @canvas.width(), @canvas.height() ),
+ painter, false )
+ if !@printer.outputFileName().empty?
+ statusBar().message( "Printed \'%s\'" % @printer.outputFileName(), 2000 )
+ end
+ end
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/element.rb b/qtruby/rubylib/examples/qt-examples/chart/element.rb
new file mode 100644
index 00000000..ba135632
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/element.rb
@@ -0,0 +1,161 @@
+class Element
+
+ FIELD_SEP = ':'
+ PROPOINT_SEP = ';'
+ XY_SEP = ','
+
+ EPSILON = 0.0000001
+
+ INVALID = -1
+ NO_PROPORTION = -1
+ MAX_PROPOINTS = 3 # One proportional point per chart type
+
+ attr_accessor :value, :valueColor, :valuePattern, :label, :labelColor
+
+ def initialize( value = INVALID, valueColor = Qt::gray,
+ valuePattern = Qt::SolidPattern,
+ label = nil,
+ labelColor = Qt::black )
+ init( value, valueColor, valuePattern, label, labelColor )
+ @propoints = []
+ for i in 0...MAX_PROPOINTS * 2
+ @propoints[i] = NO_PROPORTION
+ end
+ end
+
+ def isValid() return @value > EPSILON end
+
+
+ def init( value, valueColor, valuePattern,
+ label, labelColor )
+ @value = value
+ @valueColor = valueColor
+ if Qt::SolidPattern >= valuePattern || Qt::DiagCrossPattern <= valuePattern
+ valuePattern = Qt::SolidPattern
+ end
+ @valuePattern = valuePattern
+ @label = label
+ @labelColor = labelColor
+ end
+
+ def set( value = INVALID, valueColor = Qt::gray,
+ valuePattern = Qt::SolidPattern,
+ label = nil,
+ labelColor = Qt::black )
+ init( value, valueColor, valuePattern, label, labelColor )
+ end
+
+ def setValuePattern( valuePattern )
+ if valuePattern < Qt::SolidPattern.to_i || valuePattern > Qt::DiagCrossPattern.to_i
+ valuePattern = Qt::SolidPattern
+ end
+ @valuePattern = valuePattern
+ end
+
+
+ def proX( index )
+ return @propoints[2 * index]
+ end
+
+
+ def proY( index )
+ return @propoints[(2 * index) + 1]
+ end
+
+
+ def setProX( index, value )
+ @propoints[2 * index] = value
+ end
+
+
+ def setProY( index, value )
+ @propoints[(2 * index) + 1] = value
+ end
+
+end
+
+class Qt::TextStream
+
+ alias op_write <<
+
+ def <<( item )
+ if !item.kind_of? Element
+ return op_write(item)
+ end
+ element = item
+ self << element.value() << Element::FIELD_SEP <<
+ element.valueColor().name() << Element::FIELD_SEP <<
+ element.valuePattern().to_i << Element::FIELD_SEP <<
+ element.labelColor().name() << Element::FIELD_SEP
+
+ for i in 0...Element::MAX_PROPOINTS
+ self << element.proX( i ) << Element::XY_SEP << element.proY( i )
+ self << ( i == Element::MAX_PROPOINTS - 1 ? Element::FIELD_SEP : Element::PROPOINT_SEP )
+ end
+
+ self << element.label() << "\n"
+
+ return self
+ end
+
+ alias op_read >>
+
+ def >>( item )
+ if !item.kind_of? Element
+ return op_read(item)
+ end
+
+ element = item
+ data = readLine()
+ element.value = Element::INVALID
+
+ errors = 0
+
+ fields = data.split( Element::FIELD_SEP )
+ if fields.length() >= 4
+ value = fields[0].to_f
+ if value.nil?
+ errors += 1
+ end
+ valueColor = Qt::Color.new( fields[1] )
+ if !valueColor.isValid()
+ errors += 1
+ end
+ valuePattern = fields[2].to_i
+ if valuePattern.nil?
+ errors += 1
+ end
+ labelColor = Qt::Color.new( fields[3] )
+ if !labelColor.isValid()
+ errors += 1
+ end
+ propoints = fields[4].split( Element::PROPOINT_SEP )
+ label = data.split(Element::FIELD_SEP)[5]
+ if errors == 0
+ element.set( value, valueColor, valuePattern, label, labelColor )
+ i = 0
+ propoints.each do |point|
+ errors = 0
+ xy = point.split( Element::XY_SEP )
+ x = xy[0].to_f
+ if x.nil? || x <= 0.0 || x >= 1.0
+ errors += 1
+ end
+ y = xy[1].to_f
+ if y.nil? || y <= 0.0 || y >= 1.0
+ errors += 1
+ end
+ if errors > 0
+ x = y = Element::NO_PROPORTION
+ end
+ element.setProX( i, x )
+ element.setProY( i, y )
+ i += 1
+ end
+ end
+ end
+
+ return self
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk b/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk
new file mode 100644
index 00000000..d9087b48
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk
@@ -0,0 +1,256 @@
+##Sketch 1 2
+document()
+layout('A4',0)
+layer('Layer 1',1,1,0,0,(0,0,0))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(188.034,0,0,-149.201,526.688,-521.707)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,341.407,-572.49)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,768.68,-572.934)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(31.6796,0,0,31.6796,635.564,-722.4)
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(188.034,0,0,-149.201,518.884,-513.603)
+fp((1,1,1))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(158.398,0,0,-106.28,533.702,-545.185)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('ChartForm',(575.182,-535.064))
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,335.96,-566.743)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('OptionsForm',(354.009,-589.226))
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,763.221,-566.743)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('SetDataForm',(781.675,-587.279))
+fp((1,0,1))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(31.6796,0,0,31.6796,631.296,-719.01)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-BoldOblique')
+Fs(18)
+txt('chart',(613.251,-723.609))
+G()
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('CanvasView',(569.827,-575.941))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('depicting a',(573.94,-595.357))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('QCanvas',(580.906,-614.774))
+G_()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(662.975,-716.966,0)
+bc(669.107,-712.686,671.463,-709.765,672.485,-707.625,2)
+bc(673.507,-705.485,677.438,-697.225,677.438,-696.155,2)
+bc(677.438,-695.085,679.326,-682.725,679.326,-682.725,2)
+bc(679.326,-682.725,679.326,-670.955,679.326,-670.955,2)
+bc(679.326,-670.955,679.326,-665.605,679.326,-664.535,2)
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(710.729,-618.861,0)
+bs(759.036,-618.861,0)
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(515.603,-617.742,0)
+bs(467.885,-617.742,0)
+G()
+fp((0,0.392,0))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(29.7517,0,0,-7.65884,468.929,-768.389)
+fp((0,0.392,0))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(58.9143,0,0,-44.1857,439.032,-724.349)
+fp((0,0.392,0))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(29.7517,0,0,-7.65884,468.929,-722.581)
+G_()
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(499.125,-739.077,0)
+bc(507.548,-735.049,508.671,-732.747,512.04,-728.144,2)
+bc(515.409,-723.54,519.901,-717.21,520.463,-716.059,2)
+bc(521.024,-714.909,531.132,-689.589,531.132,-689.589,2)
+bc(531.132,-689.589,533.378,-679.231,533.378,-679.231,2)
+bc(533.378,-679.231,535.062,-671.175,535.062,-671.175,2)
+bc(535.062,-671.175,535.062,-664.845,535.062,-664.845,2)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('disk',(453.761,-753.806))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('run',(681.17,-700.783))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('save',(524.007,-725.891))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('load',(494.295,-706.489))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,525.422,-405.581)
+fp((0.596,0.984,0.596))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,519.327,-401.081)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getOpenFileName()',(526.396,-420.297))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,704.655,-405.581)
+fp((0.596,0.984,0.596))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,698.561,-401.081)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getSaveFileName()',(706.863,-420.39))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,375.286,-429.722)
+fp((0.529,0.808,0.98))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,371.024,-425.223)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getFont()',(391.333,-444.571))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,935.176,-580.856)
+fp((1,0.753,0.796))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,930.915,-576.357)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getColor()',(948.361,-598.303))
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(591.836,-511.466,0)
+bs(591.836,-471.702,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(674.96,-513.083,0)
+bs(749.29,-470.169,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(538.877,-513.083,0)
+bs(472.859,-474.968,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(410.746,-562.437,0)
+bs(410.746,-494.504,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(895.423,-617.315,0)
+bs(928.721,-617.315,0)
+guidelayer('Guide Lines',1,0,0,1,(0,0,1))
+grid((0,0,20,20),0,(0,0,1),'Grid')
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm
new file mode 100644
index 00000000..8537176c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static const char *file_new[] = {
+"20 20 12 1",
+" c white",
+"! c None",
+"# c #000",
+"$ c #2e2e2e2e2e2e",
+"% c #ffffffffffff",
+"& c #5c5c5c5c5c5c",
+"( c #878787878787",
+") c #c2c2c2c2c2c2",
+"* c black",
+"+ c #00C900",
+", c #ffff00",
+"- c red",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!##########$!!!!!!!",
+"!!#%%%%%%%%#&$!!!!!!",
+"!!#%%%%%%%%#(&$!!!!!",
+"!!#%%%%%%%%#)(&$!!!!",
+"!!#%%%%%%%%#%)(&$!!!",
+"!!#%%%%*****#####!!!",
+"!!#%%%*+++++*%%%#!!!",
+"!!#%%*,++++++*%%#!!!",
+"!!#%*,,,++++++*%#!!!",
+"!!#%*,,,,+++++*%#!!!",
+"!!#%*,,,,-++++*%#!!!",
+"!!#%*,,,---+++*%#!!!",
+"!!#%*,,-----++*%#!!!",
+"!!#%%*-------*%%#!!!",
+"!!#%%%*-----*%%%#!!!",
+"!!#%%%%*****%%%%#!!!",
+"!!#%%%%%%%%%%%%%#!!!",
+"!!###############!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm
new file mode 100644
index 00000000..7a7b681d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm
@@ -0,0 +1,33 @@
+/* XPM */
+static const char *file_open[] = {
+"20 20 9 1",
+" c white",
+"! c None",
+"# c #002EFF",
+"$ c #000",
+"% c #ffffffff0",
+"& c #ffffffffffff",
+"( c #00C900",
+") c #ffff00",
+"* c #A500FF",
+"!!!!!!!!!!####!!!!#!",
+"!!!!!!!!!#!!!!##!##!",
+"!!!!!!!!!!!!!!!!###!",
+"!!!!!!!!!!!!!!!####!",
+"!!!!!!!!!!!!!!#####!",
+"!$$$$!!!!!!!!!!!!!!!",
+"$%&%&$$$$$$$$!!!!!!!",
+"$&%&%&%&%&%&$!!!!!!!",
+"$%&&&$$$$$&&$!!!!!!!",
+"$&&&$((((($&$!!!!!!!",
+"$%&$)(($$$$$$$$$$$$$",
+"$&$)))$***********$$",
+"$%$))$***********$$!",
+"$&$)$***********$$!!",
+"$%$$***********$$!!!",
+"$&$***********$$!!!!",
+"$$***********$$!!!!!",
+"$$***********$!!!!!!",
+"$$$$$$$$$$$$$!!!!!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm
new file mode 100644
index 00000000..915f65ba
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm
@@ -0,0 +1,115 @@
+/* XPM */
+static const char *file_print[] = {
+/* columns rows colors chars-per-pixel */
+"20 20 89 1",
+" c Gray0",
+". c #101008081010",
+"X c #101010101010",
+"o c #101010101818",
+"O c #181810101818",
+"+ c #181818181818",
+"@ c #181818182121",
+"# c #212118182121",
+"$ c Gray13",
+"% c #212121212929",
+"& c #292921212929",
+"* c Gray16",
+"= c #292929293131",
+"- c #313129293131",
+"; c #313131313131",
+": c #313131313939",
+"> c #393931313939",
+", c #393939393939",
+"< c #393939394242",
+"1 c #424239394242",
+"2 c Gray26",
+"3 c #4a4a4a4a5252",
+"4 c #5a5a52525a5a",
+"5 c #5a5a5a5a6363",
+"6 c #6b6b63636b6b",
+"7 c Gray42",
+"8 c #6b6b6b6b7373",
+"9 c #73736b6b7373",
+"0 c #7b7b73737b7b",
+"q c #7b7b73738484",
+"w c #0808ffff0808",
+"e c #2929ffff2929",
+"r c #3131ffff3131",
+"t c #5a5acece5a5a",
+"y c #6b6bffff6363",
+"u c #7b7bffff7b7b",
+"i c #84847b7b8484",
+"p c #84847b7b8c8c",
+"a c #8c8c7b7b9494",
+"s c #848484848c8c",
+"d c #8c8c84848c8c",
+"f c Gray55",
+"g c #8c8c84849494",
+"h c #8c8c8c8c9494",
+"j c #94948c8c9494",
+"k c #94948c8c9c9c",
+"l c Gray58",
+"z c #949494949c9c",
+"x c #9c9c94949c9c",
+"c c Gray61",
+"v c #9c9c9494a5a5",
+"b c #9c9c9c9ca5a5",
+"n c #a5a59c9ca5a5",
+"m c #a5a59c9cadad",
+"M c #adad9c9cadad",
+"N c #a5a5a5a5a5a5",
+"B c #a5a5a5a5adad",
+"V c #adada5a5adad",
+"C c Gray68",
+"Z c #adadadadb5b5",
+"A c #b5b5adadb5b5",
+"S c Gray71",
+"D c Gray74",
+"F c #9494c6c69494",
+"G c #9c9ccecea5a5",
+"H c #bdbdd6d6bdbd",
+"J c #c0c0c0c0c0c0",
+"K c #c6c6c6c6c6c6",
+"L c #cecec6c6cece",
+"P c #cececececece",
+"I c #cecececed6d6",
+"U c #d6d6ceced6d6",
+"Y c #d6d6cecedede",
+"T c Gray84",
+"R c #d6d6d6d6dede",
+"E c #deded6d6dede",
+"W c Gray87",
+"Q c #deded6d6e7e7",
+"! c #dedededee7e7",
+"~ c #d6d6ffffd6d6",
+"^ c #e7e7dedee7e7",
+"/ c #e7e7e7e7e7e7",
+"( c #e7e7e7e7efef",
+") c #efefe7e7efef",
+"_ c #efefefefefef",
+"` c #e7e7ffffe7e7",
+"' c Gray97",
+"] c Gray100",
+"[ c None",
+/* pixels */
+"[[[[[[SDPPKKDDCD[[[[",
+"[[[[[[D_///___WD[[[[",
+"[[[[[[DKKPKKKKDK[[[[",
+"[[[[[[SDDSDDSSCD[[[[",
+"[[[[[KCKDKDDDKS[[[[[",
+"[[[[[KDDDDDDDDS[[[[[",
+"[[[[[CP/WWWWTWNNZ[[[",
+"[[[Dc9STPTPTWWj427S[",
+"[[Dziq00000pag8<%@2N",
+"[DcE(!ERRUYGtFn2##O<",
+"Db)]]]]]]]~ewePa;@X#",
+"V']]]]]]]]`yru]Q0@ #",
+"BRILITRRWE!RHUILhO @",
+"jAZVBmBnmmnmMvzh6o #",
+"jZZmBnnnbbbbvxxg6o +",
+"lmmnbnbbbvxxxvjs6O 3",
+"jBnnvcvxvxvxzjhd8o+C",
+"lsdgfgdhghjhjkhg6+l[",
+"S9%@$%&&&-::>>:-:l[[",
+"[[C511,:;**%++.2c[[["
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm
new file mode 100644
index 00000000..61638992
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm
@@ -0,0 +1,33 @@
+/* XPM */
+static const char *file_save[] = {
+"20 20 9 1",
+" c white",
+"! c #000",
+"# c #002EFF",
+"$ c #999999999999",
+"% c None",
+"& c #00C900",
+"( c #ffff00",
+") c red1",
+"* c black",
+"!!!!!!!!!!!!!!!!!!!!",
+"!##!$$$!!!!!!$$$!%%!",
+"!##!$$!&&&&&&!$$!%%!",
+"!##!$!(&&&&&&&!$!!!!",
+"!##!!(((&&&&&&&!!##!",
+"!##!!((((&&&&&&!!##!",
+"!##!!((((()&&&&!!##!",
+"!##!!((())))&&&!!##!",
+"!##!!(())))))&&!!##!",
+"!##!$!))))))))!$!##!",
+"!###!$!))))))!$*###!",
+"!####***!!!!!***###!",
+"!##################!",
+"!###!!!!!!!!!!!!!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"%!!!!!!!!!!!!!!!!!!%"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm
new file mode 100644
index 00000000..7dd75fcf
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm
@@ -0,0 +1,34 @@
+/* XPM */
+static const char *file_saveaspostscript[] = {
+"20 20 10 1",
+" c white",
+"! c #000",
+"# c #002EFF",
+"$ c #999999999999",
+"% c None",
+"& c #00C900",
+"( c #ffff00",
+") c red1",
+"* c black",
+"+ c grey100",
+"!!!!!!!!!!!!!!!!!!!!",
+"!##!$$$!!!!!!$$$!%%!",
+"!##!$$!&&&&&&!$$!%%!",
+"!##!$!(&&&&&&&!$!!!!",
+"!##!!(((&&&&&&&!!##!",
+"!##!!((((&&&&&&!!##!",
+"!##!!((((()&&&&!!##!",
+"!##!!((())))&&&!!##!",
+"!##!!(())))))&&!!##!",
+"!##!$!))))))))!$!##!",
+"!###!$!))))))!$*###!",
+"!####***!!!!!***###!",
+"!##################!",
+"!###!!!!!!!!!!!!!##!",
+"!###!+++!+++!$$$!##!",
+"!###!+!+!+!!!$$$!##!",
+"!###!+++!+++!$$$!##!",
+"!###!+!!!!!+!$$$!##!",
+"!###!+!!!+++!$$$!##!",
+"%!!!!!!!!!!!!!!!!!!%"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm
new file mode 100644
index 00000000..afb06ffa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static const char *options_horizontalbarchart[] = {
+"20 20 7 1",
+"( c #A500FF",
+" c white",
+"! c red1",
+"# c None",
+"$ c #E9FF00",
+"% c #00C900",
+"& c #002EFF",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"(((((((((((#########",
+"(((((((((((#########",
+"(((((((((((#########",
+"(((((((((((#########"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm
new file mode 100644
index 00000000..221c78de
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm
@@ -0,0 +1,30 @@
+/* XPM */
+static const char *options_piechart[] = {
+"20 20 6 1",
+" c white",
+"! c None",
+"# c black",
+"$ c #00C900",
+"% c #E9FF00",
+"& c red1",
+"!!!!!!#######!!!!!!!",
+"!!!!##$$$$$$$##!!!!!",
+"!!!#%$$$$$$$$$$#!!!!",
+"!!#%%%$$$$$$$$$$#!!!",
+"!#%%%%%$$$$$$$$$$#!!",
+"!#%%%%%$$$$$$$$$$#!!",
+"#%%%%%%%$$$$$$$$$$#!",
+"#%%%%%%%%$$$$$$$$$#!",
+"#%%%%%%%%$$$$$$$$$#!",
+"#%%%%%%%%%$$$$$$$$#!",
+"#%%%%%%%%&&$$$$$$$#!",
+"#%%%%%%%&&&&$$$$$$#!",
+"#%%%%%%&&&&&&&$$$$#!",
+"#%%%%%&&&&&&&&&$$$#!",
+"!#%%%&&&&&&&&&&&&#!!",
+"!#%%&&&&&&&&&&&&&#!!",
+"!!#&&&&&&&&&&&&&#!!!",
+"!!!#&&&&&&&&&&&#!!!!",
+"!!!!##&&&&&&&##!!!!!",
+"!!!!!!#######!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm
new file mode 100644
index 00000000..4ff70a54
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm
@@ -0,0 +1,34 @@
+/* XPM */
+static const char *options_setdata[] = {
+"20 20 10 1",
+" c white",
+"! c None",
+"# c grey40",
+"$ c #002EFF",
+"% c black",
+"& c red1",
+"( c #00C900",
+") c #A500FF",
+"* c #E9FF00",
+"+ c cyan1",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!$$!!#####!%%!",
+"!#####!$$!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!&&!!#####!%%!",
+"!#####!&&!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!((!!#####!%%!",
+"!#####!((!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!))!!#####!%%!",
+"!#####!))!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!**!!#####!%%!",
+"!#####!**!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!++!!#####!%%!",
+"!#####!++!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm
new file mode 100644
index 00000000..ab552248
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static const char *options_setfont[] = {
+"20 20 3 1",
+" c white",
+"! c None",
+"# c #002EFF",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!#####!!!",
+"!!!!!!!!!!!#######!!",
+"!!!!!!!!!!!##!!!!##!",
+"!!!!!!!!!!##!!!!###!",
+"!!!!!!!!!!##!!!!###!",
+"!!!!!!!!!###!!!!!!!!",
+"!!!!!!!!!##!!!!!!!!!",
+"!!!!!#############!!",
+"!!!!###!!########!!!",
+"!!!##!!!!##!!!!!!!!!",
+"!!!##!!!!#!!!!!!!!!!",
+"!!!!!!!!##!!!!!!!!!!",
+"!!!!!!!!##!!!!!!!!!!",
+"!!!!!!!###!!!!!!!!!!",
+"!!!!!!!##!!!!!!!!!!!",
+"!!!!!!##!!!!!!!!!!!!",
+"!#!!!###!!!!!!!!!!!!",
+"!######!!!!!!!!!!!!!",
+"!!####!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm
new file mode 100644
index 00000000..029cf47d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static const char *options_setoptions[] = {
+"20 20 8 1",
+"( c #A500FF",
+" c white",
+") c grey30",
+"! c None",
+"# c #000",
+"$ c grey60",
+"% c grey100",
+"& c black",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#############$$$$$!",
+"!#%%%%%%%%%%%%&$$$$!",
+"!#%%%%%%%%%%%%%&$$$!",
+"!#%%%%%%%%%%%%%%&$$!",
+"!#%%%%%%%%%%%%%%%&$!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#(((((((%%%%%%%%%#!",
+"!#(((((((%%%%%%%%%#!",
+"!#%%((%%%%%)%))))%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%)))%)))%))%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!#%%))%)%))))%))%%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!##################!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm
new file mode 100644
index 00000000..e812f0f9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static const char *options_verticalbarchart[] = {
+"20 20 7 1",
+"( c #A500FF",
+" c white",
+"! c None",
+"# c #00C900",
+"$ c #E9FF00",
+"% c red1",
+"& c #002EFF",
+"!!!!!!!!####!!!!!!!!",
+"!!!!!!!!####!!!!!!!!",
+"!!!!!!!!####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&(((("
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm
new file mode 100644
index 00000000..26a70cbd
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static const char *pattern01[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 1 1",
+" c black",
+/* pixels */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm
new file mode 100644
index 00000000..cc5b7948
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern02[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm
new file mode 100644
index 00000000..d9fc57a9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern03[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm
new file mode 100644
index 00000000..85b9223b
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern04[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . ."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm
new file mode 100644
index 00000000..cc7beee9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern05[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm
new file mode 100644
index 00000000..ad8b0554
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern06[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm
new file mode 100644
index 00000000..d01c55f9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern07[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm
new file mode 100644
index 00000000..b0ce09fe
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern08[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm
new file mode 100644
index 00000000..7d34bc42
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern09[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm
new file mode 100644
index 00000000..c908016d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern10[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... ."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm
new file mode 100644
index 00000000..8feda9a4
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern11[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... .."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm
new file mode 100644
index 00000000..a57233f2
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern12[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... .....",
+". ....... ....... ....... ....... ......",
+" ....... ....... ....... ....... .......",
+"....... ....... ....... ....... ....... ",
+"...... ....... ....... ....... ....... .",
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... .....",
+". ....... ....... ....... ....... ......",
+" ....... ....... ....... ....... .......",
+"....... ....... ....... ....... ....... ",
+"...... ....... ....... ....... ....... .",
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... ....."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm
new file mode 100644
index 00000000..97f874fe
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern13[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ....",
+".... ....... ....... ....... ....... ...",
+"..... ....... ....... ....... ....... ..",
+"...... ....... ....... ....... ....... .",
+"....... ....... ....... ....... ....... ",
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ....",
+".... ....... ....... ....... ....... ...",
+"..... ....... ....... ....... ....... ..",
+"...... ....... ....... ....... ....... .",
+"....... ....... ....... ....... ....... ",
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ...."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm
new file mode 100644
index 00000000..e9e68845
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern14[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... .......",
+". ..... . ..... . ..... . ..... . ..... ",
+".. ... ... ... ... ... ... ... ... ... .",
+"... . ..... . ..... . ..... . ..... . ..",
+".... ....... ....... ....... ....... ...",
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... .......",
+". ..... . ..... . ..... . ..... . ..... ",
+".. ... ... ... ... ... ... ... ... ... .",
+"... . ..... . ..... . ..... . ..... . ..",
+".... ....... ....... ....... ....... ...",
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... ......."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/main.rb b/qtruby/rubylib/examples/qt-examples/chart/main.rb
new file mode 100644
index 00000000..db395a3e
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/main.rb
@@ -0,0 +1,26 @@
+require 'Qt'
+
+require 'canvasview.rb'
+require 'canvastext.rb'
+require 'element.rb'
+require 'chartform.rb'
+require 'chartform_canvas.rb'
+require 'chartform_files.rb'
+require 'optionsform.rb'
+require 'setdataform.rb'
+
+app = Qt::Application.new( ARGV )
+
+if app.ARGV.length > 0
+ filename = app.ARGV[0]
+ if filename.rindex( /.cht$/ ).nil?
+ filename = nil
+ end
+end
+
+cf = ChartForm.new( filename )
+app.mainWidget = cf
+cf.show
+
+app.exec
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb b/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb
new file mode 100644
index 00000000..6b2eeac4
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb
@@ -0,0 +1,127 @@
+class OptionsForm < Qt::Dialog
+ slots 'chooseFont()'
+
+ attr_reader :chartTypeComboBox,
+ :noRadioButton,
+ :yesRadioButton,
+ :asPercentageRadioButton,
+ :decimalPlacesSpinBox,
+ :font
+
+ def initialize( parent = nil, name = "options form",
+ modal = false, f = 0 )
+ super( parent, name, modal, f )
+ setCaption( "Chart -- Options" )
+ resize( 320, 290 )
+
+ @optionsFormLayout = Qt::VBoxLayout.new( self, 11, 6 )
+
+ @chartTypeLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @chartTypeTextLabel = Qt::Label.new( "&Chart Type", self )
+ @chartTypeLayout.addWidget( @chartTypeTextLabel )
+
+ @chartTypeComboBox = Qt::ComboBox.new( false, self )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_piechart.xpm" ), "Pie Chart" )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_verticalbarchart.xpm" ),
+ "Vertical Bar Chart" )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_horizontalbarchart.xpm" ),
+ "Horizontal Bar Chart" )
+ @chartTypeLayout.addWidget( @chartTypeComboBox )
+ @optionsFormLayout.addLayout( @chartTypeLayout )
+
+ @fontLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @fontPushButton = Qt::PushButton.new( "&Font...", self )
+ @fontLayout.addWidget( @fontPushButton )
+ @spacer = Qt::SpacerItem.new( 0, 0, Qt::SizePolicy::Expanding,
+ Qt::SizePolicy::Minimum )
+ @fontLayout.addItem( @spacer )
+
+ @fontTextLabel = Qt::Label.new( self ) # Must be set by caller via setFont()
+ @fontLayout.addWidget( @fontTextLabel )
+ @optionsFormLayout.addLayout( @fontLayout )
+
+ @addValuesFrame = Qt::Frame.new( self )
+ @addValuesFrame.setFrameShape( Qt::Frame::StyledPanel )
+ @addValuesFrame.setFrameShadow( Qt::Frame::Sunken )
+ @addValuesFrameLayout = Qt::VBoxLayout.new( @addValuesFrame, 11, 6 )
+
+ @addValuesButtonGroup = Qt::ButtonGroup.new( "Show Values", @addValuesFrame )
+ @addValuesButtonGroup.setColumnLayout(0, Qt::Vertical )
+ @addValuesButtonGroup.layout().setSpacing( 6 )
+ @addValuesButtonGroup.layout().setMargin( 11 )
+ @addValuesButtonGroupLayout = Qt::VBoxLayout.new(
+ @addValuesButtonGroup.layout() )
+ @addValuesButtonGroupLayout.setAlignment( Qt::AlignTop )
+
+ @noRadioButton = Qt::RadioButton.new( "&No", @addValuesButtonGroup )
+ @noRadioButton.setChecked( true )
+ @addValuesButtonGroupLayout.addWidget( @noRadioButton )
+
+ @yesRadioButton = Qt::RadioButton.new( "&Yes", @addValuesButtonGroup )
+ @addValuesButtonGroupLayout.addWidget( @yesRadioButton )
+
+ @asPercentageRadioButton = Qt::RadioButton.new( "As &Percentage",
+ @addValuesButtonGroup )
+ @addValuesButtonGroupLayout.addWidget( @asPercentageRadioButton )
+ @addValuesFrameLayout.addWidget( @addValuesButtonGroup )
+
+ @decimalPlacesLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @decimalPlacesTextLabel = Qt::Label.new( "&Decimal Places", @addValuesFrame )
+ @decimalPlacesLayout.addWidget( @decimalPlacesTextLabel )
+
+ @decimalPlacesSpinBox = Qt::SpinBox.new( @addValuesFrame )
+ @decimalPlacesSpinBox.setMinValue( 0 )
+ @decimalPlacesSpinBox.setMaxValue( 9 )
+ @decimalPlacesLayout.addWidget( @decimalPlacesSpinBox )
+
+ @addValuesFrameLayout.addLayout( @decimalPlacesLayout )
+
+ @optionsFormLayout.addWidget( @addValuesFrame )
+
+ @buttonsLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+ @spacer = Qt::SpacerItem.new( 0, 0,
+ Qt::SizePolicy::Expanding, Qt::SizePolicy::Minimum )
+ @buttonsLayout.addItem( @spacer )
+
+ @okPushButton = Qt::PushButton.new( "OK", self )
+ @okPushButton.setDefault( true )
+ @buttonsLayout.addWidget( @okPushButton )
+
+ @cancelPushButton = Qt::PushButton.new( "Cancel", self )
+ @buttonsLayout.addWidget( @cancelPushButton )
+ @optionsFormLayout.addLayout( @buttonsLayout )
+
+ connect( @fontPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'chooseFont()' ) )
+ connect( @okPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
+ connect( @cancelPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'reject()' ) )
+
+ @chartTypeTextLabel.setBuddy( @chartTypeComboBox )
+ @decimalPlacesTextLabel.setBuddy( @decimalPlacesSpinBox )
+ end
+
+
+ def chooseFont()
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont( ok, @font, self )
+ if !ok.nil?
+ setFont( font )
+ end
+ end
+
+
+ def font=( font )
+ label = font.family() + " " + font.pointSize().to_s + "pt"
+ if font.bold()
+ label += " Bold"
+ end
+ if font.italic()
+ label += " Italic"
+ end
+ @fontTextLabel.setText( label )
+ @font = font
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb b/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb
new file mode 100644
index 00000000..81a9403b
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb
@@ -0,0 +1,184 @@
+class SetDataForm < Qt::Dialog
+
+ slots 'setColor()',
+ 'setChosenColor( int, int )',
+ 'currentChanged( int, int )',
+ 'valueChanged( int, int )',
+ 'accept()'
+
+ MAX_PATTERNS = 14
+
+
+ def initialize( elements, decimalPlaces,
+ parent = nil, name = "set data form",
+ modal = true, f = 0 )
+ super( parent, name, modal, f )
+
+ @elements = elements
+ @decimalPlaces = decimalPlaces
+
+ setCaption( "Chart -- Set Data" )
+ resize( 540, 440 )
+
+ @tableButtonBox = Qt::VBoxLayout.new( self, 11, 6, "@table button box layout" )
+
+ @table = Qt::Table.new( self, "data @table" )
+ @table.setNumCols( 5 )
+ @table.setNumRows( ChartForm::MAX_ELEMENTS )
+ @table.setColumnReadOnly( 1, true )
+ @table.setColumnReadOnly( 2, true )
+ @table.setColumnReadOnly( 4, true )
+ @table.setColumnWidth( 0, 80 )
+ @table.setColumnWidth( 1, 60 ) # Columns 1 and 4 must be equal
+ @table.setColumnWidth( 2, 60 )
+ @table.setColumnWidth( 3, 200 )
+ @table.setColumnWidth( 4, 60 )
+ th = @table.horizontalHeader()
+ th.setLabel( 0, "Value" )
+ th.setLabel( 1, "Color" )
+ th.setLabel( 2, "Pattern" )
+ th.setLabel( 3, "Label" )
+ th.setLabel( 4, "Color" )
+ @tableButtonBox.addWidget( @table )
+
+ @buttonBox = Qt::HBoxLayout.new( nil, 0, 6, "button box layout" )
+
+ @colorPushButton = Qt::PushButton.new( self, "color button" )
+ @colorPushButton.setText( "&Color..." )
+ @colorPushButton .setEnabled( false )
+ @buttonBox.addWidget( @colorPushButton )
+
+ spacer = Qt::SpacerItem.new( 0, 0, Qt::SizePolicy::Expanding,
+ Qt::SizePolicy::Minimum )
+ @buttonBox.addItem( spacer )
+
+ okPushButton = Qt::PushButton.new( self, "ok button" )
+ okPushButton.setText( "OK" )
+ okPushButton.setDefault( true )
+ @buttonBox.addWidget( okPushButton )
+
+ cancelPushButton = Qt::PushButton.new( self, "cancel button" )
+ cancelPushButton.setText( "Cancel" )
+ cancelPushButton.setAccel( Qt::KeySequence.new(Key_Escape) )
+ @buttonBox.addWidget( cancelPushButton )
+
+ @tableButtonBox.addLayout( @buttonBox )
+
+ connect( @table, SIGNAL( 'clicked(int,int,int,const QPoint&)' ),
+ self, SLOT( 'setChosenColor(int,int)' ) )
+ connect( @table, SIGNAL( 'currentChanged(int,int)' ),
+ self, SLOT( 'currentChanged(int,int)' ) )
+ connect( @table, SIGNAL( 'valueChanged(int,int)' ),
+ self, SLOT( 'valueChanged(int,int)' ) )
+ connect( @colorPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'setColor()' ) )
+ connect( okPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
+ connect( cancelPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'reject()' ) )
+
+ patterns = Array.new(MAX_PATTERNS)
+ patterns[0] = Qt::Pixmap.new( "images/pattern01.xpm" )
+ patterns[1] = Qt::Pixmap.new( "images/pattern02.xpm" )
+ patterns[2] = Qt::Pixmap.new( "images/pattern03.xpm" )
+ patterns[3] = Qt::Pixmap.new( "images/pattern04.xpm" )
+ patterns[4] = Qt::Pixmap.new( "images/pattern05.xpm" )
+ patterns[5] = Qt::Pixmap.new( "images/pattern06.xpm" )
+ patterns[6] = Qt::Pixmap.new( "images/pattern07.xpm" )
+ patterns[7] = Qt::Pixmap.new( "images/pattern08.xpm" )
+ patterns[8] = Qt::Pixmap.new( "images/pattern09.xpm" )
+ patterns[9] = Qt::Pixmap.new( "images/pattern10.xpm" )
+ patterns[10] = Qt::Pixmap.new( "images/pattern11.xpm" )
+ patterns[11] = Qt::Pixmap.new( "images/pattern12.xpm" )
+ patterns[12] = Qt::Pixmap.new( "images/pattern13.xpm" )
+ patterns[13] = Qt::Pixmap.new( "images/pattern14.xpm" )
+
+ rect = @table.cellRect( 0, 1 )
+ pix = Qt::Pixmap.new( rect.width(), rect.height() )
+
+ for i in 0...ChartForm::MAX_ELEMENTS
+ element = @elements[i]
+
+ if element.isValid()
+ @table.setText(i, 0, "%.#{@decimalPlaces}f" % element.value() )
+ end
+
+ color = element.valueColor()
+ pix.fill( color )
+ @table.setPixmap( i, 1, pix )
+ @table.setText( i, 1, color.name() )
+
+ combobox = Qt::ComboBox.new
+ for j in 0...MAX_PATTERNS
+ combobox.insertItem( patterns[j] )
+ end
+ combobox.setCurrentItem( element.valuePattern() - 1 )
+ @table.setCellWidget( i, 2, combobox )
+
+ @table.setText( i, 3, element.label() )
+
+ color = element.labelColor()
+ pix.fill( color )
+ @table.setPixmap( i, 4, pix )
+ @table.setText( i, 4, color.name() )
+ end
+
+ end
+
+
+ def currentChanged( i, col )
+ @colorPushButton.setEnabled( col == 1 || col == 4 )
+ end
+
+
+ def valueChanged( row, col )
+ if col == 0
+ d = @table.text( row, col ).to_f
+ if d && d > EPSILON
+ @table.setText( row, col, "%.#{@decimalPlaces}f" % d )
+ elsif ! @table.text( row, col ).empty?
+ @table.setText( row, col, @table.text( row, col ) + "?" )
+ end
+ end
+ end
+
+
+ def setColor()
+ setChosenColor( @table.currentRow(), @table.currentColumn() )
+ @table.setFocus()
+ end
+
+
+ def setChosenColor( row, col )
+ if !( col == 1 || col == 4 )
+ return
+ end
+
+ color = Qt::ColorDialog.getColor(
+ Qt::Color.new( @table.text( row, col ) ),
+ self, "color dialog" )
+ if color.isValid()
+ pix = @table.pixmap( row, col )
+ pix.fill( color )
+ @table.setPixmap( row, col, pix )
+ @table.setText( row, col, color.name() )
+ end
+ end
+
+
+ def accept()
+ for i in 0...ChartForm::MAX_ELEMENTS
+ element = @elements[i]
+ d = @table.text( i, 0 ).to_f
+ if d
+ element.value = d
+ else
+ element.value = Element::INVALID
+ end
+ element.valueColor = Qt::Color.new( @table.text( i, 1 ) )
+ element.valuePattern = (@table.cellWidget( i, 2 )).currentItem() + 1
+ element.label = @table.text( i, 3 )
+ element.labelColor = Qt::Color.new( @table.text( i, 4 ) )
+ end
+
+ super
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb b/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb
new file mode 100644
index 00000000..8f67d9aa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb
@@ -0,0 +1,147 @@
+require 'Qt'
+
+class CheckLists < Qt::Widget
+ slots 'copy1to2()', 'copy2to3()'
+
+ # Constructor
+ #
+ # Create all child widgets of the CheckList Widget
+ def initialize
+ super()
+
+ lay = Qt::HBoxLayout.new(self)
+ lay.setMargin(5)
+
+ # create a widget which layouts its childs in a column
+ vbox1 = Qt::VBoxLayout.new(lay)
+ vbox1.setMargin(5)
+
+ # First child: a Label
+ vbox1.addWidget(Qt::Label.new('Check some items!', self))
+
+ # Second child: the ListView
+ @lv1 = Qt::ListView.new(self)
+ vbox1.addWidget(@lv1)
+ @lv1.addColumn('Items')
+ @lv1.setRootIsDecorated(true)
+
+ # create a list with 4 ListViewItems which will be parent items of other ListViewItems
+ parentList = Array.new
+
+
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 1'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 2'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 3'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 4'))
+
+ item = 0
+ num = 1
+ # go through the list of parent items...
+ parentList.each {|item|
+ item.setOpen(true)
+ # ...and create 5 checkable child ListViewItems for each parent item
+ for i in 1..5
+ str = sprintf('%s. Child of Parent %s', i, num)
+ Qt::CheckListItem.new(item, str, Qt::CheckListItem.CheckBox)
+ end
+ num = num + 1
+ }
+
+ # Create another widget for layouting
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # create a pushbutton
+ copy1 = Qt::PushButton.new(' -> ', self)
+ tmp.addWidget(copy1)
+ copy1.setMaximumWidth(copy1.sizeHint.width)
+ # connect the SIGNAL clicked() of the pushbutton with the SLOT copy1to2()
+ connect(copy1, SIGNAL('clicked()'), self, SLOT('copy1to2()'))
+
+ # another widget for layouting
+ vbox2 = Qt::VBoxLayout.new(lay)
+ vbox2.setMargin(5)
+
+ # and another label
+ vbox2.addWidget(Qt::Label.new('Check one item!', self))
+
+ # create the second listview
+ @lv2 = Qt::ListView.new(self)
+ vbox2.addWidget(@lv2)
+ @lv2.addColumn('Items')
+ @lv2.setRootIsDecorated(true)
+
+ # another widget needed for layouting only
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # create another pushbutton...
+ copy2 = Qt::PushButton.new(' -> ', self)
+ lay.addWidget( copy2 )
+ copy2.setMaximumWidth(copy2.sizeHint.width)
+ # ...and connect its clicked() SIGNAL to the copy2to3() SLOT
+ connect(copy2, SIGNAL('clicked()'), self, SLOT('copy2to3()'))
+
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # and create a label which will be at the right of the window
+ @label = Qt::Label.new('No Item yet...', self)
+ tmp.addWidget(@label)
+ end
+
+ # SLOT copy1to2()
+ #
+ # Copies all checked ListViewItems from the first ListView to
+ # the second one, and inserts them as Radio-ListViewItem.
+ def copy1to2
+ @lv2.clear
+ it = Qt::ListViewItemIterator.new(@lv1)
+ # Insert first a controller Item into the second ListView. Always if Radio-ListViewItems
+ # are inserted into a Listview, the parent item of these MUST be a controller Item!
+ item = Qt::CheckListItem.new(@lv2, 'Controller', Qt::CheckListItem::Controller );
+ item.setOpen(true);
+
+ # iterate through the first ListView...
+ while (it.current)
+ # ...check state of childs, and...
+ if ( it.current.parent )
+ # ...if the item is checked...
+ if (it.current.isOn)
+ # ...insert a Radio-ListViewItem with the same text into the second ListView
+ Qt::CheckListItem.new(item, it.current.text(0), Qt::CheckListItem::RadioButton)
+ end
+ end
+ it += 1
+ end
+
+ if (item.firstChild)
+ item.firstChild.setOn(true)
+ end
+ end
+
+
+ # SLOT copy2to3()
+ #
+ # Copies the checked item of the second ListView into the
+ # Label at the right.
+ def copy2to3
+ # create an iterator which operates on the second ListView
+ it = Qt::ListViewItemIterator.new(@lv2)
+
+ @label.setText('No Item checked')
+
+ # iterate through the second ListView...
+ while (it.current)
+ # ...check state of childs, and...
+ if ( it.current.parent)
+ # ...if the item is checked...
+ if (it.current.isOn)
+ # ...set the text of the item to the label
+ @label.setText(it.current.text(0))
+ end
+ end
+ it += 1
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/checklists/main.rb b/qtruby/rubylib/examples/qt-examples/checklists/main.rb
new file mode 100755
index 00000000..0c0e755c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/checklists/main.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+
+require 'checklists'
+
+a = Qt::Application.new(ARGV)
+
+checklists = CheckLists.new
+checklists.resize(650, 350)
+checklists.setCaption('QtRuby Example - CheckLists')
+a.setMainWidget(checklists)
+checklists.show
+
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb b/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb
new file mode 100644
index 00000000..6ac52c4c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb
@@ -0,0 +1,67 @@
+require 'Qt'
+
+class DigitalClock < Qt::LCDNumber
+
+ slots 'stopDate()', 'showTime()'
+
+ # Constructs a DigitalClock widget
+ def initialize
+ super
+
+ @showingColon = false
+ setFrameStyle(Qt::Frame.Panel | Qt::Frame.Raised)
+ setLineWidth(2) # set frame line width
+ showTime # display the current time
+ @normalTimer = startTimer(500) # 1/2 second timer events
+ @showDateTimer = -1 # not showingdate
+ end
+
+ # Handles timer events for the digital clock widget.
+ # There are two different timers; one timer for updating the clock
+ # and another one for switching back from date mode to time mode.
+ def timerEvent (e)
+ if (e.timerId == @showDateTimer) # stop showing date
+ stopDate
+ else # normal timer
+ if (@showDateTimer == -1) # not showing date
+ showTime()
+ end
+ end
+ end
+
+ # Enters date mode when the left mouse button is pressed.
+ def mousePressEvent (e)
+ if (e.button == Qt::MouseEvent.LeftButton) # left button pressed
+ showDate
+ end
+ end
+
+ def stopDate
+ killTimer(@showDateTimer)
+ @showDateTimer = -1
+ showTime
+ end
+
+ def showTime
+ @showingColon = !@showingColon # toggle/blink colon
+ s = Qt::Time.currentTime.toString[0..4]
+ if (!@showingColon)
+ s[2] = ' '
+ end
+ if (s[0] == '0')
+ s[0] = ' '
+ end
+ display(s) # set LCD number/text
+ end
+
+ def showDate
+ if (@showDateTimer != -1) # already showing date
+ return
+ end
+ date = Qt::Date.currentDate
+ s = sprintf('%2d %2d', date.month, date.day)
+ display(s) # sets the LCD number/text
+ @showDateTimer = startTimer(2000) # keep this state for 2 secs
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/dclock/main.rb b/qtruby/rubylib/examples/qt-examples/dclock/main.rb
new file mode 100755
index 00000000..c76ae55d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/dclock/main.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'dclock'
+
+a = Qt::Application.new(ARGV)
+clock = DigitalClock.new
+clock.resize(170,80)
+a.setMainWidget(clock)
+clock.setCaption('QtRuby Example - Digital Clock')
+clock.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb
new file mode 100755
index 00000000..9559a921
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'viewer'
+$KCODE='u'
+
+
+a = Qt::Application.new(ARGV)
+
+textViewer = Viewer.new
+textViewer.setCaption('QtRuby Example - Simple QFont Demo')
+a.setMainWidget(textViewer)
+textViewer.show
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb
new file mode 100644
index 00000000..d9c16a62
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb
@@ -0,0 +1,140 @@
+class Viewer < Qt::Widget
+ slots 'setDefault()', 'setSansSerif()', 'setItalics()'
+
+ def initialize
+ super
+
+ setFontSubstitutions
+
+ codec = Qt::TextCodec::codecForName("utf8")
+
+ # Shouldn't 'pack("U*")' for UTF-8 work here? - Richard
+ # The 'U' option packs each element into two bytes and doesn't work
+ # The 'c' option packs them into a single byte and does work
+ greeting_heb = codec.toUnicode([0327, 0251, 0327, 0234, 0327, 0225, 0327, 0235].pack("C*"))
+ greeting_ru = codec.toUnicode([0320, 0227, 0320, 0264, 0321, 0200, 0320, 0260, 0320, 0262, 0321, 0201, 0321, 0202, 0320, 0262, 0321, 0203, 0320, 0271, 0321, 0202, 0320, 0265].pack("C*"))
+ greeting_en = 'Hello'
+
+ @greetings = Qt::TextView.new(self, 'textview')
+ @greetings.setText(
+ greeting_en + "\n" +
+ greeting_ru + "\n" +
+ greeting_heb)
+
+ @fontInfo = Qt::TextView.new(self, 'fontinfo')
+
+ setDefault
+
+ @defaultButton = Qt::PushButton.new('Default', self, 'pushbutton1')
+ @defaultButton.setFont(Qt::Font.new('times'))
+ connect(@defaultButton, SIGNAL('clicked()'), self, SLOT('setDefault()'))
+
+
+ @sansSerifButton = Qt::PushButton.new('Sans Serif', self, 'pushbutton2')
+ @sansSerifButton.setFont(Qt::Font.new('Helvetica', 12))
+ connect(@sansSerifButton, SIGNAL('clicked()'), self, SLOT('setSansSerif()'))
+
+ @italicsButton = Qt::PushButton.new('Italics', self, 'pushbutton1')
+ @italicsButton.setFont(Qt::Font.new('lucida', 12, Qt::Font.Bold, true))
+ connect(@italicsButton, SIGNAL('clicked()'), self, SLOT('setItalics()'))
+
+ layout
+ end
+
+ def setDefault
+ font = Qt::Font.new('Bavaria')
+ font.setPointSize(24)
+ font.setWeight(Qt::Font.Bold)
+ font.setUnderline(true)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setSansSerif
+ font = Qt::Font.new('Newyork', 18)
+ font.setStyleHint(Qt::Font.SansSerif)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setItalics
+ font = Qt::Font.new('Tokyo')
+ font.setPointSize(32)
+ font.setWeight(Qt::Font.Bold)
+ font.setItalic(true)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setFontSubstitutions
+ substitutes = Array.new
+
+ substitutes.push('Times')
+ substitutes.push('Mincho')
+ substitutes.push('Arabic Newspaper')
+ substitutes.push('crox')
+
+ Qt::Font.insertSubstitutions('Bavaria', substitutes)
+ Qt::Font.insertSubstitution('Tokyo', 'Lucida')
+ end
+
+ def layout
+ textViewContainer = Qt::HBoxLayout.new
+ textViewContainer.addWidget(@greetings)
+ textViewContainer.addWidget(@fontInfo)
+
+ buttonContainer = Qt::HBoxLayout.new
+ buttonContainer.addWidget(@defaultButton)
+ buttonContainer.addWidget(@sansSerifButton)
+ buttonContainer.addWidget(@italicsButton)
+
+ maxButtonHeight = @defaultButton.height
+
+ if (@sansSerifButton.height > maxButtonHeight)
+ maxButtonHeight = @sansSerifButton.height
+ end
+
+ if (@italicsButton.height > maxButtonHeight)
+ maxButtonHeight = @italicsButton.height
+ end
+
+ @defaultButton.setFixedHeight(maxButtonHeight)
+ @sansSerifButton.setFixedHeight(maxButtonHeight)
+ @italicsButton.setFixedHeight(maxButtonHeight)
+
+ container = Qt::VBoxLayout.new(self)
+ container.addLayout(textViewContainer)
+ container.addLayout(buttonContainer)
+
+ resize(700, 250)
+ end
+
+ def showFontInfo (font)
+ info = Qt::FontInfo.new(font)
+ messageText =
+ 'Font requested: "' +
+ font.family + '" ' +
+ font.pointSize.to_s + 'pt<BR>' +
+ 'Font used: "' +
+ info.family.to_s + '" ' +
+ info.pointSize.to_s + 'pt<P>'
+
+ substitutions = Qt::Font.substitutes(font.family)
+
+ unless substitutions.size == 0
+ messageText = messageText + 'The following substitutions exist for ' +
+ font.family + ':<UL>'
+ substitutions.each {|x|
+ messageText = messageText + '<LI>"' + x + '"'
+ }
+ messageText = messageText + '</UL>'
+ else
+ messageText = messageText + 'No substitutions exist for ' + font.family + '.'
+ end
+
+ @fontInfo.setText(messageText)
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/forever/forever.rb b/qtruby/rubylib/examples/qt-examples/forever/forever.rb
new file mode 100755
index 00000000..46849784
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/forever/forever.rb
@@ -0,0 +1,84 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+#
+# Forever - a widget that draws rectangles forever.
+#
+
+class Forever < Qt::Widget
+
+ NUM_COLORS = 120
+ #
+ # Constructs a Forever widget.
+ #
+
+ slots 'updateCaption()'
+
+ def initialize(*k)
+ super(nil)
+ @colors = []
+ 0.upto(NUM_COLORS-1) do |a|
+ @colors[a] = Qt::Color.new( rand(255),
+ rand(255),
+ rand(255) )
+ end
+ @rectangles = 0
+ startTimer( 0 ) # run continuous timer
+ counter = Qt::Timer.new( self )
+ connect( counter, SIGNAL("timeout()"),
+ self, SLOT("updateCaption()") )
+ counter.start( 1000 )
+ end
+
+
+ def updateCaption()
+ s = "Qt Example - Forever - " + @rectangles.to_s + " rectangles/second"
+ @rectangles = 0
+ self.caption = s
+ end
+
+
+ #
+ # Handles paint events for the Forever widget.
+ #
+
+ def paintEvent( e )
+ paint = Qt::Painter.new( self ) # painter object
+ w = width()
+ h = height()
+ if w <= 0 || h <= 0 then
+ return
+ end
+ paint.setPen( NoPen ) # do not draw outline
+ paint.setBrush( @colors[rand(NUM_COLORS)]) # set random brush color
+
+ p1 = Qt::Point.new( rand(w), rand(h)) # p1 = top left
+ p2 = Qt::Point.new( rand(w), rand(h)) # p2 = bottom right
+
+ r = Qt::Rect.new( p1, p2 )
+ paint.drawRect( r ) # draw filled rectangle
+ paint.end()
+ end
+
+ #
+ # Handles timer events for the Forever widget.
+ #
+
+ def timerEvent( e )
+ 0.upto(99) do |i|
+ repaint( false ) # repaint, don't erase
+ end
+ @rectangles += 100
+ end
+
+
+end
+
+a = Qt::Application.new(ARGV)
+always = Forever.new
+always.resize( 400, 250 ) # start up with size 400x250
+a.mainWidget = always # set as main widget
+always.caption = "QtRuby Example - Forever"
+always.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/hello/hello.rb b/qtruby/rubylib/examples/qt-examples/hello/hello.rb
new file mode 100644
index 00000000..ce957c75
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/hello/hello.rb
@@ -0,0 +1,78 @@
+require 'Qt'
+
+class Hello < Qt::Widget
+
+ signals 'clicked()'
+ slots 'animate()'
+
+ # Constructs a Hello widget. Starts a 40 ms animation timer
+ def initialize (text)
+ super()
+
+ @b = 0
+ @text = text
+ @sin_tbl = [0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38]
+ timer = Qt::Timer.new(self);
+ connect(timer, SIGNAL('timeout()'), SLOT('animate()'))
+ timer.start(40);
+
+ resize(260, 130)
+ end
+
+ # This slot is called each time the timer fires.
+ def animate
+ @b = (@b + 1) & 15
+ repaint(false)
+ end
+
+ # Handles mouse button release events for the Hello widget.
+ #
+ # We emit the clicked() signal when the mouse is released inside
+ # the widget.
+ def mouseReleaseEvent(e)
+ if (rect.contains(e.pos))
+ emit clicked
+ end
+ end
+
+ # Handles paint events for the Hello widget.
+ #
+ # Flicker-free update. The text is first drawn in the pixmap and the
+ # pixmap is then blt'ed to the screen.
+ def paintEvent(e)
+ if @text.empty?
+ return
+ end
+
+ # 1: Compute some sizes, positions etc.
+ fm = fontMetrics
+
+ w = fm.width(@text) + 20
+ h = fm.height * 2
+ pmx = width/2 - w/2
+ pmy = height/2 - h/2
+
+ # 2: Create the pixmap and fill it with the widget's background
+ pm = Qt::Pixmap.new(w, h)
+ pm.fill(self, pmx, pmy)
+
+ # 3: Paint the pixmap. Cool wave effect
+ p = Qt::Painter.new;
+ x = 10
+ y = h/2 + fm.descent
+ i = 0
+ p.begin(pm)
+ p.setFont(font)
+
+ for i in 0..@text.size-1
+ j = (@b+i) & 15
+ p.setPen(Qt::Color.new((15-j)*16,255,255,Qt::Color.Hsv) )
+ p.drawText( x, y-@sin_tbl[j]*h/800, @text[i,1], 1 )
+ x += fm.width(@text[i,1])
+ end
+ p.end
+
+ #4: Copy the pixmap to the Hello widget
+ bitBlt(self, pmx, pmy, pm)
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/hello/main.rb b/qtruby/rubylib/examples/qt-examples/hello/main.rb
new file mode 100755
index 00000000..a6d3447f
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/hello/main.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'hello'
+
+a = Qt::Application.new(ARGV)
+s = ''
+
+s = ARGV[0..ARGV.size-1].join(' ') if ARGV.length
+
+if (s.empty?)
+ s = 'Hello, World'
+end
+
+h = Hello.new(s)
+h.setCaption('QtRuby says hello')
+h.connect(h, SIGNAL('clicked()'), a, SLOT('quit()'))
+h.setFont(Qt::Font.new('times', 32, Qt::Font.Bold)) # default font
+h.setBackgroundColor(Qt::white) # default bg color
+a.setMainWidget(h)
+h.show
+
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/progress/progress.rb b/qtruby/rubylib/examples/qt-examples/progress/progress.rb
new file mode 100644
index 00000000..02116958
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/progress/progress.rb
@@ -0,0 +1,275 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+class AnimatedThingy < Qt::Label
+ attr_accessor :label, :step
+ attr_accessor :ox0, :oy0, :ox1, :oy1
+ attr_accessor :x0, :y0, :x1, :y1
+ attr_accessor :dx0, :dx1, :dy0, :dy1
+ NQIX = 10
+
+ def initialize(*k)
+ super(*k)
+ @label = k[1] + "\n... and wasting CPU\nwith this animation!\n"
+ @step = 0
+ @ox0, @oy0, @ox1, @oy1 = *Array.new(4) { Array.new(10, 0) }
+ @x0 = @y0 = @x1 = @y1 = 0
+ @dx0 = rand(8)+2
+ @dy0 = rand(8)+2
+ @dx1 = rand(8)+2
+ @dy1 = rand(8)+2
+ end
+
+ def show
+ startTimer(100) unless isVisible
+ super
+ end
+
+ def hide
+ super
+ killTimers()
+ end
+
+ def sizeHint
+ Qt::Size.new(120,100)
+ end
+
+ def inc(x, dx, b)
+ x += dx
+ if x < 0
+ x = 0
+ dx = rand(8) + 2
+ elsif x >= b
+ x = b-1
+ dx = -(rand(8)+2)
+ end
+ yield x, dx
+ end
+
+ def timerEvent(e)
+ p = Qt::Painter.new(self)
+ pn = p.pen
+ pn.setWidth(2)
+ pn.setColor(backgroundColor)
+ p.setPen(pn)
+
+ @step = (@step + 1) % NQIX
+
+ p.drawLine(@ox0[@step], @oy0[@step], @ox1[@step], @oy1[@step])
+
+ inc(@x0, @dx0, width) { |x,dx| @x0, @dx0 = x, dx }
+ inc(@y0, @dy0, height) { |y,dy| @y0, @dy0 = y, dy }
+ inc(@x1, @dx1, width) { |x,dx| @x1, @dx1 = x, dx }
+ inc(@y1, @dy1, height) { |y,dy| @y1, @dy1 = y, dy }
+ @ox0[@step] = @x0
+ @oy0[@step] = @y0
+ @ox1[@step] = @x1
+ @oy1[@step] = @y1
+
+ c = Qt::Color.new
+ c.setHsv( (@step*255)/NQIX, 255, 255 ) # rainbow effect
+ pn.setColor(c)
+ pn.setWidth(2)
+ p.setPen(pn)
+ p.drawLine(@ox0[@step], @oy0[@step], @ox1[@step], @oy1[@step])
+ p.setPen(colorGroup().text())
+ p.drawText(rect(), AlignCenter, @label)
+ p.end()
+ end
+
+ def paintEvent(event)
+ p = Qt::Painter.new(self)
+ pn = p.pen()
+ pn.setWidth(2)
+ p.setPen(pn)
+ p.setClipRect(event.rect())
+ 0.upto(NQIX-1) do |i|
+ c = Qt::Color.new()
+ c.setHsv( (i*255)/NQIX, 255, 255 ) # rainbow effect
+ pn.setColor(c)
+ p.setPen(pn)
+ p.drawLine(@ox0[i], @oy0[i], @ox1[i], @oy1[i])
+ end
+ p.setPen(colorGroup().text())
+ p.drawText(rect(), AlignCenter, @label)
+ p.end
+ end
+end
+
+class CPUWaster < Qt::Widget
+ attr_accessor :menubar, :file, :options, :rects, :pb
+ attr_accessor :td_id , :ld_id, :dl_id, :cl_id, :md_id
+ attr_accessor :got_stop, :timer_driven, :default_label
+ slots 'drawItemRects(int)', 'doMenuItem(int)', 'stopDrawing()', 'timerDriven()'
+ slots 'loopDriven()', 'defaultLabel()', 'customLabel()', 'toggleMinimumDuration()'
+
+ FIRST_DRAW_ITEM = 1000
+ LAST_DRAW_ITEM = 1006
+
+ def initialize(*k)
+ super(*k)
+
+ @menubar = Qt::MenuBar.new(self, "menu")
+ @pb = nil
+
+ @file = Qt::PopupMenu.new
+ @menubar.insertItem( "&File", file )
+ FIRST_DRAW_ITEM.upto(LAST_DRAW_ITEM) {
+ |i| file.insertItem( "#{drawItemRects(i)} Rectangles", i)
+ }
+ connect( menubar, SIGNAL('activated(int)'), self, SLOT('doMenuItem(int)') )
+ @file.insertSeparator
+ @file.insertItem("Quit", $qApp, SLOT('quit()'))
+ @options = Qt::PopupMenu.new
+ @menubar.insertItem("&Options", options)
+ @td_id = options.insertItem("Timer driven", self, SLOT('timerDriven()'))
+ @ld_id = options.insertItem("Loop driven", self, SLOT('loopDriven()'))
+ @options.insertSeparator
+ @dl_id = options.insertItem("Default label", self, SLOT('defaultLabel()'))
+ @cl_id = options.insertItem("Custom label", self, SLOT('customLabel()'))
+ @options.insertSeparator
+ @md_id = options.insertItem("No minimum duration", self, SLOT('toggleMinimumDuration()'))
+ @options.setCheckable true
+
+ loopDriven
+ defaultLabel
+
+ setFixedSize(400, 300)
+ setBackgroundColor(black)
+ end
+
+ def drawItemRects(id)
+ n = id - FIRST_DRAW_ITEM - 1
+ r = 100
+ n.downto(0) { |n|
+ r *= (n%3 != 0) ? 5 : 4
+ }
+ r
+ end
+
+ def doMenuItem(id)
+ draw drawItemRects(id) if id >= FIRST_DRAW_ITEM && id <= LAST_DRAW_ITEM
+ end
+
+ def stopDrawing
+ @got_stop = true
+ end
+
+ def timerDriven
+ @timer_driven = true
+ @options.setItemChecked(@td_id, true)
+ @options.setItemChecked(@ld_id, false)
+ end
+
+ def loopDriven
+ @timer_driven = false
+ @options.setItemChecked(@td_id, false)
+ @options.setItemChecked(@ld_id, true)
+ end
+
+ def defaultLabel
+ @default_label = true
+ @options.setItemChecked(@dl_id, true)
+ @options.setItemChecked(@cl_id, false)
+ end
+
+ def customLabel
+ @default_label = false
+ @options.setItemChecked(@dl_id, false)
+ @options.setItemChecked(@cl_id, true)
+ end
+
+ def toggleMinimumDuration
+ checked = @options.isItemChecked(@md_id)
+ @options.setItemChecked(@md_id, !checked)
+ end
+
+ def timerEvent(e)
+ @pb.setProgress( @pb.totalSteps - @rects ) if @rects % 100 == 0
+ @rects -= 1
+
+ painter = Qt::Painter.new(self)
+
+ ww = width
+ wh = height
+
+ if ww > 8 and wh > 8
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(ww - 8)
+ y = rand(wh - 8)
+ w = rand(ww - x)
+ h = rand(wh - y)
+ painter.fillRect(x, y, w, h, Qt::Brush.new(c))
+ end
+
+ painter.end()
+
+ if @rects == 0 || @got_stop
+ @pb.setProgress(@pb.totalSteps)
+ painter = Qt::Painter.new(self)
+ painter.fillRect(0, 0, width(), height(), Qt::Brush.new(backgroundColor))
+ painter.end()
+ enableDrawingItems(true)
+ killTimers()
+ @pb = nil
+ end
+ end
+
+ def newProgressDialog(label, steps, modal)
+ d = Qt::ProgressDialog.new(label, "Cancel", steps, self, "progress", modal)
+ d.setMinimumDuration(0) if @options.isItemChecked(@md_id)
+ d.setLabel( AnimatedThingy.new(d, label) ) unless @default_label
+ d.show
+ d
+ end
+
+ def enableDrawingItems(yes)
+ FIRST_DRAW_ITEM.upto(LAST_DRAW_ITEM) {
+ |i| menubar.setItemEnabled(i, yes)
+ }
+ end
+
+ def draw(n)
+ if timer_driven
+ unless @pb.nil?
+ warn("This cannot happen!")
+ return
+ end
+ @rects = n
+ @pb = newProgressDialog("Drawing rectangles.\nUsing timer event.", n, false)
+ @pb.setCaption("Please Wait")
+ connect(@pb, SIGNAL('cancelled()'), self, SLOT('stopDrawing()'))
+ enableDrawingItems(false)
+ startTimer(0)
+ @got_stop = false
+ else
+ lpb = newProgressDialog("Drawing rectangles.\nUsing loop.", n, true)
+ lpb.setCaption("Please Wait")
+
+ painter = Qt::Painter.new(self)
+ 0.upto(n) { |i|
+ if (i % 100) == 0
+ lpb.setProgress(i)
+ break if lpb.wasCancelled
+ end
+ cw, ch = width, height
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(cw - 8)
+ y = rand(cw - 8)
+ w = rand(cw - x)
+ h = rand(cw - y)
+ painter.fillRect(x, y, w, h, Qt::Brush.new(c))
+ }
+ lpb.cancel
+ painter.fillRect(0, 0, width, height, Qt::Brush.new(backgroundColor))
+ painter.end()
+ end
+ end
+end
+
+a = Qt::Application.new(ARGV)
+w = CPUWaster.new
+w.show
+a.setMainWidget(w)
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/tictac/main.rb b/qtruby/rubylib/examples/qt-examples/tictac/main.rb
new file mode 100755
index 00000000..024ae70c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tictac/main.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+require 'tictac'
+
+a = Qt::Application.new(ARGV)
+n = 3 # get board size n
+
+ttt = TicTacToe.new(n)
+a.setMainWidget(ttt)
+ttt.setCaption('QtRuby Example - TicTac')
+ttt.show()
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
new file mode 100644
index 00000000..04ab8b9d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
@@ -0,0 +1,311 @@
+require 'Qt'
+
+class TicTacButton < Qt::PushButton
+
+ attr_accessor :btype
+
+ Blank, Circle, Cross = 0, 1, 2
+
+ def initialize(p)
+ super(p)
+ @btype = Blank
+ end
+
+ def drawButtonLabel(p)
+ r = rect()
+ p.setPen( Qt::Pen.new( Qt::white,2 ) ) # set fat pen
+ if (@btype == Circle)
+ p.drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 )
+ elsif (@btype == Cross) # draw cross
+ p.drawLine( r.topLeft() +Qt::Point.new(4,4), r.bottomRight()-Qt::Point.new(4,4))
+ p.drawLine( r.bottomLeft()+Qt::Point.new(4,-4),r.topRight() -Qt::Point.new(4,-4))
+ end
+ super(p)
+ end
+end
+
+class TicTacGameBoard < Qt::Widget
+ signals 'finished()'
+ slots 'buttonClicked()'
+
+ Init, HumansTurn, HumanWon, ComputerWon, NobodyWon = 0, 1, 2, 3, 4
+
+ attr_accessor :state, :computer_starts
+
+ def initialize (n, parent)
+ super(parent)
+ @state = Init
+ @nBoard = n
+ n = n*n
+ @computer_starts = false
+ @buttons = Array.new(n)
+ @btArray = Array.new(n)
+
+ grid = Qt::GridLayout.new(self, n, n, 4)
+ p = Qt::Palette.new(Qt::blue)
+
+ for i in (0..n-1)
+ ttb = TicTacButton.new(self)
+ ttb.setPalette(p)
+ ttb.setEnabled(false)
+ connect(ttb, SIGNAL('clicked()'), self, SLOT('buttonClicked()'))
+ grid.addWidget(ttb, i % @nBoard, i / @nBoard)
+ @buttons[i] = ttb
+ @btArray[i] = TicTacButton::Blank
+ end
+ end
+
+ def newGame
+ @state = HumansTurn
+ for i in 0..(@nBoard*@nBoard)-1
+ @btArray[i] = TicTacButton::Blank
+ end
+ if @computer_starts == true
+ computerMove
+ else
+ updateButtons
+ end
+ end
+
+ def updateButtons
+ for i in 0..(@nBoard*@nBoard)-1
+ if @buttons[i].btype != @btArray[i]
+ @buttons[i].btype = @btArray[i]
+ end
+ if @buttons[i].btype == TicTacButton::Blank
+ @buttons[i].setEnabled(true)
+ else
+ @buttons[i].setEnabled(false)
+ end
+ @buttons[i].repaint
+ end
+ end
+
+ def checkBoard
+ t = 0
+ row = 0
+ col = 0
+ won = false
+
+ # check horizontal
+ for row in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[row*@nBoard]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ col = 1
+ while ( (col < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ col += 1
+ end
+ if (col == @nBoard)
+ won = true
+ end
+ end
+
+ # check vertical
+ for col in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[col]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ row = 1
+ while ( (row < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ row += 1
+ end
+ if (row == @nBoard)
+ won = true
+ end
+ end
+
+ # check diagonal top left to bottom right
+ if (won == false)
+ t = @btArray[0]
+ if (t != TicTacButton::Blank)
+ i = 1;
+ while (i<@nBoard && (@btArray[i*@nBoard+i] == t))
+ i += 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ # check diagonal bottom left to top right
+ if (won == false)
+ j = @nBoard-1
+ i = 0;
+ t = @btArray[i+j*@nBoard];
+ if (t != TicTacButton::Blank)
+ i += 1
+ j -= 1
+ while ( (i<@nBoard) && (@btArray[i+j*@nBoard] == t) )
+ i += 1
+ j -= 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ if (won == false)
+ # no winner
+ t = 0
+ end
+
+ t
+ end
+
+ def computerMove
+ numButtons = @nBoard*@nBoard
+ altv = Array.new
+ stopHuman = -1
+ i = 0
+
+ for i in 0..numButtons-1 # try all positions
+ if @btArray[i] != TicTacButton::Blank # already a piece there
+ next
+ end
+
+ @btArray[i] = TicTacButton::Cross # test if computer wins
+ if (checkBoard == @btArray[i]) # computer will win
+ @state = ComputerWon
+ stopHuman = -1
+ break
+ end
+
+ @btArray[i] = TicTacButton::Circle # test if human wins
+ if (checkBoard == @btArray[i]) # oops...
+ stopHuman = i # remember position
+ @btArray[i] = TicTacButton::Blank # restore button
+ next # computer still might win
+ end
+ @btArray[i] = TicTacButton::Blank; # restore button
+ altv.push(i) # remember alternative
+ end
+
+ if (stopHuman >= 0) # must stop human from winning
+ @btArray[stopHuman] = TicTacButton::Cross
+ elsif (i == numButtons-1) # tried all alternatives
+ if (altv.size > 0) # set random piece
+ @btArray[altv[rand(altv.size)]] = TicTacButton::Cross
+ end
+ if ((altv.size-1) == 0) # no more blanks
+ @state = NobodyWon
+ emit finished()
+ end
+ end
+ updateButtons # update buttons
+ end
+
+ def buttonClicked
+ unless @state == HumansTurn
+ return
+ end
+
+ at = nil
+ for i in 0..@buttons.size
+ if @buttons[i].object_id == sender.object_id
+ at = i
+ break
+ end
+ end
+ if @btArray[at] == TicTacButton::Blank
+ @btArray[at] = TicTacButton::Circle
+ updateButtons
+
+ if (checkBoard == 0)
+ computerMove
+ end
+ s = checkBoard
+ if (s != 0)
+ if (s == TicTacButton::Circle)
+ @state = HumanWon
+ else
+ @state = ComputerWon
+ end
+ emit finished()
+ end
+ end
+ end
+
+end
+
+class TicTacToe < Qt::Widget
+ slots 'newGameClicked()', 'gameOver()'
+
+ def initialize (boardSize)
+ super()
+
+ l = Qt::VBoxLayout.new(self, 6)
+
+ @state_msg = [
+ 'Click Play to start',
+ 'Make your move',
+ 'You won!',
+ 'Computer won!',
+ 'It\'s a draw']
+
+ # Create a message label
+ @message = Qt::Label.new(self)
+ @message.setFrameStyle((Qt::Frame.WinPanel|Qt::Frame.Sunken))
+ @message.setAlignment(Qt::AlignCenter)
+ l.addWidget(@message)
+
+ # Create the game board and connect the signal finished()
+ # to this/self gameOver() slot
+ @board = TicTacGameBoard.new(boardSize, self)
+ connect(@board, SIGNAL('finished()'), self, SLOT('gameOver()'));
+ l.addWidget(@board)
+
+ # Create a horizontal frame line
+ line = Qt::Frame.new(self)
+ line.setFrameStyle(Qt::Frame.HLine|Qt::Frame.Sunken)
+ l.addWidget(line)
+
+ # Create the combo box for deciding who should start
+ # and connect its clicked() signals to the buttonClicked() slot
+ @whoStarts = Qt::ComboBox.new(self)
+ @whoStarts.insertItem('Computer starts')
+ @whoStarts.insertItem('Human starts')
+ l.addWidget(@whoStarts);
+
+ # Create the push buttons and connect their signals to the right slots
+ @newGame = Qt::PushButton.new('Play!', self)
+ connect(@newGame, SIGNAL('clicked()'), self, SLOT('newGameClicked()'))
+ @quit = Qt::PushButton.new('Quit', self)
+ connect(@quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+ b = Qt::HBoxLayout.new
+ l.addLayout(b)
+ b.addWidget(@newGame)
+ b.addWidget(@quit)
+
+ newState()
+ end
+
+ def newState
+ @message.setText(@state_msg[@board.state])
+ end
+
+ def newGameClicked
+ if @whoStarts.currentItem == 0
+ @board.computer_starts = true
+ else
+ @board.computer_starts = false
+ end
+ @board.newGame()
+ newState()
+ end
+
+ def gameOver
+ # Update text box
+ newState()
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/tooltip/main.rb b/qtruby/rubylib/examples/qt-examples/tooltip/main.rb
new file mode 100755
index 00000000..f1f9ccda
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tooltip/main.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'tooltip'
+
+a = Qt::Application.new(ARGV)
+
+mw = TellMe.new
+mw.setCaption('QtRuby Example - Dynamic Tool Tips')
+a.setMainWidget(mw)
+mw.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb b/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb
new file mode 100644
index 00000000..181816da
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb
@@ -0,0 +1,95 @@
+require 'Qt'
+
+class DynamicTip < Qt::ToolTip
+ def initialize(p)
+ super(p)
+ end
+
+ def maybeTip(p)
+ if !parentWidget.inherits('TellMe')
+ return
+ end
+
+ r = parentWidget.tip(p)
+ if !r.isValid
+ return
+ end
+
+ s = 'position: ' + r.center.x.to_s + ', ' + r.center.y.to_s
+ tip(r,s)
+ end
+end
+
+class TellMe < Qt::Widget
+
+ def initialize
+ super
+
+ setMinimumSize(30, 30)
+
+ @r1 = randomRect
+ @r2 = randomRect
+ @r3 = randomRect
+
+ @t = DynamicTip.new(self)
+
+ Qt::ToolTip.add(self, @r3, 'this color is called red') #TT says this is helpful, I'm not so sure
+ end
+
+ def tip(point)
+ if (@r1.contains(point))
+ @r1
+ elsif (@r2.contains(point))
+ @r2
+ else
+ Qt::Rect.new(0,0, -1, -1)
+ end
+ end
+
+ def paintEvent(e)
+ p = Qt::Painter.new(self)
+
+ if (e.rect.intersects(@r1))
+ p.setBrush(Qt::blue)
+ p.drawRect(@r1)
+ end
+
+ if (e.rect.intersects(@r2))
+ p.setBrush(Qt::blue)
+ p.drawRect(@r2)
+ end
+
+ if (e.rect.intersects(@r3))
+ p.setBrush(Qt::red)
+ p.drawRect(@r3)
+ end
+
+ p.end
+ end
+
+ def mousePressEvent (e)
+ if (@r1.contains(e.pos))
+ @r1 = randomRect
+ end
+
+ if (@r2.contains(e.pos))
+ @r2 = randomRect
+ end
+
+ repaint
+ end
+
+ def resizeEvent(e)
+ unless rect.contains(@r1)
+ @r1 = randomRect
+ end
+
+ unless rect.contains(@r2)
+ @r2 = randomRect
+ end
+ end
+
+ def randomRect
+ Qt::Rect.new(rand(width - 20), rand(height - 20), 20, 20)
+ end
+end
diff --git a/qtruby/rubylib/examples/qtscribble/scribble.rb b/qtruby/rubylib/examples/qtscribble/scribble.rb
new file mode 100644
index 00000000..7c6e1ca5
--- /dev/null
+++ b/qtruby/rubylib/examples/qtscribble/scribble.rb
@@ -0,0 +1,274 @@
+#!/usr/bin/env ruby -w
+
+ #
+ # A class that lets the user draw with the mouse. The
+ # window knows how to redraw itself.
+ #
+
+require 'Qt'
+
+ class ScribbleArea < Qt::Widget
+
+ slots "setColor(QColor)", "slotLoad(const QString&)", "slotSave(const QString&)", "slotClearArea()"
+
+ #
+ # The constructor. Initializes the member variables.
+ #
+ def initialize()
+ super
+ # initialize member variables
+ @_buffer = Qt::Pixmap.new()
+ @_last = Qt::Point.new()
+ @_currentcolor = black
+
+ # don't blank the window before repainting
+ setBackgroundMode( NoBackground )
+
+ # create a pop-up menu
+ @_popupmenu = Qt::PopupMenu.new()
+ @_popupmenu.insertItem( "&Clear", self, SLOT( "slotClearArea()" ) )
+ end
+
+ #
+ # This slot sets the curren color for the scribble area. It will be
+ # connected with the colorChanged( Qt::Color ) signal from the
+ # ScribbleWindow.
+ #
+ def setColor( new_color )
+ @_currentcolor = new_color
+ end
+
+ #
+ # This slot clears the drawing area by filling the off-screen buffer with
+ # white and copying it over to the window.
+ #
+ def slotClearArea()
+ # fill the off screen buffer with plain white
+ @_buffer.fill( white )
+
+ # and copy it over to the window
+ bitBlt( self, 0, 0, @_buffer )
+ end
+
+
+ #
+ # This method does the actual loading. It relies on Qt::Pixmap (and the
+ # underlying I/O machinery) to determine the filetype.
+ #
+ def slotLoad( filename )
+ if !@_buffer.load( filename )
+ Qt::MessageBox.warning( nil, "Load error", "Could not load file" )
+ end
+
+ repaint() # refresh the window
+ end
+
+
+ #
+ # This method does the actual saving. We hard-code the file type as
+ # BMP. Unix users might want to replace this with something like XPM.
+ #
+ def slotSave( filename )
+ if !@_buffer.save( filename, "BMP" )
+ Qt::MessageBox.warning( nil, "Save error", "Could not save file" )
+ end
+ end
+
+
+ #
+ # This method is called whenever the user presses the
+ # mouse over the window. It just records the position of the mouse
+ # at the time of the click.
+ #
+ def mousePressEvent(event)
+ if event.button() == RightButton
+ @_popupmenu.exec( Qt::Cursor.pos() )
+ else
+ @_last = event.pos() # retrieve the coordinates from the event
+ end
+ end
+
+
+ #
+ # The method is called whenever the usr moves the mouse
+ # while the mouse button is pressed. If we had called
+ # setMouseTracking(true) before, the method would also be called
+ # when the mouse was moved with any button pressed. We know that
+ # we haven't, and thus don't have to check whether any buttons are
+ # pressed.
+ #
+ def mouseMoveEvent(event)
+ # create a Qt::Painter object for drawing onto the window
+ windowpainter = Qt::Painter.new()
+ # and another Qt::Painter object for drawing int an off-screen pixmap
+ bufferpainter = Qt::Painter.new()
+
+ # start painting
+ windowpainter.begin( self ) # This painter paints onto the window
+ bufferpainter.begin( @_buffer ) # and this one paints in the buffer
+
+ # set a standard pen with the currently selected color
+ windowpainter.setPen( @_currentcolor )
+ bufferpainter.setPen( @_currentcolor )
+
+ # draw a line in both the window and the buffer
+ windowpainter.drawLine( @_last, event.pos() )
+ bufferpainter.drawLine( @_last, event.pos() )
+
+ # done with painting
+ windowpainter.end()
+ bufferpainter.end()
+
+ # remember the current mouse position
+ @_last = event.pos()
+ end
+
+ #
+ # This method is called whenever the widget needs
+ # painting, for example when it has been obscured and then revealed again.
+ #
+ def paintEvent(event)
+ bitBlt(self, 0, 0, @_buffer)
+ end
+
+ #
+ # This method get called whenever the widget needs
+ # painting, for example, when it has been obscured and then revealed again.
+ #
+ def resizeEvent(event)
+ save = Qt::Pixmap.new( @_buffer )
+ @_buffer.resize( event.size() )
+ @_buffer.fill( white )
+ bitBlt( @_buffer, 0, 0, save )
+ end
+ end
+
+class ScribbleWindow < Qt::Widget
+
+ slots "slotAbout()", "slotAboutQt()", "slotColorMenu(int)", "slotLoad()", "slotSave()"
+ signals "colorChanged(QColor)", "load(const QString&)", "save(const QString&)"
+
+ COLOR_MENU_ID_BLACK = 0
+ COLOR_MENU_ID_RED = 1
+ COLOR_MENU_ID_BLUE = 2
+ COLOR_MENU_ID_GREEN = 3
+ COLOR_MENU_ID_YELLOW = 4
+
+ def initialize()
+ super
+ # The next lines build the menu bar. We first create the menus
+ # one by one, then add them to the menu bar. #
+ @_filemenu = Qt::PopupMenu.new() # create a file menu
+ @_filemenu.insertItem( "&Load", self, SLOT( "slotLoad()" ) )
+ @_filemenu.insertItem( "&Save", self, SLOT( "slotSave()" ) )
+ @_filemenu.insertSeparator()
+ @_filemenu.insertItem( "&Quit", $qApp, SLOT( "quit()" ) )
+
+ @_colormenu = Qt::PopupMenu.new() # create a color menu
+ @_colormenu.insertItem( "B&lack", COLOR_MENU_ID_BLACK)
+ @_colormenu.insertItem( "&Red", COLOR_MENU_ID_RED)
+ @_colormenu.insertItem( "&Blue", COLOR_MENU_ID_BLUE)
+ @_colormenu.insertItem( "&Green", COLOR_MENU_ID_GREEN)
+ @_colormenu.insertItem( "&Yellow", COLOR_MENU_ID_YELLOW)
+ Qt::Object.connect( @_colormenu, SIGNAL( "activated( int )" ),
+ self, SLOT( "slotColorMenu( int )" ) )
+
+ @_helpmenu = Qt::PopupMenu.new() # create a help menu
+ @_helpmenu.insertItem( "&About QtScribble", self, SLOT( "slotAbout()" ) )
+ @_helpmenu.insertItem( "&About Qt", self, SLOT( "slotAboutQt()" ) )
+
+ @_menubar = Qt::MenuBar.new( self, "" ) # create a menu bar
+ @_menubar.insertItem( "&File", @_filemenu )
+ @_menubar.insertItem( "&Color", @_colormenu )
+ @_menubar.insertItem( "&Help", @_helpmenu )
+
+ # We create a Qt::ScrollView and a ScribbleArea. The ScribbleArea will
+ # be managed by the scroll view.#
+ @_scrollview = Qt::ScrollView.new( self )
+ @_scrollview.setGeometry( 0, @_menubar.height(),
+ width(), height() - @_menubar.height() )
+ @_scribblearea = ScribbleArea.new()
+ @_scribblearea.setGeometry( 0, 0, 1000, 1000 )
+ @_scrollview.addChild( @_scribblearea )
+ Qt::Object.connect( self, SIGNAL( "colorChanged(QColor)" ),
+ @_scribblearea, SLOT( "setColor(QColor)" ) )
+ Qt::Object.connect( self, SIGNAL( "save(const QString&)" ),
+ @_scribblearea, SLOT( "slotSave(const QString&)" ) )
+ Qt::Object.connect( self, SIGNAL( "load(const QString&)" ),
+ @_scribblearea, SLOT( "slotLoad(const QString&)" ) )
+ end
+
+ def resizeEvent( event )
+ # When the whole window is resized, we have to rearrange the geometry
+ # in the ScribbleWindow as well. Note that the ScribbleArea does not need
+ # to be changed.
+ @_scrollview.setGeometry( 0, @_menubar.height(),
+ width(), height() - @_menubar.height() )
+ end
+
+
+
+ def slotAbout()
+ Qt::MessageBox.information( self, "About QtScribble 5",
+ "This is the Scribble 5 application\n" +
+ "Copyright 1998 by Mathias Kalle Dalheimer\n")
+ end
+
+ def slotAboutQt()
+ Qt::MessageBox.aboutQt( self, "About Qt" )
+ end
+
+ def slotColorMenu( item )
+ case item
+ when COLOR_MENU_ID_BLACK
+ emit colorChanged( black )
+ when COLOR_MENU_ID_RED
+ emit colorChanged( darkRed )
+ when COLOR_MENU_ID_BLUE
+ emit colorChanged( darkBlue )
+ when COLOR_MENU_ID_GREEN
+ emit colorChanged( darkGreen )
+ when COLOR_MENU_ID_YELLOW
+ emit colorChanged( yellow )
+ end
+ end
+
+
+ #
+ # This is the slot for the menu item File/Load. It opens a
+ # Qt::FileDialog to ask the user for a filename, then emits a save()
+ # signal with the filename as parameter.
+ #
+ def slotLoad()
+ # Open a file dialog for loading. The default directory is the
+ # current directory, the filter *.bmp.
+ #
+ filename = Qt::FileDialog.getOpenFileName( ".", "*.bmp", self )
+ if !filename.nil?
+ emit load( filename )
+ end
+ end
+
+ #
+ # This is the slot for the menu item File/Load. It opens a
+ # Qt::FileDialog to ask the user for a filename, then emits a save()
+ # signal with the filename as parameter.
+ #
+ def slotSave()
+ # Open a file dialog for saving. The default directory is the
+ # current directory, the filter *.bmp.
+ #
+ filename = Qt::FileDialog.getSaveFileName( ".", "*.bmp", self )
+ if !filename.nil?
+ emit save( filename )
+ end
+ end
+end
+
+myapp = Qt::Application.new(ARGV)
+mywidget = ScribbleWindow.new()
+mywidget.setGeometry(50, 500, 400, 400)
+
+myapp.setMainWidget(mywidget)
+mywidget.show()
+myapp.exec()
diff --git a/qtruby/rubylib/examples/ruboids/Manifest b/qtruby/rubylib/examples/ruboids/Manifest
new file mode 100644
index 00000000..4fe3f97a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/Manifest
@@ -0,0 +1,26 @@
+Manifest
+README
+TODO
+boids.properties
+generateManifest.rb
+index.html
+release.rb
+ruboids/
+ Boid.rb
+ BoidView.rb
+ Camera.rb
+ CameraDialog.rb
+ Canvas.rb
+ Cloud.rb
+ CloudView.rb
+ Flock.rb
+ Graphics.rb
+ Params.rb
+ Point.rb
+ Thing.rb
+ Triangle.rb
+ View.rb
+ World.rb
+ WorldWindow.rb
+ info.rb
+ ruboids.rb
diff --git a/qtruby/rubylib/examples/ruboids/README b/qtruby/rubylib/examples/ruboids/README
new file mode 100644
index 00000000..5417037a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/README
@@ -0,0 +1,53 @@
+INTRODUCTION
+============
+
+RuBoids is a Boids simulation written in Ruby and using OpenGL and Qt. For
+information on Boids, see http://www.red3d.com/cwr/boids/.
+
+Ruby is an object-oriented scripting language by Yukihiro Matsumoto. The
+official Ruby Web site (http://www.ruby-lang.org/) contains information and
+pointers to resources for this wonderful language.
+
+RuBoids is developed and maintained by Jim Menard (<jimm@io.com>). The
+latest version of RuBoids can be found on the Ruby Application Archive or
+on the official RuBoids Web page
+(http://www.io.com/~jimm/downloads/ruboids/).
+
+RUNNING
+=======
+
+ cd ruboids
+ ruboids.rb
+
+RuBoids looks for an optional properties file. If none is specified on the
+command line, it looks for a file named 'boids.properties' in the current
+directory. For example, to load the example properties file in this
+directory:
+
+ cd ruboids
+ ruboids.rb ../boids.properties
+
+DEPENDENCIES
+============
+
+RuBoids requires the OpenGL and Qt packages, which can be found on the Ruby
+Application Archive.
+
+COPYING
+=======
+
+RuBoids is copyrighted free software by Jim Menard and is released under the
+same license as Ruby. See the Ruby license
+(http://www.ruby-lang.org/en/LICENSE.txt).
+
+RuBoids may be freely copied in its entirety providing this notice, all
+source code, all documentation, and all other files are included.
+
+RuBoids is copyright (c) 2001 by Jim Menard.
+
+WARRANTY
+========
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/qtruby/rubylib/examples/ruboids/TODO b/qtruby/rubylib/examples/ruboids/TODO
new file mode 100644
index 00000000..25fe501d
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/TODO
@@ -0,0 +1,29 @@
+BUGS
+====
+
+* Boid rotation.
+
+* Frustum.
+
+TO DO
+=====
+
+* Comment the code.
+
+* More documentation.
+
+* Save/restore params (e.g. camera position).
+
+POSSIBLE ADDITIONS
+==================
+
+* Make sphere output more efficient by using strips or fans.
+
+* Boids-eye view: camera follows position of a boid. This is not hard, but
+ I have to fix boid rotation first.
+
+* Velocity and destination influence proportional to distance from other
+ boids. Boids that are farther away have less influence on your velocity
+ and destination.
+
+* Boids that are behind you don't influence you because you can't see them.
diff --git a/qtruby/rubylib/examples/ruboids/boids.properties b/qtruby/rubylib/examples/ruboids/boids.properties
new file mode 100644
index 00000000..20bb5001
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/boids.properties
@@ -0,0 +1,33 @@
+# This is an example configuration file for RuBoids. It sets all of the
+# possible properties. The values here are the default values set in
+# Params.rb.
+
+world.sleep_millis = 75
+world.width = 400
+world.height = 400
+world.depth = 400
+window.width = 500
+window.height = 500
+flock.boids = 10
+boid.max_speed = 30
+boid.bounds_limit_pull = 5
+boid.bounds_limit_above_ground_level = 5
+boid.wing_length = 10
+boid.personal_space_dist = 12
+boid.square_of_personal_space_dist = 144
+boid.max_perching_turns = 150
+boid.perch_wing_flap_percent = 30
+cloud.count = 10
+cloud.min_speed = 2
+cloud.max_speed = 50
+cloud.min_bubbles = 3
+cloud.max_bubbles = 10
+cloud.max_bubble_radius = 10
+cloud.min_altitude = 250
+camera.x = 0
+camera.y = 0
+camera.z = 60
+camera.rot_x = 50
+camera.rot_y = 10
+camera.rot_z = 0
+camera.zoom = 1
diff --git a/qtruby/rubylib/examples/ruboids/generateManifest.rb b/qtruby/rubylib/examples/ruboids/generateManifest.rb
new file mode 100755
index 00000000..f877b0b3
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/generateManifest.rb
@@ -0,0 +1,42 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+# This script builds the Manifest file. It can be run stand-alone, but
+# is normally used from within release.rb.
+#
+
+def recurseDirectory(io, dirName, indentLevel)
+ Dir.entries(dirName).sort.each { | f |
+ next if f =~ /^\.\.?/
+ fileName = "#{dirName}/#{f}"
+ fileName.sub!(/^\.\//, '')
+ if File.directory?(fileName)
+ io.puts "\t" * indentLevel + fileName + '/'
+ recurseDirectory(io, fileName, indentLevel + 1)
+ else
+ io.puts "\t" * indentLevel + f
+ end
+ }
+end
+
+def generateManifest
+ io = nil
+ begin
+ io = File.open('Manifest', 'w')
+ recurseDirectory(io, '.', 0)
+ ensure
+ io.close() if io
+ end
+end
+
+if $0 == __FILE__
+ generateManifest()
+end
+
+
+
+
diff --git a/qtruby/rubylib/examples/ruboids/index.html b/qtruby/rubylib/examples/ruboids/index.html
new file mode 100644
index 00000000..9b320f8e
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/index.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<html>
+<head>
+<title>RuBoids</title>
+<link rel="stylesheet" href="../../style.css" type="text/css">
+</head>
+<body background="../../images/gradient_bg.gif" bgcolor="white">
+<!--#exec cgi="../../cgi-bin/log_visitor.cgi" -->
+
+<table width="100%">
+ <tr>
+ <td valign="top">
+ <table width="100" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td valign="top"><font size="-1">
+<script language="JavaScript"><!--
+PREFIX = "../../"; // -->
+</script>
+<!-- #include virtual="/~jimm/menu.js"-->
+<A href="../../index.html">
+<IMG src="../../images/KeyMaster.gif"
+width="32" height="32" alt="Home" border="0"></A><BR>
+<A href="../../index.html">Home</A><BR>
+<A href="../nqxml/index.html">NQXML</A><BR>
+RuBoids<BR>
+<A href="../../computers.html">Computers</A><BR>
+<A href="../../java.html">Java</A><BR>
+<A href="../../beos.html">BeOS</A><BR>
+<A href="../../ftp_sites.html">FTP sites</A><BR>
+<A href="../../music.html">Music</A><BR>
+<A href="../../midi_ref.html">MIDI Reference</A><BR>
+<A href="../../keymaster.html">KeyMaster</A><BR>
+<A href="../../MIDI_Through.html">MIDI Through</A><BR>
+<A href="../../jimm.html">Narcissism</A><BR>
+<A href="../../resume.html">Resume</A><BR>
+<A href="../../urls.html">Links</A><BR>
+<A href="../../map.html">Site Map</A><BR>
+
+
+ </font></td>
+ </tr>
+ </table>
+ </td>
+ <td valign="top">
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr valign="top">
+ <td>
+
+<div align="right">
+<font size="+3"><b>RuBoids</b></font>
+<img src="../../images/computer.gif" width="32" height="32"
+ alt="[home]" border="0">
+</div><br>
+<hr>
+
+<h1>Introduction</h1>
+
+<p>
+RuBoids is a Boids simulation written in Ruby and using OpenGL and Qt. For
+information on Boids, see <a
+href="http://www.red3d.com/cwr/boids/">http://www.red3d.com/cwr/boids/</a>.
+</p>
+
+<p>
+Ruby is an object-oriented scripting language by Yukihiro Matsumoto. Visit
+the official <a href="http://www.ruby-lang.org/">Ruby Web site</a> for more
+information.
+</p>
+
+<p>
+</p>
+
+<p>
+RuBoids is developed and maintained by Jim Menard, <a
+href="mailto:jimm@io.com">jimm@io.com</a>. The official
+Web page of RuBoids is <a
+href="http://www.io.com/~jimm/downloads/RuBoids/">http://www.io.com/~jimm/downloads/RuBoids/</a>,
+where the latest release may be found.
+</p>
+
+
+<h1>Dependencies</h1>
+
+<p>
+RuBoids requires the OpenGL and Qt packages, which can be found on the <a
+href="html://www.ruby-lang.org/en/raa.html">Ruby Application Archive</a>.
+</p>
+
+
+<h1>Download</h1>
+
+<p>
+Download the latest version, <a href="ruboids-0.0.1.tar.gz">RuBoids version
+0.0.1</a>.
+</p>
+
+<!--
+<p>
+Earlier versions:
+</p>
+
+<ul>
+<li><a href="RuBoids-0.0.1.tar.gz">Version 0.0.1</a></li>
+</ul>
+-->
+
+<h1>Bugs</h1>
+
+<p>
+Boids don't rotate properly. In other words, they point in the wrong
+direction.
+</p>
+
+
+<h1>Copying</h1>
+
+<p>
+RuBoids is copyrighted free software by Jim Menard and is released under
+the same license as Ruby.
+</p>
+
+<h1>Warranty</h1>
+
+<p>
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+</p>
+
+<hr>
+Back to my <a href="../../index.html">home page</a>, or the
+<a href="../../map.html">Site Map</a>.<br>
+<font size="-1">
+<i>Page last modified on
+<!--#config timefmt="%B %d, %Y" -->
+<!--#echo var="LAST_MODIFIED" -->
+by <a href="mailto:jimm@io.com">me</a>.</i>
+<br>Contents &copy; 2001 by Jim Menard. All rights reserved.
+</font>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/qtruby/rubylib/examples/ruboids/release.rb b/qtruby/rubylib/examples/ruboids/release.rb
new file mode 100755
index 00000000..d82ba154
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/release.rb
@@ -0,0 +1,152 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+# This script gathers everything needed to release RuBoids into one directory
+# and, if requested, publishes the contents to the RuBoids Web site.
+#
+# usage:
+#
+# release.rb [--publish, -p]
+#
+# Specifying --publish or -p causes the resulting files to be published
+# to the Web site.
+#
+
+require 'net/ftp'
+require 'ftools' # For makedirs and install
+require 'generateManifest' # For--you guessed it--generating the Manifest
+
+# Start looking for RUBOIDS classes in this directory.
+# This forces us to use the local copy of RUBOIDS, even if there is
+# a previously installed version out there somewhere.
+$LOAD_PATH[0, 0] = '.'
+
+require 'ruboids/info' # For Version string
+
+FILE_PERMISSION = 0644
+DIR_PERMISSION = 0755
+
+PUBLISH_FLAG = '-p'
+RUBOIDS_DIR = 'ruboids'
+DOCS_DIR = '.'
+#DOCS_HTML_DIR = "#{DOCS_DIR}/README"
+
+RUBOIDS_DIR_WITH_VERSION = "#{RUBOIDS_DIR}-#{Version}"
+RELEASE_DIR = "/tmp/#{RUBOIDS_DIR_WITH_VERSION}_release"
+#RELEASE_HTML_DIR = "#{RELEASE_DIR}/README"
+
+DOWNLOAD_FILE = "#{DOCS_DIR}/index.html"
+#DOCBOOK_FILE = "#{DOCS_DIR}/README.sgml"
+
+WEB_SITE = 'io.com'
+WEB_DIR = 'public-web/downloads/ruboids'
+
+# Copies all files from `fromDir' into the release directory. Sets the
+# permissions of all files to 0644.
+def copyFiles(fromDir, toDir, match=nil)
+ Dir.foreach(fromDir) { | f |
+ next if f =~ /^\.\.?/ || (!match.nil? && !(f =~ match))
+ File.install("#{fromDir}/#{f}", toDir, FILE_PERMISSION)
+ }
+end
+
+# Recursively removes the contents of a directory.
+def rmDirectory(dirName)
+ return unless File.exists?(dirName)
+ Dir.foreach(dirName) { | f |
+ next if f =~ /^\.\.?/
+ path = "#{dirName}/#{f}"
+ rmDirectory(path) if File.directory?(path)
+ File.delete(path) if !File.directory?(path)
+ }
+
+end
+
+# Recursively sends files and directories.
+def sendToWebSite(ftp, releaseDir, webDir)
+ ftp.chdir(webDir)
+ Dir.foreach(releaseDir) { | f |
+ next if f =~ /^\.\.?/
+ path = "#{releaseDir}/#{f}"
+ if File.directory?(path)
+ begin
+ ftp.mkdir(f)
+ rescue Net::FTPPermError
+ # ignore; it's OK if the directory already exists
+ end
+ sendToWebSite(ftp, path, f)
+ ftp.chdir('..')
+ else
+ ftp.putbinaryfile(path, f)
+ end
+ }
+end
+
+def ensureVersionInFile(fileName, regex)
+ lines = File.open(fileName).grep(regex)
+ found = lines.detect { | line | line =~ /#{Version}/o }
+ if !found
+ $stderr.puts "Warning: it looks like the #{fileName} version number" +
+ " is incorrect"
+ end
+end
+
+# ================================================================
+# main
+# ================================================================
+
+# Make sure the docs mention the correct version number.
+#ensureVersionInFile(DOWNLOAD_FILE, /Download the latest/)
+#ensureVersionInFile(DOCBOOK_FILE, /releaseinfo/)
+
+# Empty release dir if it already exists.
+rmDirectory(RELEASE_DIR)
+
+# (Re)create release dir. This makes RELEASE_HTML_DIR, whose parent
+# is RELEASE_DIR. Therefore, RELEASE_DIR is created as well.
+#File.makedirs(RELEASE_HTML_DIR)
+File.makedirs(RELEASE_DIR)
+
+# Recreate the full documentation (creating README and docs/README) and copy
+# the HTML files to the release directory. Finally, clean up the docs
+# directory.
+
+#system("cd #{DOCS_DIR} && make")
+#copyFiles(DOCS_DIR, RELEASE_DIR, /\.html$/)
+#copyFiles(DOCS_HTML_DIR, RELEASE_HTML_DIR, /\.html$/)
+copyFiles(DOCS_DIR, RELEASE_DIR, 'index.html')
+
+# Generate the Manifest file.
+generateManifest()
+
+# Create .tar.gz file. We temporarily rename the RUBOIDS folder to
+# "ruboids-X.Y.Z", tar and gzip that directory, then restore its original
+# name.
+Dir.chdir('..')
+File.rename(RUBOIDS_DIR, RUBOIDS_DIR_WITH_VERSION)
+system("tar -czf #{RELEASE_DIR}/#{RUBOIDS_DIR_WITH_VERSION}.tar.gz " +
+ RUBOIDS_DIR_WITH_VERSION)
+File.chmod(FILE_PERMISSION, "#{RELEASE_DIR}/#{RUBOIDS_DIR_WITH_VERSION}.tar.gz")
+File.rename(RUBOIDS_DIR_WITH_VERSION, RUBOIDS_DIR)
+
+# ftp files if requested
+if !ARGV.empty? && ARGV[0] == PUBLISH_FLAG
+ require 'net/ftp'
+
+ # Ask for ftp username and password
+ guess = ENV['LOGNAME'] || ENV['USER']
+ print "username [#{guess}]: "
+ username = $stdin.gets().chomp()
+ username = guess if username.empty?
+ print "password: "
+ password = $stdin.gets().chomp()
+
+ # ftp files to web site
+ ftp = Net::FTP.open(WEB_SITE, username, password)
+ sendToWebSite(ftp, RELEASE_DIR, WEB_DIR)
+ ftp.close()
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb b/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb
new file mode 100644
index 00000000..38ac7bcc
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb
@@ -0,0 +1,141 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'BoidView'
+require 'Flock'
+require 'Point'
+require 'Params'
+
+class Boid < Thing
+
+ attr_accessor :maxSpeed, :maxSpeedSquared, :perchingTurnsLeft,
+ :wingFlapPos, :almostGroundLevel, :flock
+
+ def initialize(pos = nil)
+ super(pos, nil)
+ init
+ end
+
+ def init
+ @maxSpeed = $PARAMS['boid_max_speed']
+ @maxSpeedSquared = @maxSpeed * @maxSpeed
+ @flock = nil # set by flock when flock adds to self
+ @wingFlapPos = rand(7)
+ @perchingTurnsLeft = 0
+ @almostGroundLevel = 5.0
+
+ @view = BoidView.new(self)
+ end
+
+ def move
+ # Flap wings. Only flap occasionally if not perching.
+ if (@perchingTurnsLeft == 0 ||
+ rand(100) < $PARAMS['boid_perch_wing_flap_percent'])
+ @wingFlapPos = (@wingFlapPos + 1) & 7
+ end
+
+ if @perchingTurnsLeft > 0
+ # Only take off when wing flap position == 2.
+ if --@perchingTurnsLeft == 0 && @wingFlapPos != 2
+ @perchingTurnsLeft = (8 + 2 - @wingFlapPos) & 7
+ return
+ end
+ end
+
+ moveTowardsFlockCenter()
+ avoidOthers()
+ matchOthersVelocities()
+ boundPosition()
+ limitSpeed()
+
+ super() # Add velocity vector to position.
+
+ # Boids at ground level perch for a while.
+ if @position.y < @almostGroundLevel
+ @position.y = @almostGroundLevel
+ @vector.x = @vector.y = @vector.z = 0
+ @perchingTurnsLeft =
+ rand($PARAMS['boid_max_perching_turns'])
+ end
+ end
+
+ def moveTowardsFlockCenter()
+ flockCenter = @flock.centerExcluding(self)
+ flockCenter.subtractPoint(@position)
+ # Move 1% of the way towards the center
+ flockCenter.divideBy(100.0)
+
+ @vector.addPoint(flockCenter)
+ end
+
+ def avoidOthers()
+ c = Point.new()
+ @flock.members.each { | b |
+ if b != self
+ otherPos = b.position
+ if @position.squareOfDistanceTo(otherPos) <
+ $PARAMS['boid_square_of_personal_space_dist']
+ c.addPoint(@position)
+ c.subtractPoint(otherPos)
+ end
+ end
+ }
+ @vector.addPoint(c)
+ end
+
+ def matchOthersVelocities()
+ vel = Point.new()
+ flock.members.each { | b |
+ if b != self
+ vel.addPoint(b.vector)
+ end
+ }
+ vel.divideBy(flock.members.length - 1)
+ vel.subtractPoint(@vector)
+ vel.divideBy(8)
+
+ @vector.addPoint(vel)
+ end
+
+ def boundPosition()
+ v = Point.new
+
+ halfWidth = $PARAMS['world_width'] / 2
+ halfHeight = $PARAMS['world_height'] / 2
+ halfDepth = $PARAMS['world_depth'] / 2
+
+ if position.x < -halfWidth
+ v.x = $PARAMS['boid_bounds_limit_pull']
+ elsif position.x > halfWidth
+ v.x = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ if position.y < -halfHeight + almostGroundLevel +
+ $PARAMS['boid_bounds_limit_above_ground_level']
+ v.y = $PARAMS['boid_bounds_limit_pull']
+ elsif position.y > halfHeight
+ v.y = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ if position.z < -halfDepth
+ v.z = $PARAMS['boid_bounds_limit_pull']
+ elsif position.z > halfDepth
+ v.z = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ @vector.addPoint(v)
+ end
+
+ def limitSpeed()
+ speedSquared = Point::ORIGIN.squareOfDistanceTo(@vector)
+ if speedSquared > @maxSpeedSquared
+ f = Math.sqrt(speedSquared) * @maxSpeed
+ @vector.divideBy(f)
+ end
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb b/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb
new file mode 100644
index 00000000..f2fc1288
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb
@@ -0,0 +1,159 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'View'
+
+class BoidView < View
+
+ BODY_COLOR = [0, 0, 0]
+ BEAK_COLOR = [0.75, 0.5, 0.0]
+ SHADOW_COLOR = [0.25, 0.55, 0.25]
+
+ HALF_WING_BASE = 3
+ HALF_LENGTH = 5
+ HALF_THICKNESS = 1
+ NOSE_LENGTH = 3
+
+ @@object = nil
+ @@shadow = nil
+ @@wings = nil
+ @@wingsShadows = nil
+
+ def initialize(model)
+ super(model, [0, 0, 0])
+ @wings = nil
+ @wingsShadows = nil
+ end
+
+ def makeObject
+ @@object = BoidView.makeObject() unless @@object
+ @object = @@object
+ @wings = @@wings
+ end
+
+ def makeShadow
+ BoidView.makeShadow() unless @@shadow
+ @shadow = @@shadow
+ @wingsShadows = @@wingsShadows
+ end
+
+ def drawObject
+ super()
+
+ angle = 0
+ case model.wingFlapPos
+ when 0
+ angle = 60
+ when 1, 7
+ angle = 30
+ when 2, 6
+ angle = 0
+ when 3, 5
+ angle = -30
+ when 4
+ angle = -60
+ end
+
+ PushMatrix()
+ Rotate(angle, 0, 0, 1)
+ CallList(@wings[0])
+ Rotate(angle * -2, 0, 0, 1)
+ CallList(@wings[1])
+ PopMatrix()
+ end
+
+ def BoidView.makeObject
+ makeWings()
+
+ object = GenLists(1)
+ NewList(object, COMPILE)
+
+ makeBody()
+ makeNose()
+
+ EndList()
+
+ return object
+ end
+
+ def BoidView.makeShadow
+ @@shadow = GenLists(1)
+ NewList(@@shadow, COMPILE)
+
+ p0 = Point::ORIGIN.dup()
+ p1 = Point::ORIGIN.dup()
+ dims = Point.new(HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ p0.subtractPoint(dims)
+ p1.addPoint(dims)
+
+ groundLevel = -($PARAMS['world_height'] / 2) + 1
+
+ Color(SHADOW_COLOR)
+ Begin(QUADS)
+ Vertex(p1.x, groundLevel, p0.z)
+ Vertex(p0.x, groundLevel, p0.z)
+ Vertex(p0.x, groundLevel, p1.z)
+ Vertex(p1.x, groundLevel, p1.z)
+ End()
+# Begin(TRIANGLES)
+# Vertex(p1.x, groundLevel, p1.z)
+# Vertex(0, groundLevel, p0.z)
+# Vertex(p0.x, groundLevel, p1.z)
+# End()
+
+ EndList()
+ end
+
+ def BoidView.makeBody
+ p0 = Point::ORIGIN.dup()
+ p1 = Point::ORIGIN.dup()
+ dims = Point.new(HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ p0.subtractPoint(dims)
+ p1.addPoint(dims)
+
+ Color(BODY_COLOR)
+ Graphics.boxFromCorners(p0, p1)
+ end
+
+ def BoidView.makeWings
+ @@wings = []
+ len = -$PARAMS['boid_wing_length']
+ @@wings << makeOneWing(len)
+ @@wings << makeOneWing(-len)
+ end
+
+ def BoidView.makeOneWing(len)
+ wing = GenLists(1)
+ NewList(wing, COMPILE)
+
+ Color(BODY_COLOR)
+ Begin(TRIANGLES)
+
+ Vertex(0, 0, -HALF_WING_BASE)
+ Vertex(len, 0, 0)
+ Vertex(0, 0, HALF_WING_BASE)
+
+ End()
+ EndList()
+ return wing
+ end
+
+ def BoidView.makeNose()
+ Color(BEAK_COLOR)
+ Begin(TRIANGLE_FAN)
+
+ Vertex(0, 0, HALF_LENGTH + NOSE_LENGTH)
+ Vertex( HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ Vertex(-HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ Vertex(-HALF_THICKNESS, -HALF_THICKNESS, HALF_LENGTH)
+ Vertex( HALF_THICKNESS, -HALF_THICKNESS, HALF_LENGTH)
+
+ End()
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb b/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb
new file mode 100644
index 00000000..787fc4af
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Params'
+
+class Camera
+
+ attr_accessor :position, :rotation, :zoom
+
+ def initialize
+ @position = Point.new($PARAMS['camera_x'],
+ $PARAMS['camera_y'],
+ $PARAMS['camera_z'])
+ @rotation = Point.new($PARAMS['camera_rot_x'],
+ $PARAMS['camera_rot_y'],
+ $PARAMS['camera_rot_z'])
+ @zoom = $PARAMS['camera_zoom']
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb b/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb
new file mode 100644
index 00000000..6e01db15
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb
@@ -0,0 +1,213 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'World'
+require 'Camera'
+
+class Adjustor
+ attr_accessor :slider, :num, :origValue
+ def initialize(slider, num, origValue = 0)
+ @slider = slider
+ @num = num
+ @origValue = origValue
+ end
+ def setSlider(val); @slider.setValue(val); end
+ def setNum(val); @num.setNum(val); end
+ def set(val)
+ setSlider(val)
+ setNum(val)
+ end
+ def reset
+ set(@origValue)
+ return @origValue
+ end
+end
+
+class CameraDialog < Qt::Dialog
+ slots 'slotReset()', 'slotLocXChanged(int)',
+ 'slotLocYChanged(int)', 'slotLocZChanged(int)',
+ 'slotRotationXChanged(int)', 'slotRotationYChanged(int)',
+ 'slotRotationZChanged(int)', 'slotZoomChanged(int)'
+
+ def initialize(parent)
+ super
+ @locAdjustors = []
+ @rotationAdjustors = []
+ @otherAdjustors = []
+ @avoidUpdates = false
+
+ @camera = World.instance.camera
+
+ # Remember values for reset
+ @origCamera = @camera.dup()
+
+ # Group and layout widgets
+ vLayout = Qt::VBoxLayout.new(self, 5)
+
+ locBox = Qt::GroupBox.new('Location', self, 'locBox')
+ rotationBox = Qt::GroupBox.new('Rotation', self, 'rotationBox')
+ otherBox = Qt::GroupBox.new('Other', self, 'otherBox')
+
+ locLayout = Qt::GridLayout.new(locBox, 5, 3, 20)
+ rotationLayout = Qt::GridLayout.new(rotationBox, 5, 3, 20)
+ otherLayout = Qt::GridLayout.new(otherBox, 3, 3, 20)
+ buttonLayout = Qt::HBoxLayout.new()
+
+ vLayout.addWidget(locBox)
+ vLayout.addWidget(rotationBox)
+ vLayout.addWidget(otherBox)
+ vLayout.addSpacing(10)
+ vLayout.addLayout(buttonLayout)
+
+ # Add extra space at the top of each layout so the group box title
+ # doesn't get squished.
+ locLayout.addRowSpacing(0, 15)
+ rotationLayout.addRowSpacing(0, 15)
+ otherLayout.addRowSpacing(0, 15)
+
+ # Contents of camera location box
+ @locAdjustors << addSlider(1, locBox, locLayout, 'X', -1000, 1000, 1,
+ 'slotLocXChanged(int)', @camera.position.x)
+ @locAdjustors << addSlider(2, locBox, locLayout, 'Y', -1000, 1000, 1,
+ 'slotLocYChanged(int)', @camera.position.y)
+ @locAdjustors << addSlider(3, locBox, locLayout, 'Z', -1000, 1000, 1,
+ 'slotLocZChanged(int)', @camera.position.z)
+
+ # Contents of camera rotation box
+ @rotationAdjustors << addSlider(1, rotationBox, rotationLayout, 'X',
+ 0, 360, 1, 'slotRotationXChanged(int)',
+ @camera.rotation.x)
+ @rotationAdjustors << addSlider(2, rotationBox, rotationLayout, 'Y',
+ 0, 360, 1, 'slotRotationYChanged(int)',
+ @camera.rotation.y)
+ @rotationAdjustors << addSlider(3, rotationBox, rotationLayout, 'Z',
+ 0, 360, 1, 'slotRotationZChanged(int)',
+ @camera.rotation.z)
+
+ @otherAdjustors << addSlider(1, otherBox, otherLayout, 'Zoom',
+ 1, 100, 1, 'slotZoomChanged(int)',
+ @camera.zoom * 10.0)
+ @otherAdjustors[0].origValue = @camera.zoom
+
+ # The Close button
+ button = Qt::PushButton.new('Close', self, 'Dialog Close')
+ connect(button, SIGNAL('clicked()'), self, SLOT('close()'))
+ button.setDefault(true)
+ button.setFixedSize(button.sizeHint())
+ buttonLayout.addWidget(button)
+
+ # The Close button
+ button = Qt::PushButton.new('Reset', self, 'Dialog Reset')
+ connect(button, SIGNAL('clicked()'), self, SLOT('slotReset()'))
+ button.setFixedSize(button.sizeHint())
+ buttonLayout.addWidget(button)
+
+ # 15 layout management
+ locLayout.activate()
+ rotationLayout.activate()
+ otherLayout.activate()
+ vLayout.activate()
+
+ resize(0, 0)
+
+ setCaption('Camera Settings')
+ end
+
+ def addSlider(row, box, layout, label, min, max, pageStep, slot,
+ initialValue)
+ # Label
+ text = Qt::Label.new(label, box)
+ text.setMinimumSize(text.sizeHint())
+ layout.addWidget(text, row, 0)
+
+ # Slider
+ slider = Qt::Slider.new(min, max, pageStep, initialValue,
+ Qt::Slider::Horizontal, box)
+ slider.setMinimumSize(slider.sizeHint())
+ slider.setMinimumWidth(180)
+ layout.addWidget(slider, row, 1)
+
+ # Connection from slider signal to our slot
+ connect(slider, SIGNAL('valueChanged(int)'), self, SLOT(slot))
+
+ # Number display
+ num = Qt::Label.new('XXXXX', box)
+ num.setMinimumSize(num.sizeHint())
+ num.setFrameStyle(Qt::Frame::Panel | Qt::Frame::Sunken)
+ num.setAlignment(AlignRight | AlignVCenter)
+ num.setNum(initialValue)
+
+ layout.addWidget(num, row, 2)
+
+ return Adjustor.new(slider, num, initialValue)
+ end
+
+ def cameraChanged
+ World.instance.setupTranslation() unless @avoidUpdates
+ end
+
+ def slotLocXChanged(val)
+ @locAdjustors[0].setNum(val)
+ @camera.position.x = val
+ cameraChanged()
+ end
+
+ def slotLocYChanged(val)
+ @locAdjustors[1].setNum(val)
+ @camera.position.y = val
+ cameraChanged()
+ end
+
+ def slotLocZChanged(val)
+ @locAdjustors[2].setNum(val)
+ @camera.position.z = val
+ cameraChanged()
+ end
+
+ def slotRotationXChanged(val)
+ @rotationAdjustors[0].setNum(val)
+ @camera.rotation.x = val
+ cameraChanged()
+ end
+
+ def slotRotationYChanged(val)
+ @rotationAdjustors[1].setNum(val)
+ @camera.rotation.y = val
+ cameraChanged()
+ end
+
+ def slotRotationZChanged(val)
+ @rotationAdjustors[2].setNum(val)
+ @camera.rotation.z = val
+ cameraChanged()
+ end
+
+ def slotZoomChanged(val)
+ @otherAdjustors[0].setNum(val)
+ @camera.zoom = val / 10.0
+ cameraChanged()
+ end
+
+ def slotReset
+ @avoidUpdates = true
+
+ @camera.position.x = @locAdjustors[0].reset()
+ @camera.position.y = @locAdjustors[1].reset()
+ @camera.position.z = @locAdjustors[2].reset()
+
+ @camera.rotation.x = @rotationAdjustors[0].reset()
+ @camera.rotation.y = @rotationAdjustors[1].reset()
+ @camera.rotation.z = @rotationAdjustors[2].reset()
+
+ @camera.zoom = @otherAdjustors[0].reset()
+
+ @avoidUpdates = false
+ cameraChanged()
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb b/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb
new file mode 100644
index 00000000..91ed934b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb
@@ -0,0 +1,144 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'opengl'
+require 'World'
+require 'Cloud'
+require 'Flock'
+require 'Params'
+require 'Camera'
+
+include GL
+
+class Canvas < Qt::GLWidget
+
+ GRASS_COLOR = [0, 0.75, 0]
+ MDA_ROTATE = :MDA_ROTATE
+ MDA_ZOOM = :MDA_ZOOM
+ MDA_CHANGE_FOCUS = :MDA_CHANGE_FOCUS
+
+ def initialize(parent = nil, name = '')
+ super
+ @grassObject = nil
+# catchEvent
+ end
+
+ def update
+ updateGL()
+ end
+
+ def initializeGL()
+ ClearColor(0.4, 0.4, 1.0, 0.0) # Let OpenGL clear to light blue
+ @grassObject = makeGrassObject()
+ ShadeModel(FLAT)
+ end
+
+ def paintGL()
+ Enable(DEPTH_TEST)
+ Clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT)
+
+ MatrixMode(MODELVIEW)
+
+ camera = World.instance.camera
+
+ LoadIdentity()
+ Rotate(camera.rotation.x, 1, 0, 0)
+ Rotate(camera.rotation.y, 0, 1, 0)
+ Rotate(camera.rotation.z, 0, 0, 1.0)
+ Translate(-camera.position.x, -camera.position.y, -camera.position.z)
+ Scale(camera.zoom, camera.zoom, camera.zoom)
+
+ CallList(@grassObject)
+
+ World.instance.clouds.each { | cloud | cloud.draw() }
+ World.instance.flock.draw()
+ end
+
+ # Set up the OpenGL view port, matrix mode, etc.
+ def resizeGL(w, h)
+ Viewport(0, 0, w, h)
+ MatrixMode(PROJECTION)
+ LoadIdentity()
+
+# # left, right, bottom, top, front, back (focal_length)
+ halfXSize = $PARAMS['world_width'] / 2 * 1.25
+ halfYSize = $PARAMS['world_height'] / 2 * 1.25
+ halfZSize = $PARAMS['world_depth'] / 2 * 1.25
+
+# Frustum(-halfXSize, halfXSize, -halfYSize, halfYSize,
+# 5, halfZSize * 2)
+
+ Ortho(-halfXSize, halfXSize, -halfYSize, halfYSize,
+ -halfZSize, halfZSize)
+
+ MatrixMode(MODELVIEW)
+ end
+
+ def makeGrassObject
+ halfXSize = $PARAMS['world_width']
+ halfYSize = $PARAMS['world_depth'] / 2
+ halfZSize = $PARAMS['world_height']
+
+ list = GenLists(1)
+ NewList(list, COMPILE)
+ LineWidth(2.0)
+ Begin(QUADS)
+
+ Color(GRASS_COLOR)
+ # Counter-clockwise
+ Vertex( halfXSize, -halfYSize, halfZSize)
+ Vertex(-halfXSize, -halfYSize, halfZSize)
+ Vertex(-halfXSize, -halfYSize, -halfZSize)
+ Vertex( halfXSize, -halfYSize, -halfZSize)
+
+ End()
+ EndList()
+ return list
+ end
+
+ def mousePressEvent(e)
+ @mouseLoc = e.pos()
+ case e.button()
+ when Qt::LeftButton
+ @mouseDragAction = MDA_ZOOM
+ when Qt::RightButton
+ @mouseDragAction = MDA_ROTATE
+ when Qt::MidButton
+ @mouseDragAction = MDA_CHANGE_FOCUS
+ end
+ end
+
+ # Rotate around sphere with right (#2) button. Zoom with left button.
+ # Change focus with left button.
+ def mouseMoveEvent(e)
+ return if @mouseLoc.nil?
+
+ dx = dy = 0
+ if e.x() != @mouseLoc.x()
+ dx = e.x() - @mouseLoc.x() # move right increases dx
+ @mouseLoc.setX(e.x())
+ end
+ if e.y() != @mouseLoc.y()
+ dy = @mouseLoc.y() - e.y() # move up increases dy
+ @mouseLoc.setY(e.y())
+ end
+
+ return if dx == 0 && dy == 0
+
+ case @mouseDragAction
+ when MDA_ZOOM
+ return if (dy == 0)
+ World.instance.camera.zoom += 0.1 * -dy
+ when MDA_ROTATE
+ break
+ when MDA_CHANGE_FOCUS
+ break
+ end
+ World.instance.setupTranslation()
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb b/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb
new file mode 100644
index 00000000..5d30222a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Thing'
+require 'CloudView'
+require 'Params'
+
+class Bubble
+
+ attr_reader :loc, :radius, :color
+
+ def initialize
+ @radius = rand($PARAMS['cloud_max_bubble_radius']) + 1
+ @loc = Point.new(0, rand(8) - 4, rand(8) - 4)
+ c = 0.85 + rand() * 0.15
+ @color = [c, c, c]
+ end
+
+end
+
+
+class Cloud < Thing
+
+ attr_reader :speed, :bubbles, :width
+
+ def initialize
+ minSpeed = $PARAMS['cloud_min_speed']
+ minBubbles = $PARAMS['cloud_min_bubbles']
+ @speed = rand($PARAMS['cloud_max_speed'] - minSpeed) + minSpeed
+ numBubbles = rand($PARAMS['cloud_max_bubbles'] - minBubbles) +
+ minBubbles
+ @bubbles = []
+ prevBubble = nil
+ (0 ... numBubbles).each { | i |
+ bubble = Bubble.new()
+ if !prevBubble.nil?
+ bubble.loc.x = prevBubble.loc.x +
+ rand((prevBubble.radius + bubble.radius) * 0.66)
+ end
+
+ @bubbles[i] = prevBubble = bubble
+ }
+
+ @width = bubbles.last.loc.x +
+ @bubbles.first.radius + @bubbles.last.radius
+
+ @view = CloudView.new(self)
+ end
+
+ def move
+ @position.x += pixelsPerSecToPixelsPerMove(speed)
+ halfWorldWidth = $PARAMS['world_width']
+ if (@position.x >= halfWorldWidth / 2)
+ @position.x = -(halfWorldWidth + @width)
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb b/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb
new file mode 100644
index 00000000..75c62177
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'View'
+require 'Cloud'
+require 'Params'
+require 'World'
+require 'Graphics'
+
+class CloudView < View
+
+ def initialize(cloud)
+ super(cloud)
+ end
+
+ def makeObject
+ @object = GenLists(1)
+ NewList(@object, COMPILE)
+
+ @model.bubbles.each { | bubble |
+ Color(bubble.color)
+ PushMatrix()
+ Translate(bubble.loc.x, bubble.loc.y, bubble.loc.z)
+ Scale(bubble.radius, bubble.radius, bubble.radius)
+ Graphics.sphere()
+ PopMatrix()
+ }
+
+ EndList()
+ end
+
+ def makeShadow
+ @shadow = GenLists(1)
+ NewList(@shadow, COMPILE)
+
+ groundLevel = -($PARAMS['world_height'] / 2) + 1
+ @model.bubbles.each { | bubble |
+ Color(shadowColorForHeight(model.position.y + bubble.loc.y))
+ PushMatrix()
+ Translate(bubble.loc.x, groundLevel, bubble.loc.z)
+ Scale(bubble.radius, 1.0, bubble.radius)
+ Graphics.circle(2)
+ PopMatrix()
+ }
+
+ EndList()
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb b/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb
new file mode 100644
index 00000000..4d476a2b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Flock'
+require 'Boid'
+require 'Params'
+
+class Flock
+ attr_reader :members
+
+ def initialize
+ @members = []
+ end
+
+ def add(boid)
+ @members << boid
+ boid.flock = self
+ end
+
+ def draw
+ @members.each { | boid | boid.draw() }
+ end
+
+ def move
+ @members.each { | boid | boid.move() }
+ end
+
+ # Return distance between two boid's positions.
+ def distBetween(b1, b2)
+ return b1.position.distanceTo(b2.position)
+ end
+
+ # Center of mass
+ def centerExcluding(b)
+ p = Point.new()
+ @members.each { | boid |
+ p.addPoint(boid.position) unless boid == b
+ }
+ p.divideBy(@members.length - 1)
+ return p
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb b/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb
new file mode 100644
index 00000000..5e982208
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb
@@ -0,0 +1,278 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Triangle'
+
+class Graphics
+
+ DEFAULT_SPHERE_ITERATIONS = 3
+
+ XPLUS = Point.new(1, 0, 0) # X
+ XMINUS = Point.new(-1, 0, 0)# -X
+ YPLUS = Point.new(0, 1, 0) # Y
+ YMINUS = Point.new(0, -1, 0)# -Y
+ ZPLUS = Point.new(0, 0, 1) # Z
+ ZMINUS = Point.new(0, 0, -1)# -Z
+
+ # defined w/counter-clockwise triangles
+ OCTAHEDRON = [
+ Triangle.new(YPLUS, ZPLUS, XPLUS),
+ Triangle.new(XMINUS, ZPLUS, YPLUS),
+ Triangle.new(YMINUS, ZPLUS, XMINUS),
+ Triangle.new(XPLUS, ZPLUS, YMINUS),
+ Triangle.new(ZMINUS, YPLUS, XPLUS),
+ Triangle.new(ZMINUS, XMINUS , YPLUS),
+ Triangle.new(ZMINUS, YMINUS , XMINUS),
+ Triangle.new(ZMINUS, XPLUS, YMINUS)
+ ]
+ # Defines counter-clockwise points used in OpenGL TRIANGLE_STRIP to
+ # create a circle on the X/Z plane. Don't include center point here;
+ # It is added when outputting the circle.
+ SQUARE = [
+ XPLUS, ZMINUS, XMINUS, ZPLUS, XPLUS
+ ]
+
+ @@spheres = Hash.new()
+ @@circles = Hash.new()
+
+ def Graphics.radiansToDegrees(rad)
+ return rad * 180.0 / Math::PI
+ end
+
+ def Graphics.degreesToRadians(deg)
+ return deg * Math::PI / 180.0
+ end
+
+ # Given a vector, return a point containing x, y, z rotation angles.
+ #
+ # atan2(x, y) = the angle formed with the x axis by the ray from the
+ # origin to the point {x,y}
+ def Graphics.rotations(v)
+ return Point::ORIGIN.dup() if v.nil?
+ return v if v == Point::ORIGIN
+
+ x = Math.atan2(v.y, v.z)
+ y = Math.atan2(v.z, v.x)
+ z = Math.atan2(v.y, v.x)
+
+ rot = Point.new(z, x, y)
+ rot.add(Math::PI).multiplyBy(180.0).divideBy(Math::PI)
+
+ rot.x = rot.x.to_i
+ rot.y = rot.y.to_i
+ rot.z = rot.z.to_i
+
+ return rot
+ end
+
+ # Build box from corners. All faces are counter-clockwise.
+ def Graphics.boxFromCorners(p0, p1)
+ pa = p0.dup()
+ pb = p1.dup()
+
+ # Make sure all coords of pa are < all coords of pb
+ if pa.x > pb.x
+ tmp = pa.x; pa.x = pb.x; pb.x = tmp
+ end
+ if pa.y > pb.y
+ tmp = pa.y; pa.y = pb.y; pb.y = tmp
+ end
+ if pa.z > pb.z
+ tmp = pa.z; pa.z = pb.z; pb.z = tmp
+ end
+
+ Begin(QUAD_STRIP)
+
+ # top
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+ # top/front
+ Vertex(pb.x, pb.y, pb.z)
+ Vertex(pa.x, pb.y, pb.z)
+ # front/bottom
+ Vertex(pb.x, pa.y, pb.z)
+ Vertex(pa.x, pa.y, pb.z)
+ # bottom/back
+ Vertex(pb.x, pa.y, pa.z)
+ Vertex(pa.x, pa.y, pa.z)
+ # back/top
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+
+ End()
+
+ Begin(QUADS)
+
+ # left
+ Vertex(pa.x, pa.y, pb.z)
+ Vertex(pa.x, pa.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pb.z)
+
+ # right
+ Vertex(pb.x, pa.y, pb.z)
+ Vertex(pb.x, pa.y, pa.z)
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pb.x, pb.y, pb.z)
+
+ End()
+ end
+
+ # sphere() (and buildSphere()) - generate a triangle mesh approximating
+ # a sphere by recursive subdivision. First approximation is an
+ # octahedron; each level of refinement increases the number of
+ # triangles by a factor of 4.
+ #
+ # Level 3 (128 triangles) is a good tradeoff if gouraud shading is used
+ # to render the database.
+ #
+ # Usage: sphere [level] [counterClockwise]
+ #
+ # The value level is an integer >= 1 setting the recursion level
+ # (default = DEFAULT_SPHERE_ITERATIONS).
+ # The boolean counterClockwise causes triangles to be generated
+ # with vertices in counterclockwise order as viewed from
+ # the outside in a RHS coordinate system. The default is
+ # counter-clockwise.
+ #
+ # @author Jon Leech (leech@cs.unc.edu) 3/24/89 (C version)
+ # Ruby version by Jim Menard (jimm@io.com), May 2001.
+ def Graphics.sphere(iterations = DEFAULT_SPHERE_ITERATIONS,
+ counterClockwise = true)
+ if @@spheres[iterations].nil?
+ @@spheres[iterations] = buildSphere(iterations, OCTAHEDRON)
+ end
+ sphere = @@spheres[iterations]
+
+ Begin(TRIANGLES)
+ sphere.each { | triangle |
+ triangle.points.each { | p |
+ Vertex(p.x, p.y, p.z) if counterClockwise
+ Vertex(p.z, p.y, p.x) if !counterClockwise
+ }
+ }
+ End()
+ end
+
+ #
+ # Subdivide each triangle in the oldObj approximation and normalize
+ # the new points thus generated to lie on the surface of the unit
+ # sphere.
+ # Each input triangle with vertices labelled [0,1,2] as shown
+ # below will be turned into four new triangles:
+ #
+ # Make new points
+ # a = (0+2)/2
+ # b = (0+1)/2
+ # c = (1+2)/2
+ # 1
+ # /\ Normalize a, b, c
+ # / \
+ # b/____\ c Construct new counter-clockwise triangles
+ # /\ /\ [a,b,0]
+ # / \ / \ [c,1,b]
+ # /____\/____\ [c,b,a]
+ # 0 a 2 [2,c,a]
+ #
+ #
+ # The normalize step (which makes each point a, b, c unit distance
+ # from the origin) is where we can modify the sphere's shape.
+ #
+ def Graphics.buildSphere(iterations, sphere)
+ oldObj = sphere
+ # Subdivide each starting triangle (maxlevel - 1) times
+ iterations -= 1
+ iterations.times {
+ # Create a new object. Allocate 4 * the number of points in the
+ # the current approximation.
+ newObj = Array.new(oldObj.length * 4)
+
+ j = 0
+ oldObj.each { | oldt |
+ # New midpoints
+ a = Point.midpoint(oldt.points[0], oldt.points[2])
+ a.normalize!()
+ b = Point.midpoint(oldt.points[0], oldt.points[1])
+ b.normalize!()
+ c = Point.midpoint(oldt.points[1], oldt.points[2])
+ c.normalize!()
+
+ # New triangeles. Their vertices are counter-clockwise.
+ newObj[j] = Triangle.new(a, b, oldt.points[0])
+ j += 1
+ newObj[j] = Triangle.new(c, oldt.points[1], b)
+ j += 1
+ newObj[j] = Triangle.new(c, b, a)
+ j += 1
+ newObj[j] = Triangle.new(oldt.points[2], c, a)
+ j += 1
+ }
+
+ # Continue subdividing new triangles
+ oldObj = newObj
+ }
+ return oldObj
+ end
+
+ # Creates a circle in the X/Z plane. To have the circle's normal
+ # point down (-Y), specify clockwise instead of counter-clockwise.
+ # To create the circle in another plane, call OpenGL's Rotate() method
+ # before calling this.
+ def Graphics.circle(iterations = DEFAULT_SPHERE_ITERATIONS,
+ counterClockwise = true)
+ if @@circles[iterations].nil?
+ @@circles[iterations] = buildCircle(iterations, SQUARE)
+ end
+ circle = @@circles[iterations]
+
+ Begin(TRIANGLE_FAN)
+ Vertex(0, 0, 0)
+ if counterClockwise
+ circle.each { | p | Vertex(p.x, 0, p.z) }
+ else
+ circle.reverse.each { | p | Vertex(p.x, 0, p.z) }
+ end
+ End()
+ end
+
+ # Different than buildSphere because we are creating triangles to
+ # be used in an OpenGL TRIANGLE_FAN operation. Thus the first point
+ # (the center) is always inviolate. We create new points between
+ # the remaining points.
+ def Graphics.buildCircle(iterations, circle)
+ oldObj = circle
+ # Subdivide each starting line segment (maxlevel - 1) times
+ iterations -= 1
+ iterations.times {
+ # Create a new object. Allocate 2 * the number of points in the
+ # the current approximation. Subtract one because the last point
+ # (same as the first point) is simply copied.
+ newObj = Array.new(oldObj.length * 2 - 1)
+
+ prevP = nil
+ j = 0
+ oldObj.each { | p |
+ if !prevP.nil?
+ newObj[j] = prevP
+ j += 1
+
+ # New midpoint
+ a = Point.midpoint(prevP, p)
+ a.normalize!()
+ newObj[j] = a
+ j += 1
+ end
+ prevP = p
+ }
+ newObj[j] = prevP # Copy last point
+
+ # Continue subdividing new triangles
+ oldObj = newObj
+ }
+ return oldObj
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Params.rb b/qtruby/rubylib/examples/ruboids/ruboids/Params.rb
new file mode 100644
index 00000000..9ff57851
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Params.rb
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'singleton'
+
+$PARAMS = {
+ 'world_sleep_millis' => 75,
+ 'world_width' => 400,
+ 'world_height' => 400,
+ 'world_depth' => 400,
+ 'window_width' => 500,
+ 'window_height' => 500,
+ 'flock_boids' => 10,
+ 'boid_max_speed' => 30,
+ 'boid_bounds_limit_pull' => 5,
+ 'boid_bounds_limit_above_ground_level' => 5,
+ 'boid_wing_length' => 10,
+ 'boid_personal_space_dist' => 12,
+ 'boid_square_of_personal_space_dist' => 144,
+ 'boid_max_perching_turns' => 150,
+ 'boid_perch_wing_flap_percent' => 30,
+ 'cloud_count' => 10,
+ 'cloud_min_speed' => 2,
+ 'cloud_max_speed' => 50,
+ 'cloud_min_bubbles' => 3,
+ 'cloud_max_bubbles' => 10,
+ 'cloud_max_bubble_radius' => 10,
+ 'cloud_min_altitude' => 250,
+ 'camera_x' => 0,
+ 'camera_y' => 0,
+ 'camera_z' => 60,
+ 'camera_rot_x' => 50,
+ 'camera_rot_y' => 10,
+ 'camera_rot_z' => 0,
+ 'camera_zoom' => 1
+}
+
+class Params
+
+ @@reals = %w(
+world_width
+world_height
+world_depth
+boid_max_speed
+boid_bounds_limit_pull
+boid_bounds_limit_above_ground_level
+boid_wing_length
+boid_personal_space_dist
+boid_square_of_personal_space_dist
+cloud_min_speed
+cloud_max_speed
+cloud_max_bubble_radius
+cloud_min_altitude
+camera_x
+camera_y
+camera_z
+camera_rot_x
+camera_rot_y
+camera_rot_z
+camera_zoom
+)
+
+ def Params.readParamsFromFile(paramFileName)
+ File.open(paramFileName).each { | line |
+ line.chomp!
+ next if line.empty? || line =~ /^#/
+
+ key, value = line.split(/\s*=\s*/)
+ next unless value
+ key.downcase!()
+ key.gsub!(/\./, '_')
+
+ isReal = @@reals.include?(key)
+ value = value.to_f if isReal
+ value = value.to_i if !isReal
+ $PARAMS[key] = value
+ }
+ $PARAMS['boid_square_of_personal_space_dist'] =
+ $PARAMS['boid_personal_space_dist'] *
+ $PARAMS['boid_personal_space_dist']
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Point.rb b/qtruby/rubylib/examples/ruboids/ruboids/Point.rb
new file mode 100644
index 00000000..0331f795
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Point.rb
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+class Point
+
+ attr_accessor :x, :y, :z
+
+ # Return a new Point that is the midpoint on the line between two
+ # points.
+ def Point.midpoint(a, b)
+ return Point.new((a.x + b.x) * 0.5, (a.y + b.y) * 0.5,
+ (a.z + b.z) * 0.5)
+ end
+
+ def initialize(x = 0, y = 0, z = 0)
+ if x.kind_of?(Point)
+ @x = x.x
+ @y = x.y
+ @z = x.z
+ else
+ @x = x
+ @y = y
+ @z = z
+ end
+ end
+
+ ORIGIN = Point.new(0, 0, 0)
+
+ def ==(point)
+ return point.kind_of?(Point) &&
+ @x == point.x && @y == point.y && @z == point.z
+ end
+
+ # Normalize this point.
+ def normalize!
+ mag = @x * @x + @y * @y + @z * @z
+ if mag != 1.0
+ mag = 1.0 / Math.sqrt(mag)
+ @x *= mag
+ @y *= mag
+ @z *= mag
+ end
+ return self
+ end
+
+ # Return a new point that is a normalized version of this point.
+ def normalize
+ return self.dup().normalize!()
+ end
+
+ # Return a new point that is the cross product of this point and another.
+ # The cross product of two unit vectors is another vector that's at
+ # right angles to the first two (for example, a surface normal).
+ def crossProduct(p)
+ return Point.new(@y * p.z - @z * p.y, @z * p.x - @x * p.z,
+ @x * p.y - @y * p.x)
+ end
+
+ # Return the (scalar) dot product of this vector and another.
+ # The dot product of two vectors produces the cosine of the angle
+ # between them, multiplied by the lengths of those vectors. (The dot
+ # product of two normalized vectors equals cosine of the angle.)
+ def dotProduct(p)
+ return @x * p.x + @y * p.y + @z * p.z
+ end
+
+ # Return square of distance between this point and another.
+ def squareOfDistanceTo(p)
+ dx = p.x - @x
+ dy = p.y - @y
+ dz = p.z - @z
+ return dx * dx + dy * dy + dz * dz
+ end
+
+ # Return distance between this point and another.
+ def distanceTo(p)
+ dx = p.x - @x
+ dy = p.y - @y
+ dz = p.z - @z
+ return Math.sqrt(dx * dx + dy * dy + dz * dz)
+ end
+
+ def add(d)
+ @x += d
+ @y += d
+ @z += d
+ return self
+ end
+
+ def addPoint(p)
+ @x += p.x
+ @y += p.y
+ @z += p.z
+ return self
+ end
+
+
+ def subtract(d)
+ @x -= d
+ @y -= d
+ @z -= d
+ return self
+ end
+
+ def subtractPoint(p)
+ @x -= p.x
+ @y -= p.y
+ @z -= p.z
+ return self
+ end
+
+
+ def multiplyBy(d)
+ @x *= d
+ @y *= d
+ @z *= d
+ return self
+ end
+
+ def multiplyByPoint(p)
+ @x *= p.x
+ @y *= p.y
+ @z *= p.z
+ return self
+ end
+
+ def divideBy(d)
+ @x = @x / d
+ @y = @y / d
+ @z = @z / d
+ return self
+ end
+
+ def divideByPoint(p)
+ @x = @x / p.x
+ @y = @y / p.y
+ @z = @z / p.z
+ return self
+ end
+
+ def to_a
+ return [@x, @y, @z]
+ end
+
+ def to_s
+ return "Point<#{@x}, #{@y}, #{@z}>"
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb b/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb
new file mode 100644
index 00000000..9b6bfe5b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Point'
+
+class Thing
+
+ attr_accessor :position, :vector, :view
+
+ def initialize(pos = nil, vec = nil)
+ @position = pos ? pos : Point.new
+ @vector = vec ? vec : Point.new
+ end
+
+ def move
+ position.x += vector.x
+ position.y += vector.y
+ position.z += vector.z
+ end
+
+ def draw
+ view.draw() if view
+ end
+
+ def pixelsPerSecToPixelsPerMove(pixelsPerSecond)
+ pps = (pixelsPerSecond.to_f / (1000.0 / 75.0)).to_i
+ pps = 1 if pps == 0
+ return pps
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb b/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb
new file mode 100644
index 00000000..eedf69f9
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Point'
+
+class Triangle
+ attr_accessor :points
+
+ def initialize(p0 = Point::ORIGIN,
+ p1 = Point::ORIGIN,
+ p2 = Point::ORIGIN)
+ @points = []
+ @points << p0 ? p0 : Point::ORIGIN.dup()
+ @points << p1 ? p1 : Point::ORIGIN.dup()
+ @points << p2 ? p2 : Point::ORIGIN.dup()
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/View.rb b/qtruby/rubylib/examples/ruboids/ruboids/View.rb
new file mode 100644
index 00000000..a5323629
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/View.rb
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+# A lightweight view
+class View
+
+ SHADOW_COLOR = [ 0.25, 0.25, 0.25 ]
+
+ attr_accessor :model, :color, :object, :shadow
+
+ def initialize(model, color = nil)
+ super()
+ @model = model
+ @color = color
+ @object = nil
+ @shadow = nil
+ end
+
+ def makeObject
+ raise "subclass should implement"
+ end
+
+ def makeShadow
+ # Don't raise error; some models may not have a shadow
+ end
+
+ def drawObject
+ CallList(@object)
+ end
+
+ def drawShadow
+ CallList(@shadow) if @shadow
+ end
+
+ def draw
+ # We don't always have enough information to make the 3D objects
+ # at initialize() time.
+ makeObject() unless @object
+ makeShadow() unless @shadow
+
+ rot = Graphics.rotations(model.vector)
+
+ PushMatrix()
+
+ # Translate and rotate shadow. Rotation around y axis only.
+ Translate(model.position.x, 0, model.position.z)
+ Rotate(rot.y, 0, 1, 0) if rot.y.nonzero?
+
+ # Draw shadow.
+ drawShadow() unless @shadow.nil?
+
+ # Translate and rotate object. Rotate object around x and z axes (y
+ # axis already done for shadow).
+ Translate(0, model.position.y, 0)
+ Rotate(rot.x, 1, 0, 0) if rot.x.nonzero?
+ Rotate(rot.z, 0, 0, 1) if rot.z.nonzero?
+
+ # Draw object.
+ drawObject()
+
+ PopMatrix()
+ end
+
+ # Given the height of an object, return a shadow color. The shadow color
+ # gets lighter as heigt increases.
+ def shadowColorForHeight(height)
+ wh = $PARAMS['world_height']
+ ratio = (height + wh / 2.0) / wh
+
+ shadowColor = []
+ SHADOW_COLOR.each_with_index { | c0, i |
+ min = c0
+ max = Canvas::GRASS_COLOR[i]
+ if min > max
+ tmp = min
+ min = max
+ max = tmp
+ end
+ shadowColor << min + ratio * (max - min)
+ }
+ return shadowColor
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/World.rb b/qtruby/rubylib/examples/ruboids/ruboids/World.rb
new file mode 100644
index 00000000..17608bca
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/World.rb
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'singleton'
+require 'Qt'
+require 'Params'
+require 'Cloud'
+require 'Flock'
+require 'Boid'
+require 'Camera'
+require 'Canvas'
+
+class World < Qt::Object
+ slots 'slotMove()'
+
+ include Singleton
+
+ attr_accessor :canvas
+ attr_reader :width, :height, :depth, :camera, :clouds, :flock
+
+ def initialize
+ super
+ @width = $PARAMS['world_width']
+ @height = $PARAMS['world_height']
+ @depth = $PARAMS['world_depth']
+
+ @clouds = []
+ minAltitude = $PARAMS['cloud_min_altitude']
+ $PARAMS['cloud_count'].times {
+ c = Cloud.new
+ c.position =
+ Point.new(rand(@width) - @width / 2,
+ rand(@height) - @height / 2,
+ rand(@depth - minAltitude) - @depth / 2 + minAltitude)
+ @clouds << c
+ }
+ # Sort clouds by height so lower/darker shadows are drawn last
+ @clouds.sort { |a, b| a.position.y <=> b.position.y }
+
+ @flock = Flock.new
+ $PARAMS['flock_boids'].times {
+ b = Boid.new
+ b.position = Point.new(rand(@width) - @width / 2,
+ rand(@height) - @height / 2,
+ rand(@depth) - @depth / 2)
+ @flock.add(b) # flock will delete boid
+ }
+
+ @clock = Qt::Timer.new()
+ connect(@clock, SIGNAL('timeout()'), self, SLOT('slotMove()'))
+
+ @camera = Camera.new # Reads values from params
+ setupTranslation()
+ end
+
+ # Should be called whenever camera or screen changes.
+ def setupTranslation
+ @canvas.update() if @canvas
+ end
+
+ def start
+ @clock.start($PARAMS['world_sleep_millis'])
+ end
+
+ def slotMove
+ @clouds.each { | c | c.move() }
+ @flock.move()
+ @canvas.update() if @canvas
+
+ # Camera follow boid.
+# b = @flock.members.first
+# @camera.position = b.position
+# @camera.rotation = Graphics.rotations(b.vector)
+# @camera.zoom = 1.0
+
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb b/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb
new file mode 100644
index 00000000..56650ece
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'Canvas'
+require 'CameraDialog'
+
+class WorldWindow < Qt::MainWindow
+ slots 'slotMenuActivated(int)'
+
+ MENU_CAMERA_DIALOG = 1
+
+ attr_accessor :canvas
+
+ def initialize
+ super
+ setCaption("Boids")
+ setupMenubar()
+
+ @canvas = Canvas.new(self, "TheDamnCanvas")
+ setCentralWidget(@canvas)
+ setGeometry(0, 0, $PARAMS['window_width'],
+ $PARAMS['window_height'])
+ end
+
+ def setupMenubar
+
+ # Create and populate file menu
+ menu = Qt::PopupMenu.new(self)
+ menu.insertItem("Exit", $qApp, SLOT("quit()"), Qt::KeySequence.new(CTRL+Key_Q))
+
+ # Add file menu to menu bar
+ menuBar.insertItem("&File", menu)
+
+ # Create and populate options menu
+ menu = Qt::PopupMenu.new(self)
+ menu.insertItem("&Camera...", MENU_CAMERA_DIALOG, -1)
+
+ # Add options menu to menu bar and link it to method below
+ menuBar.insertItem("&Options", menu)
+ connect(menu, SIGNAL("activated(int)"), self, SLOT('slotMenuActivated(int)'))
+
+ end
+
+ def slotMenuActivated(id)
+ if id == MENU_CAMERA_DIALOG
+ CameraDialog.new(nil).exec()
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/info.rb b/qtruby/rubylib/examples/ruboids/ruboids/info.rb
new file mode 100644
index 00000000..fcfc50f6
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/info.rb
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+VERSION_MAJOR = 0
+VERSION_MINOR = 0
+VERSION_TWEAK = 1
+Version = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_TWEAK}"
+Copyright = 'Copyright (c) 2001 by Jim Menard <jimm@io.com>'
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb b/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb
new file mode 100755
index 00000000..b9bdecba
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb
@@ -0,0 +1,29 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'World'
+require 'WorldWindow'
+require 'Canvas'
+require 'Params'
+
+app = Qt::Application.new(ARGV)
+if (!Qt::GLFormat::hasOpenGL())
+ warning("This system has no OpenGL support. Exiting.")
+ exit -1
+end
+
+Params.readParamsFromFile(ARGV[0] || 'boids.properties')
+world = World.instance
+win = WorldWindow.new
+app.mainWidget = win
+
+World.instance.canvas = win.canvas
+win.show
+World.instance.start
+app.exec
diff --git a/qtruby/rubylib/examples/testcases/bugs.rb b/qtruby/rubylib/examples/testcases/bugs.rb
new file mode 100644
index 00000000..6b5e3153
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/bugs.rb
@@ -0,0 +1,57 @@
+require 'Qt'
+
+
+#### TODO ###
+# dup of qobject crash
+def bug1
+ p1 = Qt::Point.new(5,5)
+ p1.setX 5
+ p p1
+ p3 = p1.dup
+ p3.setX 5
+ p p3
+end
+#bug1
+
+
+#### FIXED ###
+def bug3
+ a = Qt::Application.new(ARGV)
+ @file = Qt::PopupMenu.new
+ @file.insertSeparator
+ Qt::debug_level = Qt::DebugLevel::High
+ p $qApp
+ @file.insertItem("Quit", $qApp, SLOT('quit()'))
+ @file.exec
+end
+#bug3
+
+
+class CPUWaster < Qt::Widget
+ def initialize(*k)
+ super(*k)
+ end
+ def draw
+ painter = Qt::Painter.new(self)
+ 0.upto(1000) { |i|
+ cw, ch = width, height
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(cw - 8)
+ y = rand(cw - 8)
+ w = rand(cw - x)
+ h = rand(cw - y)
+ brush = Qt::Brush.new(c)
+ brush.setStyle(Qt::Dense6Pattern)
+ Qt::debug_level = Qt::DebugLevel::High
+ painter.fillRect(Qt::Rect.new(x, y, w, h), brush)
+ Qt::debug_level = Qt::DebugLevel::Off
+ }
+ end
+end
+def bug4
+ Qt::Application.new(ARGV)
+ w = CPUWaster.new
+ w.show
+ w.draw
+end
+bug4
diff --git a/qtruby/rubylib/examples/testcases/error_reporting.rb b/qtruby/rubylib/examples/testcases/error_reporting.rb
new file mode 100644
index 00000000..e2012447
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/error_reporting.rb
@@ -0,0 +1,85 @@
+require 'Qt'
+
+#### CRASH ###
+# param mismatch?
+class Bug1 < Qt::PushButton
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug1.test
+ a = Qt::Application.new(ARGV)
+ w = Qt::VBox.new
+ hello = Bug1.new(a)
+ hello.resize(100, 30)
+ a.setMainWidget(w)
+ hello.show()
+ a.exec()
+ end
+end
+#Bug1.test
+
+
+#### MORE DEBUG INFO NEEDED ###
+# missing method
+class Bug2 < Qt::VBox
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug2.test
+ a = Qt::Application.new(ARGV)
+ w = Bug2.new
+ a.setMainWidget(w)
+ w.show2()
+ a.exec()
+ end
+end
+#Bug2.test
+
+
+#### MORE DEBUG INFO NEEDED ###
+# missing prototype
+class Bug2a < Qt::VBox
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug2a.test
+ a = Qt::Application.new(ARGV)
+ w = Bug2a.new
+ a.setMainWidget(w)
+ w.show(p)
+ a.exec()
+ end
+end
+Bug2a.test
+
+
+#### FIXED ###
+# no such constructor for PushButton
+class Bug3 < Qt::PushButton
+ def initialize
+ super
+ end
+ def Bug3.test
+ a = Qt::Application.new(ARGV)
+ hello = Bug3.new
+ hello.resize(100, 30)
+ a.setMainWidget(hello)
+ hello.show()
+ a.exec()
+ end
+end
+#Bug3.test
+
+
+#### FIXED ###
+# no *class* variable/method resize in PushButton
+class Bug4 < Qt::PushButton
+ def initialize
+ super
+ end
+ def Bug4.test
+ hello = Bug4
+ hello.resize(100, 30)
+ end
+end
+#Bug4.test
diff --git a/qtruby/rubylib/examples/testcases/opoverloading.rb b/qtruby/rubylib/examples/testcases/opoverloading.rb
new file mode 100644
index 00000000..1798a995
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/opoverloading.rb
@@ -0,0 +1,46 @@
+require 'Qt'
+
+class Qt::Point
+ def to_s
+ "(#{x}, #{y})"
+ end
+end
+
+$t = binding
+def test(str)
+ puts "#{str.ljust 25} => #{eval(str, $t)}"
+end
+
+test("p1 = Qt::Point.new(5,5)")
+test("p2 = Qt::Point.new(20,20)")
+test("p1 + p2")
+test("p1 - p2")
+test("-p1 + p2")
+test("p2 += p1")
+test("p2 -= p1")
+test("p2 * 3")
+
+class Qt::Region
+ def to_s
+ "(#{isNull})"
+ end
+end
+
+test("r1 = Qt::Region.new()")
+test("r2 = Qt::Region.new( 100,100,200,80, Qt::Region::Ellipse )")
+test("r1 + r2")
+
+class Qt::WMatrix
+ def to_s
+ "(#{m11}, #{m12}, #{m21}, #{m22}, #{dx}, #{dy})"
+ end
+end
+
+test("a = Math::PI/180 * 25") # convert 25 to radians
+test("sina = Math.sin(a)")
+test("cosa = Math.cos(a)")
+test("m1 = Qt::WMatrix.new(1, 0, 0, 1, 10, -20)") # translation matrix
+test("m2 = Qt::WMatrix.new( cosa, sina, -sina, cosa, 0, 0 )")
+test("m3 = Qt::WMatrix.new(1.2, 0, 0, 0.7, 0, 0)") # scaling matrix
+test("m = Qt::WMatrix.new")
+test("m = m3 * m2 * m1") # combine all transformations
diff --git a/qtruby/rubylib/examples/textedit/textedit.rb b/qtruby/rubylib/examples/textedit/textedit.rb
new file mode 100644
index 00000000..db905b4f
--- /dev/null
+++ b/qtruby/rubylib/examples/textedit/textedit.rb
@@ -0,0 +1,150 @@
+#!/usr/bin/ruby -w
+
+require 'Qt'
+require 'rexml/document'
+
+require '../base/rui.rb'
+
+class MyTextEditor < Qt::TextEdit
+ signals 'saved()'
+ slots 'insert_icon()', 'new()', 'open()', 'save_as()'
+ def initialize(w = nil)
+ @images = {}
+ @@next_image_id = 0
+ super(w)
+ self.setTextFormat(Qt::RichText)
+ end
+ def insert_richtext(richtext)
+ # todo, use a rand string
+ unique_string = '000___xxx123456789xxx___xxx123456789xxx___000'
+ insert(unique_string)
+ txt = self.text().gsub(unique_string, richtext)
+ self.setText(txt)
+ end
+ def next_image_id
+ @@next_image_id += 1
+ end
+ def load_image(fname, image_id)
+ pixmap = Qt::Pixmap.new(fname)
+ msfactory = Qt::MimeSourceFactory.defaultFactory
+ msfactory.setPixmap(image_id, pixmap)
+ @images[image_id] = fname
+ image_id
+ end
+ def insert_icon
+ fname = Qt::FileDialog.getOpenFileName
+ return if fname.nil?
+ image_id = "image_#{next_image_id}"
+ load_image(fname, image_id)
+ insert_richtext('<qt><img source="'+image_id+'"></qt>')
+ end
+ def createPopupMenu(pos) # virtual
+ pm = Qt::PopupMenu.new
+ pm.insertItem("Insert Image!", self, SLOT('insert_icon()'))
+ pm
+ end
+ def has_metadata
+ !@images.empty?
+ end
+ def metadata_fname(fname)
+ "#{fname}.metadata.xml"
+ end
+ def attempt_metadata_load(fname)
+ return unless File.exists?(metadata_fname(fname))
+ file = File.open(metadata_fname(fname))
+ @xmldoc = REXML::Document.new file
+ @xmldoc.root.elements.each("image") {
+ |image|
+ image_id = image.attributes["ident"]
+ img_fname = image.attributes["filename"]
+ load_image(img_fname, image_id)
+ }
+ end
+ def metadata_save_if_has(fname)
+ return if not has_metadata
+ metadata_doc = REXML::Document.new '<metadata/>'
+ @images.each {
+ |id, img_fname|
+ metadata_doc.root.add_element("image", {"filename"=>img_fname, "ident"=>id})
+ }
+ file = File.new(metadata_fname(fname), "w")
+ file.puts(metadata_doc)
+ file.close
+ end
+ def metadata_clear
+ @images = {}
+ end
+ def new(txt = "")
+ metadata_clear
+ self.setText(txt)
+ end
+ def open
+ fname = Qt::FileDialog.getOpenFileName
+ return if fname.nil?
+ unless File.exists?(fname)
+ Qt::MessageBox.critical(self, "File Does Not Exist", "Sorry, unable to find the requested file!")
+ return
+ end
+ return if fname.nil?
+ txt = File.open(fname).gets(nil)
+ metadata_clear
+ attempt_metadata_load(fname)
+ self.setText(txt)
+ end
+ def save_as
+ fname = Qt::FileDialog.getSaveFileName
+ return if fname.nil?
+ if File.exists?(fname)
+ Qt::MessageBox.critical(self, "File Already Exists", "Sorry, file already exists. Please choose a non-existing filename!")
+ return save_as
+ end
+ file = File.new(fname, "w")
+ file.puts(text())
+ file.close
+ metadata_save_if_has(fname)
+ emit saved()
+ end
+end
+
+class MyWidget < Qt::MainWindow
+ slots 'text_changed()', 'saved()'
+ def initialize()
+ super
+ @editor = MyTextEditor.new(self)
+ connect(@editor, SIGNAL('textChanged()'), self, SLOT('text_changed()'))
+ connect(@editor, SIGNAL('saved()'), self, SLOT('saved()'))
+
+ fileTools = Qt::ToolBar.new(self, "file operations")
+ fileMenu = Qt::PopupMenu.new(self)
+
+ actions = [
+ RAction.new("&New", Icons::FILE_NEW, @editor, SLOT('new()'), [fileTools, fileMenu]),
+ RAction.new("&Open...", Icons::FILE_OPEN, @editor, SLOT('open()'), [fileTools, fileMenu]),
+ @save = RAction.new("Save &As...", Icons::FILE_SAVE_AS, @editor, SLOT('save_as()'), [fileTools, fileMenu]),
+ RSeperator.new([fileMenu]),
+ RAction.new("E&xit", Icons::EXIT, $qApp, SLOT('quit()'), [fileMenu])
+ ]
+
+ build_actions(actions)
+
+ menubar = Qt::MenuBar.new(self)
+ menubar.insertItem("&File", fileMenu)
+
+ self.setCentralWidget(@editor)
+ end
+ def saved
+ @save.action.setEnabled(false)
+ end
+ def text_changed
+ @save.action.setEnabled(true)
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.show
+
+a.setMainWidget(w)
+a.exec()
+exit