容器秘密:尺寸分配

我最近有机会为支持 GTK+ 所有功能的容器重新实现尺寸分配。

  • RTL 支持
  • 自然尺寸
  • 对齐和展开
  • 高度随宽度变化
  • 方向支持
  • 基线

如果您在应用程序中进行一次性容器,则其中大多数可能无关紧要,但在通用的 GTK+ 小部件中,它们迟早都可能会变得相关。

由于要涵盖的内容很多,因此需要几篇文章才能完成。 让我们开始吧!

起点

GtkCenterBox 是一个简单的小部件,可以包含三个子小部件 - 它不是一个 GtkContainer,至少目前不是。 在 GTK+ 4 中,任何小部件都可以是其他小部件的父级。 GtkCenterBox 应用于其子项的布局是将中间子项居中,只要有可能。 这是 GtkBox 在 GTK+ 3 中提供的功能,但中间子项处理使已经复杂的容器更加复杂。 因此,我们将其移动到 GTK+ 4 中的一个单独的小部件中。

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

当我开始查看 GtkCenterBox 尺寸分配代码时,它非常简单。 要查看的两个方法是 measure()size_allocate()

measure 实现只是测量三个子项,在水平方向上将最小尺寸和自然尺寸相加,并在垂直方向上取它们的最大值。 大致伪代码如下:

if (orientation == GTK_ORIENTATION_HORIZONTAL) {
  *minimum = child1_min + child2_min + child3_min;
  *natural = child1_nat + child2_nat + child3_nat;
} else {
  *minimum = MAX(child1_min, child2_min, child3_min);
  *natural = MAX(child1_min, child2_min, child3_min);
}

size_allocate 实现是将第一个子项放在左侧,最后一个子项放在右侧,然后将中间子项放在中心,通过根据需要将其向右或向左推来消除重叠。

child1_width = child1_min;
child2_width = child2_min;
child3_width = child3_min;
child1_x = 0;
child3_x = total_width - child3_width;
child2_x = total_width/2 - child2_width/2;
if (child2_x < child1_x + child1_width)
  child2_2 = child1_x + child1_width;
else if (child2_x + child2_width > child3_x)
  child2_x = child3_x - child2_width;

如您所见,这非常简单。 可惜的是,它没有任何我上面列出的功能。

  • 子项始终获取其最小尺寸
  • 未考虑 ::expand 属性
  • 无论文本方向如何,第一个子项始终放置在左侧
  • 没有垂直方向
  • 不支持高度随宽度变化
  • 基线被忽略

在接下来的几篇文章中,我将尝试展示如何将这些功能添加回来,希望能在此过程中澄清 GTK+ 尺寸分配工作原理的一些奥秘。

参考

  1. 该系列中的第一个提交
  2. GtkWidget 尺寸分配的文档
  3. 我们从代码开始

关于“容器秘密:尺寸分配”的一个想法

评论已关闭。