| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	morphic.js | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	a lively Web-GUI | 
					
						
							|  |  |  | 	inspired by Squeak | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	written by Jens Mönig | 
					
						
							|  |  |  | 	jens@moenig.org | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  | 	Copyright (C) 2015 by Jens Mönig | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  | 	this documentation last changed: Dec 21, 2015 | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	This file is part of Snap!. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Snap! is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | 	it under the terms of the GNU Affero General Public License as | 
					
						
							|  |  |  | 	published by the Free Software Foundation, either version 3 of | 
					
						
							|  |  |  | 	the License, or (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | 	but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | 	GNU Affero General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  | 	along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     documentation contents | 
					
						
							|  |  |  |     ---------------------- | 
					
						
							|  |  |  |     I. inheritance hierarchy | 
					
						
							|  |  |  |     II. object definition toc | 
					
						
							|  |  |  |     III. yet to implement | 
					
						
							|  |  |  |     IV. open issues | 
					
						
							|  |  |  |     V. browser compatibility | 
					
						
							|  |  |  |     VI. the big picture | 
					
						
							|  |  |  |     VII. programming guide | 
					
						
							|  |  |  |         (1) setting up a web page | 
					
						
							|  |  |  |             (a) single world | 
					
						
							|  |  |  |             (b) multiple worlds | 
					
						
							|  |  |  |             (c) an application | 
					
						
							|  |  |  |         (2) manipulating morphs | 
					
						
							|  |  |  |         (3) events | 
					
						
							|  |  |  |             (a) mouse events | 
					
						
							|  |  |  |             (b) context menu | 
					
						
							|  |  |  |             (c) dragging | 
					
						
							|  |  |  |             (d) dropping | 
					
						
							|  |  |  |             (e) keyboard events | 
					
						
							|  |  |  |             (f) resize event | 
					
						
							|  |  |  |             (g) combined mouse-keyboard events | 
					
						
							|  |  |  |             (h) text editing events | 
					
						
							|  |  |  |         (4) stepping | 
					
						
							|  |  |  |         (5) creating new kinds of morphs | 
					
						
							|  |  |  |         (6) development and user modes | 
					
						
							|  |  |  |         (7) turtle graphics | 
					
						
							|  |  |  |         (8) damage list housekeeping | 
					
						
							|  |  |  |         (9) minifying morphic.js | 
					
						
							|  |  |  |     VIII. acknowledgements | 
					
						
							|  |  |  |     IX. contributors | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     I. hierarchy | 
					
						
							|  |  |  |     ------------- | 
					
						
							|  |  |  |     the following tree lists all constructors hierarchically, | 
					
						
							|  |  |  |     indentation indicating inheritance. Refer to this list to get a | 
					
						
							|  |  |  |     contextual overview: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Color | 
					
						
							|  |  |  |     Node | 
					
						
							|  |  |  |         Morph | 
					
						
							|  |  |  |             BlinkerMorph | 
					
						
							|  |  |  |                 CursorMorph | 
					
						
							|  |  |  |             BouncerMorph* | 
					
						
							|  |  |  |             BoxMorph | 
					
						
							|  |  |  |                 InspectorMorph | 
					
						
							|  |  |  |                 MenuMorph | 
					
						
							|  |  |  |                 MouseSensorMorph* | 
					
						
							|  |  |  |                 SpeechBubbleMorph | 
					
						
							|  |  |  |             CircleBoxMorph | 
					
						
							|  |  |  |                 SliderButtonMorph | 
					
						
							|  |  |  |                 SliderMorph | 
					
						
							|  |  |  |             ColorPaletteMorph | 
					
						
							|  |  |  |                 GrayPaletteMorph | 
					
						
							|  |  |  |             ColorPickerMorph | 
					
						
							|  |  |  |             FrameMorph | 
					
						
							|  |  |  |                 ScrollFrameMorph | 
					
						
							|  |  |  |                     ListMorph | 
					
						
							|  |  |  |                 StringFieldMorph | 
					
						
							|  |  |  |                 WorldMorph | 
					
						
							|  |  |  |             HandleMorph | 
					
						
							|  |  |  |             HandMorph | 
					
						
							|  |  |  |             PenMorph | 
					
						
							|  |  |  |             ShadowMorph | 
					
						
							|  |  |  |             StringMorph | 
					
						
							|  |  |  |             TextMorph | 
					
						
							|  |  |  |             TriggerMorph | 
					
						
							|  |  |  |                 MenuItemMorph | 
					
						
							|  |  |  |     Point | 
					
						
							|  |  |  |     Rectangle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     II. toc | 
					
						
							|  |  |  |     ------- | 
					
						
							|  |  |  |     the following list shows the order in which all constructors are | 
					
						
							|  |  |  |     defined. Use this list to locate code in this document: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Global settings | 
					
						
							|  |  |  |     Global functions | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Color | 
					
						
							|  |  |  |     Point | 
					
						
							|  |  |  |     Rectangle | 
					
						
							|  |  |  |     Node | 
					
						
							|  |  |  |     Morph | 
					
						
							|  |  |  |     ShadowMorph | 
					
						
							|  |  |  |     HandleMorph | 
					
						
							|  |  |  |     PenMorph | 
					
						
							|  |  |  |     ColorPaletteMorph | 
					
						
							|  |  |  |     GrayPaletteMorph | 
					
						
							|  |  |  |     ColorPickerMorph | 
					
						
							|  |  |  |     BlinkerMorph | 
					
						
							|  |  |  |     CursorMorph | 
					
						
							|  |  |  |     BoxMorph | 
					
						
							|  |  |  |     SpeechBubbleMorph | 
					
						
							|  |  |  |     CircleBoxMorph | 
					
						
							|  |  |  |     SliderButtonMorph | 
					
						
							|  |  |  |     SliderMorph | 
					
						
							|  |  |  |     MouseSensorMorph* | 
					
						
							|  |  |  |     InspectorMorph | 
					
						
							|  |  |  |     MenuMorph | 
					
						
							|  |  |  |     StringMorph | 
					
						
							|  |  |  |     TextMorph | 
					
						
							|  |  |  |     TriggerMorph | 
					
						
							|  |  |  |     MenuItemMorph | 
					
						
							|  |  |  |     FrameMorph | 
					
						
							|  |  |  |     ScrollFrameMorph | 
					
						
							|  |  |  |     ListMorph | 
					
						
							|  |  |  |     StringFieldMorph | 
					
						
							|  |  |  |     BouncerMorph* | 
					
						
							|  |  |  |     HandMorph | 
					
						
							|  |  |  |     WorldMorph | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * included only for demo purposes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     III. yet to implement | 
					
						
							|  |  |  |     --------------------- | 
					
						
							|  |  |  |     - keyboard support for scroll frames and lists | 
					
						
							| 
									
										
										
										
											2015-09-23 09:41:17 +00:00
										 |  |  |     - full keyboard support for menus (partial support exists) | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     - virtual keyboard support for Android and IE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     IV. open issues | 
					
						
							|  |  |  |     ---------------- | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |     - clipboard support (copy & paste) for non-textual data | 
					
						
							| 
									
										
										
										
											2015-09-23 09:41:17 +00:00
										 |  |  |     - native (unscaled) high-resolution display support | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     V. browser compatibility | 
					
						
							|  |  |  |     ------------------------ | 
					
						
							|  |  |  |     I have taken great care and considerable effort to make morphic.js | 
					
						
							|  |  |  |     runnable and appearing exactly the same on all current browsers | 
					
						
							|  |  |  |     available to me: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - Firefox for Windows | 
					
						
							|  |  |  |     - Firefox for Mac | 
					
						
							| 
									
										
										
										
											2015-09-23 09:41:17 +00:00
										 |  |  |     - Firefox for Android | 
					
						
							|  |  |  |     - Chrome for Windows | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     - Chrome for Mac | 
					
						
							| 
									
										
										
										
											2015-09-23 09:41:17 +00:00
										 |  |  |     - Chrome for Android | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |     - Safari for Windows (deprecated) | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     - safari for Mac | 
					
						
							|  |  |  |     - Safari for iOS (mobile) | 
					
						
							|  |  |  |     - IE for Windows | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |     - Edge for Windows | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     - Opera for Windows | 
					
						
							|  |  |  |     - Opera for Mac | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VI. the big picture | 
					
						
							|  |  |  |     ------------------- | 
					
						
							|  |  |  |     Morphic.js is completely based on Canvas and JavaScript, it is just | 
					
						
							|  |  |  |     Morphic, nothing else. Morphic.js is very basic and covers only the | 
					
						
							|  |  |  |     bare essentials: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         * a stepping mechanism (a time-sharing multiplexer for lively | 
					
						
							|  |  |  |           user interaction ontop of a single OS/browser thread) | 
					
						
							|  |  |  |         * progressive display updates (only dirty rectangles are | 
					
						
							|  |  |  |           redrawn in each display cycle) | 
					
						
							|  |  |  |         * a tree structure | 
					
						
							|  |  |  |         * a single World per Canvas element (although you can have | 
					
						
							|  |  |  |           multiple worlds in multiple Canvas elements on the same web | 
					
						
							|  |  |  |           page) | 
					
						
							|  |  |  |         * a single Hand per World (but you can support multi-touch | 
					
						
							|  |  |  |           events) | 
					
						
							|  |  |  |         * a single text entry focus per World | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     In its current state morphic.js doesn't support Transforms (you | 
					
						
							|  |  |  |     cannot rotate Morphs), but with PenMorph there already is a simple | 
					
						
							|  |  |  |     LOGO-like turtle that you can use to draw onto any Morph it is | 
					
						
							|  |  |  |     attached to. I'm planning to add special Morphs that support these | 
					
						
							|  |  |  |     operations later on, but not for every Morph in the system. | 
					
						
							|  |  |  |     Therefore these additions ("sprites" etc.) are likely to be part of | 
					
						
							|  |  |  |     other libraries ("microworld.js") in separate files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     the purpose of morphic.js is to provide a malleable framework that | 
					
						
							|  |  |  |     will let me experiment with lively GUIs for my hobby horse, which | 
					
						
							|  |  |  |     is drag-and-drop, blocks based programming languages. Those things | 
					
						
							|  |  |  |     (BYOB4 - http://byob.berkeley.edu) will be written using morphic.js | 
					
						
							|  |  |  |     as a library. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VII. programming guide | 
					
						
							|  |  |  |     ---------------------- | 
					
						
							|  |  |  |     Morphic.js provides a library for lively GUIs inside single HTML | 
					
						
							|  |  |  |     Canvas elements. Each such canvas element functions as a "world" in | 
					
						
							|  |  |  |     which other visible shapes ("morphs") can be positioned and | 
					
						
							|  |  |  |     manipulated, often directly and interactively by the user. Morphs | 
					
						
							|  |  |  |     are tree nodes and may contain any number of submorphs ("children"). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All things visible in a morphic World are morphs themselves, i.e. | 
					
						
							|  |  |  |     all text rendering, blinking cursors, entry fields, menus, buttons, | 
					
						
							|  |  |  |     sliders, windows and dialog boxes etc. are created with morphic.js | 
					
						
							|  |  |  |     rather than using HTML DOM elements, and as a consequence can be | 
					
						
							|  |  |  |     changed and adjusted by the programmer regardless of proprietary | 
					
						
							|  |  |  |     browser behavior. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Each World has an - invisible - "Hand" resembling the mouse cursor | 
					
						
							|  |  |  |     (or the user's finger on touch screens) which handles mouse events, | 
					
						
							|  |  |  |     and may also have a keyboardReceiver to handle key events. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The basic idea of Morphic is to continuously run display cycles and | 
					
						
							|  |  |  |     to incrementally update the screen by only redrawing those  World | 
					
						
							|  |  |  |     regions    which have been "dirtied" since the last redraw. Before | 
					
						
							|  |  |  |     each shape is processed for redisplay it gets the chance to perform | 
					
						
							|  |  |  |     a "step" procedure, thus allowing for an illusion of concurrency. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (1) setting up a web page | 
					
						
							|  |  |  |     ------------------------- | 
					
						
							|  |  |  |     Setting up a web page for Morphic always involves three steps: | 
					
						
							|  |  |  |     adding one or more Canvas elements, defining one or more worlds, | 
					
						
							|  |  |  |     initializing and starting the main loop. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (a) single world | 
					
						
							|  |  |  |     ----------------- | 
					
						
							|  |  |  |     Most commonly you will want your World to fill the browsers's whole | 
					
						
							|  |  |  |     client area. This default situation is easiest and most straight | 
					
						
							|  |  |  |     forward. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     example html file: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <!DOCTYPE html> | 
					
						
							|  |  |  |     <html> | 
					
						
							|  |  |  |         <head> | 
					
						
							|  |  |  |             <title>Morphic!</title> | 
					
						
							|  |  |  |             <script type="text/javascript" src="morphic.js"></script> | 
					
						
							|  |  |  |             <script type="text/javascript"> | 
					
						
							|  |  |  |                 var world; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 window.onload = function () { | 
					
						
							|  |  |  |                     world = new WorldMorph( | 
					
						
							|  |  |  |                         document.getElementById('world')); | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     loop(); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 function loop() { | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     requestAnimationFrame(loop); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                     world.doOneCycle(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             </script> | 
					
						
							|  |  |  |         </head> | 
					
						
							|  |  |  |         <body> | 
					
						
							|  |  |  |             <canvas id="world" tabindex="1" width="800" height="600"> | 
					
						
							|  |  |  |                 <p>Your browser doesn't support canvas.</p> | 
					
						
							|  |  |  |             </canvas> | 
					
						
							|  |  |  |         </body> | 
					
						
							|  |  |  |     </html> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if you use ScrollFrames or otherwise plan to support mouse wheel | 
					
						
							|  |  |  |     scrolling events, you might also add the following inline-CSS | 
					
						
							|  |  |  |     attribute to the Canvas element: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         style="position: absolute;" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     which will prevent the World to be scrolled around instead of the | 
					
						
							|  |  |  |     elements inside of it in some browsers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (b) multiple worlds | 
					
						
							|  |  |  |     ------------------- | 
					
						
							|  |  |  |     If you wish to create a web page with more than one world, make | 
					
						
							|  |  |  |     sure to prevent each world from auto-filling the whole page and | 
					
						
							|  |  |  |     include    it in the main loop. It's also a good idea to give each | 
					
						
							|  |  |  |     world its own tabindex: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     example html file: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <!DOCTYPE html> | 
					
						
							|  |  |  |     <html> | 
					
						
							|  |  |  |         <head> | 
					
						
							|  |  |  |             <title>Morphic!</title> | 
					
						
							|  |  |  |             <script type="text/javascript" src="morphic.js"></script> | 
					
						
							|  |  |  |             <script type="text/javascript"> | 
					
						
							|  |  |  |                 var world1, world2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 window.onload = function () { | 
					
						
							|  |  |  |                     world1 = new WorldMorph( | 
					
						
							|  |  |  |                         document.getElementById('world1'), false); | 
					
						
							|  |  |  |                     world2 = new WorldMorph( | 
					
						
							|  |  |  |                         document.getElementById('world2'), false); | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     loop(); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 function loop() { | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     requestAnimationFrame(loop); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                     world1.doOneCycle(); | 
					
						
							|  |  |  |                     world2.doOneCycle(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             </script> | 
					
						
							|  |  |  |         </head> | 
					
						
							|  |  |  |         <body> | 
					
						
							|  |  |  |             <p>first world:</p> | 
					
						
							|  |  |  |             <canvas id="world1" tabindex="1" width="600" height="400"> | 
					
						
							|  |  |  |                 <p>Your browser doesn't support canvas.</p> | 
					
						
							|  |  |  |             </canvas> | 
					
						
							|  |  |  |             <p>second world:</p> | 
					
						
							|  |  |  |             <canvas id="world2" tabindex="2" width="400" height="600"> | 
					
						
							|  |  |  |                 <p>Your browser doesn't support canvas.</p> | 
					
						
							|  |  |  |             </canvas> | 
					
						
							|  |  |  |         </body> | 
					
						
							|  |  |  |     </html> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (c) an application | 
					
						
							|  |  |  |     ------------------- | 
					
						
							|  |  |  |     Of course, most of the time you don't want to just plain use the | 
					
						
							|  |  |  |     standard Morhic World "as is" out of the box, but write your own | 
					
						
							|  |  |  |     application (something like Scratch!) in it. For such an | 
					
						
							|  |  |  |     application you'll create your own morph prototypes, perhaps | 
					
						
							|  |  |  |     assemble your own "window frame" and bring it all to life in a | 
					
						
							|  |  |  |     customized World state. the following example creates a simple | 
					
						
							|  |  |  |     snake-like mouse drawing game. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     example html file: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     <!DOCTYPE html> | 
					
						
							|  |  |  |     <html> | 
					
						
							|  |  |  |         <head> | 
					
						
							|  |  |  |             <title>touch me!</title> | 
					
						
							|  |  |  |             <script type="text/javascript" src="morphic.js"></script> | 
					
						
							|  |  |  |             <script type="text/javascript"> | 
					
						
							|  |  |  |                 var worldCanvas, sensor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 window.onload = function () { | 
					
						
							|  |  |  |                     var x, y, w, h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     worldCanvas = document.getElementById('world'); | 
					
						
							|  |  |  |                     world = new WorldMorph(worldCanvas); | 
					
						
							|  |  |  |                     world.isDevMode = false; | 
					
						
							|  |  |  |                     world.color = new Color(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     w = 100; | 
					
						
							|  |  |  |                     h = 100; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     x = 0; | 
					
						
							|  |  |  |                     y = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     while ((y * h) < world.height()) { | 
					
						
							|  |  |  |                         while ((x * w) < world.width()) { | 
					
						
							|  |  |  |                             sensor = new MouseSensorMorph(); | 
					
						
							|  |  |  |                             sensor.setPosition(new Point(x * w, y * h)); | 
					
						
							|  |  |  |                             sensor.alpha = 0; | 
					
						
							|  |  |  |                             sensor.setExtent(new Point(w, h)); | 
					
						
							|  |  |  |                             world.add(sensor); | 
					
						
							|  |  |  |                             x += 1; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         x = 0; | 
					
						
							|  |  |  |                         y += 1; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     loop(); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 function loop() { | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |                     requestAnimationFrame(loop); | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |                     world.doOneCycle(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             </script> | 
					
						
							|  |  |  |         </head> | 
					
						
							|  |  |  |         <body bgcolor='black'> | 
					
						
							|  |  |  |             <canvas id="world" width="800" height="600"> | 
					
						
							|  |  |  |                 <p>Your browser doesn't support canvas.</p> | 
					
						
							|  |  |  |             </canvas> | 
					
						
							|  |  |  |         </body> | 
					
						
							|  |  |  |     </html> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     To get an idea how you can craft your own custom morph prototypes | 
					
						
							|  |  |  |     I've included two examples which should give you an idea how to add | 
					
						
							|  |  |  |     properties, override inherited methods and use the stepping | 
					
						
							|  |  |  |     mechanism for "livelyness": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         BouncerMorph | 
					
						
							|  |  |  |         MouseSensorMorph | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     For the sake of sharing a single file I've included those examples | 
					
						
							|  |  |  |     in morphic.js itself. Usually you'll define your additions in a | 
					
						
							|  |  |  |     separate file and keep morphic.js untouched. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (2) manipulating morphs | 
					
						
							|  |  |  |     ----------------------- | 
					
						
							|  |  |  |     There are many methods to programmatically manipulate morphs. Among | 
					
						
							|  |  |  |     the most important and common ones among all morphs are the | 
					
						
							|  |  |  |     following nine: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * hide() | 
					
						
							|  |  |  |     * show() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * setPosition(aPoint) | 
					
						
							|  |  |  |     * setExtent(aPoint) | 
					
						
							|  |  |  |     * setColor(aColor) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     * add(submorph)            - attaches submorph ontop | 
					
						
							|  |  |  |     * addBack(submorph)        - attaches submorph underneath | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     * fullCopy()               - duplication | 
					
						
							|  |  |  |     * destroy()                - deletion | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (3) events | 
					
						
							|  |  |  |     ---------- | 
					
						
							|  |  |  |     All user (and system) interaction is triggered by events, which are | 
					
						
							|  |  |  |     passed on from the root element - the World - to its submorphs. The | 
					
						
							|  |  |  |     World contains a list of system (browser) events it reacts to in its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         initEventListeners() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method. Currently there are | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         - mouse | 
					
						
							|  |  |  |         - drop | 
					
						
							|  |  |  |         - keyboard | 
					
						
							|  |  |  |         - (window) resize | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     events. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     These system events are dispatched within the morphic World by the | 
					
						
							|  |  |  |     World's Hand and its keyboardReceiver (usually the active text | 
					
						
							|  |  |  |     cursor). | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (a) mouse events: | 
					
						
							|  |  |  |     ----------------- | 
					
						
							|  |  |  |     The Hand dispatches the following mouse events to relevant morphs: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         mouseDownLeft | 
					
						
							|  |  |  |         mouseDownRight | 
					
						
							|  |  |  |         mouseClickLeft | 
					
						
							|  |  |  |         mouseClickRight | 
					
						
							|  |  |  |         mouseDoubleClick | 
					
						
							|  |  |  |         mouseEnter | 
					
						
							|  |  |  |         mouseLeave | 
					
						
							|  |  |  |         mouseEnterDragging | 
					
						
							|  |  |  |         mouseLeaveDragging | 
					
						
							|  |  |  |         mouseMove | 
					
						
							|  |  |  |         mouseScroll | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     If you wish your morph to react to any such event, simply add a | 
					
						
							|  |  |  |     method of the same name as the event, e.g: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         MyMorph.prototype.mouseMove = function(pos) {}; | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     All of these methods have as optional parameter a Point object | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     indicating the current position of the Hand inside the World's | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     coordinate system. The | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mouseMove(pos, button) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event method has an additional optional parameter indicating the | 
					
						
							|  |  |  |     currently pressed mouse button, which is either 'left' or 'right'. | 
					
						
							|  |  |  |     You can use this to let users interact with 3D environments. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Events may be "bubbled" up a morph's owner chain by calling | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         this.escalateEvent(functionName, arg) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     in the event handler method's code. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Likewise, removing the event handler method will render your morph | 
					
						
							|  |  |  |     passive to the event in question. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (b) context menu: | 
					
						
							|  |  |  |     ----------------- | 
					
						
							|  |  |  |     By default right-clicking (or single-finger tap-and-hold) on a morph | 
					
						
							|  |  |  |     also invokes its context menu (in addition to firing the | 
					
						
							|  |  |  |     mouseClickRight event). A morph's context menu can be customized by | 
					
						
							|  |  |  |     assigning a Menu instance to its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         customContextMenu | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property, or altogether suppressed by overriding its inherited | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         contextMenu() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (c) dragging: | 
					
						
							|  |  |  |     ------------- | 
					
						
							|  |  |  |     Dragging a morph is initiated when the left mouse button is pressed, | 
					
						
							|  |  |  |     held and the mouse is moved. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     You can control whether a morph is draggable by setting its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         isDraggable | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property either to false or true. If a morph isn't draggable itself | 
					
						
							|  |  |  |     it will pass the pick-up request up its owner chain. This lets you | 
					
						
							|  |  |  |     create draggable composite morphs like Windows, DialogBoxes, | 
					
						
							|  |  |  |     Sliders etc. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Sometimes it is desireable to make "template" shapes which cannot be | 
					
						
							|  |  |  |     moved themselves, but from which instead duplicates can be peeled | 
					
						
							|  |  |  |     off. This is especially useful for building blocks in construction | 
					
						
							|  |  |  |     kits, e.g. the MIT-Scratch palette. Morphic.js lets you control this | 
					
						
							|  |  |  |     functionality by setting the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         isTemplate | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property flag to true for any morph whose "isDraggable" property is | 
					
						
							|  |  |  |     turned off. When dragging such a Morph the hand will instead grab | 
					
						
							|  |  |  |     a duplicate of the template whose "isDraggable" flag is true and | 
					
						
							|  |  |  |     whose "isTemplate" flag is false, in other words: a non-template. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     When creating a copy from a template, the copy's | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         reactToTemplateCopy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     is invoked, if it is present. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Dragging is indicated by adding a drop shadow to the morph in hand. | 
					
						
							|  |  |  |     If a morph follows the hand without displaying a drop shadow it is | 
					
						
							|  |  |  |     merely being moved about without changing its parent (owner morph), | 
					
						
							|  |  |  |     e.g. when "dragging" a morph handle to resize its owner, or when | 
					
						
							|  |  |  |     "dragging" a slider button. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Right before a morph is picked up its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         prepareToBeGrabbed(handMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method is invoked, if it is present. Immediately after the pick-up | 
					
						
							|  |  |  |     the former parent's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToGrabOf(grabbedMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method is called, again only if it exists. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Similar to events, these  methods are optional and don't exist by | 
					
						
							|  |  |  |     default. For a simple example of how they can be used to adjust | 
					
						
							|  |  |  |     scroll bars in a scroll frame please have a look at their | 
					
						
							|  |  |  |     implementation in FrameMorph. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (d) dropping: | 
					
						
							|  |  |  |     ------------- | 
					
						
							|  |  |  |     Dropping is triggered when the left mouse button is either pressed | 
					
						
							|  |  |  |     or released while the Hand is dragging a morph. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Dropping a morph causes it to become embedded in a new owner morph. | 
					
						
							|  |  |  |     You can control this embedding behavior by setting the prospective | 
					
						
							|  |  |  |     drop target's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         acceptsDrops | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property to either true or false, or by overriding its inherited | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         wantsDropOf(aMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Right after a morph has been dropped its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         justDropped(handMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method is called, and its new parent's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToDropOf(droppedMorph, handMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method is invoked, again only if each method exists. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Similar to events, these  methods are optional and by default are | 
					
						
							|  |  |  |     not present in morphs by default (watch out for inheritance, | 
					
						
							|  |  |  |     though!). For a simple example of how they can be used to adjust | 
					
						
							|  |  |  |     scroll bars in a scroll frame please have a look at their | 
					
						
							|  |  |  |     implementation in FrameMorph. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Drops of image elements from outside the world canvas are dispatched as | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         droppedImage(aCanvas, name) | 
					
						
							|  |  |  |         droppedSVG(anImage, name) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     events to interested Morphs at the mouse pointer. If you want you Morph | 
					
						
							|  |  |  |     to e.g. import outside images you can add the droppedImage() and / or the | 
					
						
							|  |  |  |     droppedSVG() methods to it. The parameter passed to the event handles is | 
					
						
							|  |  |  |     a new offscreen canvas element representing a copy of the original image | 
					
						
							|  |  |  |     element which can be directly used, e.g. by assigning it to another | 
					
						
							|  |  |  |     Morph's image property. In the case of a dropped SVG it is an image | 
					
						
							|  |  |  |     element (not a canvas), which has to be rasterized onto a canvas before | 
					
						
							|  |  |  |     it can be used. The benefit of handling SVGs as image elements is that | 
					
						
							|  |  |  |     rasterization can be deferred until the destination scale is known, taking | 
					
						
							|  |  |  |     advantage of SVG's ability for smooth scaling. If instead SVGs are to be | 
					
						
							|  |  |  |     rasterized right away, you can set the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         MorphicPreferences.rasterizeSVGs | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     preference to <true>. In this case dropped SVGs also trigger the | 
					
						
							|  |  |  |     droppedImage() event with a canvas containing a rasterized version of the | 
					
						
							|  |  |  |     SVG. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     The same applies to drops of audio or text files from outside the world | 
					
						
							|  |  |  |     canvas. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Those are dispatched as | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         droppedAudio(anAudio, name) | 
					
						
							|  |  |  |         droppedText(aString, name) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     events to interested Morphs at the mouse pointer. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     if none of the above content types can be determined, the file contents | 
					
						
							|  |  |  |     is dispatched as an ArrayBuffer to interested Morphs: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         droppedBinary(anArrayBuffer, name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (e) keyboard events | 
					
						
							|  |  |  |     ------------------- | 
					
						
							|  |  |  |     The World dispatches the following key events to its active | 
					
						
							|  |  |  |     keyboardReceiver: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         keypress | 
					
						
							|  |  |  |         keydown | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  |         keyup | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Currently the only morph which acts as keyboard receiver is | 
					
						
							|  |  |  |     CursorMorph, the basic text editing widget. If you wish to add | 
					
						
							|  |  |  |     keyboard support to your morph you need to add event handling | 
					
						
							|  |  |  |     methods for | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         processKeyPress(event) | 
					
						
							|  |  |  |         processKeyDown(event) | 
					
						
							|  |  |  |         processKeyUp(event) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     and activate them by assigning your morph to the World's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         keyboardReceiver | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Note that processKeyUp() is optional and doesn't have to be present | 
					
						
							|  |  |  |     if your morph doesn't require it. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (f) resize event | 
					
						
							|  |  |  |     ---------------- | 
					
						
							|  |  |  |     The Window resize event is handled by the World and allows the | 
					
						
							|  |  |  |     World's extent to be adjusted so that it always completely fills | 
					
						
							|  |  |  |     the browser's visible page. You can turn off this default behavior | 
					
						
							|  |  |  |     by setting the World's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         useFillPage | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property to false. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Alternatively you can also initialize the World with the | 
					
						
							|  |  |  |     useFillPage switch turned off from the beginning by passing the | 
					
						
							|  |  |  |     false value as second parameter to the World's constructor: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         world = new World(aCanvas, false); | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Use this when creating a web page with multiple Worlds. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     if "useFillPage" is turned on the World dispatches an | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToWorldResize(newBounds) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     events to all of its children (toplevel only), allowing each to | 
					
						
							|  |  |  |     adjust to the new World bounds by implementing a corresponding | 
					
						
							|  |  |  |     method, the passed argument being the World's new dimensions after | 
					
						
							|  |  |  |     completing the resize. By default, the "reactToWorldResize" Method | 
					
						
							|  |  |  |     does not exist. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Example: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Add the following method to your Morph to let it automatically | 
					
						
							|  |  |  |     fill the whole World, but leave a 10 pixel border uncovered: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         MyMorph.prototype.reactToWorldResize = function (rect) { | 
					
						
							|  |  |  |             this.changed(); | 
					
						
							|  |  |  |             this.bounds = rect.insetBy(10); | 
					
						
							|  |  |  |             this.drawNew(); | 
					
						
							|  |  |  |             this.changed(); | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (g) combined mouse-keyboard events | 
					
						
							|  |  |  |     ---------------------------------- | 
					
						
							|  |  |  |     Occasionally you'll want an object to react differently to a mouse | 
					
						
							|  |  |  |     click or to some other mouse event while the user holds down a key | 
					
						
							|  |  |  |     on the keyboard. Such "shift-click", "ctl-click", or "alt-click" | 
					
						
							|  |  |  |     events can be implemented by querying the World's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         currentKey | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property inside the function that reacts to the mouse event. This | 
					
						
							|  |  |  |     property stores the keyCode of the key that's currently pressed. | 
					
						
							|  |  |  |     Once the key is released by the user it reverts to null. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (h) text editing events | 
					
						
							|  |  |  |     ----------------------- | 
					
						
							|  |  |  |     Much of Morphic's "liveliness" comes out of allowing text elements | 
					
						
							|  |  |  |     (instances of either single-lined StringMorph or multi-lined TextMorph) | 
					
						
							|  |  |  |     to be directly manipulated and edited by users. This requires other | 
					
						
							|  |  |  |     objects which may have an interest in the text element's state to react | 
					
						
							|  |  |  |     appropriately. Therefore text elements and their manipulators emit | 
					
						
							|  |  |  |     a stream of events, mostly by "bubbling" them up the text element's | 
					
						
							|  |  |  |     owner chain. Text elements' parents are notified about the following | 
					
						
							|  |  |  |     events: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Whenever the user presses a key on the keyboard while a text element | 
					
						
							|  |  |  |     is being edited, a | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToKeystroke(event) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     is escalated up its parent chain, the "event" parameter being the | 
					
						
							|  |  |  |     original one received by the World. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Once the user has completed the edit, the following events are | 
					
						
							|  |  |  |     dispatched: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         accept() - <enter> was pressed on a single line of text | 
					
						
							|  |  |  |         cancel() - <esc> was pressed on any text element | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Note that "accept" only gets triggered by single-line texte elements, | 
					
						
							|  |  |  |     as the <enter> key is used to insert line breaks in multi-line | 
					
						
							|  |  |  |     elements. Therefore, whenever a text edit is terminated by the user | 
					
						
							|  |  |  |     (accepted, cancelled or otherwise), | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToEdit(StringOrTextMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     is triggered. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     If the MorphicPreference's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         useSliderForInput | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     setting is turned on, a slider is popped up underneath the currently | 
					
						
							|  |  |  |     edited text element letting the user insert numbers out of the given | 
					
						
							|  |  |  |     slider range. Whenever this happens, i.e. whenever the slider is moved | 
					
						
							|  |  |  |     or while the slider button is pressed, a stream of | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         reactToSliderEdit(StringOrTextMorph) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     events is dispatched, allowing for "Bret-Victor" style "live coding" | 
					
						
							|  |  |  |     applications. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     In addition to user-initiated events text elements also emit | 
					
						
							|  |  |  |     change notifications to their direct parents whenever their drawNew() | 
					
						
							|  |  |  |     method is invoked. That way complex Morphs containing text elements | 
					
						
							|  |  |  |     get a chance to react if something about the embedded text has been | 
					
						
							|  |  |  |     modified programmatically. These events are: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         layoutChanged() - sent from instances of TextMorph | 
					
						
							|  |  |  |         fixLayout() - sent from instances of StringMorph | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     they are different so that Morphs which contain both multi-line and | 
					
						
							|  |  |  |     single-line text elements can hold them apart. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (4) stepping | 
					
						
							|  |  |  |     ------------ | 
					
						
							|  |  |  |     Stepping is what makes Morphic "magical". Two properties control | 
					
						
							|  |  |  |     a morph's stepping behavior: the fps attribute and the step() | 
					
						
							|  |  |  |     method. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     By default the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         step() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method does nothing. As you can see in the examples of BouncerMorph | 
					
						
							|  |  |  |     and MouseSensorMorph you can easily override this inherited method | 
					
						
							|  |  |  |     to suit your needs. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     By default the step() method is called once per display cycle. | 
					
						
							|  |  |  |     Depending on the number of actively stepping morphs and the | 
					
						
							|  |  |  |     complexity of your step() methods this can cause quite a strain on | 
					
						
							|  |  |  |     your CPU, and also result in your application behaving differently | 
					
						
							|  |  |  |     on slower computers than on fast ones. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     setting | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         myMorph.fps | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     to a number lower than the interval for the main loop lets you free | 
					
						
							|  |  |  |     system resources (albeit at the cost of a less responsive or slower | 
					
						
							|  |  |  |     behavior for this particular morph). | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (5) creating new kinds of morphs | 
					
						
							|  |  |  |     -------------------------------- | 
					
						
							|  |  |  |     The real fun begins when you start to create new kinds of morphs | 
					
						
							|  |  |  |     with customized shapes. Imagine, e.g. jigsaw puzzle pieces or | 
					
						
							|  |  |  |     musical notes. For this you have to override the default | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         drawNew() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     This method creates a new offscreen Canvas and stores it in | 
					
						
							|  |  |  |     the morph's | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         image | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Use the following template for a start: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         MyMorph.prototype.drawNew = function() { | 
					
						
							|  |  |  |             var context; | 
					
						
							|  |  |  |             this.image = newCanvas(this.extent()); | 
					
						
							|  |  |  |             context = this.image.getContext('2d'); | 
					
						
							|  |  |  |             // use context to paint stuff here | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     If your new morph stores or references to other morphs outside of | 
					
						
							|  |  |  |     the submorph tree in other properties, be sure to also override the | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     default | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |         updateReferences() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     method if you want it to support duplication. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (6) development and user modes | 
					
						
							|  |  |  |     ------------------------------ | 
					
						
							|  |  |  |     When working with Squeak on Scratch or BYOB among the features I | 
					
						
							|  |  |  |     like the best and use the most is inspecting what's going on in | 
					
						
							|  |  |  |     the World while it is up and running. That's what development mode | 
					
						
							|  |  |  |     is for (you could also call it debug mode). In essence development | 
					
						
							|  |  |  |     mode controls which context menu shows up. In user mode right | 
					
						
							|  |  |  |     clicking (or double finger tapping) a morph invokes its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         customContextMenu | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property, whereas in development mode only the general | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         developersMenu() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method is called and the resulting menu invoked. The developers' | 
					
						
							|  |  |  |     menu features Gui-Builder-wise functionality to directly inspect, | 
					
						
							|  |  |  |     take apart, reassamble and otherwise manipulate morphs and their | 
					
						
							|  |  |  |     contents. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Instead of using the "customContextMenu" property you can also | 
					
						
							|  |  |  |     assign a more dynamic contextMenu by overriding the general | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         userMenu() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method with a customized menu constructor. The difference between | 
					
						
							|  |  |  |     the customContextMenu property and the userMenu() method is that | 
					
						
							|  |  |  |     the former is also present in development mode and overrides the | 
					
						
							|  |  |  |     developersMenu() result. For an example of how to use the | 
					
						
							|  |  |  |     customContextMenu property have a look at TextMorph's evaluation | 
					
						
							|  |  |  |     menu, which is used for the Inspector's evaluation pane. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     When in development mode you can inspect every Morph's properties | 
					
						
							|  |  |  |     with the inspector, including all of its methods. The inspector | 
					
						
							|  |  |  |     also lets you add, remove and rename properties, and even edit | 
					
						
							|  |  |  |     their values at runtime. Like in a Smalltalk environment the inspect | 
					
						
							|  |  |  |     features an evaluation pane into which you can type in arbitrary | 
					
						
							|  |  |  |     JavaScript code and evaluate it in the context of the inspectee. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Use switching between user and development modes while you are | 
					
						
							|  |  |  |     developing an application and disable switching to development once | 
					
						
							|  |  |  |     you're done and deploying, because generally you don't want to | 
					
						
							|  |  |  |     confuse end-users with inspectors and meta-level stuff. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (7) turtle graphics | 
					
						
							|  |  |  |     ------------------- | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     The basic Morphic kernel features a simple LOGO turtle constructor | 
					
						
							|  |  |  |     called | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         PenMorph | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     which you can use to draw onto its parent Morph. By default every | 
					
						
							|  |  |  |     Morph in the system (including the World) is able to act as turtle | 
					
						
							|  |  |  |     canvas and can display pen trails. Pen trails will be lost whenever | 
					
						
							|  |  |  |     the trails morph (the pen's parent) performs a "drawNew()" | 
					
						
							|  |  |  |     operation. If you want to create your own pen trails canvas, you | 
					
						
							|  |  |  |     may wish to modify its | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         penTrails() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property, so that it keeps a separate offscreen canvas for pen | 
					
						
							|  |  |  |     trails (and doesn't loose these on redraw). | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     the following properties of PenMorph are relevant for turtle | 
					
						
							|  |  |  |     graphics: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         color        - a Color | 
					
						
							|  |  |  |         size        - line width of pen trails | 
					
						
							|  |  |  |         heading        - degrees | 
					
						
							|  |  |  |         isDown        - drawing state | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     the following commands can be used to actually draw something: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         up()        - lift the pen up, further movements leave no trails | 
					
						
							|  |  |  |         down()        - set down, further movements leave trails | 
					
						
							|  |  |  |         clear()        - remove all trails from the current parent | 
					
						
							|  |  |  |         forward(n)    - move n steps in the current direction (heading) | 
					
						
							|  |  |  |         turn(n)        - turn right n degrees | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Turtle graphics can best be explored interactively by creating a | 
					
						
							|  |  |  |     new PenMorph object and by manipulating it with the inspector | 
					
						
							|  |  |  |     widget. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     NOTE: PenMorph has a special optimization for recursive operations | 
					
						
							|  |  |  |     called | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         warp(function) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     You can significantly speed up recursive ops and increase the depth | 
					
						
							|  |  |  |     of recursion that's displayable by wrapping WARP around your | 
					
						
							|  |  |  |     recursive function call: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     example: | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         myPen.warp(function () { | 
					
						
							|  |  |  |             myPen.tree(12, 120, 20); | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     will be much faster than just invoking the tree function, because it | 
					
						
							|  |  |  |     prevents the parent's parent from keeping track of every single line | 
					
						
							|  |  |  |     segment and instead redraws the outcome in a single pass. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (8) damage list housekeeping | 
					
						
							|  |  |  |     ---------------------------- | 
					
						
							|  |  |  |     Morphic's progressive display update comes at the cost of having to | 
					
						
							|  |  |  |     cycle through a list of "broken rectangles" every display cycle. If | 
					
						
							|  |  |  |     this list gets very long working this damage list can lead to a | 
					
						
							|  |  |  |     seemingly dramatic slow-down of the Morphic system. Typically this | 
					
						
							|  |  |  |     occurs when updating the layout of complex Morphs with very many | 
					
						
							|  |  |  |     submorphs, e.g. when resizing an inspector window. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     An effective strategy to cope with this is to use the inherited | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         trackChanges | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     property of the Morph prototype for damage list housekeeping. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     The trackChanges property of the Morph prototype is a Boolean switch | 
					
						
							|  |  |  |     that determines whether the World's damage list ('broken' rectangles) | 
					
						
							|  |  |  |     tracks changes. By default the switch is always on. If set to false | 
					
						
							|  |  |  |     changes are not stored. This can be very useful for housekeeping of | 
					
						
							|  |  |  |     the damage list in situations where a large number of (sub-) morphs | 
					
						
							|  |  |  |     are changed more or less at once. Instead of keeping track of every | 
					
						
							|  |  |  |     single submorph's changes tremendous performance improvements can be | 
					
						
							|  |  |  |     achieved by setting the trackChanges flag to false before propagating | 
					
						
							|  |  |  |     the layout changes, setting it to true again and then storing the full | 
					
						
							|  |  |  |     bounds of the surrounding morph. An an example refer to the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         moveBy() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method of HandMorph, and to the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         fixLayout() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     method of InspectorMorph, or the | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |         startLayout() | 
					
						
							|  |  |  |         endLayout() | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     methods of SyntaxElementMorph in the Snap application. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     (9) minifying morphic.js | 
					
						
							|  |  |  |     ------------------------ | 
					
						
							|  |  |  |     Coming from Smalltalk and being a Squeaker at heart I am a huge fan | 
					
						
							|  |  |  |     of browsing the code itself to make sense of it. Therefore I have | 
					
						
							|  |  |  |     included this documentation and (too little) inline comments so all | 
					
						
							|  |  |  |     you need to get going is this very file. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Nowadays with live streaming HD video even on mobile phones 250 KB | 
					
						
							|  |  |  |     shouldn't be a big strain on bandwith, still minifying and even | 
					
						
							|  |  |  |     compressing morphic.js down do about 100 KB may sometimes improve | 
					
						
							|  |  |  |     performance in production use. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Being an attorney-at-law myself you programmer folk keep harassing | 
					
						
							|  |  |  |     me with rabulistic nitpickings about free software licenses. I'm | 
					
						
							|  |  |  |     releasing morphic.js under an AGPL license. Therefore please make | 
					
						
							|  |  |  |     sure to adhere to that license in any minified or compressed version. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     VIII. acknowledgements | 
					
						
							|  |  |  |     ---------------------- | 
					
						
							|  |  |  |     The original Morphic was designed and written by Randy Smith and | 
					
						
							|  |  |  |     John Maloney for the SELF programming language, and later ported to | 
					
						
							|  |  |  |     Squeak (Smalltalk) by John Maloney and Dan Ingalls, who has also | 
					
						
							|  |  |  |     ported it to JavaScript (the Lively Kernel), once again setting | 
					
						
							|  |  |  |     a "Gold Standard" for self sustaining systems which morphic.js | 
					
						
							|  |  |  |     cannot and does not aspire to meet. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     This Morphic implementation for JavaScript is not a direct port of | 
					
						
							|  |  |  |     Squeak's Morphic, but still many individual functions have been | 
					
						
							|  |  |  |     ported almost literally from Squeak, sometimes even including their | 
					
						
							|  |  |  |     comments, e.g. the morph duplication mechanism fullCopy(). Squeak | 
					
						
							|  |  |  |     has been a treasure trove, and if morphic.js looks, feels and | 
					
						
							|  |  |  |     smells a lot like Squeak, I'll take it as a compliment. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Evelyn Eastmond has inspired and encouraged me with her wonderful | 
					
						
							|  |  |  |     implementation of DesignBlocksJS. Thanks for sharing code, ideas | 
					
						
							|  |  |  |     and enthusiasm for programming. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     John Maloney has been my mentor and my source of inspiration for | 
					
						
							|  |  |  |     these Morphic experiments. Thanks for the critique, the suggestions | 
					
						
							|  |  |  |     and explanations for all things Morphic and for being my all time | 
					
						
							|  |  |  |     programming hero. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     I have originally written morphic.js in Florian Balmer's Notepad2 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     editor for Windows, later switched to Apple's Dashcode and later | 
					
						
							|  |  |  |     still to Apple's Xcode. I've also come to depend on both Douglas | 
					
						
							|  |  |  |     Crockford's JSLint, Mozilla's Firebug and Google's Chrome to get | 
					
						
							|  |  |  |     it right. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     IX. contributors | 
					
						
							|  |  |  |     ---------------------- | 
					
						
							|  |  |  |     Joe Otto found and fixed many early bugs and taught me some tricks. | 
					
						
							|  |  |  |     Nathan Dinsmore contributed mouse wheel scrolling, cached | 
					
						
							| 
									
										
										
										
											2015-06-26 11:04:27 +00:00
										 |  |  |     background texture handling, countless bug fixes and optimizations. | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     Ian Reynolds contributed backspace key handling for Chrome. | 
					
						
							|  |  |  |     Davide Della Casa contributed performance optimizations for Firefox. | 
					
						
							| 
									
										
										
										
											2015-12-21 15:06:47 +00:00
										 |  |  |     Jason N (@cyderize) contributed native copy & paste for text editing. | 
					
						
							| 
									
										
										
										
											2013-04-09 02:15:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-21 18:40:24 +00:00
										 |  |  |     - Jens Mönig |