Custom Drawing
Some features in PinballY let you do your own custom drawing from
Javascript code. This lets you create a custom mix of text and
graphics with the precise pixel layout you want. Custom drawing
can be used in the following places:
- Popups - message boxes displayed in
the main window. To do custom drawing in a popup box, provide a
custom drawing function in the draw() property of the parameter
object when you call the mainWindow.showPopup method.
The system will call your custom drawing function as part of the
showPopup() processing.
- Drawing layers - custom graphics
layers that you can create in any of the windows through scripting code.
You can create a drawing layer via the
createDrawingLayer() method on any
of the system window objects (mainWindow, backglassWindow, etc).
That method returns an object representing the new drawing layer,
which you can draw custom graphics into using its
draw() method.
- Launch overlays -
the graphics layers shown during a game launch to provide status
updates on the progress of the launch. The system lets you access
these layers through objects that you can get through the fg
and bg properties of
mainWindow.launchOverlay.
To display custom graphics in these layers, call the
draw() method on the launch overlay
layer object, passing a reference to your custom drawing function as the argument.
Creating a custom drawing function
The procedure to carry out custom drawing is a little indirect. You
can't just execute drawing primitives like "draw a rectangle" from anywhere
in Javascript code. Instead, all of your custom drawing code has to be contained
within a "custom drawing function". This is just an ordinary Javascript
function, with the following signature:
function myDrawingFunction(dc)
{
// carry out the drawing primitives here
}
The name of the function is arbitrary - you can call it anything you
want, and you can create as many different drawing functions as you
want, all with different names. What's important is that it's a
function that takes one parameter, which we've called dc
here for "drawing context". The parameter name (like the function
name) is up to you, though - you can call it anything you want.
The dc or drawing context argument is a special system
object that the system creates and passes to your drawing function
when it invokes the function. The drawing context contains the
system methods that let you carry out the actual graphic operations,
such as drawing rectangles, text, and images. This object is only
valid for the duration of the function call to the drawing function,
so you shouldn't store it in a global variable or otherwise hang
onto it. Treat it as a temporary object that exists for the
duration of the function call only.
The system calls this function after setting up the graphics
area for the drawing. The argument to the function is a "drawing
context" object, which has methods that let you draw text and
graphics into the popup area.
Return value from the drawing function
The return value from the drawing function depends on the context
where you're using the function:
- For popups, the return value indicates the desired height in
pixels for the popup. This is only needed if you create the
popup with an indeterminate height. Using an indeterminate height
allows you to precisely size the overall popup according to the
actual contents, by measuring the sizes of the items you draw
within the box.
- For launch overlays (foreground or background layers), the
return value isn't used.
Drawing context
When the system calls your custom drawing function, it passes
in an argument that we call the drawing context. This
is a Javascript object that encapsulates the internal drawing
surface that all of the graphics primitives operate on. The
drawing context provides a set of properties and methods that
you call to carry out drawing operations on the drawing surface.
The drawing surface contained in the context is, technically
speaking, an in-memory bitmap. More intuitively, it's like
opening up a new, blank Photoshop image: it's a drawing
canvas with a certain pixel size, and you can use the
graphics primitives (the methods on the drawing context
object) to paint different sorts of graphics into the
blank image.
A drawing context is only valid within the custom drawing
function. It stops being usable as soon as the drawing
function returns (so you shouldn't store it anywhere global,
to avoid accidentally using it in other scripts, where it
would cause errors if used).
Color values
Several of the drawing context methods take color values as
arguments. You can specify these in several ways:
- As a hex integer value, in the format 0xAARRGGBB, where
AA is the alpha (transparency) value, RR is the red component,
GG is the green component, and BB is the blue component.
Each can range from 00 to FF hex. For example, 0xFF0000FF
represents opaque red (FF for the alpha component, or
completely opaque, and FF for the red component, for maximum
brightness in that component).
If you're familiar with HTML "#rrggbb" color values, these values
will look almost the same, with the differences that you replace
the "#" sign with the Javascript "hex" prefix 0x, and you
always have to add an FF at the beginning to indicate that
the color is opaque. For example, the HTML color code #123456 would
be written in your custom drawing code as 0xFF123456.
In this format, if the alpha component (AA) is zero, the
defaultAlpha property of the drawing context is
automatically used. See "Default alpha values" below.
- As an HTML-style "#RGB" color string. For example, #00F
represents solid red. For HTML-style colors, the opacity
is always fully opaque.
- As an HTML-style "#RRGGBB" color string. The opacity with
this format is always fully opaque.
- As a pseudo-HTML string in the format "#AARRGGBB". In
other words, the normal HTML color format, with the addition of
an alpha component (the "AA" portion), to let you specify an
alpha value explicitly.
- As the name of a configuration variable from the settings
file. This lets you refer to color from the settings rather
than having to look it up as a separate step.
Default alpha value
For convenience, you don't have to specify the alpha value in each
individual color parameter.
- For a color parameter passed as a hex integer value, if the
alpha component is zero, the default alpha value from the drawing
context is automatically used.
- For a color passed as an HTML-style "#RGB" or "#RRGGBB" string,
full opacity (alpha FF) is always used, regardless of the default
alpha in the drawing context.
The default alpha value is given by the defaultAlpha property
of the drawing context. You can read this property to get the current
default, and write it to set the new default that will apply to
subsequent method calls on the drawing context.
The system always sets defaultAlpha to 0xFF before calling your
custom drawing function. (This happens on every call to a custom
drawing function, so you don't have to worry about whether other drawing
functions that were called before the current one might have changed it.)
Note that if you explicitly want to draw an area with an alpha of 00,
meaning fully transparent, you must set defaultAlpha to zero first.
Since the system always replaces a zero alpha in a color parameter with
the default alpha value, the only way to actually get a zero alpha in
the final color setting is to set the default to zero. That will replace
the 00 alpha you specify in the color parameter with the 00 in the
defaultAlpha property, leaving the zero alpha unchanged for
the final coloring.
Text drawing
The drawing context methods below include a number of primitives
related to drawing text strings. Those are suitable for simple
text displays where you only need to display text in a single style
at a time; for simple tasks, they're easy to use and lightweight
in terms of performance impact. However, they're not powerful
enough for more complex tasks where you want to display text
containing a mixture of styles, especially if the text needs
to be word-wrapped to display paragraphs or more complex
layouts. For something like
that, you should instead use StyledText
or HtmlLayout. Those
classes provide higher-level interfaces for complex text
layout tasks, and they both readily inter-operate with the
primitives discussed below, so you can freely mix formatted text
layouts with the other graphics to build up composite displays.
Drawing context methods
The drawing context has the following methods:
- defaultAlpha: A property giving the default alpha component to
apply to any color parameter passed to fillRect(), frameRect(), or setTextColor()
that has a zero alpha. For example, if defaultAlpha is 0x80 (meaning
50% transparency), and you pass color code 0x0000ff (blue) to fillRect(), the system
will notice the zero alpha in your color code and substitute the 0x80 default,
for a final rectangle fill color of 0x800000ff (blue with 50% transparency).
On the other hand, if you pass a color code of 0xFF0000FF, the alpha in the
color code is already non-zero, so the default is not applied and the
actual drawing color is the same as the value you specify. Note that you
must set defaultAlpha to zero if you actually want to be able to draw
fully transparent areas, since any other value would override a zero alpha
you specify in a color parameter. The system always sets this to 0xFF
(fully opaque) before each call to a custom drawing function, so
that all drawing is fully opaque by default.
- drawImage(file, x, y, width, height):
Draw an image. file is the name of the image file (JPEG and PNG formats are supported);
this can be an absolute path, or can be a path relative to the PinballY program folder.
x and y give the top left coordinates in pixels within the popup drawing area.
- drawText(string):
Draws the text in string, starting at
the current text origin, within the current text area boundaries, using the
current text font and color. This automatically moves the text origin so that
the next drawText() call will place its text after this text. If string
ends in a newline character ("\n"), the text origin is advanced to the start
of the next "line", vertically just below the drawn text and at the left edge
of the text area. If string doesn't end in a newline, the text origin
is positioned immediately to the right of the drawn text.
See HtmlLayout and StyledText
for alternative ways of
drawing more complex layouts that include mixed styles. drawText() can only
draw text in one font style at a time, so it's difficult to use if
you want to mix multiple font styles within a single text display. HtmlLayout
and StyledText provide higher-level interfaces for more complex layouts, and
they inter-operate with the rest of the Custom Drawing primitives, so they're
like "super" versions of drawText() that work on styled text instead of
plain text.
- fillRect(x, y, width, height, color): Fills
a rectangle at the given position and dimensions with the given color.
The coordinates are in pixels relative to the popup drawing area,
and the dimensions are in pixels. The color is given as an 0xAARRGGBB value,
where AA is the alpha transparency (00 for fully
transparent, FF for fully opaque), RR is the red component (00 to FF), GG is
the green component, and BB is the blue component.
- frameRect(x, y, width, height, frameWidth, color):
Draws an outline of the given width in pixels around the specified rectangle. The color
is an 0xAARRGGBB value with alpha transparency, as with fillRect(). The frame is drawn such that each frame line is
centered on the edge of the specified rectangle. For example, if you draw a 4-pixel
frame, two of the pixels of each edge will be drawn outside the given rectangle
area and two of the pixels will be inside the rectangle area.
- getImageSize(filename): Returns an object with properties {width: integer, height: integer}
giving the dimensions in pixels of the given image file.
- getSize(): Returns an object with properties {width: integer, height: integer}
giving the dimensions in pixels of the popup drawing area.
For popup boxes, if you use the "dynamic layout height" option to figure the
popup's height based on its contents, the reported height will be invalid during
the first pass, because the whole point of the first pass is to calculate the
required height. See Dynamic layout height
in Popups.
- getTextOrigin(): Returns an object with properties {x: integer, y: integer}
giving the current text origin, in pixel coordinates within the popup drawing
area. This reflects the updates to the origin made by any drawText() calls, so
it's helpful when laying out text across multiple lines. It's also useful for
calculating the layout height of a popup box dynamically; see
Dynamic layout height
in Popups.
- measureText(string): Figures the pixel area required to display
the given text. Returns an object with properties {left: integer, top: integer,
right: integer, bottom: integer, width: integer, height: integer},
giving the pixel positions and dimensions of the bounding box the text would occupy
if drawn at the current text origin. Note that this doesn't take into
account line wrapping; it measures the text as though it were going to be laid
out in an infinitely widely boundary area.
- setFont(name, pointSize, weight, italic):
Sets the text font to use for subsequent drawText() and measureText() calls.
Any of the arguments can be passed as undefined to keep the values
for the current font; for example, you can change just the point size, keeping
the current weight, by calling dc.setFont(undefined, 24). The
weight value is from 100 to 900; for most fonts, 400 is the normal weight
and 700 is bold. (Some fonts have extra-light and extra-bold variations,
which is why the range is wider than 400-700, and some have semi-bold
variations between normal and bold.)
- setFontFromPrefs(str): Sets the text font for subsequent
drawText() and measureText() calls to a font specified in the current
user settings. str is a string giving the name of a configuration
variable that refers to a font. This can be any variable name in the
settings, including custom variables. The standard font option
variable names are:
- MenuFont: menu items
- PopupFont: base font for popup dialogs and messages
- PopupTitleFont: large font for title text in popups
- PopupSmallerFont: smaller text font in popups
- PopupDetailFont: even smaller detail text font in popups
- MediaDetailFont: small font for line items in media file listings
- WheelFont: game titles in the wheel when logos aren't available
- HighScoreFont: font for the high score list in the info box
- InfoBoxTitleFont: large font for title text in info box displays
- InfoBoxFont: font for main text in info box displays
- InfoBoxDetailFont: small font for fine print in info box displays
- StatusFont: status line font
- CreditsFont: credits message font
Alternatively, you can use the string to specify the font information
using the format that's used in the font preference settings, without
actually looking in the setting for a variable. The format is
"pointSize weight/style family", where
pointSize is an integer giving the size in points of the text;
weight/style is a combination of weight (100 to 900, or
one of the standard weight names: thin, extralight, light, normal,
medium, semibold, bold, ultrabold, black) and/or style ("regular"
or "italic"), with a slash "/" separating them if both are included;
and family is the font name as its appears in the Windows Fonts
control panel. For example, "24 bold/italic Tahoma".
- setTextAlign(horz, vert): Sets the text alignment
for drawText(). Either parameter can be set to undefined to keep the
current alignment for that dimension. For horz, -1 means left
alignment, 0 is center alignment, and 1 is right alignment. For
vert, -1 is top alignment, 0 is vertically centered, and
1 is bottom alignment. When drawing, the alignments are relative to the
current text area and the current text origin.
- setTextArea(x, y, width, height):
Sets the boundaries of the current text area. The coordinates and dimensions
are specified in pixels relative to the popup drawing area. The text
boundaries are used for word-wrapping and alignment in drawText().
- setTextColor(color): Sets the color for text drawn
with drawText(), as an 0xAARRGGBB value, with alpha transparency (the AA
component), the same as in fillRect().
- setTextOrigin(x, y): Sets the text origin
for the next call to drawText(). The coordinates are in pixels relative
to the popup drawing area.