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 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 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 >>> >>> >> >