summaryrefslogtreecommitdiffstats
path: root/examples/script/context2d/environment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/script/context2d/environment.cpp')
-rw-r--r--examples/script/context2d/environment.cpp561
1 files changed, 561 insertions, 0 deletions
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));
+}