Heres the prize!
example.bmx
Dunno about you but I'm tired of long winded event select clauses... Delphi introduced me to event callback ages ago and its a powerful idea.
For the time being I'm using a couple of Tmap's to convert pointers but I could get round the need for both if only all BRL objects had a UserData:Object field...
andhow its a bit hackerish cause I tried out a bunch of different ideas.
Idealy it would need a more specific editor (but glade will fill the gap for a fair while!) it only has callbacks for 2 event types three gui object types and the minimum of gadget properties.
That said even with such a limited implementation it shows the convienience of this approch in terms of rapid application development.
I'd really welcome peoples feedback on this as I think that a community user interface system like this would greatly speed up gui development
loadglade.bmx
test1.glade (load and visually edit widgets with glade)
if the callback functions were in gui editor properties then the whole code could be automatically created...
example.bmx
Import "loadglade.bmx" LoadGlade("test1\test1.glade") Global edit1:guiwrap=findGadget("entry1") Global label1:guiwrap=findGadget("label1") Global button1:guiwrap=findGadget("button1") Global mainwindow:guiwrap=findGadget("window1") ' you can share callback functions ie button2.setActionCallBack(quitme) mainwindow.setCloseCallBack(quitme) edit1.setActionCallBack(edit1action) button1.setActionCallBack(button1action) processGUI() Function quitme() ; End ; End Function Function edit1action() ; SetGadgetText(label1.maxgad,GadgetText(edit1.maxgad)) ; End Function Function button1action() SetGadgetText(edit1.maxgad,"") SetGadgetText(label1.maxgad,"") End Function
Dunno about you but I'm tired of long winded event select clauses... Delphi introduced me to event callback ages ago and its a powerful idea.
For the time being I'm using a couple of Tmap's to convert pointers but I could get round the need for both if only all BRL objects had a UserData:Object field...
andhow its a bit hackerish cause I tried out a bunch of different ideas.
Idealy it would need a more specific editor (but glade will fill the gap for a fair while!) it only has callbacks for 2 event types three gui object types and the minimum of gadget properties.
That said even with such a limited implementation it shows the convienience of this approch in terms of rapid application development.
I'd really welcome peoples feedback on this as I think that a community user interface system like this would greatly speed up gui development
loadglade.bmx
Import BaH.Libxml Global gadList:TList=New TList Global pointermap:tmap=New Tmap Global gadgetmap:tmap=New Tmap Type guiWrap Field maxgad:Tgadget Field props:tmap Field closeCallback()=Null Field actionCallback()=Null Function create:guiWrap() Local g:guiWrap=New guiWrap g.props=New Tmap Return g EndFunction Method setCloseCallBack(ccb:Byte Ptr) closeCallback=ccb EndMethod Method setActionCallBack(acb:Byte Ptr) actionCallback=acb EndMethod EndType Function processGUI() While WaitEvent() Local eg:Tgadget Local gw:guiwrap eg=Tgadget(EventSource()) If eg Then gw=guiwrap(MapValueForKey(gadgetmap,eg)) Select EventID() Case EVENT_WINDOWCLOSE If gw.closeCallback Then gw.closeCallback() Case EVENT_GADGETACTION If gw.actionCallback Then gw.actionCallback() End Select Wend EndFunction Function findGadget:guiwrap(name:String) Return guiwrap(MapValueForKey(pointermap,name)) EndFunction Function loadGlade(docname:String) parseDoc(docname) createInteface() EndFunction Function createInteface() Global lastwindow:guiwrap For Local g:guiWrap=EachIn GadList Local id:String,x:Int,y:Int,w:Int,h:Int,title:String,label:String,text:String Local parentid:guiWrap,pid:String id=String(g.props.ValueForKey("id")) x=Int(String(g.props.ValueForKey("x"))) y=Int(String(g.props.ValueForKey("y"))) w=Int(String(g.props.ValueForKey("width_request"))) h=Int(String(g.props.ValueForKey("height_request"))) title=String(g.props.ValueForKey("id")) label=String(g.props.ValueForKey("label")) text=String(g.props.ValueForKey("text")) pid=String(g.props.ValueForKey("id")) If w=0 Or h=0 Then Print "WARNING you must explicitly set width and height in glade for "+pid Select String(g.props.ValueForKey("class")) Case "GtkWindow" g=guiWrap.create() g.maxgad=CreateWindow(title,x,y,w,h) lastwindow=g ' this is a temp bodge todo can gadget parents be specified after creation? Case "GtkButton" g=guiWrap.create() g.maxgad=CreateButton(label,x,y,w,h,lastwindow.maxgad) Case "GtkLabel" g=guiWrap.create() g.maxgad=CreateLabel(label,x,y,w,h,lastwindow.maxgad) Case "GtkEntry" g=guiWrap.create() g.maxgad=CreateTextField(x,y,w,h,lastwindow.maxgad) SetGadgetText g.maxgad,text EndSelect pointermap.insert(pid,g) If g.maxgad Then gadgetmap.insert(g.maxgad,g) Next EndFunction ' todo check if gtkfixed causes "null" object.... Function parseNodeChildren(doc:TxmlDoc, node:TxmlNode, parentid:String,skip:Int=False,ntype:String="") Global currentGad:guiWrap Local uri:String Local list:TList = node.getChildren() For node = EachIn list If node.getName() = "widget" Then currentGad=guiWrap.create() ListAddLast GadList,currentGad If node.getattribute("class")<>"GtkFixed" Then currentGad.props.insert("class",node.getattribute("class")) MapInsert(currentGad.props,"id",node.getattribute("id")) MapInsert(currentGad.props,"parentid",parentid) parentid=node.getattribute("id") parseNodeChildren(doc,node,node.getattribute("id")) Else parseNodeChildren(doc,node,parentid,True) End If End If If node.getName() = "child" Then parseNodeChildren(doc,node,parentid) If node.getName()= "property" And Not skip Then MapInsert(currentGad.props,node.getattribute("name"),node.getContent()) If node.getName()= "packing" And Not skip Then parseNodeChildren(doc,node,parentid,False,"packing") Next End Function Function parseDoc(docname:String) Local doc:TxmlDoc Local node:TxmlNode doc = TxmlDoc.parseFile(docname) If doc = Null Then Print "Document not parsed successfully." Return End If node = doc.getRootElement() If node = Null Then Print "empty document" doc.free() Return End If If node.getName() <> "glade-interface" Then Print "document of the wrong type, root node <> glade-interface" doc.free() Return End If parseNodeChildren(doc, node, "ROOT") doc.free() End Function
test1.glade (load and visually edit widgets with glade)
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> <!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> <glade-interface> <widget class="GtkWindow" id="window1"> <property name="width_request">500</property> <property name="height_request">400</property> <property name="visible">True</property> <property name="title" translatable="yes">window1</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> <property name="modal">False</property> <property name="resizable">True</property> <property name="destroy_with_parent">False</property> <property name="decorated">True</property> <property name="skip_taskbar_hint">False</property> <property name="skip_pager_hint">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <property name="focus_on_map">True</property> <property name="urgency_hint">False</property> <child> <widget class="GtkFixed" id="fixed1"> <property name="visible">True</property> <child> <widget class="GtkButton" id="button1"> <property name="width_request">52</property> <property name="height_request">25</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">button1</property> <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </widget> <packing> <property name="x">40</property> <property name="y">72</property> </packing> </child> <child> <widget class="GtkEntry" id="entry1"> <property name="width_request">158</property> <property name="height_request">23</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="editable">True</property> <property name="visibility">True</property> <property name="max_length">0</property> <property name="text" translatable="yes"></property> <property name="has_frame">True</property> <property name="invisible_char">*</property> <property name="activates_default">False</property> </widget> <packing> <property name="x">96</property> <property name="y">144</property> </packing> </child> <child> <widget class="GtkLabel" id="label1"> <property name="width_request">160</property> <property name="height_request">16</property> <property name="visible">True</property> <property name="label" translatable="yes">label1</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> <property name="angle">0</property> </widget> <packing> <property name="x">96</property> <property name="y">176</property> </packing> </child> </widget> </child> </widget> </glade-interface>
if the callback functions were in gui editor properties then the whole code could be automatically created...