diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 90825e2392b2d70e43c7a25b8a3752299a933894 (patch) | |
tree | e33aa27f02b74604afbfd0ea4f1cfca8833d882a /qtruby/rubylib/examples | |
download | tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'qtruby/rubylib/examples')
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 © 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 |