1
votes

I'm writing a program using gtkada to display a window with a Text_View (within a Scrolled_Window) which will be updated from a GEntry.

I've got it working almost as I want it to be, with the exception of scroll.

As input is processed from the GEntry and inserted into the Text_View I want it to scroll automatically, so the most recent entry is visible at the bottom.

If I understand it correctly, doing a Scroll_To_Iter after inserting text won't work. An idle handler needs to be used to take care of the scrolling.

I just need pointers on how to call it.

The procedure to insert text from the GEntry looks like this:

procedure Insert_Text (S_Out: String) is

      Iter        : Gtk_Text_Iter;
      Scroll_Okay : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Insert (TextBuffer, Iter, "You entered:" & ASCII.LF);

      Get_End_Iter (TextBuffer, Iter);
      Insert (TextBuffer, Iter, S_Out & ASCII.LF);


      Get_End_Iter (TextBuffer, Iter);
      Scroll_Okay := Scroll_To_Iter
        (TextView, Iter, 0.0, True, 1.0, 1.0);


   end Insert_Text;

The Scroll_To_Iter call I've included there just for illustration; I know that doesn't do the job.

I have a separate procedure in the same package:

   procedure Idle_Scroll (Object : access Gtk_Widget_Record'Class) is

      Iter        : Gtk_Text_Iter;
      Scroll_Okay : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Scroll_Okay := Scroll_To_Iter
        (TextView, Iter, 0.0, True, 1.0, 1.0);

   end Idle_Scroll;

So I'd just like to know how to set up the appropriate idle handler. Any help gratefully received.

Further to the answer below (thanks) I've since tried modifying the code, changing the procedure to a function, and it seems to be progressing in the right direction. I still get stuck when trying to call the Idle_Scroll callback, I get the error '... expected type "G_Source_Func" defined at glib-main.ads ... found type access to function "Idle_Scroll" ...' I tried to set the parameter passed to Idle_Scroll of type G_Source_Func after reading its entry in glibmain.h but I seem to be going round in circles. The full code I've uploaded to sourceforge here: https://sourceforge.net/projects/test-textview/files/

2

2 Answers

1
votes

Managed to get it working.

Changed the declarations in the package test_textview_declare.ads:

   package Idle_Cb is new Glib.Main.Generic_Sources (Gtk_Text_View);

   Idle_Id : G_Source_Id;

The Idle_Scroll function in test_textview_cb.adb is now:

   function Idle_Scroll (The_View : Gtk_Text_View) return Boolean is

      Iter        : Gtk_Text_Iter;
      Scroll_Okay : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Scroll_Okay := Scroll_To_Iter
        (The_View, Iter, 0.0, True, 1.0, 1.0);
      return True;

   end Idle_Scroll;

The "return True" was the final piece of the puzzle. I'd read the reference manual several times, but had missed the fact that I needed that line for the idle function to keep running. This afternoon I'd had Idle_Scroll run when the program was executed, but only once. Return True ensures it gets called repeatedly.

I'd previously also edited the line to add the idle function in test_textview_start.adb:

 Idle_Id := Idle_Cb.Idle_Add (Idle_Scroll'Access, TextView);

Thanks again for the help.

Spoke too soon.

My above solution worked too well. After entering text from the GEntry into the Text_View, it scrolled automatically to the bottom, but I was unable to move the scrollbar back up to view earlier content.

Fix for that was to move the call to Idle_Add into the callback package test_testview.adb and in the function Idle_Scroll change the return line to "Return := False;". That way it scrolls to the bottom after text is entered, but still allows the scrollbar to be moved up and down.

Final version of test_textview.adb looks like:

package body Test_TextView_Cb is


   function Idle_Scroll (The_View : Gtk_Text_View) return Boolean is

      Iter    : Gtk_Text_Iter;
      Success : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Success := Scroll_To_Iter (The_View, Iter, 0.0, True, 1.0, 1.0);
      return False;

   end Idle_Scroll;


   procedure Insert_Text (OutStr: String) is

      Iter : Gtk_Text_Iter;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Insert (TextBuffer, Iter, "You entered:" & ASCII.LF
        & OutStr & ASCII.LF);
      Idle_Id := Idle_Cb.Idle_Add     (Idle_Scroll'Access, TextView);

   end Insert_Text;


   procedure Enter_Pressed (Self : access     Gtk_Widget_Record'Class) is
      Entered_Text : String := Get_Text (Cmd_Entry);

   begin

      Insert_Text (Entered_Text);
      Set_Text (Cmd_Entry, "");

   end Enter_Pressed;


   procedure Main_Quit (Self : access Gtk_Widget_Record'Class) is

   begin

      Gtk.Main.Main_Quit;

   end Main_Quit;


   procedure Button_Quit (Self : access Gtk_Widget_Record'Class) is

   begin

      Destroy (Self);

   end Button_Quit;


end Test_TextView_Cb;
0
votes

I think you should try using Idle_Add procedure from Glib.Main package. Something like

procedure Insert_Text (S_Out: String) is

      Iter        : Gtk_Text_Iter;
      Scroll_Okay : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Insert (TextBuffer, Iter, "You entered:" & ASCII.LF);

      Get_End_Iter (TextBuffer, Iter);
      Insert (TextBuffer, Iter, S_Out & ASCII.LF);

      Get_End_Iter (TextBuffer, Iter);

      GLib.Main.Idle_Add (Idle_Scroll'access);

   end Insert_Text;

But you must transform your procedure to a function returning a boolean value. If you need to pass parameters to your code, use an instantiation of the generic inner package Generic_Sources to provide a data structure that will be pass through the callback to your code.

Please note that I did not compile this code and that you might have to change it a bit :)

EDIT:

I forgot to mention that the prototype for G_Source_Func is

type G_Source_Func is access function return Boolean; 

Which means that it shouldn't have any parameter. So Idle_Scroll should be something like this

   function Idle_Scroll return Boolean is

      Iter        : Gtk_Text_Iter;
      Scroll_Okay : Boolean;

   begin

      Get_End_Iter (TextBuffer, Iter);
      Scroll_Okay := Scroll_To_Iter
        (TextView, Iter, 0.0, True, 1.0, 1.0);

      return Scroll_Okay;
   end Idle_Scroll;