[cells-gtk-devel] Re: [cells-devel] Something like a def-family-observer?

Peter Hildebrandt peter.hildebrandt at gmail.com
Wed Dec 12 03:21:46 UTC 2007


>
> OK, I understand. You are right, we want the tree-view to update  
> automatically as the model changes, by which I mean either the  
> population of the model or the value of a displayed slot of a node of  
> the model, and normally this is how my GUIs work. It should be easy to  
> get this in cells-gtk.

Thanks for the reassuring words.  Sounds like we're in for some fun :-)

> I may have to build Cells-gtk. Possibly you have missed some existing  
> mechanism in cells-gtk, so I have CCed that list. Or possibly the

Well, I got editing "cells" in the treeview through the gui to work in  
cells-gtk (which was not supported so far).  Thanks to that excercise I  
know the tree-view code in cells-gtk pretty much inside out.  I don't  
think I missed something.

> cells-gtk tree-view got implemented with a static model in mind and it  
> is merely time to break that assumption. No big deal, assuming GTk's API  
> has the chops (which I wager it does).

You're exactly right.  Cells-gtk is only prepared to deal with fully  
replacing the lisp side of the model.  All the code for rebuilding the  
model on the gtk-side is triggered from the def-c-observer on the roots  
slot.  So either you have something simple like a list there (and  
everytime you change it the observer rebuilds the whole model), or you  
have something complex like a family (and it only gets rebuilt when you  
setf that slot)

The GTK trieview OTOH is built on top of a dynamic model.  There is all  
the bits and pieces to do pretty much anything with that model.  I've used  
this tutorial so far:
http://scentric.net/tutorial/treeview-tutorial.html

The API is here:
http://library.gnome.org/devel/gtk/2.11/GtkTreeStore.html

> A question is how much work gets done on the Lisp side. Do we end up  
> with one Lisp widget instance for each observed row? Better yet, for  
> each field of each row? ie, the lisp tree-view runs down the model  
> rooted in "roots" looking for kids of kids and then...

Not at this point.  The current cells-gtk has nothing more fine grained  
than the tree-store/tree-model whatever they call it.  The rows and fields  
are all assembled "on the fly".

But -- this is what I had in mind.

> hmmm, maybe not, and it looks like I better build Cells-gtk.

Keep in mind that it needs the "cells_2.0" branch.  This is not in CVS but  
part of the release on the website.  Also, at least for me (SBCL/linux)  
there
was a bug in gtk-app.lisp, resulting in a crash when closing an  
application.  Line 124 reads

(loop while (> (gtk-main-level) 0) do (gtk-main-quit))

but should be

(dotimes (i (gtk-main-level)) (gtk-main-quit))

> Normally what I do is mirror each thingy on the C side with a thingy on  
> Lisp side, so there would be tree-view and then tree-view-row and maybe  
> tree-view-row-field (or tree-view-cell in spreadsheet-ese). To make  
> things super-flexible, I then make those types parameterizable, so I can  
> make a custom tree-view-cell (by subclassing tree-view-cell) and then  
> specify to tree-view that it should use that subclass as it is  
> traversing my data model building up the Lisp tree-view.

Sounds great.  So I am not the only dreamer out here :)

> At this point, of course, on the Lisp side anyway I can "see" cells-wise  
> everything that is happening, including tree insertion/deletions and  
> changes to slot values of model nodes. The next question is how to tell  
> GTk.

Exactly, that is what I had in mind when I outlined that "tto" strategy.   
Have generic model embody the functionality of observing lisp and updating  
C, and then subclass it for the various cases.

As a side effect this will make handling user input a lot nicer:  The bits  
linking the clos slots to the tree-view cells might know about the inverse  
function and thus propagate a setf back, i.e.

User changes something
   => tree-view widget sends setf to the corresponding connector
     => connector setf's the corresponding slot in the observed model
       => that gets propagated into the connector
         => the connector tells GTK about the change

> Does Gtk give us the granularity to operate on the tree view, ie, does  
> it allow us to say "remove this row" or change this field of this row to  
> show this new value ("My child")? I think you said yes to this in your  
> prior note.

Yes, it does (see pointers above).

> If so, the next question is if we have done the FFI for those bits of  
> the API. :)

Mostly, I'd say.  cells-gtk/gtk-ffi has append/insert functions and most  
of the path/iter stuff to locate items.  A function for setting values is  
also there.  What's left is removing stuff.  Shouldn't be too hard.

> I'll stop here since I am just collecting info, but rest assured this is  
> normal stuff and if the GTk API offers the hooks we should have no  
> problem getting information to flow from the lisp side to Gtk, using the  
> ideas hinted at above.

Cool.  I'm looking forward to it.

Cheers,
Peter


> kt
>
>
>
>>  So I came up with the idea to make the interface to the tree-view a  
>> tree  of cells, so that in effect for every box that is displayed in  
>> the  treeview there is a dependent cell in the treeview (Instead of one  
>> cell  connecting to the kids of the root).
>>  One way to do this would be to have an observer object
>>  (defmodel tto () ((obs :accessor obs :initarg :obs)   
>> (corresponding-point-in-gtk))
>> (def-c-output obs ((self tto))
>>    (call-gtk-and-set corresponding-point-in-gtk new-value))
>>  Then we would make six of these, two per node (name and age) when  
>> roots is  assigned:
>>  (def-c-output roots ((self tree-view))
>>    (mapcar (lambda (nd) (make-instance 'tto :obs (c? (md-name nd))   
>> :corresponding... ...)) (roots self))
>>    ;; of course we'll have to recurse into the kids and the names of  
>> the  accessors
>>    ;; are supplied somewhere to the treeview etc.
>>  Additionally we'd have some sort of structure observer that listens on  
>> the  kids of every node (here three for three nodes) and reacts to  
>> changes by  adding/deleting rows to the tree-view. Additionally it'd  
>> have to  create/remove tto's to listen to the slots of new nodes or  
>> stop listening  to removed nodes.
>>   Another option would be what I dubbed the "family-observer":  Some  
>> piece  of magic that gets notified when any slot in a model or any of  
>> its  decendents gets modified.  The notification would idealy include  
>> the  modified node, the modified slot, the new-value and a path from  
>> the root  to the node (could be a closure, (lambda (n) (nth 2 (nth 3  
>> (nth 0 (kids n]  => (lambda root) is the modified node, or just a list  
>> '(0 3 2)).  That  family observer could then take this  
>> notification/message and do the  appropriate action.
>>  I do not understand cells enough to judge whether this would even be   
>> possible.  So maybe there is something, some instance where all state   
>> changes get passed through, that could filter out the ones going to  
>> root  or its descendents, maybe not.
>>  Well, I hope it's clearer now what I wish to do.
>>  In reply to your comments:
>>  On Tue, 11 Dec 2007 21:03:39 +0100, Ken Tilton  
>> <kennytilton at optonline.net>  wrote:
>>
>>> More below, just retro-inserting notes: normally in /my/ work the  
>>> parent  slot is not even a Cell, but I /have/ done that a couple of  
>>> times on  certain subclasses of Family and it did work.
>>   Yeah, thanks for pointing that out.  I got that confused from time to  
>> time  and was wondering why a (c? parent) does not learn about (kids  
>> parent).
>>
>>> Confused: The kids slot is a Cell, so any rule anywhere (on slots not   
>>> just the ascendants) that references (kids <whatever>) will get  
>>> kicked  off whent that changes. More below on this.
>>   I was wondering whether there would be a way to kick of that rule  
>> when  something deeper down in the tree gets modified (see above, the  
>> family  observer)
>>
>>>>  If you have seen my ton of mails on the cells-gtk-devel list, you  
>>>> know  I'm  doing some GUI work with cells-gtk at the moment.  I ran  
>>>> into the   following issue:  cells-gtk can use a family tree as a  
>>>> natural   representation of the contents of a tree-view.  However,  
>>>> when I change  the  items in that family tree, cells-gtk currently  
>>>> has no way of  updating the  C data structure correspondingly.
>>>
>>>
>>> This sentence seems crucial and puzzles me some. What precisely is  
>>> meant  by "when I change the items in that family tree"? Do you mean  
>>> reorgamize  the tree by moving kids between parents?
>>   Maybe this, maybe changing a cell slot on a node in the tree, maybe  
>> adding  kids, maybe removing them. In effect I want to keep the  
>> projection of the  tree onto the tree-view consistent with the tree.
>>
>>> As for "update the C data structure correspondingly", well, /what/ C   
>>> data structure, this is the first I have heard of it. Do you mean the  
>>> C  struct implementing the tree view, or a C struct one might be   
>>> "inspecting" by mapping its hierarchy to a tree of widgets?
>>   The gtk tree-view displays an internal data structure, consisting of  
>> rows  of "cells".  rows can have children.  Whenever we want to put  
>> some lisp  structure in the treeview, we have to traverse it and build  
>> the  corresponding gtk stuff.
>>
>>> Let me clarify a couple of things first. btw, I do not even have   
>>> Cells-Gtk installed anywhere so I may have to do that if things get  
>>> too  complicated.
>>   I hope it won't come that far :) I really appreciate your help, esp.  
>> given  you won't even use cells-gtk.
>>
>>> First of all, my models normally do not have the parent slot as a  
>>> Cell  at all, meaning I do not move things from one parent to another.  
>>> But!  There have been times when I did that and it did seem to work,  
>>> so let's  keep that in mind going forward.
>>   Probably we won't have to.  I believe this one comes out of a   
>> misunderstanding -- or am I not getting it?
>>
>>> Second, without looking I am almost certain the kids slot of the  
>>> family  class already does let applications react to changes to kids,  
>>> so I am  not clear on why TTO is necessary (unless we are talking  
>>> about also  needing the parent to be a Cell, which as I said might  
>>> Just Work if we  put our minds to it).
>>   This confuses me.  "the kids slot of the family class already does  
>> let  applications react to changes to kids" -- what exactly do you mean  
>> by  that?  Adding/removing kids?  Changes to the kids themselves (setf   
>> (md-name (first (kids root))) "Joe")?
>>  To me it looks like neither happens.
>>  (defparameter root (make-instance 'node :md-name "Root" :kids (c-in  
>> nil)))
>>   => ROOT
>> (defparameter tview (make-instance 'tree-view :roots (c? (kids root))))
>>   => TVIEW
>> (push (make-instance 'node :md-name "child") (kids root))
>>   => (child)
>>  ====> Nothing
>>  (roots tview)
>>   => ("roots have changed" (child))
>>   => (child)
>>  (i.e. the def-c-observer only gets called once I query the slot)
>>
>>> Third, I'd like to understand the functionality better. Is the goal  
>>> to  manipulate a tree on the C side via a [Cells-]Gtk tree view? Or  
>>> just  dynamically restucture a treeview? This is the same question as  
>>> above  where I ask about what is meant by "update the C data  
>>> structure"?
>>   The goal is
>>  I modify lisp stuff
>>   ==>  the GTK tree model stuff ("C data structure") gets updated
>>           ==> The treeview reflects my changes to the lisp stuff
>>  It looks like I got myself into quite a mess here ...
>>  Cheers,
>> Peter
>>
>





More information about the cells-gtk-devel mailing list