librelist archives

« back to archive

Multimodal apps in Shoes

Multimodal apps in Shoes

From:
Jesse Edelstein
Date:
2012-02-09 @ 02:28
Hi all. I've gotten into Shoes recently, as I'm a cognitive
psychologist and it seems to be a practical way to code up
experiments. I've managed to answer most of my questions through
searching and trial-and-error (did you know Shoes has a pretty
functional fullscreen mode?) but I'm still pretty confused about best
practices for writing multimodal programs.

What I mean specifically is programs that have one UI, then move to a
different UI (based on time passing, or user input, or whatever), then
move on to another one, according to however I've programmed it.
Ideally you should be able to move between different modes in an
arbitrary order, so the methods for each mode should be able to set up
a new interface and then remove it before returning.

My question is: what's the natural way to do this in Shoes? My code
currently looks like this:

def first_task
  # UI setup
  # task
  # UI removal
  second_task
end

def second_task
  # as in first task
end

Shoes.app do
  # setup
  first_task
end

This does not work well, and it would still be a really hairy way to
design the program even if it worked properly. For instance, animate()
loops don't seem to close when a new method is called, so they keep
running in the background, giving errors if the objects they control
have been deleted. So what's the more appropriate way to set up a
multi-mode program?

Another question: How do I get Shoes to pop up an alert when an
unhandled error is encountered, instead of piping it to the console
(which I never remember to check)?

Thanks, Jesse

Re: [shoes] Multimodal apps in Shoes

From:
Cecil Coupe
Date:
2012-02-09 @ 07:28
Hi,

 I think there are several ways to do what you want - multiple modal
screens. It highly depends on your application and users. There are no
best practices.  I would suggest a top level guided menu screen using
url index/links/visit "Click for part 1, click for part 2" I would
**not** call part2 from inside part1. What if you later need part 3 or
1.5? 

I would call part1 or part2 depending on what part0 (your
menu/controller) thinks is the next step. Said menu screen can impose
Modality as it sees fit by.  Hacketyhack is a large Shoes program with
many lessons in dealing with modality and multiple sub-screens. A big
gulp to be sure but you only need the design or template to see what is
possible

--Cecil

On Wed, 2012-02-08 at 18:28 -0800, Jesse Edelstein wrote:
> Hi all. I've gotten into Shoes recently, as I'm a cognitive
> psychologist and it seems to be a practical way to code up
> experiments. I've managed to answer most of my questions through
> searching and trial-and-error (did you know Shoes has a pretty
> functional fullscreen mode?) but I'm still pretty confused about best
> practices for writing multimodal programs.
> 
> What I mean specifically is programs that have one UI, then move to a
> different UI (based on time passing, or user input, or whatever), then
> move on to another one, according to however I've programmed it.
> Ideally you should be able to move between different modes in an
> arbitrary order, so the methods for each mode should be able to set up
> a new interface and then remove it before returning.
> 
> My question is: what's the natural way to do this in Shoes? My code
> currently looks like this:
> 
> def first_task
>   # UI setup
>   # task
>   # UI removal
>   second_task
> end
> 
> def second_task
>   # as in first task
> end
> 
> Shoes.app do
>   # setup
>   first_task
> end
> 
> This does not work well, and it would still be a really hairy way to
> design the program even if it worked properly. For instance, animate()
> loops don't seem to close when a new method is called, so they keep
> running in the background, giving errors if the objects they control
> have been deleted. So what's the more appropriate way to set up a
> multi-mode program?
> 
> Another question: How do I get Shoes to pop up an alert when an
> unhandled error is encountered, instead of piping it to the console
> (which I never remember to check)?
> 
> Thanks, Jesse

Re: Multimodal apps in Shoes

From:
Jesse Edelstein
Date:
2012-02-09 @ 06:23
To make my question
(http://librelist.com/browser//shoes/2012/2/9/multimodal-apps-in-shoes/)
clearer, let me give a minimal example. I'd like to write multimodal
apps in the most obvious way: a series of methods for each mode, with
each one called in sequence by the main Shoes object. But this doesn't
work as advertised; instead everything seems to display at once, even
if it's supposed to wait for user input or something before
continuing. For example:

Shoes.app :width => 800, :height => 500 do

	def present_instructions (instructions)
		text = stack {para instructions}
		keypress do |key|
			if key == " " then
				text.remove	
				break
			end
		end
	end

	def main_task
		stack do
			@textdisplay = para "Here's the main task. Enter your answers below."
			@freeresponse = edit_box :width => 400, :height => 200
		end
	end	

	present_instructions('Instructions go here. Press space to continue')
	main_task()	

end

Re: [shoes] Re: Multimodal apps in Shoes

From:
ashbb
Date:
2012-02-09 @ 14:59
Hi Jesse, Cecil, J and folks,

As already Cecil and J mentioned, there are several ways. ;-)

I tried to edit Jesse's code a little bit.
But I'm not sure this code suits your taste. ;-)

Shoes.app :width => 800, :height => 500 do
 present_instructions = proc do |instructions|
   para instructions
 end

 main_task = proc do
   @textdisplay = para "Here's the main task. Enter your answers below."
   @freeresponse = edit_box :width => 400, :height => 200
 end

 tasks = []
 tasks << present_instructions
 tasks << main_task

 slot = stack{tasks[0]['Instructions go here. Press space to continue']}

 keypress do |key|
   if key == ' ' and !@stop
     slot.clear{tasks[1][]}
     @stop = true
   end
 end
end

ashbb

Re: [shoes] Re: Multimodal apps in Shoes

From:
Cecil Coupe
Date:
2012-02-09 @ 08:38
See the last example of 
http://stackoverflow.com/questions/732967/while-loop-in-ruby-shoes-gui-toolkit
to observe url and visit. It's not in the manual and I don't do it often enough
to remember the rules.  I think you have subclass Shoe. 

Re: [shoes] Re: Multimodal apps in Shoes

From:
Tobias Pfeiffer
Date:
2012-02-09 @ 08:52
url leads to a segfault for me in some easy cases (there is a bug report 
somewhere).

I've extracted the part handling tabs from HacketyHack and used it in 
infoes, I want to try to use the same code in a new app I write and if 
that works out I'll try to get it into main shoes or write some kind of 
gem. I believe this could be what you are looking for.

For the curios, code for the tab in general is there: 
https://github.com/PragTob/infoes/blob/master/lib/infoes/side_tab.rb
A little example tab: 
https://github.com/PragTob/infoes/blob/master/lib/infoes/tabs/home.rb 
(you gotta subclass side_tab)

And here is how you open those tabs: 
https://github.com/PragTob/infoes/blob/master/lib/infoes.rb#L47-62 (for 
a main shoes version/gem I'd likely move this to be class methods of 
SideTab)

Still probably needs some work but useful though.

Tobi

On 02/09/2012 09:38 AM, Cecil Coupe wrote:
> See the last example of
> http://stackoverflow.com/questions/732967/while-loop-in-ruby-shoes-gui-toolkit
> to observe url and visit. It's not in the manual and I don't do it often enough
> to remember the rules.  I think you have subclass Shoe.
>

Re: [shoes] Re: Multimodal apps in Shoes

From:
J. Kaiden
Date:
2012-02-09 @ 11:24
hi Jesse,

  you could take a look at the simple notebook widget here:

https://github.com/lljk/shoes-stuff/blob/master/notebook_widget/notebook_widget_example.rb

  i don't have the time right now (got to head off to work, bummer...) but
i think this could be pretty easily modified to do what you want.

  right now you change pages by clicking on the button (@tab) at the top of
the main window that represents the page you want to see.  if you added a
`show_page(name)` method to the NoteBook widget class that was similar to
the `@tab.click{}` block (and then perhaps removed the #click call so
people can't change pages by themselves,) you could change pages based on
user input rather than button clicks...

  hth,

  - j






On Thu, Feb 9, 2012 at 8:52 AM, Tobias Pfeiffer <
tobias.pfeiffer@student.hpi.uni-potsdam.de> wrote:

> url leads to a segfault for me in some easy cases (there is a bug report
> somewhere).
>
> I've extracted the part handling tabs from HacketyHack and used it in
> infoes, I want to try to use the same code in a new app I write and if
> that works out I'll try to get it into main shoes or write some kind of
> gem. I believe this could be what you are looking for.
>
> For the curios, code for the tab in general is there:
> https://github.com/PragTob/infoes/blob/master/lib/infoes/side_tab.rb
> A little example tab:
> https://github.com/PragTob/infoes/blob/master/lib/infoes/tabs/home.rb
> (you gotta subclass side_tab)
>
> And here is how you open those tabs:
> https://github.com/PragTob/infoes/blob/master/lib/infoes.rb#L47-62 (for
> a main shoes version/gem I'd likely move this to be class methods of
> SideTab)
>
> Still probably needs some work but useful though.
>
> Tobi
>
> On 02/09/2012 09:38 AM, Cecil Coupe wrote:
> > See the last example of
> >
> http://stackoverflow.com/questions/732967/while-loop-in-ruby-shoes-gui-toolkit
> > to observe url and visit. It's not in the manual and I don't do it often
> enough
> > to remember the rules.  I think you have subclass Shoe.
> >
>
>

Re: [shoes] Re: Multimodal apps in Shoes

From:
Jesse Edelstein
Date:
2012-02-09 @ 14:38
Thanks for all the feedback, Cecil, Tobias, & Jake. I'm learning a lot
from all this but I haven't made too much progress yet. I'm working on
refactoring my design to make it a properly object-oriented model in
line with Infoes and that notebook example.

I'm still very unclear on how to move between program elements due to
a keypress, for instance. In my program, I display some initial
instructions, then have the user press the spacebar to advance to the
next screen. What's the sensible way to do this? My intuition is to do
it like this:

class PresentInstructions < Shoes::Widget
	def initialize(instructions)
		@s = stack :margin => 100 do
			para instructions, :font => "Arial 36px", :stroke => white
		end
		@s.hide
	end

	def go
		@s.show
		# wait for user to hit space
		keypress do |key|
			if (key == " ")
				self.stop
				break  #error here!
			end
		end
	end
	
	def stop
		@s.hide
	end

end

I intended to initialize my instructions objects first (following that
notebook example) and then call their #go method to make them active
when needed, assuming that go will return once the user has pressed
space. But this does not work - Ruby throws an error when I try to
break early. Am I not allowed to break out of a keypress loop? If not,
how do I stop polling for keypresses when I'm done looking for them?
Moreover, what's a working way to design this part of my app?

Thanks again for all your advice. It's nice to see that this niche
product has a good community.
Jesse

Re: [shoes] Re: Multimodal apps in Shoes

From:
ashbb
Date:
2012-02-09 @ 15:28
Hi Jesse,

> Am I not allowed to break out of a keypress loop?
No, you can't.

> If not, how do I stop polling for keypresses when I'm done looking for
them?
The following snippet is one of the solutions. ;-)

Shoes.app do
  slot = stack
  keypress do |key|
    unless @stop
      case key
      when ' '
        slot.clear{para 'Your input key is space. So, stop showing input
key.'}
        @stop = :stopped
      else
        slot.clear{para "Your input key is #{key}"}
      end
    end
  end
end

Hope this helps,
ashbb

Re: [shoes] Multimodal apps in Shoes

From:
ashbb
Date:
2012-02-09 @ 14:57
Hi Jesse,

Sorry, I'm late.

> I've gotten into Shoes recently
Fantastic!

> I've managed to answer most of my questions through
> searching and trial-and-error
Great!
But we love to see questions in Shoes ML.
So, thank you so much for posting your mail. :)

> (did you know Shoes has a pretty functional fullscreen mode?)
Ah, sorry. Shoes doesn't support fullscreen mode so far.

About your first question. Try out the following snippet:

module Task
 def first_task
   para "First UI setup\n"
   p = para
   a = animate 2 do |i|
     p.text = "running task: #{i}"
     if i > 10
       a.stop
       clear{second_task}
     end
   end
 end
 def second_task
   para "Second UI setup\n"
   p = para
   a = animate 2 do |i|
     p.text = "running task: #{i}"
     if i > 10
       a.stop
       p.text = 'FIN!'
     end
   end
 end
end

Shoes.app do
 extend Task
 first_task
end


About your second question. Try out this one:

Shoes.app do
 begin
   IO.read 'missing_file'
 rescue Exception => e
   alert e.message
 end
end

I'm not sure that I understand your questions correctly.

But hope this helps,
ashbb

Re: [shoes] Multimodal apps in Shoes

From:
Steve Klabnik
Date:
2012-02-09 @ 15:28
Ash,

> Ah, sorry. Shoes doesn't support fullscreen mode so far.

Actually, Shoes does have a fullscreen mode, it's just a bit buggy,
and not documented:


https://github.com/shoes/shoes/blob/24843c0a9cd1d014409c58ed06a62cff41ee83a0/shoes/native.h#L37

https://github.com/shoes/shoes/blob/24843c0a9cd1d014409c58ed06a62cff41ee83a0/shoes/app.c#L58

https://github.com/shoes/shoes/blob/8b1c84fa9cfef4a380a488212461d7e4abcf798d/shoes/native/gtk.c#L536

https://github.com/shoes/shoes/blob/8b1c84fa9cfef4a380a488212461d7e4abcf798d/shoes/native/cocoa.m#L871

https://github.com/shoes/shoes/blob/24843c0a9cd1d014409c58ed06a62cff41ee83a0/shoes/native/windows.c#L897

Re: [shoes] Multimodal apps in Shoes

From:
ashbb
Date:
2012-02-09 @ 15:34
Hi Steve,

> Actually, Shoes does have a fullscreen mode,
Yeah, you are right. I know the code.

But,
> it's just a bit buggy
This is also true. So, I said "Shoes doesn't support". ;-)

ashbb

Re: [shoes] Multimodal apps in Shoes

From:
Steve Klabnik
Date:
2012-02-09 @ 15:41
> This is also true. So, I said "Shoes doesn't support". ;-)

Fair enough! :)