Thank you very much Anthony and Adrien, your comments helped me a lot, I
now have plenty of material to think on!
Best,
  ph.

2012/2/15 Anthony Tavener <anthony.tave...@gmail.com>

> Hrm... when I re-read my prior post before sending, it made sense. Several
> hours later it seems inadequate, and I've thought of something to say more
> clearly...
>
> The execution of code bounces between the UI and the mainline. When the
> mainline processes a "gui hit" it will resume the UI code *right where it
> left off (yielded)*... then the UI will do something and get to another
> point where it yields, awaiting input and thereby resuming the mainline
> where it was (back to processing gui hits).
>
> Why would I want this? So that I don't have stateful UI code which has to
> trickle down to the right place all the time. The UI code is clearer
> because it doesn't need to be re-entered from the top each frame. This
> suits the declarative style of GUI specification, like the example you
> gave, since we don't need special state or messages to communicate what the
> GUI is doing. GUI state becomes a property of the... well, the stack. It's
> the current scope of the code.
>
> Hope this helps!
>
>  -Tony
>
>
> On Tue, Feb 14, 2012 at 11:02 AM, Anthony Tavener <
> anthony.tave...@gmail.com> wrote:
>
>> Apologies Philippe, this is a bit long...
>>
>> The "update loop" I mentioned might be a bit of a red-herring, as I'm
>> only using that for continuously active UI elements: such as changing
>> cursor to represent the action which would be taken on click. It has
>> nothing to do with the basic UI flow.
>>
>> I didn't understand delimcc right away, and I hardly understand it now! :)
>>
>> I was looking to write UI code much as your example of packing buttons
>> together with directly bound activation functions.
>>
>> Here's my "menu_of_list", which takes a list of string * 'a pairs,
>> calling GUI code to make a menu using the strings as labels, and using the
>> 'a values as return values...
>>
>> let menu_of_list lst return =
>>   (* snipped: preamble which handles positioning, stacking order, getting
>> font, etc *)
>>   Gui.add_widget gui
>>     (new Gui.vbox pos stacking spacing
>>       (lst |> List.map
>>         (fun (label,value) ->
>>           Gui.wit_fn gui
>>             (new Gui.rectangle_text w h fnt label)
>>             (fun () -> return (Some value) ) )))
>>
>> The important part here is the "return" function. This will resume the UI
>> coroutine. It is given to "menu_of_list" by the UI code, then when the GUI
>> has an activation of a menu button this "return" is called... resuming the
>> UI where it left off, and with the "Some value" which was associated to the
>> button.
>>
>> The magic of how this works is in delimcc capturing portions of the run
>> stack. Here I've extracted the relevant bits of code:
>>
>>
>> (* this runs as a coroutine with the "mainline" *)
>> let ui ui_process () =
>>
>>   (* in actual code, this menu comes after a "right click", for special
>> actions *)
>>   let act = yield ui_process (menu_of_list coord
>>     [ ("Equip",`Equip);
>>       ("Spell",`Spell);
>>       ("End",`End) ] ) in
>>   (* ... handle whatever action the user chose! *)
>>
>>
>> (* given SDL events, calls activation functions of 'hit' widgets *)
>> let gui_react gui events =
>>   let hits = gui_select gui events in
>>   match hits with
>>   | h::t -> begin
>>     match get_binding gui h with
>>     | Some f -> f ()  (* runs activation function of widget, such as
>> "return" to coroutine! *)
>>     | None -> ()
>>     end
>>   | [] -> ()
>>
>> let _ =
>>   (* A prompt is delimcc's mechanism for marking the stack to -limit- the
>>    * continuation, rather than creating whole-program continuations. *)
>>   (* So here, the "ui" is initially run, and will *resume* this mainline
>> continuation
>>    * at the end of the "user" function call. *)
>>   let ui_prompt = new_prompt () in
>>   push_prompt ui_prompt (ui ui_prompt);
>>
>>   ...
>>
>>   (* in mainloop *)
>>     gui_react gui events;
>>
>> ----------------------
>>
>> Now I'm going to restate the yield function here, and try to explain...
>>
>> let yield level fn =
>>   shift level (fun k ->
>>     fn k;
>>     abort level () )
>>
>> "shift" and "abort" are delimcc. This runs the given function "fn" with a
>> continuation 'k'... so this continuation is the "return" function passed to
>> menu_of_list, and therefore bound to each menu-button. The abort exits the
>> "ui coroutine", resuming the mainline, hence the name: yield.
>>
>> The continuation 'k' comes from the shift... the continuation is the code
>> "outside" of the shift call... so when it's called (by the mainline's
>> gui_react), it resume at the end of 'yield' and keep on going... in this
>> example, handling the returned action!
>>
>> I hope this conveys at least the gist of what's going on... I read a lot
>> of papers over-and-over, not understanding... although none were
>> specifically GUI. Delimited continuations have numerous applications and a
>> surprising number of configurations for just a pair of functions! (Abort is
>> really a special case of "reset"... so it's shift and reset, in ump-teen
>> configurations.)
>>
>> I'll try to explain if you have any further questions! However, I'm still
>> trying to sort out how best to write my GUI code -- there is a lot of room
>> for improvement. :)
>>
>>  -Tony
>>
>> PS. I'd like to blame X. Leroy ;)... for a post some 10 years ago
>> replying to someone's attempt to do a GUI in OCaml... Xavier casually
>> replied something like "oh, you can use coroutines". That was a wild goose
>> chase (or Dahu?)! Delimcc didn't exist at the time, and it's native-code
>> implementation came about just a few years ago (thank-you Oleg!). Even
>> then, I had no idea how I was supposed to use a coroutine to write GUI
>> code! Oh well, it was an adventure, and I still don't know if this is a
>> good thing, but I like it a lot more than "signals and slots" -- the usual
>> scattered GUI code which is connected by messages/events.
>>
>>
>> On Tue, Feb 14, 2012 at 3:17 AM, Philippe Veber <philippe.ve...@gmail.com
>> > wrote:
>>
>>> Hi Anthony,
>>>
>>> This looks interesting, however as I'm not very familiar with delimcc
>>> (that's a shame, I admit), I fail to understand the flow of the program.
>>> Would you mind giving a snippet of the update loop you mentionned?
>>>
>>>
>>>> So far, I'm not sure how well this works out for a complete project. I
>>>> like it so far, but I have complexity growing in some "update loop" stuff,
>>>> which are little closures I add to be run each frame-update for reacting to
>>>> mouse-over/hover.
>>>>
>>>>
>>>
>>> Good luck in the hunt for elegant UI (code)!
>>>>
>>>
>>> Let's hope I'm not just Dahu hunting!
>>> (http://en.wikipedia.org/wiki/Dahu)
>>>
>>>
>>>
>>>>
>>>>  Tony
>>>>
>>>>
>>>
>>
>

-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa-roc.inria.fr/wws/info/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

Reply via email to