容器秘密:尺寸分配,第二部分

从右到左的语言

作为本系列的第一件事,我们重新添加了对从右到左语言的支持。

如果您只习惯于用英语编写软件,这可能会有点令人惊讶,但 GTK+ 传统上一直试图为像希伯来语这样从右到左书写的语言自动“做正确的事”。具体而言,这意味着我们将水平布局中的起始位置解释为在这些语言中位于右侧,即我们“翻转”水平排列。当然,可以通过设置容器的 ::text-direction 属性来覆盖此设置。默认情况下,文本方向由语言环境确定。

这当然很容易做到。我在第一篇文章中展示的代码假设子元素是按从左到右的顺序排列的。我们保持这种方式,并在必要时重新排序子元素。请注意,measure() 代码不需要任何更改,因为它根本不依赖于顺序。所以,我们只需要更改 size_allocate()

if (text_direction == rtl) {
  child[0] = last;
  child[1] = center;
  child[2] = first;
} else {
  child[0] = first;
  child[1] = center;
  child[2] = last;
}

还有一个我尚未提到的小问题:CSS 假设 :first-child 始终是最左边的元素,无论文本方向如何。因此,当我们在 RTL 上下文中将子窗口小部件从左侧移动到右侧时,我们需要在文本方向更改时重新排序相应的 CSS 节点。

if (direction == GTK_TEXT_DIR_LTR) {
  first = gtk_widget_get_css_node (start_widget);
  last = gtk_widget_get_css_node (end_widget);
} else {
  first = gtk_widget_get_css_node (end_widget);
  last = gtk_widget_get_css_node (start_widget);
}

parent = gtk_widget_get_css_node (box);
gtk_css_node_insert_after (parent, first, NULL);
gtk_css_node_insert_before (parent, last, NULL);

自然尺寸

既然这很容易,我们就继续,使我们的尺寸分配也尊重自然尺寸。

在 GTK+ 中,每个窗口小部件不仅有一个最小尺寸,这是它可以有效地呈现自身的最小尺寸,而且还有一个首选或自然尺寸。measure() 函数返回这两种尺寸。

对于自然尺寸,我们可以做得比上次展示的代码稍微好一些。那时,我们只是通过将所有子元素的自然尺寸相加来计算框的自然尺寸。但是我们希望将中间的子元素居中,所以让我们要求足够的空间来让所有子元素都达到其自然尺寸将中间的子元素放在中心

*natural = child2_nat + 2 * MAX (child1_nat, child3_nat);

size_allocate() 函数需要更多的工作,在这里我们需要做一些决定。当 3 个子元素争夺可用空间,并且居中施加了额外的约束时,我们可以选择为外部子元素提供更多空间,或者使中心子元素更大。由于居中是此窗口小部件的决定性功能,所以我选择了后一种选择。

那么,我们可以为中心窗口小部件提供多少空间?我们不想让它小于最小尺寸,也不想让它大于自然尺寸,而且我们需要为外部子元素至少保留所需的最小空间。

center_size = CLAMP (width - (left_min + right_min),
                     center_min, center_nat);

接下来,让我们计算一下我们可以为外部子元素提供多少空间。我们显然不能超出在为中心子元素分配空间后剩余的空间,并且我们必须平均分配剩余空间,以便居中工作(这就是下面代码中 avail 的作用)。同样,我们希望尊重子元素的最小和自然尺寸。

avail = MIN ( (width - center_size) / 2,
              width - (center_size + right_min));
left_size = CLAMP (avail, left_min, left_nat);

右子元素也是如此。在确定子元素的大小之后,剩下的就是以我们在第一部分中看到的方式分配位置:将外部子元素放在最左侧和最右侧,然后将中间的子元素居中并将其向右或向左推以避免重叠。

展开
自然尺寸
低于自然尺寸
较小
最小尺寸

参考文献

  1. 容器秘密,尺寸分配
  2. 包含这些更改的代码