(These examples require a Shoes that's no older than a week or two.)
On Sun, Jun 08, 2008 at 08:29:55AM +0900, Martin DeMello wrote:
> 1. A component consisting of a series of existing components hooked
> together to act as a single widget
In Shoes, you inherit from the Widget class and you can paint
your own custom widgets or combine pre-existing ones.
Like, for instance, Shoes doesn't come with a file input field like
HTML does. But you can combine an `edit_line` and a `button`.
class Browse < Widget
def initialize
@name = edit_line
@find =
button("Browse...").click do
@name.text = ask_open_file
end
end
def filename
@name.text
end
end
Shoes.app do
browse
end
When you inherit from Widget, you get a free lowercased method added
to Shoes for inserting that widget into any "stack" or "flow" (like
HTML divs, basically.)
And since the widget itself is a "flow", you can move the whole widget
as a single component. So you can call `move(x, y)` or `show` or
`hide` on the object returned by the `browse` method.
> 2. A component built 'from scratch' atop a canvas, that is, handling
> its own drawing and event management
Too easy, Shoes has painting nailed. I've worked hard to get things
on par with Processing. See the `samples` directory for a clock
widget and a calculator and a dictionary and you'll find a lot more
out on the web.
> 3. A component combining a canvas and existing widgets
So a combo of #1 and #2? Well, okay, so taking the `Browse` example
from earlier, we could add a background and a border. This just
illustrates that all widgets are drawn on a canvas anyway.
class Browse < Widget
def initialize
flow do
background "#09F"
border "#FFF"
@name = edit_line
@find =
button("Browse...").click do
@name.text = ask_open_file
end
end
end
end
> 4. A container that takes a collection of widgets and lays them out
> according to some userdefined algorithm
I'll have to think about this one. Shoes already has a 'wrapbox'
called a `flow`, but I can see why you'd want to lay things out
yourself.
Okay, let's see. So let's try a `cascade` layout that positions
everything diagonally from the element previous to it.
class Cascade < Widget
def initialize &blk
instance_eval &blk
end
def draw(a,b)
x, y = 0, 0
contents.each do |e|
if x != e.left && y != e.top
e.move x, y
end
x += e.height
y += e.width
end
super(a,b)
end
end
Shoes.app do
cascade do
button "1"
button "2"
button "3"
end
end
The `initialize` part works because every widget is just a canvas anyway.
And the `draw` method is called every time there's a repaint.
That's a bit clunky. But proves that it can be done.
> Examples (more welcomed):
>
> 1. An icon widget, that combines a picture and a textfield
> underneath, with config options to turn either off or size the image,
> make the text editable, etc
> 2. A speedometer-type dial with a configurable range and tick interval
> 3. A box that holds a component and paints a customised border around it
> 4. A pure-ruby implementation of a wrapbox
> (
http://zem.novylen.net/ruby/wrapboxdemo.png)
I'll work on some really nice answers to these. This is a fantastic exercise.
_why