GUI

图文混排

一、tintegrate::add_text_item

混排使用的字符串

图2 混排效果

混排效果

tintegrate::add_text_item中三个显示时执行、可编辑器时不执行

1、“execptions,”和“please”之间那个空行,在换行前即使有空格,只是为显示的话可以不显示。

2、该行剩余空间容得下“detailed”却容不下“ detailed”,则意味着接下一定要换行。既然要换行,只是显示的话,可以去掉之前空格。

first_word_before = " detailed"
first_word_after = "detailed"

3、判断第一个单词是否可以继续写在该行,如果不能写意味着一定要下行开始,这样可以不显示第一个单词的第一个空格。

“ detailed”一定得下行开始,那么第一个空格就可以不显示了。

 

<img>标签

curr_loc_:在创建单元项建使用的、用于指示当前输入位置的坐标(单位:像素)。下一单元将从该坐标开始。

get_min_x(const int y, const int height)。

get_y_for_floating_img(width, xpos, ypos)

语法:<img>src="" align=left|middle|right|back|here float=yes|no box=yes|no<img>
  • align:指示如何对齐。所有值都会影响水平方向,BACK还会影响垂直方向。
    here:继续从当前放置点(curr_loc_)放置。
    left:放置在该行左侧,如果不能放置在左侧,像放置位置的x已不是0,那要新起一行。
    middle:放置在该行中间。如果不能放置在中间,像放置位置的x已在中央之后,那要新起一行。
    right:放置在该行右侧。如果不能放置在右侧,像放置位置之后、再连上它要超过宽度,那要新起一行。
    back:在上个单元的左上角处放置。它必须存在上个单元。如果不存在上个单元,它将被等于同“here”。
  • box:指示是否要在该图像周周围放置一个矩形框。矩形框的四条边框度都是2,一旦放置,该图像所占区域的宽度将增加4、高度增加4。
  • float:指示是否浮动。不浮动时,单元将以align计算出的为放置坐标;浮动时,

每个单元有两种矩形:绘画矩形、布局矩形。绘画矩形是单元绘画在的矩形;布局矩形是布局时把某一块认为是它的矩形。绘画矩形总是布局矩形的子集。

文本单元后紧跟的“\n”属于该单元,它计入src_size但不计入text;图像单元紧跟的“\n”属于该单元,但不计入src_size。

calculate_cursor计算出的光标位置是放在以src_pos为索引的字符之前。

调整一行内各单元高度逻辑。1)分析每一个单元,直到一行结束,计算出这些单元最大高度curr_row_height_;2)根据curr_row_height_和特定单元高度调整该单元要放置y坐标(tintegrate::adjust_last_row)。

 

二、text_box、scrollbar_text_box

did_cursor_moved

只有tscroll_text_box会处理这事件,app不须要。当改变了光标位置时会调用这函数。功能:根据光标到达的位置,有必要的话修正item_position。

(1)当光标落在1)行时,由于顶部有一小部分没在视区,did_cursor_moved会修正item_position,以让那部分出现在视区。(2)(1)当光标落在4)行时,由于底部有一小部分没在视区,did_cursor_moved会修正item_position,以让那部分出现在视区。

 

三、word_wrap_text

处理字符串,在不超过max_width容许宽度下自动插入换行符(\n)生成多行字符串。

语法

std::string word_wrap_text(const std::string& unwrapped_text, int font_sz, int max_width, 
    int max_lines, const int attention_min_chars)

参数

unwrapped_text要处理的字符串
font_sz字号
max_width最大容许宽度。必须>0
max_lines如果设置了>0,生成字符串只要有了它指定的行数,就可以结束处理了。split_in_width就设置1,使得只需得到一行,免得一定要处理整串unwrapped_text
attention_min_chars必须>0。它指的是一个“字”中一旦超过这个字符数,那要开始调用line_size进行计算,而不是说一个“字”最多只能有的这么个字符数。详细作用参考注释。

 

返回值

返回被换行后的字符串。注意,一旦设了max_lines,返回的可能不是和unwrapped_text对应的整串字符。由于换行符“\n”要等到有下一行有效时才追加,所有返回值的最后字符不会是追加的“\n”。举个例子,当max_lines=1时,它返回的只是第一行内容,不会有追加的“\n”。

当内容中有换行符时,这换行符被放在了下一行。举个例子,有这么个输入字符串“where are you form?\nI' am from.”,那第一行是“where are you from?”,不包括那个换行符。

范例

<example>

注释

说下一个概念:“字”。在处理时“字”中字符串将做为一个整体,理论上它们将不能被分割。那什么样的是一个“字”?一)被“空格”、“\n”隔开的。二)前面已有字符串,但又遇到这么个字符,同时满足了1)它可以和前面隔开,而已有字符中最后一个字符允许和后面隔开,2)已有字符中的最后一个字符允许和后面隔开,它可以和前面隔开。

如果严格按“字”的长度去截断,可能会存在由于“字”太长(举个例子,故意输入没有空格的纯英文字符串)超过了参数限定的最大容许宽度(max_width),而满足max_width的优先级要高于“字”。为此采用方法是在形成“字”的过程中,要实时计算该“字”长度,一旦超过max_width,强制截断。这里就有个效率问题,如果“字”每加一个字符都计算一次长度,这会增加计算量,于是增加了叫attention_min_chars参数,只有“字”中字符数超过了attention_min_chars,才会去调用line_size计算字长。也就是说,一旦内容中存在着字符数<=attention_min_chars的“字”,而它又超过max_width,本函数将产生异常。那如何设置attention_min_chars?

    int attention_min_chars = width / font_size;
    if (attention_min_chars <= 0) {
            attention_min_chars = 10;
    } else if (attention_min_chars > 20) {
            attention_min_chars = 20;
    }

直观看上,font_size约等于字高,假设以全是“正方”字符(“%”)去对待,那width下最多能让出现的就是width/font_size。

相关类、函数

bool no_break_before(const wchart_t ch)。指示ch是否能和前面的字符串分开,true表示不能隔开,false表示可以。那什么样的字符是属于要返回true的字符?像“、”、“。”、“}”。

bool no_break_after(const wchar_t ch)。它类似no_break_before,指示ch是否能和后面的字符串分开,true表示不能隔开,false表示可以。那什么样的字符是属于要返回true的字符?像“<”、“[”、“{”。

bool is_cjk_char(const wchar_t ch)。指示ch是否是中日韩汉字,true表示是中日韩汉字,false则不是。一旦是中日韩汉字,那意味着它可以单独成“字”,即可以和前面断开,也可以和后面断开。

 

四、tintegrate

tintegrate在编辑状态时,要强制去掉“\r”,为什么?\r会占一个字符,会使得处理编辑框变得复杂。举个例子,backspace,1)光标在是下一行头处,在删除上一行的\n同时应该删除\r。2)光标在本行尾处,除了要删除前面那字符,还须要删除紧跟的\r。3)在Windows,SDL会保证复制到剪贴板内容都含有\r。

tintegrate内部会把src解析到items_(std::list<titem>),以下是产生items_的逻辑。

  1. 不断枚举字符,一直到超过了max_width或遇到标签,之前遍历的内容形成一个titem。
  2. 继续步骤一,直到枚举到完所有字符。
  3. 最后个字符是“\n”,会出一个额外的titem,该item的src_size是0,pos是src_长度,text是空。

如何区分一个titem是本身有换行符产生的,还是由自动换行产生的?last_row_指示该行已经解析出的titem,当遇到“\n”,此时它是empty意味着该“\n”是该行第一个titem。

get_first_word:返回字符串的第一个单词。对英文:单词间已空隔分开,对中文测是一个汉字。

makeup_pos、pos、text、src_size

text。字符串缓存。不管是max_width导致的换行还是内容有换行符导致的换行,text末尾都不包括那个换行符。为不什么不包括?——省空间。

markup_pos。此个item在源字符串中的偏移。

pos。此个item的text部分在源字符串中的偏移。

src_size。只有编辑状态时才会生成。1)是text类型的titem时,此个item在源字符串中对应的字符数(包括后面的“\n”)。

markup_pos src_size

0,  43

43, 52

95, 47

142, 3

145, 38

183, 52

235, 37

272, 3

275, 2

277, 44

item[n+1].markup_pos = item[n].markup_pos + item[n].src_size

假设M是最后项,那item[M].markup_pos + item[M].src_size = src.size()

对src_size,重点注意它对应的是源字符串,不会增、减源字符串。所以可得出这么些结论,1)因为超过max_width导致的换行,src_size不会计入那个换行符,原因是这换行符原字符串是没有的。2)当内容中有转义符时,src_size要累加转义符“\”,原因是源字符串中有“\”。

quote_require_escape:指示内容区出现“"”时是否要加转义符。

  1. quote_require_escape=true的src_中,内容中的“"”前面要加转义符。内容不包括前后两个“"”。
  2. 操作编辑框,向quote_require_escape=true的titem插入字符时,补转义符的操作是tintegrate::insert_str执行,不是ttext_box层(目的是让ttext_box透明,ttext_box不知道此刻的titem中quote_require_escape是true还是false)。
  3. app调用set_label时,字符串参数是需要转义符过的。
  4. ttext_box调用insert_str时,要用tintegrate::insert_str的返回值,而不是根据原字符串+插入字符串自动计算。
  5. 密码框不允许出现markup。因而密码框不存在转义问题。

在titem内部,quote_require_escape和指示该titem是否是text类的markup是等价的。

 

五、tintegrate::substr_from_src

从src_提取一串连续字符。

语法

std::string tintegrate::substr_from_src(int from, int to) const

参数

from基于titem.text角度看的起始偏移
to基于titem.text角度看的结束偏移,不包括to指向的字符。默认是1048576,即提取from开始的所有数据。

返回值

从src_提取出的字符串,[from, to),一定是连续的。

范例

<Example>

注释

from、to由两部分组成,titem.pos + titem.text内偏移。正是因为这两部分是分散的,第二个参数用表示偏移位置的to,而不是size。

如果from所在的titem是markup,而且from落在了标识辅助字节上,这时分两种情况,1)落在前半部分,像<format>,那后向跳到本titem的pos处。2)落在后半部分,像</format>,那落在下一个titem的pos处。——总之都是向后跳到最近一个的pos。to在这方面不作修正,当不使用1048576时,调用程序需确保该参数值。

相关类、函数

<Relative class, function>

全部评论: 0

    写评论: