Copyright 2017-2023 Moddable Tech, Inc.
Revised: August 31, 2023
Piu is a user interface framework designed to run on microcontrollers. The programming interface to Piu is a JavaScript API of global constructors, functions, and objects that define the containment hierarchy, appearance, behavior, and flow of applications. This document provides details on the objects that define the Piu API and important related concepts.
Figure 1 summarizes the inheritance hierarchy for the objects described in this document.
Figure 1. Piu Inheritance Hierarchy
The basic relationship between these objects in the context of a Piu application is as follows:
- Graphical parts of the user interface are all
content
objects
-
skin
, style
, and texture
objects customize the look (colors, fonts, etc.) of content
objects
-
behavior
objects are bound to content
objects to handle events
-
timeline
and transition
objects animate content
objects
Introduction to Important Concepts
This section explains important concepts related to Piu applications and defines some of the terms used throughout the rest of this document.
Containment Hierarchy and Appearance
The graphical user interface elements of Piu applications are composed of a hierarchy of content
objects. The basic structure is as follows:
- The
application
object is the root of the containment hierarchy
-
container
objects are branches of the containment hierarchy
-
content
objects are leaves of the containment hierarchy
Applications use constructors to define content
and container
objects. These objects are attached to the containment hierarchy using the add
, insert
, and replace
functions, and are removed from the containment hierarchy using the remove
and replace
functions. See Functions in the section Container Object for descriptions of these properties.
Bound and Unbound Contents
Contents that are not attached to the containment hierarchy are called unbound contents; contents attached to the containment hierarchy, bound contents. Only objects that are part of the containment hierarchy appear on screen.
Unbound contents do not participate in layout. They are neither measured nor fitted; consequently, their position and size are undefined
and cannot be changed.
let content = new Content();
let before = content.position; // undefined
application.add(content);
let after = content.position; // {x: 160, y:120} (assuming the application is 320x240)
The coordinates of an object define implicit constraints on its position and size.
For example, centered content and contents whose sizes/position are dependent on their container's size/position cannot move.
// Cannot move
let centeredContent = new Content(null, {
width: 10, height: 10
});
let dependentOnContainerContent = new Content(null, {
top: 0, left: 0, bottom: 100, right: 100,
});
// Can move
let unconstrainedContent = new Content(null, {
top: 0, left: 0, height: 100, width: 100
});
All contents have a measured width and measured height, which are the default width and height computed by the content itself. For example, the measured width of the following content object will be 100.
let sampleContent = new Content(null, {
width: 100
});
The measured width of the following content will be 0, because the content has no default width.
let sampleContent = new Content(null, {
left: 0, right: 0
});
The coordinates
property of a content
object reflect the content's measured size. This property can be changed at any time.
sampleContent.coordinates = {
left: 0,
width: 100,
top: 0,
height: 100
};
All contents also have a fitted width and fitted height, which are the effective width and height of the content computed by its container.
If both left
and right
coordinates are defined, the content stretches horizontally with its container, and the fitted width of the content depends on the fitted width of its container. Similarly, if both top
and bottom
coordinates are defined, the content stretches vertically with its container, and the fitted height of the content depends on the fitted height of its container. For example, the fitted width and fitted height of the sampleContent
object here will both be 100.
let sampleContent = new Content(null, {
left: 0, right: 0
});
let sampleContainer = new Container(null, {
height: 100, width: 100,
contents: [
sampleContent
]
});
If a left
or right
coordinate (but not both) is defined, or if neither left
nor right
is defined, the fitted width equals the measured width. Similarly, if a top
or bottom
coordinate (but not both) is defined, or if neither top
nor bottom
is defined, the fitted width equals the measured height. For example, the fitted width and fitted height of the sampleContent
object here will both be 50.
let sampleContent = new Content(null, {
left: 0, top: 0, width: 50, height: 50
});
let sampleContainer = new Container(null, {
height: 100, width: 100,
contents: [
sampleContent
]
});
The width
and height
properties of a content
object reflect the content's fitted size. A content's measured width and height are available immediately after the content is created; the fitted width and height are not available until its onDisplaying
event has been triggered.
let sampleContent = new Content(null, {
left: 0, right: 0, top: 0, height: 50,
Behavior: class extends Behavior {
onCreate(content) {
let measuredHeight = content.coordinates.height; // 50
let measuredWidth = content.coordinates.width; // undefined
let fittedWidth = content.width; // undefined
let fittedHeight = content.height; // 50
}
onDisplaying(content) {
let fittedWidth = content.width; // 320 (assuming the application is 320x240)
let fittedHeight = content.height; // 50
}
}
});
application.add(sampleContent)
Templates are a tool that reduce the script code needed to instantiate contents and build the containment hierarchy. Templates are often used to create objects that are similar, but have a few slightly different properties.
For example, consider the following screens:
The code for these screens without templates is unnecessarily repetitive. The only difference between screen1
and screen2
here is the header background color and string.
let screen1 = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "blue" }), style: sampleStyle,
contents: [
Label(null, {
top: 0, height: 40, left: 0, right: 0,
string: "Screen 1"
}),
Content(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" })
}),
]
});
let screen2 = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "red" }), style: sampleStyle,
contents: [
Label(null, {
top: 0, height: 40, left: 0, right: 0,
string: "Screen 2"
}),
Content(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" })
}),
]
});
Using templates significantly reduces the amount of code needed to define the two screens.
let BasicScreen = Column.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: $.headerColor }), style: sampleStyle,
contents: [
Label(null, {
top: 0, height: 40, left: 0, right: 0,
string: $.title
}),
Content(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" })
}),
]
}));
let screen1 = new BasicScreen({ title: "Screen 1", headerColor: "blue" });
let screen2 = new BasicScreen({ title: "Screen 2", headerColor: "red" });
As seen in the example above, the constructor has one parameter, $
, which applications use to pass data to the template. The data may have any prototype; it is often a string
, number
, or JSON object. In their attributes, content
and container
objects use $
to access data properties. The $
parameter is referred to as “the data” or “the instantiating data.”
The template
function for most Piu objects returns a constructor and a template
function; the only exceptions are the Skin
and Texture
objects, which simply return constructors. These template
functions allow constructors to be further specialized. In the example below, a HeaderWithBehavior
instance would have all the properties of a BasicHeader
instance in addition to being active and having a behavior.
let headerStyle = new Style({ font:"600 28px Open Sans", color: "white", horizontal: "left" });
let headerSkin = new Skin({ fill: "blue" });
let BasicHeader = Label.template($ => ({
top: 0, height: 40, left: 0, right: 0,
skin: headerSkin, style: headerStyle, string: $
}));
class HeaderBehavior extends Behavior {
onTouchEnded(header) {
trace("Header tapped\n");
}
}
let HeaderWithBehavior = BasicHeader.template($ => ({
active: true, Behavior: HeaderBehavior
}));
Piu delivers events to the containment hierarchy of applications, and content
objects can reference behavior
objects, which contain functions that respond to events. Piu uses events extensively.
When a content
object receives an event, it checks whether its behavior
object has a corresponding function to respond to that event (either directly or indirectly in its prototype chain). If it does, the content
object calls the function, passing itself as the first parameter. If it does not, nothing happens.
Piu defines low-level events that are useful on a wide range of target devices. For example, onTouchBegan
and onTouchEnded
are useful for target devices with touch screens.
Applications can also define their own higher-level events. To help efficiently implement common event propagation patterns, contents have delegate
, distribute
, bubble
, firstThat
, and lastThat
properties. See Functions in the section Content Object for descriptions of these properties.
There are multiple ways to create time-based animation behaviors. One way is to use content
objects as clocks, as described in the Duration, Fraction, Interval, Loop, and Time section of this document. This method is commonly used to animate a single content in response to events (to show touch feedback, for example) and to animate a single content for long periods of time.
The simplest way to create complex behaviors that animate several contents or properties is using the timeline
object. The timeline
object provides a mechanism for sequencing and running a collection of tweens, making it the best method for staggered animations of multiple content objects (to transition graphical elements of a screen in and out, for example). For more information, see the Timeline Object section of this document.
Piu transition
objects are best for simple animations to move between screens or swap content objects. They often modify the containment hierarchy by adding or removing contents. They can also modify properties of objects as timeline
objects do, but creating a sequence of animations is more complicated. For more information, see the Transition Object section of this document.
Animations that linearly modify the properties of content objects often appear awkward. Using easing equations is a common way to implement animations that feel more natural.
Piu extends the JavaScript Math
object with Robert Penner’s open source easing equations (see the Easing section of Robert Penner’s Programming Macromedia Flash MX). The source code is in piuTransition.c
.
The Piu implementations of these easing equations all take a single argument: a number
in the range [0, 1]. The return value is a number
in the range [0, 1] that maps the input to the eased output. These equations are used extensively in all types of animations. They are commonly used to map the fraction
property of content
objects or the fraction
argument of a transition
object's onStep
function, and as an argument to many timeline
object functions.
Properties of the Piu global object can be used anywhere in an application.
Arguments |
Type |
Description |
string |
string |
The string to trace |
Traces the specified string in the virtual machine of the hosted application.
Note: Strings will not be traced until a line break ("\n") has also been traced.
trace("Hello world\n");
let sampleVariable = 2;
trace(`sampleVariable value is: ${sampleVariable}\n`); // "sampleVariable value is 2"
Adding Additional Properties
Additional properites can be added by setting a property of the global object.
global.application = new Application(null, {
displayListLength: 2048, commandListLength: 2048
});
export default global.application;
Descriptions of Properties
This section provides descriptions of select properties referenced throughout the Piu Object Reference section below.
Each content
object can have an optional anchor
property. When the template is instantiated, a reference to the created content
object is assigned to a property of the instantiating data; the identifier of the property is the value of the anchor
property.
Anchors allow applications to directly access specific contents and containers in a containment hierarchy instantiated from a template. This can make it easier to access objects to modify while the application is running—for example, to change the label of a string, disable a button, or add lines to a column in a table.
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "white" });
let SampleContent = Label.template($ => ({
anchor: "ANCHORED_CONTENT", top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: $.color }), style: sampleStyle,
string: $.title
}));
let SampleContainer = Container.template($ => ({
active: true, top: 0, bottom: 0, left: 0, right: 0,
contents: [
new SampleContent($)
],
Behavior: class extends Behavior {
onCreate(container, data) {
this.data = data;
}
onTouchEnded(container) {
this.data["ANCHORED_CONTENT"].string = "Hello!"
}
}
}));
application.add(new SampleContainer({ title: "Tap to update", color: "blue" }));
A color
parameter can be passed into the dictionaries of skin
and style
constructors.
To specify a color, you can use CSS names (Level 2) or hexadecimal notations ("#RGB"
, "#RGBA"
, "#RRGGBB"
, "#RRGGBBAA"
):
const whiteSkin = new Skin({ fill:"white" });
const redSkin = new Skin({ fill:"#F00" });
const halfRedSkin = new Skin({ fill:"#F008" });
const greenSkin = new Skin({ fill:"#00FF00" });
const halfGreenSkin = new Skin({ fill:"#00FF0088" });
To specify a color with an alpha channel, you can also use a mere hexadecimal number 0xRRGGBBAA
:
const blueSkin = new Skin({ fill:0x0000FFFF });
const halfBlueSkin = new Skin({ fill:0x0000FF88 });
To build such hexadecimal numbers, Piu exports functions similar to the CSS functional notations:
import { rgb, rgba, hsl, hsla } from "piu/All";
const yellowSkin = new Skin({ fill:rgb(255, 255, 0) });
const halfYellowSkin = new Skin({ fill:rgba(255, 255, 0, 0.5) });
const cyanSkin = new Skin({ fill:hsl(180, 1, 0.5) });
const halfCyanSkin = new Skin({ fill:hsla(180, 1, 0.5, 0.5) });
In dictionaries, colors can be a single color or an array of 2, 3, or 4 colors. The skin
and style
objects blend a color based on the state of the content
object that uses them. See Variant, Variants, State, and States for more information.
All content
objects have a coordinates
property. The coordinates property is an object with left
, width
, right
, top
, height
, and bottom
properties, all of which can be undefined
. The coordinates of contents determine their position and size relative to their container and their previous
and next
properties (other content
objects in the same container).
When a content's container is an application
, container
, scroller
, or layout
object:
-
top
, bottom
, left
, and right
coordinates are all relative to their container
- If
width
, left
, and right
coordinates are all specified, the left
and right
coordinates will be overruled
- If
left
and right
are both unspecified, the content will be centered horizontally in its container with the width specified (or a width of 0, if unspecified)
- If
height
, top
, and bottom
coordinates are all specified, the top
and bottom
coordinates will be overruled
- If
top
and bottom
are both unspecified, the content will be centered vertically in its container with the height specified (or a height of 0, if unspecified)
When a content's container is a column
object:
-
top
and bottom
coordinates are relative to their previous
and next
properties
-
left
and right
coordinates are relative to their container
- If
width
, left
, and right
coordinates are all specified, the left
and right
coordinates will be overruled
When a content's container is a row
object:
-
left
and right
coordinates are relative to their previous
and next
properties
-
top
and bottom
coordinates are relative to their container
- If
height
, top
, and bottom
coordinates are all specified, the top
and bottom
coordinates will be overruled
Duration, Fraction, Interval, Loop, and Time
Every content in the containment hierarchy can be used as a clock to control time-based animation behaviors using its duration
, fraction
, interval
, and time
properties.
- The
duration
property is the duration of the animation, expressed in milliseconds.
- The
time
property provides the current time of the content’s clock.
- The
fraction
property is the ratio of the clock’s current time to the content’s duration.
- The
interval
property is the time between frames (frame rate) of the animation, expressed in milliseconds.
The content’s start
and stop
functions control when the clock is running. The clock is automatically stopped when its current time reaches its duration. If the content's loop
property is set to true, the clock will restart.
When a clock is running, the onTimeChanged
function of its content is triggered at the interval specified by the content's interval
property. When the content's time is equal to its duration, the onFinished
function is triggered.
let animatedContent = new Content(null, {
height: 100, width: 100, loop: true,
skin: new Skin({ fill: ["red", "yellow", "blue"] }),
Behavior: class extends Behavior {
onCreate(content) {
this.startAnimation(content);
}
startAnimation(content) {
content.duration = 3000;
content.time = 0;
content.start();
}
onTimeChanged(content) {
content.state = content.fraction*2;
}
}
});
application.add(animatedContent);
The interval
property sets the desired frame rate for an object's clock, but be aware that it may not be exact if the application is overloaded. It is not safe to assume, for instance, that if a content's interval
is 2 and its duration
is 100 that it will trigger the onTimeChanged
event exactly 50 times before it triggers the onFinished
event. Therefore, it is recommended that applications use the fraction
or time
properties to determine which frame to display for animations.
For example, consider two implementations of a button that expands and contracts 10 pixels in both directions when tapped.
The following implementation is not recommended, as it assumes that onTimeChanged
will be triggered exactly 20 times before onFinished
. While this may work most of the time, it is possible that the content will trigger its onFinished
event before it shrinks down to its original size.
class ExpandingBehavior extends Behavior {
onTouchEnded(content) {
this.index = 0;
content.interval = 5;
content.duration = 100;
content.time = 0;
content.start();
}
onTimeChanged(content) {
this.index++;
if (this.index < 10) content.sizeBy(1, 1);
else content.sizeBy(-1, -1);
}
}
let expandingButton = new Content(null, {
active: true, height: 50, width: 100,
skin: new Skin({ fill: "blue" }),
Behavior: ExpandingBehavior
});
The following implementation is better because it makes no assumptions about the number of frames that will draw and ensures that the content shrinks down to the correct size when onFinished
is called.
class ExpandingBehavior extends Behavior {
onTouchEnded(content) {
this.startingSize = { h: content.height, w: content.width };
content.interval = 5;
content.duration = 100;
content.time = 0;
content.start();
}
onTimeChanged(content) {
let startingSize = this.startingSize;
let fraction = content.fraction;
if (fraction > 0.5) fraction = 1-fraction;
fraction *= 20;
content.height = startingSize.h + fraction;
content.width = startingSize.w + fraction;
}
onFinished(content) {
let startingSize = this.startingSize;
content.height = startingSize.h;
content.width = startingSize.w;
}
}
let expandingButton = new Content(null, {
active: true, height: 50, width: 100,
skin: new Skin({ fill: "blue" }),
Behavior: ExpandingBehavior
});
A font
parameter must be passed into the dictionary of style
constructors.
Piu uses bitmap fonts. The metrics are provided by binary FNT files, the glyphs are provided by PNG files.
Fonts are assets and must be defined in the resources of your manifest. Use the default target or the -alpha
or -color
pseudo targets for fonts.
The binary FNT file format was defined by
AngelCode, which also released the BMFont generator on Windows. On Mac you can for instance use Glyph Designer or bmGlyph to generate such files.
One bitmap font corresponds to one style, one weight, one stretch, one size and one family. You will need separate bitmap fonts for each variation.
The Style
constructor uses the font
property of its dictionary to lookup its font. You can just set the font
property to the name of a binary FNT file:
const popStyle = new Style({ font:"popFont" });
The popStyle
object will use the popFont.fnt
file in your assets.
The lookup happens only when label
or text
objects that use the style are bound to the displayed containment hierarchy, or when the Style.prototype.measure
method is called.
In order to cascade styles, you may want to use something similar to the CSS font shortcut. Note that if you use this method of defining fonts in an application, you should not define other fonts in the application using just the font name as described above.
const style = new Style({ font:"italic bold 16px Open Sans" });
In Piu, the font property has five optional parts, in that order:
- style:
italic
| normal
| inherit
- weight:
100
| ultralight
| 200
| thin
| 300
| light
| 400
| normal
| 500
| medium
| 600
| semibold
| 700
| bold
| 800
| heavy
| 900
| black
| lighter
| bolder
| inherit
- stretch:
condensed
| normal
| inherit
- size:
xx-small
| x-small
| small
| medium
| large
| x-large
| xx-large
| smaller
| larger
| [1-9][0-9]+px
| [1-9][0-9]+%
| inherit
- family: the rest of the font property if any.
The inherit
value is the default value and is useful only to disambiguate a font property. By default the style of a content
object inherits the style of its container
objects.
All parts are optional and are cascaded separately. So you can for instance define a generic style for the application and specific styles for its contents:
const appStyle = new Style({ font:"16px Fira Sans" });
const menuStyle = new Style({ font:"bold" });
Styles are only cascaded when label
or text
objects that use them are bound to the displayed containment hierarchy.
For Piu to find the corresponding bitmap font files in your assets, you have to adopt the following convention, based on common practices:
- the family, without spaces,
-
-
,
- the capitalized name of the stretch, if not
normal
,
- the capitalized name of the computed weight, if not
normal
,
- the capitalized name of the style, if not
normal
,
-
Regular
, if the stretch, the computed weight and the style are all normal
,
-
-
,
- the computed size in pixels without units.
Here above style
will look for OpenSans-BoldItalic-16.fnt
, appStyle
will look for FiraSans-Regular-16.fnt
and menuStyle
will look for FiraSans-Bold-16.fnt
.
Applications can tile skins using their tiles
property. The size of the tiles is determined by left, right, top, and bottom values, as follows:
- If the
tiles
property is undefined or if its left
, right
, top
and bottom
values are all undefined, the skin is just an image, for instance an icon.
- Else if only the
left
or right
values are defined, the skin becomes a horizontal 3-part pattern. The left part is drawn at the left of the content, the right part is drawn at the right of the content, and the center part is repeated to fill the center of the content.
- Else if only the
top
or bottom
values are defined, the skin becomes a vertical 3-part pattern. The top part is drawn at the top of the content, the bottom part is drawn at the bottom of the content, and the middle part is repeated to fill the middle of the content.
- Else the skin becomes a 9-part pattern. Corner parts are drawn in the corresponding corners of the content, side parts are repeated in the sides, and the middle part is repeated to fill the middle. The
left
, right
, top
and bottom
values can all be defined to 0 to fill the content with the skin.
Tiling skins allows content objects of different sizes to share a single asset. Here is an example that uses this 30x30 pixel background to fill arbitrarily sized contents.
let roundedRectangleTexture = new Texture("roundedRectangle.png");
let roundedRectangleSkin = new Skin({
texture: roundedRectangleTexture,
x: 0, y: 0, width: 30, height: 30,
tiles: { left: 5, right: 5, top: 5, bottom: 5 }
});
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "white" });
let smallText = new Label(null, {
skin: roundedRectangleSkin, top: 20, left: 20, height: 30, width: 30,
style: sampleStyle, string: "Hi"
});
let bigText = new Text(null, {
skin: roundedRectangleSkin, top: 70, left: 20, height: 120, width: 100,
style: sampleStyle, string: "This is a long string"
});
application.add(smallText);
application.add(bigText);
Variant, Variants, State, and States
Applications often use the state
and variant
properties of content
objects to update their appearance. Because they can change dynamically, they can be used to animate content
objects and provide visual feedback to touch events, for example.
A common way that the state
property is used is to update the color of contents. As described in the Color section of this document, the fill
property of a skin
or style
object can be an array of colors. The state
property of a content
object using the skin
determines the index of the array. If the state is not an integer, colors from surrounding states are blended.
let multiColoredSkin = new Skin({ fill: ["black", "white", "red"] });
let blackContent = new Content(null, {
top: 20, left: 20, width: 80, height: 80,
skin: multiColoredSkin, state: 0,
});
let redContent = new Content(null, {
top: 20, left: 120, width: 80, height: 80,
skin: multiColoredSkin, state: 2
});
let grayContent = new Content(null, {
top: 20, left: 220, width: 80, height: 80,
skin: multiColoredSkin, state: 0.5
});
application.add(blackContent);
application.add(redContent);
application.add(grayContent);
It is often convenient to store several icons or other user interface elements in a single image. Specifying states
and variants
properties in the dictionary of skin
constructors enables you to reference different sections of the same texture. This prevents an application from having to reference similar images and create multiple skins.
The states
and variants
properties of a skin are numerical values used to define the size of a single element in the texture. The states
property represents the vertical offset between states, and the variants
property represents the horizontal offset between variants. Here is an example of an asset that includes ten 28x28 pixel icons in one image, and a skin
that will allow applications to reference each icon separately.
const wiFiStripTexture = new Texture({ path:"wifi-strip.png" });
const wiFiSkin = new Skin({
texture: wiFiStripTexture,
width: 28, height: 28,
states: 28, variants: 28
});
The states
and variants
properties of texture
objects should not be confused with the state
and variant
properties of content
objects, although they are related. The state
and variant
of a content
object are used to select which area of their skin
to render. Here is a visualization of the state
and variant
properties a content
would use to reference different portions of the skin
object from the last example.
The state
and variant
of a content
can be updated at any time. This is often done when an event is triggered.
let WiFiStatusIcon = Content.template($ => ({
skin: wiFiSkin, state: $.passwordProtected, variant: 0,
interval: 500, duration: 2500, loop: true,
active: true,
Behavior: class extends Behavior {
onDisplaying(content) {
content.start();
}
onTimeChanged(content) {
let variant = content.variant;
variant++;
if (variant > 4) variant = 0;
content.variant = variant;
}
}
}));
application.add(new WiFiStatusIcon({ passwordProtected: false }, { top: 20, right: 20 }));
application.add(new WiFiStatusIcon({ passwordProtected: true }, { top: 58, right: 20 }));
This section provides details on the objects that define the Piu API. For each object, the following information is presented if relevant:
-
Source Code: A link to the source code for the object
-
Relevant Examples: Links to example apps that demonstrate how to use the object
-
Constructor Description: A description of the object's constructor(s)
-
Dictionary: Present when additional information is needed regarding the dictionary passed to the object's dictionary-based constructor; describes the properties that the dictionary may contain. Dictionary parameters set properties having the same name (unless noted otherwise) in the created instance.
-
Prototype Description: The prototype from which this object's prototype inherits and descriptions of any properties and functions specific to this object's prototype
-
Events: Descriptions of the events that the object triggers
For the complete JavaScript programming interface, see piuAll.js
.
All Piu applications must have an application
object at the root of their containment hierarchy. All other content
objects must be added to the application
to appear on screen.
There is no default object, so you have to create one yourself and export it in the main module.
export default new Application();
Alternatively, you can export a function that returns an application
object.
export default function() {
return new Application();
}
Application([behaviorData, dictionary])
Arguments |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this container's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns an application
instance, an object that inherits from Container.prototype
.
export default new Application(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "blue" }),
});
Application.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Application.prototype
. The prototype
property of the result is Application.prototype
. The result also provides a template
function.
// Taken from the balls example app
...
let BallApplication = Application.template($ => ({
skin:backgroundSkin,
contents: [
Content(6, { left:0, top:0, skin:ballSkin, variant:0, Behavior: BallBehavior } ),
Content(5, { right:0, top:0, skin:ballSkin, variant:1, Behavior: BallBehavior } ),
Content(4, { right:0, bottom:0, skin:ballSkin, variant:2, Behavior: BallBehavior } ),
Content(3, { left:0, bottom:0, skin:ballSkin, variant:3, Behavior: BallBehavior } ),
]
}));
export default new BallApplication(null, { displayListLength:4096, touchCount:0 });
Same as for container
object (see Dictionary in the section Container Object), plus:
Parameter |
Type |
Description |
commandListLength |
number |
The size of the command list buffer in bytes used for holding Piu drawing operations |
displayListLength |
number |
The size of the display list buffer in bytes for targets using the Poco rendering engine |
touchCount |
number |
The number of touch events that can trigger at the same time |
Prototype inherits from Container.prototype
.
The behavior
object contains functions corresponding to events triggered by a content
object. A content
object checks whether its behavior owns or inherits a function property with the name of the event, and if so calls that function, passing itself as the first parameter.
Applications define their own constructors for behavior
objects, which inherit from Behavior.prototype
and assign them to content
objects when they are constructed. When a content
object is constructed, it creates an instance of the behavior class assigned to it and triggers the behavior's onCreate
event. This function does nothing by default; a behavior can use it to initialize its properties, for example.
class SampleBehavior extends Behavior {
onCreate(content, data) {
this.name = data.name;
}
onTouchEnded(content) {
trace(`Name is: ${this.name}\n`); // "Name is: Moddable"
}
}
let sampleContent = new Content({ name: "Moddable" }, {
active: true, height: 100, width: 100,
skin: new Skin({fill: "blue"}),
Behavior: SampleBehavior
});
application.add(sampleContent);
Prototype inherits from Object.prototype
.
The column
object is a container
object that arranges its contents vertically.
Column([behaviorData, dictionary])
Arguments |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. The dictionary is the same as for the content object. Only parameters specified in the Dictionary section of the Content Object will have an effect; other parameters will be ignored. |
Returns a column
instance, an object that inherits from Column .prototype
let ColoredSquare = Content.template($ => ({
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: $ })
}));
let sampleColumn = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
contents: [
new ColoredSquare("red"),
new ColoredSquare("blue"),
new ColoredSquare("black"),
]
});
application.add(sampleColumn);
Column.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Column.prototype
. The prototype
property of the result is Column.prototype
. The result also provides a template
function.
let ColoredSquare = Content.template($ => ({
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: $ })
}));
let SampleColumn = Column.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
contents: [
new ColoredSquare($.firstColor),
new ColoredSquare($.secondColor),
],
}));
application.add(new SampleColumn({ firstColor:"red", secondColor:"blue" }));
Prototype inherits from Container.prototype
.
Same as for container
object (see Events in the section Container Object)
The container
object is a content
object that can contain other content
objects. In a container, content
objects are stored in a doubly linked list. The content
objects can also be accessed by index or by name using the content
property, for instance container.content(0)
or container.content("foo")
.
Container([behaviorData, dictionary])
Arguments |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this container's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result.Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a container
instance, an object that inherits from Container.prototype
.
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
contents: [
new ColoredSquare("blue", { left: 0, top: 0 }),
new ColoredSquare("red", { right: 0, top: 50 }),
new ColoredSquare("black", { left: 100, bottom: 0 }),
]
})
application.add(sampleContainer);
Container.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Container.prototype
. The prototype
property of the result is Container.prototype
. The result also provides a template
function.
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let SampleContainer = Container.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: $.backgroundColor }),
contents: [
new ColoredSquare( $.squareColor ),
]
}));
application.add(new SampleContainer({ backgroundColor: "white", squareColor: "blue" }));
Same as for content
object (see Dictionary in the section Content Object), plus:
Parameter |
Type |
Description |
clip |
boolean |
If true , this container will clip its contents. |
Prototype inherits from Content.prototype
.
Same as for content
object (see Properties in the section Content Object), plus:
Name |
Type |
Default Value |
Read Only |
Description |
clip |
boolean |
false |
|
If true , this container clips its contents. |
first |
object |
|
✓ |
The first content object in this container, or null if this container is empty |
last |
object |
|
✓ |
The last content object in this container, or null if this container is empty |
length |
number |
|
✓ |
The number of content objects in this container |
transitioning |
boolean |
false |
✓ |
If true , this container is running a transition object. |
add(content)
Argument |
Type |
Description |
content |
content |
The content object to add. It must be unbound; that is, its container must be null . |
Adds the specified content
object to this container. The content
object becomes the last content
object in this container.
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
});
sampleContainer.add(new ColoredSquare("black", {bottom: 10, left: 15}));
sampleContainer.add(new ColoredSquare("blue", {left: 100}));
sampleContainer.add(new ColoredSquare("green", {top: 10, left: 10}));
application.add(sampleContainer);
content(at)
Argument |
Type |
Description |
at |
number or string
|
The index or name property of the content object you want to access |
Returns the specified content
object, or undefined
if no content with the index
or name
specified is in this container
let sampleContainer = new Container(null, {
contents: [
new Content(null, { name: "Moddable" }),
new Content(),
]
});
let namedContent = sampleContainer.content("Moddable");
let unnamedContent = sampleContainer.content(1);
let nonexistentContent = sampleContainer.content("Nonexistent"); // undefined
empty([start, stop])
Argument |
Type |
Description |
start |
number |
The starting index |
stop |
number |
The stopping index (this.length by default) |
Removes content
objects from this container, starting at index start
and stopping at index stop
. If start
or stop
is less than 0, it is an offset from this.length
.
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
new ColoredSquare("blue", { top: 0, left:0 }),
new ColoredSquare("red", { top: 0, right: 0 })
]
});
sampleContainer.empty();
application.add(sampleContainer);
firstThat(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event to trigger |
... |
* |
Zero or more extra parameters |
Causes all content
objects in this container to trigger an event named by the value of id
. The order of traversal is from the first to the last. Traversal halts when a distributed event returns true
. Note that the first parameter of a distributed event is the content
object that triggers the event, not this container. Additional parameters, if any, of the event are the extra parameters of the firstThat
function.
class SampleBehavior extends Behavior {
sampleEvent(content) {
trace(content.name+" triggered\n");
return true;
}
}
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
Content(null, { name: "firstContent" }),
Content(null, { name: "secondContent", Behavior: SampleBehavior }),
Content(null, { name: "thirdContent", Behavior: SampleBehavior }),
],
Behavior: class extends Behavior {
onDisplaying(container) {
container.firstThat("sampleEvent"); // "secondContent triggered" will be traced here
}
}
});
application.add(sampleContainer);
insert(content, before)
Argument |
Type |
Description |
content |
content |
The content object to insert. Its container must be null . |
before |
object |
The content object before which to insert. Its container must be this container. |
Inserts one content
object before another in this container as specified by the parameters
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
new ColoredSquare("blue", { top: 0, left:0 }),
]
});
let redSquare = new ColoredSquare("red", { top: 20, left: 20, });
sampleContainer.insert(redSquare, sampleContainer.first);
application.add(sampleContainer);
lastThat(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event to trigger |
... |
* |
Zero or more extra parameters |
Causes all content
objects in this container to trigger an event named by the value of id
. The order of traversal is from the last to the first. Traversal halts when a distributed event returns true
. Note that the first parameter of a distributed event is the content
object that triggers the event, not this container. Additional parameters, if any, of the event are the extra parameters of the lastThat
function.
class SampleBehavior extends Behavior {
sampleEvent(content) {
trace(content.name+" triggered\n");
return true;
}
}
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
Content(null, { name: "firstContent" }),
Content(null, { name: "secondContent", Behavior: SampleBehavior }),
Content(null, { name: "thirdContent", Behavior: SampleBehavior }),
],
Behavior: class extends Behavior {
onDisplaying(container) {
container.lastThat("sampleEvent"); // "thirdContent triggered" will be traced here
}
}
});
application.add(sampleContainer);
remove(content)
Argument |
Type |
Description |
content |
content |
The content object to remove. Its container must be this container. |
Removes the specified content
object from this container
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let redSquare = new ColoredSquare("red");
let blueSquare = new ColoredSquare("blue");
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
redSquare,
blueSquare,
],
});
sampleContainer.remove(redSquare);
application.add(sampleContainer);
replace(content, by)
Argument |
Type |
Description |
content |
content |
The content object to replace. Its container must be this container. |
by |
content |
The replacing content object. It must be unbound; that is, its container must be null . |
Replaces one content
object with another in this container as specified by the parameters
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let redSquare = new ColoredSquare("red");
let blueSquare = new ColoredSquare("blue");
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
blueSquare,
],
});
sampleContainer.replace(blueSquare, redSquare);
application.add(sampleContainer);
run(transition [, ...])
Argument |
Type |
Description |
transition |
transition |
The transition object to run |
... |
* |
Zero or more extra parameters |
Runs the specified transition
object in this container, binding that object to this container for the duration of the transition. The extra parameters are passed to the onBegin
and onEnd
functions of the transition
object. The container triggers the onTransitionBeginning
event before the transition starts and the onTransitionEnded
event after the transition ends.
import CombTransition from "piu/CombTransition";
class SwitchScreenBehavior extends Behavior {
onCreate(content, data) {
this.data = data;
}
onTouchEnded(content) {
let data = this.data;
let transition = new CombTransition(250, Math.quadEaseOut, "horizontal", 4);
let nextScreen = new ColoredScreen({ color: data.nextColor, nextColor: data.color })
application.run(transition, application.first, nextScreen);
}
}
let ColoredScreen = Container.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: $.color }),
contents: [
Content($, {
active: true, height: 100, width: 100,
skin: new Skin({ fill: $.nextColor }),
Behavior: SwitchScreenBehavior
})
]
}));
application.add(new ColoredScreen({ color: "red", nextColor: "blue" }));
swap(content0, content1)
Argument |
Type |
Description |
content0, content1 |
content |
The content objects to swap. The container of both objects must be this container. |
Swaps the specified content
objects in this container
let ColoredSquare = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({ fill: $ })
}));
let sampleContainer = new Container(null, {
active: true, top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
contents: [
new ColoredSquare("blue", { top: 0, left:0 }),
new ColoredSquare("red", { top: 50, left:50 }),
],
Behavior: class extends Behavior {
onTouchEnded(container) {
container.swap(container.first, container.last);
}
}
});
application.add(sampleContainer);
Same as for content
object (see Events in the section Content Object), plus:
onTransitionBeginning(container)
Argument |
Type |
Description |
container |
container |
The container object that triggered the event |
This event is triggered when a transition
object starts in the specified container
object.
onTransitionEnded(container)
Argument |
Type |
Description |
container |
container |
The container object that triggered the event |
This event is triggered when a transition
object ends in the specified container
object.
Applications use content
objects for graphical parts of their user interface, such as buttons, icons, sliders, switches, and tabs.
Content([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a content
instance, an object that inherits from Content.prototype
let sampleContent = new Content("Hello", {
top: 0, right: 50, height: 100, width: 100,
skin: new Skin({fill: "blue"}),
Behavior: class extends Behavior {
onCreate(content, data) {
trace(`${data}\n`); // Prints "Hello" to console
}
}
})
application.add(sampleContent);
Content.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Content.prototype
. The prototype
property of the result is Content.prototype
. The result also provides a template
function.
let SampleContent = Content.template($ => ({
height: 100, width: 100,
skin: new Skin({fill: $.color}),
Behavior: class extends Behavior {
onCreate(content, data) {
trace(`This box is ${data.color}\n`); // Prints "This box is red" to console
}
}
}));
application.add(new SampleContent({color: "red"}, {top: 0, right: 50}));
application.add(new SampleContent({color: "blue"}));
Parameter |
Type |
Description |
active |
boolean |
If true , this content can be touched; that is, it triggers touch events. |
anchor |
string |
Creates an anchor, a reference to the created content object in the instantiating data |
backgroundTouch |
boolean |
If true , this container receives any touch events that are received by its contents; that is, it will trigger touch events when one of its contents has been touched. |
Behavior |
function |
A function that creates instances of Behavior.prototype ; generally a class that extends the Behavior class. This content will create an instance of this behavior , set its behavior parameter to the created instance, and trigger the onCreate method. |
bottom |
number |
This content's bottom coordinate, in pixels (setting bottom in the created instance's coordinates property) |
duration |
number |
This content's duration, in milliseconds. This content triggers the onFinished event when its clock is running and its time equals its duration. |
exclusiveTouch |
boolean |
If true , this content always captures touches; that is, captureTouch is implicitly invoked on onTouchDown for this content. Setting exclusiveTouch to true is equivalent to calling captureTouch in response to the onTouchDown event for every touch id. |
fraction |
number |
This content's fraction--that is, the ratio of its time to its duration |
height |
number |
This content's height, in pixels (setting height in the created instance's coordinates property) |
interval |
number |
The time between ticks of this content's clock--that is, number of milliseconds between triggering the onTimeChanged events of the content's behavior when its clock is running. |
left |
number |
This content's left coordinate, in pixels (setting left in the created instance's coordinates property) |
loop |
boolean |
If true , this content will restart its clock when its time equals its duration |
multipleTouch |
boolean |
If true , this content handles multiple touches. |
name |
string |
This content's name |
right |
number |
This content's right coordinate, in pixels (setting right in the created instance's coordinates property) |
skin |
skin |
This content's skin |
Skin |
function |
A function that creates instances of Skin.prototype . This content will create an instance of this skin , and set its skin parameter to the created instance. |
state |
number |
This content's state. If this content's skin defines states, setting the state changes the appearance of this content. |
style |
style |
This content's style |
Style |
function |
A function that creates instances of Style.prototype . This content will create an instance of this style , and set its style parameter to the created instance. |
time |
number |
This content's time, in milliseconds. When its time is set, this content triggers the onTimeChanged event. |
top |
number |
This content's top coordinate, in pixels (setting top in the created instance's coordinates property) |
variant |
number |
This content's variant. If this content's skin defines variants, setting the variant changes the appearance of this content. |
visible |
boolean |
If true , this content is visible. |
width |
number |
This content's width, in pixels (setting width in the created instance's coordinates property) |
Prototype inherits from Object.prototype
.
Name |
Type |
Default Value |
Read Only |
Description |
active |
boolean |
false |
|
If true , this content can be touched; that is, it triggers touch events. |
anchor |
string |
The identifier of the property that references this content object in its instantiating data |
|
|
backgroundTouch |
boolean |
false |
|
If true , this container receives any touch events that are received by its contents; that is, it will trigger touch events when one of its contents has been touched. |
behavior |
object |
null |
|
This content's behavior object or null . When this content triggers an event, it calls the corresponding function property of its behavior, if any. |
bounds |
object |
|
|
This content's global position and size, as an object with x , y , width , and height number properties, specified in pixels. If this content is unbound, the getter returns undefined and the setter is ignored. |
container |
object |
|
✓ |
This content's container, or null if this content is unbound--that is, if it has no container |
coordinates |
object |
|
|
This content's coordinates, as an object with left , width , right , top , height , or bottom number properties (specified in pixels), or an empty object if no coordinates are passed into the constructor |
duration |
number |
0 |
|
This content's duration, in milliseconds. This content triggers the onFinished event when its clock is running and its time equals its duration. |
exclusiveTouch |
boolean |
false |
|
If true , this content always captures touches; that is, captureTouch is implicitly invoked on onTouchDown for this content. Setting exclusiveTouch to true is equivalent to calling captureTouch in response to the onTouchDown event for every touch id. |
fraction |
number |
undefined |
|
This content's fraction--that is, the ratio of its time to its duration. If the duration is 0, the getter returns undefined and the setter is ignored. This content triggers the onTimeChanged event when its fraction is set. |
height |
number |
|
|
This content's height, in pixels |
index |
number |
|
✓ |
The index of this content in its container, or –1 if this content is unbound |
interval |
number |
1 |
|
The time between ticks of this content's clock--that is, number of milliseconds between triggering the onTimeChanged events of the content's behavior when its clock is running. |
loop |
boolean |
false |
|
If true , this content will restart its clock when its time equals its duration |
multipleTouch |
boolean |
false |
|
If true , this content handles multiple touches. |
name |
string |
|
|
This content's name |
next |
object |
|
✓ |
The next content object of this content's container; null if this content is the last content object of this content's container or if this content has no container |
offset |
object |
|
|
This content's local position, as an object with x and y number properties, specified in pixels. If this content is unbound, the getter returns undefined and the setter is ignored. |
position |
object |
|
|
This content's global position, as an object with x and y number properties, specified in pixels. If this content is unbound, the getter returns undefined and the setter is ignored. |
previous |
object |
|
✓ |
The previous content object in this content's container; null if this content is the first content object of this content's container or if this content has no container |
running |
boolean |
|
✓ |
If true , this content's clock is running. |
size |
object |
|
|
This content's size, as an object with width and height number properties, specified in pixels |
skin |
skin |
null |
|
This content's skin or null
|
state |
number |
0 |
|
This content's state. If this content's skin defines states, setting the state changes the appearance of this content. |
style |
style |
null |
|
This content's style or null
|
time |
number |
0 |
|
This content's time, in milliseconds. When its time is set, this content triggers the onTimeChanged event. |
variant |
number |
0 |
|
This content's variant. If this content's skin defines variants, setting the variant changes the appearance of this content. |
visible |
boolean |
true |
|
If true , this content is visible. |
width |
number |
|
|
This content's width, in pixels |
x |
number |
|
|
This content's global x position. If this content is unbound, the getters return undefined and the setters are ignored. |
y |
number |
|
|
This content's global y position. If this content is unbound, the getters return undefined and the setters are ignored. |
bubble(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event to trigger |
... |
* |
Zero or more extra parameters |
Causes this content and all container
objects upward in the containment hierarchy to trigger an event named by the value of id
. The bubbling halts when a bubbled event returns true
. Note that the first parameter of a bubbled event is the container
object that triggers the event, not this content. Additional parameters, if any, of a bubbled event are the extra parameters of the bubble
function.
let NamedContainer = Container.template($ => ({
name: $.name, active: true, top: 20, bottom: 20, left: 20, right: 20,
skin: new Skin({ fill: $.color }),
Behavior: class extends Behavior {
printName(container) {
trace(`${container.name} triggered\n`);
}
onTouchEnded(container) {
trace("\n");
container.bubble("printName");
}
}
}));
let outerContainer = new NamedContainer({ name: "outerContainer", color: "red" });
let middleContainer = new NamedContainer({ name: "middleContainer", color: "blue" });
let innerContainer = new NamedContainer({ name: "innerContainer", color: "black" });
outerContainer.add(middleContainer);
middleContainer.add(innerContainer);
application.add(outerContainer);
captureTouch(id, x, y, ticks)
Argument |
Type |
Description |
id |
number |
The identifier of the touch |
x, y |
number |
The global position of the touch, in pixels |
ticks |
number |
The global time of the touch |
Causes this content to capture the touch named id
, meaning that only this content will trigger the remaining onTouchMoved
and onTouchEnded
events related to that touch. Other content
objects concerned with the captured touch trigger the onTouchCancelled
event when the captureTouch
function is called.
class BlueBehavior extends Behavior {
onTouchBegan(content, id, x, y, ticks) {
trace("Blue touch began\n");
content.captureTouch(id, x, y, ticks); // With this line, the redContainer behavior's onTouchCancelled method is called; without this line, its onTouchBegan and onTouchEnded methods would be called
}
onTouchEnded(content, id, x, y, ticks) {
trace("Blue touch ended\n");
}
}
let blueCapturingContent = new Content(null, {
active: true, top: 25, left: 25, height: 50, width: 50,
skin: new Skin({fill: "blue"}),
Behavior: BlueBehavior
});
class RedBehavior extends Behavior {
onTouchBegan(content, id, x, y, ticks) {
trace("Red touch began\n");
}
onTouchCancelled(content) {
trace("Red touch cancelled\n");
}
onTouchEnded(content, id, x, y, ticks) {
trace("Red touch ended\n");
}
}
let redContainer = new Container(null, {
active: true, backgroundTouch: true,
top: 0, left: 0, height: 100, width: 100,
skin: new Skin({fill: "red"}),
contents: [
blueCapturingContent
],
Behavior: RedBehavior
});
application.add(redContainer);
defer(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event to trigger |
... |
* |
Zero or more extra parameters |
The defer
function is similar to the delegate
function; both cause this content to trigger an event named by the value of id
. The difference is in their timing. The delegate
function sends the event immediately while the defer
functions posts the event. The event will be triggered at the following iteration of the main event loop.
The first parameter of the deferred event is this content. Additional parameters, if any, of the deferred event are the extra parameters of the defer
function.
delegate(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event to trigger |
... |
* |
Zero or more extra parameters |
Causes this content to trigger an event named by the value of id
. The first parameter of the delegated event is this content. Additional parameters, if any, of the delegated event are the extra parameters of the delegate
function.
let NamedContainer = Container.template($ => ({
name: $.name, active: true, top: 20, bottom: 20, left: 20, right: 20,
skin: new Skin({ fill: $.color }),
Behavior: class extends Behavior {
printName(container) {
trace(`${container.name} triggered\n`);
}
onTouchEnded(container) {
trace("\n");
container.delegate("printName");
}
}
}));
let outerContainer = new NamedContainer({ name: "outerContainer", color: "blue" });
let middleContainer = new NamedContainer({ name: "middleContainer", color: "black" });
let innerContainer = new NamedContainer({ name: "innerContainer", color: "red" });
outerContainer.add(middleContainer);
middleContainer.add(innerContainer);
application.add(outerContainer);
focus()
Focuses this content so that it triggers keyboard events. Only one content object at a time is focused.
distribute(id [, ...])
Argument |
Type |
Description |
id |
string |
The name of the event |
... |
* |
|
Causes this container and all content
objects downward in the containment hierarchy to trigger an event named by the value of id
. The order of traversal is depth first. Traversal halts when one of the triggered event-handling functions returns true
. Note that the first parameter of a distributed event is the content
object that triggers the event, not this container. Additional parameters, if any, of the event are the extra parameters of the distribute
function.
let NamedContainer = Container.template($ => ({
name: $.name, active: true, top: 20, bottom: 20, left: 20, right: 20,
skin: new Skin({ fill: $.color }),
Behavior: class extends Behavior {
printName(container) {
trace(`${container.name} triggered\n`);
}
onTouchEnded(container) {
trace("\n");
container.distribute("printName");
}
}
}));
let outerContainer = new NamedContainer({ name: "outerContainer", color: "red" });
let middleContainer = new NamedContainer({ name: "middleContainer", color: "blue" });
let innerContainer = new NamedContainer({ name: "innerContainer", color: "black" });
outerContainer.add(middleContainer);
middleContainer.add(innerContainer);
application.add(outerContainer);
hit(x, y)
Argument |
Type |
Description |
x, y |
number |
The global position to test, in pixels |
Returns this content if this content is active, bound, and contains the position, and undefined
otherwise. If this content is a container
instance, returns either one of its contents or itself if the content or itself is active, bound, and contains the position, or undefined
.
Note that this function should only be used after a content has been measured and fitted; otherwise it will always return undefined
.
let sampleContent = new Content(null, {
active: true, top: 0, left: 0, height: 100, width: 100,
skin: new Skin({fill: "blue"}),
Behavior: class extends Behavior {
onDisplaying(content) {
let x = content == content.hit(10, 10); // true
let y = content.hit(200, 200); // undefined
}
}
});
measure()
Returns the measured size of this content, as an object with width
and height
parameters.
Example 1:
let sampleContent = new Content(null, {
top: 0, left: 0, height: 100, width: 100,
skin: new Skin({fill: "blue"})
});
application.add(sampleContent);
let measuredSize = sampleContent.measure(); // {height: 100, width: 100}
let fittedHeight = sampleContent.height; // 100
let fittedWidth = sampleContent.width; // 100
Example 2:
let sampleContent = new Content(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "blue"})
});
application.add(sampleContent);
let measuredSize = sampleContent.measure(); // {height: 0, width: 0}
let fittedHeight = sampleContent.height; // 320 (assuming running on 240x320 screen)
let fittedWidth = sampleContent.width; // 240 (assuming running on 240x320 screen)
moveBy(x, y)
Argument |
Type |
Description |
x, y |
number |
The deltas by which to move this content, in pixels |
Moves this content as specified by the parameters. If the content's coordinates constrain its position, the moveBy
function ignores the corresponding horizontal or vertical deltas.
let unconstrainedContent = new Content(null, {
top: 0, left: 0, height: 100, width: 100,
skin: new Skin({fill: "blue"}),
});
application.add(unconstrainedContent);
unconstrainedContent.moveBy(100,100); // Moves unconstrainedContent 100 pixels in the x and y directions
let constrainedContent = new Content(null, {
top: 0, left: 0, bottom: 140, right: 220,
skin: new Skin({fill: "red"}),
});
application.add(constrainedContent);
constrainedContent.moveBy(100,100); // Does nothing
sizeBy(width, height)
Argument |
Type |
Description |
width, height |
number |
The deltas by which to size this content, in pixels |
Sizes this content as specified by the parameters. If this content's coordinates constrain its size, the sizeBy
function ignores the corresponding horizontal or vertical deltas.
let unconstrainedContent = new Content(null, {
top: 0, left: 0, height: 100, width: 100,
skin: new Skin({fill: "blue"}),
})
application.add(unconstrainedContent);
unconstrainedContent.sizeBy(100,100); // Makes unconstrainedContent 100 pixels wider and taller
let constrainedContent = new Content(null, {
top: 0, left: 0, bottom: 140, right: 220,
skin: new Skin({fill: "red"}),
})
application.add(constrainedContent);
constrainedContent.sizeBy(100,100); // Does nothing
start()
Starts this content's clock
class SampleBehavior extends Behavior {
onDisplaying(content) {
this.index = 0;
content.interval = 750;
content.time = 0;
content.start();
}
onTimeChanged(content) {
let state = content.state + 1;
if (state > 3) state = 0;
content.state = state;
}
}
let sampleContent = new Content(null, {
height: 100, width: 100,
skin: new Skin({fill: ["red", "orange", "yellow", "green"]}),
Behavior: SampleBehavior
});
application.add(sampleContent);
stop()
Stops this content's clock
class SampleBehavior extends Behavior {
onDisplaying(content) {
this.index = 0;
content.interval = 750;
content.time = 0;
content.start();
}
onTimeChanged(content) {
content.state = !content.state;
}
onTouchBegan(content) {
content.stop();
}
onTouchEnded(content) {
content.start();
}
}
let sampleContent = new Content(null, {
active: true, height: 100, width: 100,
skin: new Skin({ fill: ["blue", "white"]}),
Behavior: SampleBehavior
});
application.add(sampleContent);
The following standard events are triggered by content
objects.
onCreate(content, data, context)
Argument |
Type |
Description |
content |
content |
The content object that triggered the event |
data, context |
object |
The parameters of the constructor of the content object that references or contains the behavior |
This event is triggered when the content is constructed.
onDisplaying(content)
Argument |
Type |
Description |
content |
content |
The content object that triggered the event |
This event is triggered after the specified content
object is added to the containment hierarchy and has been measured and fitted, but before it is visible to the user. This is the first event the object receives after its coordinates have been computed.
onFinished(content)
Argument |
Type |
Description |
content |
content |
The content object that triggered the event |
This event is triggered when the specified content
object is running and its time equals its duration.
onTimeChanged(content)
Argument |
Type |
Description |
content |
content |
The content object that triggered the event |
This event is triggered when the time of the specified content
object changes.
onTouchBegan(content, id, x, y, ticks)
onTouchCancelled(content, id)
onTouchEnded(content, id, x, y, ticks)
onTouchMoved(content, id, x, y, ticks)
Argument |
Type |
Description |
content |
content |
The content object that triggered the event |
id |
number |
The identifier of the touch |
x, y |
number |
The global coordinates of the event, in pixels |
ticks |
number |
The global time of the event |
These events are triggered when the specified content
object is active and touched.
The die
object is a layout
object that allows you to “die cut” its contents with a region, minimizing the areas to invalidate and to update. These are useful for building animations and transitions on constrained devices that cannot update every screen pixel at every frame.
The die
object maintains two regions:
- the work region that the available operations build,
- the clip region that clips the contents of the
die
object
Both regions are initially empty.
Die([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this die's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. The dictionary is the same as for the content object. Only parameters specified in the Dictionary section of the Content Object will have an effect; other parameters will be ignored. |
Returns a die
instance, an object that inherits from Die.prototype.
let sampleDie = new Die(null, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.or(40, 40, die.width-80, die.height-80)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
});
let sampleScreenWithDie = new Container(null, {
left:0, right:0, top:0, bottom:0,
contents: [
Content(null, {
top: 0, bottom: 120, left: 0, right: 0,
skin: new Skin({ fill: "blue" }),
}),
Content(null, {
top: 120, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "black" }),
}),
sampleDie
]
});
application.add(sampleScreenWithDie);
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Die.prototype
. The prototype
property of the result is Die.prototype
. The result also provides a template
function.
let SampleDie = Die.template($ => ({
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.or(40, 40, die.width-80, die.height-80)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}));
let sampleScreenWithDie = new Container(null, {
left:0, right:0, top:0, bottom:0,
contents: [
Content(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "blue" }),
}),
Row(null, {
top: 0, bottom: 0, left: 0, right: 0,
contents: [
SampleDie(),
SampleDie(),
]
})
]
});
application.add(sampleScreenWithDie);
Prototype inherits from Layout.prototype
.
Same as for layout
object (see Functions in the section Layout Object), plus:
and(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
A local rectangle, in pixels |
Intersects the rectangle with the work region and returns this
.
let sampleContainer = new Container(null, {
left:0, right:0, top:0, bottom:0, skin: new Skin({ fill: "blue" }),
contents: [
Die($, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.fill()
.and(10, 10, 50, 50)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}),
]
});
application.add(sampleContainer);
attach(content)
Argument |
Type |
Description |
content |
content |
The content object to attach |
Binds the die
object to the containment hierarchy by replacing the specified content
object in the content's container with this die
object and adding the content
object to this die
object.
let whiteScreen = new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
Behavior: class extends Behavior {
onDisplaying(content) {
application.insert(blueScreen, content);
let die = this.die = new Die();
die.attach(content);
die.or(0, 0, die.width, die.height/4)
die.or(0, die.height/2, die.width, die.height/4)
.cut();
}
}
});
let blueScreen = new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "blue" }),
});
application.add(whiteScreen);
cut()
Copies the work region into the current region, and invalidates only the difference between the work and the clip regions.
detach()
Unbind this die
object from the content hierarchy by removing the first content
object from this die
object and replacing this die
object in its container with the removed content
object.
let whiteScreen = new Content(null, {
active: true, left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
Behavior: class extends Behavior {
onTouchBegan(content) {
application.add(blueScreen);
let die = this.die = new Die();
die.attach(blueScreen);
die.or(0, 0, die.width, die.height/4)
die.or(0, die.height/2, die.width, die.height/4)
.cut();
}
onTouchEnded(content) {
let die = this.die;
die.detach();
application.remove(blueScreen)
}
}
});
let blueScreen = new Content(null, {
active: true, left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "blue" }),
});
application.add(whiteScreen);
empty()
Empties the work region and returns this
.
fill()
Sets the work region to the bounds of this die
object and returns this
.
or(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
A local rectangle, in pixels |
Inclusively unions the rectangle with the work region and returns this
.
let sampleContainer = new Container(null, {
left:0, right:0, top:0, bottom:0, skin: new Skin({ fill: "red" }),
contents: [
Die($, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.or(10, 10, 50, 50)
die.or(80, 80, 100, 100)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}),
]
});
application.add(sampleContainer);
set(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
A local rectangle, in pixels |
Sets the work region to the rectangle and returns this
.
let sampleContainer = new Container(null, {
left:0, right:0, top:0, bottom:0, skin: new Skin({ fill: "blue" }),
contents: [
Die($, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.set(50, 50, 220, 140)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}),
]
});
application.add(sampleContainer);
sub(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
A local rectangle, in pixels |
Subtracts the rectangle from the work region and returns this
.
let sampleContainer = new Container(null, {
left:0, right:0, top:0, bottom:0, skin: new Skin({ fill: "blue" }),
contents: [
Die($, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.fill()
.sub(0, 0, 50, 50)
.sub(100, 0, 50, 50)
.sub(200, 0, 50, 50)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}),
]
});
application.add(sampleContainer);
xor(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
A local rectangle, in pixels |
Exclusively unions the work region with the rectangle and returns this
.
let sampleContainer = new Container(null, {
left:0, right:0, top:0, bottom:0, skin: new Skin({ fill: "blue" }),
contents: [
Die($, {
left:0, right:0, top:0, bottom:0,
Behavior: class extends Behavior {
onDisplaying(die) {
die.set(0, 0, die.width/2, die.height)
.xor(50, 50, die.width-100, die.height-100)
.cut();
}
},
contents: [
new Content(null, {
left:0, right:0, top:0, bottom:0,
skin: new Skin({ fill: "white" }),
}),
]
}),
]
});
application.add(sampleContainer);
The image
object is a content
object that displays images.
Image assets may be a GIF, JPEG, or PNG file, or a folder of JPEG and PNG files. The images example provides an example for every supported type.
Assets must be defined in the resources of your manifest. The quality of JPEG and PNG files can be set to a value between 1 and 100; higher numbers correspond to higher quality.
"resources":{
"*-image(100)": [
"$(MODDABLE)/examples/assets/images/screen1",
],
"*-image(40)": [
"$(MODDABLE)/examples/assets/images/screen2",
]
},
Images in a folder are used as frames of a single animated image. The frame rate is determined by the name of the folder. For example, the fish.15fps
folder from the example images folder tells the application to run at 15 frames per second. In the manifest, the .15fps
is dropped from the path.
"resources":{
"*-image": [
"$(MODDABLE)/examples/assets/images/fish",
],
}
The frame rate of a GIF is set in the file itself and cannot be changed by the application.
All supported image types are compressed into a single resource with a .cs
extension. These are the files that should be referenced in the application's script code. For example, to create image
objects using the assets mentioned above, the application would use the paths "screen1.cs"
, "screen2.cs"
, and "street.cs"
.
Image([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this image's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns an image
instance, an object that inherits from Image.prototype
let sampleImage = new Image(null, ({
path: "screen1.cs"
}));
application.add(sampleImage);
This example uses screen1.png
from the example images folder
Image.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Image.prototype
. The prototype
property of the result is Image.prototype
. The result also provides a template
function.
class ImageBehavior extends Behavior {
onDisplaying(image) {
image.start();
}
}
let SampleImage = Image.template($ => ({
path: $, loop: true, Behavior:ImageBehavior,
}));
application.add(new SampleImage("street.cs"));
This example uses street.gif
from the example images folder
Same as for content
object (see Dictionary in the section Content Object), plus:
Parameter |
Type |
Description |
path |
string |
The URL of the image file. It must be a file URL. |
Prototype inherits from Content.prototype
.
Name |
Type |
Default Value |
Read Only |
Description |
frameCount |
number |
|
✓ |
The total number of frames in this image |
frameIndex |
number |
|
|
The index of the current frame |
The label
object is a content
object that renders a string on a single line with a single style. The string is truncated if it does not fit the bounds of the label
object.
Label([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this label's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a label
instance, an object that inherits from Label.prototype
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "blue" });
let sampleLabel = new Label(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
style: sampleStyle, string: "Hello, World!"
});
application.add(sampleLabel)
Label.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Label.prototype
. The prototype
property of the result is Label.prototype
. The result also provides a template
function.
let blueStyle = new Style({ font:"600 28px Open Sans", color: "blue" });
let redStyle = new Style({ font:"600 28px Open Sans", color: "red" });
let SampleLabel = Label.template($ => ({
style: $.style, string: $.string,
skin: new Skin({ fill: "white" }),
}));
application.add(new SampleLabel({ string: "Hello, World!", style: blueStyle }, { top: 0, left: 0 }));
application.add(new SampleLabel({ string: "Hello, World!", style: redStyle }, { bottom: 0, right: 0 }));
Same as for content
object (see Dictionary in the section Content Object), plus:
Parameter |
Type |
Description |
string |
string |
This label's string |
Prototype inherits from Content.prototype
.
Name |
Type |
Default Value |
Read Only |
Description |
string |
string |
|
|
This label's string |
The layout
object is a container
object that delegates positioning and sizing of its contents to a script in its behavior.
When its width is measured, the layout
object triggers the onMeasureHorizontally
event, and the behavior can modify the measured width of the layout
object or the coordinates of its contents.
When its height is measured, the layout
object triggers the onMeasureVertically
event, and the behavior can modify the measured height of the layout
object or the coordinates of its contents.
Layout([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this layout's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. The dictionary is the same as for the content object. Only parameters specified in the Dictionary section of the Content Object will have an effect; other parameters will be ignored. |
Returns a layout
instance, an object that inherits from Layout.prototype/
let ColoredSquare = Content.template($ => ({
height: 0, width: 0,
skin: new Skin({ fill: $ }),
}));
let sampleLayout = new Layout(null, {
height: application.height, width: application.width,
skin: new Skin({fill: "black"}),
contents: [
new ColoredSquare("red", {top: 0, left: 0}),
new ColoredSquare("yellow", {top: 0, right: 0}),
new ColoredSquare("green", {bottom: 0, left: 0}),
new ColoredSquare("blue", {bottom: 0, right: 0}),
],
Behavior: class extends Behavior {
onMeasureHorizontally(layout, width) {
let squareWidth = width/2;
let square = layout.first;
while (square) {
square.sizeBy(squareWidth, 0);
square = square.next;
}
return width;
}
onMeasureVertically(layout, height) {
let squareHeight = height/2;
let square = layout.first;
while (square) {
square.sizeBy(0, squareHeight);
square = square.next;
}
return height;
}
}
});
application.add(sampleLayout);
Layout.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Layout.prototype
. The prototype
property of the result is Layout.prototype
. The result also provides a template
function.
let ColoredSquare = Content.template($ => ({
height: 0, width: 0,
skin: new Skin({ fill: $ }),
}));
let SampleLayout = Layout.template($ => ({
contents: [
new ColoredSquare("red", {top: 0, left: 0}),
new ColoredSquare("yellow", {top: 0, right: 0}),
new ColoredSquare("green", {bottom: 0, left: 0}),
new ColoredSquare("blue", {bottom: 0, right: 0}),
],
Behavior: class extends Behavior {
onMeasureHorizontally(layout, width) {
let squareWidth = width/2;
let square = layout.first;
while (square) {
square.sizeBy(squareWidth, 0);
square = square.next;
}
return width;
}
onMeasureVertically(layout, height) {
let squareHeight = height/2;
let square = layout.first;
while (square) {
square.sizeBy(0, squareHeight);
square = square.next;
}
return height;
}
}
}));
application.add(new SampleLayout(null, {top: 0, width: 100, left: 0, height: 100}));
application.add(new SampleLayout(null, {bottom: 0, width: 200, right: 0, height: 100}));
Prototype inherits from Container.prototype
.
Same as for container
object (see Events in the section Container Object), plus:
onFitHorizontally(layout, width)
Argument |
Type |
Description |
layout |
object |
The layout object that triggered the event |
width |
number |
The fitted width of the layout object, in pixels |
This event is triggered when the fitted width of the layout
object is calculated. Once this is triggered, the behavior can modify the coordinates of its contents. Returns the fitted width of the layout
object, in pixels.
onFitVertically(layout, height)
Argument |
Type |
Description |
layout |
object |
The layout object that triggered the event |
height |
number |
The fitted height of the layout object, in pixels |
This event is triggered when the fitted height of the layout
object is calculated. Once this is triggered, the behavior can modify the coordinates of its contents. Returns the height of the layout
object, in pixels.
onMeasureHorizontally(layout, width)
Argument |
Type |
Description |
layout |
object |
The layout object that triggered the event |
width |
number |
The measured width of the layout object, in pixels |
This event is triggered when the measured width of the layout
object is calculated. Returns the measured width of the layout
object, in pixels.
onMeasureVertically(layout, height)
Argument |
Type |
Description |
layout |
object |
The layout object that triggered the event |
height |
number |
The measured height of the layout object, in pixels |
This event is triggered when the measured height of the layout
object is calculated. Returns the measured height of the layout
object, in pixels.
The port
object is a content
object that delegates drawing to a script in its behavior that draws using simple Piu graphics commands.
The port
object has a clip rectangle (initially the bounds of the port
object) that affects all drawing.
Port([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. The dictionary is the same as for the content object. Only parameters specified in the Dictionary section of the Content Object will have an effect; other parameters will be ignored. |
Returns a port
instance, an object that inherits from Port.prototype
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
port.fillColor("blue", 50, 50, port.width-100, port.height-100);
}
}
})
application.add(samplePort);
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Port.prototype
. The prototype
property of the result is Port.prototype
. The result also provides a template
function.
let SamplePort = Port.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onCreate(port, data) {
this.colors = data;
}
onDraw(port) {
let colors = this.colors;
let x = 0, y = 0;
for (let i = 0; i < colors.length; i++) {
port.fillColor(colors[i], x, y, 75, 75);
x += 35;
y += 35;
}
}
}
}));
application.add(new SamplePort(["blue", "red", "black"]));
Prototype inherits from Content.prototype
.
drawContent(x, y, width, height)
Argument |
Type |
Description |
x, y, width, height |
number |
The local position and size of the area in which to draw, in pixels |
Draws this port's skin in the position specified
let heartSkin = new Skin({
texture: new Texture("heart.png"),
color: "red",
x: 0, y: 0, width: 60, height: 60,
});
let sampleStyle = new Style({ font:"600 28px Open Sans", color: ["red", "yellow", "green", "blue"] });
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: heartSkin,
Behavior: class extends Behavior {
onDraw(port) {
let size = 60;
port.drawContent(0, 0, size, size);
port.drawContent(port.width-size, 0, size, size);
port.drawContent(0, port.height-size, size, size);
port.drawContent(port.width-size, port.height-size, size, size);
}
}
});
application.add(samplePort);
drawLabel(string, x, y, width, height)
Argument |
Type |
Description |
string |
string |
The string to draw |
x, y, width, height |
number |
The local position and size of the area in which to draw, in pixels |
Draws the string the way a label instance would, with the style of this port
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "red" });
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }), style: sampleStyle,
Behavior: class extends Behavior {
onDraw(port) {
let string = "Hello, World!";
let size = sampleStyle.measure(string);
port.drawLabel(string, port.width-size.width, port.height-size.height, size.width, size.height);
}
}
})
application.add(samplePort);
drawSkin(skin, x, y, width, height [, variant, state])
Argument |
Type |
Description |
skin |
skin |
The skin to draw |
x, y, width, height |
number |
The local position and size of the area in which to draw, in pixels |
variant |
number |
The variant of the skin to draw. If the specified skin defines variants, setting the variant changes the appearance. |
state |
number |
The state of the skin to draw. If the specified skin defines states, setting the state changes the appearance. |
Draws the skin the way a content
instance would, with the state, variant, and position specified.
let heartSkin = new Skin({
texture: new Texture("heart.png"),
color: ["red", "blue"],
x: 0, y: 0, width: 60, height: 60,
});
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
Behavior: class extends Behavior {
onDraw(port) {
port.drawSkin(heartSkin, 20, 20, 60, 60, 0, 1);
}
}
})
application.add(samplePort);
drawString(string, style, color, x, y, width, height)
Argument |
Type |
Description |
string |
string |
The string to draw |
style |
style |
The style to use to draw the string |
color |
string |
The color to draw the string, as a string of the form specified in the Color section of this document |
x, y, width, height |
number |
The local position and size of the area in which to draw, in pixels |
Draws the string the way a label
instance would, with the style, color, and position specified.
let sampleStyle = new Style({ font:"600 28px Open Sans"});
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
port.drawString("Hello, World!", sampleStyle, "blue", 0, 0, port.width, port.height);
}
}
});
application.add(samplePort);
drawStyle(string, style, x, y, w, h [, ellipsis, state])
Argument |
Type |
Description |
string |
string |
The string to draw |
style |
style |
The style to use to draw the string |
x, y, width, height |
number |
The local position and size of the area in which to draw, in pixels |
ellipsis |
boolean |
If true , the string is truncated to fit the specified bounds. If false , the entire string is drawn, even if it extends beyond the specified bounds. |
state |
number |
The state of the style to draw. If the specified style has multiple fill colors, setting the state selects which color to use. |
Draws a string with the style, position, and state specified.
let sampleStyle = new Style({ font:"600 28px Open Sans", color: ["red", "yellow", "green", "blue"] });
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
Behavior: class extends Behavior {
onDraw(port) {
let string = "Hello, World!";
let size = sampleStyle.measure(string);
let w = size.width;
let h = size.height;
port.drawStyle(string, sampleStyle, 20, 10, w, h, true, 0);
port.drawStyle(string, sampleStyle, 20, h+10, w, h, true, 1);
port.drawStyle(string, sampleStyle, 20, h*2+10, w-10, h, false, 2); // Not truncated
port.drawStyle(string, sampleStyle, 20, h*3+10, w-10, h, true, 3); // Truncated
}
}
});
application.add(samplePort);
drawTexture(texture, color, x, y, sx, sy, sw, sh)
Argument |
Type |
Description |
texture |
texture |
The texture to draw |
color |
string |
If the texture has only an alpha bitmap, the value of the color property will be used to colorize the bitmap. Must be a string of the form specified in the Color section of this document. |
x, y |
number |
The local position and size of the area in which to draw, in pixels |
sx, sy, sw, sh |
number |
The source area--the position and size of the area to copy pixels from, in pixels. The default is the entire image. |
Draws the image referenced by the texture.
let ballTexture = new Texture("balls.png");
let alphaHeartTexture = new Texture("heart.png");
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
port.drawTexture(ballTexture, "black", 0, 0, 0, 0, 30, 30);
port.drawTexture(alphaHeartTexture, "red", 0, 30, 0, 0, 60, 60);
port.drawTexture(alphaHeartTexture, "blue", 0, 90, 0, 0, 60, 60);
}
}
})
application.add(samplePort);
fillColor(color, x, y, width, height)
Argument |
Type |
Description |
color |
string |
The color to draw the image in, as a string of the form specified in the Color section of this document |
x, y, width, height |
number |
The local position and size of the area to fill, in pixels |
Fills the area with the color specified.
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
port.fillColor("red", 0, 0, port.width/2, port.height);
port.fillColor("blue", port.width/2, 0, port.width/2, port.height);
}
}
})
application.add(samplePort);
fillTexture(texture, color, x, y, width, height, sx, sy, sw, sh)
Argument |
Type |
Description |
texture |
texture |
The filling image |
x, y, width, height |
number |
The destination area--the local position and size of the area to copy pixels to, in pixels |
sx, sy, sw, sh |
number |
The source area--the position and size of the area to copy pixels from, in pixels. |
Fills the area with the image. The source area of the image is repeated to cover the destination area.
let alphaHeartTexture = new Texture("heart.png");
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
let w = port.width, h = port.height;
port.fillTexture(alphaHeartTexture, "red", 0, 0, w, h/2, 0, 0, 60, 60);
port.fillTexture(alphaHeartTexture, "blue", 0, h/2, w, h/2, 0, 0, 60, 60);
}
}
})
application.add(samplePort);
invalidate([x, y, width, height])
Argument |
Type |
Description |
x, y, width, height |
number |
The local position and size of the area to invalidate, in pixels |
Invalidates the specified area of this port (or the entire port if no area is specified), which triggers the onDraw
event.
let samplePort = new Port(null, {
active: true, top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onCreate(port) {
this.color = "blue";
}
onDraw(port) {
port.fillColor(this.color, 0, 0, port.width, port.height);
}
onTouchEnded(port) {
this.color = (this.color == "blue")? "red" : "blue";
port.invalidate();
}
}
})
application.add(samplePort);
measureString(string, style)
Argument |
Type |
Description |
string |
string |
The string to measure |
style |
style |
The style to use when measuring the string |
Measures the string the way a label
instance would, with the style specified
let sampleStyle = new Style({ font:"600 28px Open Sans"});
let samplePort = new Port(null, {
active: true, top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onCreate(port) {
this.index = 0;
this.strings = ["H", "He", "Hel", "Hell", "Hello"];
}
onDraw(port) {
let string = this.strings[this.index];
let stringWidth = port.measureString(string, sampleStyle).width;
port.drawString(string, sampleStyle, "blue", (port.width-stringWidth)/2, 0, stringWidth, 30);
}
onTouchEnded(port) {
this.index++;
if (this.index == this.strings.length) this.index = 0;
port.invalidate();
}
}
})
application.add(samplePort);
popClip()
Restores the current clip rectangle from this port's clip rectangles stack
pushClip([x, y, width, height])
Argument |
Type |
Description |
x, y, width, height |
number |
The local position and size of the clip rectangle |
Saves the specified clip rectangle to this port's clip rectangles stack
let alphaHeartTexture = new Texture("heart.png");
let samplePort = new Port(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
Behavior: class extends Behavior {
onDraw(port) {
port.fillTexture(alphaHeartTexture, "blue", 0, 0, port.width, port.height, 0, 0, 60, 60);
port.pushClip(0, 0, 200, 100);
port.fillTexture(alphaHeartTexture, "red", 0, 0, port.width, port.height, 0, 0, 60, 60);
port.popClip();
}
}
})
application.add(samplePort);
Same as for content
object (see Events in the section Content Object), plus:
onDraw(port, x, y, width, height)
Argument |
Type |
Description |
port |
port |
The port object that triggered the event |
x, y, width, height |
number |
The local position and size of the area to draw, in pixels |
This event is triggered when the specified port
object needs to update the area (when it's invalidated).
-
Source code:
piuRow.c
-
Relevant Examples: N/A
The row
object is a container
object that arranges its contents horizontally.
Row([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. The dictionary is the same as for the content object. Only parameters specified in the Dictionary section of the Content Object will have an effect; other parameters will be ignored. |
Returns a row
instance, an object that inherits from Row.prototype
let sampleRow = new Row(null, {
top: 0, bottom: 0, left: 0, right: 0,
contents: [
new ColoredSquare("red"),
new ColoredSquare("blue"),
new ColoredSquare("black"),
]
});
application.add(sampleRow);
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Row.prototype
. The prototype
property of the result is Row.prototype
. The result also provides a template
function.
let ColoredSquare = Content.template($ => ({
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: $ })
}));
let SampleRow = Row.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
contents: [
new ColoredSquare($.firstColor),
new ColoredSquare($.secondColor),
],
}));
application.add(new SampleRow({ firstColor:"red", secondColor:"blue" }));
Prototype inherits from Container.prototype
.
Same as for container
object (see Events in the section Container Object)
The scroller
object is a container
object that scrolls its first content
object horizontally and vertically.
Scroller([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a scroller
instance, an object that inherits from Scroller.prototype
import { VerticalScrollerBehavior } from "scroller"; // See "scroller.js" from the scroller example
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "white" });
let scrollerSample = new Scroller(null, {
left: 0, right: 0, top: 0, bottom: 0,
style: sampleStyle, skin: new Skin({ fill: "blue" }),
active: true, backgroundTouch: true, clip: true,
Behavior: VerticalScrollerBehavior,
contents:[
Text(null, {
left: 0, right: 0, top: 0,
blocks: [
{spans: [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Pellentesque a massa et massa rutrum maximus non quis tellus.",
"Fusce quis eros quis leo sodales vehicula. Praesent pretium massa vel ornare pharetra."
]}
]
}),
],
});
application.add(scrollerSample);
Scroller.template(anonymous)
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Scroller.prototype
. The prototype
property of the result is Scroller.prototype
. The result also provides a template
function.
import { VerticalScrollerBehavior } from "scroller"; // See "scroller.js" from the scroller example
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "white" });
let ScrollerSample = Scroller.template($ => ({
left: 0, right: 0, top: 0, bottom: 0, skin: new Skin({ fill: "black" }),
active: true, backgroundTouch: true, clip: true,
Behavior: VerticalScrollerBehavior,
contents:[
Text(null, {
left: 0, top: 0, right: 0,
string: "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.",
}),
],
}));
let screenWithScrollerSample = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
style: sampleStyle,
contents: [
Text(null, {
top: 0, height: 40, left: 0, right: 0,
skin: new Skin({ fill: "blue" }),
string: "Scroller Example"
}),
new ScrollerSample(),
]
});
application.add(screenWithScrollerSample);
Same as for container
object (see Dictionary in the section Container Object), plus:
Parameter |
Type |
Definition |
loop |
boolean |
If true , this scroller will loop its first content object |
Prototype inherits from Container.prototype
.
Name |
Type |
Default Value |
Read Only |
Description |
constraint |
object |
|
✓ |
The constrained scroll offsets of this scroller, as an object with x and y number properties. The scroll offsets when this scroller is tracking may be different from the constrained scroll offsets. |
loop |
boolean |
false |
|
If true , this content will restart its clock when its time equals its duration |
scroll |
object |
|
|
The scroll offsets of this scroller, as an object with x and y number properties, specified in pixels |
tracking |
boolean |
false |
|
If true , this scroller is tracking. When tracking, the scroller does not constrain its scroll offsets. |
reveal(bounds)
Argument |
Type |
Description |
bounds |
object |
The local position and size of the area to reveal, as an object with x , y , width , and height properties, specified in pixels |
Scrolls this scroller to reveal the specified area
class SampleScrollerBehavior extends Behavior {
onDisplaying(scroller) {
let bounds = scroller.bounds;
bounds.y = scroller.first.last.y;
scroller.reveal(bounds);
}
}
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "white" });
let ScrollerItem = Label.template($ => ({
left: 20, right: 20, bottom: 90, height: 30,
style: sampleStyle, string: "Item" + $
}));
let scrollerSample = new Scroller(null, {
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: "black" }),
Behavior: SampleScrollerBehavior,
contents:[
Column(null, {
top: 0, left: 0,
contents: [
ScrollerItem(1),
ScrollerItem(2),
ScrollerItem(3),
ScrollerItem(4),
ScrollerItem(5),
]
})
],
});
application.add(scrollerSample);
scrollBy(dx, dy)
Argument |
Type |
Description |
dx, dy |
number |
The deltas by which to scroll this scroller, in pixels |
Adds the deltas to the scroll offsets of this scroller
class SampleScrollerBehavior extends Behavior {
onDisplaying(scroller) {
this.halfway = scroller.y + scroller.height/2;
}
onTouchEnded(scroller, id, x, y, ticks) {
scroller.scrollBy(0, y-this.halfway);
}
}
let ColoredSquare = Content.template($ => ({
left: 20, right: 20, top: 20, height: 80,
skin: new Skin({ fill: $ })
}));
let scrollerSample = new Scroller(null, {
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: "black" }),
active: true, backgroundTouch: true, clip: true,
Behavior: SampleScrollerBehavior,
contents:[
Column(null, {
active: true, top: 0, left: 0, right: 0,
contents: [
ColoredSquare("red"),
ColoredSquare("orange"),
ColoredSquare("yellow"),
ColoredSquare("green"),
ColoredSquare("blue"),
ColoredSquare("purple"),
]
})
],
});
application.add(scrollerSample);
scrollTo(x, y)
Argument |
Type |
Description |
x, y |
number |
The offsets to which to scroll this scroller, in pixels |
Changes the scroll offsets of this scroller
let ColoredSquare = Content.template($ => ({
active: true, top: 20, width: 80, height: 80,
skin: new Skin({ fill: $ }),
Behavior: class extends Behavior {
onDisplaying(content) {
this.x = content.x - 40;
this.y = content.y - 40;
}
onTouchEnded(content) {
let scroller = content.container.container;
scroller.scrollTo(this.x, this.y);
}
}
}));
let scrollerSample = new Scroller(null, {
left: 0, right: 0, top: 0, bottom: 0,
skin: new Skin({ fill: "black" }),
contents:[
Column(null, {
top: 0, left: 0,
contents: [
ColoredSquare("red", {left: 0}),
ColoredSquare("orange", {left: 40}),
ColoredSquare("yellow", {left: 80}),
ColoredSquare("green", {left: 120}),
ColoredSquare("blue", {left: 160}),
ColoredSquare("purple", {left: 200}),
]
})
],
});
application.add(scrollerSample);
Same as for container
object (see Events in the section Container Object), plus:
Argument |
Type |
Description |
scroller |
scroller |
The scroller object that triggered the event |
This event is triggered when the specified scroller
object scrolls.
When triggered by a scroller, this event is also triggered by all the contents of the scroller. This makes it easier to implement scrollbars, for example.
The skin
object defines the appearance of content
objects. It can draw or fill content
objects with portions of texture
objects or fill or stroke content
objects with colors.
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a skin
instance, an object that inherits from Skin.prototype
// Texture skin
let ballTexture = new Texture("balls.png");
let ballSkin = new Skin({ texture:ballTexture, x:0, y:0, width:30, height:30, variants:30 });
let ballContent = new Content(null, {
top: 0, left: 0,
skin: ballSkin
});
application.add(ballContent);
// Color skin
let borderedSkin = new Skin({ fill: "black", stroke: "blue", borders: { left: 5, right: 5, top: 5, bottom: 5}})
let borderedContent = new Content(null, {
top: 50, left: 0, height: 50, width: 50,
skin: borderedSkin
});
application.add(borderedContent);
Skin.template([dictionary])
Arguments |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a constructor, a function that creates instances of Skin.prototype
. The prototype
property of the result is Skin.prototype
.
// Texture skin
let ballTexture = new Texture("balls.png");
let BallSkin = Skin.template({ texture:ballTexture, x:0, y:0, width:30, height:30, variants:30 });
let ballContent = new Content(null, {
top: 0, right: 0, variant: 2,
Skin: BallSkin // Note the capital "S" in "Skin"
});
application.add(ballContent);
// Color skin
let BorderedSkin = Skin.template({ fill: "black", stroke: "red", borders: { left: 5, right: 5, top: 5, bottom: 5}})
let borderedContent = new Content(null, {
top: 50, right: 0, height: 50, width: 50,
skin: new BorderedSkin() // Note the lowercase "S" in "Skin"
});
application.add(borderedContent);
If there is a texture
or Texture
property in the dictionary, the constructor returns a texture skin, otherwise the constructor returns a color skin.
Texture skins only
Parameter |
Type |
Description |
bottom |
number |
The skin's bottom tile (setting the bottom parameter in the created instance, and bottom in the created instance's tiles property) |
color |
string or array
|
If the texture has only an alpha bitmap, the value of the color property will be used to colorize the bitmap. Must be a string or array of strings of the form specified in the Color section of this document. |
left |
number |
The skin's left tile (setting the left parameter in the created instance, and left in the created instance's tiles property) |
right |
number |
The skin's right tile (setting the right parameter in the created instance, and right in the created instance's tiles property) |
states |
number |
This skin's vertical offset between states, in pixels |
texture |
texture |
This skin's texture |
Texture |
function |
A function that creates instances of Texture.prototype . This skin will create an instance of this texture , and seet its texture parameter to the created instance. |
tiles |
object |
This skin's tiles, as an object with left , right , top , or bottom number properties, specified in pixels. See Tiles for more information. |
top |
number |
The skin's top tile (setting the top parameter in the created instance, and top in the created instance's tiles property) |
variants |
number |
This skin's horizontal offset between variants, in pixels |
x, y, width, height |
number |
The portion of the texture object to extract, in pixels (setting the created instance's bounds , width , and height properties) |
Color skins only
Parameter |
Type |
Description |
borders |
object |
The borders to stroke content objects with, as an object with left , right , top , or bottom number properties, specified in pixels. The default is no borders. |
fill |
string or array
|
The color(s) to fill content objects with, as a string or an array of strings of the form specified in the Color section of this document. |
stroke |
string or array
|
This skin's stroke color(s), as a string or an array of strings of the form specified in the Color section of this document. |
Prototype inherits from Object.prototype
.
All properties of a skin
object are read-only, but you can change the style of content objects at any time.
Texture Skins
Name |
Type |
Default Value |
Description |
bottom |
number |
0 |
The skin's bottom tile |
color |
string |
|
If the texture has only an alpha bitmap, the value of the color property will be used to colorize the bitmap. Must be a string or array of strings of the form specified in the Color section of this document. |
bounds |
object |
|
The portion of the texture object to extract, as an object with x , y , width , and height number properties, specified in pixels |
height |
number |
|
This skin's height, in pixels |
left |
number |
0 |
The skin's left tile |
right |
number |
0 |
The skin's right tile |
states |
number |
undefined |
This skin's vertical offset between states, in pixels |
texture |
texture |
|
This skin's texture |
tiles |
object |
undefined |
This skin's tiles, as an object with left , right , top , and bottom number properties, specified in pixels |
top |
number |
0 |
The skin's top tile |
variants |
number |
undefined |
This skin's horizontal offset between variants, in pixels |
width |
number |
|
This skin's width, in pixels |
Color Skins
Name |
Type |
Default Value |
Description |
borders |
object |
{left: 0, right: 0, top: 0, bottom: 0} |
This skin's borders, as an object with left , right , top , and bottom number properties, specified in pixels |
fill |
object |
|
This skin's fill color(s), as an array of strings of the form specified in the Color section of this document.
The state property of the content object using the skin determines the index of the array; if state is not an integer, colors from surrounding states are blended. If specified as one string instead of an array, it is treated as an array with a single item. The default fill color is transparent . |
stroke |
object |
|
This skin's stroke color(s), as an array of strings of the form specified in the Color section of this document.
The state property of the content object using the skin determines the index of the array; if state is not an integer, colors from surrounding states are blended. If specified as one string instead of an array, it is treated as an array with a single item. The default stroke color is transparent . |
The Sound
object plays audio using the AudioOut
class. It may be used to play all or part of an audio resource once or repeatedly. The Sound
object is designed to play short sounds to provide audible feedback for user actions. Use the AudioOut
class directly for other audio playback needs.
A separate instance of the Sound class is created for each audio resource to be played.
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below have an effect; other parameters are ignored. |
Returns a sound
instance, an object that inherits from Sound.prototype
let sampleSound = new Sound({ path: "piano.wav" });
Parameter |
Type |
Description |
path |
string |
The name of the resource containing the audio audio. |
offset |
number |
The number of samples into the audio to begin playback. If not specified, playback begins with the first sample. |
size |
number |
The number of samples to play. If not specified, playback continues to the end of the audio resource. |
Prototype inherits from Object.prototype
.
All properties are static. The default values for the bitsPerSample
, numChannels
, and sampleRate
properties reflect the configuration of the AudioOut
module.
Name |
Type |
Default Value |
Read Only |
Description |
bitsPerSample |
number |
|
✓ |
The number of bits (either 8 or 16) for audio playback. |
numChannels |
number |
|
✓ |
The number of channels for audio playback. |
sampleRate |
number |
|
✓ |
The number of samples per second for audio playback. |
volume |
number |
1 |
|
The volume of sounds; values range from 0 for silent, to 1 for full volume |
static close()
Stops any sounds that are playing and closes the AudioOut
instance used by the Sound
object. Instances of the Sound
class are not closed or otherwise affected by this call.
play([stream, repeat, callback])
Argument |
Type |
Description |
stream |
number |
The stream to play the sound on. Defaults to 0 . |
repeat |
number |
The number of times to repeat the sound. Defaults to 1 . Set the repeat property to Infinity to repeat the sound indefinitely. |
callback |
function |
An optional callback function to invoke after the audio resource completes playback. |
Plays the audio sample on the specified stream repeat
times. If the callback
parameter is provided, it is invoked after playback of the audio completes.
// Play sampleSound once
sampleSound.play();
// Play sampleSound 5 times
sampleSound.play(0, 5);
// Play sampleSound once and print to the console when finished
sampleSound.play(0, 1, () => {
trace("Sound finished\n");
});
The style
object defines the appearance of strings in label
and text
objects. Styles can be inherited from those of containing objects. For more information, see the Cascading Styles section below.
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns style
instance, an object that inherits from Style.prototype
let sampleStyle = new Style({ font:"600 28px Open Sans", color: "blue" });
let sampleLabel = new Label(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
style: sampleStyle, string: "Hello, World!"
});
application.add(sampleLabel)
Style.template(dictionary)
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a constructor, a function that creates instances of Style.prototype
. The prototype
property of the result is Style
. The result also provides a template
function.
let RedStyle = Style.template({ font:"600 28px Open Sans", color: "red" });
let BlueStyle = Style.template({ font:"600 28px Open Sans", color: "blue" });
let sampleLabel = new Label(null, {
top: 0, height:30, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
Style: RedStyle, string: "Hello, World!" // Note the capital "S" in "Style"
});
let sampleLabel2 = new Label(null, {
top: 30, height: 30, left: 0, right: 0,
skin: new Skin({ fill: "white" }),
style: new BlueStyle, string: "Hello, World!" // Note the lowercase "s" in "style"
});
application.add(sampleLabel);
application.add(sampleLabel2);
Parameter |
Type |
Description |
bottom |
number |
This style's bottom margin, in pixels (setting the bottom property of the created instance, and bottom in the created instance's margins property) |
leading |
number |
This style's line height, or "leading"--the distance between lines of a block, in pixels. If 0 or unspecified, it is automatically calculated. Use a negative value to force a distance even if lines overlap. |
left |
number |
This style's left margin, in pixels (setting the left property of the created instance, and left in the created instance's margins property) |
right |
number |
This style's right margin, in pixels (setting the right property of the created instance, and right in the created instance's margins property) |
Parameter |
Type |
Description |
vertical |
string |
This style's vertical alignment, as top , middle (the default), or bottom
|
Parameter |
Type |
Description |
color |
string or array
|
This style's color(s), as a string or an array of strings of the form specified in the Color section of this document |
font |
string |
This style's font, as a string of the form specified in the Cascading Styles section of this document (setting the style , weight , stretch , size , and family properties of the created instance) |
horizontal |
string |
This style's horizontal alignment, as left , center (the default), right , or justify
|
top |
number |
This style's top margin, in pixels (setting the top property of the created instance, and top in the created instance's margins property) |
Prototype inherits from Object.prototype
.
All properties of a style
object are read-only, but you can change the style of content objects at any time.
Name |
Type |
Default Value |
Description |
bottom |
number |
0 |
The bottom margin of this style |
color |
object |
undefined |
This style's color(s), as an array of strings, or undefined if no color has been specified. The state property of the content object using the style determines the index of the array; if state is not an integer, colors from surrounding states are blended. |
family |
string |
|
This style's font family |
horizontal |
string |
|
This style's horizontal alignment, as left , center (the default), right , or justify
|
leading |
number |
|
This style's line height (or "leading")--the distance between lines of a block, in pixels. If 0 or unspecified, it is automatically calculated |
left |
number |
0 |
The left margin of this style |
margins |
object |
|
This style's margins, as an object with left , right , top , and bottom number properties, specified in pixels |
right |
number |
0 |
The right margin of this style |
size |
string |
|
This style's font size, in pixels. |
stretch |
string |
|
This style's stretch |
top |
number |
0 |
The top margin of this style |
vertical |
string |
|
This style's vertical alignment, as top , middle (the default), or bottom , specified in pixels |
weight |
number |
|
The weight of this style's font |
measure(string)
Argument |
Type |
Description |
string |
string |
The string to measure |
Calculates the size of the string rendered with this style (and any inherited styles, if this style is attached to a content
object), and returns it as an object
with width
and height
properties, specified in pixels
let normalStyle = new Style({ font:"600 28px Open Sans", color: "black" });
let size = normalStyle.measure("Moddable"); // {"width":134,"height":38}
The text
object is a content
object that renders a string on multiple lines with multiple styles. There are two ways to modify the string of a text
object. An application typically uses only one of these approaches for a specific text
object.
- Set the
string
property. This replaces the full string.
- Build the string with blocks and spans, between calls to the
begin
and end
functions. This appends characters to the string. This method provides the most control, since each span can have a different style.
Text([behaviorData, dictionary])
Argument |
Type |
Description |
behaviorData |
* |
A parameter that is passed into the onCreate function of this content's behavior . This may be any type of object, including null or a dictionary with arbitrary parameters. |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a text
instance, an object that inherits from Text.prototype
let sampleStyle = new Style({ font:"600 28px Open Sans"});
let redStyle = new Style({ color: "red" });
let blueStyle = new Style({ color: "blue" });
let sampleText = new Text(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({fill: "white"}),
style: sampleStyle,
blocks: [
{ spans: [
" Lorem ipsum dolor sit amet, ",
{ style: redStyle, spans: "consectetur adipiscing elit." },
]},
{ style: blueStyle, spans: "In dignissim hendrerit ultricies." }
]
});
application.add(sampleText);
Arguments |
Type |
Description |
anonymous |
function |
A function that returns an object with properties to initialize the instances that the result creates |
Returns a constructor, a function that creates instances of Text.prototype
. The prototype
property of the result is Text.prototype
. The result also provides a template
function.
let sampleStyle = new Style({ font:"600 28px Open Sans"});
let redStyle = new Style({ color: "red", horizontal: "left" });
let blueStyle = new Style({ color: "blue", horizontal: "right" });
let SampleText = Text.template($ => ({
top: 50, bottom: 50, left: 50, right: 50,
skin: new Skin({fill: "white"}),
style: $.baseStyle,
blocks: [
{ style: redStyle, spans: $.redText },
{ style: blueStyle, spans: $.blueText }
]
}));
application.add(new SampleText({ baseStyle: sampleStyle, redText: "Red!", blueText: "Blue!" }));
Same as for content
object (see Dictionary in the section Content Object), plus:
Parameter |
Type |
Description |
blocks |
array |
An array of blocks, where a block is an object with the following properties: - behavior : An object or null (the default). When this text is active and the block is touched, the block calls the corresponding function properties of its behavior. - style : A style instance or null (the default). - spans : A string or an array of spans.
Like a block, a span is an object with behavior , style , and spans properties. |
string |
string |
This text's string. Setting this string creates one block containing one span that uses this text's style. |
Prototype inherits from Content.prototype
.
Name |
Type |
Read Only |
Description |
blocks |
array |
|
This text's blocks |
string |
string |
|
This text's string. Setting this string creates one block containing one span that uses this text's style. |
For sample code that uses all the functions below, see the text example.
begin()
Starts the process of defining the string and styles of this text using blocks and spans. The string is reset to empty. The begin
function must be called before beginBlock
or beginSpan
. After defining the string and styles, call end
.
beginBlock([style, behavior])
Argument |
Type |
Description |
style |
style |
The style of the block |
behavior |
object |
The behavior of the block |
Creates and opens a new block. The begin
function must have been already called without a corresponding end
. There cannot be another block already open.
beginSpan(style [, behavior])
Argument |
Type |
Description |
style |
style |
The style of the span |
behavior |
object |
The behavior of the span |
Creates and opens a new span. There must be an open block. There cannot be another open span.
concat(string)
Argument |
Type |
Description |
string |
string |
The string to concatenate |
Concatenates the specified string to this text. There must be an open span.
end()
Completes the process of building this text's string and styles using blocks and spans; must be called after begin
and before this text can be measured, fit, or rendered
endBlock()
Closes the open block
endSpan()
Closes the open span
Same as for content
object (see Events in the section Content Object).
The texture
object is an asset that references an image file. Applications use texture
objects in defining skin
objects.
Argument |
Type |
Description |
path |
string |
The URL of the image file. It must be a file URL. |
Returns a texture
instance, an object that inherits from Object.prototype
const logoTexture = new Texture("logo.png");
const logoSkin = new Skin({ texture: logoTexture, x: 0, y: 0, width: 100, height: 20 });
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a texture
instance, an object that inherits from Object.prototype
const logoTexture = new Texture({ path: "logo.png" });
const logoSkin = new Skin({ texture: logoTexture, x: 0, y: 0, width: 100, height: 20 });
Texture.template(dictionary)
Argument |
Type |
Description |
dictionary |
object |
An object with properties to initialize the result. Only parameters specified in the Dictionary section below will have an effect; other parameters will be ignored. |
Returns a constructor, a function that creates instances of Texture.prototype
. The prototype
property of the result is Texture.prototype
.
const LogoTexture = Texture.template({ path: "logo.png" });
// Note the capital "T" in "Texture" below
const LogoSkin = Skin.template({ Texture: LogoTexture, x: 0, y: 0, width: 100, height: 20, color: "white" });
const AnotherLogoTexture = Texture.template({ path: "logo.png" });
// Note the lowercase "t" in "texture" below
const AnotherLogoSkin = Skin.template({ texture: new AnotherLogoTexture(), x: 0, y: 0, width: 100, height: 20, color: "white" });
Parameter |
Type |
Description |
path |
string |
The URL of the image file. It must be a file URL. |
Prototype inherits from Object.prototype
.
Name |
Type |
Read Only |
Description |
height |
number |
✓ |
This texture's height, in physical pixels |
width |
number |
✓ |
This texture's width, in physical pixels |
The timeline
object provides a mechanism for sequencing and running a collection of tweens. This is useful for managing transitions between Piu screens and other animations.
Tweens work by taking in a target object and an object that specifies a list of properties and values. When the tween is set to a specific fraction, the appropriate properties of the target object are updated with values between their initial value and the destination value. The specifics of how this works are determined by the type of tween ("on", "from", or "to", as described below) and the easing function used for the tween.
The application manages all of the tweens in a timeline at once by seeking to a particular point in the timeline. This is usually driven by the onTimeChanged
function of a content
object.
The Piu Timeline implementation is based on the TimelineLite class developed by GreenSock.
Note that the Timeline
class must be imported into your application to be used:
import Timeline from "piu/Timeline";`
Returns a timeline object, an instance of the Timeline
class.
let timeline = new Timeline();
Name |
Type |
Default Value |
Read Only |
Description |
duration |
number |
|
|
How long this timeline will take to complete once started, in ms. |
fraction |
number |
|
|
The fraction of this timeline that has completed, as a decimal between 0 and 1. Setting the fraction is equivalent to calling seekTo(fraction * duration) . |
time |
number |
|
|
The amount of time the timeline has completed, in ms. This should not be modified directly — use seekTo(time) instead. |
from(target, fromProperties, duration, [easing, delay])
Argument |
Type |
Description |
target |
object |
The object that will have its properties tweened by the timeline. |
fromProperties |
object |
The keys of this object are the properties of the target object that will be tweened by the timeline. Their values are the starting values the properties of the target object will have at the begining of the tween. |
duration |
number |
The duration of the tween in ms. |
easing |
number |
An easing function to use for the tween. If null is provided, the tween will use a linear easing function. |
delay |
number |
The number of ms after the previous tween in the timeline completes that this one should begin. If this number is negative, the tween will begin before the prior tween completes. If no duration is provided, the tween will begin immediately upon completion of the prior tween. |
Adds a "from tween" to the timeline. A "from tween" eases the properties of the target
object from the values specified in the toProperties
object to the original values of the target
object over duration
ms.
Returns this timeline, useful for chaining together multiple to
, from
, and on
calls.
let sampleStyle = new Style({ font: "600 28px Open Sans", color: ["blue", "white"] });
let sampleColumn = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }), style: sampleStyle,
contents: [
Label(null, { top: 90, height: 28, left: 80, string: "Hello", state: 0 }),
Label(null, { top: 2, height: 28, left: 80, string: "Moddable", state: 0 }),
],
Behavior: class extends Behavior {
onDisplaying(column) {
let timeline = this.timeline = new Timeline();
timeline.from(column.first, { x: -column.first.width, state: 1 }, 1000, Math.quadEaseOut, 0)
.from(column.last, { x: application.width, state: 1 }, 800, Math.quadEaseOut, -800);
column.duration = timeline.duration;
timeline.seekTo(0);
column.time = 0;
column.start();
}
onTimeChanged(column) {
this.timeline.seekTo(column.time);
}
}
});
application.add(sampleColumn);
on(target, onProperties, duration, easing, delay, when)
Argument |
Type |
Description |
target |
object |
The object that will have its properties tweened by the timeline. |
onProperties |
object |
The keys of this object are the properties of the target object that will be tweened by the timeline. Their values are arrays of values that the tween will ease between over the duration of the timeline. |
duration |
number |
The duration of the tween in ms. |
easing |
number |
An easing function to use for the tween. If null is provided, the tween will use a linear easing function. |
delay |
number |
The number of ms after the previous tween in the timeline completes that this one should begin. If this number is negative, the tween will begin before the prior tween completes. If no duration is provided, the tween will begin immediately upon completion of the prior tween. |
Adds an "on tween" to the timeline. An "on tween" eases the values of the target
object through a sequence of steps as specified by arrays in the onProperties
object over duration
ms.
Returns this timeline, useful for chaining together multiple to
, from
, and on
calls.
let sampleContainer = new Container(null, {
top: 0, bottom: 0, left: 0, right: 0, skin: new Skin({ fill: "white" }),
contents: [
Content(null, { top: 0, height: 50, left: 0, width: 50, skin: new Skin({ fill: ["blue", "red"] }) })
],
Behavior: class extends Behavior {
onDisplaying(container) {
this.startAnimation(container);
}
startAnimation(container) {
let timeline = this.timeline = new Timeline();
let l=0, r=150, b=150, t=0;
timeline.on(container.first, { x: [l, r, r, l, l], y: [t, t, b, b, t], state: [0, 1] }, 1000, Math.quadEaseInOut, 500);
container.duration = timeline.duration;
timeline.seekTo(0);
container.time = 0;
container.start();
}
onTimeChanged(container) {
let time = container.time;
if (this.reverse) time = container.duration - time;
this.timeline.seekTo(time);
}
onFinished(container) {
this.reverse = !this.reverse;
this.startAnimation(container);
}
}
});
application.add(sampleContainer);
seekTo(time)
Argument |
Type |
Description |
time |
number |
The position in the Timeline to seek to. |
Causes this timeline to jump its tweens to the specified time. This sets the properties of the tweens' target objects.
to(target, toProperties, duration, [easing, delay])
Argument |
Type |
Description |
target |
object |
The object that will have its properties tweened by the timeline. |
toProperties |
object |
The keys of this object are the properties of the target object that will be tweened by the timeline. Their values are the destination values the properties of the target object will have when the tween is complete. |
duration |
number |
The duration of the tween in ms. |
easing |
number |
An easing function to use for the tween. If null is provided, the tween will use a linear easing function. |
delay |
number |
The number of ms after the previous tween in the timeline completes that this one should begin. If this number is negative, the tween will begin before the prior tween completes. If no duration is provided, the tween will begin immediately upon completion of the prior tween. |
Adds a "to tween" to the timeline. A "to tween" eases the properties of the target
object from its current values to the desired values specified in the toProperties
object over duration
ms.
Returns this timeline, useful for chaining together multiple to
, from
, and on
calls.
let sampleStyle = new Style({ font: "600 28px Open Sans", color: ["blue", "white"] });
let sampleColumn = new Column(null, {
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: "white" }), style: sampleStyle,
contents: [
Label(null, { top: 90, height: 28, left: 80, string: "Hello", state: 0 }),
Label(null, { top: 2, height: 28, left: 80, string: "Moddable", state: 0 }),
],
Behavior: class extends Behavior {
onDisplaying(column) {
let timeline = this.timeline = new Timeline();
timeline.to(column.first, { x: -column.first.width, state: 1 }, 1000, Math.quadEaseOut, 1000)
.to(column.last, { x: application.width, state: 1 }, 800, Math.quadEaseOut, -800);
column.duration = timeline.duration;
timeline.seekTo(0);
column.time = 0;
column.start();
}
onTimeChanged(column) {
this.timeline.seekTo(column.time);
}
}
});
application.add(sampleColumn);
The transition
object is used to animate modifications of the containment hierarchy.
Applications define their own constructors for transition
objects, which inherit from Transition.prototype
and override the onBegin
, onEnd
, and onStep
functions.
class BasicLeftToRightTransition extends Transition {
constructor(duration) {
super(duration);
}
onBegin(container, current, next) {
container.add(next);
this.die = new Die();
this.die.attach(next);
this.width = container.width;
this.height = container.height;
}
onStep(fraction) {
fraction = Math.quadEaseOut(fraction);
let left = 0, right = Math.round(this.width * fraction);
this.die.set(left, 0, right - left, this.height);
this.die.cut();
}
onEnd(container, current, next) {
this.die.detach();
container.remove(current);
}
}
Container
objects use instances of transition
objects as a parameter to their run
function.
class SwitchScreenBehavior extends Behavior {
onCreate(content, data) {
this.data = data;
}
onTouchEnded(content) {
let data = this.data;
let transition = new BasicLeftToRightTransition(1000);
let nextScreen = new ColoredScreen({ color: data.nextColor, nextColor: data.color })
application.run(transition, application.first, nextScreen);
}
}
let ColoredScreen = Container.template($ => ({
top: 0, bottom: 0, left: 0, right: 0,
skin: new Skin({ fill: $.color }),
contents: [
Content($, {
active: true, height: 100, width: 100,
skin: new Skin({ fill: $.nextColor }),
Behavior: SwitchScreenBehavior
})
]
}));
application.add(new ColoredScreen({ color: "red", nextColor: "blue" }));
Prototype inherits from Object.prototype
.
Name |
Type |
Default Value |
Read Only |
Description |
duration |
number |
250 |
|
The duration of the transition, in milliseconds |
onBegin(container [, ...])
Argument |
Type |
Description |
container |
container |
The container object that is running the transition |
... |
* |
Zero or more extra parameters |
Invoked when this transition starts. The extra parameters are the extra parameters of the call to the run
function that bound this transition to the specified container
object.
onEnd(container [, ...])
Argument |
Type |
Description |
container |
container |
The container object that is running the transition |
... |
* |
Zero or more extra parameters |
Invoked when this transition ends. The extra parameters are the extra parameters of the call to the run
function that bound this transition to the specified container
object.
onStep(fraction)
Argument |
Type |
Description |
fraction |
number |
The ratio of the time elapsed and the duration of this transition, as a number between 0 and 1 (inclusive) |
Called while this transition is running; called at least twice (with a fraction
parameter of 0 and 1) and at most at the display refresh rate--for example, 60 times a second