The Image Block At The Bottom Of Shoes

May 22nd 23:57
by why

In Shoes, images have been much as they are in HTML. Generally, a path to the image. And maybe its width and height.

Shoes.app do
  image "static/shoes-icon.png"
end

You have a picture window.


In recent times, some Shoesers have been eschewing images and preferring to fabricate the shapes on their own. An example would be the minesweeper clone, which paints the circles and lines for all the bombs and flags. Probably to keep things as a single Ruby script.

The little bombs get drawn with something akin to this bomb method.

module Arsenal
  def bomb x, y
    nostroke
    fill "#000"
    oval x+3, y+3, 13
    fill "#333"
    oval x+5, y+5, 7
    fill "#AAA"
    oval x+6, y+6, 3

    fill "#000"
    stroke "#222"
    strokewidth 2
    oval x+12, y+3, 2
    oval x+14, y+3, 1
  end
end

Shoes.app do
  extend Arsenal
  background white
  bomb 0, 0
end

So, the bomb gets drawn at 0, 0. Holy goalie, though. Look at all that math. And the worst part of it is that every time you move the bomb, you’ve got to recompute and redraw everything. Either that or you’ve got to move each little oval individually.

Rather, let’s draw a bomb inside an image block.

module Arsenal
  def bomb x, y
    image 20, 20, :top => x, :left => y do
      nostroke
      fill "#000"
      oval 3, 3, 13
      fill "#333"
      oval 5, 5, 7    
      fill "#AAA"
      oval 6, 6, 3    

      fill "#000"
      stroke "#222"
      strokewidth 2
      oval 12, 3, 2
      oval 14, 3, 1
    end
  end
end

This image syntax creates a bitmap surface in memory. In this case: 20 pixels by 20 pixels. Upon which shapes are drawn on to. And it’s then treated like an image loaded from a file.

The advantages in this case are:

  • The image block is only drawn once. So faster paint times. Shapes aren’t constantly recomputed.
  • Everything is positioned according to the image’s origin. Less math. (Notice no x and y used in the image block.)
  • Image effects (such as blur and shadow effects) can be applied to this image.
  • Can be moved and resized as a single image. Conceptually easier, I guess.

Shoes is pretty meager on image effects right now, but a good example of using the blur effect is in samples/simple-sphere.rb.

Alls I did was follow this Photoshop tutorial, each of its steps for piling on the inner and outer glows and gradients. This was a lot of fun to do and I think could be the basis of a pretty inspiring class for kids. Give them a Photoshop tutorial and work through expressing each of its steps in code.

You will need a recent build to make any of this fly, though.

11 comments

Tieg

said on May 22nd 21:48

I don’t know what kind of magic just happened, but updating to the recent build just made my current script much faster! Unfortunately I don’t think that’ll make my coding skills any faster, but I must learn patience.

Matt

said on May 23rd 04:19

It would be easy to paint the bomb in different places if Shoes had an affine transform per drawing context, like Java2D or OpenGL. You could write a bomb method that drew a bomb at 0,0. Then to draw a bomb at (x, y) you could just use the code “x,y); bomb;”.

_why

said on May 23rd 09:25

Matt: True, good point! You can accomplish an affine transform in Shoes with the rotate, skew or scale methods, followed by a translate.

failureontheweb

said on May 23rd 09:56

I wonder if there is a practical way to pull in an OpenGL library into shoes….

zverok

said on May 24th 12:13

I should say dislike the API . The ethernal problem of graphic APIs is their imperativitiy: we typically say “set fill; then draw somethings”, while having in mind “draw something with fill”. Like this

Next: for parameters (oval) seems to bee already as much as it requires parameter naming (through hash). It may seem bit too verbose, but with upcoming ruby1.9 hashes (like `width: 100`) and parameters abbreviations (`w: 100, h: 200, :f => ‘#4df’, :b => ‘20%’) it seems to be “just right”.

And next: z-order question is also solved in imperative way (“A is drawn on top of B because A is drawn after B”). Why not to solve it through nesting of drawing commands? (“Oval, having oval and text inside it”). This solution also allows usage of “relative” sizes (like “50%”) and maybe even fills (transformations in HSV space?). Think about reusable function drawing this image with sphere (with changable width, height and color parameters). With current solution, you should calculate all sizes of ovals when drawing with another width/height, but having relative sizes, you can handle this case naturally.

danield

said on May 26th 02:53

Nice blog!
What is the window theme you use with Shoes and GTK /Gnome?

zverok

said on May 26th 05:06

one more example with changed API : bomb method

someguy

said on May 26th 08:57

I’m encouraged to see the progress on Shoes; when will this translate into some work on hackety hack? I was using it with some kids but stopped when development seemed to cease.

_why

said on May 26th 17:33

zverok: Shoes already allows that hash syntax. Most things even accept :stroke and :fill. I’m just using the shorter syntax above. Rather than :x, :y and :r, you’d use :left, :top and :radius.

This and your z-order question make me think you didn’t read this post and haven’t really done your homework on Shoes at all. Have you ever written anything in Shoes?

someguy: Stick around, this stuff just needs to get completely stable.

someotherguy

said on May 29th 19:11

Thanks _why, I’ll keep my eyes open. Except when I’m sleeping.

kamran

said on May 30th 03:21

So i want to create 2 different kinds of blocks, one blue and one green, but i want to make many of them. Should i assign the image block for creating them to variables, and then just copy that variable when i need a copy of the image, or is there a better way to do that? I really enjoy using shoes, and for zverok, i’d try checking out Nobody Knows Shoes, a very useful book if your interested in this toolkit.

Comments are closed for this entry.