diff options
Diffstat (limited to 'examples/script')
77 files changed, 7958 insertions, 0 deletions
diff --git a/examples/script/README b/examples/script/README new file mode 100644 index 0000000..089a7fa --- /dev/null +++ b/examples/script/README @@ -0,0 +1,40 @@ +Qt is provided with a powerful embedded scripting environment through the QtScript +classes. + +These examples demonstrate the fundamental aspects of scripting applications +with Qt. + + +The example launcher provided with Qt can be used to explore each of the +examples in this directory. + +Documentation for these examples can be found via the Tutorial and Examples +link in the main Qt documentation. + + +Finding the Qt Examples and Demos launcher +========================================== + +On Windows: + +The launcher can be accessed via the Windows Start menu. Select the menu +entry entitled "Qt Examples and Demos" entry in the submenu containing +the Qt tools. + +On Mac OS X: + +For the binary distribution, the qtdemo executable is installed in the +/Developer/Applications/Qt directory. For the source distribution, it is +installed alongside the other Qt tools on the path specified when Qt is +configured. + +On Unix/Linux: + +The qtdemo executable is installed alongside the other Qt tools on the path +specified when Qt is configured. + +On all platforms: + +The source code for the launcher can be found in the demos/qtdemo directory +in the Qt package. This example is built at the same time as the Qt libraries, +tools, examples, and demonstrations. diff --git a/examples/script/calculator/calculator.js b/examples/script/calculator/calculator.js new file mode 100644 index 0000000..62c2cba --- /dev/null +++ b/examples/script/calculator/calculator.js @@ -0,0 +1,264 @@ +//! [0] +function Calculator(ui) +{ + this.ui = ui; + + this.pendingAdditiveOperator = ""; + this.pendingMultiplicativeOperator = ""; + this.sumInMemory = 0; + this.sumSoFar = 0; + this.factorSoFar = 0; + this.waitingForOperand = true; + + with (ui) { + display.text = "0"; + + zeroButton.clicked.connect(this, this.digitClicked); + oneButton.clicked.connect(this, "digitClicked"); + twoButton.clicked.connect(this, "digitClicked"); + threeButton.clicked.connect(this, "digitClicked"); + fourButton.clicked.connect(this, "digitClicked"); + fiveButton.clicked.connect(this, "digitClicked"); + sixButton.clicked.connect(this, "digitClicked"); + sevenButton.clicked.connect(this, "digitClicked"); + eightButton.clicked.connect(this, "digitClicked"); + nineButton.clicked.connect(this, "digitClicked"); + + pointButton.clicked.connect(this, "pointClicked"); + changeSignButton.clicked.connect(this, "changeSignClicked"); + + backspaceButton.clicked.connect(this, "backspaceClicked"); + clearButton.clicked.connect(this, "clear"); + clearAllButton.clicked.connect(this, "clearAll"); + + clearMemoryButton.clicked.connect(this, "clearMemory"); + readMemoryButton.clicked.connect(this, "readMemory"); + setMemoryButton.clicked.connect(this, "setMemory"); + addToMemoryButton.clicked.connect(this, "addToMemory"); + + divisionButton.clicked.connect(this, "multiplicativeOperatorClicked"); + timesButton.clicked.connect(this, "multiplicativeOperatorClicked"); + minusButton.clicked.connect(this, "additiveOperatorClicked"); + plusButton.clicked.connect(this, "additiveOperatorClicked"); + + squareRootButton.clicked.connect(this, "unaryOperatorClicked"); + powerButton.clicked.connect(this, "unaryOperatorClicked"); + reciprocalButton.clicked.connect(this, "unaryOperatorClicked"); + equalButton.clicked.connect(this, "equalClicked"); + } +} +//! [0] + +Calculator.prototype.abortOperation = function() +{ + this.clearAll(); + this.ui.display.text = "####"; +} + +Calculator.prototype.calculate = function(rightOperand, pendingOperator) +{ + if (pendingOperator == "+") { + this.sumSoFar += rightOperand; + } else if (pendingOperator == "-") { + this.sumSoFar -= rightOperand; + } else if (pendingOperator == "*") { + this.factorSoFar *= rightOperand; + } else if (pendingOperator == "/") { + if (rightOperand == 0) + return false; + this.factorSoFar /= rightOperand; + } + return true; +} + +//! [1] +Calculator.prototype.digitClicked = function() +{ + var digitValue = __qt_sender__.text - 0; + if ((digitValue == 0) && (this.ui.display.text == "0")) + return; + if (this.waitingForOperand) { + this.ui.display.clear(); + this.waitingForOperand = false; + } + this.ui.display.text += digitValue; +} +//! [1] + +Calculator.prototype.unaryOperatorClicked = function() +{ + var operand = this.ui.display.text - 0; + var result = 0; + if (__qt_sender__.text == "Sqrt") { + if (operand < 0) { + this.abortOperation(); + return; + } + result = Math.sqrt(operand); + } else if (__qt_sender__.text == "x^2") { + result = Math.pow(operand, 2); + } else if (__qt_sender__.text == "1/x") { + if (operand == 0.0) { + this.abortOperation(); + return; + } + result = 1 / operand; + } + this.ui.display.text = result + ""; + this.waitingForOperand = true; +} + +Calculator.prototype.additiveOperatorClicked = function() +{ + var operand = this.ui.display.text - 0; + + if (this.pendingMultiplicativeOperator.length != 0) { + if (!this.calculate(operand, this.pendingMultiplicativeOperator)) { + this.abortOperation(); + return; + } + this.ui.display.text = this.factorSoFar + ""; + operand = this.factorSoFar; + this.factorSoFar = 0; + this.pendingMultiplicativeOperator = ""; + } + + if (this.pendingAdditiveOperator.length != 0) { + if (!this.calculate(operand, this.pendingAdditiveOperator)) { + this.abortOperation(); + return; + } + this.ui.display.text = this.sumSoFar + ""; + } else { + this.sumSoFar = operand; + } + + this.pendingAdditiveOperator = __qt_sender__.text; + this.waitingForOperand = true; +} + +Calculator.prototype.multiplicativeOperatorClicked = function() +{ + var operand = this.ui.display.text - 0; + + if (this.pendingMultiplicativeOperator.length != 0) { + if (!this.calculate(operand, this.pendingMultiplicativeOperator)) { + this.abortOperation(); + return; + } + this.ui.display.text = this.factorSoFar + ""; + } else { + this.factorSoFar = operand; + } + + this.pendingMultiplicativeOperator = __qt_sender__.text; + this.waitingForOperand = true; +} + +Calculator.prototype.equalClicked = function() +{ + var operand = this.ui.display.text - 0; + + if (this.pendingMultiplicativeOperator.length != 0) { + if (!this.calculate(operand, this.pendingMultiplicativeOperator)) { + this.abortOperation(); + return; + } + operand = this.factorSoFar; + this.factorSoFar = 0.0; + this.pendingMultiplicativeOperator = ""; + } + if (this.pendingAdditiveOperator.length != 0) { + if (!this.calculate(operand, this.pendingAdditiveOperator)) { + this.abortOperation(); + return; + } + this.pendingAdditiveOperator = ""; + } else { + this.sumSoFar = operand; + } + + this.ui.display.text = this.sumSoFar + ""; + this.sumSoFar = 0.0; + this.waitingForOperand = true; +} + +Calculator.prototype.pointClicked = function() +{ + if (this.waitingForOperand) + this.ui.display.text = "0"; + if (this.ui.display.text.indexOf(".") == -1) + this.ui.display.text += "."; + this.waitingForOperand = false; +} + +//! [2] +Calculator.prototype.changeSignClicked = function() +{ + var text = this.ui.display.text; + var value = text - 0; + + if (value > 0) { + text = "-" + text; + } else if (value < 0) { + text = text.slice(1); + } + this.ui.display.text = text; +} +//! [2] + +Calculator.prototype.backspaceClicked = function() +{ + if (this.waitingForOperand) + return; + + var text = this.ui.display.text; + text = text.slice(0, -1); + if (text.length == 0) { + text = "0"; + this.waitingForOperand = true; + } + this.ui.display.text = text; +} + +Calculator.prototype.clear = function() +{ + if (this.waitingForOperand) + return; + + this.ui.display.text = "0"; + this.waitingForOperand = true; +} + +Calculator.prototype.clearAll = function() +{ + this.sumSoFar = 0.0; + this.factorSoFar = 0.0; + this.pendingAdditiveOperator = ""; + this.pendingMultiplicativeOperator = ""; + this.ui.display.text = "0"; + this.waitingForOperand = true; +} + +Calculator.prototype.clearMemory = function() +{ + this.sumInMemory = 0.0; +} + +Calculator.prototype.readMemory = function() +{ + this.ui.display.text = this.sumInMemory + ""; + this.waitingForOperand = true; +} + +Calculator.prototype.setMemory = function() +{ + this.equalClicked(); + this.sumInMemory = this.ui.display.text - 0; +} + +Calculator.prototype.addToMemory = function() +{ + this.equalClicked(); + this.sumInMemory += this.ui.display.text - 0; +} diff --git a/examples/script/calculator/calculator.pro b/examples/script/calculator/calculator.pro new file mode 100644 index 0000000..226d5f4 --- /dev/null +++ b/examples/script/calculator/calculator.pro @@ -0,0 +1,12 @@ +QT += script +CONFIG += uitools +RESOURCES += calculator.qrc +SOURCES += main.cpp + +contains(QT_CONFIG, scripttools): QT += scripttools + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/calculator +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro *.js *.ui +sources.path = $$[QT_INSTALL_EXAMPLES]/script/calculator +INSTALLS += target sources diff --git a/examples/script/calculator/calculator.qrc b/examples/script/calculator/calculator.qrc new file mode 100644 index 0000000..afa6686 --- /dev/null +++ b/examples/script/calculator/calculator.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/" > + <file>calculator.js</file> + <file>calculator.ui</file> + </qresource> +</RCC> diff --git a/examples/script/calculator/calculator.ui b/examples/script/calculator/calculator.ui new file mode 100644 index 0000000..bb519ba --- /dev/null +++ b/examples/script/calculator/calculator.ui @@ -0,0 +1,406 @@ +<ui version="4.0" > + <class>Calculator</class> + <widget class="QWidget" name="Calculator" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>314</width> + <height>301</height> + </rect> + </property> + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Fixed" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize" > + <size> + <width>314</width> + <height>301</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>314</width> + <height>301</height> + </size> + </property> + <property name="windowTitle" > + <string>Calculator</string> + </property> + <widget class="QToolButton" name="backspaceButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>50</y> + <width>91</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>Backspace</string> + </property> + </widget> + <widget class="QToolButton" name="clearButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>50</y> + <width>91</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>Clear</string> + </property> + </widget> + <widget class="QToolButton" name="clearAllButton" > + <property name="geometry" > + <rect> + <x>210</x> + <y>50</y> + <width>91</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>Clear All</string> + </property> + </widget> + <widget class="QToolButton" name="clearMemoryButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>MC</string> + </property> + </widget> + <widget class="QToolButton" name="readMemoryButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>MR</string> + </property> + </widget> + <widget class="QToolButton" name="setMemoryButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>MS</string> + </property> + </widget> + <widget class="QToolButton" name="addToMemoryButton" > + <property name="geometry" > + <rect> + <x>10</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>M+</string> + </property> + </widget> + <widget class="QToolButton" name="sevenButton" > + <property name="geometry" > + <rect> + <x>60</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>7</string> + </property> + </widget> + <widget class="QToolButton" name="eightButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>8</string> + </property> + </widget> + <widget class="QToolButton" name="nineButton" > + <property name="geometry" > + <rect> + <x>160</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>9</string> + </property> + </widget> + <widget class="QToolButton" name="fourButton" > + <property name="geometry" > + <rect> + <x>60</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>4</string> + </property> + </widget> + <widget class="QToolButton" name="fiveButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>5</string> + </property> + </widget> + <widget class="QToolButton" name="sixButton" > + <property name="geometry" > + <rect> + <x>160</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>6</string> + </property> + </widget> + <widget class="QToolButton" name="oneButton" > + <property name="geometry" > + <rect> + <x>60</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>1</string> + </property> + </widget> + <widget class="QToolButton" name="twoButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>2</string> + </property> + </widget> + <widget class="QToolButton" name="threeButton" > + <property name="geometry" > + <rect> + <x>160</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>3</string> + </property> + </widget> + <widget class="QToolButton" name="zeroButton" > + <property name="geometry" > + <rect> + <x>60</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>0</string> + </property> + </widget> + <widget class="QToolButton" name="pointButton" > + <property name="geometry" > + <rect> + <x>110</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>.</string> + </property> + </widget> + <widget class="QToolButton" name="changeSignButton" > + <property name="geometry" > + <rect> + <x>160</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>+-</string> + </property> + </widget> + <widget class="QToolButton" name="plusButton" > + <property name="geometry" > + <rect> + <x>210</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>+</string> + </property> + </widget> + <widget class="QToolButton" name="divisionButton" > + <property name="geometry" > + <rect> + <x>210</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>/</string> + </property> + </widget> + <widget class="QToolButton" name="timesButton" > + <property name="geometry" > + <rect> + <x>210</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>*</string> + </property> + </widget> + <widget class="QToolButton" name="minusButton" > + <property name="geometry" > + <rect> + <x>210</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>-</string> + </property> + </widget> + <widget class="QToolButton" name="squareRootButton" > + <property name="geometry" > + <rect> + <x>260</x> + <y>100</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>Sqrt</string> + </property> + </widget> + <widget class="QToolButton" name="powerButton" > + <property name="geometry" > + <rect> + <x>260</x> + <y>150</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>x^2</string> + </property> + </widget> + <widget class="QToolButton" name="reciprocalButton" > + <property name="geometry" > + <rect> + <x>260</x> + <y>200</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>1/x</string> + </property> + </widget> + <widget class="QToolButton" name="equalButton" > + <property name="geometry" > + <rect> + <x>260</x> + <y>250</y> + <width>41</width> + <height>41</height> + </rect> + </property> + <property name="text" > + <string>=</string> + </property> + </widget> + <widget class="QLineEdit" name="display" > + <property name="geometry" > + <rect> + <x>10</x> + <y>10</y> + <width>291</width> + <height>31</height> + </rect> + </property> + <property name="maxLength" > + <number>15</number> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/script/calculator/main.cpp b/examples/script/calculator/main.cpp new file mode 100644 index 0000000..4608aa5 --- /dev/null +++ b/examples/script/calculator/main.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QUiLoader> +#include <QtScript> +#include <QWidget> +#include <QFile> +#include <QMainWindow> +#include <QLineEdit> + +#ifndef QT_NO_SCRIPTTOOLS +#include <QScriptEngineDebugger> +#endif + +int main(int argc, char **argv) +{ + Q_INIT_RESOURCE(calculator); + + QApplication app(argc, argv); +//! [0a] + QScriptEngine engine; +//! [0a] + +#ifndef QT_NO_SCRIPTTOOLS + QScriptEngineDebugger debugger; + debugger.attachTo(&engine); + QMainWindow *debugWindow = debugger.standardWindow(); + debugWindow->resize(1024, 640); +#endif + +//! [0b] + QString scriptFileName(":/calculator.js"); + QFile scriptFile(scriptFileName); + scriptFile.open(QIODevice::ReadOnly); + engine.evaluate(scriptFile.readAll(), scriptFileName); + scriptFile.close(); +//! [0b] + +//! [1] + QUiLoader loader; + QFile uiFile(":/calculator.ui"); + uiFile.open(QIODevice::ReadOnly); + QWidget *ui = loader.load(&uiFile); + uiFile.close(); +//! [1] + +//! [2] + QScriptValue ctor = engine.evaluate("Calculator"); + QScriptValue scriptUi = engine.newQObject(ui, QScriptEngine::ScriptOwnership); + QScriptValue calc = ctor.construct(QScriptValueList() << scriptUi); +//! [2] + +#ifndef QT_NO_SCRIPTTOOLS + QLineEdit *display = qFindChild<QLineEdit*>(ui, "display"); + QObject::connect(display, SIGNAL(returnPressed()), + debugWindow, SLOT(show())); +#endif +//! [3] + ui->show(); + return app.exec(); +//! [3] +} diff --git a/examples/script/context2d/context2d.cpp b/examples/script/context2d/context2d.cpp new file mode 100644 index 0000000..d49cc3d --- /dev/null +++ b/examples/script/context2d/context2d.cpp @@ -0,0 +1,825 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "context2d.h" + +#include <QVariant> + +#include <math.h> +static const double Q_PI = 3.14159265358979323846; // pi + +#define DEGREES(t) ((t) * 180.0 / Q_PI) + +#define qClamp(val, min, max) qMin(qMax(val, min), max) +static QList<qreal> parseNumbersList(QString::const_iterator &itr) +{ + QList<qreal> points; + QString temp; + while ((*itr).isSpace()) + ++itr; + while ((*itr).isNumber() || + (*itr) == '-' || (*itr) == '+' || (*itr) == '.') { + temp = QString(); + + if ((*itr) == '-') + temp += *itr++; + else if ((*itr) == '+') + temp += *itr++; + while ((*itr).isDigit()) + temp += *itr++; + if ((*itr) == '.') + temp += *itr++; + while ((*itr).isDigit()) + temp += *itr++; + while ((*itr).isSpace()) + ++itr; + if ((*itr) == ',') + ++itr; + points.append(temp.toDouble()); + //eat spaces + while ((*itr).isSpace()) + ++itr; + } + + return points; +} + +QColor colorFromString(const QString &name) +{ + QString::const_iterator itr = name.constBegin(); + QList<qreal> compo; + if (name.startsWith("rgba(")) { + ++itr; ++itr; ++itr; ++itr; ++itr; + compo = parseNumbersList(itr); + if (compo.size() != 4) { + return QColor(); + } + //alpha seems to be always between 0-1 + compo[3] *= 255; + return QColor((int)compo[0], (int)compo[1], + (int)compo[2], (int)compo[3]); + } else if (name.startsWith("rgb(")) { + ++itr; ++itr; ++itr; ++itr; + compo = parseNumbersList(itr); + if (compo.size() != 3) { + return QColor(); + } + return QColor((int)qClamp(compo[0], qreal(0), qreal(255)), + (int)qClamp(compo[1], qreal(0), qreal(255)), + (int)qClamp(compo[2], qreal(0), qreal(255))); + } else { + //QRgb color; + //CSSParser::parseColor(name, color); + return QColor(name); + } +} + + +static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator) +{ + if ( compositeOperator == "source-over" ) { + return QPainter::CompositionMode_SourceOver; + } else if ( compositeOperator == "source-out" ) { + return QPainter::CompositionMode_SourceOut; + } else if ( compositeOperator == "source-in" ) { + return QPainter::CompositionMode_SourceIn; + } else if ( compositeOperator == "source-atop" ) { + return QPainter::CompositionMode_SourceAtop; + } else if ( compositeOperator == "destination-atop" ) { + return QPainter::CompositionMode_DestinationAtop; + } else if ( compositeOperator == "destination-in" ) { + return QPainter::CompositionMode_DestinationIn; + } else if ( compositeOperator == "destination-out" ) { + return QPainter::CompositionMode_DestinationOut; + } else if ( compositeOperator == "destination-over" ) { + return QPainter::CompositionMode_DestinationOver; + } else if ( compositeOperator == "darker" ) { + return QPainter::CompositionMode_SourceOver; + } else if ( compositeOperator == "lighter" ) { + return QPainter::CompositionMode_SourceOver; + } else if ( compositeOperator == "copy" ) { + return QPainter::CompositionMode_Source; + } else if ( compositeOperator == "xor" ) { + return QPainter::CompositionMode_Xor; + } + + return QPainter::CompositionMode_SourceOver; +} + +static QString compositeOperatorToString(QPainter::CompositionMode op) +{ + switch (op) { + case QPainter::CompositionMode_SourceOver: + return "source-over"; + case QPainter::CompositionMode_DestinationOver: + return "destination-over"; + case QPainter::CompositionMode_Clear: + return "clear"; + case QPainter::CompositionMode_Source: + return "source"; + case QPainter::CompositionMode_Destination: + return "destination"; + case QPainter::CompositionMode_SourceIn: + return "source-in"; + case QPainter::CompositionMode_DestinationIn: + return "destination-in"; + case QPainter::CompositionMode_SourceOut: + return "source-out"; + case QPainter::CompositionMode_DestinationOut: + return "destination-out"; + case QPainter::CompositionMode_SourceAtop: + return "source-atop"; + case QPainter::CompositionMode_DestinationAtop: + return "destination-atop"; + case QPainter::CompositionMode_Xor: + return "xor"; + case QPainter::CompositionMode_Plus: + return "plus"; + case QPainter::CompositionMode_Multiply: + return "multiply"; + case QPainter::CompositionMode_Screen: + return "screen"; + case QPainter::CompositionMode_Overlay: + return "overlay"; + case QPainter::CompositionMode_Darken: + return "darken"; + case QPainter::CompositionMode_Lighten: + return "lighten"; + case QPainter::CompositionMode_ColorDodge: + return "color-dodge"; + case QPainter::CompositionMode_ColorBurn: + return "color-burn"; + case QPainter::CompositionMode_HardLight: + return "hard-light"; + case QPainter::CompositionMode_SoftLight: + return "soft-light"; + case QPainter::CompositionMode_Difference: + return "difference"; + case QPainter::CompositionMode_Exclusion: + return "exclusion"; + default: + break; + } + return QString(); +} + +void Context2D::save() +{ + m_stateStack.push(m_state); +} + + +void Context2D::restore() +{ + if (!m_stateStack.isEmpty()) { + m_state = m_stateStack.pop(); + m_state.flags = AllIsFullOfDirt; + } +} + + +void Context2D::scale(qreal x, qreal y) +{ + m_state.matrix.scale(x, y); + m_state.flags |= DirtyTransformationMatrix; +} + + +void Context2D::rotate(qreal angle) +{ + m_state.matrix.rotate(DEGREES(angle)); + m_state.flags |= DirtyTransformationMatrix; +} + + +void Context2D::translate(qreal x, qreal y) +{ + m_state.matrix.translate(x, y); + m_state.flags |= DirtyTransformationMatrix; +} + + +void Context2D::transform(qreal m11, qreal m12, qreal m21, qreal m22, + qreal dx, qreal dy) +{ + QMatrix mat(m11, m12, + m21, m22, + dx, dy); + m_state.matrix *= mat; + m_state.flags |= DirtyTransformationMatrix; +} + + +void Context2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22, + qreal dx, qreal dy) +{ + QMatrix mat(m11, m12, + m21, m22, + dx, dy); + m_state.matrix = mat; + m_state.flags |= DirtyTransformationMatrix; +} + + +QString Context2D::globalCompositeOperation() const +{ + return compositeOperatorToString(m_state.globalCompositeOperation); +} + +void Context2D::setGlobalCompositeOperation(const QString &op) +{ + QPainter::CompositionMode mode = + compositeOperatorFromString(op); + m_state.globalCompositeOperation = mode; + m_state.flags |= DirtyGlobalCompositeOperation; +} + +QVariant Context2D::strokeStyle() const +{ + return m_state.strokeStyle; +} + +void Context2D::setStrokeStyle(const QVariant &style) +{ + if (qVariantCanConvert<CanvasGradient>(style)) { + CanvasGradient cg = qvariant_cast<CanvasGradient>(style); + m_state.strokeStyle = cg.value; + } else { + QColor color = colorFromString(style.toString()); + m_state.strokeStyle = color; + } + m_state.flags |= DirtyStrokeStyle; +} + +QVariant Context2D::fillStyle() const +{ + return m_state.fillStyle; +} + +//! [3] +void Context2D::setFillStyle(const QVariant &style) +{ + if (qVariantCanConvert<CanvasGradient>(style)) { + CanvasGradient cg = qvariant_cast<CanvasGradient>(style); + m_state.fillStyle = cg.value; + } else { + QColor color = colorFromString(style.toString()); + m_state.fillStyle = color; + } + m_state.flags |= DirtyFillStyle; +} +//! [3] + +qreal Context2D::globalAlpha() const +{ + return m_state.globalAlpha; +} + +void Context2D::setGlobalAlpha(qreal alpha) +{ + m_state.globalAlpha = alpha; + m_state.flags |= DirtyGlobalAlpha; +} + + +CanvasGradient Context2D::createLinearGradient(qreal x0, qreal y0, + qreal x1, qreal y1) +{ + QLinearGradient g(x0, y0, x1, y1); + return CanvasGradient(g); +} + + +CanvasGradient Context2D::createRadialGradient(qreal x0, qreal y0, + qreal r0, qreal x1, + qreal y1, qreal r1) +{ + QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0)); + return CanvasGradient(g); +} + +qreal Context2D::lineWidth() const +{ + return m_state.lineWidth; +} + +void Context2D::setLineWidth(qreal w) +{ + m_state.lineWidth = w; + m_state.flags |= DirtyLineWidth; +} + +//! [0] +QString Context2D::lineCap() const +{ + switch (m_state.lineCap) { + case Qt::FlatCap: + return "butt"; + case Qt::SquareCap: + return "square"; + case Qt::RoundCap: + return "round"; + default: ; + } + return QString(); +} + +void Context2D::setLineCap(const QString &capString) +{ + Qt::PenCapStyle style; + if (capString == "round") + style = Qt::RoundCap; + else if (capString == "square") + style = Qt::SquareCap; + else if (capString == "butt") + style = Qt::FlatCap; + m_state.lineCap = style; + m_state.flags |= DirtyLineCap; +} +//! [0] + +QString Context2D::lineJoin() const +{ + switch (m_state.lineJoin) { + case Qt::RoundJoin: + return "round"; + case Qt::BevelJoin: + return "bevel"; + case Qt::MiterJoin: + return "miter"; + default: ; + } + return QString(); +} + +void Context2D::setLineJoin(const QString &joinString) +{ + Qt::PenJoinStyle style; + if (joinString == "round") + style = Qt::RoundJoin; + else if (joinString == "bevel") + style = Qt::BevelJoin; + else if (joinString == "miter") + style = Qt::MiterJoin; + m_state.lineJoin = style; + m_state.flags |= DirtyLineJoin; +} + +qreal Context2D::miterLimit() const +{ + return m_state.miterLimit; +} + +void Context2D::setMiterLimit(qreal m) +{ + m_state.miterLimit = m; + m_state.flags |= DirtyMiterLimit; +} + +void Context2D::setShadowOffsetX(qreal x) +{ + m_state.shadowOffsetX = x; + m_state.flags |= DirtyShadowOffsetX; +} + +void Context2D::setShadowOffsetY(qreal y) +{ + m_state.shadowOffsetY = y; + m_state.flags |= DirtyShadowOffsetY; +} + +void Context2D::setShadowBlur(qreal b) +{ + m_state.shadowBlur = b; + m_state.flags |= DirtyShadowBlur; +} + +void Context2D::setShadowColor(const QString &str) +{ + m_state.shadowColor = colorFromString(str); + m_state.flags |= DirtyShadowColor; +} + +qreal Context2D::shadowOffsetX() const +{ + return m_state.shadowOffsetX; +} + +qreal Context2D::shadowOffsetY() const +{ + return m_state.shadowOffsetY; +} + + +qreal Context2D::shadowBlur() const +{ + return m_state.shadowBlur; +} + + +QString Context2D::shadowColor() const +{ + return m_state.shadowColor.name(); +} + + +void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h) +{ + beginPainting(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.setCompositionMode(QPainter::CompositionMode_Source); + m_painter.fillRect(QRectF(x, y, w, h), QColor(0, 0, 0, 0)); + m_painter.restore(); + scheduleChange(); +} + + +//! [1] +void Context2D::fillRect(qreal x, qreal y, qreal w, qreal h) +{ + beginPainting(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.fillRect(QRectF(x, y, w, h), m_painter.brush()); + m_painter.restore(); + scheduleChange(); +} +//! [1] + + +void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h) +{ + QPainterPath path; + path.addRect(x, y, w, h); + beginPainting(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + m_painter.strokePath(path, m_painter.pen()); + m_painter.restore(); + scheduleChange(); +} + + +void Context2D::beginPath() +{ + m_path = QPainterPath(); +} + + +void Context2D::closePath() +{ + m_path.closeSubpath(); +} + + +void Context2D::moveTo(qreal x, qreal y) +{ + QPointF pt = m_state.matrix.map(QPointF(x, y)); + m_path.moveTo(pt); +} + + +void Context2D::lineTo(qreal x, qreal y) +{ + QPointF pt = m_state.matrix.map(QPointF(x, y)); + m_path.lineTo(pt); +} + + +void Context2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y) +{ + QPointF cp = m_state.matrix.map(QPointF(cpx, cpy)); + QPointF xy = m_state.matrix.map(QPointF(x, y)); + m_path.quadTo(cp, xy); +} + + +void Context2D::bezierCurveTo(qreal cp1x, qreal cp1y, + qreal cp2x, qreal cp2y, qreal x, qreal y) +{ + QPointF cp1 = m_state.matrix.map(QPointF(cp1x, cp1y)); + QPointF cp2 = m_state.matrix.map(QPointF(cp2x, cp2y)); + QPointF end = m_state.matrix.map(QPointF(x, y)); + m_path.cubicTo(cp1, cp2, end); +} + + +void Context2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius) +{ + //FIXME: this is surely busted + QPointF st = m_state.matrix.map(QPointF(x1, y1)); + QPointF end = m_state.matrix.map(QPointF(x2, y2)); + m_path.arcTo(st.x(), st.y(), + end.x()-st.x(), end.y()-st.y(), + radius, 90); +} + + +void Context2D::rect(qreal x, qreal y, qreal w, qreal h) +{ + QPainterPath path; path.addRect(x, y, w, h); + path = m_state.matrix.map(path); + m_path.addPath(path); +} + +void Context2D::arc(qreal xc, qreal yc, qreal radius, + qreal sar, qreal ear, + bool anticlockwise) +{ + //### HACK + // In Qt we don't switch the coordinate system for degrees + // and still use the 0,0 as bottom left for degrees so we need + // to switch + sar = -sar; + ear = -ear; + anticlockwise = !anticlockwise; + //end hack + + float sa = DEGREES(sar); + float ea = DEGREES(ear); + + double span = 0; + + double xs = xc - radius; + double ys = yc - radius; + double width = radius*2; + double height = radius*2; + + if (!anticlockwise && (ea < sa)) { + span += 360; + } else if (anticlockwise && (sa < ea)) { + span -= 360; + } + + //### this is also due to switched coordinate system + // we would end up with a 0 span instead of 360 + if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) && + qFuzzyCompare(qAbs(span), 360))) { + span += ea - sa; + } + + QPainterPath path; + path.moveTo(QPointF(xc + radius * cos(sar), + yc - radius * sin(sar))); + + path.arcTo(xs, ys, width, height, sa, span); + path = m_state.matrix.map(path); + m_path.addPath(path); +} + + +void Context2D::fill() +{ + beginPainting(); + m_painter.fillPath(m_path, m_painter.brush()); + scheduleChange(); +} + + +void Context2D::stroke() +{ + beginPainting(); + m_painter.save(); + m_painter.setMatrix(m_state.matrix, false); + QPainterPath tmp = m_state.matrix.inverted().map(m_path); + m_painter.strokePath(tmp, m_painter.pen()); + m_painter.restore(); + scheduleChange(); +} + + +void Context2D::clip() +{ + m_state.clipPath = m_path; + m_state.flags |= DirtyClippingRegion; +} + + +bool Context2D::isPointInPath(qreal x, qreal y) const +{ + return m_path.contains(QPointF(x, y)); +} + + +ImageData Context2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh) +{ + Q_UNUSED(sx); + Q_UNUSED(sy); + Q_UNUSED(sw); + Q_UNUSED(sh); + return ImageData(); +} + + +void Context2D::putImageData(ImageData image, qreal dx, qreal dy) +{ + Q_UNUSED(image); + Q_UNUSED(dx); + Q_UNUSED(dy); +} + +Context2D::Context2D(QObject *parent) + : QObject(parent), m_changeTimerId(-1) +{ + reset(); +} + +const QImage &Context2D::endPainting() +{ + if (m_painter.isActive()) + m_painter.end(); + return m_image; +} + +void Context2D::beginPainting() +{ + if (!m_painter.isActive()) { + m_painter.begin(&m_image); + m_painter.setRenderHint(QPainter::Antialiasing); + if (!m_state.clipPath.isEmpty()) + m_painter.setClipPath(m_state.clipPath); + m_painter.setBrush(m_state.fillStyle); + m_painter.setOpacity(m_state.globalAlpha); + QPen pen; + pen.setBrush(m_state.strokeStyle); + if (pen.style() == Qt::NoPen) + pen.setStyle(Qt::SolidLine); + pen.setCapStyle(m_state.lineCap); + pen.setJoinStyle(m_state.lineJoin); + pen.setWidthF(m_state.lineWidth); + pen.setMiterLimit(m_state.miterLimit); + m_painter.setPen(pen); + } else { + if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) + m_painter.setClipPath(m_state.clipPath); + if (m_state.flags & DirtyFillStyle) + m_painter.setBrush(m_state.fillStyle); + if (m_state.flags & DirtyGlobalAlpha) + m_painter.setOpacity(m_state.globalAlpha); + if (m_state.flags & DirtyGlobalCompositeOperation) + m_painter.setCompositionMode(m_state.globalCompositeOperation); + if (m_state.flags & MDirtyPen) { + QPen pen = m_painter.pen(); + if (m_state.flags & DirtyStrokeStyle) + pen.setBrush(m_state.strokeStyle); + if (m_state.flags & DirtyLineWidth) + pen.setWidthF(m_state.lineWidth); + if (m_state.flags & DirtyLineCap) + pen.setCapStyle(m_state.lineCap); + if (m_state.flags & DirtyLineJoin) + pen.setJoinStyle(m_state.lineJoin); + if (m_state.flags & DirtyMiterLimit) + pen.setMiterLimit(m_state.miterLimit); + m_painter.setPen(pen); + } + m_state.flags = 0; + } +} + +void Context2D::clear() +{ + endPainting(); + m_image.fill(qRgba(0,0,0,0)); + scheduleChange(); +} + +void Context2D::reset() +{ + m_stateStack.clear(); + m_state.matrix = QMatrix(); + m_state.clipPath = QPainterPath(); + m_state.globalAlpha = 1.0; + m_state.globalCompositeOperation = QPainter::CompositionMode_SourceOver; + m_state.strokeStyle = Qt::black; + m_state.fillStyle = Qt::black; + m_state.lineWidth = 1; + m_state.lineCap = Qt::FlatCap; + m_state.lineJoin = Qt::MiterJoin; + m_state.miterLimit = 10; + m_state.shadowOffsetX = 0; + m_state.shadowOffsetY = 0; + m_state.shadowBlur = 0; + m_state.shadowColor = qRgba(0, 0, 0, 0); + m_state.flags = AllIsFullOfDirt; + clear(); +} + +void Context2D::setSize(int width, int height) +{ + endPainting(); + QImage newi(width, height, QImage::Format_ARGB32_Premultiplied); + newi.fill(qRgba(0,0,0,0)); + QPainter p(&newi); + p.drawImage(0, 0, m_image); + p.end(); + m_image = newi; + scheduleChange(); +} + +void Context2D::setSize(const QSize &size) +{ + setSize(size.width(), size.height()); +} + +QSize Context2D::size() const +{ + return m_image.size(); +} + +void Context2D::drawImage(DomImage *image, qreal dx, qreal dy) +{ + if (!image) + return; + if (dx < 0) { + qreal sx = qAbs(dx); + qreal sy = qAbs(dy); + qreal sw = image->width() - sx; + qreal sh = image->height() - sy; + + drawImage(image, sx, sy, sw, sh, 0, 0, sw, sh); + } else { + beginPainting(); + m_painter.drawImage(QPointF(dx, dy), image->image()); + scheduleChange(); + } +} + +void Context2D::drawImage(DomImage *image, qreal dx, qreal dy, + qreal dw, qreal dh) +{ + if (!image) + return; + beginPainting(); + m_painter.drawImage(QRectF(dx, dy, dw, dh).toRect(), image->image()); + scheduleChange(); +} + +void Context2D::drawImage(DomImage *image, qreal sx, qreal sy, + qreal sw, qreal sh, qreal dx, qreal dy, + qreal dw, qreal dh) +{ + if (!image) + return; + beginPainting(); + m_painter.drawImage(QRectF(dx, dy, dw, dh), image->image(), + QRectF(sx, sy, sw, sh)); + scheduleChange(); +} + +//! [2] +void Context2D::scheduleChange() +{ + if (m_changeTimerId == -1) + m_changeTimerId = startTimer(0); +} + +void Context2D::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == m_changeTimerId) { + killTimer(m_changeTimerId); + m_changeTimerId = -1; + emit changed(endPainting()); + } else { + QObject::timerEvent(e); + } +} +//! [2] diff --git a/examples/script/context2d/context2d.h b/examples/script/context2d/context2d.h new file mode 100644 index 0000000..38188f7 --- /dev/null +++ b/examples/script/context2d/context2d.h @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTEXT2D_H +#define CONTEXT2D_H + +#include "domimage.h" + +#include <QPainter> +#include <QPainterPath> +#include <QString> +#include <QStack> +#include <QMetaType> +#include <QTimerEvent> + +// [3] +class CanvasGradient +{ +public: + CanvasGradient(const QGradient &v) + : value(v) {} + CanvasGradient() {} + + QGradient value; +}; +// [3] + +Q_DECLARE_METATYPE(CanvasGradient) +Q_DECLARE_METATYPE(CanvasGradient*) + +class ImageData { +}; + +class QContext2DCanvas; + +//! [0] +class Context2D : public QObject +{ + Q_OBJECT + // compositing + Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha) + Q_PROPERTY(QString globalCompositeOperation READ globalCompositeOperation WRITE setGlobalCompositeOperation) + Q_PROPERTY(QVariant strokeStyle READ strokeStyle WRITE setStrokeStyle) + Q_PROPERTY(QVariant fillStyle READ fillStyle WRITE setFillStyle) + // line caps/joins + Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth) + Q_PROPERTY(QString lineCap READ lineCap WRITE setLineCap) + Q_PROPERTY(QString lineJoin READ lineJoin WRITE setLineJoin) + Q_PROPERTY(qreal miterLimit READ miterLimit WRITE setMiterLimit) + // shadows + Q_PROPERTY(qreal shadowOffsetX READ shadowOffsetX WRITE setShadowOffsetX) + Q_PROPERTY(qreal shadowOffsetY READ shadowOffsetY WRITE setShadowOffsetY) + Q_PROPERTY(qreal shadowBlur READ shadowBlur WRITE setShadowBlur) + Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor) +//! [0] + +public: + Context2D(QObject *parent = 0); + void setSize(int width, int height); + void setSize(const QSize &size); + QSize size() const; + + void clear(); + void reset(); + + // compositing + qreal globalAlpha() const; // (default 1.0) + QString globalCompositeOperation() const; // (default over) + QVariant strokeStyle() const; // (default black) + QVariant fillStyle() const; // (default black) + + void setGlobalAlpha(qreal alpha); + void setGlobalCompositeOperation(const QString &op); + void setStrokeStyle(const QVariant &style); + void setFillStyle(const QVariant &style); + + // line caps/joins + qreal lineWidth() const; // (default 1) + QString lineCap() const; // "butt", "round", "square" (default "butt") + QString lineJoin() const; // "round", "bevel", "miter" (default "miter") + qreal miterLimit() const; // (default 10) + + void setLineWidth(qreal w); + void setLineCap(const QString &s); + void setLineJoin(const QString &s); + void setMiterLimit(qreal m); + + // shadows + qreal shadowOffsetX() const; // (default 0) + qreal shadowOffsetY() const; // (default 0) + qreal shadowBlur() const; // (default 0) + QString shadowColor() const; // (default black) + + void setShadowOffsetX(qreal x); + void setShadowOffsetY(qreal y); + void setShadowBlur(qreal b); + void setShadowColor(const QString &str); + +//! [1] +public slots: + void save(); // push state on state stack + void restore(); // pop state stack and restore state + + void scale(qreal x, qreal y); + void rotate(qreal angle); + void translate(qreal x, qreal y); + void transform(qreal m11, qreal m12, qreal m21, qreal m22, + qreal dx, qreal dy); + void setTransform(qreal m11, qreal m12, qreal m21, qreal m22, + qreal dx, qreal dy); + + CanvasGradient createLinearGradient(qreal x0, qreal y0, + qreal x1, qreal y1); + CanvasGradient createRadialGradient(qreal x0, qreal y0, + qreal r0, qreal x1, + qreal y1, qreal r1); + + // rects + void clearRect(qreal x, qreal y, qreal w, qreal h); + void fillRect(qreal x, qreal y, qreal w, qreal h); + void strokeRect(qreal x, qreal y, qreal w, qreal h); + + // path API + void beginPath(); + void closePath(); + void moveTo(qreal x, qreal y); + void lineTo(qreal x, qreal y); + void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y); + void bezierCurveTo(qreal cp1x, qreal cp1y, + qreal cp2x, qreal cp2y, qreal x, qreal y); + void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius); + void rect(qreal x, qreal y, qreal w, qreal h); + void arc(qreal x, qreal y, qreal radius, + qreal startAngle, qreal endAngle, + bool anticlockwise); + void fill(); + void stroke(); + void clip(); + bool isPointInPath(qreal x, qreal y) const; +//! [1] + + // drawing images + void drawImage(DomImage *image, qreal dx, qreal dy); + void drawImage(DomImage *image, qreal dx, qreal dy, + qreal dw, qreal dh); + void drawImage(DomImage *image, qreal sx, qreal sy, + qreal sw, qreal sh, qreal dx, qreal dy, + qreal dw, qreal dh); + + // pixel manipulation + ImageData getImageData(qreal sx, qreal sy, qreal sw, qreal sh); + void putImageData(ImageData image, qreal dx, qreal dy); + +//! [2] +signals: + void changed(const QImage &image); +//! [2] + +protected: + void timerEvent(QTimerEvent *e); + +private: + void beginPainting(); + const QImage &endPainting(); + void scheduleChange(); + + int m_changeTimerId; + QImage m_image; + QPainter m_painter; + QPainterPath m_path; + + enum DirtyFlag { + DirtyTransformationMatrix = 0x00001, + DirtyClippingRegion = 0x00002, + DirtyStrokeStyle = 0x00004, + DirtyFillStyle = 0x00008, + DirtyGlobalAlpha = 0x00010, + DirtyLineWidth = 0x00020, + DirtyLineCap = 0x00040, + DirtyLineJoin = 0x00080, + DirtyMiterLimit = 0x00100, + MDirtyPen = DirtyStrokeStyle + | DirtyLineWidth + | DirtyLineCap + | DirtyLineJoin + | DirtyMiterLimit, + DirtyShadowOffsetX = 0x00200, + DirtyShadowOffsetY = 0x00400, + DirtyShadowBlur = 0x00800, + DirtyShadowColor = 0x01000, + DirtyGlobalCompositeOperation = 0x2000, + DirtyFont = 0x04000, + DirtyTextAlign = 0x08000, + DirtyTextBaseline = 0x10000, + AllIsFullOfDirt = 0xfffff + }; + + struct State { + State() : flags(0) {} + QMatrix matrix; + QPainterPath clipPath; + QBrush strokeStyle; + QBrush fillStyle; + qreal globalAlpha; + qreal lineWidth; + Qt::PenCapStyle lineCap; + Qt::PenJoinStyle lineJoin; + qreal miterLimit; + qreal shadowOffsetX; + qreal shadowOffsetY; + qreal shadowBlur; + QColor shadowColor; + QPainter::CompositionMode globalCompositeOperation; + QFont font; + int textAlign; + int textBaseline; + int flags; + }; + State m_state; + QStack<State> m_stateStack; +}; + +#endif diff --git a/examples/script/context2d/context2d.pro b/examples/script/context2d/context2d.pro new file mode 100644 index 0000000..30ec9a7 --- /dev/null +++ b/examples/script/context2d/context2d.pro @@ -0,0 +1,23 @@ +TEMPLATE = app +QT += script +# Input +HEADERS += qcontext2dcanvas.h \ + context2d.h \ + domimage.h \ + environment.h \ + window.h +SOURCES += qcontext2dcanvas.cpp \ + context2d.cpp \ + domimage.cpp \ + environment.cpp \ + window.cpp \ + main.cpp +RESOURCES += context2d.qrc + +contains(QT_CONFIG, scripttools): QT += scripttools + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/context2d +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS context2d.pro scripts +sources.path = $$[QT_INSTALL_EXAMPLES]/script/context2d +INSTALLS += target sources diff --git a/examples/script/context2d/context2d.qrc b/examples/script/context2d/context2d.qrc new file mode 100644 index 0000000..75e570c --- /dev/null +++ b/examples/script/context2d/context2d.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/"> + <file>scripts</file> +</qresource> +</RCC> diff --git a/examples/script/context2d/domimage.cpp b/examples/script/context2d/domimage.cpp new file mode 100644 index 0000000..66a2c95 --- /dev/null +++ b/examples/script/context2d/domimage.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "domimage.h" + +#include <QVariant> + +#include <qscriptcontext.h> + +QScriptValue DomImage::s_self; + +DomImage::DomImage() +{ +} + + +int DomImage::width() const +{ + return m_image.width(); +} + + +int DomImage::height() const +{ + return m_image.height(); +} + + +QString DomImage::src() const +{ + return m_src; +} + +void DomImage::setSrc(const QString &src) +{ + m_src = src; + m_image = QImage(m_src); +} + + +QString DomImage::name() const +{ + return m_src; +} + +static QScriptValue Image(QScriptContext *context, QScriptEngine *env) +{ + QScriptValue val = context->thisObject(); + DomImage *image = new DomImage(); + QScriptValue klass = env->newVariant(qVariantFromValue(image)); + klass.setPrototype(DomImage::s_self); + return klass; +} + + +static QScriptValue width(QScriptContext *context, QScriptEngine *) +{ + QScriptValue val = context->thisObject(); + + DomImage *image = qvariant_cast<DomImage*> (val.toVariant()); + if (image) + return image->width(); + + return 0; +} + + +static QScriptValue height(QScriptContext *context, QScriptEngine *) +{ + QScriptValue val = context->thisObject(); + + DomImage *image = qvariant_cast<DomImage*> (val.toVariant()); + if (image) + return image->height(); + + return 0; +} + + +static QScriptValue setSrc(QScriptContext *context, QScriptEngine *env) +{ + QScriptValue val = context->thisObject(); + QString src = context->argument(0).toString(); + + DomImage *image = qvariant_cast<DomImage*> (val.toVariant()); + if (image) + image->setSrc(src); + + return env->undefinedValue(); +} + + +static QScriptValue name(QScriptContext *context, QScriptEngine *) +{ + QScriptValue val = context->thisObject(); + + DomImage *image = qvariant_cast<DomImage*> (val.toVariant()); + if (image) + return image->name(); + + return QString(); +} + + +void DomImage::setup(QScriptEngine *e) +{ + qRegisterMetaType<DomImage>(); + + e->globalObject().setProperty("Image", + e->newFunction(::Image, 0)); + + s_self = e->newObject(); + s_self.setProperty("setSrc", e->newFunction(&::setSrc, 1)); + s_self.setProperty("width", e->newFunction(&::width)); + s_self.setProperty("height", e->newFunction(&::height)); + s_self.setProperty("name", e->newFunction(&::name)); + + e->setDefaultPrototype(qMetaTypeId<DomImage>(), s_self); +} diff --git a/examples/script/context2d/domimage.h b/examples/script/context2d/domimage.h new file mode 100644 index 0000000..0793d1d --- /dev/null +++ b/examples/script/context2d/domimage.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOMIMAGE_H +#define DOMIMAGE_H + +#include <QPixmap> +#include <QImage> +#include <QMetaType> + +#include <qscriptengine.h> + +class DomImage +{ +public: + DomImage(); + static void setup(QScriptEngine *e); + + int width() const; + int height() const; + + QString src() const; + void setSrc(const QString &src); + + QString name() const; + + static QScriptValue s_self; + + const QImage &image() const + { + return m_image; + } +private: + QImage m_image; + QString m_src; + //attribute boolean isMap; + //attribute DOMString longDesc; + //attribute DOMString useMap; + //attribute DOMString align; + //attribute DOMString alt; + //attribute DOMString border; + //attribute long vspace; + //attribute long hspace; +}; + +Q_DECLARE_METATYPE(DomImage) +Q_DECLARE_METATYPE(DomImage*) + +#endif diff --git a/examples/script/context2d/environment.cpp b/examples/script/context2d/environment.cpp new file mode 100644 index 0000000..1c1a3a6 --- /dev/null +++ b/examples/script/context2d/environment.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "environment.h" +#include "qcontext2dcanvas.h" +#include "context2d.h" +#include <QScriptValueIterator> +#include <QDateTime> + +struct FakeDomEvent +{ + enum KeyCodes { + DOM_VK_UNDEFINED = 0x0, + DOM_VK_RIGHT_ALT = 0x12, + DOM_VK_LEFT_ALT = 0x12, + DOM_VK_LEFT_CONTROL = 0x11, + DOM_VK_RIGHT_CONTROL = 0x11, + DOM_VK_LEFT_SHIFT = 0x10, + DOM_VK_RIGHT_SHIFT = 0x10, + DOM_VK_META = 0x9D, + DOM_VK_BACK_SPACE = 0x08, + DOM_VK_CAPS_LOCK = 0x14, + DOM_VK_DELETE = 0x7F, + DOM_VK_END = 0x23, + DOM_VK_ENTER = 0x0D, + DOM_VK_ESCAPE = 0x1B, + DOM_VK_HOME = 0x24, + DOM_VK_NUM_LOCK = 0x90, + DOM_VK_PAUSE = 0x13, + DOM_VK_PRINTSCREEN = 0x9A, + DOM_VK_SCROLL_LOCK = 0x91, + DOM_VK_SPACE = 0x20, + DOM_VK_TAB = 0x09, + DOM_VK_LEFT = 0x25, + DOM_VK_RIGHT = 0x27, + DOM_VK_UP = 0x26, + DOM_VK_DOWN = 0x28, + DOM_VK_PAGE_DOWN = 0x22, + DOM_VK_PAGE_UP = 0x21, + DOM_VK_F1 = 0x70, + DOM_VK_F2 = 0x71, + DOM_VK_F3 = 0x72, + DOM_VK_F4 = 0x73, + DOM_VK_F5 = 0x74, + DOM_VK_F6 = 0x75, + DOM_VK_F7 = 0x76, + DOM_VK_F8 = 0x77, + DOM_VK_F9 = 0x78, + DOM_VK_F10 = 0x79, + DOM_VK_F11 = 0x7A, + DOM_VK_F12 = 0x7B, + DOM_VK_F13 = 0xF000, + DOM_VK_F14 = 0xF001, + DOM_VK_F15 = 0xF002, + DOM_VK_F16 = 0xF003, + DOM_VK_F17 = 0xF004, + DOM_VK_F18 = 0xF005, + DOM_VK_F19 = 0xF006, + DOM_VK_F20 = 0xF007, + DOM_VK_F21 = 0xF008, + DOM_VK_F22 = 0xF009, + DOM_VK_F23 = 0xF00A, + DOM_VK_F24 = 0xF00B + }; + + static int qtToDomKey(int keyCode); +}; + +int FakeDomEvent::qtToDomKey(int keyCode) +{ + switch (keyCode) { + case Qt::Key_Backspace: + return DOM_VK_BACK_SPACE; + case Qt::Key_Enter: + return DOM_VK_ENTER; + case Qt::Key_Return: + return DOM_VK_ENTER; + case Qt::Key_NumLock: + return DOM_VK_NUM_LOCK; + case Qt::Key_Alt: + return DOM_VK_RIGHT_ALT; + case Qt::Key_Control: + return DOM_VK_LEFT_CONTROL; + case Qt::Key_Shift: + return DOM_VK_LEFT_SHIFT; + case Qt::Key_Meta: + return DOM_VK_META; + case Qt::Key_CapsLock: + return DOM_VK_CAPS_LOCK; + case Qt::Key_Delete: + return DOM_VK_DELETE; + case Qt::Key_End: + return DOM_VK_END; + case Qt::Key_Escape: + return DOM_VK_ESCAPE; + case Qt::Key_Home: + return DOM_VK_HOME; + case Qt::Key_Pause: + return DOM_VK_PAUSE; + case Qt::Key_Print: + return DOM_VK_PRINTSCREEN; + case Qt::Key_ScrollLock: + return DOM_VK_SCROLL_LOCK; + case Qt::Key_Left: + return DOM_VK_LEFT; + case Qt::Key_Right: + return DOM_VK_RIGHT; + case Qt::Key_Up: + return DOM_VK_UP; + case Qt::Key_Down: + return DOM_VK_DOWN; + case Qt::Key_PageDown: + return DOM_VK_PAGE_DOWN; + case Qt::Key_PageUp: + return DOM_VK_PAGE_UP; + case Qt::Key_F1: + return DOM_VK_F1; + case Qt::Key_F2: + return DOM_VK_F2; + case Qt::Key_F3: + return DOM_VK_F3; + case Qt::Key_F4: + return DOM_VK_F4; + case Qt::Key_F5: + return DOM_VK_F5; + case Qt::Key_F6: + return DOM_VK_F6; + case Qt::Key_F7: + return DOM_VK_F7; + case Qt::Key_F8: + return DOM_VK_F8; + case Qt::Key_F9: + return DOM_VK_F9; + case Qt::Key_F10: + return DOM_VK_F10; + case Qt::Key_F11: + return DOM_VK_F11; + case Qt::Key_F12: + return DOM_VK_F12; + case Qt::Key_F13: + return DOM_VK_F13; + case Qt::Key_F14: + return DOM_VK_F14; + case Qt::Key_F15: + return DOM_VK_F15; + case Qt::Key_F16: + return DOM_VK_F16; + case Qt::Key_F17: + return DOM_VK_F17; + case Qt::Key_F18: + return DOM_VK_F18; + case Qt::Key_F19: + return DOM_VK_F19; + case Qt::Key_F20: + return DOM_VK_F20; + case Qt::Key_F21: + return DOM_VK_F21; + case Qt::Key_F22: + return DOM_VK_F22; + case Qt::Key_F23: + return DOM_VK_F23; + case Qt::Key_F24: + return DOM_VK_F24; + } + return keyCode; +} + +//! [0] +Environment::Environment(QObject *parent) + : QObject(parent) +{ + m_engine = new QScriptEngine(this); + + m_document = m_engine->newQObject( + new Document(this), QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassContents); + + CanvasGradientPrototype::setup(m_engine); + + m_originalGlobalObject = m_engine->globalObject(); + reset(); +} +//! [0] + +Environment::~Environment() +{ +} + +QScriptEngine *Environment::engine() const +{ + return m_engine; +} + +QScriptValue Environment::document() const +{ + return m_document; +} + +int Environment::setTimeout(const QScriptValue &expression, int delay) +{ + if (expression.isString() || expression.isFunction()) { + int timerId = startTimer(delay); + m_timeoutHash.insert(timerId, expression); + return timerId; + } + return -1; +} + +void Environment::clearTimeout(int timerId) +{ + killTimer(timerId); + m_timeoutHash.remove(timerId); +} + +//! [1] +int Environment::setInterval(const QScriptValue &expression, int delay) +{ + if (expression.isString() || expression.isFunction()) { + int timerId = startTimer(delay); + m_intervalHash.insert(timerId, expression); + return timerId; + } + return -1; +} + +void Environment::clearInterval(int timerId) +{ + killTimer(timerId); + m_intervalHash.remove(timerId); +} + +void Environment::timerEvent(QTimerEvent *event) +{ + int id = event->timerId(); + QScriptValue expression = m_intervalHash.value(id); + if (!expression.isValid()) { + expression = m_timeoutHash.value(id); + if (expression.isValid()) + killTimer(id); + } + if (expression.isString()) { + evaluate(expression.toString()); + } else if (expression.isFunction()) { + expression.call(); + } + maybeEmitScriptError(); +} +//! [1] + +//! [5] +void Environment::addCanvas(QContext2DCanvas *canvas) +{ + m_canvases.append(canvas); +} + +QContext2DCanvas *Environment::canvasByName(const QString &name) const +{ + for (int i = 0; i < m_canvases.size(); ++i) { + QContext2DCanvas *canvas = m_canvases.at(i); + if (canvas->objectName() == name) + return canvas; + } + return 0; +} +//! [5] + +QList<QContext2DCanvas*> Environment::canvases() const +{ + return m_canvases; +} + +void Environment::reset() +{ + if (m_engine->isEvaluating()) + m_engine->abortEvaluation(); + + { + QHash<int, QScriptValue>::const_iterator it; + for (it = m_intervalHash.constBegin(); it != m_intervalHash.constEnd(); ++it) + killTimer(it.key()); + m_intervalHash.clear(); + for (it = m_timeoutHash.constBegin(); it != m_timeoutHash.constEnd(); ++it) + killTimer(it.key()); + m_timeoutHash.clear(); + } + + for (int i = 0; i < m_canvases.size(); ++i) + m_canvases.at(i)->reset(); + + QScriptValue self = m_engine->newQObject( + this, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeSuperClassContents); + + { + QScriptValueIterator it(m_originalGlobalObject); + while (it.hasNext()) { + it.next(); + self.setProperty(it.scriptName(), it.value(), it.flags()); + } + } + + self.setProperty("self", self); + self.setProperty("window", self); + + QScriptValue navigator = m_engine->newObject(); + navigator.setProperty("appCodeName", "context2d"); + navigator.setProperty("appMinorVersion", 1); + navigator.setProperty("appVersion", 1); + navigator.setProperty("browserLanguage", "en_US"); + navigator.setProperty("cookieEnabled", false); + navigator.setProperty("cpuClass", "i686"); + navigator.setProperty("onLine", false); + navigator.setProperty("platform", "bogus OS"); + navigator.setProperty("systemLanguage", "en_US"); + navigator.setProperty("userAgent", "Context2D/1.1"); + navigator.setProperty("userLanguage", "en_US"); + self.setProperty("navigator", navigator); + + m_engine->setGlobalObject(self); + + m_engine->collectGarbage(); +} + +QScriptValue Environment::evaluate(const QString &code, const QString &fileName) +{ + return m_engine->evaluate(code, fileName); +} + +//! [2] +QScriptValue Environment::toWrapper(QObject *object) +{ + return m_engine->newQObject(object, QScriptEngine::QtOwnership, + QScriptEngine::PreferExistingWrapperObject + | QScriptEngine::ExcludeSuperClassContents); +} +//! [2] + +//! [3] +void Environment::handleEvent(QContext2DCanvas *canvas, QMouseEvent *e) +{ + QString type; + switch (e->type()) { + case QEvent::MouseButtonPress: + type = "mousedown"; break; + case QEvent::MouseButtonRelease: + type = "mouseup"; break; + case QEvent::MouseMove: + type = "mousemove"; break; + default: break; + } + if (type.isEmpty()) + return; + + QScriptValue handlerObject; + QScriptValue handler = eventHandler(canvas, type, &handlerObject); + if (!handler.isFunction()) + return; + + QScriptValue scriptEvent = newFakeDomEvent(type, toWrapper(canvas)); + // MouseEvent + scriptEvent.setProperty("screenX", e->globalX(), QScriptValue::ReadOnly); + scriptEvent.setProperty("screenY", e->globalY(), QScriptValue::ReadOnly); + scriptEvent.setProperty("clientX", e->x(), QScriptValue::ReadOnly); + scriptEvent.setProperty("clientY", e->y(), QScriptValue::ReadOnly); + scriptEvent.setProperty("layerX", e->x(), QScriptValue::ReadOnly); + scriptEvent.setProperty("layerY", e->y(), QScriptValue::ReadOnly); + scriptEvent.setProperty("pageX", e->x(), QScriptValue::ReadOnly); + scriptEvent.setProperty("pageY", e->y(), QScriptValue::ReadOnly); + scriptEvent.setProperty("altKey", (e->modifiers() & Qt::AltModifier) != 0, + QScriptValue::ReadOnly); + scriptEvent.setProperty("ctrlKey", (e->modifiers() & Qt::ControlModifier) != 0, + QScriptValue::ReadOnly); + scriptEvent.setProperty("metaKey", (e->modifiers() & Qt::MetaModifier) != 0, + QScriptValue::ReadOnly); + scriptEvent.setProperty("shiftKey", (e->modifiers() & Qt::ShiftModifier) != 0, + QScriptValue::ReadOnly); + int button = 0; + if (e->button() == Qt::RightButton) + button = 2; + else if (e->button() == Qt::MidButton) + button = 1; + scriptEvent.setProperty("button", button); + scriptEvent.setProperty("relatedTarget", m_engine->nullValue(), + QScriptValue::ReadOnly); + handler.call(handlerObject, QScriptValueList() << scriptEvent); + maybeEmitScriptError(); +} +//! [3] + +void Environment::handleEvent(QContext2DCanvas *canvas, QKeyEvent *e) +{ + QString type; + switch (e->type()) { + case QEvent::KeyPress: + type = "keydown"; break; + case QEvent::KeyRelease: + type = "keyup"; break; + default: break; + } + if (type.isEmpty()) + return; + + QScriptValue handlerObject; + QScriptValue handler = eventHandler(canvas, type, &handlerObject); + if (!handler.isFunction()) + return; + + QScriptValue scriptEvent = newFakeDomEvent(type, toWrapper(canvas)); + // KeyEvent + scriptEvent.setProperty("isChar", !e->text().isEmpty()); + scriptEvent.setProperty("charCode", e->text()); + scriptEvent.setProperty("keyCode", FakeDomEvent::qtToDomKey(e->key())); + scriptEvent.setProperty("which", e->key()); + + handler.call(handlerObject, QScriptValueList() << scriptEvent); + maybeEmitScriptError(); +} + +QScriptValue Environment::eventHandler(QContext2DCanvas *canvas, const QString &type, + QScriptValue *who) +{ + QString handlerName = "on" + type; + QScriptValue obj = toWrapper(canvas); + QScriptValue handler = obj.property(handlerName); + if (!handler.isValid()) { + obj = m_document; + handler = obj.property(handlerName); + } + if (who && handler.isFunction()) + *who = obj; + return handler; +} + +//! [4] +QScriptValue Environment::newFakeDomEvent(const QString &type, const QScriptValue &target) +{ + QScriptValue e = m_engine->newObject(); + // Event + e.setProperty("type", type, QScriptValue::ReadOnly); + e.setProperty("bubbles", true, QScriptValue::ReadOnly); + e.setProperty("cancelable", false, QScriptValue::ReadOnly); + e.setProperty("target", target, QScriptValue::ReadOnly); + e.setProperty("currentTarget", target, QScriptValue::ReadOnly); + e.setProperty("eventPhase", 3); // bubbling + e.setProperty("timeStamp", QDateTime::currentDateTime().toTime_t()); + // UIEvent + e.setProperty("detail", 0, QScriptValue::ReadOnly); + e.setProperty("view", m_engine->globalObject(), QScriptValue::ReadOnly); + return e; +} +//! [4] + +void Environment::maybeEmitScriptError() +{ + if (m_engine->hasUncaughtException()) + emit scriptError(m_engine->uncaughtException()); +} + + +Document::Document(Environment *env) + : QObject(env) +{ +} + +Document::~Document() +{ +} + +QScriptValue Document::getElementById(const QString &id) const +{ + Environment *env = qobject_cast<Environment*>(parent()); + QContext2DCanvas *canvas = env->canvasByName(id); + if (!canvas) + return QScriptValue(); + return env->toWrapper(canvas); +} + +QScriptValue Document::getElementsByTagName(const QString &name) const +{ + if (name != "canvas") + return QScriptValue(); + Environment *env = qobject_cast<Environment*>(parent()); + QList<QContext2DCanvas*> list = env->canvases(); + QScriptValue result = env->engine()->newArray(list.size()); + for (int i = 0; i < list.size(); ++i) + result.setProperty(i, env->toWrapper(list.at(i))); + return result; +} + +void Document::addEventListener(const QString &type, const QScriptValue &listener, + bool useCapture) +{ + Q_UNUSED(useCapture); + if (listener.isFunction()) { + Environment *env = qobject_cast<Environment*>(parent()); + QScriptValue self = env->toWrapper(this); + self.setProperty("on" + type, listener); + } +} + + +QColor colorFromString(const QString &name); + +CanvasGradientPrototype::CanvasGradientPrototype(QObject *parent) + : QObject(parent) +{ +} + +void CanvasGradientPrototype::addColorStop(qreal offset, const QString &color) +{ + CanvasGradient *self = qscriptvalue_cast<CanvasGradient*>(thisObject()); + if (!self || (self->value.type() == QGradient::NoGradient)) + return; + self->value.setColorAt(offset, colorFromString(color)); +} + +void CanvasGradientPrototype::setup(QScriptEngine *engine) +{ + CanvasGradientPrototype *proto = new CanvasGradientPrototype(); + engine->setDefaultPrototype(qMetaTypeId<CanvasGradient>(), + engine->newQObject(proto, QScriptEngine::ScriptOwnership, + QScriptEngine::ExcludeSuperClassContents)); +} diff --git a/examples/script/context2d/environment.h b/examples/script/context2d/environment.h new file mode 100644 index 0000000..e47e6cb --- /dev/null +++ b/examples/script/context2d/environment.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +#include <qobject.h> +#include <qlist.h> +#include <qhash.h> +#include <QTimerEvent> +#include <QMouseEvent> +#include <QKeyEvent> +#include <QScriptEngine> +#include <QScriptable> +class QContext2DCanvas; + +//! [0] +class Environment : public QObject +{ + Q_OBJECT + Q_PROPERTY(QScriptValue document READ document) +public: + Environment(QObject *parent = 0); + ~Environment(); + + QScriptValue document() const; + + void addCanvas(QContext2DCanvas *canvas); + QContext2DCanvas *canvasByName(const QString &name) const; + QList<QContext2DCanvas*> canvases() const; + + QScriptValue evaluate(const QString &code, + const QString &fileName = QString()); + + QScriptValue toWrapper(QObject *object); + + void handleEvent(QContext2DCanvas *canvas, QMouseEvent *e); + void handleEvent(QContext2DCanvas *canvas, QKeyEvent *e); + + void reset(); +//! [0] + + QScriptEngine *engine() const; + +//! [1] +public slots: + int setInterval(const QScriptValue &expression, int delay); + void clearInterval(int timerId); + + int setTimeout(const QScriptValue &expression, int delay); + void clearTimeout(int timerId); +//! [1] + +//! [2] +signals: + void scriptError(const QScriptValue &error); +//! [2] + +protected: + void timerEvent(QTimerEvent *event); + +private: + QScriptValue eventHandler(QContext2DCanvas *canvas, + const QString &type, QScriptValue *who); + QScriptValue newFakeDomEvent(const QString &type, + const QScriptValue &target); + void maybeEmitScriptError(); + + QScriptEngine *m_engine; + QScriptValue m_originalGlobalObject; + QScriptValue m_document; + QList<QContext2DCanvas*> m_canvases; + QHash<int, QScriptValue> m_intervalHash; + QHash<int, QScriptValue> m_timeoutHash; +}; + +//! [3] +class Document : public QObject +{ + Q_OBJECT +public: + Document(Environment *env); + ~Document(); + +public slots: + QScriptValue getElementById(const QString &id) const; + QScriptValue getElementsByTagName(const QString &name) const; + + // EventTarget + void addEventListener(const QString &type, const QScriptValue &listener, + bool useCapture); +}; +//! [3] + +class CanvasGradientPrototype : public QObject, public QScriptable +{ + Q_OBJECT +protected: + CanvasGradientPrototype(QObject *parent = 0); +public: + static void setup(QScriptEngine *engine); + +public slots: + void addColorStop(qreal offset, const QString &color); +}; + +#endif diff --git a/examples/script/context2d/main.cpp b/examples/script/context2d/main.cpp new file mode 100644 index 0000000..78c9df9 --- /dev/null +++ b/examples/script/context2d/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" +#include <QApplication> + +int main(int argc, char **argv) +{ + Q_INIT_RESOURCE(context2d); + + QApplication app(argc, argv); + Window win; + win.show(); + return app.exec(); +} diff --git a/examples/script/context2d/qcontext2dcanvas.cpp b/examples/script/context2d/qcontext2dcanvas.cpp new file mode 100644 index 0000000..30bb3eb --- /dev/null +++ b/examples/script/context2d/qcontext2dcanvas.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcontext2dcanvas.h" + +#include "context2d.h" +#include "environment.h" +#include "domimage.h" + +#include <QPainter> +#include <QPaintEvent> + +//! [3] +QContext2DCanvas::QContext2DCanvas(Context2D *context, Environment *env, QWidget *parent) + : QWidget(parent), m_context(context), m_env(env) +{ + QObject::connect(context, SIGNAL(changed(QImage)), this, SLOT(contentsChanged(QImage))); + setMouseTracking(true); +} +//! [3] + +QContext2DCanvas::~QContext2DCanvas() +{ +} + +Context2D *QContext2DCanvas::context() const +{ + return m_context; +} + +//! [0] +QScriptValue QContext2DCanvas::getContext(const QString &str) +{ + if (str != "2d") + return QScriptValue(); + return m_env->toWrapper(m_context); +} +//! [0] + +//! [1] +void QContext2DCanvas::contentsChanged(const QImage &image) +{ + m_image = image; + update(); +} + +void QContext2DCanvas::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + p.setClipRect(e->rect()); + p.drawImage(0, 0, m_image); +} +//! [1] + +//! [2] +void QContext2DCanvas::mouseMoveEvent(QMouseEvent *e) +{ + m_env->handleEvent(this, e); +} + +void QContext2DCanvas::mousePressEvent(QMouseEvent *e) +{ + m_env->handleEvent(this, e); +} + +void QContext2DCanvas::mouseReleaseEvent(QMouseEvent *e) +{ + m_env->handleEvent(this, e); +} + +void QContext2DCanvas::keyPressEvent(QKeyEvent *e) +{ + m_env->handleEvent(this, e); +} + +void QContext2DCanvas::keyReleaseEvent(QKeyEvent *e) +{ + m_env->handleEvent(this, e); +} +//! [2] + +void QContext2DCanvas::resizeEvent(QResizeEvent *e) +{ + m_context->setSize(e->size().width(), e->size().height()); +} + +void QContext2DCanvas::resize(int width, int height) +{ + QWidget::resize(width, height); +} + +void QContext2DCanvas::reset() +{ + m_context->reset(); +} + +void QContext2DCanvas::addEventListener(const QString &type, const QScriptValue &listener, + bool useCapture) +{ + Q_UNUSED(useCapture); + if (listener.isFunction()) { + QScriptValue self = m_env->toWrapper(this); + self.setProperty("on" + type, listener); + } +} diff --git a/examples/script/context2d/qcontext2dcanvas.h b/examples/script/context2d/qcontext2dcanvas.h new file mode 100644 index 0000000..657ffc3 --- /dev/null +++ b/examples/script/context2d/qcontext2dcanvas.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONTEXT2DCANVAS_H +#define QCONTEXT2DCANVAS_H + +#include <qscriptengine.h> +#include <qscriptcontext.h> +#include <qscriptvalue.h> + +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QPaintEvent; +class QResizeEvent; +class QMouseEvent; +class QKeyEvent; +QT_END_NAMESPACE +class Environment; +class Context2D; + +//! [0] +class QContext2DCanvas : public QWidget +{ + Q_OBJECT +public: + QContext2DCanvas(Context2D *context, Environment *env, QWidget *parent = 0); + ~QContext2DCanvas(); + + Context2D *context() const; + void reset(); + +public slots: + QScriptValue getContext(const QString &str); + void resize(int width, int height); + + // EventTarget + void addEventListener(const QString &type, const QScriptValue &listener, + bool useCapture); + +protected: + virtual void paintEvent(QPaintEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseReleaseEvent(QMouseEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + virtual void keyReleaseEvent(QKeyEvent *e); + virtual void resizeEvent(QResizeEvent *e); + +private slots: + void contentsChanged(const QImage &image); +//! [0] + +private: + Context2D *m_context; + Environment *m_env; + QImage m_image; +}; + +#endif diff --git a/examples/script/context2d/scripts/alpha.js b/examples/script/context2d/scripts/alpha.js new file mode 100644 index 0000000..23fa5d4 --- /dev/null +++ b/examples/script/context2d/scripts/alpha.js @@ -0,0 +1,21 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + // draw background + ctx.fillStyle = '#FD0'; + ctx.fillRect(0,0,75,75); + ctx.fillStyle = '#6C0'; + ctx.fillRect(75,0,75,75); + ctx.fillStyle = '#09F'; + ctx.fillRect(0,75,75,75); + ctx.fillStyle = '#F30'; + ctx.fillRect(75,75,75,75); + ctx.fillStyle = '#FFF'; + + // set transparency value + ctx.globalAlpha = 0.2; + + // Draw semi transparent circles + for (i=0;i<7;i++){ + ctx.beginPath(); + ctx.arc(75,75,10+10*i,0,Math.PI*2,true); + ctx.fill(); + } diff --git a/examples/script/context2d/scripts/arc.js b/examples/script/context2d/scripts/arc.js new file mode 100644 index 0000000..650bcda --- /dev/null +++ b/examples/script/context2d/scripts/arc.js @@ -0,0 +1,30 @@ +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Draw shapes + for (i=0;i<4;i++){ + for(j=0;j<3;j++){ + ctx.beginPath(); + var x = 25+j*50; // x coordinate + var y = 25+i*50; // y coordinate + var radius = 20; // Arc radius + var startAngle = 0; // Starting point on circle + var endAngle = Math.PI+(Math.PI*j)/2; // End point on circle + var clockwise = i%2==0 ? false : true; // clockwise or anticlockwise + + ctx.arc(x,y,radius,startAngle,endAngle, clockwise); + + if (i>1){ + ctx.fill(); + } else { + ctx.stroke(); + } + } + } + + } diff --git a/examples/script/context2d/scripts/bezier.js b/examples/script/context2d/scripts/bezier.js new file mode 100644 index 0000000..719800e --- /dev/null +++ b/examples/script/context2d/scripts/bezier.js @@ -0,0 +1,26 @@ +function drawShape() { +// get the canvas element using the DOM +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Draw shapes + + ctx.beginPath(); + ctx.moveTo(75,40); + ctx.bezierCurveTo(75,37,70,25,50,25); + ctx.bezierCurveTo(20,25,20,62.5,20,62.5); + ctx.bezierCurveTo(20,80,40,102,75,120); + ctx.bezierCurveTo(110,102,130,80,130,62.5); + ctx.bezierCurveTo(130,62.5,130,25,100,25); + ctx.bezierCurveTo(85,25,75,37,75,40); + ctx.fill(); + ctx.globalAlpha = 0.5; + } +} + +drawShape(); diff --git a/examples/script/context2d/scripts/clock.js b/examples/script/context2d/scripts/clock.js new file mode 100644 index 0000000..ad287d8 --- /dev/null +++ b/examples/script/context2d/scripts/clock.js @@ -0,0 +1,99 @@ +function init(){ + clock(); + setInterval('clock()',1000); +} +function clock(){ + var now = new Date(); + var ctx = document.getElementById('tutorial').getContext('2d'); + ctx.save(); + ctx.clearRect(0,0,150,150); + ctx.translate(75,75); + ctx.scale(0.4,0.4); + ctx.rotate(-Math.PI/2); + ctx.strokeStyle = "black"; + ctx.fillStyle = "white"; + ctx.lineWidth = 8; + ctx.lineCap = "round"; + + // Hour marks + ctx.save(); + ctx.beginPath(); + for (i=0;i<12;i++){ + ctx.rotate(Math.PI/6); + ctx.moveTo(100,0); + ctx.lineTo(120,0); + } + ctx.stroke(); + ctx.restore(); + + // Minute marks + ctx.save(); + ctx.lineWidth = 5; + ctx.beginPath(); + for (i=0;i<60;i++){ + if (i%5!=0) { + ctx.moveTo(117,0); + ctx.lineTo(120,0); + } + ctx.rotate(Math.PI/30); + } + ctx.stroke(); + ctx.restore(); + + var sec = now.getSeconds(); + var min = now.getMinutes(); + var hr = now.getHours(); + hr = hr>=12 ? hr-12 : hr; + + ctx.fillStyle = "black"; + + // write Hours + ctx.save(); + ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec ) + ctx.lineWidth = 14; + ctx.beginPath(); + ctx.moveTo(-20,0); + ctx.lineTo(80,0); + ctx.stroke(); + ctx.restore(); + + // write Minutes + ctx.save(); + ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec ) + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.moveTo(-28,0); + ctx.lineTo(112,0); + ctx.stroke(); + ctx.restore(); + + // Write seconds + ctx.save(); + ctx.rotate(sec * Math.PI/30); + ctx.strokeStyle = "#D40000"; + ctx.fillStyle = "#D40000"; + ctx.lineWidth = 6; + ctx.beginPath(); + ctx.moveTo(-30,0); + ctx.lineTo(83,0); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(0,0,10,0,Math.PI*2,true); + ctx.fill(); + ctx.beginPath(); + ctx.arc(95,0,10,0,Math.PI*2,true); + ctx.stroke(); + ctx.fillStyle = "#555"; + ctx.arc(0,0,3,0,Math.PI*2,true); + ctx.fill(); + ctx.restore(); + + ctx.beginPath(); + ctx.lineWidth = 14; + ctx.strokeStyle = '#325FA2'; + ctx.arc(0,0,142,0,Math.PI*2,true); + ctx.stroke(); + + ctx.restore(); +} +init(); diff --git a/examples/script/context2d/scripts/fill1.js b/examples/script/context2d/scripts/fill1.js new file mode 100644 index 0000000..db5eeb7 --- /dev/null +++ b/examples/script/context2d/scripts/fill1.js @@ -0,0 +1,8 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + for (i=0;i<6;i++){ + for (j=0;j<6;j++){ + ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + + Math.floor(255-42.5*j) + ',0)'; + ctx.fillRect(j*25,i*25,25,25); + } + } diff --git a/examples/script/context2d/scripts/grad.js b/examples/script/context2d/scripts/grad.js new file mode 100644 index 0000000..24ccfbb --- /dev/null +++ b/examples/script/context2d/scripts/grad.js @@ -0,0 +1,20 @@ + var ctx = document.getElementById('tutorial').getContext('2d'); + + // Create gradients + var lingrad = ctx.createLinearGradient(0,0,0,150); + lingrad.addColorStop(0, '#00ABEB'); + lingrad.addColorStop(0.5, '#fff'); + lingrad.addColorStop(0.5, '#66CC00'); + lingrad.addColorStop(1, '#fff'); + + var lingrad2 = ctx.createLinearGradient(0,50,0,95); + lingrad2.addColorStop(0.5, '#000'); + lingrad2.addColorStop(1, 'rgba(0,0,0,0)'); + + // assign gradients to fill and stroke styles + ctx.fillStyle = lingrad; + ctx.strokeStyle = lingrad2; + + // draw shapes + ctx.fillRect(10,10,130,130); + ctx.strokeRect(50,50,50,50); diff --git a/examples/script/context2d/scripts/linecap.js b/examples/script/context2d/scripts/linecap.js new file mode 100644 index 0000000..18ceb23 --- /dev/null +++ b/examples/script/context2d/scripts/linecap.js @@ -0,0 +1,24 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + var lineCap = ['butt','round','square']; + + // Draw guides + ctx.save(); + ctx.strokeStyle = '#09f'; + ctx.beginPath(); + ctx.moveTo(10,10); + ctx.lineTo(140,10); + ctx.moveTo(10,140); + ctx.lineTo(140,140); + ctx.stroke(); + + // Draw lines + ctx.strokeStyle = 'black'; + for (i=0;i<lineCap.length;i++){ + ctx.lineWidth = 15; + ctx.lineCap = lineCap[i]; + ctx.beginPath(); + ctx.moveTo(25+i*50,10); + ctx.lineTo(25+i*50,140); + ctx.stroke(); + } + ctx.restore(); diff --git a/examples/script/context2d/scripts/linestye.js b/examples/script/context2d/scripts/linestye.js new file mode 100644 index 0000000..728e3e6 --- /dev/null +++ b/examples/script/context2d/scripts/linestye.js @@ -0,0 +1,10 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); +ctx.save(); + for (i=0;i<10;i++){ + ctx.lineWidth = 1+i; + ctx.beginPath(); + ctx.moveTo(5+i*14,5); + ctx.lineTo(5+i*14,140); + ctx.stroke(); + } +ctx.restore();
\ No newline at end of file diff --git a/examples/script/context2d/scripts/moveto.js b/examples/script/context2d/scripts/moveto.js new file mode 100644 index 0000000..73c4e8d --- /dev/null +++ b/examples/script/context2d/scripts/moveto.js @@ -0,0 +1,20 @@ +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Draw shapes + ctx.beginPath(); + ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle + ctx.moveTo(110,75); + ctx.arc(75,75,35,0,Math.PI,false); // Mouth + ctx.moveTo(65,65); + ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye + ctx.moveTo(95,65); + ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye + ctx.stroke(); + + } diff --git a/examples/script/context2d/scripts/moveto2.js b/examples/script/context2d/scripts/moveto2.js new file mode 100644 index 0000000..021f47b --- /dev/null +++ b/examples/script/context2d/scripts/moveto2.js @@ -0,0 +1,24 @@ +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Filled triangle + ctx.beginPath(); + ctx.moveTo(25,25); + ctx.lineTo(105,25); + ctx.lineTo(25,105); + ctx.fill(); + + // Stroked triangle + ctx.beginPath(); + ctx.moveTo(125,125); + ctx.lineTo(125,45); + ctx.lineTo(45,125); + ctx.closePath(); + ctx.stroke(); + + } diff --git a/examples/script/context2d/scripts/pacman.js b/examples/script/context2d/scripts/pacman.js new file mode 100644 index 0000000..af3750f --- /dev/null +++ b/examples/script/context2d/scripts/pacman.js @@ -0,0 +1,83 @@ +function roundedRect(ctx,x,y,width,height,radius){ + ctx.beginPath(); + ctx.moveTo(x,y+radius); + ctx.lineTo(x,y+height-radius); + ctx.quadraticCurveTo(x,y+height,x+radius,y+height); + ctx.lineTo(x+width-radius,y+height); + ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); + ctx.lineTo(x+width,y+radius); + ctx.quadraticCurveTo(x+width,y,x+width-radius,y); + ctx.lineTo(x+radius,y); + ctx.quadraticCurveTo(x,y,x,y+radius); + ctx.stroke(); +} + +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Draw shapes + roundedRect(ctx,12,12,150,150,15); + roundedRect(ctx,19,19,150,150,9); + roundedRect(ctx,53,53,49,33,10); + roundedRect(ctx,53,119,49,16,6); + roundedRect(ctx,135,53,49,33,10); + roundedRect(ctx,135,119,25,49,10); + + // Character 1 + ctx.beginPath(); + ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false); + ctx.lineTo(34,37); + ctx.fill(); + + // blocks + for(i=0;i<8;i++){ + ctx.fillRect(51+i*16,35,4,4); + } + for(i=0;i<6;i++){ + ctx.fillRect(115,51+i*16,4,4); + } + for(i=0;i<8;i++){ + ctx.fillRect(51+i*16,99,4,4); + } + + // character 2 + ctx.beginPath(); + ctx.moveTo(83,116); + ctx.lineTo(83,102); + + ctx.bezierCurveTo(83,94,89,88,97,88); + ctx.bezierCurveTo(105,88,111,94,111,102); + ctx.lineTo(111,116); + ctx.lineTo(106.333,111.333); + ctx.lineTo(101.666,116); + ctx.lineTo(97,111.333); + ctx.lineTo(92.333,116); + ctx.lineTo(87.666,111.333); + ctx.lineTo(83,116); + ctx.fill(); + ctx.fillStyle = "white"; + ctx.beginPath(); + ctx.moveTo(91,96); + ctx.bezierCurveTo(88,96,87,99,87,101); + ctx.bezierCurveTo(87,103,88,106,91,106); + ctx.bezierCurveTo(94,106,95,103,95,101); + ctx.bezierCurveTo(95,99,94,96,91,96); + ctx.moveTo(103,96); + ctx.bezierCurveTo(100,96,99,99,99,101); + ctx.bezierCurveTo(99,103,100,106,103,106); + ctx.bezierCurveTo(106,106,107,103,107,101); + ctx.bezierCurveTo(107,99,106,96,103,96); + ctx.fill(); + ctx.fillStyle = "black"; + ctx.beginPath(); + ctx.arc(101,102,2,0,Math.PI*2,true); + ctx.fill(); + ctx.beginPath(); + ctx.arc(89,102,2,0,Math.PI*2,true); + ctx.fill(); + } diff --git a/examples/script/context2d/scripts/plasma.js b/examples/script/context2d/scripts/plasma.js new file mode 100644 index 0000000..1aa9294 --- /dev/null +++ b/examples/script/context2d/scripts/plasma.js @@ -0,0 +1,58 @@ +var counter = 0; + +var PIXEL_SIZE = 4; + +var temp_1 = 0; + +function init() +{ + setInterval('render()',50); +} + +function dist(a, b, c, d) +{ + return Math.sqrt((a - c) * (a - c) + (b - d) * (b - d)); +} + + +function render() +{ + var canvas = document.getElementById('tutorial'); + canvas.resize(128, 128); + var ctx = canvas.getContext('2d'); + ctx.save(); + + var time = counter * 5; + + + for( y = 0; y < 128; y+=PIXEL_SIZE) { + for( x = 0 ; x < 128; x+=PIXEL_SIZE) { + + + var temp_val = Math.floor(Math.sin(dist(x + time, y, 128.0, 128.0) / 8.0) + + Math.sin(dist(x, y, 64.0, 64.0) / 8.0) + + Math.sin(dist(x, y + time / 7, 192.0, 64) / 7.0) + + Math.sin(dist(x, y, 192.0, 100.0) / 8.0)); + + + + + var temp_col = Math.floor((2 + temp_val) * 50); + + var rand_red = temp_col * 3; + var rand_green = temp_col ; + var rand_blue = 128 - temp_col; + + ctx.fillStyle = "rgb("+rand_red+","+rand_green+","+rand_blue+")"; + + ctx.fillRect(x,y,PIXEL_SIZE,PIXEL_SIZE); + } + } + + + ctx.restore(); + counter++; + +} + +init(); diff --git a/examples/script/context2d/scripts/pong.js b/examples/script/context2d/scripts/pong.js new file mode 100644 index 0000000..2bff053 --- /dev/null +++ b/examples/script/context2d/scripts/pong.js @@ -0,0 +1,235 @@ +// globals +playarea_canvas = document.getElementById('tutorial'); +playarea_canvas.resize(320,200); +playarea = playarea_canvas.getContext('2d'); +//p1_scr = document.getElementById('p1_scr'); +//p2_scr = document.getElementById('p2_scr'); +//status_msg = document.getElementById('status'); +//debug = document.getElementById('debug'); +ball_direction = 0; +up = -1; +down = 1; + +//key codes +key_up = 38; +key_down = 40; +key_W = 87; +key_S = 83; +key_pause = 32; + +speed = 2; //controls the speed of the ball +paddle_inc = 10; //how many pixels paddle can move in either direction +pause = false; + +player_1 = 0; //player IDs +player_2 = 1; +player_1_scr = 0; //player scores +player_2_scr = 0; +player_1_direction = null; //null = no movement whatsoever +player_2_direction = null; + +pa = new Array(); +divider = new Array(); +paddle_1 = new Array(); +paddle_2 = new Array(); +ball = new Array(); + + +function sleep(numberMillis) +{ + var now = new Date(); + var exitTime = now.getTime() + numberMillis; + while (true) { + now = new Date(); + if (now.getTime() > exitTime) + return; + } +} + +function init() +{ + pa['width'] = 150; + pa['height'] = 140; + pa['player_margin'] = 10; //area behind player paddles + pa['foreground'] = "#FFFFFF"; + pa['background'] = "#000000"; + + divider['pos'] = pa['width']/2; + divider['width'] = 4; + + paddle_1['width'] = 8; + paddle_1['height'] = 64; + paddle_1['x'] = pa['player_margin']; + paddle_1['y'] = (pa['height'] /2 ) - (paddle_1['height'] / 2); + + paddle_2['width'] = 8; + paddle_2['height'] = 64; + paddle_2['x'] = (pa['width'] - pa['player_margin'] - paddle_2['width']); + paddle_2['y'] = (pa['height'] /2 ) - (paddle_2['height'] / 2); + + ball['width'] = 10; + ball['height'] = 10; + ball['x'] = (pa['width']/2) - (ball['width'] / 2); + ball['y'] = (pa['height']/2) - (ball['height'] / 2); + + ball_direction = Math.random() * 360; //initialize ball direction, which is determined by angle, at random + speed = 2; +} + +function renderPlayarea() +{ + playarea.beginPath(); + + playarea.clearRect(0,0,pa['width'],pa['height']); + playarea.fillStyle = pa['background']; + playarea.strokeStyle = pa['foreground']; + playarea.fillRect(0,0, pa['width'], pa['height']); + + //move paddles + if(player_1_direction != null) + { + if(player_1_direction == up) + paddle_1['y'] = paddle_1['y'] - paddle_inc; + else + paddle_1['y'] = paddle_1['y'] + paddle_inc; + } + if(player_2_direction != null) + { + if(player_2_direction == up) + paddle_2['y'] = paddle_2['y'] - paddle_inc; + else + paddle_2['y'] = paddle_2['y'] + paddle_inc; + } + playarea.rect(paddle_1['x'],paddle_1['y'],paddle_1['width'],paddle_1['height']); + playarea.rect(paddle_2['x'],paddle_2['y'],paddle_2['width'],paddle_2['height']); + + //move ball + playarea.rect(ball['x'], ball['y'], ball['width'], ball['height']); + ball['x'] = ball['x'] + Math.cos((ball_direction)*Math.PI/180) * speed; + ball['y'] = ball['y'] + Math.sin((ball_direction)*Math.PI/180) * speed; + + playarea.fillStyle = pa['foreground']; + playarea.fill(); + + playarea.beginPath(); + //redraw divider + playarea.lineWidth = divider['width']; + playarea.lineTo(divider['pos'], 0); + playarea.lineTo(divider['pos'], pa['height'] = 200); + playarea.lineWidth = 1; + + playarea.stroke(); + playarea.closePath(); +} + +function testCollisions() +{ + //make sure paddles don't go beyond play area + if(((paddle_1['y'] <= 0) && (player_1_direction == up)) || ((paddle_1['y'] >= (pa['height'] - paddle_1['height'])) && (player_1_direction == down))) + player_1_direction = null; + if(((paddle_2['y'] <= 0) && (player_2_direction == up)) || ((paddle_2['y'] >= (pa['height'] - paddle_2['height'])) && (player_2_direction == down))) + player_2_direction = null; + + //check to see if ball went beyond paddles, and if so, score accordingly and reset playarea + if(ball['x'] <= 0) + { + setScore(player_2); + init() + sleep(1000); + } + if(ball['x'] >= (pa['width'] - ball['width'])) + { + setScore(player_1); + init(); + sleep(1000); + } + + //check to see if ball hit top or bottom wall. if so, change direction + if((ball['y'] >= (pa['height'] - ball['height'])) || ball['y'] <= 0) + ball_direction = -ball_direction; + + //check to see if the ball hit a paddle, and if so, change ball angle dependant on where it hit the paddle + if((ball['x'] <= (paddle_1['x'] + paddle_1['width'])) && (ball['y'] >= paddle_1['y']) && (ball['y'] <= (paddle_1['y'] + paddle_1['height']))) + { + ball_direction = -ball_direction/2; + speed += .5; + } + if(((ball['x'] + ball['width']) >= paddle_2['x']) && (ball['y'] >= paddle_2['y']) && (ball['y'] <= (paddle_2['y'] + paddle_2['height']))) + { + ball_direction = (180+ball_direction)/2; + speed += .5; + } +} + +function setScore(p) +{ + if(p == player_1) + { + player_1_scr++; + //p1_scr.firstChild.nodeValue = player_1_scr; + } + if(p == player_2) + { + player_2_scr++; + //p2_scr.firstChild.nodeValue = player_2_scr; + } +} + + +//handle input +document.onkeydown = function(ev) +{ + switch(ev.keyCode) + { + case key_W: + player_1_direction = up; + break; + case key_S: + player_1_direction = down; + break; + case key_up: + player_2_direction = up; + break; + case key_down: + player_2_direction = down; + break; + } +} + +document.onkeyup = function(ev) +{ + switch(ev.keyCode) + { + case key_W: + case key_S: + player_1_direction = null; + break; + case key_up: + case key_down: + player_2_direction = null; + break; + case key_pause: + if(pause == false) + { + clearInterval(game); + //status_msg.style.visibility = "visible"; + pause = true; + } + else + { + game = setInterval(main, 25); + //status_msg.style.visibility = "hidden"; + pause = false; + } + break; + } +} + +function main() +{ + testCollisions(); + renderPlayarea(); +} + +init(); +game = setInterval(main, 25); diff --git a/examples/script/context2d/scripts/quad.js b/examples/script/context2d/scripts/quad.js new file mode 100644 index 0000000..ad3a0d5 --- /dev/null +++ b/examples/script/context2d/scripts/quad.js @@ -0,0 +1,21 @@ +var canvas = document.getElementById('tutorial'); + + // Make sure we don't execute when canvas isn't supported + if (canvas.getContext){ + + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + + // Draw shapes + + ctx.beginPath(); + ctx.moveTo(75,25); + ctx.quadraticCurveTo(25,25,25,62.5); + ctx.quadraticCurveTo(25,100,50,100); + ctx.quadraticCurveTo(50,120,30,125); + ctx.quadraticCurveTo(60,120,65,100); + ctx.quadraticCurveTo(125,100,125,62.5); + ctx.quadraticCurveTo(125,25,75,25); + ctx.stroke(); + + } diff --git a/examples/script/context2d/scripts/rgba.js b/examples/script/context2d/scripts/rgba.js new file mode 100644 index 0000000..a4e5e9a --- /dev/null +++ b/examples/script/context2d/scripts/rgba.js @@ -0,0 +1,19 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + + // Draw background + ctx.fillStyle = 'rgb(255,221,0)'; + ctx.fillRect(0,0,150,37.5); + ctx.fillStyle = 'rgb(102,204,0)'; + ctx.fillRect(0,37.5,150,37.5); + ctx.fillStyle = 'rgb(0,153,255)'; + ctx.fillRect(0,75,150,37.5); + ctx.fillStyle = 'rgb(255,51,0)'; + ctx.fillRect(0,112.5,150,37.5); + + // Draw semi transparent rectangles + for (i=0;i<10;i++){ + ctx.fillStyle = 'rgba(255,255,255,'+(i+1)/10+')'; + for (j=0;j<4;j++){ + ctx.fillRect(5+i*14,5+j*37.5,14,27.5) + } + } diff --git a/examples/script/context2d/scripts/rotate.js b/examples/script/context2d/scripts/rotate.js new file mode 100644 index 0000000..c7ef369 --- /dev/null +++ b/examples/script/context2d/scripts/rotate.js @@ -0,0 +1,16 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + ctx.translate(75,75); + + for (i=1;i<6;i++){ // Loop through rings (from inside to out) + ctx.save(); + ctx.fillStyle = 'rgb('+(51*i)+','+(255-51*i)+',255)'; + + for (j=0;j<i*6;j++){ // draw individual dots + ctx.rotate(Math.PI*2/(i*6)); + ctx.beginPath(); + ctx.arc(0,i*12.5,5,0,Math.PI*2,true); + ctx.fill(); + } + + ctx.restore(); + } diff --git a/examples/script/context2d/scripts/scale.js b/examples/script/context2d/scripts/scale.js new file mode 100644 index 0000000..75ef865 --- /dev/null +++ b/examples/script/context2d/scripts/scale.js @@ -0,0 +1,67 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + ctx.strokeStyle = "#fc0"; + ctx.lineWidth = 1.5; + ctx.fillRect(0,0,300,300); + + // Uniform scaling + ctx.save() + ctx.translate(50,50); + drawSpirograph(ctx,22,6,5); // no scaling + + ctx.translate(100,0); + ctx.scale(0.75,0.75); + drawSpirograph(ctx,22,6,5); + + ctx.translate(133.333,0); + ctx.scale(0.75,0.75); + drawSpirograph(ctx,22,6,5); + ctx.restore(); + + // Non uniform scaling (y direction) + ctx.strokeStyle = "#0cf"; + ctx.save() + ctx.translate(50,150); + ctx.scale(1,0.75); + drawSpirograph(ctx,22,6,5); + + ctx.translate(100,0); + ctx.scale(1,0.75); + drawSpirograph(ctx,22,6,5); + + ctx.translate(100,0); + ctx.scale(1,0.75); + drawSpirograph(ctx,22,6,5); + ctx.restore(); + + // Non uniform scaling (x direction) + ctx.strokeStyle = "#cf0"; + ctx.save() + ctx.translate(50,250); + ctx.scale(0.75,1); + drawSpirograph(ctx,22,6,5); + + ctx.translate(133.333,0); + ctx.scale(0.75,1); + drawSpirograph(ctx,22,6,5); + + ctx.translate(177.777,0); + ctx.scale(0.75,1); + drawSpirograph(ctx,22,6,5); + ctx.restore(); +function drawSpirograph(ctx,R,r,O){ + var x1 = R-O; + var y1 = 0; + var i = 1; + ctx.beginPath(); + ctx.moveTo(x1,y1); + do { + if (i>20000) break; + var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72)) + var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72)) + ctx.lineTo(x2,y2); + x1 = x2; + y1 = y2; + i++; + } while (x2 != R-O && y2 != 0 ); + ctx.stroke(); +} diff --git a/examples/script/context2d/scripts/stroke1.js b/examples/script/context2d/scripts/stroke1.js new file mode 100644 index 0000000..0561a52 --- /dev/null +++ b/examples/script/context2d/scripts/stroke1.js @@ -0,0 +1,10 @@ +var ctx = document.getElementById('tutorial').getContext('2d'); + for (i=0;i<6;i++){ + for (j=0;j<6;j++){ + ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' + + Math.floor(255-42.5*j) + ')'; + ctx.beginPath(); + ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true); + ctx.stroke(); + } + } diff --git a/examples/script/context2d/scripts/translate.js b/examples/script/context2d/scripts/translate.js new file mode 100644 index 0000000..7c94433 --- /dev/null +++ b/examples/script/context2d/scripts/translate.js @@ -0,0 +1,29 @@ + var ctx = document.getElementById('tutorial').getContext('2d'); + ctx.fillRect(0,0,300,300); + for (var i=0;i<3;i++) { + for (var j=0;j<3;j++) { + ctx.save(); + ctx.strokeStyle = "#9CFF00"; + ctx.translate(50+j*100,50+i*100); + drawSpirograph(ctx,20*(j+2)/(j+1),-8*(i+3)/(i+1),10); + ctx.restore(); + } + } + +function drawSpirograph(ctx,R,r,O){ + var x1 = R-O; + var y1 = 0; + var i = 1; + ctx.beginPath(); + ctx.moveTo(x1,y1); + do { + if (i>20000) break; + var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72)) + var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72)) + ctx.lineTo(x2,y2); + x1 = x2; + y1 = y2; + i++; + } while (x2 != R-O && y2 != 0 ); + ctx.stroke(); +} diff --git a/examples/script/context2d/window.cpp b/examples/script/context2d/window.cpp new file mode 100644 index 0000000..a93bf30 --- /dev/null +++ b/examples/script/context2d/window.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" +#include "environment.h" +#include "context2d.h" +#include "qcontext2dcanvas.h" +#include <QHBoxLayout> +#include <QListWidget> +#include <QDir> +#include <QMessageBox> + +#ifndef QT_NO_SCRIPTTOOLS +#include <QAction> +#include <QApplication> +#include <QMainWindow> +#include <QPushButton> +#include <QVBoxLayout> +#include <QScriptEngineDebugger> +#endif + +static QString scriptsDir() +{ + if (QFile::exists("./scripts")) + return "./scripts"; + return ":/scripts"; +} + +//! [0] +Window::Window(QWidget *parent) + : QWidget(parent) +{ + m_env = new Environment(this); + QObject::connect(m_env, SIGNAL(scriptError(QScriptValue)), + this, SLOT(reportScriptError(QScriptValue))); + + Context2D *context = new Context2D(this); + context->setSize(150, 150); + m_canvas = new QContext2DCanvas(context, m_env, this); + m_canvas->setFixedSize(context->size()); + m_canvas->setObjectName("tutorial"); + m_env->addCanvas(m_canvas); +//! [0] + +#ifndef QT_NO_SCRIPTTOOLS + QVBoxLayout *vbox = new QVBoxLayout(); + vbox->addWidget(m_canvas); + m_debugButton = new QPushButton(tr("Run in Debugger")); + connect(m_debugButton, SIGNAL(clicked()), this, SLOT(runInDebugger())); + vbox->addWidget(m_debugButton); +#endif + + QHBoxLayout *hbox = new QHBoxLayout(this); + m_view = new QListWidget(this); + m_view->setEditTriggers(QAbstractItemView::NoEditTriggers); + hbox->addWidget(m_view); +#ifndef QT_NO_SCRIPTTOOLS + hbox->addLayout(vbox); +#else + hbox->addWidget(m_canvas); +#endif + +//! [1] + QDir dir(scriptsDir()); + QFileInfoList entries = dir.entryInfoList(QStringList() << "*.js"); + for (int i = 0; i < entries.size(); ++i) + m_view->addItem(entries.at(i).fileName()); + connect(m_view, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), + this, SLOT(selectScript(QListWidgetItem*))); +//! [1] + +#ifndef QT_NO_SCRIPTTOOLS + m_debugger = new QScriptEngineDebugger(this); + m_debugger->attachTo(m_env->engine()); + m_debugWindow = m_debugger->standardWindow(); + m_debugWindow->setWindowModality(Qt::ApplicationModal); + m_debugWindow->resize(1280, 704); +#endif + + setWindowTitle(tr("Context 2D")); +} + +//! [2] +void Window::selectScript(QListWidgetItem *item) +{ + QString fileName = item->text(); + runScript(fileName, /*debug=*/false); +} +//! [2] + +void Window::reportScriptError(const QScriptValue &error) +{ + QMessageBox::warning(this, tr("Context 2D"), tr("Line %0: %1") + .arg(error.property("lineNumber").toInt32()) + .arg(error.toString())); +} + +#ifndef QT_NO_SCRIPTTOOLS +//! [3] +void Window::runInDebugger() +{ + QListWidgetItem *item = m_view->currentItem(); + if (item) { + QString fileName = item->text(); + runScript(fileName, /*debug=*/true); + } +} +//! [3] +#endif + +//! [4] +void Window::runScript(const QString &fileName, bool debug) +{ + QFile file(scriptsDir() + "/" + fileName); + file.open(QIODevice::ReadOnly); + QString contents = file.readAll(); + file.close(); + m_env->reset(); + +#ifndef QT_NO_SCRIPTTOOLS + if (debug) + m_debugger->action(QScriptEngineDebugger::InterruptAction)->trigger(); +#else + Q_UNUSED(debug); +#endif + + QScriptValue ret = m_env->evaluate(contents, fileName); + +#ifndef QT_NO_SCRIPTTOOLS + m_debugWindow->hide(); +#endif + + if (ret.isError()) + reportScriptError(ret); +} +//! [4] diff --git a/examples/script/context2d/window.h b/examples/script/context2d/window.h new file mode 100644 index 0000000..a0aff8e --- /dev/null +++ b/examples/script/context2d/window.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include <QWidget> +class Environment; +class QContext2DCanvas; +QT_BEGIN_NAMESPACE +class QListWidget; +class QListWidgetItem; +class QMainWindow; +class QPushButton; +class QScriptValue; +class QScriptEngineDebugger; +QT_END_NAMESPACE + +class Window : public QWidget +{ + Q_OBJECT +public: + Window(QWidget *parent = 0); +private slots: + void selectScript(QListWidgetItem *item); + void reportScriptError(const QScriptValue &value); +#ifndef QT_NO_SCRIPTTOOLS + void runInDebugger(); +#endif +private: + void runScript(const QString &fileName, bool debug); + + QListWidget *m_view; + Environment *m_env; + QContext2DCanvas *m_canvas; +#ifndef QT_NO_SCRIPTTOOLS + QScriptEngineDebugger *m_debugger; + QPushButton *m_debugButton; + QMainWindow *m_debugWindow; +#endif +}; + +#endif // WINDOW_H diff --git a/examples/script/customclass/bytearrayclass.cpp b/examples/script/customclass/bytearrayclass.cpp new file mode 100644 index 0000000..7865381 --- /dev/null +++ b/examples/script/customclass/bytearrayclass.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtScript/QScriptClassPropertyIterator> +#include <QtScript/QScriptEngine> +#include "bytearrayclass.h" +#include "bytearrayprototype.h" + +#include <stdlib.h> + +Q_DECLARE_METATYPE(QByteArray*) +Q_DECLARE_METATYPE(ByteArrayClass*) + +class ByteArrayClassPropertyIterator : public QScriptClassPropertyIterator +{ +public: + ByteArrayClassPropertyIterator(const QScriptValue &object); + ~ByteArrayClassPropertyIterator(); + + bool hasNext() const; + void next(); + + bool hasPrevious() const; + void previous(); + + void toFront(); + void toBack(); + + QScriptString name() const; + uint id() const; + +private: + int m_index; + int m_last; +}; + +static qint32 toArrayIndex(const QString &str) +{ + QByteArray bytes = str.toUtf8(); + char *eptr; + quint32 pos = strtoul(bytes.constData(), &eptr, 10); + if ((eptr == bytes.constData() + bytes.size()) + && (QByteArray::number(pos) == bytes)) { + return pos; + } + return -1; +} + +//! [0] +ByteArrayClass::ByteArrayClass(QScriptEngine *engine) + : QObject(engine), QScriptClass(engine) +{ + qScriptRegisterMetaType<QByteArray>(engine, toScriptValue, fromScriptValue); + + length = engine->toStringHandle(QLatin1String("length")); + + proto = engine->newQObject(new ByteArrayPrototype(this), + QScriptEngine::QtOwnership, + QScriptEngine::SkipMethodsInEnumeration + | QScriptEngine::ExcludeSuperClassMethods + | QScriptEngine::ExcludeSuperClassProperties); + QScriptValue global = engine->globalObject(); + proto.setPrototype(global.property("Object").property("prototype")); + + ctor = engine->newFunction(construct); + ctor.setData(qScriptValueFromValue(engine, this)); +} +//! [0] + +ByteArrayClass::~ByteArrayClass() +{ +} + +//! [3] +QScriptClass::QueryFlags ByteArrayClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + QByteArray *ba = qscriptvalue_cast<QByteArray*>(object.data()); + if (!ba) + return 0; + if (name == length) { + return flags; + } else { + qint32 pos = toArrayIndex(name); + if (pos == -1) + return 0; + *id = pos; + if ((flags & HandlesReadAccess) && (pos >= ba->size())) + flags &= ~HandlesReadAccess; + return flags; + } +} +//! [3] + +//! [4] +QScriptValue ByteArrayClass::property(const QScriptValue &object, + const QScriptString &name, uint id) +{ + QByteArray *ba = qscriptvalue_cast<QByteArray*>(object.data()); + if (!ba) + return QScriptValue(); + if (name == length) { + return ba->length(); + } else { + qint32 pos = id; + if ((pos < 0) || (pos >= ba->size())) + return QScriptValue(); + return uint(ba->at(pos)) & 255; + } + return QScriptValue(); +} +//! [4] + +//! [5] +void ByteArrayClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + QByteArray *ba = qscriptvalue_cast<QByteArray*>(object.data()); + if (!ba) + return; + if (name == length) { + ba->resize(value.toInt32()); + } else { + qint32 pos = id; + if (pos < 0) + return; + if (ba->size() <= pos) + ba->resize(pos + 1); + (*ba)[pos] = char(value.toInt32()); + } +} +//! [5] + +//! [6] +QScriptValue::PropertyFlags ByteArrayClass::propertyFlags( + const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/) +{ + if (name == length) { + return QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration; + } + return QScriptValue::Undeletable; +} +//! [6] + +//! [7] +QScriptClassPropertyIterator *ByteArrayClass::newIterator(const QScriptValue &object) +{ + return new ByteArrayClassPropertyIterator(object); +} +//! [7] + +QString ByteArrayClass::name() const +{ + return QLatin1String("ByteArray"); +} + +QScriptValue ByteArrayClass::prototype() const +{ + return proto; +} + +QScriptValue ByteArrayClass::constructor() +{ + return ctor; +} + +QScriptValue ByteArrayClass::newInstance(int size) +{ + return newInstance(QByteArray(size, /*ch=*/0)); +} + +//! [1] +QScriptValue ByteArrayClass::newInstance(const QByteArray &ba) +{ + QScriptValue data = engine()->newVariant(qVariantFromValue(ba)); + return engine()->newObject(this, data); +} +//! [1] + +//! [2] +QScriptValue ByteArrayClass::construct(QScriptContext *ctx, QScriptEngine *) +{ + ByteArrayClass *cls = qscriptvalue_cast<ByteArrayClass*>(ctx->callee().data()); + if (!cls) + return QScriptValue(); + int size = ctx->argument(0).toInt32(); + return cls->newInstance(size); +} +//! [2] + +QScriptValue ByteArrayClass::toScriptValue(QScriptEngine *eng, const QByteArray &ba) +{ + QScriptValue ctor = eng->globalObject().property("ByteArray"); + ByteArrayClass *cls = qscriptvalue_cast<ByteArrayClass*>(ctor.data()); + if (!cls) + return eng->newVariant(qVariantFromValue(ba)); + return cls->newInstance(ba); +} + +void ByteArrayClass::fromScriptValue(const QScriptValue &obj, QByteArray &ba) +{ + ba = qscriptvalue_cast<QByteArray>(obj.data()); +} + + + +ByteArrayClassPropertyIterator::ByteArrayClassPropertyIterator(const QScriptValue &object) + : QScriptClassPropertyIterator(object) +{ + toFront(); +} + +ByteArrayClassPropertyIterator::~ByteArrayClassPropertyIterator() +{ +} + +//! [8] +bool ByteArrayClassPropertyIterator::hasNext() const +{ + QByteArray *ba = qscriptvalue_cast<QByteArray*>(object().data()); + return m_index < ba->size(); +} + +void ByteArrayClassPropertyIterator::next() +{ + m_last = m_index; + ++m_index; +} + +bool ByteArrayClassPropertyIterator::hasPrevious() const +{ + return (m_index > 0); +} + +void ByteArrayClassPropertyIterator::previous() +{ + --m_index; + m_last = m_index; +} + +void ByteArrayClassPropertyIterator::toFront() +{ + m_index = 0; + m_last = -1; +} + +void ByteArrayClassPropertyIterator::toBack() +{ + QByteArray *ba = qscriptvalue_cast<QByteArray*>(object().data()); + m_index = ba->size(); + m_last = -1; +} + +QScriptString ByteArrayClassPropertyIterator::name() const +{ + return QScriptString(); +} + +uint ByteArrayClassPropertyIterator::id() const +{ + return m_last; +} +//! [8] diff --git a/examples/script/customclass/bytearrayclass.h b/examples/script/customclass/bytearrayclass.h new file mode 100644 index 0000000..e9a5f07 --- /dev/null +++ b/examples/script/customclass/bytearrayclass.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BYTEARRAYCLASS_H +#define BYTEARRAYCLASS_H + +#include <QtCore/QObject> +#include <QtScript/QScriptClass> +#include <QtScript/QScriptString> + +class ByteArrayClass : public QObject, public QScriptClass +{ +public: + ByteArrayClass(QScriptEngine *engine); + ~ByteArrayClass(); + + QScriptValue constructor(); + + QScriptValue newInstance(int size = 0); + QScriptValue newInstance(const QByteArray &ba); + + QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + + QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint id); + + void setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value); + + QScriptValue::PropertyFlags propertyFlags( + const QScriptValue &object, const QScriptString &name, uint id); + + QScriptClassPropertyIterator *newIterator(const QScriptValue &object); + + QString name() const; + + QScriptValue prototype() const; + +private: + static QScriptValue construct(QScriptContext *ctx, QScriptEngine *eng); + + static QScriptValue toScriptValue(QScriptEngine *eng, const QByteArray &ba); + static void fromScriptValue(const QScriptValue &obj, QByteArray &ba); + + QScriptString length; + QScriptValue proto; + QScriptValue ctor; +}; + +#endif diff --git a/examples/script/customclass/bytearrayclass.pri b/examples/script/customclass/bytearrayclass.pri new file mode 100644 index 0000000..05fdeb4 --- /dev/null +++ b/examples/script/customclass/bytearrayclass.pri @@ -0,0 +1,6 @@ +SOURCES += $$PWD/bytearrayclass.cpp \ + $$PWD/bytearrayprototype.cpp +HEADERS += $$PWD/bytearrayclass.h \ + $$PWD/bytearrayprototype.h + +INCLUDEPATH += $$PWD diff --git a/examples/script/customclass/bytearrayprototype.cpp b/examples/script/customclass/bytearrayprototype.cpp new file mode 100644 index 0000000..eeb73f9 --- /dev/null +++ b/examples/script/customclass/bytearrayprototype.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bytearrayprototype.h" +#include <QtScript/QScriptEngine> + +Q_DECLARE_METATYPE(QByteArray*) + +ByteArrayPrototype::ByteArrayPrototype(QObject *parent) + : QObject(parent) +{ +} + +ByteArrayPrototype::~ByteArrayPrototype() +{ +} + +//! [0] +QByteArray *ByteArrayPrototype::thisByteArray() const +{ + return qscriptvalue_cast<QByteArray*>(thisObject().data()); +} +//! [0] + +void ByteArrayPrototype::chop(int n) +{ + thisByteArray()->chop(n); +} + +bool ByteArrayPrototype::equals(const QByteArray &other) +{ + return *thisByteArray() == other; +} + +QByteArray ByteArrayPrototype::left(int len) const +{ + return thisByteArray()->left(len); +} + +//! [1] +QByteArray ByteArrayPrototype::mid(int pos, int len) const +{ + return thisByteArray()->mid(pos, len); +} + +QScriptValue ByteArrayPrototype::remove(int pos, int len) +{ + thisByteArray()->remove(pos, len); + return thisObject(); +} +//! [1] + +QByteArray ByteArrayPrototype::right(int len) const +{ + return thisByteArray()->right(len); +} + +QByteArray ByteArrayPrototype::simplified() const +{ + return thisByteArray()->simplified(); +} + +QByteArray ByteArrayPrototype::toBase64() const +{ + return thisByteArray()->toBase64(); +} + +QByteArray ByteArrayPrototype::toLower() const +{ + return thisByteArray()->toLower(); +} + +QByteArray ByteArrayPrototype::toUpper() const +{ + return thisByteArray()->toUpper(); +} + +QByteArray ByteArrayPrototype::trimmed() const +{ + return thisByteArray()->trimmed(); +} + +void ByteArrayPrototype::truncate(int pos) +{ + thisByteArray()->truncate(pos); +} + +QString ByteArrayPrototype::toLatin1String() const +{ + return QString::fromLatin1(*thisByteArray()); +} + +//! [2] +QScriptValue ByteArrayPrototype::valueOf() const +{ + return thisObject().data(); +} +//! [2] diff --git a/examples/script/customclass/bytearrayprototype.h b/examples/script/customclass/bytearrayprototype.h new file mode 100644 index 0000000..fe9e15b --- /dev/null +++ b/examples/script/customclass/bytearrayprototype.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BYTEARRAYPROTOTYPE_H +#define BYTEARRAYPROTOTYPE_H + +#include <QtCore/QByteArray> +#include <QtCore/QObject> +#include <QtScript/QScriptable> +#include <QtScript/QScriptValue> + +//! [0] +class ByteArrayPrototype : public QObject, public QScriptable +{ +Q_OBJECT +public: + ByteArrayPrototype(QObject *parent = 0); + ~ByteArrayPrototype(); + +public slots: + void chop(int n); + bool equals(const QByteArray &other); + QByteArray left(int len) const; + QByteArray mid(int pos, int len = -1) const; + QScriptValue remove(int pos, int len); + QByteArray right(int len) const; + QByteArray simplified() const; + QByteArray toBase64() const; + QByteArray toLower() const; + QByteArray toUpper() const; + QByteArray trimmed() const; + void truncate(int pos); + QString toLatin1String() const; + QScriptValue valueOf() const; + +private: + QByteArray *thisByteArray() const; +}; +//! [0] + + +#endif diff --git a/examples/script/customclass/customclass.pro b/examples/script/customclass/customclass.pro new file mode 100644 index 0000000..ba7f69d --- /dev/null +++ b/examples/script/customclass/customclass.pro @@ -0,0 +1,13 @@ +QT = core script +win32: CONFIG += console +mac:CONFIG -= app_bundle + +SOURCES += main.cpp + +include(bytearrayclass.pri) + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/customclass +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro *.pri +sources.path = $$[QT_INSTALL_EXAMPLES]/script/customclass +INSTALLS += target sources diff --git a/examples/script/customclass/main.cpp b/examples/script/customclass/main.cpp new file mode 100644 index 0000000..1c3ceb1 --- /dev/null +++ b/examples/script/customclass/main.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtScript> +#include "bytearrayclass.h" + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QScriptEngine eng; + + ByteArrayClass *baClass = new ByteArrayClass(&eng); + eng.globalObject().setProperty("ByteArray", baClass->constructor()); + + qDebug() << "ba = new ByteArray(4):" << eng.evaluate("ba = new ByteArray(4)").toString(); + qDebug() << "ba.length:" << eng.evaluate("ba.length").toNumber(); + qDebug() << "ba[1] = 123; ba[1]:" << eng.evaluate("ba[1] = 123; ba[1]").toNumber(); + qDebug() << "ba[7] = 224; ba.length:" << eng.evaluate("ba[7] = 224; ba.length").toNumber(); + qDebug() << "for-in loop:" << eng.evaluate("result = '';\n" + "for (var p in ba) {\n" + " if (result.length > 0)\n" + " result += ', ';\n" + " result += '(' + p + ',' + ba[p] + ')';\n" + "} result").toString(); + qDebug() << "ba.toBase64():" << eng.evaluate("b64 = ba.toBase64()").toString(); + qDebug() << "ba.toBase64().toLatin1String():" << eng.evaluate("b64.toLatin1String()").toString(); + qDebug() << "ba.valueOf():" << eng.evaluate("ba.valueOf()").toString(); + qDebug() << "ba.chop(2); ba.length:" << eng.evaluate("ba.chop(2); ba.length").toNumber(); + + return 0; +} diff --git a/examples/script/defaultprototypes/code.js b/examples/script/defaultprototypes/code.js new file mode 100644 index 0000000..048e131 --- /dev/null +++ b/examples/script/defaultprototypes/code.js @@ -0,0 +1,20 @@ +//! [0] +listWidget.addItem("Red"); +listWidget.addItem("Blue"); +listWidget.addItem("Green"); +listWidget.addItem("Cyan"); +listWidget.addItem("Yellow"); +listWidget.addItem("Purple"); +listWidget.addItems(["Orange", "Gray"]); +//! [0] + +//! [1] +listWidget.currentItemChanged.connect( + function(item) + { + listWidget.setBackgroundColor(item.text); + } +); +//! [1] + +listWidget.show(); diff --git a/examples/script/defaultprototypes/defaultprototypes.pro b/examples/script/defaultprototypes/defaultprototypes.pro new file mode 100644 index 0000000..b9a6765 --- /dev/null +++ b/examples/script/defaultprototypes/defaultprototypes.pro @@ -0,0 +1,10 @@ +QT += script +RESOURCES += defaultprototypes.qrc +SOURCES += main.cpp prototypes.cpp +HEADERS += prototypes.h + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/defaultprototypes +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.js defaultprototypes.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/script/defaultprototypes +INSTALLS += target sources diff --git a/examples/script/defaultprototypes/defaultprototypes.qrc b/examples/script/defaultprototypes/defaultprototypes.qrc new file mode 100644 index 0000000..ada405b --- /dev/null +++ b/examples/script/defaultprototypes/defaultprototypes.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/" > + <file>code.js</file> + </qresource> +</RCC> diff --git a/examples/script/defaultprototypes/main.cpp b/examples/script/defaultprototypes/main.cpp new file mode 100644 index 0000000..3245ae0 --- /dev/null +++ b/examples/script/defaultprototypes/main.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> +#include <QtScript> +#include "prototypes.h" + +//! [0] +Q_DECLARE_METATYPE(QListWidgetItem*) +Q_DECLARE_METATYPE(QListWidget*) +//! [0] + +int main(int argc, char **argv) +{ + Q_INIT_RESOURCE(defaultprototypes); + + QApplication app(argc, argv); +//! [1] + QScriptEngine engine; + + ListWidgetItemPrototype lwiProto; + engine.setDefaultPrototype(qMetaTypeId<QListWidgetItem*>(), + engine.newQObject(&lwiProto)); + + ListWidgetPrototype lwProto; + engine.setDefaultPrototype(qMetaTypeId<QListWidget*>(), + engine.newQObject(&lwProto)); +//! [1] + +//! [2] + QListWidget listWidget; + engine.globalObject().setProperty("listWidget", + engine.newQObject(&listWidget)); +//! [2] + + QFile file(":/code.js"); + file.open(QIODevice::ReadOnly); + QScriptValue result = engine.evaluate(file.readAll()); + file.close(); + if (engine.hasUncaughtException()) { + int lineNo = engine.uncaughtExceptionLineNumber(); + qWarning() << "line" << lineNo << ":" << result.toString(); + } + + return app.exec(); +} diff --git a/examples/script/defaultprototypes/prototypes.cpp b/examples/script/defaultprototypes/prototypes.cpp new file mode 100644 index 0000000..b2bad45 --- /dev/null +++ b/examples/script/defaultprototypes/prototypes.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "prototypes.h" +#include <QtGui/QListWidgetItem> +#include <QtGui/QListWidget> +#include <QtScript/QScriptValue> +#include <QtScript/QScriptEngine> + +Q_DECLARE_METATYPE(QListWidgetItem*) +Q_DECLARE_METATYPE(QListWidget*) + +//! [0] +ListWidgetItemPrototype::ListWidgetItemPrototype(QObject *parent) + : QObject(parent) +{ +} + +QString ListWidgetItemPrototype::text() const +{ + QListWidgetItem *item = qscriptvalue_cast<QListWidgetItem*>(thisObject()); + if (item) + return item->text(); + return QString(); +} + +void ListWidgetItemPrototype::setText(const QString &text) +{ + QListWidgetItem *item = qscriptvalue_cast<QListWidgetItem*>(thisObject()); + if (item) + item->setText(text); +} + +QString ListWidgetItemPrototype::toString() const +{ + return QString("ListWidgetItem(text = %0)").arg(text()); +} +//! [0] + + + +//! [1] +ListWidgetPrototype::ListWidgetPrototype(QObject *parent) + : QObject(parent) +{ +} + +void ListWidgetPrototype::addItem(const QString &text) +{ + QListWidget *widget = qscriptvalue_cast<QListWidget*>(thisObject()); + if (widget) + widget->addItem(text); +} + +void ListWidgetPrototype::addItems(const QStringList &texts) +{ + QListWidget *widget = qscriptvalue_cast<QListWidget*>(thisObject()); + if (widget) + widget->addItems(texts); +} + +void ListWidgetPrototype::setBackgroundColor(const QString &colorName) +{ + QListWidget *widget = qscriptvalue_cast<QListWidget*>(thisObject()); + if (widget) { + QPalette palette = widget->palette(); + QColor color(colorName); + palette.setBrush(QPalette::Base, color); + widget->setPalette(palette); + } +} +//! [1] diff --git a/examples/script/defaultprototypes/prototypes.h b/examples/script/defaultprototypes/prototypes.h new file mode 100644 index 0000000..76cecaa --- /dev/null +++ b/examples/script/defaultprototypes/prototypes.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROTOTYPES_H +#define PROTOTYPES_H + +#include <QtCore/QObject> +#include <QtScript/QScriptable> + +//! [0] +class ListWidgetItemPrototype : public QObject, public QScriptable +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) +public: + ListWidgetItemPrototype(QObject *parent = 0); + + QString text() const; + void setText(const QString &text); + +public slots: + QString toString() const; +}; +//! [0] + +//! [1] +class ListWidgetPrototype : public QObject, public QScriptable +{ + Q_OBJECT +public: + ListWidgetPrototype(QObject *parent = 0); + +public slots: + void addItem(const QString &text); + void addItems(const QStringList &texts); + void setBackgroundColor(const QString &colorName); +}; +//! [1] + +#endif diff --git a/examples/script/helloscript/helloscript.pro b/examples/script/helloscript/helloscript.pro new file mode 100644 index 0000000..d94a318 --- /dev/null +++ b/examples/script/helloscript/helloscript.pro @@ -0,0 +1,9 @@ +QT += script +RESOURCES += helloscript.qrc +SOURCES += main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/helloscript +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS helloscript.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/script/helloscript +INSTALLS += target sources diff --git a/examples/script/helloscript/helloscript.qrc b/examples/script/helloscript/helloscript.qrc new file mode 100644 index 0000000..dc93461 --- /dev/null +++ b/examples/script/helloscript/helloscript.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/" > + <file>helloscript.qs</file> + </qresource> +</RCC> diff --git a/examples/script/helloscript/helloscript.qs b/examples/script/helloscript/helloscript.qs new file mode 100644 index 0000000..6d8e87c --- /dev/null +++ b/examples/script/helloscript/helloscript.qs @@ -0,0 +1,5 @@ +//! [0] +button.text = qsTr('Hello World!'); +button.styleSheet = 'font-style: italic'; +button.show(); +//! [0] diff --git a/examples/script/helloscript/main.cpp b/examples/script/helloscript/main.cpp new file mode 100644 index 0000000..4d243a6 --- /dev/null +++ b/examples/script/helloscript/main.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QMessageBox> +#include <QPushButton> +#include <QtScript> + +//! [0] +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(helloscript); +//! [0] + +//! [1] + QApplication app(argc, argv); + + QScriptEngine engine; + + QTranslator translator; + translator.load("helloscript_la"); + app.installTranslator(&translator); + engine.installTranslatorFunctions(); +//! [1] + +//! [2] + QPushButton button; + QScriptValue scriptButton = engine.newQObject(&button); + engine.globalObject().setProperty("button", scriptButton); +//! [2] + +//! [3] + QString fileName(":/helloscript.qs"); + QFile scriptFile(fileName); + scriptFile.open(QIODevice::ReadOnly); + QTextStream stream(&scriptFile); + QString contents = stream.readAll(); + scriptFile.close(); +//! [3] + +//! [4] + QScriptValue result = engine.evaluate(contents, fileName); +//! [4] + +//! [5] + if (result.isError()) { + QMessageBox::critical(0, "Hello Script", + QString::fromLatin1("%0:%1: %2") + .arg(fileName) + .arg(result.property("lineNumber").toInt32()) + .arg(result.toString())); + return -1; + } +//! [5] + +//! [6] + return app.exec(); +} +//! [6] diff --git a/examples/script/marshal/main.cpp b/examples/script/marshal/main.cpp new file mode 100644 index 0000000..e5dbdde --- /dev/null +++ b/examples/script/marshal/main.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore> +#include <QtScript> + +template <class Container> +QScriptValue toScriptValue(QScriptEngine *eng, const Container &cont) +{ + QScriptValue a = eng->newArray(); + typename Container::const_iterator begin = cont.begin(); + typename Container::const_iterator end = cont.end(); + typename Container::const_iterator it; + for (it = begin; it != end; ++it) + a.setProperty(quint32(it - begin), qScriptValueFromValue(eng, *it)); + return a; +} + +template <class Container> +void fromScriptValue(const QScriptValue &value, Container &cont) +{ + quint32 len = value.property("length").toUInt32(); + for (quint32 i = 0; i < len; ++i) { + QScriptValue item = value.property(i); + typedef typename Container::value_type ContainerValue; + cont.push_back(qscriptvalue_cast<ContainerValue>(item)); + } +} + +typedef QVector<int> IntVector; +typedef QVector<QString> StringVector; + +Q_DECLARE_METATYPE(IntVector) +Q_DECLARE_METATYPE(StringVector) + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QScriptEngine eng; + // register our custom types + qScriptRegisterMetaType<IntVector>(&eng, toScriptValue, fromScriptValue); + qScriptRegisterMetaType<StringVector>(&eng, toScriptValue, fromScriptValue); + + QScriptValue val = eng.evaluate("[1, 4, 7, 11, 50, 3, 19, 60]"); + + fprintf(stdout, "Script array: %s\n", qPrintable(val.toString())); + + IntVector iv = qscriptvalue_cast<IntVector>(val); + + fprintf(stdout, "qscriptvalue_cast to QVector<int>: "); + for (int i = 0; i < iv.size(); ++i) + fprintf(stdout, "%s%d", (i > 0) ? "," : "", iv.at(i)); + fprintf(stdout, "\n"); + + val = eng.evaluate("[9, 'foo', 46.5, 'bar', 'Qt', 555, 'hello']"); + + fprintf(stdout, "Script array: %s\n", qPrintable(val.toString())); + + StringVector sv = qscriptvalue_cast<StringVector>(val); + + fprintf(stdout, "qscriptvalue_cast to QVector<QString>: "); + for (int i = 0; i < sv.size(); ++i) + fprintf(stdout, "%s%s", (i > 0) ? "," : "", qPrintable(sv.at(i))); + fprintf(stdout, "\n"); + + return 0; +} diff --git a/examples/script/marshal/marshal.pro b/examples/script/marshal/marshal.pro new file mode 100644 index 0000000..46b33b9 --- /dev/null +++ b/examples/script/marshal/marshal.pro @@ -0,0 +1,9 @@ +QT = core script +CONFIG += console +SOURCES += main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/marshal +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS marshal.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/script/marshal +INSTALLS += target sources diff --git a/examples/script/qscript/main.cpp b/examples/script/qscript/main.cpp new file mode 100644 index 0000000..891c89f --- /dev/null +++ b/examples/script/qscript/main.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qscriptengine.h> + +#include <QtCore/QFile> +#include <QtCore/QTextStream> +#include <QtCore/QStringList> +#include <QtGui/QApplication> + +#include <stdlib.h> + +#include "bytearrayclass.h" + +static bool wantsToQuit; + +static QScriptValue qtscript_quit(QScriptContext *ctx, QScriptEngine *eng) +{ + Q_UNUSED(ctx); + wantsToQuit = true; + return eng->undefinedValue(); +} + +static void interactive(QScriptEngine *eng) +{ + QScriptValue global = eng->globalObject(); + QScriptValue quitFunction = eng->newFunction(qtscript_quit); + if (!global.property(QLatin1String("exit")).isValid()) + global.setProperty(QLatin1String("exit"), quitFunction); + if (!global.property(QLatin1String("quit")).isValid()) + global.setProperty(QLatin1String("quit"), quitFunction); + wantsToQuit = false; + + QTextStream qin(stdin, QFile::ReadOnly); + + const char *qscript_prompt = "qs> "; + const char *dot_prompt = ".... "; + const char *prompt = qscript_prompt; + + QString code; + + forever { + QString line; + + printf("%s", prompt); + fflush(stdout); + + line = qin.readLine(); + if (line.isNull()) + break; + + code += line; + code += QLatin1Char('\n'); + + if (line.trimmed().isEmpty()) { + continue; + + } else if (! eng->canEvaluate(code)) { + prompt = dot_prompt; + + } else { + QScriptValue result = eng->evaluate(code, QLatin1String("typein")); + + code.clear(); + prompt = qscript_prompt; + + if (! result.isUndefined()) + fprintf(stderr, "%s\n", qPrintable(result.toString())); + + if (wantsToQuit) + break; + } + } +} + +static QScriptValue importExtension(QScriptContext *context, QScriptEngine *engine) +{ + return engine->importExtension(context->argument(0).toString()); +} + +static QScriptValue loadScripts(QScriptContext *context, QScriptEngine *engine) +{ + for (int i = 0; i < context->argumentCount(); ++i) { + QString fileName = context->argument(0).toString(); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) + return context->throwError(QString::fromLatin1("could not open %0 for reading").arg(fileName)); + QTextStream ts(&file); + QString contents = ts.readAll(); + file.close(); + QScriptContext *pc = context->parentContext(); + context->setActivationObject(pc->activationObject()); + context->setThisObject(pc->thisObject()); + QScriptValue ret = engine->evaluate(contents); + if (engine->hasUncaughtException()) + return ret; + } + return engine->undefinedValue(); +} + +int main(int argc, char *argv[]) +{ + QApplication *app; + if (argc >= 2 && !qstrcmp(argv[1], "-tty")) { + ++argv; + --argc; + app = new QApplication(argc, argv, QApplication::Tty); + } else { + app = new QApplication(argc, argv); + } + + QScriptEngine *eng = new QScriptEngine(); + + QScriptValue globalObject = eng->globalObject(); + + globalObject.setProperty("load", eng->newFunction(loadScripts, /*length=*/1)); + + { + if (!globalObject.property("qt").isObject()) + globalObject.setProperty("qt", eng->newObject()); + QScriptValue qscript = eng->newObject(); + qscript.setProperty("importExtension", eng->newFunction(importExtension)); + globalObject.property("qt").setProperty("script", qscript); + } + + ByteArrayClass *byteArrayClass = new ByteArrayClass(eng); + globalObject.setProperty("ByteArray", byteArrayClass->constructor()); + + if (! *++argv) { + interactive(eng); + return EXIT_SUCCESS; + } + + while (const char *arg = *argv++) { + QString fn = QString::fromLocal8Bit(arg); + + if (fn == QLatin1String("-i")) { + interactive(eng); + break; + } + + QString contents; + int lineNumber = 1; + + if (fn == QLatin1String("-")) { + QTextStream stream(stdin, QFile::ReadOnly); + contents = stream.readAll(); + } + + else { + QFile file(fn); + + if (file.open(QFile::ReadOnly)) { + QTextStream stream(&file); + contents = stream.readAll(); + file.close(); + + // strip off #!/usr/bin/env qscript line + if (contents.startsWith("#!")) { + contents.remove(0, contents.indexOf("\n")); + ++lineNumber; + } + } + } + + if (contents.isEmpty()) + continue; + + QScriptValue r = eng->evaluate(contents, fn, lineNumber); + if (eng->hasUncaughtException()) { + QStringList backtrace = eng->uncaughtExceptionBacktrace(); + fprintf (stderr, " %s\n%s\n\n", qPrintable(r.toString()), + qPrintable(backtrace.join("\n"))); + return EXIT_FAILURE; + } + } + + delete eng; + delete app; + + return EXIT_SUCCESS; +} diff --git a/examples/script/qscript/qscript.pro b/examples/script/qscript/qscript.pro new file mode 100644 index 0000000..759eedf --- /dev/null +++ b/examples/script/qscript/qscript.pro @@ -0,0 +1,14 @@ + +QT += script +win32: CONFIG += console +mac:CONFIG -= app_bundle + +SOURCES += main.cpp + +include(../customclass/bytearrayclass.pri) + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/qscript +sources.files = $$RESOURCES $$FORMS main.cpp qscript.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/script/qscript +INSTALLS += target sources diff --git a/examples/script/qsdbg/example.qs b/examples/script/qsdbg/example.qs new file mode 100644 index 0000000..47c1363 --- /dev/null +++ b/examples/script/qsdbg/example.qs @@ -0,0 +1,17 @@ +function bar() { + var x = 1; + var y = 2; + return x + y; +} + +function foo(a, b, c) { + var i = a + bar(); + var j = b - bar(); + var k = c * bar(); + return Math.cos(i) + Math.sin(j) - Math.atan(k); +} + +var first = foo(1, 2, 3); +var second = foo(4, 5, 6); +print("first was:", first, ", and second was:", second); + diff --git a/examples/script/qsdbg/main.cpp b/examples/script/qsdbg/main.cpp new file mode 100644 index 0000000..eb377cf --- /dev/null +++ b/examples/script/qsdbg/main.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtScript> + +#include "scriptdebugger.h" + +int main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "*** you must specify a script file to evaluate (try example.qs)\n"); + return(-1); + } + + QString fileName = QString::fromLatin1(argv[1]); + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + fprintf(stderr, "*** failed to open `%s' for reading\n", argv[1]); + return(-1); + } + + QScriptEngine engine; + QString code = QTextStream(&file).readAll(); + file.close(); + + fprintf(stdout, "\n*** Welcome to qsdbg. Debugger commands start with a . (period)\n"); + fprintf(stdout, "*** Any other input will be evaluated by the script interpreter.\n"); + fprintf(stdout, "*** Type .help for help.\n\n"); + + ScriptDebugger *dbg = new ScriptDebugger(&engine); + dbg->breakAtNextStatement(); + + engine.evaluate(code, fileName); + + return 0; +} diff --git a/examples/script/qsdbg/qsdbg.pri b/examples/script/qsdbg/qsdbg.pri new file mode 100644 index 0000000..618e623 --- /dev/null +++ b/examples/script/qsdbg/qsdbg.pri @@ -0,0 +1,9 @@ +SOURCES += \ + $$PWD/scriptdebugger.cpp \ + $$PWD/scriptbreakpointmanager.cpp + +HEADERS += \ + $$PWD/scriptdebugger.h \ + $$PWD/scriptbreakpointmanager.h + +INCLUDEPATH += $$PWD diff --git a/examples/script/qsdbg/qsdbg.pro b/examples/script/qsdbg/qsdbg.pro new file mode 100644 index 0000000..c199123 --- /dev/null +++ b/examples/script/qsdbg/qsdbg.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +QT += script +win32: CONFIG += console +mac: CONFIG -= app_bundle + +SOURCES += main.cpp + +include(qsdbg.pri) + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/qsdbg +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS qsdbg.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/script/qsdbg +INSTALLS += target sources + + diff --git a/examples/script/qsdbg/scriptbreakpointmanager.cpp b/examples/script/qsdbg/scriptbreakpointmanager.cpp new file mode 100644 index 0000000..7668d7b --- /dev/null +++ b/examples/script/qsdbg/scriptbreakpointmanager.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scriptbreakpointmanager.h" + +ScriptBreakpointManager::ScriptBreakpointManager() +{ +} + +ScriptBreakpointManager::~ScriptBreakpointManager() +{ +} + +bool ScriptBreakpointManager::hasBreakpoints() const +{ + return !breakpoints.isEmpty(); +} + +int ScriptBreakpointManager::setBreakpoint(const QString &fileName, int lineNumber) +{ + breakpoints.append(ScriptBreakpointInfo(fileName, lineNumber)); + return breakpoints.size() - 1; +} + +int ScriptBreakpointManager::setBreakpoint(const QString &functionName, const QString &fileName) +{ + breakpoints.append(ScriptBreakpointInfo(functionName, fileName)); + return breakpoints.size() - 1; +} + +int ScriptBreakpointManager::setBreakpoint(const QScriptValue &function) +{ + breakpoints.append(ScriptBreakpointInfo(function)); + return breakpoints.size() - 1; +} + +void ScriptBreakpointManager::removeBreakpoint(int id) +{ + if (id >= 0 && id < breakpoints.size()) + breakpoints[id] = ScriptBreakpointInfo(); +} + +int ScriptBreakpointManager::findBreakpoint(const QString &fileName, int lineNumber) const +{ + for (int i = 0; i < breakpoints.size(); ++i) { + const ScriptBreakpointInfo &brk = breakpoints.at(i); + if (brk.type != ScriptBreakpointInfo::File) + continue; + if (brk.fileName == fileName && brk.lineNumber == lineNumber) + return i; + } + return -1; +} + +int ScriptBreakpointManager::findBreakpoint(const QString &functionName, const QString &fileName) const +{ + for (int i = 0; i < breakpoints.size(); ++i) { + const ScriptBreakpointInfo &brk = breakpoints.at(i); + if (brk.type != ScriptBreakpointInfo::FunctionName) + continue; + if (brk.functionName == functionName && brk.fileName == fileName) + return i; + } + return -1; +} + +int ScriptBreakpointManager::findBreakpoint(const QScriptValue &function) const +{ + for (int i = 0; i < breakpoints.size(); ++i) { + const ScriptBreakpointInfo &brk = breakpoints.at(i); + if (brk.type != ScriptBreakpointInfo::Function) + continue; + if (brk.function.strictlyEquals(function)) + return i; + } + return -1; +} + +bool ScriptBreakpointManager::isBreakpointEnabled(int id) const +{ + return breakpoints.value(id).enabled; +} + +void ScriptBreakpointManager::setBreakpointEnabled(int id, bool enabled) +{ + if (id >= 0 && id < breakpoints.size()) + breakpoints[id].enabled = enabled; +} + +QString ScriptBreakpointManager::breakpointCondition(int id) const +{ + return breakpoints.value(id).condition; +} + +void ScriptBreakpointManager::setBreakpointCondition(int id, const QString &expression) +{ + if (id >= 0 && id < breakpoints.size()) + breakpoints[id].condition = expression; +} + +int ScriptBreakpointManager::breakpointIgnoreCount(int id) const +{ + return breakpoints.value(id).ignoreCount; +} + +void ScriptBreakpointManager::setBreakpointIgnoreCount(int id, int ignoreCount) +{ + if (id >= 0 && id < breakpoints.size()) + breakpoints[id].ignoreCount = ignoreCount; +} + +bool ScriptBreakpointManager::isBreakpointSingleShot(int id) const +{ + return breakpoints.value(id).singleShot; +} + +void ScriptBreakpointManager::setBreakpointSingleShot(int id, bool singleShot) +{ + if (id >= 0 && id < breakpoints.size()) + breakpoints[id].singleShot = singleShot; +} diff --git a/examples/script/qsdbg/scriptbreakpointmanager.h b/examples/script/qsdbg/scriptbreakpointmanager.h new file mode 100644 index 0000000..cdb176c --- /dev/null +++ b/examples/script/qsdbg/scriptbreakpointmanager.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCRIPTBREAKPOINTMANAGER_H +#define SCRIPTBREAKPOINTMANAGER_H + +#include <QtCore/qlist.h> +#include <QtCore/qstring.h> +#include <QtScript/qscriptvalue.h> + +class ScriptBreakpointInfo +{ +public: + enum Type { + File, + FunctionName, + Function, + Invalid + }; + + Type type; + QString functionName; + QString fileName; + int lineNumber; + QScriptValue function; + bool enabled; + QString condition; + int ignoreCount; + bool singleShot; + + ScriptBreakpointInfo(const QString &fileName, int lineNumber) + : type(File), fileName(fileName), lineNumber(lineNumber), + enabled(true), ignoreCount(0), singleShot(false) + { } + ScriptBreakpointInfo(const QString &functionName, const QString &fileName = QString()) + : type(FunctionName), functionName(functionName), fileName(fileName), + enabled(true), ignoreCount(0), singleShot(false) + { } + ScriptBreakpointInfo(const QScriptValue &function) + : type(Function), function(function), + enabled(true), ignoreCount(0), singleShot(false) + { } + ScriptBreakpointInfo() + : type(Invalid) + { } +}; + +class ScriptBreakpointManager +{ +public: + ScriptBreakpointManager(); + ~ScriptBreakpointManager(); + + bool hasBreakpoints() const; + + int setBreakpoint(const QString &fileName, int lineNumber); + int setBreakpoint(const QString &functionName, const QString &fileName = QString()); + int setBreakpoint(const QScriptValue &function); + + void removeBreakpoint(int id); + + int findBreakpoint(const QString &fileName, int lineNumber) const; + int findBreakpoint(const QString &functionName, const QString &fileName = QString()) const; + int findBreakpoint(const QScriptValue &function) const; + + bool isBreakpointEnabled(int id) const; + void setBreakpointEnabled(int id, bool enabled); + + QString breakpointCondition(int id) const; + void setBreakpointCondition(int id, const QString &expression); + + int breakpointIgnoreCount(int id) const; + void setBreakpointIgnoreCount(int id, int ignoreCount); + + bool isBreakpointSingleShot(int id) const; + void setBreakpointSingleShot(int id, bool singleShot); + +private: + QList<ScriptBreakpointInfo> breakpoints; + + Q_DISABLE_COPY(ScriptBreakpointManager) +}; + +#endif // SCRIPTBREAKPOINTMANAGER_H diff --git a/examples/script/qsdbg/scriptdebugger.cpp b/examples/script/qsdbg/scriptdebugger.cpp new file mode 100644 index 0000000..e3639b9 --- /dev/null +++ b/examples/script/qsdbg/scriptdebugger.cpp @@ -0,0 +1,737 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scriptdebugger.h" +#include "scriptbreakpointmanager.h" + +#include <QtScript/QScriptEngine> +#include <QtScript/QScriptEngineAgent> +#include <QtScript/QScriptContextInfo> +#include <QtScript/QScriptValueIterator> +#include <QtCore/QTextStream> +#include <QtCore/QStack> + +static QString safeValueToString(const QScriptValue &value) +{ + if (value.isObject()) + return QLatin1String("[object Object]"); + else + return value.toString(); +} + +class ScriptInfo; +class ScriptBreakpointManager; + +class ScriptDebuggerPrivate + : public QScriptEngineAgent +{ + Q_DECLARE_PUBLIC(ScriptDebugger) +public: + enum Mode { + Run, + StepInto, + StepOver + }; + + ScriptDebuggerPrivate(QScriptEngine *engine); + ~ScriptDebuggerPrivate(); + + // QScriptEngineAgent interface + void scriptLoad(qint64 id, const QString &program, + const QString &fileName, int lineNumber); + void scriptUnload(qint64 id); + + void positionChange(qint64 scriptId, + int lineNumber, int columnNumber); + + void functionEntry(qint64 scriptId); + void functionExit(qint64 scriptId, + const QScriptValue &returnValue); + + void exceptionThrow(qint64 scriptId, + const QScriptValue &exception, bool hasHandler); + + + void interactive(); + bool executeCommand(const QString &command, const QStringList &args); + + void setMode(Mode mode); + Mode mode() const; + + int frameCount() const; + void setCurrentFrameIndex(int index); + int currentFrameIndex() const; + + QScriptContext *frameContext(int index) const; + QScriptContext *currentFrameContext() const; + + ScriptInfo *scriptInfo(QScriptContext *context) const; + + int listLineNumber() const; + void setListLineNumber(int lineNumber); + + QString readLine(); + void output(const QString &text); + void message(const QString &text); + void errorMessage(const QString &text); + + // attributes + QTextStream *m_defaultInputStream; + QTextStream *m_defaultOutputStream; + QTextStream *m_defaultErrorStream; + QTextStream *m_inputStream; + QTextStream *m_outputStream; + QTextStream *m_errorStream; + + ScriptBreakpointManager *m_bpManager; + Mode m_mode; + QMap<qint64, ScriptInfo*> m_scripts; + QMap<QScriptContext*, QStack<qint64> > m_contextProgramIds; + + QString m_lastInteractiveCommand; + QString m_commandPrefix; + int m_stepDepth; + int m_currentFrameIndex; + int m_listLineNumber; + + ScriptDebugger *q_ptr; +}; + +class ScriptInfo +{ +public: + ScriptInfo(const QString &code, const QString &fileName, int lineNumber) + : m_code(code), m_fileName(fileName), m_lineNumber(lineNumber) + { } + + inline QString code() const + { return m_code; } + inline QString fileName() const + { return m_fileName; } + inline int lineNumber() const + { return m_lineNumber; } + + QString lineText(int lineNumber); + QMap<int, int> m_lineOffsets; + +private: + int lineOffset(int lineNumber); + + QString m_code; + QString m_fileName; + int m_lineNumber; +}; + +int ScriptInfo::lineOffset(int lineNumber) +{ + QMap<int, int>::const_iterator it = m_lineOffsets.constFind(lineNumber); + if (it != m_lineOffsets.constEnd()) + return it.value(); + + int offset; + it = m_lineOffsets.constFind(lineNumber - 1); + if (it != m_lineOffsets.constEnd()) { + offset = it.value(); + offset = m_code.indexOf(QLatin1Char('\n'), offset); + if (offset != -1) + ++offset; + m_lineOffsets.insert(lineNumber, offset); + } else { + int index; + it = m_lineOffsets.lowerBound(lineNumber); + --it; + if (it != m_lineOffsets.constBegin()) { + index = it.key(); + offset = it.value(); + } else { + index = m_lineNumber; + offset = 0; + } + int j = index; + for ( ; j < lineNumber; ++j) { + m_lineOffsets.insert(j, offset); + offset = m_code.indexOf(QLatin1Char('\n'), offset); + if (offset == -1) + break; + ++offset; + } + m_lineOffsets.insert(j, offset); + } + return offset; +} + +QString ScriptInfo::lineText(int lineNumber) +{ + int startOffset = lineOffset(lineNumber); + if (startOffset == -1) + return QString(); + int endOffset = lineOffset(lineNumber + 1); + if (endOffset == -1) + return m_code.mid(startOffset); + else + return m_code.mid(startOffset, endOffset - startOffset - 1); +} + + + +ScriptDebuggerPrivate::ScriptDebuggerPrivate(QScriptEngine *engine) + : QScriptEngineAgent(engine), m_mode(Run) +{ + m_commandPrefix = QLatin1String("."); + m_bpManager = new ScriptBreakpointManager; + m_defaultInputStream = new QTextStream(stdin); + m_defaultOutputStream = new QTextStream(stdout); + m_defaultErrorStream = new QTextStream(stderr); + m_inputStream = m_defaultInputStream; + m_outputStream = m_defaultOutputStream; + m_errorStream = m_defaultErrorStream; +} + +ScriptDebuggerPrivate::~ScriptDebuggerPrivate() +{ + delete m_defaultInputStream; + delete m_defaultOutputStream; + delete m_defaultErrorStream; + delete m_bpManager; + qDeleteAll(m_scripts); +} + +QString ScriptDebuggerPrivate::readLine() +{ + return m_inputStream->readLine(); +} + +void ScriptDebuggerPrivate::output(const QString &text) +{ + *m_outputStream << text; +} + +void ScriptDebuggerPrivate::message(const QString &text) +{ + *m_outputStream << text << endl; + m_outputStream->flush(); +} + +void ScriptDebuggerPrivate::errorMessage(const QString &text) +{ + *m_errorStream << text << endl; + m_errorStream->flush(); +} + +void ScriptDebuggerPrivate::setMode(Mode mode) +{ + m_mode = mode; +} + +ScriptDebuggerPrivate::Mode ScriptDebuggerPrivate::mode() const +{ + return m_mode; +} + +QScriptContext *ScriptDebuggerPrivate::frameContext(int index) const +{ + QScriptContext *ctx = engine()->currentContext(); + for (int i = 0; i < index; ++i) { + ctx = ctx->parentContext(); + if (!ctx) + break; + } + return ctx; +} + +int ScriptDebuggerPrivate::currentFrameIndex() const +{ + return m_currentFrameIndex; +} + +void ScriptDebuggerPrivate::setCurrentFrameIndex(int index) +{ + m_currentFrameIndex = index; + m_listLineNumber = -1; +} + +int ScriptDebuggerPrivate::listLineNumber() const +{ + return m_listLineNumber; +} + +void ScriptDebuggerPrivate::setListLineNumber(int lineNumber) +{ + m_listLineNumber = lineNumber; +} + +QScriptContext *ScriptDebuggerPrivate::currentFrameContext() const +{ + return frameContext(currentFrameIndex()); +} + +int ScriptDebuggerPrivate::frameCount() const +{ + int count = 0; + QScriptContext *ctx = engine()->currentContext(); + while (ctx) { + ++count; + ctx = ctx->parentContext(); + } + return count; +} + +ScriptInfo *ScriptDebuggerPrivate::scriptInfo(QScriptContext *context) const +{ + QStack<qint64> pids = m_contextProgramIds.value(context); + if (pids.isEmpty()) + return 0; + return m_scripts.value(pids.top()); +} + +void ScriptDebuggerPrivate::interactive() +{ + setCurrentFrameIndex(0); + + QString qsdbgPrompt = QString::fromLatin1("(qsdbg) "); + QString dotPrompt = QString::fromLatin1(".... "); + QString prompt = qsdbgPrompt; + + QString code; + + forever { + + *m_outputStream << prompt; + m_outputStream->flush(); + + QString line = readLine(); + + if (code.isEmpty() && (line.isEmpty() || line.startsWith(m_commandPrefix))) { + if (line.isEmpty()) + line = m_lastInteractiveCommand; + else + m_lastInteractiveCommand = line; + + QStringList parts = line.split(QLatin1Char(' '), QString::SkipEmptyParts); + if (!parts.isEmpty()) { + QString command = parts.takeFirst().mid(1); + if (executeCommand(command, parts)) + break; + } + + } else { + if (line.isEmpty()) + continue; + + code += line; + code += QLatin1Char('\n'); + + if (line.trimmed().isEmpty()) { + continue; + + } else if (! engine()->canEvaluate(code)) { + prompt = dotPrompt; + + } else { + setMode(Run); + QScriptValue result = engine()->evaluate(code, QLatin1String("typein")); + + code.clear(); + prompt = qsdbgPrompt; + + if (! result.isUndefined()) { + errorMessage(result.toString()); + engine()->clearExceptions(); + } + } + } + } +} + +bool ScriptDebuggerPrivate::executeCommand(const QString &command, const QStringList &args) +{ + if (command == QLatin1String("c") + || command == QLatin1String("continue")) { + setMode(Run); + return true; + } else if (command == QLatin1String("s") + || command == QLatin1String("step")) { + setMode(StepInto); + return true; + } else if (command == QLatin1String("n") + || command == QLatin1String("next")) { + setMode(StepOver); + m_stepDepth = 0; + return true; + } else if (command == QLatin1String("f") + || command == QLatin1String("frame")) { + bool ok = false; + int index = args.value(0).toInt(&ok); + if (ok) { + if (index < 0 || index >= frameCount()) { + errorMessage("No such frame."); + } else { + setCurrentFrameIndex(index); + QScriptContext *ctx = currentFrameContext(); + message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString())); + } + } + } else if (command == QLatin1String("bt") + || command == QLatin1String("backtrace")) { + QScriptContext *ctx = engine()->currentContext(); + int index = -1; + while (ctx) { + ++index; + QString line = ctx->toString(); + message(QString::fromLatin1("#%0 %1").arg(index).arg(line)); + ctx = ctx->parentContext(); + } + } else if (command == QLatin1String("up")) { + int index = currentFrameIndex() + 1; + if (index == frameCount()) { + errorMessage(QString::fromLatin1("Initial frame selected; you cannot go up.")); + } else { + setCurrentFrameIndex(index); + QScriptContext *ctx = currentFrameContext(); + message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString())); + } + } else if (command == QLatin1String("down")) { + int index = currentFrameIndex() - 1; + if (index < 0) { + errorMessage(QString::fromLatin1("Bottom (innermost) frame selected; you cannot go down.")); + } else { + setCurrentFrameIndex(index); + QScriptContext *ctx = currentFrameContext(); + message(QString::fromLatin1("#%0 %1").arg(index).arg(ctx->toString())); + } + } else if (command == QLatin1String("b") + || command == QLatin1String("break")) { + QString str = args.value(0); + int colonIndex = str.indexOf(QLatin1Char(':')); + if (colonIndex != -1) { + // filename:line form + QString fileName = str.left(colonIndex); + int lineNumber = str.mid(colonIndex+1).toInt(); + int id = m_bpManager->setBreakpoint(fileName, lineNumber); + message(QString::fromLatin1("Breakpoint %0 at %1, line %2.").arg(id+1).arg(fileName).arg(lineNumber)); + } else { + // function + QScriptValue fun = engine()->globalObject().property(str); + if (fun.isFunction()) { + int id = m_bpManager->setBreakpoint(fun); + message(QString::fromLatin1("Breakpoint %0 at %1().").arg(id+1).arg(str)); + } + } + } else if (command == QLatin1String("d") + || command == QLatin1String("delete")) { + int id = args.value(0).toInt() - 1; + m_bpManager->removeBreakpoint(id); + } else if (command == QLatin1String("disable")) { + int id = args.value(0).toInt() - 1; + m_bpManager->setBreakpointEnabled(id, false); + } else if (command == QLatin1String("enable")) { + int id = args.value(0).toInt() - 1; + m_bpManager->setBreakpointEnabled(id, true); + } else if (command == QLatin1String("list")) { + QScriptContext *ctx = currentFrameContext(); + ScriptInfo *progInfo = scriptInfo(ctx); + if (!progInfo) { + errorMessage("No source text available for this frame."); + } else { + QScriptContextInfo ctxInfo(ctx); + bool ok; + int line = args.value(0).toInt(&ok); + if (ok) { + line = qMax(1, line - 5); + } else { + line = listLineNumber(); + if (line == -1) + line = qMax(progInfo->lineNumber(), ctxInfo.lineNumber() - 5); + } + for (int i = line; i < line + 10; ++i) { + message(QString::fromLatin1("%0\t%1").arg(i).arg(progInfo->lineText(i))); + } + setListLineNumber(line + 10); + } + } else if (command == QLatin1String("info")) { + if (args.size() < 1) { + } else { + QString what = args.value(0); + if (what == QLatin1String("locals")) { + QScriptValueIterator it(currentFrameContext()->activationObject()); + while (it.hasNext()) { + it.next(); + QString line; + line.append(it.name()); + line.append(QLatin1String(" = ")); + line.append(safeValueToString(it.value())); + message(line); + } + } + } + } else if (command == QLatin1String("help")) { + message("continue - continue execution\n" + "step - step into statement\n" + "next - step over statement\n" + "list - show where you are\n" + "\n" + "break - set breakpoint\n" + "delete - remove breakpoint\n" + "disable - disable breakpoint\n" + "enable - enable breakpoint\n" + "\n" + "backtrace - show backtrace\n" + "up - one frame up\n" + "down - one frame down\n" + "frame - set frame\n" + "\n" + "info locals - show local variables"); + } else { + errorMessage(QString::fromLatin1("Undefined command \"%0\". Try \"help\".") + .arg(command)); + } + + return false; +} + + +// QScriptEngineAgent interface + +void ScriptDebuggerPrivate::scriptLoad(qint64 id, const QString &program, + const QString &fileName, int lineNumber) +{ + ScriptInfo *info = new ScriptInfo(program, fileName, lineNumber); + m_scripts.insert(id, info); +} + +void ScriptDebuggerPrivate::scriptUnload(qint64 id) +{ + ScriptInfo *info = m_scripts.take(id); + delete info; +} + +void ScriptDebuggerPrivate::functionEntry(qint64 scriptId) +{ + if (scriptId != -1) { + QScriptContext *ctx = engine()->currentContext(); + QStack<qint64> ids = m_contextProgramIds.value(ctx); + ids.push(scriptId); + m_contextProgramIds.insert(ctx, ids); + } + + if (mode() == StepOver) + ++m_stepDepth; +} + +void ScriptDebuggerPrivate::functionExit(qint64 scriptId, + const QScriptValue &/*returnValue*/) +{ + if (scriptId != -1) { + QScriptContext *ctx = engine()->currentContext(); + QStack<qint64> ids = m_contextProgramIds.value(ctx); + Q_ASSERT(!ids.isEmpty()); + Q_ASSERT(ids.top() == scriptId); + ids.pop(); + m_contextProgramIds.insert(ctx, ids); + } + + if (mode() == StepOver) + --m_stepDepth; +} + +void ScriptDebuggerPrivate::positionChange(qint64 scriptId, + int lineNumber, int /*columnNumber*/) +{ + ScriptInfo *info = 0; + bool enterInteractiveMode = false; + + if (m_bpManager->hasBreakpoints()) { + // check if we hit a breakpoint + info = m_scripts.value(scriptId); + QScriptContext *ctx = engine()->currentContext(); + QScriptContextInfo ctxInfo(ctx); + QScriptValue callee = ctx->callee(); + + // try fileName:lineNumber + int bpid = m_bpManager->findBreakpoint(info->fileName(), lineNumber); + if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) { + message(QString::fromLatin1("Breakpoint %0 at %1:%2") + .arg(bpid + 1).arg(info->fileName()).arg(lineNumber)); + if (m_bpManager->isBreakpointSingleShot(bpid)) + m_bpManager->removeBreakpoint(bpid); + } + if (bpid == -1) { + // try function + bpid = m_bpManager->findBreakpoint(callee); + if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) { + message(QString::fromLatin1("Breakpoint %0, %1()") + .arg(bpid + 1).arg(ctxInfo.functionName())); + if (m_bpManager->isBreakpointSingleShot(bpid)) + m_bpManager->removeBreakpoint(bpid); + } + } + if ((bpid == -1) && !ctxInfo.functionName().isEmpty()) { + // try functionName:fileName + bpid = m_bpManager->findBreakpoint(ctxInfo.functionName(), ctxInfo.fileName()); + if ((bpid != -1) && m_bpManager->isBreakpointEnabled(bpid)) { + message(QString::fromLatin1("Breakpoint %0, %1():%2").arg(bpid + 1) + .arg(ctxInfo.functionName()).arg(ctxInfo.fileName())); + if (m_bpManager->isBreakpointSingleShot(bpid)) + m_bpManager->removeBreakpoint(bpid); + } + } + + enterInteractiveMode = (bpid != -1); + } + + switch (mode()) { + case Run: + break; + + case StepInto: + enterInteractiveMode = true; + break; + + case StepOver: + enterInteractiveMode = enterInteractiveMode || (m_stepDepth <= 0); + break; + } + + if (enterInteractiveMode) { + if (!info) + info = m_scripts.value(scriptId); + Q_ASSERT(info); + message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(info->lineText(lineNumber))); + interactive(); + } +} + +void ScriptDebuggerPrivate::exceptionThrow(qint64 /*scriptId*/, + const QScriptValue &exception, + bool hasHandler) +{ + if (!hasHandler) { + errorMessage(QString::fromLatin1("uncaught exception: %0").arg(exception.toString())); + QScriptContext *ctx = engine()->currentContext(); + int lineNumber = QScriptContextInfo(ctx).lineNumber(); + ScriptInfo *info = scriptInfo(ctx); + QString lineText = info ? info->lineText(lineNumber) : QString("(no source text available)"); + message(QString::fromLatin1("%0\t%1").arg(lineNumber).arg(lineText)); + interactive(); + } +} + + + +ScriptDebugger::ScriptDebugger(QScriptEngine *engine) + : d_ptr(new ScriptDebuggerPrivate(engine)) +{ + d_ptr->q_ptr = this; + engine->setAgent(d_ptr); +} + +ScriptDebugger::ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd) + : d_ptr(&dd) +{ + d_ptr->q_ptr = this; + engine->setAgent(d_ptr); +} + +ScriptDebugger::~ScriptDebugger() +{ + delete d_ptr; + d_ptr = 0; +} + +void ScriptDebugger::breakAtNextStatement() +{ + Q_D(ScriptDebugger); + d->setMode(ScriptDebuggerPrivate::StepInto); +} + +void ScriptDebugger::setBreakpoint(const QString &fileName, int lineNumber) +{ + Q_D(ScriptDebugger); + d->m_bpManager->setBreakpoint(fileName, lineNumber); +} + +void ScriptDebugger::setBreakpoint(const QString &functionName, const QString &fileName) +{ + Q_D(ScriptDebugger); + d->m_bpManager->setBreakpoint(functionName, fileName); +} + +void ScriptDebugger::setBreakpoint(const QScriptValue &function) +{ + Q_D(ScriptDebugger); + d->m_bpManager->setBreakpoint(function); +} + +QTextStream *ScriptDebugger::inputStream() const +{ + Q_D(const ScriptDebugger); + return d->m_inputStream; +} + +void ScriptDebugger::setInputStream(QTextStream *inputStream) +{ + Q_D(ScriptDebugger); + d->m_inputStream = inputStream; +} + +QTextStream *ScriptDebugger::outputStream() const +{ + Q_D(const ScriptDebugger); + return d->m_outputStream; +} + +void ScriptDebugger::setOutputStream(QTextStream *outputStream) +{ + Q_D(ScriptDebugger); + d->m_outputStream = outputStream; +} + +QTextStream *ScriptDebugger::errorStream() const +{ + Q_D(const ScriptDebugger); + return d->m_errorStream; +} + +void ScriptDebugger::setErrorStream(QTextStream *errorStream) +{ + Q_D(ScriptDebugger); + d->m_errorStream = errorStream; +} diff --git a/examples/script/qsdbg/scriptdebugger.h b/examples/script/qsdbg/scriptdebugger.h new file mode 100644 index 0000000..c33adf6 --- /dev/null +++ b/examples/script/qsdbg/scriptdebugger.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCRIPTDEBUGGER_H +#define SCRIPTDEBUGGER_H + +#include <QtCore/qlist.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE +class QScriptEngine; +class QScriptValue; +class QTextStream; +QT_END_NAMESPACE + +class ScriptDebuggerPrivate; +class ScriptDebugger +{ +public: + ScriptDebugger(QScriptEngine *engine); + virtual ~ScriptDebugger(); + + void breakAtNextStatement(); + + void setBreakpoint(const QString &fileName, int lineNumber); + void setBreakpoint(const QString &functionName, const QString &fileName = QString()); + void setBreakpoint(const QScriptValue &function); + + QTextStream *inputStream() const; + void setInputStream(QTextStream *inputStream); + + QTextStream *outputStream() const; + void setOutputStream(QTextStream *outputStream); + + QTextStream *errorStream() const; + void setErrorStream(QTextStream *errorStream); + +protected: + ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd); + ScriptDebuggerPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(ScriptDebugger) + Q_DISABLE_COPY(ScriptDebugger) +}; + +#endif // SCRIPTDEBUGGER_H diff --git a/examples/script/qstetrix/main.cpp b/examples/script/qstetrix/main.cpp new file mode 100644 index 0000000..6d7af45 --- /dev/null +++ b/examples/script/qstetrix/main.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tetrixboard.h" + +#include <QtGui> +#include <QtScript> +#include <QUiLoader> + +#ifndef QT_NO_SCRIPTTOOLS +#include <QtScriptTools> +#endif + +struct QtMetaObject : private QObject +{ +public: + static const QMetaObject *get() + { return &static_cast<QtMetaObject*>(0)->staticQtMetaObject; } +}; + +//! [0] +class TetrixUiLoader : public QUiLoader +{ +public: + TetrixUiLoader(QObject *parent = 0) + : QUiLoader(parent) + { } + virtual QWidget *createWidget(const QString &className, QWidget *parent = 0, + const QString &name = QString()) + { + if (className == QLatin1String("TetrixBoard")) { + QWidget *board = new TetrixBoard(parent); + board->setObjectName(name); + return board; + } + return QUiLoader::createWidget(className, parent, name); + } +}; +//! [0] + +static QScriptValue evaluateFile(QScriptEngine &engine, const QString &fileName) +{ + QFile file(fileName); + file.open(QIODevice::ReadOnly); + return engine.evaluate(file.readAll(), fileName); +} + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(tetrix); + +//! [1] + QApplication app(argc, argv); + QScriptEngine engine; + + QScriptValue Qt = engine.newQMetaObject(QtMetaObject::get()); + Qt.setProperty("App", engine.newQObject(&app)); + engine.globalObject().setProperty("Qt", Qt); +//! [1] + +#ifndef QT_NO_SCRIPTTOOLS + QScriptEngineDebugger debugger; + debugger.attachTo(&engine); + QMainWindow *debugWindow = debugger.standardWindow(); + debugWindow->resize(1024, 640); +#endif + +//! [2] + evaluateFile(engine, ":/tetrixpiece.js"); + evaluateFile(engine, ":/tetrixboard.js"); + evaluateFile(engine, ":/tetrixwindow.js"); +//! [2] + +//! [3] + TetrixUiLoader loader; + QFile uiFile(":/tetrixwindow.ui"); + uiFile.open(QIODevice::ReadOnly); + QWidget *ui = loader.load(&uiFile); + uiFile.close(); + + QScriptValue ctor = engine.evaluate("TetrixWindow"); + QScriptValue scriptUi = engine.newQObject(ui, QScriptEngine::ScriptOwnership); + QScriptValue tetrix = ctor.construct(QScriptValueList() << scriptUi); +//! [3] + + QPushButton *debugButton = qFindChild<QPushButton*>(ui, "debugButton"); +#ifndef QT_NO_SCRIPTTOOLS + QObject::connect(debugButton, SIGNAL(clicked()), + debugger.action(QScriptEngineDebugger::InterruptAction), + SIGNAL(triggered())); + QObject::connect(debugButton, SIGNAL(clicked()), + debugWindow, SLOT(show())); +#else + debugButton->hide(); +#endif + +//! [4] + ui->resize(550, 370); + ui->show(); + + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + return app.exec(); +//! [4] +} diff --git a/examples/script/qstetrix/qstetrix.pro b/examples/script/qstetrix/qstetrix.pro new file mode 100644 index 0000000..3db66ab --- /dev/null +++ b/examples/script/qstetrix/qstetrix.pro @@ -0,0 +1,17 @@ +QT += script +CONFIG += uitools + +HEADERS = tetrixboard.h +SOURCES = main.cpp \ + tetrixboard.cpp + +FORMS = tetrixwindow.ui +RESOURCES = tetrix.qrc + +contains(QT_CONFIG, scripttools): QT += scripttools + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script/qstetrix +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS qstetrix.pro *.js +sources.path = $$[QT_INSTALL_EXAMPLES]/script/qstetrix +INSTALLS += target sources diff --git a/examples/script/qstetrix/tetrix.qrc b/examples/script/qstetrix/tetrix.qrc new file mode 100644 index 0000000..58d085a --- /dev/null +++ b/examples/script/qstetrix/tetrix.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/" > + <file>tetrixwindow.js</file> + <file>tetrixwindow.ui</file> + <file>tetrixboard.js</file> + <file>tetrixpiece.js</file> + </qresource> +</RCC> diff --git a/examples/script/qstetrix/tetrixboard.cpp b/examples/script/qstetrix/tetrixboard.cpp new file mode 100644 index 0000000..55c4d3c --- /dev/null +++ b/examples/script/qstetrix/tetrixboard.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tetrixboard.h" + +#include <QtGui> + +Q_DECLARE_METATYPE(QPainter*) + +TetrixBoard::TetrixBoard(QWidget *parent) + : QFrame(parent) +{ + timer = new QTimer(this); + qMetaTypeId<QPainter*>(); +} + +void TetrixBoard::setNextPieceLabel(QWidget *label) +{ + nextPieceLabel = qobject_cast<QLabel*>(label); +} + +QObject *TetrixBoard::getTimer() +{ + return timer; +} + +QSize TetrixBoard::minimumSizeHint() const +{ + return QSize(BoardWidth * 5 + frameWidth() * 2, + BoardHeight * 5 + frameWidth() * 2); +} + +void TetrixBoard::paintEvent(QPaintEvent *event) +{ + QFrame::paintEvent(event); + QPainter painter(this); + painter.drawImage(0, 0, image); +} + +void TetrixBoard::keyPressEvent(QKeyEvent *event) +{ + emit keyPressed(event->key()); +} + +void TetrixBoard::showNextPiece(int width, int height) +{ + if (!nextPieceLabel) + return; + + QPixmap pixmap(width * squareWidth(), height * squareHeight()); + QPainter painter(&pixmap); + painter.fillRect(pixmap.rect(), nextPieceLabel->palette().background()); + + emit paintNextPieceRequested(&painter); + + nextPieceLabel->setPixmap(pixmap); +} + +void TetrixBoard::drawPauseScreen(QPainter *painter) +{ + painter->drawText(contentsRect(), Qt::AlignCenter, tr("Pause")); +} + +void TetrixBoard::drawSquare(QPainter *painter, int x, int y, int shape) +{ + static const QRgb colorTable[8] = { + 0x000000, 0xCC6666, 0x66CC66, 0x6666CC, + 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00 + }; + + x = x*squareWidth(); + y = y*squareHeight(); + + QColor color = colorTable[shape]; + painter->fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2, + color); + + painter->setPen(color.light()); + painter->drawLine(x, y + squareHeight() - 1, x, y); + painter->drawLine(x, y, x + squareWidth() - 1, y); + + painter->setPen(color.dark()); + painter->drawLine(x + 1, y + squareHeight() - 1, + x + squareWidth() - 1, y + squareHeight() - 1); + painter->drawLine(x + squareWidth() - 1, y + squareHeight() - 1, + x + squareWidth() - 1, y + 1); +} + +void TetrixBoard::update() +{ + QRect rect = contentsRect(); + if (image.size() != rect.size()) + image = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied); + image.fill(qRgba(0,0,0,0)); + QPainter painter; + painter.begin(&image); + int boardTop = rect.bottom() - BoardHeight*squareHeight(); + painter.translate(rect.left(), boardTop); + emit paintRequested(&painter); + QFrame::update(); +} diff --git a/examples/script/qstetrix/tetrixboard.h b/examples/script/qstetrix/tetrixboard.h new file mode 100644 index 0000000..e8c1016 --- /dev/null +++ b/examples/script/qstetrix/tetrixboard.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TETRIXBOARD_H +#define TETRIXBOARD_H + +#include <QTimer> +#include <QFrame> +#include <QPointer> + +QT_BEGIN_NAMESPACE +class QLabel; +QT_END_NAMESPACE + +class TetrixBoard : public QFrame +{ + Q_OBJECT + Q_PROPERTY(QObject* timer READ getTimer) + Q_PROPERTY(QWidget* nextPieceLabel WRITE setNextPieceLabel) + +public: + TetrixBoard(QWidget *parent = 0); + + void setNextPieceLabel(QWidget *label); + void setBoardWidth(int width); + void setBoardHeight(int height); + QSize minimumSizeHint() const; + + QObject *getTimer(); + +signals: + void scoreChanged(int score); + void levelChanged(int level); + void linesRemovedChanged(int numLines); + +#if !defined(Q_MOC_RUN) +private: // can only be emitted by TetrixBoard +#endif + void keyPressed(int key); + void paintRequested(QPainter *painter); + void paintNextPieceRequested(QPainter *painter); + +protected: + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + +protected slots: + void showNextPiece(int width, int height); + void drawPauseScreen(QPainter *painter); + void drawSquare(QPainter *painter, int x, int y, int shape); + void update(); + +private: + enum { BoardWidth = 10, BoardHeight = 22 }; + + int squareWidth() { return contentsRect().width() / BoardWidth; } + int squareHeight() { return contentsRect().height() / BoardHeight; } + + QTimer *timer; + QPointer<QLabel> nextPieceLabel; + QImage image; +}; + +#endif diff --git a/examples/script/qstetrix/tetrixboard.js b/examples/script/qstetrix/tetrixboard.js new file mode 100644 index 0000000..f198397 --- /dev/null +++ b/examples/script/qstetrix/tetrixboard.js @@ -0,0 +1,261 @@ +function TetrixBoard(ui) +{ + this.ui = ui; + + this.isStarted = false; + this.isPaused = false; + this.inKeyPress = false; + + this._board = new Array(TetrixBoard.BoardWidth * TetrixBoard.BoardHeight); + this.clearBoard(); + + this.curPiece = new TetrixPiece(); + this.nextPiece = new TetrixPiece(); + this.nextPiece.setRandomShape(); + + ui.timer.singleShot = true; + ui.timer.timeout.connect(this, this.onTimer); + ui.keyPressed.connect(this, this.onKeyPress); + ui.paintRequested.connect(this, this.onPaint); + ui.paintNextPieceRequested.connect(this, this.onPaintNextPiece); +} + +TetrixBoard.BoardWidth = 10; +TetrixBoard.BoardHeight = 22; + +TetrixBoard.prototype.start = function() { + if (this.isPaused) + return; + + this.isStarted = true; + this.isWaitingAfterLine = false; + this.numLinesRemoved = 0; + this.numPiecesDropped = 0; + this.score = 0; + this.level = 1; + this.clearBoard(); + + this.ui.linesRemovedChanged(this.numLinesRemoved); + this.ui.scoreChanged(this.score); + this.ui.levelChanged(this.level); + + this.newPiece(); + this.ui.timer.start(this.timeoutTime()); +} + +TetrixBoard.prototype.pause = function() { + if (!this.isStarted) + return; + + this.isPaused = !this.isPaused; + if (this.isPaused) { + this.ui.timer.stop(); + } else { + this.ui.timer.start(this.timeoutTime()); + } + this.ui.update(); +} + +TetrixBoard.prototype.getShapeAt = function(x, y) { + return this._board[(y * TetrixBoard.BoardWidth) + x]; +} + +TetrixBoard.prototype.setShapeAt = function(x, y, newShape) { + this._board[(y * TetrixBoard.BoardWidth) + x] = newShape; +} + +TetrixBoard.prototype.clearBoard = function() { + for (var i = 0; i < TetrixBoard.BoardHeight * TetrixBoard.BoardWidth; ++i) + this._board[i] = TetrixShape.NoShape; +} + +TetrixBoard.prototype.dropDown = function() { + var dropHeight = 0; + var newY = this.curY; + while (newY > 0) { + if (!this.tryMove(this.curPiece, this.curX, newY - 1)) + break; + --newY; + ++dropHeight; + } + this.pieceDropped(dropHeight); +} + +TetrixBoard.prototype.oneLineDown = function() { + if (!this.tryMove(this.curPiece, this.curX, this.curY - 1)) + this.pieceDropped(0); +} + +TetrixBoard.prototype.pieceDropped = function(dropHeight) { + for (var i = 0; i < 4; ++i) { + var x = this.curX + this.curPiece.getX(i); + var y = this.curY - this.curPiece.getY(i); + this.setShapeAt(x, y, this.curPiece.shape); + } + + ++this.numPiecesDropped; + if ((this.numPiecesDropped % 25) == 0) { + ++this.level; + this.ui.timer.start(this.timeoutTime()); + this.ui.levelChanged(this.level); + } + + this.score += dropHeight + 7; + this.ui.scoreChanged(this.score); + this.removeFullLines(); + + if (!this.isWaitingAfterLine) + this.newPiece(); + + if (this.isStarted && !this.ui.timer.active) + this.ui.timer.start(this.timeoutTime()); +} + +TetrixBoard.prototype.removeFullLines = function() { + var numFullLines = 0; + + for (var i = TetrixBoard.BoardHeight - 1; i >= 0; --i) { + var lineIsFull = true; + + for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { + if (this.getShapeAt(j, i) == TetrixShape.NoShape) { + lineIsFull = false; + break; + } + } + + if (lineIsFull) { + ++numFullLines; + for (var k = i; k < TetrixBoard.BoardHeight - 1; ++k) { + for (var j = 0; j < TetrixBoard.BoardWidth; ++j) + this.setShapeAt(j, k, this.getShapeAt(j, k + 1)); + } + for (var j = 0; j < TetrixBoard.BoardWidth; ++j) + this.setShapeAt(j, TetrixBoard.BoardHeight - 1, TetrixShape.NoShape); + } + } + + if (numFullLines > 0) { + this.numLinesRemoved += numFullLines; + this.score += 10 * numFullLines; + this.ui.linesRemovedChanged(this.numLinesRemoved); + this.ui.scoreChanged(this.score); + + this.ui.timer.start(500); + this.isWaitingAfterLine = true; + this.curPiece.shape = TetrixShape.NoShape; + this.ui.update(); + } +} + +TetrixBoard.prototype.newPiece = function() { + this.curPiece = this.nextPiece; + this.nextPiece = new TetrixPiece(); + this.nextPiece.setRandomShape(); + this.ui.showNextPiece(this.nextPiece.maxX - this.nextPiece.minX + 1, + this.nextPiece.maxY - this.nextPiece.minY + 1); + this.curX = TetrixBoard.BoardWidth / 2 + 1; + this.curY = TetrixBoard.BoardHeight - 1 + this.curPiece.minY; + + if (!this.tryMove(this.curPiece, this.curX, this.curY)) { + this.curPiece.shape = TetrixShape.NoShape; + this.ui.timer.stop(); + this.isStarted = false; + } +} + +TetrixBoard.prototype.tryMove = function(newPiece, newX, newY) { + for (var i = 0; i < 4; ++i) { + var x = newX + newPiece.getX(i); + var y = newY - newPiece.getY(i); + if ((x < 0) || (x >= TetrixBoard.BoardWidth) || (y < 0) || (y >= TetrixBoard.BoardHeight)) + return false; + if (this.getShapeAt(x, y) != TetrixShape.NoShape) + return false; + } + + this.curPiece = newPiece; + this.curX = newX; + this.curY = newY; + this.ui.update(); + return true; +} + +TetrixBoard.prototype.onPaint = function(painter) { + if (this.isPaused) { + this.ui.drawPauseScreen(painter); + return; + } + + for (var i = 0; i < TetrixBoard.BoardHeight; ++i) { + for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { + var shape = this.getShapeAt(j, TetrixBoard.BoardHeight - i - 1); + if (shape != TetrixShape.NoShape) + this.ui.drawSquare(painter, j, i, shape); + } + } + + if (this.curPiece.shape != TetrixShape.NoShape) { + for (var i = 0; i < 4; ++i) { + var x = this.curX + this.curPiece.getX(i); + var y = this.curY - this.curPiece.getY(i); + this.ui.drawSquare(painter, x, TetrixBoard.BoardHeight - y - 1, + this.curPiece.shape); + } + } +} + +TetrixBoard.prototype.onPaintNextPiece = function(painter) { + for (var i = 0; i < 4; ++i) { + var x = this.nextPiece.getX(i) - this.nextPiece.minX; + var y = this.nextPiece.getY(i) - this.nextPiece.minY; + this.ui.drawSquare(painter, x, y, this.nextPiece.shape); + } +} + +TetrixBoard.prototype.onKeyPress = function(key) { + if (!this.isStarted || this.isPaused || (this.curPiece.shape == TetrixShape.NoShape)) + return; + this.inKeyPress = true; + switch (key) { + case Qt.Key_Left: + this.tryMove(this.curPiece, this.curX - 1, this.curY); + break; + case Qt.Key_Right: + this.tryMove(this.curPiece, this.curX + 1, this.curY); + break; + case Qt.Key_Down: + this.tryMove(this.curPiece.rotatedRight(), this.curX, this.curY); + break; + case Qt.Key_Up: + this.tryMove(this.curPiece.rotatedLeft(), this.curX, this.curY); + break; + case Qt.Key_Space: + this.dropDown(); + break; + case Qt.Key_D: + this.oneLineDown(); + break; + } + this.inKeyPress = false; + if (this.isStarted && !this.ui.timer.active) + this.ui.timer.start(this.timeoutTime()); +} + +TetrixBoard.prototype.onTimer = function() { + if (this.isWaitingAfterLine) { + this.isWaitingAfterLine = false; + this.newPiece(); + this.ui.timer.start(this.timeoutTime()); + } else { + if (!this.inKeyPress) { + this.oneLineDown(); + if (this.isStarted && !this.ui.timer.active) + this.ui.timer.start(this.timeoutTime()); + } + } +} + +TetrixBoard.prototype.timeoutTime = function() { + return 1000 / (1 + this.level); +} diff --git a/examples/script/qstetrix/tetrixpiece.js b/examples/script/qstetrix/tetrixpiece.js new file mode 100644 index 0000000..e99fa8a --- /dev/null +++ b/examples/script/qstetrix/tetrixpiece.js @@ -0,0 +1,131 @@ +TetrixShape = { + NoShape:0, + ZShape:1, + SShape:2, + LineShape:3, + TShape:4, + SquareShape:5, + LShape:6, + MirroredLShape:7 +} + +TetrixCoordsTable = [ + [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], + [ [ 0, -1 ], [ 0, 0 ], [ -1, 0 ], [ -1, 1 ] ], + [ [ 0, -1 ], [ 0, 0 ], [ 1, 0 ], [ 1, 1 ] ], + [ [ 0, -1 ], [ 0, 0 ], [ 0, 1 ], [ 0, 2 ] ], + [ [ -1, 0 ], [ 0, 0 ], [ 1, 0 ], [ 0, 1 ] ], + [ [ 0, 0 ], [ 1, 0 ], [ 0, 1 ], [ 1, 1 ] ], + [ [ -1, -1 ], [ 0, -1 ], [ 0, 0 ], [ 0, 1 ] ], + [ [ 1, -1 ], [ 0, -1 ], [ 0, 0 ], [ 0, 1 ] ] +] + +function TetrixPiece() +{ + this.shape = TetrixShape.NoShape; +} + +TetrixPiece.prototype.__defineGetter__( + "shape", + function() { + return this._shape; + } +); + +TetrixPiece.prototype.__defineSetter__( + "shape", + function(shape) { + this._shape = shape; + this._coords = new Array(4); + for (var i = 0; i < 4; ++i) + this._coords[i] = TetrixCoordsTable[shape][i].slice(); + } +); + +TetrixPiece.prototype.setRandomShape = function() { + this.shape = Math.floor(((Math.random() * 100000) % 7) + 1); +} + +TetrixPiece.prototype.getX = function(index) { + return this._coords[index][0]; +} + +TetrixPiece.prototype.getY = function(index) { + return this._coords[index][1]; +} + +TetrixPiece.prototype._setX = function(index, x) { + this._coords[index][0] = x; +} + +TetrixPiece.prototype._setY = function(index, y) { + this._coords[index][1] = y; +} + +TetrixPiece.prototype.__defineGetter__( + "minX", + function() { + var min = this._coords[0][0]; + for (var i = 1; i < 4; ++i) + min = Math.min(min, this._coords[i][0]); + return min; + } +); + +TetrixPiece.prototype.__defineGetter__( + "maxX", + function() { + var max = this._coords[0][0]; + for (var i = 1; i < 4; ++i) + max = Math.max(max, this._coords[i][0]); + return max; + } +); + +TetrixPiece.prototype.__defineGetter__( + "minY", + function() { + var min = this._coords[0][1]; + for (var i = 1; i < 4; ++i) + min = Math.min(min, this._coords[i][1]); + return min; + } +); + +TetrixPiece.prototype.__defineGetter__( + "maxY", + function() { + var max = this._coords[0][1]; + for (var i = 1; i < 4; ++i) + max = Math.max(max, this._coords[i][1]); + return max; + } +); + +TetrixPiece.prototype.rotatedLeft = function() { + var result = new TetrixPiece(); + if (this._shape == TetrixShape.SquareShape) { + result.shape = this._shape; + return result; + } + result._shape = this._shape; + for (var i = 0; i < 4; ++i) { + result._setX(i, this.getY(i)); + result._setY(i, -this.getX(i)); + } + return result; +} + +TetrixPiece.prototype.rotatedRight = function() { + var result = new TetrixPiece(); + if (this._shape == TetrixShape.SquareShape) { + result.shape = this._shape; + return result; + } + result._shape = this._shape; + for (var i = 0; i < 4; ++i) { + result._setX(i, -this.getY(i)); + result._setY(i, this.getX(i)); + } + return result; +} diff --git a/examples/script/qstetrix/tetrixwindow.js b/examples/script/qstetrix/tetrixwindow.js new file mode 100644 index 0000000..6157a8c --- /dev/null +++ b/examples/script/qstetrix/tetrixwindow.js @@ -0,0 +1,16 @@ +function TetrixWindow(ui) +{ + this.ui = ui; + + var boardUi = ui.findChild("board"); + boardUi.nextPieceLabel = ui.findChild("nextPieceLabel"); + + this.board = new TetrixBoard(boardUi); + + ui.findChild("startButton").clicked.connect(this.board, this.board.start); + ui.findChild("quitButton").clicked.connect(Qt.App.quit); + ui.findChild("pauseButton").clicked.connect(this.board, this.board.pause); + boardUi.scoreChanged.connect(ui.findChild("scoreLcd")["display(int)"]); + boardUi.levelChanged.connect(ui.findChild("levelLcd")["display(int)"]); + boardUi.linesRemovedChanged.connect(ui.findChild("linesLcd")["display(int)"]); +} diff --git a/examples/script/qstetrix/tetrixwindow.ui b/examples/script/qstetrix/tetrixwindow.ui new file mode 100644 index 0000000..a53e94f --- /dev/null +++ b/examples/script/qstetrix/tetrixwindow.ui @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TetrixWindow</class> + <widget class="QWidget" name="TetrixWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>537</width> + <height>475</height> + </rect> + </property> + <property name="windowTitle"> + <string>Tetrix</string> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>9</number> + </property> + <item> + <layout class="QGridLayout"> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="4" column="0"> + <widget class="QPushButton" name="startButton"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string>&Start</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QLCDNumber" name="linesLcd"> + <property name="segmentStyle"> + <enum>QLCDNumber::Filled</enum> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="linesRemovedLabel"> + <property name="text"> + <string>LINES REMOVED</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignHCenter</set> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLCDNumber" name="scoreLcd"> + <property name="segmentStyle"> + <enum>QLCDNumber::Filled</enum> + </property> + </widget> + </item> + <item row="0" column="1" rowspan="6"> + <widget class="TetrixBoard" name="board"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Panel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="levelLabel"> + <property name="text"> + <string>LEVEL</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignHCenter</set> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="nextLabel"> + <property name="text"> + <string>NEXT</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignHCenter</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLCDNumber" name="levelLcd"> + <property name="segmentStyle"> + <enum>QLCDNumber::Filled</enum> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="scoreLabel"> + <property name="text"> + <string>SCORE</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignHCenter</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="nextPieceLabel"> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QPushButton" name="quitButton"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string>&Quit</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QPushButton" name="pauseButton"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string>&Pause</string> + </property> + </widget> + </item> + <item row="5" column="2"> + <widget class="QPushButton" name="debugButton"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="text"> + <string>&Debug</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>TetrixBoard</class> + <extends>QFrame</extends> + <header>tetrixboard.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/examples/script/script.pro b/examples/script/script.pro new file mode 100644 index 0000000..ae3542e --- /dev/null +++ b/examples/script/script.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs +SUBDIRS = helloscript context2d defaultprototypes customclass + +!wince*:SUBDIRS += qscript marshal +!wince*:!cross_compile:SUBDIRS += calculator qstetrix + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/script +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS script.pro README +sources.path = $$[QT_INSTALL_EXAMPLES]/script +INSTALLS += target sources |