From: Tom Sawyer Date: 2002-07-24T12:15:00+09:00 Subject: Re: GUI's and the Rouge, Part III (yes, finally) 1/2 --=-T1K4tQ1ur3mKPvKh/9yM Content-Type: text/plain Content-Transfer-Encoding: 7bit On Tue, 2002-07-23 at 19:07, Clifford Heath wrote: > Tom Sawyer wrote: > > it was stated that a main goal of Rouge was to create a cross-compatible > > gui api that "boiled down" into the native gui of each platform. > > As you've found, it's a *major* piece of work. I should know - I designed > and my company built such a product (called OpenUI) in the 1st half of > the 90's. There are better toolkits out there for this now, of which I like > Qt and fxruby best. You definitely shouldn't build your own, it's a problem > that needs multiple hundreds of thousands of lines of code to solve. interesting OpenUI...well i'm not really building my own. i'm building a layer on top of pre-existing api (ClanLib). wouldn't really consider writing it all from scratch. > > i think too that this is a fantastic idea. > > so that's the final piece and we end up with basically this: > > You've described the architecture of OpenUI, but perhaps haven't understood > the factor that makes it really work: rich asynchronous message passing. > > I'm still of the firm opinion that this is the single integrating feature > which is needed to revolutionise GUI programming. Message delivery needs > to be based on hierarchies of objects, including propagation of undelivered > (or partly-delivered) messages up the hierarchy, publish-subscribe propagation > down the hierarchy, and proxy-address mapping for remote objects. Add that to > the basic queueing facilities needed for asynchronous delivery, with a > priority-nesting feature to provide some minimal sequencing control for > consequential messaging (needed for remote validation for example), and you > have an exceptionally powerful and flexible application framework supporting > separation of presentation and semantic content to the fullest extent possible. rich asynchronous message passing. does it really need to be that "fancy"? perhaps. the communications layer is optional, but i tend to think standard tcp/ip + marshaling might do the job. after all networked games these days don't use much more. (i think). if this part proves too much of a bottle neck we can either do without it or hopefully pull together something more like what you describe. ClanLib also includes some networking features for netowked games. perhaps that would be useful. > The native GUI widgets should be assembled into hierarchies not by API calls, > but by a hierarchical description language - XML probably. In fact I started > making "qtml" - a Qt markup language, which allows simple assembly of arbitrary > widget hierarchies (UIs), and embedded scripting to animate and control the UI. > I'd love to use Ruby with this, it's the most suitable language for the purpose. well, i disagree here. i thought about that option: whether the models should be in markup versus executable code. i went executable b/c we can always make markups that "compile" into the transaction code. but you may be interest in a little program that i threw together that builds tk interfaces from xml. i've attached it. you'll need rexml to run it and you may need to tweak the require statements. tkxml-l.rb is the simple example. > Sorry that much of the above discussion is kind-of schematic, incomplete and > probably confusing, I can discuss the ideas further if they ring anyone's > bells. Suffice it to say that people who've used these ideas in the form of > our (now obsolescent) product have found them to be truly revolutionary. no apology required. thanks for the comments. i'm interested to know more about OpenUI and if you should decide that you could contribute to the project please let me know. ~transami --=-T1K4tQ1ur3mKPvKh/9yM Content-Disposition: attachment; filename=tkxml.rb Content-Transfer-Encoding: quoted-printable Content-Type: text/x-ruby; name=tkxml.rb; charset=ANSI_X3.4-1968 # TkXML=0D # by Thomas Sawyer (transami@runbox.com)=0D # version April 2002 - Alpha (2.04a)=0D # A combination of Ruby/Tk + REXML=20 # to allow for fast and easy creation # of Tk interfaces using standard XML=0D =0D require 'rexml/document'=0D require 'tk'=0D =0D include REXML=0D module TomsLib module TkXML class TkXML=0D =20=0D def initialize(source)=0D @listener =3D TkXML_Listener.new=0D Document.parse_stream(source, @listener)=0D end=0D =20=0D def build=0D Tk.mainloop=0D end=0D =20=0D end=0D =20=0D class TkXML_Listener=0D =20=0D def initialize=0D puts "Initializing TkXML_Listner"=0D @widget =3D Hash.new=0D @widget_stack =3D Array.new=0D @parent =3D nil=0D end=0D =20=0D def tag_start name, attributes=0D =20=0D # get parent, the widget on the bottom of the stack=0D @parent =3D @widget_stack.last=0D =20=0D # pull off the tag name if prefixed with the Tk namespace=0D if name[0..2] =3D=3D "Tk:"=0D tag_name =3D name[3..name.length]=0D else=0D tag_name =3D name=0D end=0D =20=0D # looks life the attributes object given is nothing morethen a arra= y in an array. how lame!=0D # this wll turn it into a hash=0D attr_hash =3D Hash.new=0D attributes.each do |a|=0D attr_hash[a[0]] =3D a[1]=0D end=0D =20=0D # okay, lets do this thing=0D =20=0D # is it a method call or a new widget?=0D if tag_name[0..0] =3D=3D '_'=0D =20=0D # apply method=0D puts "Applying Method: #{name} to #{@parent}"=0D =20=0D # get method name=0D meth_name =3D tag_name[1..tag_name.length]=0D =20=0D # assign the method's parameters=0D p_arr =3D Array.new # array for parameters to be passed=0D p_init =3D Hash.new # for the ordered arguments _1 _2 etc.=0D p_hash =3D Hash.new # for all other named parameters=0D =20=0D # weed out the ordered parameters from the hash parameters=0D attr_hash.each do |n, v|=0D puts " #{n} =3D> #{v}"=0D if n[0..0] =3D=3D "_"=0D p_init[n] =3D v=0D else=0D p_hash[n] =3D v=0D end=0D end=0D =20=0D # sort the ordered parameters based on the hash key=0D # note: this converts p_init into an associative array=0D # then place each one in the parameter array=0D if not p_init.empty?=0D p_init.sort=0D p_init.each do |a|=0D p_arr.push a[1]=0D end=0D end=0D =20=0D # now add the hash to the array if there is one=0D if not p_hash.empty?=0D p_arr.push p_hash=0D end=0D =20=0D # call the method=0D @parent.send(meth_name, *p_arr)=0D =20=0D else=0D =20=0D # create widget=0D puts "Creating Widget: #{name} of #{@parent}"=0D =20=0D widget_class =3D "Tk" + tag_name.capitalize=0D widget_name =3D attr_hash['name']=0D =20=0D if @parent =3D=3D nil=0D @widget[widget_name] =3D Tk.const_get(widget_class).new=0D else=0D @widget[widget_name] =3D Tk.const_get(widget_class).new(@parent= )=0D end=0D =20=0D # assign the widget properties=0D attr_hash.each do |n, v|=0D if not n =3D=3D 'name'=0D puts " #{n} =3D> #{v}"=0D @widget[widget_name].send(n, v)=0D end=0D end=0D =20=0D # push widget on to the stack=0D @widget_stack.push(@widget[widget_name])=0D =20=0D end=0D =20=0D end=0D =20=0D =20=0D def tag_end name=0D =20=0D # pull off the tag name if prefixed with the Tk namespace=0D if name[0..2] =3D=3D "Tk:"=0D tag_name =3D name[3..name.length]=0D else=0D tag_name =3D name=0D end=0D =20=0D # if method then we're finish=0D # else if widget then finish creation and pop off the widget stack=0D if tag_name[0..0] =3D=3D "_"=0D =20=0D puts "End Method: #{name}"=0D =20=0D else=0D =20=0D @parent =3D @widget_stack[-2]=0D current =3D @widget_stack.last=0D =20=0D case tag_name.downcase=0D when "menu"=0D @parent.menu(current)=0D end=0D =20=0D # pop current widget off of stack=0D @widget_stack.pop=0D =20=0D puts "End Widget: #{name}"=0D =20=0D end=0D =20=0D end=0D =20=0D =20=0D def text free_radical=0D if not free_radical.strip =3D=3D ""=0D puts "Error: TkXML does not use XML text entries: #{free_radical}= "=0D end=0D end=0D =20=0D end=0D end end --=-T1K4tQ1ur3mKPvKh/9yM Content-Disposition: attachment; filename=tkxml-1.rb Content-Transfer-Encoding: quoted-printable Content-Type: text/x-ruby; name=tkxml-1.rb; charset=ANSI_X3.4-1968 # TomsLib - Tom's Ruby Support Library # Example: TkXML #1 # Copyright (c) 2002 Thomas Sawyer, Ruby License require 'tomslib/tkxml' include TomsLib::TkXML source =3D %Q{ } tkxml =3D TkXML.new(source) tkxml.build --=-T1K4tQ1ur3mKPvKh/9yM--