GTKGrid centered rows optimizing screenspace

Hello everyone,
I am trying to write an on-screen keyboard but I am having difficulties to get a nice layout. I sketched how I imagine the layout to look like. The keys of the keyboard can come in a few different sizes. They are all multiples from a default key size. Because keys can have different sizes, not all rows have the same “width”. I want each row of keys to have an equal amount of space to the right and to the left side. Basically rows as a unit should be centered. When the window is resized, the widest row of buttons should take up all available space and the other rows should also change their size accordingly.

This is what it is supposed to look like:

My solution:
I found a solution but it seems over-complicated and has a problem with resizing the window.
I thought I would just make a grid and calculate the max size of all rows. The unit of measurement is “defaultKeySize” Then I calculate the starting point of each row and add the keys of each row. For the row with the max_length for example it starts at position 0. Now it can happen, that a row is just one key size shorter. To center even these cases properly the number of colums of the grid is twice the max_length of all rows. That way I can move those rows inwards one column, which equals half a keysize. Then I set the size of all columns homogenous and get a neat looking layout. The only problem with that is that I can not shrink it to the size I need to fit it on a small screen (Pinephone).

Previous idea:
My first idea was to use a vertical box to store a horizontal box filled with the buttons. I can easily center those horizontal boxes but then I was unable to to get the buttons of all rows to change size uniformly.

Does anybody know the solution to my problem?

Bonus: Another great thing would be to shrink/expand the font size with the size of the buttons

1 Like

Hey @grelltrier, given the requirements you describe, you might find Emeus useful. As you can define rows and buttons, sizes and positions. relatively to each other.

This looks like you want a vertical GtkBox with 3 horizontal GtkBoxes inside it really.

That was the first idea I had but then how can I set the button sizes so that the buttons in all horizontal boxes have the same size and some of the buttons can have twice the width of the “standard” button size? I think if all buttons were the same size I could add them to a SizeGroup but I don’t know if it is possible to say that some of the added buttons are supposed to be twice the size.

That looks like it could solve my problems but the project was last updated 3 years ago and I would prefer sticking to the standard gtk. Thank you for your tip

If you have 3 boxes, you don’t need buttons to be the same size. Just don’t do anything with their size and they will be same automatically.

Try the following UI file:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<interface>
  <requires lib="gtk+" version="3.22"/>
  <object class="GtkWindow">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="valign">center</property>
        <property name="orientation">vertical</property>
        <property name="spacing">6</property>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="halign">center</property>
            <property name="spacing">6</property>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">Q</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">W</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">E</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">R</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">3</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="halign">center</property>
            <property name="spacing">6</property>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">A</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">S</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">Enter</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <style>
                  <class name="long"/>
                </style>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox" id="You don't really You don't really ">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="halign">center</property>
            <property name="spacing">6</property>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">Ctrl</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <style>
                  <class name="long"/>
                </style>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <style>
                  <class name="space"/>
                </style>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">Ctrl</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <style>
                  <class name="long"/>
                </style>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">2</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
    <child type="titlebar">
      <placeholder/>
    </child>
  </object>
</interface>

(Glade)

And this CSS:

button {
  min-height: 48px;
  min-width: 48px;
  padding: 0;
}

button.long {
  min-width: 72px;
}

button.space {
  min-width: 128px;
}

Screenshot from 2020-07-30 17-57-16

Awesome, thank you for this. I will try it with boxes :slight_smile: