From: Rich Kilmer Date: 2002-07-21T04:26:40+09:00 Subject: RE: GUI's and the Rouge, Part II Apologize in advance...this is a LONG response... > -----Original Message----- > From: Tom Sawyer [mailto:transami@transami.net] > Sent: Saturday, July 20, 2002 1:01 PM > To: ruby-talk ML > Subject: GUI's and the Rouge, Part II > > in part one of this message i mention the problem of non-POLS and > ugliness when it came to hand coding a GUI interface. follow this link. > it is example code of the Rouge's utopia: > > http://www.rubyide.org/cgi-bin/wiki.pl?RougeArchitecture/Alpha Well I have not looked at this in a bit. I wrote this in an evening as more of a proof of concept than anything else. Sean Russell had ideas that appear to follow yours more closely than mine. BTW: I have uploaded the source that enabled this to: http://www.infoether.com/ruby/utopia.zip It does not show it in the example, but the attributes and available widget definitions are completely extensible in the model (see utopia.rb). Again, it was more of an experiment than a "real solution" to the problem of GUI abstraction. > > i can honestly say this code is probably better than any i have ever > seen, but i'm sorry, it's still just dosen't look like my idea of gui > utopia. it is still a traditional approach, albiet very innovative in > its use of ruby's OO and iterators, it nonetheless follows the same > overall design characteristics of other tools: defining each and every > widget, designating *content* and style, their coorelation, and binding > procedures before passing off execution control (app.controller.start) First, execution control is not necessarily passed off by starting the controller. It does not have to be, but since Ruby's threading is non-native, most UI toolkits kind of take over. This could be addressed (without adding native threads to Ruby)...such as having another process that presents and controls the UI and communicates to the Ruby process via a socket...like X. Second, I have no problem with binding an object-attribute in as a binding to a widget. Like: class MyClass attr_accessor :avar def initialize @avar = "" end end myobj = MyClass.new myLabel(:label).text(bind_object(myobj, :avar)) and when the method bind_object is called it aliases the original avar= method with one that updates the Label's 'text' attribute (and vice versa). Or to more align with your example below: myobj.extend Utopia::WidgetBinder myobj.bind_widget(mainWindow.myLabel, :avar) > to the gui engine. but, i hear you thinking, "what other way is there? > that's just how it's done!" well, i emphisized content above because its > the key to a better approach. we can get a taste of this by looking > amrita: > > http://kari.to/amrita/sources/docs/QuickStart > > the beauty of amrita lies in the fact that the data which is to appear > in the end result contributes to its design. thus, in part, the layout > does not have to be specified because the data itself designates it. the > end result is cleaner leaner code. in effect amrita has done what OO > design is intended to do, it has given precedence to the data model. Well, in amrita, the hierarchy of the data has to match the hierarchy of the (HTML) UI. As can be shown in this example from the QuickStart doc above:
nameauthor
data = { :table1=>[ { :name=>"Ruby", :author=>"matz" }, { :name=>"perl", :author=>"Larry Wall" }, { :name=>"python", :author=>"Guido van Rossum" }, ] } You see, the minimum you need is a hierarchy in your design of the UI because UIs are built using a "container/component" model. My example from utopia presented a simple hierarchy, but one that needs to be specified somewhere. That I fully specified all of the attributes of the elements in the UI...up front...does not mean it needs to be so. You could do: require 'utopia' app = Utopia.new_application("My Application") mainWindow = app.modeller.build(:window).body { icon(:icon) menu(:menubar).items { file(:menu) help(:menu) } fruit_panel(:panel).body { firstName(:textfield) lastName(:textfield) favoriteFruit(:textarea) submit(:button) clear(:button) } } Then do: mainWindow.fruit_panel.body.firstName.text.bind_object(obj, :foo); > > although amrita is a unidirection html/xhtml templating system, her > principles just as easily carry over to guis. arbitrarily, as > programmers, we can think of it like this: instead of widget.displays(x) > we get x.widgetized. let me provide a mock code fragment to help > clearify. we'll call our imaginary gui toolkit, RougeDuex. > > require 'rougeduex' > > class MyClass > attr_accessor avar > def initialize > @avar = "" > end > end > > myobj = MyClass.new > myobj.avar.extend RougeDeux::WidgetFactory(:Label) > > mywin = RougeDuex::WidgetFactory(:Window).show > mywin.embody { > pack myobj.avar, RougeDuex::TOP > } > > myobj.avar = "Hello, World!" > > and just like that we have a window with a label in it greeting us. OK, now give me syntax for the example I presented on the the rubyide site. Your idea of mixing the widget capability into the object is cool, but how the widgets get organized on the screen needs to be defined somewhere. > > you might notice something a bit odd about this very simple example: the > window was displayed prior to the label being added. this is a key > point. by retaining execution, such that the gui is a spawned processes, > we retain the ability to modify it "on-the-fly". just think of all the > neat tricks we can do with that! no longer are we limited to just the > event model of the gui's engine. morever, notice that the class Again, I absolutely agree with you, and I don't think we should be limited to the event model of the GUI (OS'es aren't). > definition is completly clean. there's no mention of RougeDuex anywhere > in it, nonetheless it is direclty linked to our gui. should avar change > for any reason, so will our label. and if avar were a text entry field > or any other input widget, instead of a label, avar would automagically > reflect that input. Again, having the UI widgets bind to non-UI objects is cool, as I showed above. > > you may wonder how other aspects of avar as a label get designated. well > since avar was extended to be a label it gained a few things that allow > us to do that: myobj.avar.style={:color=>'red'}, for example. no > problem! > > also one might be concerned about performance with such dynamic > rendering, since anytime one changes a variable the gui requires > refreshing. well, a transaction model can help with that were it is > essential. > > so there's the ideal, my friends. i am sure certain elements of the > current Rouge project could be carried over into this, and i think the > end result would be the easiest, most intuitive and fun (like ruby!) gui > to ever have the priviledge of being coded by you ;-) I am not hung up on anything done so far (it was a quick hack), but we need to see semi-realistic examples with windows, menus, events, etc. > > in the last part of my series (don't ask me what posessed me to do this, > i don't know!) i'll go into the possabilities of implementation. > I will look forward to it. > > ~transami > > _(")_ v man > \v/ > ^ ^