GUI

通过同列控件计算最大正文宽度(mtwusc)

label控件存放着字符串,字符串需要的空间会随着容许宽度不同而不同。举个例子,有这么个字符串,一行显示时需要640像素,给它480像素时,须要两行,给它640时,只需要一行。根据容许尺寸的不同来源,有三种方法实现多行文本。注:表中mtwusc是calculate Maximum Text Width Using Same Column control缩写。

使用场景widthwidth_is_maxmtwusc实例
写脚本时就知道该控件的标称宽度,它将作为容许宽度设置falsefalse 
写脚本时知道该控件的最大标称宽度,它将作为容许宽度,最终标称宽度会因为内容而变小设置truefalsesimple_message
由其它控件算出容许尺寸留空falsetrue 

label控件的height必须留空。前两种都要给控件设置width,实际使用中更多的是要由其它控件决定容许尺寸,即mtwusc=yes时的第三种情况。

“同一列内格子必相同宽度”,网式布局利用这条规则去布局可能多行的文本控件。换句话说,通过同一列的其它格子计算出宽度,然后把这个宽度做为自个容许宽度。基于这个原因,布局逻辑在第一次计算该控件的标称尺寸时,总是返回(0, 0),它要到后面才真正确定尺寸,像放置阶段。在图形化布局时,用以下步骤放置可能多行的文本控件。

  1. 放置文本控件。打开“标称尺寸”页,使能“mtwuse”。
  2. 确保有同列的其它控件去计算宽度。
  3. 如何设置对齐?水平方向、垂直方向都不能用两端对齐。当内容不足一行时,或左对齐、或中央对齐、或右对齐就会影响字符串位置。当所在行有其它控件的高度大于它时,或上对齐、或中央对齐、或下对齐就会影响字符串位置。

一旦使能mtwuse,控件会受到些限制(Studio会执行这些检查)。1)不能出现在树形节点。2)不能设置等尺寸组。3)所在行存在多列时,该列放大系数不能是0。4)滚动面板的孩子有多行文本时,必须把width留空(height通常置0),这是为了一定计算内中mtwuse控件的标称尺寸。

一些gui有个和多行文本相关的控件叫滚动文本框(scroll_label),它是右侧可能会出现垂直滚动条的多行文本。为减少种类,Rose没有做scroll_label,也不做成模板。要实现scroll_label,通常做法是放一个scroll_panel,然后内部一个label。

 

一、只要前、后宽度不一样,tgrid::require_invalidate_layout就返回true

<librose>/gui/widgets/grid.cpp
------
bool tgrid::require_invalidate_layout(const tcontrol& from) const
{
  ...
  const tpoint new_best_size = from.calculate_best_size();
  const int max_jitter = from.get_text_font_size() * 1 / 3;
  const int hjitter = new_best_size.x - current_best.x;
  if (consider_width) {
    // if (new_best_size.x > current_best.x || posix_abs(hjitter) > max_jitter) {
    // 改为
    if (new_best_size.x != current_best.x) {
      return true;
    }
  }
  ...
}

为什么宽度一有不同就要invalid?——同行可能存在mtwusc控件。确保from控件宽度改变后,就会调用mtwusc控件的tcontrol::set_text_maximum_width,让mtwusc控件“补”上hjitter。

上图这grid有三个控件:icon、input_vars、state。其中input_vars是mtwusc控件。

当state改了label,此时new_best_size.x是90,current_best.x是94,即label宽度由94变成90。相应的,input_vars的text_maximum_width_得从1462变成1466。

 

二、calculate_col_grow_visible

<librose>/gui/widgets/grid.cpp
------
static std::unique_ptr<bool> calculate_col_grow_visible(const tgrid::tchild* children, int children_vsize, 
        const std::vector<unsigned>& col_grow_factor, unsigned& w_size)
{
	...
	for (int at = 0; at < children_vsize; ) {
		if (children[at].widget_->get_visible() == twidget::INVISIBLE) {
			at ++;
			continue;
		}
		ptr[at % cols] = true;
		at ++;
		if (at % cols == 0) {
			...
			if (all_is_true) {
				// grid有多行,通过前面行已知道所有列都存在非INVISIBLE控件,没必要遍历后面行了。
				break;
			}
		}
	}
 
	w_size = 0;
	for (int at = 0; at < cols; at ++) {
		if (ptr[at]) {
			// w_size是那些可见列的grow_factor和
			w_size += col_grow_factor[at];
		}
	}
	return col_grow_visible;
}

calculate_col_grow_visible检查各列是存至少个非INVISIBLE控件。要计算两个值。

  • w_size是那些可见列的grow_factor和。
  • 返回值是个bool数组,每个单元指示一列。true表示该列至少存在一个非INVISIBLE控件。意味着grow_factor不是0时,计算放大时得考虑它。否则,该列都是INVISIBLE控件,计算放大时,不必考虑它。

 

全部评论: 0

    写评论: