Gtkada widget from scratch

137 Views Asked by At

I don’t have a lot of hope for this but anyway.

I need to create a widget to select a range (like a scale widget but with two cursors, one for the lower bound and another for the upper bound). This needs to be built "from scratch". According to the Gtkada documentation, I just have to take a look at the gtkdial example (gtkdial seems to be the classic example for gtk to build widget from scratch).

The example is clearly out of date, a lot of functions, packages and events don’t exist anymore.

For example Gtk.Widget.Realize_Handling is gone (instead we have on_Realize I think), the function Get_Count doesn’t exist as the event "size_request"… I tried to do it on my own by reading and understanding the source code, but I’ m still a beginner with GTK.

Do you know if an up-to-date version of this example exists?

1

There are 1 best solutions below

0
On

not sure to well understand what you want to do but it seems it perhaps wouldn't be too far from this example. And it could be adapted. Freely inspired by https://www.youtube.com/watch?v=aJAh4m7C2bM from C example.

-Normally, y'll have the following interface : enter image description here

In Ada we trust. Good luck. Mark

    -- Glade_7
    
    -- units from Gtk
    with Gtk.Main;
    with Glib.Error;     use Glib.Error;
    with Gtk.Widget;     use Gtk.Widget;
    with Gtk.Builder;    use Gtk.Builder;
    with Gtkada.Builder; use Gtkada.Builder;
    
    -- Ada predefined units
    with Ada.Text_IO;    use Ada.Text_IO;
    with Ada.Exceptions;
    
    -- Application specific units
    with Window1_Callbacks; use Window1_Callbacks;
    
    procedure Glade_7 is
    
      Builder       : Gtkada_Builder;
      Error         : aliased Glib.Error.GError;
      FileName      : constant String := "glade_7";
      GladeFileName : constant String := FileName & ".glade";
      use type Glib.Guint;
         
      begin
        -- Appelé dans toutes les applications GtkAda.
        -- Arguments ligne de commande sont analysés & retournés à l'application.
        Gtk.Main.Init;
    
        -- Etape 1 : créer un Builder 
        --         & lui donner accès à la fenetre maitre du fichier XML.
        Gtk_New (Builder);
        if Add_From_File (Gtk_Builder(Builder), GladeFileName, Error'Access) = 0 then
          Put_Line ("Error : " & Get_Message (Error));
          Error_Free (Error);
          return;
        end if;
        Put_Line (FileName & " : loading of builder OK ");
       
        -- Etape 2 : créer les handlers ("poignées") des events
        --             (de façon à préparer les callback).
        Register_Handler (Builder, "on_button1_clicked",     On_Button1_Clicked'Access);
        Register_Handler (Builder, "on_radio1_toggled",      On_Radio1_Toggled'Access);
        Register_Handler (Builder, "on_radio2_toggled",      On_Radio2_Toggled'Access);
        Register_Handler (Builder, "on_radio3_toggled",      On_Radio3_Toggled'Access);
        Register_Handler (Builder, "on_check1_toggled",      On_Check1_Toggled'Access);
        Register_Handler (Builder, "on_toggle1_toggled",     On_Toggle1_Toggled'Access);
        Register_Handler (Builder, "on_spin1_value_changed", On_Spin1_Value_Changed'Access);
        Register_Handler (Builder, "on_switch1_state_set",   On_Switch1_State_Set'Access);
    
        Register_Handler (Builder, "on_combo1_changed",      On_Combo1_Changed'Access);  --Ajout
        Register_Handler (Builder, "on_gentry1_changed",     On_Gentry1_Changed'Access); --Ajout
    
        -- Etape 3 : Do_Connect connecte tous les handlers enregistrés en une fois.
        Do_Connect (Builder);
      --Put_Line ("Booleen du Switch : " & boolean'Image (On_Switch1_State_Set (Builder)));
    
        -- Etape 4 : Afficher la fenetre avec ses dépendances
        Show_All (Gtk_Widget (Get_Object (GTK_Builder (Builder), "window")));
    
        -- Etape 5 : Lancer la boucle infinie.
        Gtk.Main.Main;
    
        -- Etape 6 : appeler Unref quand l'application se termine
        --             pour libérer la memoire associée au Builder.
        Unref (Builder);
        Put_Line ("Program " & FileName & " is finished !");
    
      exception
        when Error : others =>
          Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (Error));
      end Glade_7;

 

        
    -- Glade_7
    
    with Gtkada.Builder; use Gtkada.Builder;
    
    package Window1_Callbacks is
      
      procedure On_Button1_Clicked (Builder : access Gtkada_Builder_Record'Class);
    
      Procedure On_Radio1_Toggled (Builder : access Gtkada_Builder_Record'Class);
      Procedure On_Radio2_Toggled (Builder : access Gtkada_Builder_Record'Class);
      Procedure On_Radio3_Toggled (Builder : access Gtkada_Builder_Record'Class);
    
      Procedure On_Check1_Toggled (Builder : access Gtkada_Builder_Record'Class);
    
      Procedure On_Toggle1_Toggled     (Builder : access Gtkada_Builder_Record'Class);
      Procedure On_Spin1_Value_Changed (Builder : access Gtkada_Builder_Record'Class);
    
      Function On_Switch1_State_Set   (Builder : access Gtkada_Builder_Record'Class) return boolean;
      
      Procedure On_Combo1_Changed (Builder : access Gtkada_Builder_Record'Class);   --Ajout
      Procedure On_Gentry1_Changed (Builder : access Gtkada_Builder_Record'Class);  --Ajout
    
    end Window1_Callbacks;

    
-- Glade_7

-- units from Gtk
with Gtk.Label;          use Gtk.Label;
with Gtk.Check_Button;   use Gtk.Check_Button;
with Gtk.Toggle_Button;  use Gtk.Toggle_Button;
with Gtk.Spin_Button;    use Gtk.Spin_Button;
with Gtk.Switch;         use Gtk.Switch;
with Gtk.Combo_Box;      use Gtk.Combo_Box; --Ajout
with Gtk.GEntry;         use Gtk.GEntry;    --Ajout

with Glib;              use Glib;

with Ada.Text_IO;       use Ada.Text_IO;


package body Window1_Callbacks  is

  -----------------------------------------------
  -- On_Button1_Clicked  -- Modifié pour réagir au Spin Button
  -----------------------------------------------
  procedure On_Button1_Clicked (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      -- Mettre la valeur du bouton de spin dans label1.
      Gtk.Label.Set_Text 
          (Gtk_Label (Get_Object (Builder, "label1")),
           Gint'Image ((Gtk.Spin_Button.Get_Value_As_Int (Gtk_Spin_Button (Get_Object (Builder, "spin1"))))));
    end On_Button1_Clicked;

  -----------------------------------------------
  -- On_Radio1_Toggled
  -----------------------------------------------
  Procedure On_Radio1_Toggled (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Check_Button (Get_Object (Builder, "radio1")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Radio 1 Active");            
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label2")), "Radio 1 Not Active");
      end if;
    end On_Radio1_Toggled;

  -----------------------------------------------
  -- On_Radio2_Toggled
  -----------------------------------------------  
  Procedure On_Radio2_Toggled (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Check_Button (Get_Object (Builder, "radio2")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Radio 2 Active");            
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label2")), "Radio 2 Not Active");
      end if;
    end On_Radio2_Toggled;

  -----------------------------------------------
  -- On_Radio3_Toggled
  -----------------------------------------------
  Procedure On_Radio3_Toggled (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Check_Button (Get_Object (Builder, "radio3")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Radio 3 Active");            
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label2")), "Radio 3 Not Active");
      end if;
    end On_Radio3_Toggled;

  -----------------------------------------------
  -- On_Check1_Toggled
  -----------------------------------------------
  Procedure On_Check1_Toggled (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Toggle_Button (Get_Object (Builder, "check1")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Check 1 Active");            
        else
          -- même label car on ne peut pas grouper les "check button", à la diff. des "radio button".
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Check 1 Not Active");
      end if;
    end On_Check1_Toggled;

  -----------------------------------------------
  -- On_Toggle1_Toggled -- AJOUT
  -----------------------------------------------
  Procedure On_Toggle1_Toggled (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Toggle_Button (Get_Object (Builder, "toggle1")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Toggle 1 Active");            
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Toggle 1 Not Active");
      end if;
    end On_Toggle1_Toggled;

  -----------------------------------------------
  -- On_Spin1_Value_Changed
  -----------------------------------------------
  Procedure On_Spin1_Value_Changed (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    begin
      if Gtk_Toggle_Button (Get_Object (Builder, "spin1")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Toggle 1 Active");            
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Toggle 1 Not Active");
      end if;
    end On_Spin1_Value_Changed;

  -----------------------------------------------
  -- On_Switch1_Activate
  -----------------------------------------------
  Function On_Switch1_State_Set (Builder : access Gtkada_Builder_Record'Class) return boolean is
    pragma Unreferenced (Builder); -- Builder n'est sciemment pas utilisé dans la fonction
    Switch_On : boolean := true;
    begin
      if Gtk_Switch (Get_Object (Builder, "switch1")).Get_Active then
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Switch 1 Active");  
        else
          Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")), "Switch 1 Not Active");
      end if;
    return Switch_On;
    end On_Switch1_State_Set;

  --------------------------------
  -- On_Combo1_Changed  -- Ajout
  --------------------------------
  procedure On_Combo1_Changed (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder);
    begin
      Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label2")), "Combo1_changed entered"); 
    end On_Combo1_Changed;

  ---------------------------------
  -- On_Gentry1_Changed  -- Ajout
  ---------------------------------
  procedure On_Gentry1_Changed (Builder : access Gtkada_Builder_Record'Class) is
    pragma Unreferenced (Builder);
    begin
    --Afficher l'entry de la combo-box.
      Gtk.Label.Set_Text (Gtk_Label (Get_Object (Builder, "label1")),
                          Gtk.Gentry.Get_Text (Gtk_Gentry (Get_Object (Builder, "entry1"))));
    exception
      when Constraint_Error => 
        put_line ("Constraint Error : ");
    end On_Gentry1_Changed;

end Window1_Callbacks;

And you need the glade file here :

    <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkAdjustment" id="adjustment1">
    <property name="upper">100</property>
    <property name="step-increment">1</property>
    <property name="page-increment">10</property>
  </object>
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name Col_1 -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0">Ligne-1</col>
      </row>
      <row>
        <col id="0">bbb</col>
      </row>
      <row>
        <col id="0">dddd</col>
      </row>
      <row>
        <col id="0">eeeeeeee</col>
      </row>
      <row>
        <col id="0">ligne-5</col>
      </row>
      <row>
        <col id="0">ligne-6</col>
      </row>
    </data>
  </object>
  <object class="GtkWindow" id="window">
    <property name="name">window</property>
    <property name="width-request">89</property>
    <property name="height-request">3</property>
    <property name="can-focus">False</property>
    <property name="hexpand">True</property>
    <property name="vexpand">True</property>
    <property name="border-width">0</property>
    <property name="window-position">center</property>
    <property name="gravity">center</property>
    <child>
      <object class="GtkFixed" id="fixed1">
        <property name="name">fixed1</property>
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <child>
          <object class="GtkButton" id="button1">
            <property name="name">button1</property>
            <property name="width-request">100</property>
            <property name="height-request">80</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">True</property>
            <property name="tooltip-text" translatable="yes"> Click Me!</property>
            <property name="always-show-image">True</property>
            <signal name="clicked" handler="on_button1_clicked" swapped="no"/>
            <child>
              <object class="GtkImage" id="harddisk">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="stock">gtk-harddisk</property>
                <property name="icon_size">6</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="x">36</property>
            <property name="y">40</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="width-request">200</property>
            <property name="height-request">40</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="tooltip-text" translatable="yes">I am a label hiding here.</property>
            <property name="label" translatable="yes">label</property>
            <attributes>
              <attribute name="font-desc" value="Sans Bold Italic 15"/>
              <attribute name="foreground" value="#efef29292929"/>
            </attributes>
          </object>
          <packing>
            <property name="x">150</property>
            <property name="y">170</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label2">
            <property name="width-request">200</property>
            <property name="height-request">40</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="xpad">0</property>
            <property name="ypad">17</property>
            <property name="label" translatable="yes">label2</property>
            <property name="xalign">0.5</property>
            <property name="yalign">0.5</property>
          </object>
          <packing>
            <property name="x">150</property>
            <property name="y">220</property>
          </packing>
        </child>
        <child>
          <object class="GtkRadioButton" id="radio1">
            <property name="label" translatable="yes">radio button 1</property>
            <property name="width-request">100</property>
            <property name="height-request">22</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">False</property>
            <property name="halign">start</property>
            <property name="active">True</property>
            <property name="draw-indicator">True</property>
            <signal name="toggled" handler="on_radio1_toggled" swapped="no"/>
          </object>
          <packing>
            <property name="x">190</property>
            <property name="y">30</property>
          </packing>
        </child>
        <child>
          <object class="GtkRadioButton" id="radio2">
            <property name="label" translatable="yes">radio button 2</property>
            <property name="width-request">100</property>
            <property name="height-request">22</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">False</property>
            <property name="active">True</property>
            <property name="draw-indicator">True</property>
            <property name="group">radio1</property>
            <signal name="toggled" handler="on_radio2_toggled" swapped="no"/>
          </object>
          <packing>
            <property name="x">190</property>
            <property name="y">60</property>
          </packing>
        </child>
        <child>
          <object class="GtkRadioButton" id="radio3">
            <property name="label" translatable="yes">radio button3</property>
            <property name="width-request">100</property>
            <property name="height-request">22</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">False</property>
            <property name="active">True</property>
            <property name="draw-indicator">True</property>
            <property name="group">radio1</property>
            <signal name="toggled" handler="on_radio3_toggled" swapped="no"/>
          </object>
          <packing>
            <property name="x">190</property>
            <property name="y">90</property>
          </packing>
        </child>
        <child>
          <object class="GtkCheckButton" id="check1">
            <property name="label" translatable="yes">check button1</property>
            <property name="width-request">100</property>
            <property name="height-request">30</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">False</property>
            <property name="draw-indicator">True</property>
            <signal name="toggled" handler="on_check1_toggled" swapped="no"/>
          </object>
          <packing>
            <property name="x">190</property>
            <property name="y">120</property>
          </packing>
        </child>
        <child>
          <object class="GtkToggleButton" id="toggle1">
            <property name="label" translatable="yes">toggle button</property>
            <property name="width-request">123</property>
            <property name="height-request">36</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">True</property>
            <signal name="toggled" handler="on_toggle1_toggled" swapped="no"/>
          </object>
          <packing>
            <property name="x">25</property>
            <property name="y">174</property>
          </packing>
        </child>
        <child>
          <object class="GtkSpinButton" id="spin1">
            <property name="width-request">118</property>
            <property name="height-request">34</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="max-width-chars">2</property>
            <property name="adjustment">adjustment1</property>
            <property name="wrap">True</property>
            <signal name="value-changed" handler="on_spin1_value_changed" swapped="no"/>
          </object>
          <packing>
            <property name="x">25</property>
            <property name="y">218</property>
          </packing>
        </child>
        <child>
          <object class="GtkSwitch" id="switch1">
            <property name="use-action-appearance">True</property>
            <property name="name">switch</property>
            <property name="width-request">100</property>
            <property name="height-request">35</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="active">True</property>
            <signal name="state-set" handler="on_switch1_state_set" swapped="no"/>
          </object>
          <packing>
            <property name="x">27</property>
            <property name="y">284</property>
          </packing>
        </child>
        <child>
          <object class="GtkComboBox" id="combo1">
            <property name="width-request">176</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="model">liststore1</property>
            <property name="active">0</property>
            <property name="has-entry">True</property>
            <property name="entry-text-column">0</property>
            <property name="id-column">0</property>
            <property name="active-id">0</property>
            <signal name="changed" handler="on_combo1_changed" swapped="no"/>
            <child internal-child="entry">
              <object class="GtkEntry" id="entry1">
                <property name="can-focus">False</property>
                <signal name="changed" handler="on_gentry1_changed" swapped="no"/>
              </object>
            </child>
          </object>
          <packing>
            <property name="x">38</property>
            <property name="y">357</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>