Slots
Slots are boxes used to lay out images, text and so on. The two most common
slots are stacks
and flows
. Slots can also be referred to as "boxes" or
"canvases" in Shoes terminology.
Since the mouse wheel and PageUp and PageDown are so pervasive on every platform, vertical scrolling has really become the only overflow that matters. So, in Shoes, just as on the web, width is generally fixed. While height goes on and on.
Now, you can also just use specific widths and heights for everything, if you want. That'll take some math, but everything could be perfect.
Generally, I'd suggest using stacks and flows. The idea here is that you want to fill up a certain width with things, then advance down the page, filling up further widths. You can think of these as being analogous to HTML's "block" and "inline" styles.
Stacks
A stack is simply a vertical stack of elements. Each element in a stack is placed directly under the element preceding it.
A stack is also shaped like a box. So if a stack is given a width of 250, that stack is itself an element which is 250 pixels wide.
To create a new stack, use the stack method, which is available inside any slot. So stacks can contain other stacks and flows.
Flows
A flow will pack elements in as tightly as it can. A width will be filled, then will wrap beneath those elements. Text elements placed next to each other will appear as a single paragraph. Images and widgets will run together as a series.
Like the stack, a flow is a box. So stacks and flows can safely be embedded and, without respect to their contents, are identical. They just treat their contents differently.
Making a flow means calling the flow method. Flows may contain other flows and stacks.
Last thing: The Shoes window itself is a flow.
Art for slots
Each slot is like a canvas, a blank surface which can be covered with an assortment of colored shapes or gradients.
Many common shapes can be drawn with methods like oval
and rect
. You'll need to set up the paintbrush colors first, though.
The stroke
command sets the line color. And the fill
command sets the color used to paint inside the lines.
Shoes.app do
stroke red
fill blue
oval :top => 10, :left => 10,
:radius => 100
end
That code gives you a blue pie with a red line around it. One-hundred pixels wide, placed just a few pixels southeast of the window's upper left corner.
The blue
and red
methods above are Color objects. See the section on Colors for more on how to mix colors.
Inspiration from Processing and NodeBox
The artful methods generally come verbatim from NodeBox, a drawing kit for Python. In turn, NodeBox gets much of its ideas from Processing, a Java-like language for graphics and animation. I owe a great debt to the creators of these wonderful programs!
Shoes does a few things differently from NodeBox and Processing. For example, Shoes has different color methods, including having its own Color objects, though these are very similar to Processing's color methods. And Shoes also allows images and gradients to be used for drawing lines and filling in shapes.
Shoes also borrows some animation ideas from Processing and will continue to closely consult Processing's methods as it expands.
arc(left, top, width, height, angle1, angle2) » Shoes::Shape
Draws an arc shape (a section of an oval) at coordinates (left, top). This
method just give you a bit more control than oval, by offering the
:angle1
and :angle2
styles. (In fact, you can mimick the oval
method by
setting :angle1
to 0 and :angle2
to Shoes::TWO_PI
.)
Shoes.app do
fill red
arc self.width / 2, self.height / 2, 150, 75, Shoes::PI, 0
fill green
arc self.width / 2, self.height / 2, 150, 75, 0, Shoes::PI
end
arrow(left, top, width) » Shoes::Shape
Draws an arrow at coordinates (left, top) with a pixel width
.
Shoes.app do
arrow 100, 100, 50
end
cap(:curve or :rect or :project) » self
Sets the line cap, which is the shape at the end of every line you draw. If
set to :curve
, the end is rounded. The default is :rect
, a line which ends
abruptly flat. The :project
cap is also fat, but sticks out a bit longer.
Shoes.app do
[:curve, :rect, :project].each_with_index do |n, m|
cap n
strokewidth 5
stroke rgb(rand(255), rand(255), rand(255))
line 50, 50 + (m * 25), self.width - 50, 50 + (m * 25)
end
end
fill(pattern) » pattern
Sets the fill bucket to a specific color (or pattern.) Patterns can be colors, gradients or images. So, once the fill bucket is set, you can draw shapes and they will be colored in with the pattern you've chosen.
To draw a star with an image pattern:
Shoes.app do
fill "#{DIR}/static/avatar.png"
star 200, 200, 5
end
To clear the fill bucket, use nofill
. And to set the line color (the border
of the star,) use the stroke
method.
nofill() » self
Blanks the fill color, so that any shapes drawn will not be filled in. Instead, shapes will have only a lining, leaving the middle transparent.
nostroke() » self
Empties the line color. Shapes drawn will have no outer line. If nofill
is
also set, shapes drawn will not be visible.
line(left, top, x2, y2) » Shoes::Shape
Draws a line using the current line color (aka "stroke") starting at coordinates (left, top) and ending at coordinates (x2, y2).
Shoes.app do
100.times do |n|
strokewidth rand(10)
stroke rgb(rand(255), rand(255), rand(255))
line rand(self.width), rand(self.height), rand(self.width), rand(self.height)
end
end
Mask() » Shoes::Mask
Mask is a slot allowing to clip elements outside its own area. The size and frame of the area is defined by a number of Shoes elements - shapes, images and texts.
In the example below there are two same colour slots. The left slot is drawn with a green star while the right slot contains the green star used as a clipping mask. Notice how the colour of the star is not taken into account.
Shoes.app width: 300, height: 150 do
flow width: 0.5, height: 1.0 do
background orange
star left: 75, top: 75, points: 6, outer: 40, inner: 9, fill: green
end
flow width: 0.5, height: 1.0 do
background orange
mask do
star left: 75, top: 75, points: 6, outer: 40, inner: 9, fill: green
end
end
end
Next the same setup is used but this time an image is used for clipping.
Shoes.app width: 300, height: 150 do
flow width: 0.5, height: 1.0 do
background orange
image "#{DIR}/static/shoes-icon.png", left: 25, top: 25, width: 100
end
flow width: 0.5, height: 1.0 do
background orange
mask do
image "#{DIR}/static/shoes-icon.png", left: 25, top: 25, width: 100
end
end
end
Texts can be used for their shape too.
Shoes.app width: 400, height: 100 do
flow width: 0.5, height: 1.0 do
background orange
title "SHOES!", weight: "ultrabold", align: "center"
end
flow width: 0.5, height: 1.0 do
background orange
mask do
title "SHOES!", weight: "ultrabold", align: "center"
end
end
end
Check the sample directory for more examples.
oval(left, top, radius) » Shoes::Shape
Draws a circular form at pixel coordinates (left, top) with a width and height
of radius
pixels. The line and fill colors are used to draw the shape. By
default, the coordinates are for the oval's leftmost, top corner, but this can
be changed by calling the transformo method or by using the :center
style on the next method below.
Shoes.app do
stroke blue
strokewidth 4
fill black
oval 10, 10, 50
end
To draw an oval of varied proportions, you may also use the syntax: oval(left, top, width, height)
.
oval(styles) » Shoes::Shape
Draw circular form using a style hash. The following styles are supported:
top
: the y-coordinate for the oval pen.left
: the x-coordinate for the oval pen.radius
: the width and height of the circle.width
: a specific pixel width for the oval.height
: a specific pixel height for the oval.center
: do the coordinates specific the oval's center? (true or false)
These styles may also be altered using the style
method on the Shape object.
rect(top, left, width, height, corners = 0) » Shoes::Shape
Draws a rectangle starting from coordinates (top, left) with dimensions of width x height. Optionally, you may give the rectangle rounded corners with a fifth argument: the radius of the corners in pixels.
As with all other shapes, the rectangle is drawn using the stroke and fill colors.
Shoes.app do
stroke rgb(0.5, 0.5, 0.7)
fill rgb(1.0, 1.0, 0.9)
rect 10, 10, self.width - 20, self.height - 20
end
The above sample draws a rectangle which fills the area of its parent box,
leaving a margin of 10 pixels around the edge. Also see the background
method for a rectangle which defaults to filling its parent box.
rect(styles) » Shoes::Shape
Draw a rectangle using a style hash. The following styles are supported:
top
: the y-coordinate for the rectangle.left
: the x-coordinate for the rectangle.curve
: the pixel radius of the rectangle's corners.width
: a specific pixel width for the rectangle.height
: a specific pixel height for the rectangle.center
: do the coordinates specific the rectangle's center? (true or false)
These styles may also be altered using the style
method on the Shape object.
rotate(degrees: a number) » self
Rotates the pen used for drawing by a certain number of degrees
, so that any
shapes will be drawn at that angle.
In this example below, the rectangle drawn at (30, 30) will be rotated 45 degrees.
Shoes.app do
fill "#333"
rotate 45
rect 30, 30, 40, 40
end
scale(sx: a float, sy: a float) » self
Scales the pen used for drawing by sx an sy in width and height respectively, so that any shapes will be drawn at that scale. Second argument is optional, in which case scaling will be the same in both direction.
0.5 means scaling to half the size, 2.0 doubles the size.
Shoes.app do
nofill
rect 30, 30, 100, 100, stroke: red
fill "#333"
scale 1.2, 0.8
rect 30, 30, 100, 100
end
skew(sx: a float, sy: a float) » self
Skews the pen used for drawing by sx an sy in width and height respectively, so that any shapes will be drawn skewed by those amounts. Second argument is optional, in which case skew happens only horizontally.
Shoes.app do
fill "#333"
skew 7.5, 9.5
rect 30, 30, 100, 100
end
shape(left, top) { ... } » Shoes::Shape
Describes an arbitrary shape to draw, beginning at coordinates (left, top) and
continued by calls to line_to
, move_to
, curve_to
and arc_to
inside the
block. You can look at it as sketching a shape with a long line that curves
and arcs and bends.
Shoes.app do
fill red(0.2)
shape do
move_to(90, 55)
arc_to(50, 55, 50, 50, 0, Shoes::PI/2)
arc_to(50, 55, 60, 60, Shoes::PI/2, Shoes::PI)
arc_to(50, 55, 70, 70, Shoes::PI, Shoes::TWO_PI-Shoes::PI/2)
arc_to(50, 55, 80, 80, Shoes::TWO_PI-Shoes::PI/2, Shoes::TWO_PI)
end
end
A shape can also contain other shapes. So, you can place an oval, a rect, a line, a star or an arrow (and all of the other methods in this art section) inside a shape, but they will not be part of the line. They will be more like a group of shapes are all drawn as one.
shape(styles) { ... } » Shoes::Shape
Describes an arbitrary shape to draw, initialized using a style hash. The following styles are relevant:
top
: the y-coordinate for the shape.left
: the x-coordinate for the shape.center
: do the coordinates specifie the rectangle's center? (true or false).cap
: sets the line endpoints of the shape.stroke
: color of the outline of the shape.strokewidth
: size of the outline of the shape.fill
: color of the shape.
These styles may also be altered using the style
method on the Shape object.
star(left, top, points = 10, outer = 100.0, inner = 50.0) » Shoes::Shape
Draws a star using the stroke and fill colors. The star is positioned with its
center point at coordinates (left, top) with a certain number of points
. The
outer
width defines the full radius of the star; the inner
width specifies
the radius of the star's middle, where points stem from.
Shoes.app do
10.times do |n|
fill rgb(rand(255), rand(255), rand(255))
star rand(self.width) + 50, rand(self.height) + 50, rand(10) + 5, rand(50) + 50, rand(50)
end
end
stroke(pattern) » pattern
Set the active line color for this slot. The pattern
may be a color, a
gradient or an image, all of which are categorized as "patterns." The line
color is then used to draw the borders of any subsequent shape.
So, to draw an arrow with a red line around it:
Shoes.app do
stroke red
arrow 100, 100, 50
end
To clear the line color, use the nostroke
method.
strokewidth(a number) » self
Sets the line size for all drawing within this slot. Whereas the stroke
method alters the line color, the strokewidth
method alters the line size in
pixels. Calling strokewidth(4)
will cause lines to be drawn 4 pixels wide.
transform(:center or :corner) » self
Should transformations (such as skew
and rotate
) be performed around the
center of the shape? Or the corner of the shape? Shoes defaults to :corner
.
translate(left, top) » self
Moves the starting point of the drawing pen for this slot. Normally, the pen
starts at (0, 0) in the top-left corner, so that all shapes are drawn from that
point. With translate
, if the starting point is moved to (10, 20) and a
shape is drawn at (50, 60), then the shape is actually drawn at (60, 80) on the
slot.
Element Creation
Shoes has a wide variety of elements, many cherry-picked from HTML. This page describes how to create these elements in a slot. See the Elements section of the manual for more on how to modify and use these elements after they have been placed.
animate(fps) { |frame| ... } » Shoes::Animation
Starts an animation timer, which runs parallel to the rest of the app. The
fps
is a number, the frames per seconds. This number dictates how many times
per second the attached block will be called.
The block is given a frame
number. Starting with zero, the frame
number
tells the block how many frames of the animation have been shown.
Shoes.app do
@counter = para "STARTING"
animate(24) do |frame|
@counter.replace "FRAME #{frame}"
end
end
The above animation is shown 24 times per second. If no number is given, the
fps
defaults to 10.
background(pattern) » Shoes::Background
Draws a Background element with a specific color (or pattern.) Patterns can be colors, gradients or images. Colors and images will tile across the background. Gradients stretch to fill the background.
Shoes.app do
background black
background white, :width => 50
end
The above example paints two backgrounds. First, a black background is painted over the entire app's surface area. Then a 50 pixel white stripe is painted along the left side.
Background are reusable and can be copied because they inherit from Pattern.
Shoes.app do
stack(left: 0, top: 0, width: width / 4, height: height / 4) do
@b = background "#{DIR}/static/stripe.png"
end
4.times do |n|
stack(left: n * width / 4, top: n * height / 4, width: width / 4, height: height / 4) do
background @b
end
end
end
Once a background is created it's size and location won't change unless the slot is resized. If the slot has a scroll bar it may do what you think. Scroll thru this example:
Shoes.app(title: "No Scroll", width: 300, height: 400, resizable: true ) do
background green
@main = stack left: 0.05, top: 0.15, width: 0.9, height: 0.8, scroll: true do
background beige
100.times do |i|
para "#{i+1} times"
end
end
end
As of Shoes 3.3.3, You can ask Shoes to be more respectful of scrolling by setting scroll: true as this example does
Shoes.app(title: "Scroll", width: 300, height: 400, resizable: true ) do
background green
@main = stack left: 0.05, top: 0.15, width: 0.9, height: 0.8, scroll: true do
background beige, scroll: true
100.times do |i|
para "#{i+1} times"
end
end
end
Be careful when using scroll: true. It may find a scrollbar you didn't want to use and it's not Shoes 4 compatible.
PLEASE NOTE: Backgrounds are actual elements, not styles. HTML treats backgrounds like styles. Which means every box can only have one background. Shoes layers background elements.
banner(text) » Shoes::Banner
Creates a Banner text block. Shoes automatically styles this text to 48 pixels high.
border(text, :strokewidth => a number) » Shoes::Border
Draws a Border element using a specific color (or pattern). Patterns can be colors, gradients or images. Colors and images will tile across the border. Gradients stretch to fill the border.
border(pattern) » Shoes::Border
Draws a Border element with a specific pattern. Borders are reusable and can be copied because they inherit from Pattern.
Shoes.app do
stack :width => 50, :height => 30 do
@b = border red, :strokewidth => 5
para "=^.^=", :stroke => green
end
12.times do |n|
stack :left => n * 50, :top => height / 2, :width => 50 do
border @b
para "=^.^=", :stroke => green
end
end
end
PLEASE NOTE: Like Backgrounds, Borders are actual elements, not styles. HTML treats backgrounds and borders like styles. Which means every box can only have one borders. Shoes layers border and background elements, along with text blocks, images, and everything else.
button(text) { ... } » Shoes::Button
Adds a push button with the message text
written across its surface. An
optional block can be attached, which is called if the button is pressed.
Shoes.app do
button("push me") { alert "How dare ya!" }
end
caption(text) » Shoes::Caption
Creates a Caption text block. Shoes styles this text to 14 pixels high.
check() » Shoes::Check
Adds a check box.
code(text) » Shoes::Code
Create a Code text fragment. This text defaults to a monospaced font.
Shoes.app do
para code %q[
Shoes.app do
para "Shoes version #{Shoes::VERSION_NUMBER}"
end
]
end
del(text) » Shoes::Del
Creates a Del text fragment (short for "deleted") which defaults to text with a single strikethrough in its middle.
dialog(styles) { ... } » Shoes::App
Opens a new app window (just like the window method does,) but the window is given a dialog box look.
edit_box(text) » Shoes::EditBox
Adds a large, multi-line textarea to this slot. The text
is optional and
should be a string that will start out the box. An optional block can be
attached here which is called any type the user changes the text in the box.
Shoes.app do
edit_box
edit_box "HORRAY EDIT ME"
edit_box "small one", :width => 100, :height => 160
end
edit_line(text) » Shoes::EditLine
Adds a single-line text box to this slot. The text
is optional and should be
a string that will start out the box. An optional block can be attached here
which is called any type the user changes the text in the box.
em(text) » Shoes::Em
Creates an Em text fragment (short for "emphasized") which, by default, is styled with italics.
every(seconds) { |count| ... } » Shoes::Every
A timer similar to the animation
method, but much slower. This timer fires a
given number of seconds, running the block attached. So, for example, if you
need to check a web site every five minutes, you'd call every(300)
with a
block containing the code to actually ping the web site.
flow(styles) { ... } » Shoes::Flow
A flow is an invisible box (or "slot") in which you place Shoes elements. Both flows and stacks are explained in great detail on the main Slots page.
Flows organize elements horizontally. Where one would use a stack to keep things stacked vertically, a flow places its contents end-to-end across the page. Once the end of the page is reached, the flow starts a new line of elements.
image(path) » Shoes::Image
Creates an image element for displaying a picture. PNG, JPEG and GIF formats are allowed.
The path
can be a file path or a URL. All images loaded are temporarily
cached in memory, but remote images are also cached locally in the user's
personal Shoes directory. Remote images are loaded in the background; as with
browsers, the images will not appear right away, but will be shown when they
are loaded.
You can disable the remote image caching in several ways. For just this image, append the hash arg 'cache: false` See AppMethods for the global way.
imagesize(path) » [width, height]
Quickly grab the width and height of an image. The image won't be loaded into the cache or displayed.
URGENT NOTE: This method cannot be used with remote images (loaded from HTTP, rather than the hard drive.)
ins(text) » Shoes::Ins
Creates an Ins text fragment (short for "inserted") which Shoes styles with a single underline.
inscription(text) » Shoes::Inscription
Creates an Inscription text block. Shoes styles this text at 10 pixels high.
link(text, :click => proc or string) » Shoes::Link
Creates a Link text block, which Shoes styles with a single underline and colors with a #06E (blue) colored stroke.
The default LinkHover style is also single-underlined with a #039 (dark blue) stroke.
Shoes.app do
para link("click here\n", click: proc { |btn, left, top|
alert "#{btn}, #{left}, #{top}\n"
})
end
list_box(:items => [strings, ...]) » Shoes::ListBox
Adds a drop-down list box containing entries for everything in the items
array. An optional block may be attached, which is called if anything in the
box becomes selected by the user.
Shoes.app do
stack :margin => 10 do
para "Pick a card:"
list_box :items => ["Jack", "Ace", "Joker"]
end
end
Call ListBox#text
to get the selected string. See the ListBox
section
under Native
controls for more help.
progress() » Shoes::Progress
Adds a progress bar.
para(text) » Shoes::Para
Create a Para text block (short for "paragraph") which Shoes styles at 12 pixels high.
radio(group name: a string or symbol) » Shoes::Radio
Adds a radio button. If a group name
is given, the radio button is
considered part of a group. Among radio buttons in the same group, only one
may be checked. (If no group name is given, one is created that only
contains this radio button.
span(text) » Shoes::Span
Creates a Span text fragment, unstyled by default.
stack(styles) { ... } » Shoes::Stack
Creates a new stack. A stack is a type of slot. (See the main Slots page for a full explanation of both stacks and flows.)
In short, stacks are an invisible box (a "slot") for placing stuff. As you add things to the stack, such as buttons or images, those things pile up vertically. Yes, they stack up!
strong(text) » Shoes::Strong
Creates a Strong text fragment, styled in bold by default.
sub(text) » Shoes::Sub
Creates a Sub text fragment (short for "subscript") which defaults to lowering the text by 10 pixels and styling it in an x-small font.
subtitle(text) » Shoes::Subtitle
Creates a Subtitle text block. Shoes styles this text to 26 pixels high.
sup(text) » Shoes::Sup
Creates a Sup text fragment (short for "superscript") which defaults to raising the text by 10 pixels and styling it in an x-small font.
tagline(text) » Shoes::Tagline
Creates a Tagline text block. Shoes styles this text to 18 pixels high.
timer(seconds) { ... } » Shoes::Timer
A one-shot timer. If you want to schedule to run some code in a few seconds (or minutes, hours) you can attach the code as a block here.
To display an alert box five seconds from now:
Shoes.app do
timer(5) do
alert("Your five seconds are up.")
end
end
You can can create timers for fractions of a second: timer(0.1) is something you might see if you poke around inside Shoes
title(text) » Shoes::Title
Creates a Title text block. Shoes styles these elements to 34 pixels high.
video(path or url) » Shoes::Video
Embeds a movie in this slot.
window(styles) { ... } » Shoes::App
Opens a new app window. This method is almost identical to the
Shoes.app method used to start an app in the first place. The
difference is that the window
method sets the new window's owner
property. (A normal Shoes.app has its owner
set to nil
.)
So, the new window's owner
will be set to the Shoes::App which launched the
window. This way the child window can call the parent.
Shoes.app :title => "The Owner" do
button "Pop up?" do
window do
para "Okay, popped up from #{owner}"
end
end
end
Events
Wondering how to catch stray mouse clicks or keyboard typing? Events are sent to a slot whenever a mouse moves inside the slot. Or whenever a key is pressed. Even when the slot is created or destroyed. You can attach a block to each of these events.
Mouse events include motion
, click
, wheel
, hover
and leave
. Keyboard typing
is represented by the keypress
event. And the start
and finish
events
indicate when a canvas comes into play or is discarded.
So, let's say you want to change the background of a slot whenever the mouse
floats over it. We can use the hover
event to change the background when the
mouse comes inside the slot. And leave
to change back when the mouse floats
away.
The mouse related events also provide a mods value that reports whether the control, shift or both keys were held down during the event. The mods will be empty (nil), or a string of 'control', 'shift' or 'control_shift'. This was introduced in Shoes 3.3.5. Older scripts still work.
Shoes.app do
s = stack :width => 200, :height => 200 do
background red
hover do
s.clear { background blue }
end
leave do
s.clear { background red }
end
end
end
click { |button, left, top, mods| ... } » self
The click block is called when a mouse button is clicked. The button
is the
number of the mouse button which has been pressed. The left
and top
are
the mouse coordinates at which the click happened.
To catch the moment when the mouse is unclicked, see the release event.
NOTE: only button numbers of 1,2,3 (left, wheel-press, right) are available for all platforms and mice. If you have an exotic mouse you can get higher button numbers but you should not expect other users have such a device.
Shoes.app do
click do |btn, left, top|
para "#{btn}, #{left}, #{top}, \n"
end
end
wheel { |dir, left, top, mods| ...} » self
The wheel block is called when the mouse wheel is scrolled up or down. dir is 0 or 1. Beware! No one knows if 1 is up or down since it can be changed by the users operating system. Like click, wheel is attatched to a slot so you can have many of them.
Shoes.app do
stack height: 200 do
click do |b,l,t|
@p.replace "Stack clicked"
end
@p = para "None"
flow width: 200 do
para "Flow 1"
wheel do |d,l,t|
@p.replace "Flow 1 wheel #{d}"
end
end
flow width: 200 do
para "Flow 2"
click do |b,l,t|
@p.replace "Flow 2 clicked"
end
end
end
wheel {|d,l,t,mods| @p.replace "default slot wheel #{d} #{mods}"}
end
Notice that the mods
is only supplied in the outer most wheel
. Its ignored
if you don't ask for mods.
finish { |self| ... } » self
When a slot is removed, it's finish event occurs. The finish block is
immediately handed self
, the slot object which has been removed.
hover { |self| ... } » self
The hover event happens when the mouse enters the slot. The block gets self
,
meaning the object which was hovered over.
To catch the mouse exiting the slot, check out the leave event.
keydown { |key| ... } » self
Triggered whenever a single key is pressed, the block gets called. The block is sent a key which is a string representing the character (such as the letter or number) on the key. For special keys (not modifiers keys), a Ruby symbol is sent, rather than a string, see keypress for a list of special keys.
Shoes.app {
@info = para "Press a key."
keydown do |k|
@info.replace "#{k} was PRESSED."
end
}
keyup { |key| ... } » self
Triggered whenever a single key is released, the block gets called. The block is sent a key which is a string representing the character (such as the letter or number) on the key. For special keys (not modifiers keys), a Ruby symbol is sent, rather than a string, see keypress for a list of special keys.
Shoes.app {
@info = para "Press a key and release it."
keyup do |k|
@info.replace "#{k} was RELEASED."
end
}
keypress { |key| ... } » self
Whenever a key (or combination of keys) is pressed, the block gets called, and will be repeatedly called as long as it is pressed. The
block is sent a key
which is a string representing the character (such as the
letter or number) on the key. For special keys and key combos, a Ruby symbol
is sent, rather than a string.
So, for example, if Shift-a
is pressed, the block will get the string "A"
.
However, if the F1 key is pressed, the :f1
symbol is received. For
Shift-F1
, the symbol would be :shift_f1
.
The modifier keys are control
, shift
and alt
. They appear in that order.
If Shift-Control-Alt-PgUp
is pressed, the symbol will be
:control_shift_alt_page_up
.
One thing about the shift key. You won't see the shift key on most keys. On
US keyboards, Shift-7
is an ampersand. So you'll get the string "&"
rather
than :shift_5
. And, if you press Shift-Alt-7
on such a keyboard, you'll
get the symbol: :alt_&
. You'll only see the shift modifier on the special
keys listed a few paragraphs down.
Shoes.app do
@info = para "NO KEY is PRESSED."
keypress do |k|
@info.replace "#{k.inspect} was PRESSED."
end
end
Keep in mind that Shoes itself uses a few hotkeys. Alt-Period (:alt_.
),
Alt-Question (:alt_?
) and Alt-Slash (:alt_/
) are reserved for Shoes.
The list of special keys is as follows: :escape
, :delete
, :backspace
,
:tab
, :page_up
, :page_down
, :home
, :end
, :left
, :up
, :right
,
:down
, :f1
, :f2
, :f3
, :f4
, :f5
, :f6
, :f7
, :f8
, :f9
, :f10
,
:f11
and :f12
.
One caveat to all of those rules: normally the Return key gives you a string "\n"
. When pressed with modifier keys, however, you end up with :control_enter
, :control_alt_enter
, :shift_alt_enter
and the like.
leave { |self| ... } » self
The leave event takes place when the mouse cursor exits a slot. The moment it no longer is inside the slot's edges. When that takes place, the block is called with self
, the slot object which is being left.
Also see hover if you'd like to detect the mouse entering a slot.
motion { |left, top, mods| ... } » self
The motion block gets called every time the mouse moves around inside the slot.
The block is handed the cursor's left
and top
coordinates and the optional mods.
Shoes.app :width => 200, :height => 200 do
background black
fill white
@circ = oval 0, 0, 100, 100
motion do |left, top|
@circ.move left - 50, top - 50
end
end
release { |button, left, top| ... } » self
The release block runs whenever the mouse is unclicked (on mouse up). When the finger is lifted. The button
is the number of the button that was depressed.
The left
and top
are the coordinates of the mouse at the time the button was released.
To catch the actual mouse click, use the click event.
start { |self| ... } » self
The first time the slot is drawn, the start event fires. The block is handed self
, the slot object which has just been drawn.
Manipulation Blocks
The manipulation methods below make quick work of shifting around slots and inserting new elements.
append() { ... } » self
Adds elements to the end of a slot.
Shoes.app do
@slot = stack { para 'Good Morning' }
timer 3 do
@slot.append do
title "Breaking News"
tagline "Astronauts arrested for space shuttle DUI."
end
end
end
The title
and tagline
elements will be added to the end of the @slot
.
after(element) { ... } » self
Adds elements to a specific place in a slot, just after the element
which is a child of the slot.
The command should be executed for the slot (slot.after) where the entry will be added. The element should be a full path (slot.element) after which the new entry will be pushed.
Shoes.app do
@my_stack = stack do
background yellow
para 'number 1'
para 'number 2'
para 'number 3'
para 'number 4'
end
@my_stack.after(@my_stack.contents[1] ) do
para 'number 1.5'
end
end
before(element) { ... } » self
Adds elements to a specific place in a slot, just before the element
which is a child of the slot.
The command should be executed for the slot (slot.before) where the entry will be added. The element should be a full path (slot.element) before which the new entry will be pushed.
Shoes.app do
@my_stack = stack do
background yellow
para 'number 1'
para 'number 2'
para 'number 3'
para 'number 4'
end
@my_stack.before(@my_stack.contents[2] ) do
para 'number 1.5'
end
end
clear() » self
Empties the slot of any elements, timers and nested slots. This is effectively identical to looping through the contents of the slot and calling each element's remove
method.
clear() { ... } » self
The clear method also takes an optional block. The block will be used to replace the contents of the slot.
Shoes.app do
@slot = stack { para "Old text" }
timer 3 do
@slot.clear { para "Brand new text" }
end
end
In this example, the "Old text" paragraph will be cleared out, replaced by the "Brand new text" paragraph.
prepend() { ... } » self
Adds elements to the beginning of a slot.
Shoes.app do
@slot = stack { para 'Good Morning' }
timer 3 do
@slot.prepend { para "Your car is ready." }
end
end
The para
element is added to the beginning of the @slot
.
refresh()
Sometimes you want the slot to be drawn as soon as possible, to update an inside background color for example. That methods urges Shoes to do so.
Position of a Slot
Like any other element, slots can be styled and customized when they are created.
To set the width of a stack to 150 pixels:
Shoes.app do
stack(:width => 150) { para "Now that's precision." }
end
Each style setting also has a method, which can be used to grab that
setting. (So, like, the width
method returns the width of the slot in
pixels.)
displace(left: a number, top: a number) » self
A shortcut method for setting the :displace_left and :displace_top styles.
Displacing is a handy way of moving a slot without altering the layout. In fact, the top
and left
methods will not report displacement at all. So, generally, displacement is only for temporary animations. For example,
jiggling a button in place.
The left
and top
numbers sent to displace
are added to the slot's own top-left coordinates. To subtract from the top-left coordinate, use negative numbers.
gutter() » a number
The size of the scrollbar area. When Shoes needs to show a scrollbar, the scrollbar may end up covering up some elements that touch the edge of the window. The gutter
tells you how many pixels to expect the scrollbar to cover.
This is commonly used to pad elements on the right, like so:
Shoes.app do
stack :margin_right => 20 + gutter do
para "Insert fat and ratified declaration of independence here..."
end
end
height() » a number
The vertical size of the viewable slot in pixels. So, if this is a scrolling slot, you'll need to use scroll_height()
to get the full size of the slot.
hide() » self
Hides the slot, so that it can't be seen. See also show and toggle.
left() » a number
The left pixel location of the slot. Also known as the x-axis coordinate.
move(left, top) » self
Moves the slot to specific coordinates, the (left, top) being the upper left hand corner of the slot.
remove() » self
Removes the slot. It will no longer be displayed and will not be listed in its parent's contents. It's gone.
scroll() » true or false
Is this slot allowed to show a scrollbar? True or false. The scrollbar will only appear if the height of the slot is also fixed.
scroll = true or false
Establishes this slot as a scrolling slot. If scroll = true
is set, the slot will show a scrollbar if any of its contents go past its height. The scrollbar will appear and disappear as needed.
See also the scroll style.
scroll_height() » a number
The vertical size of the full slot, including any of it which is hidden by scrolling.
scroll_max() » a number
The top coordinate which this slot can be scrolled down to. The top coordinateof a scroll bar is always zero. The bottom coordinate is the full height of the slot minus one page of scrolling. This bottom coordinate is what scroll_max
returns.
This is basically a shortcut for writing slot.scroll_height - slot.height
.
To scroll to the bottom of a slot, use slot.scroll_top = slot.scroll_max
.
scroll_top() » a number
The top coordinate which this slot is scrolled down to. So, if the slot is scrolled down twenty pixels, this method will return 20
.
scroll_top = a number
Scrolls the slot to a certain coordinate. This must be between zero and
scroll_max
.
show() » self
Reveals the slot, if it is hidden. See also hide and toggle.
style() » styles
Calling the style
method with no arguments returns a hash of the styles presently applied to this slot.
While methods such as height
and width
return the true pixel dimensions of the slot, you can use style[:height]
or style[:width]
to get the dimensions originally requested.
Shoes.app do
@s = stack :width => "100%"
para @s.style[:width]
end
In this example, the paragraph under the stack will display the string "100%".
style(styles) » styles
Alter the slot using a hash of style settings. Any of the methods on this page (aside from this method, of course) can be used as a style setting. So, for example, there is a width
method, thus there is also a width
style.
Shoes.app do
@s = stack { background green }
@s.style(:width => 400, :height => 200)
end
toggle() » self
Hides the slot, if it is shown. Or shows the slot, if it is hidden.
top() » a number
The top pixel location of the slot. Also known as the y-axis coordinate.
width() » a number
The horizontal size of the slot in pixels.
Traversing the Page
You may find yourself needing to loop through the elements inside a slot. Or maybe you need to climb the page, looking for a stack that is the parent of an element.
On any element, you may call the parent
method to get the slot directly above it. And on slots, you can call the contents
method to get all of the children. (Some elements, such as text blocks, also have a contents
method for getting their children.)
contents() » an array of elements
Lists all elements in a slot.
parent() » a Shoes::Stack or Shoes::Flow
Gets the object for this element's container.