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.

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.