I gave this talk at Ruby Manor Classic. I gave it alongside Martin Sadler as a two parter about building GUIs with Ruby. Martin spoke about using monkeybars via Jruby, and we had a shared intro. This transcript only covers my part of the talk, not the shared intro, and not Martinʼs bit.
The transcript comes from my presenter notes and these were a first draft, so itʼs very unlikely to be a word-for-word copy of what I said on the day. It should be very close though.
A video of this talk is available from Ruby Manor:
This video is of the full talk including the shared intro, Martinʼs monkeybars talk, and my shoes talk. The shoes part of the talk starts at about 22minutes.
This is going to be a quick tour of shoes.
So what is Shoes?
It’s a GUI framework written by _why the lucky stiff.
Some of you may remember Hackety-hack, a project _why came up with to teach programming to young school kids.
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.
So _why put Hackety-hack on hiatus to work on Shoes as a replacement for the Gecko engine in Hackety-hack.
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.
You might think that installing shoes is as simple as:
gem install shoes
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.
So, if it’s not a gem, how do you get it? First off go to
shoooes.net for all your Shoes needs.
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.
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!
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.
This is the simplest Shoes app you can write.
Shoes.app is your gateway. Everything is a block…
Running this (drag the file onto the Shoes icon in the dock or use the “Open…” menu) brings up an empty Shoes window.
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
Anyway, this gives us the following, as you might expect. Let’s do something more exciting.
Ohhh… what’s all this?
So we’re adding a second
background to add an image, and we’re specifically positioning it with those
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
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:
caption). They act much like
h6 and simply scale the text up and down in terms of
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?
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!
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
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.
First up are
stacks. 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
stacks. Each element you add to the stack creates a new vertical layer. Except…
…gravity is upside down. Elements fill down the page, not up.
flows. 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.
flows 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:
flows. 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
right style attributes.
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
flows to create the rest of the layout.
It’s four things in a
- 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
We’ve already seen the
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
stacks around the
paras 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
Other interesting things to note about this code:
edit_line- this is how you get a text box
- the negative
widths on the text box, what this means is be 100% of the box wide minus
170px. Because this is in a
flow, it allows us to combine stacks and other “wide-able” elements to create single “layer” of elements in the
button- the block passed to the
buttonis what will happen when the
buttonis 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.
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?
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.
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.
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
toggle, etc… them.
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.
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.
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
timers can then be started or stopped. There’s also the
timer, for events you want to fire every so often instead of once after a short time has passed.
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.
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.
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.
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.
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 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
visited. 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.
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.
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.
⌘min 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