• GtkAda's "On_Edited"

    From John Perry@21:1/5 to All on Sun May 29 22:28:41 2022
    I'm trying to edit a cell in a Tree_View with a List_Store, and saw in GtkAda's User Guide that it offers the On_Edited procedure. I set up a callback this way with the following procedure:

    procedure Editing_Done
    ( Self : access Gtk_Cell_Renderer_Text_Record'Class;
    Path : Glib.UTF8_String; -- this is the row
    New_Text : Glib.UTF8_String
    ) is
    begin
    Tio.Put_Line( Get_Property(Self, Gtk.Cell_Renderer_Text.Text_Property)'Image ); -- line 1
    Tio.Put_Line(Path'Image); -- line 2
    Tio.Put_Line(New_Text'Image); -- line 3
    Set_Property(Self, Gtk.Cell_Renderer_Text.Text_Property, New_Text);
    Self.Stop_Editing( False );
    Tio.Put_Line( Get_Property(Self, Gtk.Cell_Renderer_Text.Text_Property)'Image ); -- line 4
    end Editing_Done;

    I didn't really expect this to work, and it doesn't, but here's what I have verified it does do, in order:

    * prints the data that was in the cell before editing (line 1)
    * prints the row that was edited (line 2)
    * prints the new text (line 3)
    * prints the data that is in the cell as the procedure ends (line 4)

    Lines 3 and 4 agree, which is great! But what I see in the TreeView is that the cell reverts after editing to the value in Line 1.

    My questions:

    1) The documentation of On_Edited states that I am supposed to "update the model and store New_Text at the position indicated by Path." How do I get the model? I understand that "Path" indicates the row in the List_Store / TreeView, but Get_Model's
    Signature requires a TreeView, which I do not have.

    2) What else might I be missing from a correct implementation of the On_Edited callback?

    thanks in advance
    john perry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to John Perry on Mon May 30 08:47:01 2022
    On 2022-05-30 07:28, John Perry wrote:
    I'm trying to edit a cell in a Tree_View with a List_Store, and saw in GtkAda's User Guide that it offers the On_Edited procedure. I set up a callback this way with the following procedure:

    procedure Editing_Done
    ( Self : access Gtk_Cell_Renderer_Text_Record'Class;
    Path : Glib.UTF8_String; -- this is the row
    New_Text : Glib.UTF8_String
    ) is
    begin
    Tio.Put_Line( Get_Property(Self, Gtk.Cell_Renderer_Text.Text_Property)'Image ); -- line 1
    Tio.Put_Line(Path'Image); -- line 2
    Tio.Put_Line(New_Text'Image); -- line 3
    Set_Property(Self, Gtk.Cell_Renderer_Text.Text_Property, New_Text);
    Self.Stop_Editing( False );
    Tio.Put_Line( Get_Property(Self, Gtk.Cell_Renderer_Text.Text_Property)'Image ); -- line 4
    end Editing_Done;

    I didn't really expect this to work, and it doesn't, but here's what I have verified it does do, in order:

    * prints the data that was in the cell before editing (line 1)
    * prints the row that was edited (line 2)
    * prints the new text (line 3)
    * prints the data that is in the cell as the procedure ends (line 4)

    Lines 3 and 4 agree, which is great! But what I see in the TreeView is that the cell reverts after editing to the value in Line 1.

    My questions:

    1) The documentation of On_Edited states that I am supposed to "update the model and store New_Text at the position indicated by Path." How do I get the model? I understand that "Path" indicates the row in the List_Store / TreeView, but Get_Model's
    Signature requires a TreeView, which I do not have.

    On_* procedures are useless most of the time. Instead, you have to
    instantiate Gtk.Handlers.User_Callback with a parameter indicating the
    widget:

    package Edited_Handlers is
    new Gtk.Handlers.User_Callback
    ( Gtk_Cell_Renderer_Text_Record,
    My_Widget_Where_The_Tree_View_Lives_Ptr
    );

    The parameter could be Tree_Vuew as well, but having a widget is always
    a better design.

    Usually you derive your widget from some container like Gtk_Grid. The
    extension holds children and anything else you would need. E.g.:

    type My_Widget_Where_The_Tree_View_Lives is new Gtk_Grid_Record with
    View : Gtk_Tree_View;
    Store : Gtk_List_Store;
    Fancy_Button : Gtk_Button;
    ...
    end record;

    Define Gtk_New and override Initialize. In the Initialize after you
    called Gtk_Grid's Initialize you create all children and connect to the
    signal "editing-done" to the renderer:

    procedure Editing_Done
    ( Self : access Gtk_Cell_Renderer_Text_Record'Class;
    Path : UTF8_String;
    New_Text : UTF8_String;
    Widget : My_Widget_Where_The_Tree_View_Lives_Ptr
    )

    Now when it is called you have the tree View and the list store (= the
    model) in the callback. Use Get_Iter_From_String in order to get the
    iterator from Path. Change the store at the iterator if you accept the
    edit. That's all.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John Perry@21:1/5 to All on Mon May 30 00:46:39 2022
    On_* procedures are useless most of the time.

    I guess you mean in GtkAda? I've found them invaluable in other contexts. If so, that's disappointing. To be fair, in the hours of reading on this I did notice that Gtk+ itself makes this difficult; the On_* procedures seem to be a GtkAda enhancement.

    In the end I made it work with an On_* design, but it was your suggestion that helped! I used the second form of On_Edited and passed a TreeView in the slot. To get the model:

    Tree_View: Gtk_Tree_View := Gtk_Tree_View(Self);
    Model: Gtk_Tree_Model := Get_Model( Tree_View );
    Iter : Gtk_Tree_Iter := Get_Iter_From_String(Model, Path);
    Store: Gtk_List_Store := Gtk_List_Store( To_Object(Model) );

    Getting the rest wasn't too hard after I had that. What I hadn't understood at first was that the Model had to be converted from the Interface via the To_Object function.

    Thank you very much, and also for the quick answer!

    john perry

    PS If anyone knows how to make the first form of On_Edited work, I'd be delighted to know.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dmitry A. Kazakov@21:1/5 to John Perry on Mon May 30 20:57:23 2022
    On 2022-05-30 09:46, John Perry wrote:
    On_* procedures are useless most of the time.

    I guess you mean in GtkAda?

    Yes.

    I've found them invaluable in other contexts. If so, that's disappointing. To be fair, in the hours of reading on this I did notice that Gtk+ itself makes this difficult; the On_* procedures seem to be a GtkAda enhancement.

    Yes, GtkAda adds a typed layer on top of untyped GTK signals.

    In the end I made it work with an On_* design, but it was your suggestion that helped! I used the second form of On_Edited and passed a TreeView in the slot. To get the model:

    Tree_View: Gtk_Tree_View := Gtk_Tree_View(Self);
    Model: Gtk_Tree_Model := Get_Model( Tree_View );
    Iter : Gtk_Tree_Iter := Get_Iter_From_String(Model, Path);
    Store: Gtk_List_Store := Gtk_List_Store( To_Object(Model) );

    Getting the rest wasn't too hard after I had that. What I hadn't understood at first was that the Model had to be converted from the Interface via the To_Object function.

    If that is OK to you, but in production code you need a lot of stuff to
    do in a handler, most of it is unrelated to the tree view. This is why a
    custom widget is always advisable. Using a slot is a matter of taste/ I
    never use slots and avoid run-time type conversions.

    BTW, derived widgets is also a GtkAda feature, in GTK a derived widget
    require a lot of work. In GtkAda they are trivial.

    Typically in a renderer edit commit you would maintain undo/redo
    buffers, change the active cell for smooth navigation, [un]gray/hide a
    couple of buttons (like Save). Same goes with the buttons and basically
    with all signals.

    The design pattern you need to keep in mind is that a signal sent to a
    visual element like renderer or button, logically, is rather sent to
    some container widget a couple layers above. If you do not follow this
    logic, you will have a very complicated fragile code.

    PS If anyone knows how to make the first form of On_Edited work, I'd be delighted to know.

    The first form can be used with a static layout and global variables. (:-))

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From John Perry@21:1/5 to Dmitry A. Kazakov on Tue May 31 20:18:29 2022
    On Monday, May 30, 2022 at 1:57:30 PM UTC-5, Dmitry A. Kazakov wrote:
    In the end I made it work with an On_* design...
    If that is OK to you, but in production code you need a lot of stuff to
    do in a handler, most of it is unrelated to the tree view.

    I agree with what you write, and learned a bit. I've never been in a situation where I had to implement a TreeView-like object before, so I never had to think about it much. I probably won't pursue it since the project I'm working on is a small, personal
    project with corresponding amounts of time available.

    BTW, derived widgets is also a GtkAda feature, in GTK a derived widget require a lot of work. In GtkAda they are trivial.

    Interesting! I'll probably look into this more at some future point.

    thanks again
    john perry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)