Talks ∋ Tying your shoes
A whirlwind guide to tying your shoes
This is going to be a quick tour of shoes.
What is Shoes?
So what is Shoes?
It’s a GUI framework written by _why the lucky stiff.
A little history - hackety-hack
Some of you may remember Hackety-hack, a project _why came up with to teach programming to young school kids.
A little history - gecko
His first attempt at Hackety-hack used an embedded Gecko engine and a lot of the UI was pretty much HTML. However, it seems that this didn’t cut it for some reason, perhaps it was too complex to make changes to or perhaps embedding Gecko was too prone to oddness. I’m not really sure.
A little history - shoes
So _why put Hackety-hack on hiatus to work on Shoes as a replacement for the Gecko engine in Hackety-hack.
This is familiar
As you might imagine from something designed to replace an embedded HTML rendering engine, Shoes is heavily influenced by HTML. To me it’s always felt like a weird combo of HTML, JS and CSS. Except, rather than learning three syntaxes and splitting everything over three files (if you’re doing it semantically, unobtrusively and presentationally); you’re learning one syntax (ruby) and defining everything in one place. I think if you’re at all familiar with building apps for the web, you’ll feel completely at home very quickly with Shoes.
It’s also inspired by Nodebox and Processing - so everything is a canvas. Just imagine that a body tag is also a canvas tag and you’ll be set!
gem install shoes
?
You might think that installing shoes is as simple as:
gem install shoes
gem install shoes
- No!
But unfortunately not. Unlike other ruby GUI frameworks, Shoes is not a gem. This isn’t a quirky way of packaging it, it’s by design because it’s actually a separate ruby runtime that you download and install. You then ask Shoes to run the programs you create, instead of your standard ruby install. It’s based on 1.8.6 though so it should be fine. It also has gems support (using gems 1.2), so you can still use the ruby eco-system that you know and love, but not specifically the one that you’ve pre-installed.
How do I get shoes?
So, if it’s not a gem, how do you get it? First off go to shoooes.net
for all your Shoes needs.
How do I get shoes - a mnemonic
A nice hint to remember the url is this:
There are 3 “o”s in shoooes just like there are 3 eyelets in a standard man’s shoe.
SIMPLE!1
Shoes is for everyone
Anyway, once at shoooes.net
you can find the version of Shoes for your platform.
It’s cross platform, currently available for OS X (PPC & Intel, although PPC tends to lag behind on some features - it took ages to get Video support into PPC), Windows and Linux / BSD using GTK+.
Download it, install it and you are all set to go!
How to tie your shoes - loop it, swoop it & pull
So. Now we all have Shoes, we want to know how to tie them. (or … you know … build applications).
Martin and I decided that we’d both build a simple Twitter client as the demonstration app for our talks. The app I built is called Talon.
The simplest shoes app - code
This is the simplest Shoes app you can write. Shoes.app
is your gateway. Everything is a block…
The simplest shoes app - screenshot
Running this (drag the file onto the Shoes icon in the dock or use the “Open…” menu) brings up an empty Shoes window.
Customising a shoes app - code
So let’s spruce it up a bit, we’ll give it a title and give it a nice crisp white background.
We specify the title via a styles hash on the Shoes.app
call. We could specify other things here, such as the window size, but we’ll leave that for now. The default is ok for us.
The background colour is specified as a method. The block passed to Shoes.app
is evaluated in the context of the Shoes application. So this background
method comes from Shoes.app
.
Customising a shoes app - screenshot
Anyway, this gives us the following, as you might expect. Let’s do something more exciting.
Building the main talon window - code
Ohhh… what’s all this?
So we’re adding a second background
to add an image, and we’re specifically positioning it with those bottom
and right
style entries in the hash. The positioning stuff should be very familiar to anyone with a passing knowledge of CSS. For those with more than a passing knowledge you should recognise the multiple backgrounds stuff from CSS3 (which would get rid of things like the sliding doors technique).
Next we’re encountering this curious object called a flow
. We’ll come back to it later, but for now it’s enough to know that it’s a container that we can put other things in. Note that we pass a block and everything in that block is evaluated in the context of that flow
. So by calling background
here, we’re setting the background of the flow
, not our main Shoes.app
. (The curve
param passed the background
call gives us rounded corners - sweet!)
The final thing is the title
method. This lets us specify some text. Text in Shoes is all based on derivatives of the para
element and helpfully (much like HTML) provides several default styles to get you started (for example: title
, subtitle
, caption
). They act much like h1
- h6
and simply scale the text up and down in terms of font-size
.
Building the main talon window - screenshot
Anyway running that code this gives us this.
I mean, that’s pretty awesome. It’s almost ready to ship! Ok, Perhaps we need … a login screen?
The talon login window - screenshot
We want something like this. Now we’re going to have to talk about buttons, controls and layouts. Once you know that, well, there’s not much else to learn. So let’s go!
The talon login window - base code
To build this login box we need to start with the container for all the elements; the title, the two edit boxes, their labels, and the button.
The box is a stack
, the second of the two Shoes layout containers. We’re applying a margin
to it so it doesn’t fill up the whole window width and is spaced away from the main app title. Just like CSS we can specify this stuff in array form, or individually with margin-top
etc…
We’ve now seen both a flow
(used earlier to contain the main app title) and a stack
(used here to contain the whole login UI). So it’s as good a time as any to talk about the features shoes provides for laying out your UI elements.
These are the only two layout containers that Shoes provides, anyone familiar with other GUI frameworks will be used to things like Grid Layouts or Compass Layouts or whatever… nothing so complex with Shoes.
stack
s
First up are stack
s. Imagine all the technical books on your desk. If you want to tidy the desk you’ll probably stack the books up on top of each other to save space. Each book goes on top of the previous one creating a new layer in the stack with each book.
That’s how it is in Shoes with stack
s. Each element you add to the stack creates a new vertical layer. Except…
stack
s with gravity
…gravity is upside down. Elements fill down the page, not up.
flow
s
Next are flow
s. Imagine an empty box of matches. As you put matches into the box they fill up the bottom layer of the box. Once that layer is full we start filling up the next layer, until that’s filled up and we create a new layer, and so-on.
flow
s in Shoes are very similar. UI elements in a flow
fills up the width of the flow
from left to right and then drop down horizontally and fill up that layer, and so on.
So that’s layout in Shoes: stack
s and flow
s. Which are, yes, almost exactly like inline vs block elements in HTML & CSS. Also, just like CSS you can ignore these containers and position things absolutely with top
, bottom
, left
and right
style attributes.
The talon login window - screenshot
Remember, we are trying to build this. Now that you know what kinds of layout options are available, and that I’ve already shown you that I’ve got a stack
box to contain the whole login UI, you should have a pretty good idea of how to combine stack
s and flow
s to create the rest of the layout.
It’s four things in a stack
:
- the ‘who goes there?’ title
- the ‘user name’ label and entry
- the ‘password’ label and entry
- the login button
And it should be pretty obvious that each label and entry are contained within a flow
.
The talon login window - UI layout code
We’ve already seen the title
and stack
, so here’s the rest of it. Is this what you thought it would be? Give yourself a clap on the back if you did. The only weird things are the extra stack
s around the para
s to act as the labels. Text elements are truly inline and don’t have specifiable widths; it’s not just because they’re in a flow
here.
Other interesting things to note about this code:
- the
edit_line
- this is how you get a text box - the negative
width
s on the text box, what this means is be 100% of the box wide minus170px
. Because this is in aflow
, it allows us to combine stacks and other “wide-able” elements to create single “layer” of elements in theflow
. - the
button
- the block passed to thebutton
is what will happen when thebutton
is clicked. This is how you add event handlers to things in Shoes. Anyone who has written GUI event handling code in java will surely appreciate this brevity. - For the first time I’m doing something with the results of these methods that create objects. For both the user and password edit boxes I’m assigning them to instance variables (remember, everything in Shoes is evaluated in the context of
Shoes.app
, so these are instance variables available to the whole app). Every method in Shoes returns the object you’re creating, even things like background.
Shoes & Gems
Now that we have a login screen we’re going to need to be able to log into Twitter. I’ve used the twitter gem by John Nunemaker. But, I mentioned that shoes is it’s own version of ruby, and that it has it’s own version of rubygems, so if you want to use other gems in your app how do you do it?
gem 'twitter'
Well, unfortunately, it’s a bit more complex than you’d expect. You can’t just require the gem you want, like in this example. Still, it’s not significantly more complex, and it does something quite neat.
Shoes.setup { gem 'twitter' }
You put the gem statement in a Shoes.setup
block. This will tell Shoes that you want to use that gem. Shoes will also go and download / setup / install that gem if you don’t have it. Which is pretty cool.
It can be a bit temperamental right now, but it’s only going to get better as Shoes moves on.
The talon login method
So here’s the login method. Pretty boring really. The only thing to note is the @login.hide
. In the real version of Talon, I’ve recorded the stack
used to contain all the login UI in an instance variable, so when you login successfully I can hide it. All UI Elements in Shoes have these sort of methods to hide
, show
, toggle
, etc… them.
incorrect_login
- overview
With the login screen, I wanted to do something fun with it instead of just showing an alert box with “incorrect” in it. I thought it would be nice to do the same as the OS X login screen and shake the box if you got it wrong. So here’s the code to do that.
incorrect_login
- animation
Shoes has a nifty animate
method that takes a block that will be run for every frame of your animation (it defaults to 10fps, but can take an arg to say how many fps you want). What I’m doing here is using another handy element method displace
to move the whole login UI by employing some MATHS. displace
is different to move
because it doesn’t cause the whole UI to reflow, it’s almost like it was intended for this sort of little effect.
If we did nothing else this animation would run forever.
incorrect_login
- timing
That’s what this timer
block is for. timer
blocks take an arg to say how many seconds in the future you want the block to fire, and then when that time has passed, the block fires. Here we use this block to stop the animation. Remember, everything in Shoes returns what you just built, even animate
and timer
. timer
s can then be started or stopped. There’s also the every
timer
, for events you want to fire every so often instead of once after a short time has passed.
Tying more complicated shoes
So… I could go on and show you how I’ve built the rest of Talon. It does connect to Twitter and get a list of your friends tweets and even allow you to post a tweet back to Twitter. But I won’t, I don’t have much time, and I want to briefly mention some other stuff that Shoes does that I didn’t really have the time to build into Talon. Also, the rest of the Talon code doesn’t really show off anything new, apart from perhaps some other style attributes, or UI elements.
Drawing
I mentioned at the start that Shoes is influenced by Nodebox and Processing. Everything is a canvas and it has some really powerful animation (which I touched on) and drawing (which I didn’t) features. In recent builds _why has been building in more and more features for doing really neat graphical stuff (like filters and alpha transparency). Thankfully also without sacrificing the simplicity of the API. Remember, the goal of this is to power Hackety-hack, a tool for teaching kids to program. Adding this to the fact that you can do pixel perfect layout of elements means you could do some stunning looking animated UIs. For example, if you wanted a random name generator you could draw a hat that spits out stars and then picks a random name2. Or… something good.
Custom controls
Shoes has the ability to create custom controls, so if you need a dial or big flippy switch as a UI element, you can combine the drawing stuff I just mentioned and the existing controls and layouts in a class that extends from Shoes::Widget
. You can then use these custom widgets inside your Shoes app and not have to worry about repeating code, or having code in the wrong place cluttering up your main logic.
Organising your shoes
Speaking, as I was just briefly about tidying up the code and so on, I should point out that all the code I’ve shown you has been from one file: talon.rb
. That’s not to say that you can’t organise your code better. Shoes has some interesting features that could help this. I have to say, I’ve not fully explored this aspect of Shoes, so I’m just letting you know that it’s out there.
Organising your shoes with urls
You can extend Shoes itself and this lets you define url endpoints which are methods in your Shoes class that you can call with the visit
method. visit
takes a url, relative or absolute. You can have regexp’s in the URL and any groups in the pattern become arguments to the method being visit
ed. The main advantage here is then being able to put your Shoes code into multiple files.
It’s not clear to me the full power of advantage of this, except for the fact that the urls you visit
can be absolute, and thus you can put shoes apps online to perhaps combine the power of a desktop app with the simplicity of updating via a central web app.
Packaging your app
Shoes has an excellent in built packaging feature. From the “Package” menu of any Shoes app you can bundle up your Shoes code, along with Shoes and dependencies, as a Windows, OS X, Linux or Shoes application. Shoes has a cross-platform bundle called SHY which you can use instead.
It’s a really simple and nice way of bundling your code, much easier than any other mechanism I’ve used in the past, and it’s awesome that it’s built in.
Find out more
So, that’s it.
Hopefully I’ve whetted your appetite for Shoes, if you want to know more there are excellent resources out there about shoes. First is the shoes manual, which is built into every shoes app. Press cmd m to make it appear. Then go and get a copy of “nobody knows shoes”. Then explore the rest.
I really recommend it3.
shoes --manual
or⌘m
in a Shoes app- http://cloud.github.com/downloads/shoes/shoes/nks.pdf - Nobody Knows Shoes
- http://shoesrb.com/ - the main place
- https://github.com/shoes/shoes - original code and wiki
- https://github.com/Shoes3/Shoes3 - Shoes v3 code and wiki
- https://walkabout.mvmanila.com/ - Shoes v3 blog
- https://github.com/shoes/shoes4 - Shoes v4 code and wiki
- http://shoesrb.com/blog/ - Shoes v4 blog
- https://github.com/hlame/talon - my awesome app
Without whom
All the images I used came from Flickr. Thanks to these photographers.