Search code examples
c++gtkgtkmm

Two Gtk::Grids holding Gtk::DrawingArea: sizing issue


I have a custom GameBoard which inherits from Gtk::VBox container and stacking two child Gtk::Grid containers:

class GameBoard : public Gtk::VBox
{

public:

    GameBoard();
    virtual ~GameBoard();

private:

    Gtk::Grid m_nextDiscArea;
    Gtk::Grid m_gameBoardGrid;

};

The GameBoard constructor is implemented this way:

GameBoard::GameBoard()
{
    const int nbRows{6};
    const int nbColumns{7};

    m_nextDiscArea.set_row_homogeneous(true);
    m_nextDiscArea.set_column_homogeneous(true);

    for(int col{0}; col < nbColumns; ++col)
    {
        Disc* noDisc{new Disc};
        m_nextDiscArea.attach(*noDisc, col, 0, 1, 1);
    }

    m_gameBoardGrid.set_row_homogeneous(true);
    m_gameBoardGrid.set_column_homogeneous(true);

    for(int row{0}; row < nbRows; ++row)
    {
        for(int col{0}; col < nbColumns; ++col)
        {
            Disc* noDisc{new Disc};
            m_gameBoardGrid.attach(*noDisc, col, row, 1, 1);
        }
    }

    pack_start(m_nextDiscArea);
    pack_start(m_gameBoardGrid);
}

The issue I am facing is partially covered in my last post, but that solution is not working for this case. The problem is that when the child widgets of of the two grids are displayed, they have different sizing, and the 6x7 grid has smaller discs, which seems a bit weird:

enter image description here

I have tried playing with set_v/hexpand, set_v/halign but nothing seems to work. How can I have the same size for the child widgets of both grids?


For completion, here is the interface of the Disc class. It simply draws a disc with a color background using Cairo:

class Disc : public Gtk::DrawingArea
{

public:

    Disc();
    Disc(double p_red, double p_green, double p_blue, double p_alpha);
    virtual ~Disc();

protected:

    // Signal handlers:
    bool on_draw(const Cairo::RefPtr<Cairo::Context>& p_context) override;

private:

    double m_red   {0.0};
    double m_green {0.0};
    double m_blue  {0.0};
    double m_alpha {0.0};

};

Solution

  • A solution to this problem was given to me by theGtkNerd. Instead of using a Gtk::VBox to pack the two Gtk::Grids, a Gtk::Paned can be used. The GameBoard class then becomes:

    class GameBoard : public Gtk::Paned
    {
    
    public:
    
        GameBoard();
        virtual ~GameBoard();
    
    private:
    
        Gtk::Grid m_nextDiscArea;
        Gtk::Grid m_gameBoardGrid;
    
    };
    

    The constructor can be implemented as:

    GameBoard::GameBoard()
    {
        // The two Paned areas are vertically aligned:
        set_orientation(Gtk::Orientation::ORIENTATION_VERTICAL);
    
        const int nbRows{6};
        const int nbColumns{7};
    
        m_nextDiscArea.set_row_homogeneous(true);
        m_nextDiscArea.set_column_homogeneous(true);
    
        for(int col{0}; col < nbColumns; ++col)
        {
            Disc* noDisc{new Disc};
            noDisc->set_size_request(40, 40); // Give minimal size.
            m_nextDiscArea.attach(*noDisc, col, 0, 1, 1);
        }
    
        m_gameBoardGrid.set_row_homogeneous(true);
        m_gameBoardGrid.set_column_homogeneous(true);
    
        for(int row{0}; row < nbRows; ++row)
        {
            for(int col{0}; col < nbColumns; ++col)
            {
                Disc* noDisc{new Disc};
                noDisc->set_size_request(40, 40); // Give minimal size.
                m_gameBoardGrid.attach(*noDisc, col, row, 1, 1);
            }
        }
    
        // Layout setup: 'true' for m_nextDiscArea to be expanded   
        // 'false' to make sure it is not shrinkable (we can make
        // it hidden using the paned). Same for m_gameBoardGrid.
        pack1(m_nextDiscArea, true, false);
        pack2(m_gameBoardGrid, true, false);
    }
    

    Here is a screenshot of the result. Resizing keeps all discs in proportion:

    Grid with Gtk::Paned

    I am not exactly sure why this works as expected, and I have found nothing on this in the documentation so far, but it does.