3 * This code renders the Gtk tree into a set of Gtk elements.
4 * principle = one NodeToGtk wraps around the original 'node'
6 * it's called by the view element with
7 * var x = new JsRender.NodeToGtk(file.tree);
8 var obj = x.munge() as Gtk.Widget;
12 * The idea behind the Javascript tools stuff is that we can
13 * transform what is actually being requested to be rendered
14 * -- eg. an AboutBox, and turn that into load of real widgets..
15 * that could be displayed..
17 * we could go on the theory that we send the whole tree to the 'plugin'
18 * and that would do all the transformations before rendering..
19 * -- this would make more sense...
20 * -- otherwise we would call it on each element, and might get really confused
26 public class JsRender.NodeToGtk : Object {
29 Object wrapped_object;
32 Gee.ArrayList<NodeToGtk> children;
34 Gee.ArrayList<string> els;
35 //Gee.ArrayList<string> skip;
36 Gee.HashMap<string,string> ar_props;
37 public static int vcnt = 0;
41 public NodeToGtk( Project.Gtk project, Node node , NodeToGtk? parent_obj = null)
44 this.project = project;
46 this.els = new Gee.ArrayList<string>();
47 this.children = new Gee.ArrayList<NodeToGtk>();
48 //this.skip = new Gee.ArrayList<string>();
49 this.ar_props = new Gee.HashMap<string,string>();
50 this.parentObj = parent_obj;
52 if (parent_obj == null) {
53 // then serialize up the node,
54 // send it to javascript for processsing,
55 // then rebuild node from return value..
57 var ret = Palete.Javascript.singleton().executeFile(
58 BuilderApplication.configDirectory() + "/resources/node_to_gtk.js",
62 var new_node = new Node();
63 var pa = new Json.Parser();
64 pa.load_from_data(ret);
66 var rnode = pa.get_root();
69 new_node.loadFromJson(rnode.get_object(), 2);
72 } catch (Palete.JavascriptError e) {
73 GLib.debug("Error: %s\n", e.message);
74 } catch (GLib.Error e) {
75 GLib.debug("Error: %s\n", e.message);
83 public Object? munge ( )
85 var ret = this.mungeNode( );
90 return ret.wrapped_object;
93 public NodeToGtk? mungeChild ( Node cnode)
95 var x = new NodeToGtk( this.project, cnode, this);
101 public NodeToGtk? mungeNode()
104 var parent = this.parentObj != null ? this.parentObj.wrapped_object : null;
105 var cls = this.node.fqn().replace(".", "");
106 var ns = this.node.fqn().split(".")[0];
107 var gtkbuilder = new global::Gtk.Builder();
109 var cls_gtype = gtkbuilder.get_type_from_name(cls);
110 print("Type: %s ?= %s\n", this.node.fqn(), cls_gtype.name());
112 if (cls_gtype == GLib.Type.INVALID) {
113 print("SKIP - gtype is invalid\n");
116 // if it's a window... -- things we can not render....
118 if (cls_gtype.is_a(typeof(global::Gtk.Window))) {
119 // what if it has none...
120 if (this.node.items.size < 1) {
123 return this.mungeChild(this.node.items.get(0));
125 if (cls_gtype.is_a(typeof(global::Gtk.Popover))) {
126 // what if it has none...
127 if (this.node.items.size < 1) {
130 return this.mungeChild(this.node.items.get(0));
132 if (cls_gtype.is_a(typeof(global::Gtk.Widget))) {
136 var ret = Object.new(cls_gtype);
137 ret.ref(); //??? problematic?
138 this.wrapped_object = ret;
143 //case "GtkTreeStore": // top level.. - named and referenced
144 case "GtkListStore": // top level.. - named and referenced
145 //case "GtkTreeViewColumn": // part of liststore?!?!
146 //case "GtkMenu": // top level..
147 //case "GtkCellRendererText":
148 case "GtkSourceBuffer":
149 case "GtkClutterActor"://fixme..
150 case "GtkClutterEmbed"://fixme.. -- we can not nest embedded.. need to solve..
160 // GTK 4 does not appear to have any way to determine if a element is a container..
161 //if (parent != null && parent.get_type().is_a(typeof(global::Gtk.Container))) {
162 this.packContainerParams();
164 var cls_gir =Palete.Gir.factoryFqn(this.project, this.node.fqn());
165 if (cls_gir == null) {
168 //var id = this.node.uid();
169 //var ret = @"$pad<object class=\"$cls\" id=\"$id\">\n";
171 var props = cls_gir.props;
174 var pviter = props.map_iterator();
175 while (pviter.next()) {
177 // print("Check: " +cls + "::(" + pviter.get_value().propertyof + ")" + pviter.get_key() + " " );
178 var k = pviter.get_key();
179 // skip items we have already handled..
180 if (!this.node.has(k)) {
183 // find out the type of the property...
184 var type = pviter.get_value().type;
185 type = Palete.Gir.fqtypeLookup(this.project, type, ns);
187 var ocl = (ObjectClass) cls_gtype.class_ref ();
188 var ps = ocl.find_property(k);
190 // attempt to read property type and enum...
193 var vt = ps.value_type;
196 var raw_val = this.node.get(k).strip();
197 var rv_s = raw_val.split(".");
198 if (rv_s.length > 0) {
199 raw_val = rv_s[rv_s.length-1];
200 EnumClass ec = (EnumClass) vt.class_ref ();
202 for (var i =0;i< ec.n_values; i++) {
203 var ev = ec.values[i].value_name;
204 var ev_s= ev.split("_");
205 if (raw_val == ev_s[ev_s.length-1]) {
206 var sval = GLib.Value(typeof(int));
207 sval.set_int(ec.values[i].value);
208 ret.set_property(k, sval);
224 var val = this.toValue(this.node.get(k).strip(), type);
226 print("skip (failed to transform value %s type = %s from %s\n",
227 cls + "." + k, type, this.node.get(k).strip());
230 print ("set_property ( %s , %s / %s)\n", k, this.node.get(k).strip(), val.strdup_contents());
233 ret.set_property(k, val);
238 // for now... - just try the builder style packing
242 if (this.node.items.size < 1) {
246 for (var i = 0; i < this.node.items.size; i++ ) {
248 var ch = this.mungeChild(this.node.items.get(i));
250 this.children.add(ch);
255 this.afterChildren();
264 public void afterChildren()
266 // things like GtkNotebook - we have to pack children after they have been created..
267 var cls = this.node.fqn().replace(".", "");
269 if (cls == "GtkNotebook") {
270 this.afterChildrenGtkNotebook();
277 public void afterChildrenGtkNotebook()
279 // we have a number of children..
280 // some are labels - this might need to be more complex...
281 // perhaps labels should be a special property labels[] of the notebook..
282 var labels = new Gee.ArrayList<NodeToGtk>();
283 var bodies = new Gee.ArrayList<NodeToGtk>();
284 for (var i = 0; i < this.children.size; i++) {
285 var cn = this.children.get(i).node.fqn().replace(".", "");
286 if (cn != "GtkLabel") {
287 bodies.add(this.children.get(i));
290 labels.add(this.children.get(i));
292 for (var i = 0; i < bodies.size; i++) {
293 var lbl = (i > (labels.size -1)) ? null : labels.get(i);
295 ((global::Gtk.Notebook)this.wrapped_object).append_page(
296 (global::Gtk.Notebook) bodies.get(i).wrapped_object,
297 lbl != null ? (global::Gtk.Notebook) lbl.wrapped_object : null
308 * called after the this.object has been created
309 * and it needs to be packed onto parent.
311 public void packParent()
313 var cls = this.node.fqn().replace(".", "");
315 var gtkbuilder = new global::Gtk.Builder();
316 var cls_gtype = gtkbuilder.get_type_from_name(cls);
318 if (this.parentObj == null) {
323 var parent = this.parentObj.wrapped_object;
327 if (parent == null) { // no parent.. can not pack.
330 // ------------- handle various special parents .. -----------
332 var par_type = this.parentObj.node.fqn().replace(".", "");
334 if (par_type == "GtkNotebook") {
335 // do not pack - it's done afterwards...
339 // ------------- handle various child types.. -----------
341 if (cls == "GtkMenu") {
346 if (cls == "GtkTreeStore") { // other stores?
347 // tree store is buildable??? ---
348 this.packTreeStore();
351 if (cls =="GtkTreeViewColumn") { // other stores?
352 //?? treeview column is actually buildable -- but we do not use the builder???
353 this.packTreeViewColumn();
356 if (cls_gtype.is_a(typeof(global::Gtk.CellRenderer))) { // other stores?
357 this.packCellRenderer();
363 // -- handle buildable add_child..
364 if ( cls_gtype.is_a(typeof(global::Gtk.Buildable))
366 parent.get_type().is_a(typeof(global::Gtk.Buildable))
369 ((global::Gtk.Buildable)parent).add_child(gtkbuilder,
370 this.wrapped_object, null);
379 public void packMenu()
383 var parent = this.parentObj.wrapped_object;
384 if (!parent.get_type().is_a(typeof(global::Gtk.Widget))) {
385 print("skip menu pack - parent is not a widget");
390 var p = (global::Gtk.Menu)this.wrapped_object;
391 ((global::Gtk.Widget)parent).button_press_event.connect((s, ev) => {
392 p.set_screen(Gdk.Screen.get_default());
394 p.popup_at_pointer(ev);
400 public void packTreeStore()
402 var parent = this.parentObj.wrapped_object;
403 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
404 print("skip treestore pack - parent is not a treeview");
407 ((global::Gtk.TreeView)parent).set_model((global::Gtk.TreeModel)this.wrapped_object);
410 public void packTreeViewColumn()
412 var parent = this.parentObj.wrapped_object;
413 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
414 print("skip packGtkViewColumn pack - parent is not a treeview");
417 ((global::Gtk.TreeView)parent).append_column((global::Gtk.TreeViewColumn)this.wrapped_object);
418 // init contains the add_attribute for what to render...
423 public void packCellRenderer()
425 var parent = this.parentObj.wrapped_object;
426 if (!parent.get_type().is_a(typeof(global::Gtk.TreeViewColumn))) {
427 print("skip packGtkViewColumn pack - parent is not a treeview");
430 ((global::Gtk.TreeViewColumn)parent).pack_start((global::Gtk.CellRenderer)this.wrapped_object, false);
431 // init contains the add_attribute for what to render...
436 public void packContainerParams()
439 if (this.parentObj == null) {
442 // child must be a widget..
443 if (!this.wrapped_object.get_type().is_a(typeof(global::Gtk.Widget))) {
447 var parent_gir = Palete.Gir.factoryFqn(this.project, this.parentObj.node.fqn());
449 var parent = this.parentObj.wrapped_object;
451 if (parent_gir == null) {
455 // let's test just setting expand to false...
456 var cls_methods = parent_gir.methods;
457 if (cls_methods == null) {
461 if (!this.node.props.has_key("* pack") ||
462 this.node.props.get("* pack").val.length < 1) {
466 var ns = this.parentObj.node.fqn().split(".")[0];
468 var pack = this.node.props.get("* pack").val.split(",");
470 // this tries to use the parameter names from the '*pack' function as properties in child_set_property.
471 // for a grid it's trying to do left/top/width/height.
474 if (cls_methods.has_key(pack[0])) {
475 var mparams = cls_methods.get(pack[0]).paramset.params;
476 for (var i = 1; i < mparams.size; i++ ) {
477 if (i > (pack.length -1)) {
480 Palete.Gir.checkParamOverride(mparams.get(i));
481 var k = mparams.get(i).name;
485 var type = mparams.get(i).type;
486 type = Palete.Gir.fqtypeLookup(this.project, type, ns);
488 var val = this.toValue(pack[i].strip(), type);
490 print("skip (failed to transform value %s type = %s from %s\n",
491 this.parentObj.node.fqn() + "." + k, type, pack[i].strip());
494 print ("pack:set_property ( %s , %s / %s)\n", k, pack[i].strip(), val.strdup_contents());
496 //((global::Gtk.Container)parent).child_set_property(
497 // (global::Gtk.Widget)this.wrapped_object , k, val);
509 public GLib.Value? toValue(string val, string type) {
513 if (type == "string") {
514 var qret = GLib.Value(typeof(string));
515 qret.set_string(val);
521 * var gtkbuilder = new global::Gtk.Builder();
522 var prop_gtype = gtkbuilder.get_type_from_name(type);
525 if (prop_gtype == GLib.Type.INVALID) {
536 var ret = GLib.Value(typeof(bool));
537 ret.set_boolean(val.down() == "false" ? false : true);
541 var ret = GLib.Value(typeof(uint));
542 ret.set_uint(int.parse(val));
546 var ret = GLib.Value(typeof(int));
547 ret.set_int(int.parse(val));
553 var ret = GLib.Value(typeof(long));
554 ret.set_long((long)int64.parse(val));
558 var ret = GLib.Value(typeof(ulong));
559 ret.set_ulong((ulong) uint64.parse(val));
563 var ret = GLib.Value(typeof(float));
564 ret.set_float((float)double.parse(val));
568 var ret = GLib.Value(typeof(string));
575 var sval = GLib.Value(typeof(string));
576 sval.set_string(val);
578 if (!sval.transform(ref ret)) {
585 // should not get here..