第二人生的源码分析(九十二)LLLineEditor实现编辑框

在基于GUI界面的软件交互时,最基本的输入就是编辑框了,比如下图里输入的用户名称和密码,在游戏界面的编辑框里输入文字是一个高技术难度的问题,因为Windows输入法调用,也是难点之一。
 
那么在第二人生里的用户名称和密码的编辑框是怎么样实现的呢?现在就来分析这部份的代码,它的类继承关系如下:
class LLLineEditor
: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor
LLLineEditor继续了LLUICtrl类,说明它是一个控件类。它的主要显示代码如下:
#001 void LLLineEditor::draw()
#002 {
 
判断不能显示时就直接返回去。
#003    if( !getVisible() )
#004    {
#005        return;
#006    }
#007 
 
获取显示字符串的长度。
#008    S32 text_len = mText.length();
#009 
 
如果是密码的方式,就只显示为星字符串。
#010    LLString saved_text;
#011    if (mDrawAsterixes)
#012    {
#013        saved_text = mText.getString();
#014        LLString text;
#015        for (S32 i = 0; i < mText.length(); i++)
#016        {
#017            text += '*';
#018        }
#019        mText = text;
#020    }
#021 
 
设置背景框的大小。
#022    // draw rectangle for the background
#023    LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 
根据边框的大小设置合适的显示背景。
#024    background.stretch( -mBorderThickness );
#025 
#026    LLColor4 bg_color = mReadOnlyBgColor;
#027 
 
显示背景的颜色。
#028    // drawing solids requires texturing be disabled
#029    {
#030        LLGLSNoTexture no_texture;
#031        // draw background for text
#032        if( !mReadOnly )
#033        {
#034            if( gFocusMgr.getKeyboardFocus() == this )
#035            {
#036                bg_color = mFocusBgColor;
#037             }
#038            else
#039            {
#040                bg_color = mWriteableBgColor;
#041            }
#042        }
#043        gl_rect_2d(background, bg_color);
#044    }
#045 
#046    // draw text
#047 
 
开始显示字符串。
#048    S32 cursor_bottom = background.mBottom + 1;
#049    S32 cursor_top = background.mTop - 1;
#050 
 
获取字体显示的颜色。
#051    LLColor4 text_color;
#052    if (!mReadOnly)
#053    {
#054        if (!getTentative())
#055        {
#056            text_color = mFgColor;
#057        }
#058        else
#059        {
#060            text_color = mTentativeFgColor;
#061        }
#062    }
#063    else
#064    {
#065        text_color = mReadOnlyFgColor;
#066    }
#067    LLColor4 label_color = mTentativeFgColor;
#068 
 
显示预先编辑的标志。
#069    if (hasPreeditString())
#070    {
#071        // Draw preedit markers. This needs to be before drawing letters.
#072        for (U32 i = 0; i < mPreeditStandouts.size(); i++)
#073        {
#074            const S32 preedit_left = mPreeditPositions[i];
#075            const S32 preedit_right = mPreeditPositions[i + 1];
#076            if (preedit_right > mScrollHPos)
#077            {
#078                S32 preedit_pixels_left = findPixelNearestPos(llmax(preedit_left, mScrollHPos) - getCursor());
#079                S32 preedit_pixels_right = llmin(findPixelNearestPos(preedit_right - getCursor()), background.mRight);
#080                if (preedit_pixels_left >= background.mRight)
#081                {
#082                    break;
#083                }
#084                if (mPreeditStandouts[i])
#085                {
#086                    gl_rect_2d(preedit_pixels_left + PREEDIT_STANDOUT_GAP,
#087                        background.mBottom + PREEDIT_STANDOUT_POSITION,
#088                        preedit_pixels_right - PREEDIT_STANDOUT_GAP - 1,
#089                        background.mBottom + PREEDIT_STANDOUT_POSITION -
#090 PREEDIT_STANDOUT_THICKNESS,
#091                        (text_color * PREEDIT_STANDOUT_BRIGHTNESS + bg_color * (1 -
#092 PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f));
#093                }
#094                else
#095                {
#096                    gl_rect_2d(preedit_pixels_left + PREEDIT_MARKER_GAP,
#097                        background.mBottom + PREEDIT_MARKER_POSITION,
#098                        preedit_pixels_right - PREEDIT_MARKER_GAP - 1,
#099                        background.mBottom + PREEDIT_MARKER_POSITION -
#100 PREEDIT_MARKER_THICKNESS,
#101                        (text_color * PREEDIT_MARKER_BRIGHTNESS + bg_color * (1 -
#102 PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f));
#103                }
#104            }
#105        }
#106    }
#107 
#108    S32 rendered_text = 0;
#109     F32 rendered_pixels_right = (F32)mMinHPixels;
#110     F32 text_bottom = (F32)background.mBottom + (F32)UI_LINEEDITOR_V_PAD;
#111 
 
 
显示选中的效果。
#112    if( (gFocusMgr.getKeyboardFocus() == this) && hasSelection() )
#113    {
#114        S32 select_left;
#115        S32 select_right;
#116        if( mSelectionStart < getCursor() )
#117        {
#118            select_left = mSelectionStart;
#119            select_right = getCursor();
#120        }
#121        else
#122        {
#123            select_left = getCursor();
#124            select_right = mSelectionStart;
#125        }
#126       
#127        if( select_left > mScrollHPos )
#128        {
#129            // unselected, left side
#130            rendered_text = mGLFont->render(
#131                mText, mScrollHPos,
#132                rendered_pixels_right, text_bottom,
#133                text_color,
#134                LLFontGL::LEFT, LLFontGL::BOTTOM,
#135                LLFontGL::NORMAL,
#136                select_left - mScrollHPos,
#137                mMaxHPixels - llround(rendered_pixels_right),
#138                &rendered_pixels_right);
#139        }
#140       
#141        if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )
#142        {
#143            LLColor4 color(1.f - bg_color.mV[0], 1.f - bg_color.mV[1], 1.f - bg_color.mV[2], 1.f);
#144            // selected middle
#145            S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text);
#146            width = llmin(width, mMaxHPixels - llround(rendered_pixels_right));
#147            gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color);
#148 
 
显示相应选中的字符串。
#149            rendered_text += mGLFont->render(
#150                mText, mScrollHPos + rendered_text,
#151                rendered_pixels_right, text_bottom,
#152                LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
#153                LLFontGL::LEFT, LLFontGL::BOTTOM,
#154                LLFontGL::NORMAL,
#155                select_right - mScrollHPos - rendered_text,
#156                mMaxHPixels - llround(rendered_pixels_right),
#157                &rendered_pixels_right);
#158        }
#159 
 
下面开始显示没有选中的字符串。
#160        if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )
#161        {
#162            // unselected, right side
#163            mGLFont->render(
#164                mText, mScrollHPos + rendered_text,
#165                rendered_pixels_right, text_bottom,
#166                text_color,
#167                LLFontGL::LEFT, LLFontGL::BOTTOM,
#168                LLFontGL::NORMAL,
#169                S32_MAX,
#170                mMaxHPixels - llround(rendered_pixels_right),
#171                &rendered_pixels_right);
#172        }
#173    }
#174    else
#175    {
#176        mGLFont->render(
#177            mText, mScrollHPos,
#178            rendered_pixels_right, text_bottom,
#179            text_color,
#180            LLFontGL::LEFT, LLFontGL::BOTTOM,
#181            LLFontGL::NORMAL,
#182            S32_MAX,
#183            mMaxHPixels - llround(rendered_pixels_right),
#184            &rendered_pixels_right);
#185    }
#186 
 
如果正在编辑过程中,设置IME在合适的位置。
#187    // If we're editing...
#188    if( gFocusMgr.getKeyboardFocus() == this)
#189    {
#190        // (Flash the cursor every half second)
#191        if (gShowTextEditCursor && !mReadOnly)
#192        {
#193             F32 elapsed = mKeystrokeTimer.getElapsedTimeF32();
#194            if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) )
#195            {
#196                S32 cursor_left = findPixelNearestPos();
#197                cursor_left -= UI_LINEEDITOR_CURSOR_THICKNESS / 2;
#198                S32 cursor_right = cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS;
#199                if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
#200                {
#201                    const LLWString space(utf8str_to_wstring(LLString(" ")));
#202                    S32 wswidth = mGLFont->getWidth(space.c_str());
#203                    S32 width = mGLFont->getWidth(mText.getWString().c_str(), getCursor(), 1) + 1;
#204                    cursor_right = cursor_left + llmax(wswidth, width);
#205                }
#206                // Use same color as text for the Cursor
#207                gl_rect_2d(cursor_left, cursor_top,
#208                    cursor_right, cursor_bottom, text_color);
#209                if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
#210                {
#211                    mGLFont->render(mText, getCursor(), (F32)(cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS / 2),
#212 text_bottom,
#213                        LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
#214                        LLFontGL::LEFT, LLFontGL::BOTTOM,
#215                        LLFontGL::NORMAL,
#216                        1);
#217                }
#218 
#219                // Make sure the IME is in the right place
#220                S32 pixels_after_scroll = findPixelNearestPos();    // RCalculcate for IME position
#221                LLRect screen_pos = getScreenRect();
#222                LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - UI_LINEEDITOR_V_PAD );
#223 
#224                ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
#225                ime_pos.mY = (S32) (ime_pos.mY * LLUI::sGLScaleFactor.mV[VY]);
#226                getWindow()->setLanguageTextInput( ime_pos );
#227            }
#228        }
#229 
 
显示子窗口。
#230        // Draw children (border)
#231        //mBorder->setVisible(TRUE);
#232        mBorder->setKeyboardFocusHighlight( TRUE );
#233        LLView::draw();
#234        mBorder->setKeyboardFocusHighlight( FALSE );
#235        //mBorder->setVisible(FALSE);
#236    }
#237    else // does not have keyboard input
#238    {
 
没有字符串,就显示为一个标签。
#239        // draw label if no text provided
#240        if (0 == mText.length())
#241        {
#242            mGLFont->render(mLabel.getWString(), 0,
#243                            LABEL_HPAD, (F32)text_bottom,
#244                            label_color,
#245                            LLFontGL::LEFT, LLFontGL::BOTTOM,
#246                            LLFontGL::NORMAL,
#247                            S32_MAX,
#248                            mMaxHPixels - llround(rendered_pixels_right),
#249                            &rendered_pixels_right, FALSE);
#250        }
#251        // Draw children (border)
#252        LLView::draw();
#253    }
#254 
 
保存相应的密码字符串。
#255    if (mDrawAsterixes)
#256    {
#257        mText = saved_text;
#258    }
#259 }
 
上面的函数先设置背景的颜色,并且把背景显示,然后根据是否为密码,或者选择字符串来作合适的处理,最后显示相应的字符串,并且输入法窗口在合适的位置上。
 
posted @ 2008-06-16 21:57  ajuanabc  阅读(184)  评论(0编辑  收藏  举报