Idea: Simplified GTK

Here’s an idea. I’ve begun implementing it.

Tell me why it’s dumb, or what its shortcomings are.

Put all your logic inside an App.logic (which will get called from
App.run and wrapped with the stuff it needs). Afterward, call App.run
itself.

You automatically get one toplevel window, called @main in App.
Everything in App.logic defaults to this as a container.

When you create a container, you put a block on the constructor. Any
widget (container or other) created in that block will belong to the
current container. So the nesting of the block structure reflects the
nesting of the containers.

When you create a non-container, you put a block on the constructor.
It will be associated with the “default” (most common) message for
that widget.

Here’s some code. It works, for what it’s worth.

 require 'ez-gtk'
 include EZ_GTK

 def App.logic
   @main.title = "My window"
   @hb = HBox.new do
     @vb1 = VBox.new do
       @btn1 = Button.new("Do it") { puts "pressed btn1" }
       @btn2 = Button.new("This too") { puts "pressed btn2" }
     end
     @vb2 = VBox.new do
       @btn3 = Button.new("Third button") { puts "pressed btn3" }
     end
   end
 end

 App.run

Please comment on this before asking to see ez-gtk itself. :wink:

Thanks,
Hal

Do you need the instance variables? It seems like, in many cases, you
wouldn’t. It’s definitely nicer to look at like this:

 def App.logic
   @main.title = "My window"
   HBox.new do
     VBox.new do
       Button.new("Do it") { puts "pressed btn1" }
       Button.new("This too") { puts "pressed btn2" }
     end
     VBox.new do
       Button.new("Third button") { puts "pressed btn3" }
     end
   end
 end

I know you lose some flexibility (or you make it one level harder), but
I can’t help wanting it to look like this:

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

Even if something like this (your idea) has some shortcomings, I still
think it’s worth doing. It will be very useful for the situations when
its shortcomings aren’t an issue (for example, quick and dirty little
GUI apps).

Now that I’ve commented, can I see the code? :wink:

Chad

···

On 7/4/2004, at 5:29 AM, Hal Fulton wrote:

Here’s an idea. I’ve begun implementing it.

Tell me why it’s dumb, or what its shortcomings are.

Put all your logic inside an App.logic (which will get called from
App.run and wrapped with the stuff it needs). Afterward, call App.run
itself.

You automatically get one toplevel window, called @main in App.
Everything in App.logic defaults to this as a container.

When you create a container, you put a block on the constructor. Any
widget (container or other) created in that block will belong to the
current container. So the nesting of the block structure reflects the
nesting of the containers.

When you create a non-container, you put a block on the constructor.
It will be associated with the “default” (most common) message for
that widget.

Here’s some code. It works, for what it’s worth.

require 'ez-gtk'
include EZ_GTK

def App.logic
  @main.title = "My window"
  @hb = HBox.new do
    @vb1 = VBox.new do
      @btn1 = Button.new("Do it") { puts "pressed btn1" }
      @btn2 = Button.new("This too") { puts "pressed btn2" }
    end
    @vb2 = VBox.new do
      @btn3 = Button.new("Third button") { puts "pressed btn3" }
    end
  end
end

App.run

In article 4073C9EC.7020400@hypermetrics.com,

Here’s an idea. I’ve begun implementing it.

Tell me why it’s dumb, or what its shortcomings are.

Put all your logic inside an App.logic (which will get called from
App.run and wrapped with the stuff it needs). Afterward, call App.run
itself.

You automatically get one toplevel window, called @main in App.
Everything in App.logic defaults to this as a container.

When you create a container, you put a block on the constructor. Any
widget (container or other) created in that block will belong to the
current container. So the nesting of the block structure reflects the
nesting of the containers.

When you create a non-container, you put a block on the constructor.
It will be associated with the “default” (most common) message for
that widget.

Here’s some code. It works, for what it’s worth.

require 'ez-gtk'
include EZ_GTK

def App.logic
  @main.title = "My window"
  @hb = HBox.new do
    @vb1 = VBox.new do
      @btn1 = Button.new("Do it") { puts "pressed btn1" }
      @btn2 = Button.new("This too") { puts "pressed btn2" }
    end
    @vb2 = VBox.new do
      @btn3 = Button.new("Third button") { puts "pressed btn3" }
    end
  end
end

App.run

Please comment on this before asking to see ez-gtk itself. :wink:

This is exactly how the FLTK ruby bindings I’m using work (unfortunately
they’re not publicly available yet) except that instead of defining a
class method we actually define a class and this is done in the
constructor for that class. It is a nice way of doing things.

However, your naming convention seems confusing to me. You’re calling
this method App.logic, when in reality this is App.GUI since this is where
you’re actually defining your GUI elements. App.logic, (again it seems to
me) should be something like a state machine that responds to events that
come from the GUI.

I guess I’m sensitive to this since the app we’re currently
developing needs to work both as a
GUI and as a console app (depending on the environment it’s running in) so
I’m trying to seperate the GUI elements from
the underlying logic as much as possible. Basically I have a state
machine that encapsulates all of the logic and then I can plug in
different front ends (or at least that’s the goal, it’s not all there
yet). I use Observable as a means of passing events back and forth
between the state machine and GUI.

Phil

···

Hal Fulton hal9000@hypermetrics.com wrote:

I love it!

Here with several (imo) improvements:

  1. use dyamically scoped variables (really appropriate)
  2. can use 1. to set up any overridable defaults e.g.
    with_context(:VBox=>{:direction=>:top_down}) { … }
    find_in_context [:VBox, :direction]
  3. return handles to widgets
  4. can add widgets “after the fact”
  5. can add externally created widget instances
···

########################

Begin code

require ‘gtk2’

class Gtk::Window
def add_child c
self.add c
end
end

class Gtk::HBox
def add_child c
self.pack_start c
end
end

class Gtk::VBox
def add_child c
self.pack_start c
end
end

BEGIN: dynamically scoped variables

Modified version of Avi Bryant’s code

Can lookup a symbol OR a path (list of symbols)

Used for widget’s :parent, can be used for all GTK defaults

def with_context(params)
k, name = catch(:context) {yield; return}
k.call(lookup(params,name) || find_in_context(name))
end

def find_in_context(name)
callcc{|k| throw(:context, [k, name])}
end

def lookup(params, name)
return params[name] if name.is_a? Symbol
if name.is_a? Array
name.each do |n| params = params[n] end
return params
end
throw :Wrong_type
end

END: dynamically scoped variables

p lookup ( {:a=>{:b=>{:c=>3}}}, [:a, :b] )

class EzGtkWindow

could easily set up defaults for all widget configuration

use dynamically scoped variables for easy temporary overriding

def main
window = Gtk::Window.new
with_context(:parent=>window) { yield }
window
end
def hbox
hbox = Gtk::HBox.new(false)
parent = find_in_context(:parent)
parent.add_child(hbox)
with_context(:parent=>hbox) { yield }
hbox
end
def vbox
vbox = Gtk::VBox.new(false)
parent = find_in_context(:parent)
parent.add_child(vbox)
with_context(:parent=>vbox) { yield }
vbox
end
def button(string, &block)
button = Gtk::Button.new(string)
button.signal_connect(“clicked”, block)
parent = find_in_context(:parent)
parent.add_child(button)
button
end
def external(widget)
find_in_context(:parent).add_child(widget)
end
end

class MyWindow < EzGtkWindow
def initialize
@m = main {
@hb = hbox {
@vb = vbox {
@b1 = button(“Do it”) { puts “pressed btn1”; $stdout.flush }
@b2 = button(“This too”) { puts “pressed btn2”; $stdout.flush }
}
@vb2 = vbox {
@b3 = button(“Quit”) { puts Gtk.main_quit; $stdout.flush }
}
}
}

with_context (:parent=>@vb2) {
  @b4 = button("Added later") { puts "Added later"; $stdout.flush }
}

@external = Gtk::Button.new("Externally Created")
with_context (:parent=>@vb2) {
  external(@external)
}

[@m, @hb, @b1, @b2, @vb2, @b3, @b4, @external].each { |w| p w.class }
@m.show_all

end
end

Gtk.init
c = MyWindow.new
Gtk.main

End code

The current discussion Hal started is quite good. But it is focused on one
part of the problem e.g. it does not directly address the potentially
complicated problem of hooking together UI, dialog state (enabling/disabling
etc), and domain objects, keeping all in sync.

At the risk of broadening things … I am partial to Joel BanderWerf’s work
on FoxTails for FxRuby. The biggest things that comes to mind are:

  • a great Observable: you don’t observe an object, you observe an Attribute
    of an object
  • a nice way to attach any object (not just strings) to widgets like a
    ComboBox or TextField
  • a nice way to extensible events e.g. “when selection changes” and “file
    chosen”

The Hal/Chad/Gregory style of “vbox { button {}; button {}; …}” is on
FoxTails 0.1 to-do list. Seems like we might complement nicely.

Joel, care to comment / join in?

Chad Fowler wrote:

[…]

I know you lose some flexibility (or you make it one level harder), but
I can’t help wanting it to look like this:

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

Just cause you yield the instance to the block, doesn’t mean you can’t
return the instance as well, so you don’t HAVE to lose the object.

Charles Comstock

Of the two:

require 'ez-gtk'
include EZ_GTK

def App.logic
  @main.title = "My window"
  @hb = HBox.new do
    @vb1 = VBox.new do
      @btn1 = Button.new("Do it") { puts "pressed btn1" }
      @btn2 = Button.new("This too") { puts "pressed btn2" }
    end
    @vb2 = VBox.new do
      @btn3 = Button.new("Third button") { puts "pressed btn3" }
    end
  end
end

App.run

Or -

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

The second one looks much more to-the-point. And in fact, wouldn’t be that hard to do. The first (original poster) attempts to go halfway between Gtk and the rapidity of the second.

The following code implements the second bit. Just hbox, vbox, and buttons, though ;). I do like this idea, for fairly rapid prototyping.

Begin code

require ‘gtk2’

class EzGtkWindow
def main
@window = Gtk::Window.new
@addfunc = lambda { |item| @window.add(item) }
yield @window
@window.show_all
end
def hbox
hbox = Gtk::HBox.new(false)
@addfunc.call( hbox )
storefunc = @addfunc
@addfunc = lambda { |item| hbox.pack_start( item ) }
yield hbox
@addfunc = storefunc
end
def vbox
vbox = Gtk::VBox.new(false)
@addfunc.call( vbox )
storefunc = @addfunc
@addfunc = lambda { |item| vbox.pack_start( item ) }
yield vbox
@addfunc = storefunc
end
def button(string,&block)
button = Gtk::Button.new(string)
button.signal_connect(“clicked”,block)
@addfunc.call( button )
end
end

class MyWindow < EzGtkWindow
def initialize
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Quit”) { puts Gtk.main_quit }
}
}
}
end
end

Gtk.init
c = MyWindow.new
Gtk.main

End code

  • Greg Millam

Chad Fowler wrote:

I know you lose some flexibility (or you make it one level harder), but
I can’t help wanting it to look like this:

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

Nice and clean. Sometimes you’d need to save references to the
objects, though.

Even if something like this (your idea) has some shortcomings, I still
think it’s worth doing. It will be very useful for the situations when
its shortcomings aren’t an issue (for example, quick and dirty little
GUI apps).

Now that I’ve commented, can I see the code? :wink:

Sure, I’ll email it. :wink:

Hal

Phil Tomson wrote:

This is exactly how the FLTK ruby bindings I’m using work (unfortunately
they’re not publicly available yet) except that instead of defining a
class method we actually define a class and this is done in the
constructor for that class. It is a nice way of doing things.

I’ll check that out when it is available.

However, your naming convention seems confusing to me. You’re calling
this method App.logic, when in reality this is App.GUI since this is where
you’re actually defining your GUI elements. App.logic, (again it seems to
me) should be something like a state machine that responds to events that
come from the GUI.

I’ve tried before to separate gui logic from the rest of the app’s
logic. It has not worked well for me yet, though I approve of it in
principle.

Here I’m simply not separating those.

I guess I’m sensitive to this since the app we’re currently
developing needs to work both as a
GUI and as a console app (depending on the environment it’s running in) so
I’m trying to seperate the GUI elements from
the underlying logic as much as possible. Basically I have a state
machine that encapsulates all of the logic and then I can plug in
different front ends (or at least that’s the goal, it’s not all there
yet). I use Observable as a means of passing events back and forth
between the state machine and GUI.

That’s pretty interesting. I’ve never yet conceived of a state-
machine approach in that kind of situation.

If I were you, I’d put together a working example (not too complex,
not too simple) and write an article about it. Bet Dr Dobbs would
go for it.

Cheers,
Hal

Its Me wrote:

The current discussion Hal started is quite good. But it is focused on one
part of the problem e.g. it does not directly address the potentially
complicated problem of hooking together UI, dialog state (enabling/disabling
etc), and domain objects, keeping all in sync.

At the risk of broadening things … I am partial to Joel BanderWerf’s work
on FoxTails for FxRuby. The biggest things that comes to mind are:

  • a great Observable: you don’t observe an object, you observe an Attribute
    of an object
  • a nice way to attach any object (not just strings) to widgets like a
    ComboBox or TextField
  • a nice way to extensible events e.g. “when selection changes” and “file
    chosen”

The Hal/Chad/Gregory style of “vbox { button {}; button {}; …}” is on
FoxTails 0.1 to-do list. Seems like we might complement nicely.

Joel, care to comment / join in?

I’ve been following the discussion with interest, but probably won’t
really digest it until the weekend.

The “specification language” style of GUI programming is very tempting,
but OTOH the Fox API is pretty good already, so that’s one reason why
it’s still on my to-do list :slight_smile:

Maybe the possibility of abstracting from the particulars of the GUI
toolkit is the point that will tip the scales towards this specification
approach.

I’m also interested in the explicit state machine idea that came up
elsewhere in the this thread, and the possibility of integrating it into
FoxTails. Observable attrs can already be thought of as synchronization
of state machines, but the state is just a bunch of variables. Sometimes
it is useful to have an explicit notion of state in the sense of
“discrete mode” and explicit transition rules, entry/exit actions, etc.
Expressing state in this way, if possible, may be clearer than just
using some related variables and observer code.

I know you lose some flexibility (or you make it one level harder),
but I can’t help wanting it to look like this:

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

Even if something like this (your idea) has some shortcomings, I still
think it’s worth doing. It will be very useful for the situations
when its shortcomings aren’t an issue (for example, quick and dirty
little GUI apps).

Have you checked out Rich’s Guitopia? Looks similar to this. We plan to
use something like that as the top layer for a GUI toolkit one of my
students is doing.

Regards,

Robert

Chad Fowler wrote:

···

On Wed, 7 Apr 2004, Charles Comstock wrote:

[…]

> I know you lose some flexibility (or you make it one level harder), but

> I can’t help wanting it to look like this:

>

> def app_logic

> main {

> hbox {

> vbox {

> button(“Do it”) { puts “pressed btn1” }

> button(“This too”) { puts “pressed btn2” }

> }

> vbox {

> button(“Third button”) { puts “pressed btn3” }

> }

> }

> }

> end

>

Just cause you yield the instance to the block, doesn’t mean you can’t

return the instance as well, so you don’t HAVE to lose the object.

Charles Comstock

I didn’t think I had to lose the object. I didn’t want it. (I assume
you’re talking about maintaining a variable reference to the widget
instances?)

Chad

Gregory Millam wrote:

The second one looks much more to-the-point. And in fact, wouldn’t be that hard
to do. The first (original poster) attempts to go halfway between Gtk and the
rapidity of the second.

Correct assessment. But there are times when you’d want to capture
references to the widgets.

The following code implements the second bit. Just hbox, vbox, and buttons,
though ;). I do like this idea, for fairly rapid prototyping.

You coded the same thing I did in half the time, and it’s prettier. I
find that disgusting. :wink:

I was using an explicit stack in a class variable for the containers.
This is much nicer, and I need to eyeball it and make sure I get it.

Thanks,
Hal

I liked this book a lot:
“Constructing the User Interface with Statecharts”
by Ian Horrocks
ISBN: 0201342782

(But then again, since I don’t write GUIs, I haven’t had a chance
to try out Horrocks’ ideas in practice.)

···

On Wednesday 07 April 2004 14:19, Hal Fulton wrote:

That’s pretty interesting. I’ve never yet conceived of a state-
machine approach in that kind of situation.

In article 40744628.1090309@hypermetrics.com,

Phil Tomson wrote:

This is exactly how the FLTK ruby bindings I’m using work (unfortunately
they’re not publicly available yet) except that instead of defining a
class method we actually define a class and this is done in the
constructor for that class. It is a nice way of doing things.

I’ll check that out when it is available.

I hope it will eventually be available. These particular RubyFLTK
bindings were developed by someone else in the company where I’m
contracting. Theoretically, they could be released, but there is
probably some paperwork to get through to clear it with the Legal folks.
It probably won’t happen very soon, unfortuneately, it’s too bad because
they’re quite nice to work with and they’ve even got the FLUID GUI-Builder
emitting Ruby code.

However, your naming convention seems confusing to me. You’re calling
this method App.logic, when in reality this is App.GUI since this is where
you’re actually defining your GUI elements. App.logic, (again it seems to
me) should be something like a state machine that responds to events that
come from the GUI.

I’ve tried before to separate gui logic from the rest of the app’s
logic. It has not worked well for me yet, though I approve of it in
principle.

Here I’m simply not separating those.

I guess I’m sensitive to this since the app we’re currently
developing needs to work both as a
GUI and as a console app (depending on the environment it’s running in) so
I’m trying to seperate the GUI elements from
the underlying logic as much as possible. Basically I have a state
machine that encapsulates all of the logic and then I can plug in
different front ends (or at least that’s the goal, it’s not all there
yet). I use Observable as a means of passing events back and forth
between the state machine and GUI.

That’s pretty interesting. I’ve never yet conceived of a state-
machine approach in that kind of situation.

I started out in hardware design. In hardware we use state-machines
everywhere so they just seem natural. Of course in software you can be
much more creative in the types of state-machines you develop. I often
wonder why it’s not a more commonly used design pattern.

If I were you, I’d put together a working example (not too complex,
not too simple) and write an article about it. Bet Dr Dobbs would
go for it.

Hmmm… That might be worth a try. Thanks for the idea.

Phil

···

Hal Fulton hal9000@hypermetrics.com wrote:

Hi,

I just encountered a rare case where I need a Hash where keys
are object id. Class Hash compares keys by value. As a result
two different String with the same value are considered the
same key. This is fine in most cases. But right now I need to
be more restrictive and I need two String objects to be treated
as two keys even if they have the same value.

I think IdentityHash is a probable name for such a beast, yet
I could not find one in Ruby and I don’t see any method in
class Hash that I could redefine in a derived class to change
the way keys are compared.

BTW: IdentityHash should be slightly faster than Hash.

Any clue ?

Thanks,

Jean-Hugues Robert

Well, I’m not him, but I’ll go ahead and do a little “show and tell”
here… I recently worked on an application with a Fox GUI, and in the
process I wrapped some code around Fox to make GUI creation easier.
Part of my thinking when I built it was that there are two things we do
when we set up a GUI, and it would be cleaner if we did them as two
steps instead of mashing them together. Those two steps are setting up
the components relationships to one another, and setting up the
component’s properties, event handlers, etc. So I ended up with code
that looks like this:

class LoginDialog
include FXUtil

 attr_reader :credentials

 def initialize(app)
   super()
   create(app)
 end

 def create(app)
   template(app) do
     dialog("Login"){vertical{
     matrix{label(:please_log_in); empty
            label("User name:");   text_field(:username)
            label("Password:");    text_field(:password)}
     horizontal(:buttons){button(:ok); button(:cancel)}}}
   end

   setup :please_log_in do |w|
     w.text = "Please log in"
     w.bold = true
   end

   setup :username do |w|
     w.columns_visible = 20
   end

   setup :password do |w|
     w.options |= TEXTFIELD_PASSWD
     w.columns_visible = 20
     w.on_keypress do |source, selector, event|
       if(event.text == "\r")
         ok(source)
       else
         false
       end
     end
   end

   setup :buttons do |w|
     w.options = LAYOUT_CENTER_X
   end

   setup :ok do |w|
     w.text = "&OK"
     w.options |= BUTTON_DEFAULT|BUTTON_INITIAL
     w.on_click{|source, s, e| ok(source)}
   end

   setup :cancel do |w|
     w.text = "&Cancel"
     w.on_click{|source, s, e| cancel(source)}
   end

   build
 end

 def ok(source)
   @credentials = [widget(:username).text, widget(:password).text]
   widget.handle(source, MKUINT(FXDialogBox::ID_ACCEPT, 

SEL_COMMAND), nil)
end

 def cancel(source)
   widget.handle(source, MKUINT(FXDialogBox::ID_CANCEL, 

SEL_COMMAND), nil)
end

 def execute
   widget(:username).setFocus
   (widget.execute(PLACEMENT_SCREEN) == 1) ? true : false
 end

end

Currently ‘FXUtil’ is in no way ready for prime time, but hopefully
this code (which is presently live production code) illustrates one
better way that I found of building GUIs.

Just my $0.02,

Nathaniel
Terralien, Inc.

<:((><

···

On Apr 7, 2004, at 13:19, Hal Fulton wrote:

If I were you, I’d put together a working example (not too complex,
not too simple) and write an article about it. Bet Dr Dobbs would
go for it.

“Joel VanderWerf” vjoel@PATH.Berkeley.EDU wrote in message
news:40758C97.6070906@path.berkeley.edu…

The “specification language” style of GUI programming is very tempting,
but OTOH the Fox API is pretty good already, so that’s one reason why
it’s still on my to-do list :slight_smile:

You’ve been too close to your own code :wink: Browsing your FoxTails examples,
there is so much Fox stuff around, specially around initialization, that it
makes it quite hard for me to see the essence of FoxTails.

Maybe the possibility of abstracting from the particulars of the GUI
toolkit is the point that will tip the scales towards this specification
approach.

Hmmm. From platform-independent toolkit to toolkit-independent platform? If
doable, it would make a lot of very protracted and agonizing decisions about
which toolkit much simpler for a whole bunch of poor saps like me.

I’m also interested in the explicit state machine idea that came up
elsewhere in the this thread, and the possibility of integrating it into
FoxTails. Observable attrs can already be thought of as synchronization
of state machines, but the state is just a bunch of variables. Sometimes
it is useful to have an explicit notion of state in the sense of
“discrete mode” and explicit transition rules, entry/exit actions, etc.
Expressing state in this way, if possible, may be clearer than just
using some related variables and observer code.

I fully agree. Perhaps the Observable underpinnings could
re-establish/maintain invariants that hold within any given state. A
low-level example: list.selection =
list.first_matching_prefix(text_field.value).

In article 40758C97.6070906@path.berkeley.edu,

Its Me wrote:

I’ve been following the discussion with interest, but probably won’t
really digest it until the weekend.

The “specification language” style of GUI programming is very tempting,
but OTOH the Fox API is pretty good already, so that’s one reason why
it’s still on my to-do list :slight_smile:

Maybe the possibility of abstracting from the particulars of the GUI
toolkit is the point that will tip the scales towards this specification
approach.

Toolkit-neutral GUI code would be cool.

I’m also interested in the explicit state machine idea that came up
elsewhere in the this thread, and the possibility of integrating it into
FoxTails. Observable attrs can already be thought of as synchronization
of state machines, but the state is just a bunch of variables. Sometimes
it is useful to have an explicit notion of state in the sense of
“discrete mode” and explicit transition rules, entry/exit actions, etc.
Expressing state in this way, if possible, may be clearer than just
using some related variables and observer code.

I define a class for each state in the machine (and I ‘include
Singleton’ in their superclass, State ). The
transitions/actions/etc are contained in the state classes. Each state
class has a ‘do_action(event)’ method, that looks something like:

class LoginState < State
def do_action(event_class)
if event_class == NextEvent #Next button or ‘return’ key in console

  begin
    status = do_login(@@ui_obj.email,@@ui_obj.serial_number)
  rescue Errno::ECONNREFUSED
    @next_state = ConnectionErrorState
    @@ui_obj.display_message("Could not connect to site")
    return
  end
  #figure out which state to goto next
  case status
  when NewUser
    @next_state = VerifyEmailState
  when DuplicateSN
    @@ui_obj.display_message("Duplicate Serial Number; please 

re-enter")
@next_state = LoginState
when…

end
end
end

NOTE: @@ui_obj points to a proxy class that acts as a ‘translator’ between
the state machine and the actual GUI code. It should make
it easier to use different toolkits.

The StateMachine class itself is Observable, not the states themselves in
this implementation. Sounds kind of like what you’re describing.

Phil

···

Joel VanderWerf vjoel@PATH.Berkeley.EDU wrote:

Yes. It’s not exactly like this–better, actually. But, it’s not
available publicly yet. I think he calls it Utopia (Gutopia was
apparently a name someone else attached to the same idea).

Sounds like your students work on some pretty great projects. :slight_smile:

Chad

···

On 11/4/2004, at 12:36 PM, Robert Feldt wrote:

I know you lose some flexibility (or you make it one level harder),
but I can’t help wanting it to look like this:

def app_logic
main {
hbox {
vbox {
button(“Do it”) { puts “pressed btn1” }
button(“This too”) { puts “pressed btn2” }
}
vbox {
button(“Third button”) { puts “pressed btn3” }
}
}
}
end

Even if something like this (your idea) has some shortcomings, I
still think it’s worth doing. It will be very useful for the
situations when its shortcomings aren’t an issue (for example, quick
and dirty little GUI apps).

Have you checked out Rich’s Guitopia? Looks similar to this. We plan
to use something like that as the top layer for a GUI toolkit one of
my students is doing.