1 void InputBox::_SetCaretPos( int iPos )
2 {
3 // 将光標位置保持在0到文本的總長度間
4 int iNewPos = iPos < 0 ? 0 : (iPos > m_strText.length() ? m_strText.length() : iPos);
5
6 // 如果光標位置較上一次有所改變
7 if( iNewPos != m_iCaretCharPos )
8 {
9 // 如果新的位置小於上一次光標位置
10 if( iNewPos < m_iCaretCharPos )
11 {
12 // 最開始左邊界是邊界寬度
13 int iLeftBorder = BORDER_WIDTH;
14 // 將光標相對於首字符的顯示位置根據兩個位置間的字符的寬度加以調整
15 for( int i = iNewPos;i < m_iCaretCharPos; ++i )
16 {
17 m_iCaretFirstCharDistance -= m_pFont->GetCharWidth( m_strText.c_str()[i] ) + CHAR_SPACE;
18 }
19 // 如果前面仍有字符,就調整邊界位置
20 if( iNewPos > 0 )
21 {
22 // 調整邊界位置
23 iLeftBorder += m_pFont->GetCharWidth( m_strText.c_str()[iNewPos-1] ) + CHAR_SPACE;
24 }
25 // 光标渲染位置超出左边界,將光標移動到邊界上
26 if( m_iCaretFirstCharDistance + m_iFirstCharRenderPosition < iLeftBorder )
27 {
28 m_iFirstCharRenderPosition = iLeftBorder - m_iCaretFirstCharDistance;
29 }
30 }
31 else
32 {
33 // 計算右邊界,寬度減去邊界寬度,還有為光標位置留出的像素
34 int iRightBorder = m_iWidth - BORDER_WIDTH - CARET_WIDTH;
35 for( int i = m_iCaretCharPos; i < iNewPos; ++i )
36 {
37 m_iCaretFirstCharDistance += m_pFont->GetCharWidth( m_strText.c_str()[i] ) + CHAR_SPACE;
38 }
39 // 如果後面還有一個字符
40 if( iNewPos < m_strText.length() )
41 {
42 iRightBorder -= m_pFont->GetCharWidth( m_strText.c_str()[iNewPos] );
43 }
44 // 光标超出右边界
45 if( m_iCaretFirstCharDistance + m_iFirstCharRenderPosition > iRightBorder )
46 {
47 m_iFirstCharRenderPosition = iRightBorder - m_iCaretFirstCharDistance;
48 }
49 }
50
51 m_iCaretCharPos = iNewPos;
52 }
53 }
54
m_iCaretFirstCharDistance 表示光標位置和第一個字符位置之間的距離
m_iFirstCharRenderPosition 表示第一個字符的渲染位置
m_iCaretCharPos 表示光標在字符串的字符索引位置
BORDER_WIDTH 表示編輯框向內的邊界寬度
CARET_WIDTH 表示光標的寬度
CHAR_SPACE 表示編輯框中字符間距
1 void InputBox::Render()
2 {
3 hge->Gfx_SetClipping( m_iX, m_iY, m_iWidth, m_iHeight );
4 _RenderBox(0xffffff00);
5 m_pFont->Render( m_strText.c_str(), m_strText.length(), m_iX + BORDER_WIDTH + m_iFirstCharRenderPosition, m_iY, 0xff000000 );
6 if( m_bShowCaret )
7 {
8 for( int i = 0;i < m_iCaretWidth; ++i )
9 {
10 hge->Gfx_RenderLine(
11 m_iX + BORDER_WIDTH + m_iFirstCharRenderPosition + m_iCaretFirstCharDistance + i,
12 m_iY,
13 m_iX + m_iFirstCharRenderPosition + BORDER_WIDTH + m_iCaretFirstCharDistance + i,
14 m_iY + m_iHeight,
15 0xff000000 );
16 }
17 }
18 hge->Gfx_SetClipping();
19 }
m_iX 表示文本框的位置X
m_iY 表示文本框的位置Y
m_iWidth 表示文本框的寬度
m_iHeight 表示文本框的高度
hge->Gfx_RenderLine 是畫線的
_RenderBox 是畫外框的。
hge->Gfx_SetClipping 是設置裁剪的
m_pFont->Render 是渲染字符串
針對_SetCaretPos的邏輯算法,需要注意的一點是,如果要刪除光標位置和首字符間的字符,就一定要對光標位置進行重定位。
退格鍵邏輯裏面,應該先設置光標位置向前一格,再執行刪除邏輯刪除光標當前位置上的字符。
刪除邏輯只要刪除光標位置上的字符就可以了,光標相對於首字符的位置不會改變。
綜上,光標位置的主要邏輯思想是
1- 改變光標位置
2- 計算新的光標位置到首字符的距離
3- 根據新的距離產生一個新的光標顯示位置
4- 根據光標顯示位置是否超出邊界和超出的多少,調整首字符顯示位置。