diff options
Diffstat (limited to 'doc/src/examples/context2d.qdoc')
-rw-r--r-- | doc/src/examples/context2d.qdoc | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/doc/src/examples/context2d.qdoc b/doc/src/examples/context2d.qdoc new file mode 100644 index 0000000..f10e1ec --- /dev/null +++ b/doc/src/examples/context2d.qdoc @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example script/context2d + \title Context2D Example + + This Qt Script example is an implementation of the Context2D API. + + \image context2d-example.png + + Context2D is part of the specification for the HTML \c{<canvas>} + element. It can be used to draw graphics via scripting. A good + resource for learning more about the HTML \c{<canvas>} element is + the \l{http://developer.mozilla.org/en/docs/HTML:Canvas}{Mozilla Developer Center}. + + \section1 Using The HTML Canvas Element in a Web Browser + + First, let's look at how the \c{<canvas>} element is typically + used in a web browser. The following HTML snippet defines a + canvas of size 400x400 pixels with id \c{mycanvas}: + + \code + <canvas width="400" height="400" id="mycanvas">Fallback content goes here.</canvas> + \endcode + + To draw on the canvas, we must first obtain a reference to the + DOM element corresponding to the \c{<canvas>} tag and then call + the element's getContext() function. The resulting object + implements the Context2D API that we use to draw. + + \code + <script> + var canvas = document.getElementById("mycanvas"); + var ctx = canvas.getContext("2d"); + + // Draw a face + 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(); + </script> + \endcode + + When the page is rendered by a browser that supports the + \c{<canvas>} tag, this would be the result: + + \image context2d-example-smileysmile.png + + \section1 Using Qt Script to script a Canvas + + The goal of this example is to be able to evaluate scripts + that use the Context2D API, and render the results. Basic + interaction (mouse, keyboard) should also be supported. + In other words, we want to present scripts with an execution + environment that very much resembles that of a web browser. Of + course, our environment is only a small subset of what a browser + provides; i.e. we don't provide a full DOM API, only what is + needed to run "self-contained" Context2D scripts (i.e. scripts + that don't depend on other parts of the DOM document). + + Our "Context2D-browser" is set up through the following steps: + \list + \o Create an Environment. + \o Create a Context2D, and a QContext2DCanvas widget to render it. + \o Add the canvas object to the environment; this will enable + scripts to obtain a reference to it. + \o Evaluate scripts in the environment. + \endlist + + Once a script has been evaluated, the application handles any + timer events and input events that occur subsequently + (i.e. forwards events to their associated script targets). + + \section1 The Context2D Class + + The "heart" of this example is the Context2D C++ class that implements + the drawing API. Its interface is defined in terms of properties + and slots. Note that this class isn't tied to Qt Script in any + way. + + \snippet examples/script/context2d/context2d.h 0 + + The properties define various aspects of the Context2D + configuration. + + \snippet examples/script/context2d/context2d.h 1 + + The slots define the operations that can be performed. + + \snippet examples/script/context2d/context2d.h 2 + + The changed() signal is emitted when the contents of the drawing + area has changed, so that clients associated with the Context2D + object (i.e. the canvas widget that renders it) are notified. + + \section2 Implementation + + Conveniently enough, the concepts, data structures and operations + of the Context2D API map more or less directly to Qt's painting + API. Conceptually, all we have to do is initialize a QPainter + according to the Context2D properties, and use functions like + QPainter::strokePath() to do the painting. Painting is done on a + QImage. + + \snippet examples/script/context2d/context2d.cpp 0 + + The property accessors and most of the slots manipulate the + internal Context2D state in some way. For the \c{lineCap} + property, Context2D uses a string representation; we therefore + have to map it from/to a Qt::PenCapStyle. The \c{lineJoin} + property is handled in the same fashion. All the property setters + also set a \e{dirty flag} for the property; this is used to + decide which aspects of the QPainter that need to be updated + before doing the next painting operation. + + \snippet examples/script/context2d/context2d.cpp 3 + + The implementation of the \c{fillStyle} property is interesting, + since the value can be either a string or a \c{CanvasGradient}. + We handle this by having the property be of type QVariant, + and check the actual type of the value to see how to handle the + write. + + \snippet examples/script/context2d/context2d.cpp 1 + + Context2D does not have a concept of a paint event; painting + operations can happen at any time. We would like to be efficient, + and not have to call QPainter::begin() and QPainter::end() for + every painting operation, since typically many painting operations + will follow in quick succession. The implementations of the + painting operations use a helper function, beginPainting(), that + activates the QPainter if it isn't active already, and updates + the state of the QPainter (brush, pen, etc.) so that it reflects + the current Context2D state. + + \snippet examples/script/context2d/context2d.cpp 2 + + The implementation of each painting operation ends by calling + scheduleChange(), which will post a zero-timer event if one is + not already pending. When the application returns to the event + loop later (presumably after all the drawing operations have + finished), the timer will trigger, QPainter::end() will be + called, and the changed() signal is emitted with the new + image as argument. The net effect is that there will typically + be only a single (QPainter::begin(), QPainter::end()) pair + executed for the full sequence of painting operations. + + \section1 The Canvas Widget + + \snippet examples/script/context2d/qcontext2dcanvas.h 0 + + The QContext2DCanvas class provides a widget that renders + the contents of a Context2D object. It also provides a + minimal scripting API, most notably the getContext() function. + + \snippet examples/script/context2d/qcontext2dcanvas.cpp 3 + + The constructor connects to the changed() signal of the + Context2D object, so that the widget can update itself + when it needs to do so. Mouse tracking is enabled so that + mouse move events will be received even when no mouse + buttons are depressed. + + \snippet examples/script/context2d/qcontext2dcanvas.cpp 0 + + The getContext() function asks the environment to wrap the + Context2D object; the resulting proxy object makes the + Context2D API available to scripts. + + \snippet examples/script/context2d/qcontext2dcanvas.cpp 1 + + The paintEvent() function simply paints the contents that + was last received from the Context2D object. + + \snippet examples/script/context2d/qcontext2dcanvas.cpp 2 + + The canvas widget reimplements mouse and key event handlers, and + forwards these events to the scripting environment. The + environment will take care of delivering the event to the proper + script target, if any. + + \section1 The Environment + + \snippet examples/script/context2d/environment.h 0 + + The Environment class provides a scripting environment where a + Canvas C++ object can be registered, looked up by ID (name), + and where scripts can be evaluated. The environment has a + \c{document} property, just like the scripting environment of a + web browser, so that scripts can call + \c{document.getElementById()} to obtain a reference to a canvas. + + \snippet examples/script/context2d/environment.h 1 + + The Environment class provides the timer attributes of the DOM + Window Object interface. This enables us to support scripts that + do animation, for example. + + \snippet examples/script/context2d/environment.h 2 + + The scriptError() signal is emitted when evaluation of a script + causes a script exception. For example, if a mouse press handler + or timeout handler causes an exception, the environment's client(s) + will be notified of this and can report the error. + + \snippet examples/script/context2d/environment.cpp 0 + + The constructor initializes the environment. First it creates + the QScriptEngine that will be used to evaluate scripts. It + creates the Document object that provides the getElementById() + function. Note that the QScriptEngine::ExcludeSuperClassContents + flag is specified to avoid the wrapper objects from exposing properties + and methods inherited from QObject. Next, the environment wraps + a pointer to \e{itself}; this is to prepare for setting this object + as the script engine's Global Object. The properties of the standard + Global Object are copied, so that these will also be available in + our custom Global Object. We also create two self-references to the + object; again, this is to provide a minimal level of compabilitity + with the scripting environment that web browsers provide. + + \snippet examples/script/context2d/environment.cpp 5 + + The addCanvas() function adds the given canvas to the list of + registered canvas objects. The canvasByName() function looks up + a canvas by QObject::objectName(). This function is used to + implement the \c{document.getElementById()} script function. + + \snippet examples/script/context2d/environment.cpp 1 + + The setInterval() and clearInterval() implementations use a QHash + to map from timer ID to the QScriptValue that holds the expression + to evaluate when the timer is triggered. A helper function, + maybeEmitScriptError(), is called after invoking the script handler; + it will emit the scriptError() signal if the script engine has an + uncaught exception. + + \snippet examples/script/context2d/environment.cpp 2 + + The toWrapper() functions creates a QScriptValue that wraps the + given QObject. Note that the QScriptEngine::PreferExistingWrapperObject + flag is specified; this guarantees that a single, unique wrapper + object will be returned, even if toWrapper() is called several times + with the same argument. This is important, since it is possible that + a script can set new properties on the resulting wrapper object (e.g. + event handlers like \c{onmousedown}), and we want these to persist. + + \snippet examples/script/context2d/environment.cpp 3 + + The handleEvent() function determines if there exists a handler + for the given event in the environment, and if so, invokes that + handler. Since the script expects a DOM event, the Qt C++ event + must be converted to a DOM event before it is passed to the + script. This mapping is relatively straightforward, but again, + we only implement a subset of the full DOM API; just enough to + get most scripts to work. + + \snippet examples/script/context2d/environment.cpp 4 + + The newFakeDomEvent() function is a helper function that creates + a new script object and initializes it with default values for + the attributes defined in the DOM Event and DOM UIEvent + interfaces. + + \snippet examples/script/context2d/environment.h 3 + + The Document class defines two slots that become available to + scripts: getElementById() and getElementsByTagName(). + When the tag name is "canvas", getElementsByTagName() will + return a list of all canvas objects that are registered in + the environment. + + \section1 The Application Window + + \snippet examples/script/context2d/window.cpp 0 + + The Window constructor creates an Environment object and + connects to its scriptError() signal. It then creates a + Context2D object, and a QContext2DCanvas widget to hold it. + The canvas widget is given the name \c{tutorial}, and added to the + environment; scripts can access the canvas by e.g. + \c{document.getElementById('tutorial')}. + + \snippet examples/script/context2d/window.cpp 1 + + The window contains a list widget that is populated with + available scripts (read from a \c{scripts/} folder). + + \snippet examples/script/context2d/window.cpp 2 + + When an item is selected, the corresponding script is + evaluated in the environment. + + \snippet examples/script/context2d/window.cpp 3 + + When the "Run in Debugger" button is clicked, the Qt Script debugger will + automatically be invoked when the first statement of the script is + reached. This enables the user to inspect the scripting environment and + control further execution of the script; e.g. he can single-step through + the script and/or set breakpoints. It is also possible to enter script + statements in the debugger's console widget, e.g. to perform custom + Context2D drawing operations, interactively. + + \snippet examples/script/context2d/window.cpp 4 + + If the evaluation of a script causes an uncaught exception, the Qt Script + debugger will automatically be invoked; this enables the user to get an + idea of what went wrong. + +*/ |