[sword-svn] r117 - in trunk/src/SwordReader_GUI: . SRFramework

dtrotzjr at www.crosswire.org dtrotzjr at www.crosswire.org
Sun Apr 13 20:16:22 MST 2008


Author: dtrotzjr
Date: 2008-04-13 20:16:21 -0700 (Sun, 13 Apr 2008)
New Revision: 117

Added:
   trunk/src/SwordReader_GUI/SRReaderApp.cpp
   trunk/src/SwordReader_GUI/SRReaderApp.h
   trunk/src/SwordReader_GUI/SRTextView.cpp
   trunk/src/SwordReader_GUI/SRTextView.h
Removed:
   trunk/src/SwordReader_GUI/BTextViewer.cpp
   trunk/src/SwordReader_GUI/BTextViewer.h
   trunk/src/SwordReader_GUI/SwordReaderApp.cpp
   trunk/src/SwordReader_GUI/SwordReaderApp.h
Modified:
   trunk/src/SwordReader_GUI/Main.cpp
   trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.cpp
   trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.h
   trunk/src/SwordReader_GUI/SRFramework/SRMenu.cpp
   trunk/src/SwordReader_GUI/SRFramework/SRMenu.h
   trunk/src/SwordReader_GUI/SRMainFrame.cpp
   trunk/src/SwordReader_GUI/SRMainFrame.h
   trunk/src/SwordReader_GUI/SwordReader_GUI.vcproj
Log:
More restructuring.

Deleted: trunk/src/SwordReader_GUI/BTextViewer.cpp
===================================================================
--- trunk/src/SwordReader_GUI/BTextViewer.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/BTextViewer.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -1,1189 +0,0 @@
-/******************************************************************************
- *  BTextViewer.cpp - HTML Renderer for rendering biblical texts on Pocket PC 
- *  devices.
- *  Author: David C Trotz Jr. 
- *  e-mail: dtrotzjr at crosswire.org
- *
- * $Id$
- *
- * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
- *	CrossWire Bible Society
- *	P. O. Box 2528
- *	Tempe, AZ  85280-2528
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- */
-#include <Winuser.h>
-#include "stdafx.h"
-#include "BTextViewer.h"
-
-
-VOID LOGTAG(const char *tag)
-{
-#if 0
-    FILE *fp = fopen("\\Storage Card\\tags.txt", "a");
-    fprintf(fp, "%s\n", tag);
-    fclose(fp);
-#endif
-}
-
-BTextViewer::BTextViewer(HINSTANCE hInstance, HWND hWndParent, RECT lRect)
-: m_fDragging(FALSE)
-, m_nTop(0)
-, m_nDragStart(0)
-, m_dwBuffSize(BTEXT_BUFF_INC)
-, m_dwBuffEnd(0)
-, m_fPreRendered(FALSE)
-, m_nRollVelocity(FALSE)
-, m_dwTrueStartPos(0)
-, m_dwTrueStartTime(0)
-, m_hCurFont(NULL)
-{
-    TCHAR   szWindowClass[] = L"BTextViewer";
-    m_ptLastClick.x = 0; m_ptLastClick.y = 0;
-
-    // Init the current font 
-    HFONT hSystemVariableFont = (HFONT ) GetStockObject(SYSTEM_FONT);
-    GetObject(hSystemVariableFont, sizeof(LOGFONT), &m_lfCurFont);
-    m_lfCurFont.lfHeight = -11;
-    m_lfCurFont.lfQuality = CLEARTYPE_QUALITY;
-    lstrcpy(m_lfCurFont.lfFaceName, _T("Veranda"));
-
-    m_lpszBuff = new TCHAR[m_dwBuffSize];
-
-    // Register window class...
-    WNDCLASS    wc;
-    wc.style            = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
-    wc.lpfnWndProc      = (WNDPROC) BTextViewer::MessageRoute;
-    wc.cbClsExtra       = 0;
-    wc.cbWndExtra       = 0;
-    wc.hInstance        = hInstance;
-    wc.hIcon            = NULL;
-    wc.hCursor          = 0;
-    wc.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH);
-    wc.lpszMenuName     = 0;
-    wc.lpszClassName    = szWindowClass;
-
-    RegisterClass(&wc);
-    m_hWnd = CreateWindow(szWindowClass, NULL, WS_CHILD | WS_VISIBLE,
-        lRect.left, lRect.top, lRect.right - lRect.left, lRect.bottom - lRect.top, hWndParent, NULL, hInstance, this);
-    for(DWORD i = 0; i < BTEXT_FONT_CACHE_MAX; i++)
-        m_hFontCache[i] = 0;
-}
-
-BTextViewer::~BTextViewer()
-{
-    if(m_lpszBuff)
-        delete [] m_lpszBuff;
-
-    DestroyWindow(m_hWnd);
-}
-
-VOID BTextViewer::Show()
-{
-    ShowWindow(m_hWnd, SW_SHOW);
-    // FOR COMPARATIVE PERFORMANCE TESTING...
-    // REMOVE ONCE INTEGRATED
-    m_fPreRendered = FALSE;
-    InvalidateRect(m_hWnd, NULL, TRUE);
-    UpdateWindow(m_hWnd);
-}
-
-VOID BTextViewer::Hide()
-{
-    ShowWindow(m_hWnd, SW_HIDE);
-}
-
-/* Routes the messages to the appropiate WindowProcedure by unwrapping the lParam 
-* we associated with this window upon creation.
-*/
-LRESULT CALLBACK BTextViewer::MessageRoute(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-    BTextViewer*    wnd = NULL;
-
-    if (message == WM_CREATE) {	
-        ::SetWindowLong (hwnd, GWL_USERDATA, long((LPCREATESTRUCT(lParam))->lpCreateParams));
-    }
-
-    wnd = (BTextViewer*) (::GetWindowLong (hwnd, GWL_USERDATA));
-
-    if (wnd)
-        return wnd->WndProcBText(hwnd, message, wParam, lParam);
-    return ::DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-LRESULT CALLBACK BTextViewer::WndProcBText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-    HDC         hdc;
-    PAINTSTRUCT ps;
-
-    switch (message) 
-    {
-    case WM_PAINT:
-        hdc = BeginPaint(hWnd, &ps);
-        this->Paint(hWnd,hdc,ps);
-        EndPaint(hWnd, &ps);
-        break;
-    case WM_LBUTTONDOWN:
-        this->SetTapState(TRUE, lParam);
-        break;
-    case WM_LBUTTONUP:
-        this->SetTapState(FALSE, lParam);
-        break;
-    case WM_MOUSEMOVE:
-        this->DragScreenToPoint(lParam);
-        break;
-    default:
-        return DefWindowProc(hWnd, message, wParam, lParam);
-    }
-    return 0;
-}
-VOID BTextViewer::MoveWindow(INT x, INT y, INT w, INT h)
-{
-    ::MoveWindow(m_hWnd, x, y, w, h, FALSE);
-}
-
-INT BTextViewer::GetHTMLTags(RenderState& rsState, DWORD &dwWordIndex)
-{
-    BOOL    fDone               = FALSE;
-    DWORD   dwBegin;
-    DWORD   dwEnd;
-    DWORD   dwIdentifyResult;
-    INT     nLineBreaks         = 0;
-
-    while(!fDone){
-        GetSpaces(rsState, dwWordIndex);
-        dwBegin = dwWordIndex + 1;
-        if(m_lpszBuff[dwWordIndex] != 0 && m_lpszBuff[dwWordIndex] == '<'){
-            while(m_lpszBuff[dwWordIndex] != 0 && m_lpszBuff[dwWordIndex] != '>')
-                dwWordIndex++;
-            dwEnd = dwWordIndex - dwBegin;
-            dwIdentifyResult = IndentifyTag(rsState, dwBegin, dwEnd);
-            dwWordIndex++;
-            switch(dwIdentifyResult){
-                case BTEXT_HTML_B_BEG:
-                    rsState.m_wBoldState++;
-                    break;
-                case BTEXT_HTML_B_END:
-                    if(rsState.m_wBoldState)
-                        rsState.m_wBoldState--;
-                    break;
-                case BTEXT_HTML_BR:
-                    nLineBreaks++;
-                    break;
-                case BTEXT_HTML_I_BEG:
-                    rsState.m_wItalicState++;
-                    break;
-                case BTEXT_HTML_I_END:
-                    if(rsState.m_wItalicState)
-                        rsState.m_wItalicState--;
-                    break;
-                case BTEXT_HTML_A_BEG:
-                    rsState.m_wAState++;
-                    rsState.m_dwlWordNum++;
-                    rsState.m_dwSubWordNum = 0;
-                    break;
-                case BTEXT_HTML_A_END:
-                    if(rsState.m_wAState)
-                        rsState.m_wAState--;
-                    rsState.m_dwlWordNum++;
-                    rsState.m_dwSubWordNum = 0;
-                    break;
-                case BTEXT_HTML_SUB_BEG:
-                    rsState.m_wSubState++;
-                    break;
-                case BTEXT_HTML_SUB_END:
-                    if(rsState.m_wSubState)
-                        rsState.m_wSubState--;
-                    break;
-                case BTEXT_HTML_SUP_BEG:
-                    rsState.m_wSuperState++;
-                    break;
-                case BTEXT_HTML_SUP_END:
-                    if(rsState.m_wSuperState)
-                        rsState.m_wSuperState--;
-                    break;
-                case BTEXT_HTML_P_BEG:
-                    rsState.m_wParagraphState++;
-                    nLineBreaks++;
-                    break;
-                case BTEXT_HTML_P_END:
-                    if(rsState.m_wParagraphState)
-                        rsState.m_wParagraphState--;
-                    nLineBreaks++;
-                    break;
-            }
-        }else
-            fDone = TRUE;
-    }
-    return nLineBreaks;
-}
-
-DWORD BTextViewer::IndentifyTag(RenderState& rsState,DWORD dwWordIndex,DWORD dwWordEnd)
-{
-    DWORD dwMask      = 0x00000000;
-    DWORD dwResult    = 0x00000000;
-    DWORD dwLen       = 0;
-    DWORD dwOrigIndex = dwWordIndex;
-    DWORD dwSubIndex  = 0;
-
-    if(!dwWordEnd)
-        return BTEXT_HTML_ILLEGAL_TAG_FORMAT; // There is nothing to do here.
-
-    if((dwWordIndex - dwOrigIndex) >=  dwWordEnd)
-        return BTEXT_HTML_ILLEGAL_TAG_FORMAT;
-
-    if(m_lpszBuff[dwWordIndex] == '/'){
-        dwMask = 0xFFFFFFFF;
-        dwWordIndex++;
-    }
-
-    if((dwWordIndex - dwOrigIndex) >=  dwWordEnd)
-        return BTEXT_HTML_ILLEGAL_TAG_FORMAT;
-    // Get the token
-    while((dwWordIndex  - dwOrigIndex) + dwLen <  dwWordEnd && m_lpszBuff[dwWordIndex + dwLen] != ' '){
-        dwLen++;
-    }
-
-    // Determine the token
-    switch(dwLen){
-        case 0:
-            dwResult = BTEXT_HTML_ILLEGAL_TAG_FORMAT;
-            break;
-        case 1:
-            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"a", 1) == 0){
-                dwSubIndex = dwWordIndex + 1;
-                while(m_lpszBuff[dwSubIndex] == ' ')
-                    dwSubIndex++;
-                if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"name=\"", 6) == 0){
-                    dwSubIndex += 6;
-                    rsState.m_wVerseNum = (short)_wtoi(&m_lpszBuff[dwSubIndex]);
-                }else if(dwMask == 0){ // This is not an '/a'
-                    while(m_lpszBuff[dwSubIndex] == ' ')
-                        dwSubIndex++;
-                    if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"href=\"", 6) == 0){
-                        dwSubIndex += 6;
-                        rsState.m_lpszHref = &m_lpszBuff[dwSubIndex];
-                        rsState.m_dwHrefLen = 0;
-                        while(m_lpszBuff[dwSubIndex++] != '\"')
-                            rsState.m_dwHrefLen++;
-                    }
-                    dwResult = dwMask ^ BTEXT_HTML_A_BEG;
-                }else
-                    dwResult = dwMask ^ BTEXT_HTML_A_BEG;
-
-            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"b", 1) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_B_BEG;
-            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"i", 1) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_I_BEG;
-            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"p", 1) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_P_BEG;
-            }
-            break;
-        case 2:
-            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"br", 2) == 0){
-                dwResult = BTEXT_HTML_BR;		
-            }
-            break;
-        case 3:
-            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"sup", 3) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_SUP_BEG;	
-            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"sub", 3) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_SUB_BEG;
-            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"br/", 3) == 0){
-                dwResult = BTEXT_HTML_BR;		
-            }
-            break;
-        case 4:
-            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"font", 4) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_FONT_BEG;
-                if(!dwMask){
-                    // Found a <font... element
-                    if(!rsState.m_lpftFontTagTail){
-                        rsState.m_lpftFontTagHead = new FontTagItem();
-                        rsState.m_lpftFontTagTail = rsState.m_lpftFontTagHead;
-                    }else{
-                        rsState.m_lpftFontTagTail->m_lpftNext = new FontTagItem();
-                        rsState.m_lpftFontTagTail = rsState.m_lpftFontTagTail->m_lpftNext;
-                    }
-                    dwSubIndex += dwWordIndex + 4;
-                    while(m_lpszBuff[dwSubIndex] != '>'){
-                        while(m_lpszBuff[dwSubIndex] == ' ')
-                            dwSubIndex++;
-                        if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"size=\"", 6) == 0){
-                            dwSubIndex += 6;
-                            rsState.m_lpftFontTagTail->m_siRelFontSize = (short)_wtoi(&m_lpszBuff[dwSubIndex]);
-                            while(m_lpszBuff[dwSubIndex] != '\"')
-                                dwSubIndex++;
-                            dwSubIndex++;
-                        }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"color=\"", 7) == 0){
-                            dwSubIndex += 7;
-                            if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"red\"", 4) == 0){
-                                dwSubIndex += 4;
-                                rsState.m_lpftFontTagTail->m_crFontColor = 0x000000FF;
-                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"green\"", 6) == 0){
-                                dwSubIndex += 6;
-                                rsState.m_lpftFontTagTail->m_crFontColor = 0x0000FF00;
-                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"blue\"", 5) == 0){
-                                dwSubIndex += 5;
-                                rsState.m_lpftFontTagTail->m_crFontColor = 0x00FF0000;
-                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"black\"", 6) == 0){
-                                dwSubIndex += 6;
-                                rsState.m_lpftFontTagTail->m_crFontColor = 0x00000000;
-                            }
-                        }
-                    }
-                }else{ 
-                    // Its a </font pop the last item off the linked list
-                    // this has potential to be memory leak central...
-                    if(rsState.m_lpftFontTagTail){
-                        if(rsState.m_lpftFontTagHead == rsState.m_lpftFontTagTail){
-                            delete rsState.m_lpftFontTagHead;
-                            rsState.m_lpftFontTagHead = NULL;
-                            rsState.m_lpftFontTagTail = NULL;
-                        }else{
-                            FontTagItem *next = rsState.m_lpftFontTagHead;
-                            FontTagItem *prev = next;
-
-                            while(next != rsState.m_lpftFontTagTail){
-                                prev = next;
-                                next = prev->m_lpftNext;
-                            }
-                            delete next;
-                            rsState.m_lpftFontTagTail = prev;
-                        }
-                    }
-                }
-            }
-            break;
-        case 5:
-            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"small", 5) == 0){
-                dwResult = dwMask ^ BTEXT_HTML_SMALL_BEG;
-            }
-            break;
-        default:
-            dwResult = 0;
-    }
-
-    return dwResult;
-}
-
-
-INT BTextViewer::NextWord(RenderState& rsState,DWORD dwWordIndex, DWORD &dwWordEnd)
-{
-    dwWordEnd = 0;
-    // Special Entities are: 
-    //      &gt; &lt; &amp; 
-    //      and others (later)
-    rsState.m_wTotalSpclEnt = 0;
-
-    while(m_lpszBuff[dwWordIndex + dwWordEnd] != 0 && m_lpszBuff[dwWordIndex + dwWordEnd] != ' ' && m_lpszBuff[dwWordIndex + dwWordEnd] != '\n' && m_lpszBuff[dwWordIndex + dwWordEnd] != '<'){
-        if(m_lpszBuff[dwWordIndex + dwWordEnd] == '&'){
-            dwWordEnd++;
-            while(m_lpszBuff[dwWordIndex + dwWordEnd] != ';'){
-                dwWordEnd++;
-                rsState.m_wTotalSpclEnt++;
-            }
-        }
-        dwWordEnd++;
-    }
-    if(m_lpszBuff[dwWordIndex + dwWordEnd] == '\n')
-        return BTEXT_NEWLINE_ENCOUNTERED;
-    else if(m_lpszBuff[dwWordIndex + dwWordEnd] == '<')
-        return BTEXT_HTML_OPEN_BRACKET;
-
-    return BTEXT_SPACE_ENCOUNTERED;
-}
-VOID BTextViewer::Clear()
-{
-    m_BTLines.ClearLines();
-    m_BTLines.InitLines(0);
-    if(m_lpszBuff)
-        delete [] m_lpszBuff;
-    m_lpszBuff = NULL;
-    m_dwBuffEnd = 0;
-    m_dwBuffSize = 0;
-    m_nTop = 0;
-    m_fPreRendered = FALSE;
-}
-VOID BTextViewer::PreRenderBuff(HDC hdc)
-{
-    BTextWord   thisWord;
-    RenderState rsState;
-    memset(&rsState, 0, sizeof(rsState));
-    RECT        rectDims;
-    INT         nLineX      = BTEXT_MARGIN;
-    INT         nLineY      = BTEXT_MARGIN;
-    DWORD       dwLineNum   = 0;
-    rectDims.top            = 0; 
-    rectDims.left           = 0; 
-    rectDims.right          = 0; 
-    rectDims.bottom         = 0;
-    INT         nLineH      = (INT)(BTEXT_LINE_SPACING*(FLOAT)DrawText(hdc, L" ", 1, &rectDims, DT_CALCRECT | DT_LEFT | DT_BOTTOM | DT_SINGLELINE));
-    DWORD       dwWordIndex = 0;
-    DWORD       dwWordEnd   = 0;
-    INT         nSpaceWidth = rectDims.right - rectDims.left;
-    INT         nScreenWidth= GetSystemMetrics(SM_CXSCREEN) - BTEXT_MARGIN;
-    DWORD       dwResult    = 0;
-    INT         nAddLines   = 0;
-    DWORDLONG   dwlFontState= 0;
-    DWORDLONG dwlFontColor;
-    DWORDLONG dwlFontHeight;
-
-    m_BTLines.ClearLines();
-    m_BTLines.InitLines(nLineH);
-
-    while(TRUE){
-        thisWord.Clear();
-        rsState.m_space_encountered = FALSE;
-
-        GetSpaces(rsState, dwWordIndex);
-        nAddLines = GetHTMLTags(rsState, dwWordIndex);
-        if(nAddLines){
-            dwLineNum += nAddLines;
-            nLineX = BTEXT_MARGIN;
-            nLineY += nAddLines * nLineH;
-            rsState.m_space_encountered = FALSE;
-        }
-        GetSpaces(rsState, dwWordIndex);
-        if(rsState.m_space_encountered){
-            nLineX += nSpaceWidth;
-            rsState.m_space_encountered = FALSE;
-            rsState.m_dwlWordNum++;
-            rsState.m_dwSubWordNum = 0;
-        }else
-            rsState.m_dwSubWordNum++;
-
-        dwResult = NextWord(rsState, dwWordIndex, dwWordEnd);
-        if(dwWordEnd == 0){
-            break;
-        }
-        rectDims.left = nLineX;
-
-        // Font...
-        FontTagItem *tag = rsState.m_lpftFontTagHead;
-        dwlFontColor = BTEXT_DEFAULT_FONT_COLOR;
-        dwlFontHeight = abs(BTEXT_DEFAULT_FONT_HEIGHT);
-        while(tag){
-            if(tag->m_crFontColor != BTEXT_FONT_NOT_A_COLOR)
-                dwlFontColor = tag->m_crFontColor;
-            dwlFontHeight += tag->m_siRelFontSize;
-            tag = tag->m_lpftNext;
-        }
-        if(rsState.m_wSubState || rsState.m_wSuperState)
-            dwlFontHeight -= 3;
-
-        dwlFontState = 
-            ((DWORDLONG)(dwlFontColor  << 40) & 0xFFFFFF0000000000)	| 
-            ((DWORDLONG)(dwlFontHeight << 32) & 0x000000FF00000000)	|
-            (rsState.m_wAState > 0	    ? BTEXT_HTML_A_BEG : 0)	|
-            (rsState.m_wBoldState > 0   ? BTEXT_HTML_B_BEG : 0)	|
-            (rsState.m_wItalicState > 0 ? BTEXT_HTML_I_BEG : 0);
-        SetFont(hdc, dwlFontState);
-
-        rectDims.top = nLineY;
-        // Set the properties for this word.
-        thisWord.m_rect             = rectDims;
-        thisWord.m_dwlfFontState    = dwlFontState;
-        thisWord.m_lpszHref         = rsState.m_lpszHref;
-        thisWord.m_dwHrefLen        = rsState.m_dwHrefLen;
-        thisWord.m_dwlWordNum       = rsState.m_dwlWordNum;
-        thisWord.m_dwSubWordNum     = rsState.m_dwSubWordNum;
-        // Determine if we encountered any special entities...
-        if(rsState.m_wTotalSpclEnt > 0){
-            InterpretSpecialEntities(dwWordIndex, dwWordEnd, &thisWord);
-        }else{
-            thisWord.m_fOwner = FALSE;
-            thisWord.m_lpszWord = &m_lpszBuff[dwWordIndex];
-            thisWord.m_dwWordLen = dwWordEnd;
-        }
-        // Calc the text rect
-        DrawText(hdc, thisWord.m_lpszWord, thisWord.m_dwWordLen, &thisWord.m_rect, 
-            DT_CALCRECT | DT_LEFT | DT_BOTTOM | DT_SINGLELINE);
-
-        if(rsState.m_wSuperState)
-            thisWord.m_rect.top -= 1; // TODO: Determine the '1' value based upon the font size
-        else if(rsState.m_wSubState)
-            thisWord.m_rect.top = 2*thisWord.m_rect.top + nLineH - thisWord.m_rect.bottom + 1; // TODO: Same as above...
-        else
-            thisWord.m_rect.top = 2*thisWord.m_rect.top + nLineH - thisWord.m_rect.bottom; // Baseline justify
-
-        if(thisWord.m_rect.right > (nScreenWidth - BTEXT_MARGIN)){
-            // Place on next line. But...
-            // We may need to move the prefix of this word down, thus we need to adjust the left
-            // edge of this word to make room.
-            int adjustedMargin = BTEXT_MARGIN;
-            if(thisWord.m_dwSubWordNum > 0)
-                adjustedMargin = m_BTLines.ValidateNewLineWord(thisWord.m_dwlWordNum,nLineH, BTEXT_MARGIN);
-
-            dwLineNum++;
-            thisWord.m_rect.right = thisWord.m_rect.right - thisWord.m_rect.left + adjustedMargin;
-            thisWord.m_rect.left = adjustedMargin;
-            thisWord.m_rect.top += nLineH;
-            thisWord.m_rect.bottom += nLineH;
-
-            nLineY += nLineH;
-        }
-
-        // Store the line to be rendered later.
-        m_BTLines.AddWordToLine(dwLineNum, thisWord);
-
-        // Prep for next iteration
-        if(rsState.m_space_encountered)
-            nLineX = thisWord.m_rect.right + nSpaceWidth;
-        else
-            nLineX = thisWord.m_rect.right;
-
-        //curWord++;
-        dwWordIndex += dwWordEnd;
-    }
-    if(rsState.m_lpftFontTagHead) // Properly formatted text would never need this, but that cannot be assumed.
-        delete rsState.m_lpftFontTagHead; // Do not delete Tail it is a convenience pointer...
-
-    m_fPreRendered = TRUE;
-}
-
-// I wanted to use the same font setter for both prerendering and rendering
-// so I wrote this method. The first if statement will try to determine if
-// we can safely skip this call since it is a rather expensive call
-// after several thousand words are pre-rendered and rendered. But,
-// If the text is already pre-rendered and we are calling this during
-// the actual rendering stage we are sure we want to make this call already
-// and thus the !m_bnRendering statement ensures we will change the font - otherwise
-// certain lines get the wrong fonts applied to them.
-VOID BTextViewer::SetFont(HDC hdc, DWORDLONG dwlFontState)
-{
-    INT     lfWeight    = dwlFontState & BTEXT_HTML_B_BEG ? FW_BOLD : FW_NORMAL;
-    UCHAR   lfItalic    = (char)((dwlFontState & BTEXT_HTML_I_BEG) > 0 ? 1 : 0);
-    UCHAR   lfUnderline = (char)((dwlFontState & BTEXT_HTML_A_BEG) > 0 ? 1 : 0); 
-    INT     lfHeight    = -1*((int)(0x000000FF & ((dwlFontState & 0x000000FF00000000) >> 32)));
-    HGDIOBJ oldFont     = 0;
-    // Compute the font cache index...
-    DWORD   dwFontCacheIndex = 0x000000FF & ((dwlFontState & (BTEXT_HTML_B_BEG | BTEXT_HTML_I_BEG | BTEXT_HTML_A_BEG)) | ((dwlFontState & 0x000000FF00000000) >> 24));
-    
-    if(!m_fPreRendered && 
-        m_lfCurFont.lfWeight    == lfWeight && 
-        m_lfCurFont.lfItalic    == lfItalic && 
-        m_lfCurFont.lfHeight    == lfHeight &&
-        m_lfCurFont.lfUnderline == lfUnderline)
-        return;
-
-    m_lfCurFont.lfWeight    = lfWeight;
-    m_lfCurFont.lfItalic    = lfItalic;
-    m_lfCurFont.lfHeight    = lfHeight;
-    m_lfCurFont.lfUnderline = lfUnderline;
-    
-    if(!m_hFontCache[dwFontCacheIndex]){
-        m_hFontCache[dwFontCacheIndex] = CreateFontIndirect(&m_lfCurFont);
-    }
-    SelectObject(hdc, m_hFontCache[dwFontCacheIndex]);
-    /*
-    m_hCurFont = CreateFontIndirect(&m_lfCurFont);
-    oldFont = SelectObject(hdc, m_hCurFont);
-    if(oldFont)
-        DeleteObject(oldFont);
-    */
-}
-
-BOOL BTextViewer::GetSpaces(RenderState& rsState, DWORD &dwWordIndex){
-    DWORD i = 0;
-
-    while(m_lpszBuff[dwWordIndex] != '\0' && (m_lpszBuff[dwWordIndex] == ' ' || (m_lpszBuff[dwWordIndex] == '&' && wcsnicmp(&m_lpszBuff[dwWordIndex], L"&nbsp;", 6) == 0)) ){
-        dwWordIndex += m_lpszBuff[dwWordIndex] == '&' ? 6 : 1; // Did we find a &nbsp; then we need to increment that much.
-        i++;
-
-    }
-
-    if(i) 
-        rsState.m_space_encountered = TRUE;
-    return i > 0;
-}
-
-VOID BTextViewer::InterpretSpecialEntities(DWORD dwWordIndex, DWORD dwWordLen, BTextWord *pbtWord)
-{
-    DWORD dwSubIndex    = 0;
-    DWORD dwBufIndex    = 0;
-    TCHAR szBuf[256]    = {0};
-
-    while(dwSubIndex < dwWordLen){
-        if(m_lpszBuff[dwWordIndex + dwSubIndex] == '&'){
-            dwSubIndex++;
-            if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"lt;",3) == 0){
-                szBuf[dwBufIndex++] = '<';
-                dwSubIndex += 3;
-            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"gt;",3) == 0){
-                szBuf[dwBufIndex++] = '>';
-                dwSubIndex += 3;
-            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"amp;",4) == 0){
-                szBuf[dwBufIndex++] = '&';
-                dwSubIndex += 4;
-            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"nbsp;",5) == 0){
-                szBuf[dwBufIndex++] = ' ';
-                dwSubIndex += 5;
-            }else{
-                // I have no idea what this is, simply display it...
-                szBuf[dwBufIndex++] = '&';
-                dwSubIndex++;
-            }
-        }
-        else
-            szBuf[dwBufIndex++] = m_lpszBuff[dwWordIndex + dwSubIndex++];
-    }
-
-    pbtWord->OwnWord(szBuf, dwBufIndex);
-}
-
-INT BTextViewer::Paint(HWND hWnd, HDC hdc, PAINTSTRUCT ps)
-{
-    COLORREF    crColor     = 0x00000000;
-    COLORREF    crOldColor  = SetTextColor(hdc, crColor); 
-    INT         nSavedDC    = SaveDC(hdc);
-    RECT        rectDims;
-    rectDims.top            = 0; 
-    rectDims.left           = 0; 
-    rectDims.right          = 0; 
-    rectDims.bottom         = 0;
-
-    SetBkMode(hdc, TRANSPARENT); 
-    if(!m_fPreRendered)
-        PreRenderBuff(hdc);
-
-    for(unsigned int line = 0; line <= m_BTLines.m_dwLastLine; line++){
-        BTextWord *pTWord = &m_BTLines.m_lpLines[line];
-        if((pTWord->m_rect.top + m_BTLines.m_nLineH + m_nTop) <= ps.rcPaint.top)
-            continue; // this line is above the region we are interested in painting
-        else if(pTWord->m_rect.top + m_nTop > ps.rcPaint.bottom)
-            break; // We are done the rest of the lines are below the region we care about.
-        while(pTWord->m_lpszWord){
-            if(!pTWord->m_lpPrevWord || pTWord->m_dwlfFontState != pTWord->m_lpPrevWord->m_dwlfFontState){
-                if(pTWord->m_dwlfFontState & BTEXT_HTML_A_BEG){ // links get priority coloring
-                    crColor = COLORREF(0x00FF0000);
-                }else{
-                    crColor = COLORREF(((pTWord->m_dwlfFontState >> 40) & 0x00FFFFFF));
-                }
-                SetTextColor(hdc, crColor);
-                SetFont(hdc, pTWord->m_dwlfFontState);
-            }
-
-            ExtTextOut(hdc,pTWord->m_rect.left, pTWord->m_rect.top + m_nTop, NULL, NULL, pTWord->m_lpszWord, pTWord->m_dwWordLen, NULL);
-            pTWord = pTWord->m_lpNextWord;
-        }
-    }
-
-    SetTextColor(hdc, crOldColor); 
-    ClearFontCache(hdc);
-    RestoreDC(hdc, nSavedDC);
-    return 0;
-}
-
-VOID BTextViewer::ClearFontCache(HDC hdc)
-{
-    // Clear the font from device context so it can be deleted with the rest...
-    SelectObject(hdc, GetStockObject(SYSTEM_FONT));
-    
-    for(DWORD i = 0; i < BTEXT_FONT_CACHE_MAX; i++){
-        if(m_hFontCache[i]){
-            DeleteObject(m_hFontCache[i]);
-            m_hFontCache[i] = 0;
-
-        }
-    }
-}
-
-VOID BTextViewer::SetTapState(BOOL fMouseDown, LPARAM lParam)
-{
-    POINT pt;
-    DWORD dwDiffTime = 0;
-    pt.x = LOWORD(lParam);
-    pt.y = HIWORD(lParam);
-    ScreenToClient(m_hWnd, &pt);
-    // Test if the mouse moved more than some threshold value.
-    BOOL mouseMoved = (abs(m_ptLastClick.y - pt.y) > 5) || (abs(m_ptLastClick.x - pt.x) > 5);
-
-    if(!m_fDragging){	
-        m_nDragStart =  pt.y;
-    }
-
-    // If we are about to go into a dragging mode, 
-    // or we are about to leave a dragging mode,
-    // we should calculate a rolling velocity.
-    if(fMouseDown && !m_fDragging){
-        m_dwTrueStartPos = pt.y;
-        m_dwTrueStartTime = GetTickCount();
-        m_nRollVelocity = 0;
-    }else if(!fMouseDown && m_fDragging){
-        dwDiffTime = GetTickCount() - m_dwTrueStartTime;
-        if(dwDiffTime > 200)
-            m_nRollVelocity = 0;
-        else
-            m_nRollVelocity = (80*(int)(pt.y - m_dwTrueStartPos))/((int)dwDiffTime);
-    }
-
-    if(fMouseDown){
-        m_dwClickTime = GetTickCount();
-        m_fDragging = TRUE;
-        SetCapture(m_hWnd);
-    }else{
-        m_fDragging = FALSE;
-        ReleaseCapture();
-    }
-
-    // If we are absolutely positive the user wants to click...
-    if(!fMouseDown && !mouseMoved && (GetTickCount() - m_dwClickTime) < 120)
-        GetWordAtPoint(lParam);
-    m_ptLastClick = pt;
-
-    // If there is a velocity set this will use it up, otherwise it drops out nicely.
-    RollTillStopped();
-}
-
-VOID BTextViewer::GetWordAtPoint(LPARAM lParam)
-{
-    POINT pt;
-    pt.x = LOWORD(lParam);
-    pt.y = HIWORD(lParam);
-    BTextWord *pbtWord;
-    DWORD dwLineNum = 0;
-    TCHAR szWordFound[128] = {0};
-
-    while(dwLineNum <= m_BTLines.m_dwLastLine && (m_BTLines.m_lpLines[dwLineNum].m_rect.bottom + m_nTop) < pt.y)
-        dwLineNum++;
-    if(dwLineNum > m_BTLines.m_dwLastLine)
-        return;
-    pbtWord = &m_BTLines.m_lpLines[dwLineNum]; 
-    while(pbtWord->m_lpszWord && pbtWord->m_rect.right < pt.x)
-        pbtWord = pbtWord->m_lpNextWord;
-    if(pbtWord->m_lpszWord){
-        if(pbtWord->m_dwlfFontState & BTEXT_HTML_A_BEG && pbtWord->m_lpszHref){
-            wcsncpy(szWordFound, pbtWord->m_lpszHref, pbtWord->m_dwHrefLen);
-        }else{
-            wcsncpy(szWordFound, pbtWord->m_lpszWord, pbtWord->m_dwWordLen);
-        }
-        MessageBox(m_hWnd, szWordFound, L"Found...", MB_OK);
-    }
-}
-
-VOID BTextViewer::DragScreenToPoint(LPARAM lParam)
-{
-    POINT   pt;
-    RECT    rectUpdateRect;
-    INT     nDragDist = 0;
-
-    if(m_fDragging){
-        pt.x = 0;
-        pt.y = HIWORD(lParam);
-        ScreenToClient(m_hWnd, &pt);
-        nDragDist = pt.y - m_nDragStart;
-        m_nTop += nDragDist;
-        // Prevent rolling past top or bottom
-        if(m_nTop > 0){
-            nDragDist -= m_nTop;
-            m_nTop = 0;
-        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
-            // nDragDist does not matter here because we are Scrolling a white window, 
-            // Keeping track of m_nTop is important as it is our reference point for 
-            // scrolling later
-            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
-        }
-
-        ScrollWindowEx(m_hWnd, 0, nDragDist, NULL, NULL, NULL, &rectUpdateRect, NULL);
-        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
-        UpdateWindow(m_hWnd);
-
-        m_nDragStart = pt.y;
-    }
-}
-
-VOID BTextViewer::RollTillStopped()
-{
-    RECT    rectUpdateRect;
-    BOOL    fDone       = FALSE;
-    INT     nDirection  = m_nRollVelocity > 0 ? 1 : -1;
-
-    while(!fDone && nDirection*m_nRollVelocity > 0){
-        m_nTop += m_nRollVelocity;
-
-        // Prevent rolling beyond the top of the page.
-        if(m_nTop > 0){
-            m_nRollVelocity -= m_nTop;
-            m_nTop = 0;
-            fDone = TRUE;
-        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
-            // dist does not matter here because we are Scrolling a white window, 
-            // Keeping track of m_nTop is important as it is our reference point for 
-            // scrolling later
-            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
-            fDone = TRUE;
-        }
-
-        ScrollWindowEx(m_hWnd, 0, m_nRollVelocity, NULL, NULL, NULL, &rectUpdateRect, NULL);
-        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
-        UpdateWindow(m_hWnd);
-        m_nRollVelocity = (m_nRollVelocity - m_nRollVelocity/6) - ((nDirection*m_nRollVelocity < 10) ? nDirection : 0); // the nDirection part ensures continual degrading in the velocity
-    }
-}
-
-VOID BTextViewer::ScrollFullPage(INT nDirection)
-{
-    RECT    rectUpdateRect;
-    RECT    rectClientRect;
-    INT     nDist       = 0;
-    BOOL    fDone       = FALSE;
-    GetClientRect(m_hWnd,&rectClientRect);
-    INT     nRollBy     = rectClientRect.bottom - rectClientRect.top;
-    INT     nCalcDist   = 0;
-    CONST INT UPPER_SB  = 15; // Upper bound on the scrolling per iteration.
-    nDirection          = (nDirection > 0) ? 1 : -1;
-    
-    for(INT i = 0;!fDone && i < nRollBy; i+=nCalcDist){
-        nCalcDist = UPPER_SB - (int)(UPPER_SB*((float)i/(float)nRollBy)) + 1;
-        nDist = nDirection*nCalcDist;
-        m_nTop += nDist;
-        // Prevent rolling beyond the top of the page.
-        if(m_nTop > 0){
-            nDist -= m_nTop;
-            m_nTop = 0;
-            fDone = TRUE;
-        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
-            // nDist does not matter here because we are Scrolling a white window, 
-            // Keeping track of m_nTop is important as it is our reference point for 
-            // scrolling later
-            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
-            fDone = TRUE;
-        }
-        ScrollWindowEx(m_hWnd, 0, nDist, NULL, NULL, NULL, &rectUpdateRect, NULL);
-        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
-        UpdateWindow(m_hWnd);
-    }
-}
-
-VOID BTextViewer::AddText(TCHAR *szText, DWORD dwSize)
-{
-    DWORD i = 0;
-
-    // Do we need to make room for the new szText
-    if((m_dwBuffEnd + dwSize) > m_dwBuffSize){
-        DWORD dwNewSize = BTEXT_BUFF_INC > dwSize ? BTEXT_BUFF_INC : dwSize;
-        TCHAR *lpszTmp = new TCHAR[dwNewSize];
-        for(i = 0; i < m_dwBuffSize; i++){
-            lpszTmp[i] = m_lpszBuff[i];
-        }
-        delete [] m_lpszBuff;
-        m_lpszBuff = lpszTmp;
-        m_dwBuffSize = dwNewSize;
-    }
-
-    // If this is a new buffer we need to
-    // discard HTML header stuff by pointing to the beginning of the <body></body>
-    i = 0;
-    if(m_dwBuffEnd == 0){ 
-        do{
-            while(szText[i] != '<' && i < dwSize) i++;
-            if(wcsnicmp(&szText[i], L"<body>", 6) == 0){
-                i += 6;
-                break;
-            }
-            while(szText[i++] != '>' && i < dwSize);
-        }while(TRUE);
-    }
-
-    // Copy it in, and ignore the closing tags, if any
-    for(; i < dwSize; i++){
-        // We arbitrarily choose to start looking at the last 100 characters for the tail end 
-        // of this HTML stream. If we fail to chop it off its not the end of the world, but
-        // it would be nice to get out of the way now.
-        if(dwSize > 100 && i > (dwSize - 100) && wcsnicmp(&szText[i], L"</body>", 7) == 0)
-            break; 
-        if(szText[i] == 0x09) // Horizontal tab, replace with a single space. (for now at least.)
-            m_lpszBuff[m_dwBuffEnd++] = ' ';
-        else if(szText[i] != '\n') // Ignore new-lines
-            m_lpszBuff[m_dwBuffEnd++] = szText[i];
-    }
-    for(i = 0; i + m_dwBuffEnd < m_dwBuffSize; i++)
-        m_lpszBuff[i + m_dwBuffEnd] = 0;
-}
-
-/*****************************************************************************
- * BTextWord                                                                 *
- *****************************************************************************/
-
-BTextViewer::BTextWord::BTextWord()
-: m_lpNextWord(0)
-, m_lpPrevWord(0)
-, m_lpszWord(NULL)
-, m_dwWordLen(0)
-, m_lpszHref(NULL)
-, m_dwHrefLen(0)
-, m_fOwner(FALSE)
-, m_dwlfFontState(0)
-, m_dwlWordNum(0)
-, m_dwSubWordNum(0)
-{
-    m_rect.top      = 0;
-    m_rect.left     = 0;
-    m_rect.bottom   = 0;
-    m_rect.right    = 0;
-}
-
-VOID BTextViewer::BTextWord::Clear()
-{
-    if(m_fOwner && m_lpszWord)
-        delete [] m_lpszWord;
-    m_fOwner            = FALSE;
-    m_dwlfFontState     = 0;
-    m_dwHrefLen         = 0;
-    m_dwWordLen         = 0;
-    m_lpszWord          = NULL;
-    m_lpszHref          = NULL;
-    m_rect.top          = 0;
-    m_rect.bottom       = 0;
-    m_rect.left         = 0;
-    m_rect.right        = 0;
-    m_dwlWordNum        = 0;
-    m_dwSubWordNum      = 0;
-    m_lpNextWord        = NULL;
-    m_lpPrevWord        = NULL;
-}
-
-VOID BTextViewer::BTextWord::OwnWord(TCHAR *lpszWord, DWORD dwWordLen)
-{
-    if(m_fOwner && m_lpszWord){
-        delete [] m_lpszWord;
-    }
-    m_lpszWord = new TCHAR[dwWordLen + 1];
-    for(DWORD i = 0; i < dwWordLen; i++)
-        m_lpszWord[i] = lpszWord[i];
-
-    m_lpszWord[dwWordLen]   = 0;
-    m_dwWordLen             = dwWordLen;
-    m_fOwner                = TRUE;
-}
-
-BTextViewer::BTextWord::BTextWord(const BTextViewer::BTextWord &rhs)
-{
-    m_dwlfFontState = rhs.m_dwlfFontState;
-    m_dwHrefLen     = rhs.m_dwHrefLen;
-    m_dwWordLen     = rhs.m_dwWordLen;
-    m_lpszHref      = rhs.m_lpszHref;
-    m_lpNextWord    = rhs.m_lpNextWord;
-    m_lpPrevWord    = rhs.m_lpPrevWord;
-    m_fOwner        = rhs.m_fOwner;
-    m_rect          = rhs.m_rect;
-    m_dwlWordNum    = rhs.m_dwlWordNum;
-    m_dwSubWordNum  = rhs.m_dwSubWordNum;
-
-    if(m_fOwner && rhs.m_lpszWord){
-        m_lpszWord = new TCHAR[m_dwWordLen + 1];
-        for(DWORD i = 0; i < m_dwWordLen; i++)
-            m_lpszWord[i] = rhs.m_lpszWord[i];
-        m_lpszWord[m_dwWordLen] = 0;
-    }else{
-        m_lpszWord = rhs.m_lpszWord;
-    }
-}
-BTextViewer::BTextWord & BTextViewer::BTextWord::operator=(const BTextViewer::BTextWord &rhs)
-{
-    if(this == &rhs)
-        return *this; // We detect self assignment
-
-    m_dwlfFontState = rhs.m_dwlfFontState;
-    m_dwHrefLen     = rhs.m_dwHrefLen;
-    m_dwWordLen     = rhs.m_dwWordLen;
-    m_lpszHref      = rhs.m_lpszHref;
-    m_lpNextWord    = rhs.m_lpNextWord;
-    m_lpPrevWord    = rhs.m_lpPrevWord;
-    m_rect          = rhs.m_rect;
-    m_dwlWordNum    = rhs.m_dwlWordNum;
-    m_dwSubWordNum  = rhs.m_dwSubWordNum;
-
-    if(m_fOwner && m_lpszWord)
-        delete [] m_lpszWord;
-
-    m_fOwner        = rhs.m_fOwner;
-
-    if(m_fOwner && rhs.m_lpszWord){
-        m_lpszWord = new TCHAR[m_dwWordLen + 1];
-        for(DWORD i = 0; i < m_dwWordLen; i++)
-            m_lpszWord[i] = rhs.m_lpszWord[i];
-        m_lpszWord[m_dwWordLen] = 0;
-    }else{
-        m_lpszWord = rhs.m_lpszWord;
-    }
-    return *this;
-}
-
-BTextViewer::BTextWord::~BTextWord()
-{
-    if(m_fOwner && m_lpszWord){
-        delete [] m_lpszWord;
-    }
-}
-/*****************************************************************************
- * BTextLines                                                                *
- *****************************************************************************/
-
-BTextViewer::BTextLines::BTextLines()
-: m_nLineH(0)
-, m_dwLastLine(0)
-{
-    InitLines(0);
-}
-
-VOID BTextViewer::BTextLines::InitLines(CONST INT nLineH)
-{
-    m_dwLines           = BTEXT_LINE_INC;
-    m_lpLines           = new BTextWord[m_dwLines];
-    m_lppLinesLastWord  = new BTextWord*[m_dwLines];
-    
-    for(DWORD i = 0; i < m_dwLines; i++)
-        m_lppLinesLastWord[i] = &m_lpLines[i];
-    m_nLineH = nLineH;
-}
-
-BTextViewer::BTextLines::BTextLines(CONST BTextViewer::BTextLines &rhs)
-{
-    m_dwLastLine        = rhs.m_dwLastLine;
-    m_dwLines           = rhs.m_dwLines;
-    m_lpLines           = new BTextWord[m_dwLines];
-    m_lppLinesLastWord  = new BTextWord*[m_dwLines];
-
-    for(DWORD i = 0; i < m_dwLines; i++){
-        m_lpLines[i]            = rhs.m_lpLines[i];
-        m_lppLinesLastWord[i]   = rhs.m_lppLinesLastWord[i];
-    }
-}
-
-BTextViewer::BTextLines & BTextViewer::BTextLines::operator=(CONST BTextViewer::BTextLines &rhs)
-{
-    if(this == &rhs)
-        return *this; // We detect self assignment
-
-    ClearLines();
-
-    m_dwLastLine    = rhs.m_dwLastLine;
-    m_dwLines       = rhs.m_dwLines;
-
-    m_lpLines           = new BTextWord[m_dwLines];
-    m_lppLinesLastWord  = new BTextWord*[m_dwLines];
-
-    for(DWORD i = 0; i < m_dwLines; i++){
-        m_lpLines[i]            = rhs.m_lpLines[i];
-        m_lppLinesLastWord[i]   = rhs.m_lppLinesLastWord[i];
-    }
-
-    return *this;
-}
-
-BTextViewer::BTextLines::~BTextLines()
-{
-    ClearLines();
-}
-
-VOID BTextViewer::BTextLines::ClearLines()
-{
-    DWORD dwCurLine = 0;
-    BTextWord *pbtNextWord = NULL;
-    BTextWord *pbtTempWord = NULL;
-
-    for(dwCurLine = 0; dwCurLine < m_dwLines; dwCurLine++){
-        pbtNextWord = m_lpLines[dwCurLine].m_lpNextWord;
-        // Delete all the words in this line
-        while(pbtNextWord){
-            pbtTempWord = pbtNextWord->m_lpNextWord;
-            delete pbtNextWord;
-            pbtNextWord = pbtTempWord;
-        }
-    }
-    m_dwLastLine = 0;
-    m_dwLines = 0;
-
-    delete [] m_lpLines;
-    m_lpLines = NULL;
-    delete [] m_lppLinesLastWord;
-    m_lppLinesLastWord = NULL;
-}
-
-INT BTextViewer::BTextLines::ValidateNewLineWord(CONST DWORDLONG dwlWordNum,CONST INT nLineH, CONST INT nMargin)
-{
-    if(!m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord)
-        return nMargin; // There is no word on the last line, nothing to do...
-
-    BTextViewer::BTextWord *pbtWord = m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord;
-
-    if(pbtWord->m_dwlWordNum != dwlWordNum)
-        return nMargin; // Different word, nothing to do...
-
-    pbtWord->m_rect.top     += nLineH;
-    pbtWord->m_rect.bottom  += nLineH;
-    pbtWord->m_rect.right   = nMargin + (pbtWord->m_rect.right - pbtWord->m_rect.left);
-    pbtWord->m_rect.left    = nMargin;
-
-    // break this word off the old line's chain
-    BTextViewer::BTextWord *pbtChainPrev = pbtWord->m_lpPrevWord;
-    BTextViewer::BTextWord *pbtChainNext = pbtWord->m_lpNextWord;
-
-    if(pbtWord->m_lpPrevWord)
-        pbtWord->m_lpPrevWord->m_lpNextWord = pbtChainNext;
-    if(pbtWord->m_lpNextWord)
-        pbtWord->m_lpNextWord->m_lpPrevWord = pbtChainPrev;
-
-    m_lppLinesLastWord[m_dwLastLine] = pbtChainNext;
-    pbtWord->m_lpPrevWord = NULL;
-    pbtWord->m_lpNextWord = NULL;
-    AddWordToLine(m_dwLastLine + 1, *pbtWord);
-    delete pbtWord;
-
-    return m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord->m_rect.right;
-}
-
-VOID BTextViewer::BTextLines::AddWordToLine(DWORD dwLine, CONST BTextViewer::BTextWord &btWord)
-{
-    DWORD dwLines   = 0;
-    DWORD i         = 0;
-
-    // Check if we are about to overflow the allocated lines
-    // If so resize...
-    if(dwLine >= m_dwLines){
-        dwLines = m_dwLines + BTEXT_LINE_INC;
-        //unsigned int nLastLine = m_dwLastLine;
-        i = 0;
-        BTextWord *pbtTemp1     = new BTextWord[dwLines];
-        BTextWord **ppbtTemp2   = new BTextWord*[dwLines];
-
-        for(i = 0; i <= m_dwLastLine; i++){
-            pbtTemp1[i] = m_lpLines[i];
-            // Now the next btWord doesn't know it has a new prev btWord
-            // Fixing...
-            if(pbtTemp1[i].m_lpNextWord)
-                pbtTemp1[i].m_lpNextWord->m_lpPrevWord = &pbtTemp1[i];
-            ppbtTemp2[i] = m_lppLinesLastWord[i];
-        }
-        for(;i < dwLines; i++){
-            ppbtTemp2[i] = &pbtTemp1[i];
-        }
-        m_dwLastLine = dwLine;
-        m_dwLines = dwLines;
-        delete [] m_lpLines;
-        delete [] m_lppLinesLastWord;
-        m_lpLines = pbtTemp1;
-        m_lppLinesLastWord = ppbtTemp2;
-    }else if(dwLine > m_dwLastLine){
-        m_dwLastLine = dwLine;
-    }
-    BTextViewer::BTextWord *pbtPrevWord = m_lppLinesLastWord[dwLine]->m_lpPrevWord;
-    *m_lppLinesLastWord[dwLine] = btWord;
-    m_lppLinesLastWord[dwLine]->m_lpNextWord = new BTextWord();
-    m_lppLinesLastWord[dwLine]->m_lpPrevWord = pbtPrevWord;
-    // Create the relationship between this btWord and the next 
-    // potential btWord...
-    m_lppLinesLastWord[dwLine]->m_lpNextWord->m_lpPrevWord = m_lppLinesLastWord[dwLine];
-    m_lppLinesLastWord[dwLine] = m_lppLinesLastWord[dwLine]->m_lpNextWord;
-}
\ No newline at end of file

Deleted: trunk/src/SwordReader_GUI/BTextViewer.h
===================================================================
--- trunk/src/SwordReader_GUI/BTextViewer.h	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/BTextViewer.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -1,668 +0,0 @@
-/******************************************************************************
-*  BTextViewer.h - HTML Renderer for rendering biblical texts on Pocket PC 
-*  devices.
-*  Author: David C Trotz Jr. 
-*  e-mail: dtrotzjr at crosswire.org
-*
-* $Id$
-*
-* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
-*	CrossWire Bible Society
-*	P. O. Box 2528
-*	Tempe, AZ  85280-2528
-*
-* This program is free software; you can redistribute it and/or modify it
-* under the terms of the GNU General Public License as published by the
-* Free Software Foundation version 2.
-*
-* This program is distributed in the hope that it will be useful, but
-* WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-* General Public License for more details.
-*
-*/
-
-#pragma once
-
-//! BTextViewer::m_lpszBuff gets re-sized in increments based upon this number.
-#define BTEXT_BUFF_INC              2000
-//! BTextViewer::m_BTLines gets re-sized based upon this number
-#define BTEXT_LINE_INC              400
-//!  Determines the margin around the border of the display. 
-//!  May be broken into Top, Bottom, Left, and Right margins in the future.
-#define BTEXT_MARGIN                4
-
-#define BTEXT_FONT_CACHE_MAX        0x7FFF
-
-
-//! Determines the default font height. 
-//! @note Future implementations may read this from a config file.
-#define BTEXT_DEFAULT_FONT_HEIGHT   -11
-//! Flags an uninitialized color state.
-//! This is actually an invalid COLOREF Color, which makes it ideal for
-//! this type of use, as it will never come up naturally.
-#define BTEXT_FONT_NOT_A_COLOR      0xFF000000
-//! Determines the default font face color.
-//! @note Future implementations may read this from a config file.
-#define BTEXT_DEFAULT_FONT_COLOR    0x00000000
-//! Determines the line spacing factor.
-//! @note Future implementations may read this from a config file.
-#define BTEXT_LINE_SPACING          1.1
-
-//! Flag indicating a space of some sort was encountered.
-//! @deprecated Future implementations will move away from this flag
-#define BTEXT_SPACE_ENCOUNTERED     0
-//! Flag indicating a new line has been encountered
-//! @deprecated Use of this flag may not be needed in future releases.
-#define BTEXT_NEWLINE_ENCOUNTERED   -1
-//! Flag indicating we have encountered an opening bracket for HTML processing.
-#define BTEXT_HTML_OPEN_BRACKET     -2
-
-//! Flag indicating a &lt;br&gt; element was encountered
-#define BTEXT_HTML_BR               0x00000001
-//! Flag used to mask against the ..._BEG counterpart of an ..._END.
-#define BTEXT_HTML_MASK             0xFFFFFFFF
-
-//!Flag indicating we encountered a &lt;b&gt; element
-#define BTEXT_HTML_B_BEG            0x00000002
-//!Flag indicating we encountered a &lt;/b&gt; element
-#define BTEXT_HTML_B_END            BTEXT_HTML_MASK ^ BTEXT_HTML_B_BEG
-
-//!Flag indicating we encountered a &lt;i&gt; element
-#define BTEXT_HTML_I_BEG            0x00000004
-//!Flag indicating we encountered a &lt;/i&gt; element
-#define BTEXT_HTML_I_END            BTEXT_HTML_MASK ^ BTEXT_HTML_I_BEG
-
-//!Flag indicating we encountered a &lt;sup&gt; element
-#define BTEXT_HTML_SUP_BEG          0x00000008
-//!Flag indicating we encountered a &lt;/sup&gt; element
-#define BTEXT_HTML_SUP_END          BTEXT_HTML_MASK ^ BTEXT_HTML_SUP_BEG
-
-//!Flag indicating we encountered a &lt;sub&gt; element
-#define BTEXT_HTML_SUB_BEG          0x00000010
-//!Flag indicating we encountered a &lt;/sub&gt; element
-#define BTEXT_HTML_SUB_END          BTEXT_HTML_MASK ^ BTEXT_HTML_SUB_BEG
-
-//!Flag indicating we encountered a &lt;small&gt; element
-#define BTEXT_HTML_SMALL_BEG        0x00000020
-//!Flag indicating we encountered a &lt;/small&gt; element
-#define BTEXT_HTML_SMALL_END        BTEXT_HTML_MASK ^ BTEXT_HTML_SMALL_BEG
-
-//!Flag indicating we encountered a &lt;font ...&gt; element
-#define BTEXT_HTML_FONT_BEG         0x00000040
-//!Flag indicating we encountered a &lt;/font&gt; element
-#define BTEXT_HTML_FONT_END         BTEXT_HTML_MASK ^ BTEXT_HTML_FONT_BEG
-
-//!Flag indicating we encountered a &lt;a ...&gt; element
-#define BTEXT_HTML_A_BEG            0x00000080
-//!Flag indicating we encountered a &lt;/a&gt; element
-#define BTEXT_HTML_A_END            BTEXT_HTML_MASK ^ BTEXT_HTML_A_BEG
-
-//!Flag indicating we encountered a &lt;p&gt; element
-#define BTEXT_HTML_P_BEG            0x00000100
-//!Flag indicating we encountered a &lt;/p&gt; element
-#define BTEXT_HTML_P_END            BTEXT_HTML_MASK ^ BTEXT_HTML_P_BEG
-
-//! Flag indicating we encountered an illegal tag format.
-#define BTEXT_HTML_ILLEGAL_TAG_FORMAT   0x80000000
-//! Flag indicating we encountered an unknown tag.
-#define BTEXT_HTML_UNKNOWN_TAG          0x40000000
-
-//! BTextViewer - A custom HTML Renderer for Biblical Texts on WinCE Platforms.
-/*!
-    BTextViewer was designed to be a replacement for the built in HTML Renderer
-    on Windows CE platforms. This replacement was decided necessary due to the
-    limitations and performance issues encountered when designing a front end
-    for The SWORD Project on the Windows CE platform.
-
-    When implementing this class I have taken every precaution I could to ensure
-    the class could be easily manipulated in the future to add support for new
-    features necessary to display biblical and supporting texts. Whether I have
-    been successful at this or not is unfounded, only time will tell.
- */
-class BTextViewer
-{
-private:
-
-    //! BTextWord - The most basic element of this text display. 
-    /*!	BTextWord represents a single (whole or partial) word. Each word 
-    			contains information to describe its placement on the screen and any
-    			display characteristics it may possess such as bold, italic, font 
-    			size, etc. In order to preserve memory and time copying text from the 
-    			main buffer BTextWord objects typically only point to the main text 
-    			buffer BTextViewer::m_lpszBuff 
-    			
-    			On rare occasions it is necessary for the word to store its own copy 
-    			of the word it represents, in these cases m_fOwner will be true and 
-    			special care is taken to manage its memory.
-    			
-    			This Class also represents a doubly linked list, care must be taken 
-    			whenever a single node is removed from the list or else you risk
-    			memory leaks or dangling pointers, both of which are a death sentence
-    			on the WinCE platform.
-    				
-     */
-    class BTextWord
-    {
-    public:
-    		//! Default Constructor
-        BTextWord();
-        //! Copy Constructor
-        BTextWord(CONST BTextViewer::BTextWord &rhs);
-        //! Destructor
-        ~BTextWord();
-        //! Assignment operator
-        BTextViewer::BTextWord &operator=(CONST BTextViewer::BTextWord &rhs);
-        //! Clears the contents of this word.
-        //! This may include deleting any memory it may own.
-        VOID Clear();
-        //! Copy the pWord object internally and manage it internally.
-        //! Tells this instance of BTextWord that it needs to make a copy of 
-        //! this word and "own" the word.
-        //! @param pWord pointer to the word being copied in.
-        //! @param dwWordLen length of the word being copied in.
-        VOID OwnWord(TCHAR *lpszWord, DWORD dwWordLen);
-        //! Points to a specific word inside a buffered string stored and 
-        //! managed outside of this class.
-        //! Thus we do not try to manage the memory, unless the m_fOwner 
-        //! flag is set.
-        TCHAR   *       m_lpszWord;
-        //! Indicates how many characters this word is in length.
-        DWORD           m_dwWordLen;
-        //! Points to a specific href inside a buffered string stored and 
-        //! managed outside of this class.
-        //! Thus we do not try to manage the memory, not even if m_fOwner is set
-        TCHAR   *       m_lpszHref;
-        //! Indicates how many characters this href is in length.
-        DWORD           m_dwHrefLen;
-        //! Indicates the on screen bounds of this word.
-        RECT            m_rect;
-        //! Flags indicating the font status of this word.
-        //! @code 
-        //! X = Reserved     H = Font Height
-        //! M = Small        B = Subscript
-        //! U = Superscript  O = Bold
-        //! I = Italic       A = Link
-        //! P = Paragraph
-        //! F = Font (not used here)
-        //! RR = Red	GG = Green BB = Blue
-        //! - = Line-break bit (not used here)
-        //! BYTE: 7[7654 3210] 6[7654 3210] 5[7654 3210] 4[7654 3210]
-        //!        [BBBB BBBB]  [GGGG GGGG]  [RRRR RRRR]  [HHHH HHHH]
-        //! BYTE: 3[7654 3210] 2[7654 3210] 1[7654 3210] 0[7654 3210]
-        //!        [XXXX XXXX]  [XXXX XXXX]  [XXXX XXXP]  [AFMB UIO-]
-        //! @endcode
-        DWORDLONG       m_dwlfFontState;
-
-				//! Indicates that this BTextWord object should manage the memory
-				//! pointed to by m_lpszWord.
-        //! There are times when this BTextWord needs to clean up the 
-        //! character allocation it points to, such as when Special
-        //! Entities are interpreted and stored separately from the main
-        //! text buffer.
-        BOOL            m_fOwner;
-        //! Points to the next word in the list.
-        BTextWord *     m_lpNextWord;
-        //! Points to the previous word in the list.
-        BTextWord *     m_lpPrevWord;
-        //! Indicates the unique number assigned to each word.
-        //! This number is helpful in keeping words together when a
-        //! html element is introduced mid-word such as 
-        //! L&lt;font size="-1"&gt;ORD&lt;/font&gt; In this case two BTextWord
-        //! objects are created and all that ties them together is this 
-        //! variable. 
-        //! @see m_dwSubWordNum.
-        DWORDLONG       m_dwlWordNum;
-        //! Indicates which piece of a word this word is (most often it will be 0)
-        DWORD           m_dwSubWordNum;
-    };
-
-    //! BTextLines - Stores all the words in an array of lines.
-    /*!	BTextLines is responsible for storing the BTextWord objects in a way that 
-    			is convenient for rendering on the display, and for x,y coordinate to 
-    			BTextWord object look-up.
-     */
-    class BTextLines
-    {
-    public:
-    		//! Default Constructor
-        BTextLines();
-        // Copy Constructor
-        BTextLines(CONST BTextViewer::BTextLines &rhs);
-        //! Destructor
-        ~BTextLines();
-        //! Assignment operator.
-        BTextViewer::BTextLines &operator=(CONST BTextViewer::BTextLines &rhs);
-				
-				//! Adds the given word to the end of the line indicated by the line number.
-				/*! If dwLine is larger than the current m_dwLastLine property, then 
-						m_dwLastLine is changed accordingly (hence it grows). Since we do 
-						not want to thrash the heap by reallocating every time m_dwLastLine
-						increments (and we expect it will often), we instead allocate in 
-						increments of BTEXT_LINE_INC.
-						@param dwLine Indicates the line number where the new btWord is being 
-						added.
-						@param btWord The BTextWord object we will copy into the BTextLines
-						object.
-				*/
-        VOID    AddWordToLine(DWORD dwLine, CONST BTextViewer::BTextWord &btWord);
-        //! Clears all lines from this instance of BTextLines. 
-        /*! BEWARE - Once this is called the object is not usable again until, 
-        		InitLines is called to re-initialize the memory for m_lpLines and 
-        		m_lppLinesLastWord
-         */	
-        VOID    ClearLines();
-        //! Initializes (or allocates) memory to store the words.
-        /*! @param nLineH indicates the physical line height in pixels. 
-        		@note Not sure how appropriate nLineH is here. Expect this to change
-        		in future releases.
-        */
-        VOID    InitLines(CONST INT nLineH);
-        //! Validates the incoming word's position on a new line.
-        /*!
-        		Checks to see if this word might be part of a word that ended on the
-        		previous line. If it is part of the previous line's word, it moves 
-        		the previous word down to the new line and prepares this word to be 
-        		inserted immediately following.
-        		@param dwWordNum indicates the word's unique number to determine if it 
-        			belongs to the word in the line above.
-        		@param nLineH indicates how far down to move the word (physically in 
-        			pixels) if it is determined that it needs to be moved.
-        		@param nMargin indicates the margin to obey when placing the word on 
-        			a new line if it is determined that it needs to be moved.
-        		@return the position in pixels that the new word can start at. If it 
-        			was determined that the word above did not need to be moved, it 
-        			simply returns nMargin as its value, if it did move down its 
-        			rightmost extent is returned instead.
-         */
-        INT     ValidateNewLineWord(CONST DWORDLONG dwlWordNum,CONST INT nLineH, CONST INT nMargin);
-        //! Indicates the total number of lines currently allocated.
-        DWORD           m_dwLines;
-        //! Indicates the last line actually being used,
-        //! hence m_dwLastLine < m_dwLines is always true!
-        DWORD           m_dwLastLine;
-        //! Indicates the physical line height in pixels. Useful for 
-        //! determining line boundaries.
-        int             m_nLineH;
-        //! Pointer to an array of BTextWords, where each index into the array 
-        //! represents a single line of text.
-        BTextWord*      m_lpLines;
-        //! Convenience pointer to the last word in each line.
-        //! @note Do not manage this memory!!! It is already managed 
-        //! as m_lpLines.
-        BTextWord**     m_lppLinesLastWord;
-    };
-
-    //! FontTagItem - Tracks font tag elements and their respected properties.
-    /*! This simple class is a basic queue for tracking font tags and the properties related to those tags. 
-     */
-    class FontTagItem{
-    public:
-        //! Default Constructor
-        FontTagItem(){ m_siAbsFontSize = BTEXT_DEFAULT_FONT_HEIGHT; m_siRelFontSize = 0; m_crFontColor = BTEXT_FONT_NOT_A_COLOR; m_lpftNext = NULL; };
-        //! Destructor
-        ~FontTagItem() { if(m_lpftNext) delete m_lpftNext; };
-
-        //! Represents the absolute font size related to this font tag.
-        //! @note not fully implemented.
-        SHORT           m_siAbsFontSize;
-        //! Represents the relative font size related to this font tag.
-        //! Examples: &lt;font size="+2"&gt; -- indicates a font size +2 
-        //! greater than the current font size.
-        SHORT           m_siRelFontSize;
-        //! Represents the fore color of the font related to this font tag.
-        COLORREF        m_crFontColor;
-        //! Points to the next font tag item (if there exists one.)
-        FontTagItem*    m_lpftNext;
-    };
-
-    //! RenderState - Keeps track of the current rendering state.
-    /*! As new tags are encountered this structure is useful for keeping
-        track of such changes so that each word is rendered with the correct 
-        formatting tags applied.
-     */
-    struct RenderState{
-        //! Indicates that we encountered a space outside of a tag element.
-        BOOL            m_space_encountered;
-        //! Indicates the bold state.
-        /*! \code
-            m_wBoldState == 0 indicates not bold; 
-            m_wBoldState >  0 indicates bold
-            \endcode
-         */
-        WORD            m_wBoldState;
-        //! Indicates the italic state. 
-        /*! \code
-            m_wItalicState == 0 indicates not italicized; 
-            m_wItalicState >  0 indicates italicized
-            \endcode
-         */
-        WORD            m_wItalicState;
-        //! Indicates the super script state.
-        /*! \code
-            m_wSuperState == 0 indicates not super scripted; 
-            m_wSuperState >  0 indicates super scripted
-            \endcode
-         */
-        WORD            m_wSuperState;
-        //! Indicates the anchor (link) state.
-        /*! \code
-            m_wAState == 0 indicates not in anchor state
-            m_wAState >  0 indicates anchor state
-            \endcode
-            @note it is assumed that anchors are not nested 
-            thus: \code -1 < m_wAState > 1 \endcode
-         */
-        WORD            m_wAState;
-        //! Indicates the sub script state.
-        /*! \code
-            m_wSubState == 0 indicates not sub scripted
-            m_wSubState >  0 indicates sub scripted
-            \endcode
-         */
-        WORD            m_wSubState;
-        //! Indicates the paragraph state.
-        /*! \code
-            m_wParagraphState == 0 indicates not in paragraph
-            m_wParagraphState > indicates in a paragraph
-            \endcode
-         */
-        WORD            m_wParagraphState;
-        //! Tracks the font tag elements that help make the current font 
-        //! state. This linked list is treated as a last in first out (LIFO)
-        //! queue.
-        FontTagItem*    m_lpftFontTagHead;
-        //! This is where new elements are pushed/popped on to the queue.
-        FontTagItem*    m_lpftFontTagTail;
-        //! Pointer to an anchor href property the current font state
-        //! may reference.
-        TCHAR*          m_lpszHref; 
-        //! The length of that anchor href property ( m_lpszHref ) string
-        DWORD           m_dwHrefLen;
-        //! Indicates the current verse we believe we are representing.
-        WORD            m_wVerseNum;
-        //! Indicates how many HTML Special entities we have encountered and 
-        //! need to be interpreted later.
-        WORD            m_wTotalSpclEnt;
-        //! Used to compose a word that may be broken up by rendering
-        //! tags introduced mid-word such as the very common
-        //! L<font size="-1">ORD</font>
-        DWORDLONG       m_dwlWordNum;
-        //! Further helps compose words broken apart by tags.
-        DWORD           m_dwSubWordNum;
-    };
-
-public:
-    // Public Methods
-    //! Default Constructor
-    BTextViewer(HINSTANCE hInstance, HWND hWndParent, RECT lRect);
-    //! Destructor
-    virtual ~BTextViewer();
-    //! Adds the given text to the window control for rendering.
-    /*! The method appends the given text string to the text currently being 
-        stored in m_lpszBuff. To save on constantly resizing m_lpszBuff at 
-        each call to this method we instead re-size at increments of 
-        BTEXT_BUFF_INC
-        @param szText the text being added to this control.
-        @param dwSize the length of the text being added.
-     */
-    VOID    AddText(TCHAR *szText, DWORD dwSize);
-    //! Scrolls the window a full height in a given direction.
-    /*! @param nDirection the direction to scroll 
-        \code
-        nDirection > 0 indicates up.
-        nDirection <= 0 indicates down.
-        \endcode
-     */
-    VOID    ScrollFullPage(INT nDirection);
-    //! Shows the window control.
-    //! Calls ShowWindow with the SW_SHOW parameter for the underlying window.
-    VOID    Show();
-    //! Hides the window control.
-    //! Calls ::ShowWindow with the SW_HIDE parameter for the underlying window.
-    VOID    Hide();
-    //! Changes the position and or size of the window.
-    //! Calls ::MoveWindow for the underlying window.
-    VOID    MoveWindow(INT x, INT y, INT w, INT h);
-    //! Clears the text from m_lpszBuff and removes the lines from m_BTLines.
-    VOID    Clear();
-private:
-    // Private Methods
-    //! Handles the WM_PAINT message for this window control. 
-    /*! This is the heart and soul of this window control. Well in theory it 
-        is, except most of the real work is done in PreRenderBuff. This method 
-        checks to see if the buffer has been pre-rendered, if not it calls 
-        PreRenderBuff. Once it is established that the buffer has been 
-        pre-rendered the method continues to actually render the text on 
-        screen, skipping any lines not expected to be showing on the screen.
-        @param hWnd handle to the window being painted
-        @param hdc  device context to do our rendering on.
-        @param ps   contains information about what to paint.
-        @note 
-            It is expected that 
-            \code hWnd == m_hWnd \endcode 
-            is always true. 
-            Given this assumption this first parameter may be removed in 
-            future releases.
-     */
-    INT     Paint(HWND hWnd, HDC hdc, PAINTSTRUCT ps);
-    //! Drags the text across the screen.
-    /*! Drags the text across the screen according to the point given and the 
-        current value of m_nDragStart.
-        @param lParam contains information about the pointer's position.
-        @note
-        \code
-        xPos = LOWORD(lParam); 
-        yPos = HIWORD(lParam);
-        \endcode
-     */
-    VOID    DragScreenToPoint(LPARAM lParam);
-    //! Set's the state of the pen. 
-    /*! The pen's state includes its current position and whether the pen is 
-        considered up or down. This method also tries to detect what the user 
-        is intending to do, such as tap a word or scroll a few lines or send the
-        window in a rolling motion.
-        @param fMouseDown   indicates the pen is in the down position.
-        @param lParam       contains information about the pointer's position.
-        @note
-        \code
-        xPos = LOWORD(lParam); 
-        yPos = HIWORD(lParam);
-        \endcode 
-     */
-    VOID    SetTapState(BOOL fMouseDown, LPARAM lParam);
-    //! Gets the word (if any) at the given point on the screen.
-    /*! Does a methodical search for the word that exists under the given point.
-        @param lParam  contains information about the position to be searched.
-        @note
-        \code
-        xPos = LOWORD(lParam); 
-        yPos = HIWORD(lParam);
-        \endcode 
-        
-        @par
-        @note Future implementations will return the word found. The current 
-        implementation only displays a MessageBox containing the word.
-     */
-    VOID    GetWordAtPoint(LPARAM lParam);
-    //! Rolls the screen until the m_nRollVelocity member has reached a value of 0.
-    /*! @note Future implementations will work a little differently to allow the 
-        cancellation of a roll by replacing the main loop in this method with 
-        sending a user defined message indicating a roll is requested which will 
-        call this method until either m_nRollVelocity is 0 at which point this 
-        method will no longer send the user defined message to itself, or the 
-        user taps the screen in the middle of a roll resetting the 
-        m_nRollVelocity data member.
-     */
-    VOID    RollTillStopped();
-    //! The actual call back function for this window.
-    /*! This only acts as a mediator between the callback function we really 
-        want and the call back the Win API is expecting.
-        @param hwnd     Handle to the window.
-        @param message  Specifies the message. 
-        @param wParam   Specifies additional message information. The contents 
-                        of this parameter depend on the value of the message 
-                        parameter. 
-        @param lParam   Specifies additional message information. The contents 
-                        of this parameter depend on the value of the message 
-                        parameter. 
-     */
-    static LRESULT CALLBACK MessageRoute(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-    //! The expected WinProc callback function.
-    /*! Handles any messages sent to this window.
-        @param hwnd     Handle to the window.
-        @param message  Specifies the message. 
-        @param wParam   Specifies additional message information. The contents 
-                        of this parameter depend on the value of the message 
-                        parameter. 
-        @param lParam   Specifies additional message information. The contents 
-                        of this parameter depend on the value of the message 
-                        parameter. 
-     */
-    LRESULT CALLBACK WndProcBText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
-    //! Sets the Font for the given device context. 
-    /*! Tries to determine if changing the font is even necessary. If not it 
-        returns immediately otherwise it proceeds to change the font based 
-        upon the dwlFontState parameter.
-        @param hdc          the device context getting the font change.
-        @param dwlFontState contains flags indicating the new state of the 
-                            font.
-        @note If called, be sure to free the last created font prior to 
-                releasing the device context otherwise a resource leak will 
-                occur. Sequential calls to this method do take care of any 
-                fonts created in prior calls. Its the last call that needs 
-                the extra attention.
-        @see BTextViewer::BTextWord::m_dwlfFontState
-     */
-    VOID    SetFont(HDC hdc, DWORDLONG dwlFontState);
-    //! Tries to detect any spaces at the current stream position.
-    /*! Spaces are then discarded (by incrementing the dwWordIndex) and their 
-        existence is recorded in the rsState.m_space_encountered parameter.
-        @param rsState      contains current rendering information. This is 
-                            where we store our 'space' encounters.
-        @param dwWordIndex  Index into the current stream m_lpszBuff indicating 
-                            where to be looking for spaces.
-        @return A BOOL value where a non-zero value indicates that spaces were 
-                encountered.
-        @note The return value is redundant information, it was the original 
-                way I dealt with acknowledging spaces. Since then I have moved 
-                onto a structure containing the overall state of the renderer, 
-                as such the return value here may change to void in future 
-                implementations.
-     */
-    BOOL    GetSpaces(RenderState& rsState, DWORD &dwWordIndex);
-    //! Determines location the next word in the stream.
-    /*! Based upon the current stream position this method will determine the 
-        extents of the word assumed to have its origin at dwWordIndex.
-        @param  rsState     the current state of the renderer.
-        @param  dwWordIndex where in m_lpszBuff to begin looking.
-        @param  dwWordEnd   the determined length of the word will land here.
-        @return An INT value indicating the character that terminated the search.
-        @note The return value was originally designed help determine what state 
-                we should be in next, but is currently unused and may end up 
-                going unused and removed in future releases.
-     */
-    INT     NextWord(RenderState& rsState,DWORD dwWordIndex, DWORD &dwWordEnd);
-    //! Determines what HTML tags are at the location in the stream.
-    /*! As HTML tags are encountered they are logged in the rsState parameter 
-        for future rendering.
-        @param rsState      the current state of the renderer
-        @param dwWordIndex  where in m_lpszBuff to begin looking. This value is
-                            also updated as the tags are being encountered and 
-                            recorded.
-        @return An INT indicating how many line breaks &lt;br&gt; were 
-                encountered during this call.
-     */
-    INT     GetHTMLTags(RenderState& rsState, DWORD &dwWordIndex);
-    //! Identifies what tag element is at the stream position.
-    /*! Once GetHTMLTags encounters a new tag it needs to know what tag it is, 
-        and that job falls to this method. This method is also the one 
-        responsible for building the FontTagItem linked list representing any 
-        &lt;font ...&gt; tags it encounters.
-        @param rsState      the current state of the renderer, and the recipient 
-                            of any changes to that state as a result of the tag 
-                            encountered. i.e An anchor tag may have an href 
-                            property attached to it, as such this state will 
-                            reflect that property upon return.
-        @param dwWordIndex  where in m_lpszBuff to begin looking
-        @param dwWordEnd    the predetermined length of the tag element being 
-                            examined.
-        @return A DWORD value indicating which tag was identified. 
-     */
-    DWORD   IndentifyTag(RenderState& rsState, DWORD dwWordIndex, DWORD dwWordEnd);
-    //! Looks for HTML special entities and translates them into their single character equivalents.
-    /*! @param dwWordIndex  where in m_lpszBuff to begin looking.
-        @param dwWordLen    where to stop translating
-        @param pbtWord      where the new translated string will be copied.
-        @note This causes the given pbtWord object to "own" its own copy of the 
-                newly translated string.
-     */
-    VOID    InterpretSpecialEntities(DWORD dwWordIndex, DWORD dwWordLen, BTextWord *pbtWord);
-    //! Pre-Renders the internal buffer stream.
-    /*! @par
-        This is the big boss!
-        @par
-        This method is responsible for interpreting how the text stream is 
-        intended to be rendered.
-        @par
-        The main body of this function is a loop. At each iteration of the loop 
-        a single word is extracted. However every word has the possibility of 
-        being preceded with spaces, and/or html tags so we try to parse these 
-        out first. Once we have determined that we are at the start of a new 
-        word we call NextWord and get the actual word. If it happens that 
-        dwWordEnd is 0 after this call we exit, this is the only exit condition 
-        from this loop. Once we have the word we then set the font according 
-        to the current rendering state and do a "fake" draw of the word to 
-        determine its bounding rectangle. Now that we have the word, its font 
-        settings, and its boundaries, we store the word for actual rendering 
-        later. The loop continues to the next word, and so on...
-        @param  hdc the current device context to base our "fake" drawing on.
-     */
-    VOID    PreRenderBuff(HDC hdc);
-
-    VOID ClearFontCache(HDC hdc);
-    
-    // Private data members
-
-    //! Indicates whether we are in a dragging state.
-    BOOL                        m_fDragging;
-    //! 
-    POINT                       m_ptLastClick;
-    //! Indicates the yPos that the current dragging motion should start from.
-    INT                         m_nDragStart;
-    /*! Like m_nDragStart except it keeps track of the true start point 
-        as opposed to the m_nDragStart which is updated upon each WM_MOUSEMOVE 
-        message sent to this window.
-     */
-    DWORD                       m_dwTrueStartPos;
-    //! The start time related to m_dwTrueStartPos
-    DWORD                       m_dwTrueStartTime;
-    //! A virtual velocity used to do the fancy rolling motion.
-    INT                         m_nRollVelocity;
-    //! Indicates where the top of the "canvas" is in relationship to the top 
-    //! of the physical screen.
-    INT                         m_nTop;
-    //! The actual text stream is stored here.
-    TCHAR*                      m_lpszBuff;
-    //! Indicates how much memory has been allocated to the text buffer pointed 
-    //! to by m_lpszBuff
-    DWORD                       m_dwBuffSize;
-    //! Indicates the end of the text stream and the actual memory used in 
-    //! m_lpszBuff
-    DWORD                       m_dwBuffEnd;
-    //! Indicates when the time when the pen down event was first registered
-    DWORD                       m_dwClickTime;
-    //! A handle to the currently selected font.
-    HFONT                       m_hCurFont;
-    //! A LOGFONT description of the current font.
-    LOGFONT                     m_lfCurFont;
-    //! Represents rendered words sorted by line.
-    BTextViewer::BTextLines     m_BTLines;
-    //! A handle to the window that this object represents.
-    HWND                        m_hWnd;
-    //! Indicates whether the text stream has been pre-rendered according to 
-    //! the current window layout.
-    BOOL                        m_fPreRendered;
-
-    HFONT                       m_hFontCache[BTEXT_FONT_CACHE_MAX];        
-};

Modified: trunk/src/SwordReader_GUI/Main.cpp
===================================================================
--- trunk/src/SwordReader_GUI/Main.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/Main.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -1,7 +1,7 @@
 #include <aygshell.h>
 #include <htmlctrl.h>
 
-#include "SwordReaderApp.h"
+#include "SRReaderApp.h"
 #include "resource.h"
 
 int WINAPI WinMain(	HINSTANCE hInstance,
@@ -9,13 +9,14 @@
 					LPTSTR    lpCmdLine,
 					int       nCmdShow)
 {
-    SwordReaderApp *app = new SwordReaderApp(hInstance);
+    SRReaderApp *app = new SRReaderApp(hInstance);
 
 	HCURSOR hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
 	if (!app->InitApp(nCmdShow)) 
 		return FALSE; // Either it failed, or it's already loaded...
 	SetCursor(hOldCursor);
-	
+	app->RefreshWindows();
+
     return app->Run();
 }
 

Modified: trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -53,10 +53,16 @@
     return FALSE;
 }
 
-HMENU SRCommandBar::GetMenu(INT nPos)
+HMENU SRCommandBar::GetSubMenu(UINT nPos)
 {
     TBBUTTON tb = {0};
     SendMessage(m_hWndCB, TB_GETBUTTON, nPos, (LPARAM)&tb);
 
     return (HMENU)SendMessage(m_hWndCB,SHCMBM_GETSUBMENU, 0, tb.idCommand);
 }
+
+
+void SRCommandBar::RedrawMenu()
+{
+    DrawMenuBar(m_hWndCB);
+}

Modified: trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.h
===================================================================
--- trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.h	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRFramework/SRCommandBar.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -17,7 +17,8 @@
         BOOL Create(SRWnd* pWndParent, UINT nBarID);
         BOOL Show();
         BOOL Hide();
-        HMENU GetMenu(INT nPos);
+        HMENU GetSubMenu(UINT nPos);
+        void RedrawMenu();
     protected:
         HWND m_hWndCB;
         SRMenu *m_menu;

Modified: trunk/src/SwordReader_GUI/SRFramework/SRMenu.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SRFramework/SRMenu.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRFramework/SRMenu.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -40,3 +40,10 @@
     m_hMenu = ::CreatePopupMenu();
     return m_hMenu != NULL;
 }
+
+BOOL SRMenu::InsertMenu(const SRMenu & menu, UINT uPosition, UINT uFlags, const WCString & wcsNewItem)
+{   
+    return ::InsertMenu(m_hMenu, uPosition, uFlags, (UINT)menu.m_hMenu, wcsNewItem.w_str());
+}
+
+

Modified: trunk/src/SwordReader_GUI/SRFramework/SRMenu.h
===================================================================
--- trunk/src/SwordReader_GUI/SRFramework/SRMenu.h	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRFramework/SRMenu.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -18,6 +18,7 @@
         BOOL CreateMenu();
         BOOL CreatePopupMenu();
         void DestroyMenu();
+        BOOL InsertMenu(const SRMenu & menu, UINT uPosition, UINT uFlags,const WCString & wcsNewItem);
         BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem,const WCString &wcsNewItem);
     };
 

Modified: trunk/src/SwordReader_GUI/SRMainFrame.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SRMainFrame.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRMainFrame.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -2,11 +2,94 @@
 
 SRMainFrame::SRMainFrame()
 {
-    m_cmdBar = new SRCommandBar();
-    m_cmdBar->Create(this,IDM_MENU);
+    m_wcsClassName = "SRMainFrame";
+    m_wcsWindowName = "SwordReader";
+    m_hInstance = SRFramework::SRApp::GetInstanceHandle();
+    
 }
 
 SRMainFrame::~SRMainFrame()
 {
+
 }
 
+BOOL SRMainFrame::Register()
+{
+    WNDCLASS wc;
+
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc = MessageRoute;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = m_hInstance;
+    wc.hIcon = NULL;
+    wc.hCursor = NULL;
+    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = m_wcsClassName.w_str();
+
+    if(RegisterClass(&wc) == 0) 
+        return FALSE;
+    return TRUE;
+}
+
+BOOL SRMainFrame::Create()
+{
+    RECT bounds = {CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT};
+    if(!Register())
+        return FALSE;
+
+    if(!SRFrame::Create(m_wcsClassName,m_wcsWindowName,WS_VISIBLE, bounds, NULL, NULL, m_hInstance))
+        return FALSE;
+
+    return TRUE;
+}
+
+BOOL SRMainFrame::Init()
+{
+    RECT view_rect;
+    GetClientRect(m_hWnd, &view_rect);
+
+    CreateCommandBar();
+
+    view_rect.bottom -= m_cmdBar->Height();
+
+    m_viewText = new SRTextView();
+    if(!m_viewText->Create(this, view_rect))
+        return FALSE;
+    m_viewText->Show();
+    WCString test_str = "This is a <b>test</b>. It worked?";
+    m_viewText->AddText(test_str.w_str(),test_str.length());
+    return TRUE;
+}
+
+
+BOOL SRMainFrame::CreateCommandBar()
+{
+    m_cmdBar = new SRCommandBar();
+    if(!m_cmdBar->Create(this, IDM_MENU))
+        return FALSE;
+    m_menuMain = new SRMenu(m_cmdBar->GetSubMenu(5));
+
+    // Create the translations menu
+    m_menuTrans = new SRMenu();
+    if(!m_menuTrans->CreatePopupMenu())
+        return FALSE;
+    if(!m_menuMain->InsertMenu(*m_menuTrans,0, MF_BYPOSITION | MF_POPUP | MF_STRING, "Translations"))
+        return FALSE;
+    // Create the options menu
+    m_menuOpts = new SRMenu();
+    if(!m_menuOpts->CreatePopupMenu())
+        return FALSE;
+    if(!m_menuMain->InsertMenu(*m_menuOpts,0, MF_BYPOSITION | MF_POPUP | MF_STRING, "Options"))
+        return FALSE;
+
+    m_cmdBar->RedrawMenu();
+    m_cmdBar->Show();
+
+    return TRUE;
+}
+BOOL SRMainFrame::UpdateWindow()
+{
+    return m_viewText->UpdateWindow();
+}

Modified: trunk/src/SwordReader_GUI/SRMainFrame.h
===================================================================
--- trunk/src/SwordReader_GUI/SRMainFrame.h	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SRMainFrame.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -3,6 +3,8 @@
 #include "SRFramework/SRFrame.h"
 #include "SRFramework/SRCommandBar.h"
 #include "SRFramework/SRCommandBar.h"
+#include "SRFramework/SRMenu.h"
+#include "SRTextView.h"
 
 // The one and only command bar.
 #define SR_COMMAND_BAR_ID 0x0001
@@ -14,6 +16,15 @@
 public:
     SRMainFrame();
     virtual ~SRMainFrame();
+    virtual BOOL Register();
+    BOOL Init();
+    BOOL Create();
+    BOOL UpdateWindow();
+    BOOL CreateCommandBar();
 private:
     SRCommandBar *m_cmdBar;
+    SRTextView   *m_viewText;
+    SRMenu       *m_menuMain;
+    SRMenu       *m_menuTrans;
+    SRMenu       *m_menuOpts;
 };

Added: trunk/src/SwordReader_GUI/SRReaderApp.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SRReaderApp.cpp	                        (rev 0)
+++ trunk/src/SwordReader_GUI/SRReaderApp.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -0,0 +1,70 @@
+#include "SRReaderApp.h"
+#include "SwordReaderResource.h"
+
+#include <swordce.h>
+
+
+SRReaderApp::SRReaderApp(HINSTANCE hInstance)
+: SRFramework::SRApp(hInstance)
+, m_confOptions(NULL)
+, m_pMainFrame(NULL)
+{
+    m_hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BIBLEREADER);
+}
+
+SRReaderApp::~SRReaderApp()
+{
+}
+
+WPARAM SRReaderApp::Run()
+{
+	MSG msg;
+	bool ignoreMsgs = false;
+	DWORD ignoreTill = GetTickCount();
+
+    // Main message loop:
+	while (GetMessage(&msg, NULL, 0, 0)) 
+	{
+		if(msg.message == WM_TXT_START){ 
+			ignoreMsgs = true;
+		}else if(msg.message == WM_TXT_END){
+			ignoreMsgs = false;
+			ignoreTill = msg.time;
+		}
+		// If we have a button or key event, and we are in the ignore message 
+		// window of time we ignore this message
+		if((msg.message == WM_LBUTTONDOWN || msg.message == WM_KEYDOWN) && (ignoreMsgs || msg.time < ignoreTill))
+			continue;
+
+		if (!m_hAccelTable || !TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)) 
+		{
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+		}
+	}
+	return msg.wParam;
+}
+
+BOOL SRReaderApp::InitApp(int nCmdShow)
+{
+    // Create a general options file for storing options 
+	// and navigaiton history
+	const char *cwd = getWorkingDirectory();
+	char confFName[MAX_PATH];
+	_snprintf(confFName, MAX_PATH, "%s\\options.conf", cwd);
+
+	m_confOptions = new SWConfig(confFName);
+	m_confOptions->Load();
+
+    m_pMainFrame = new SRMainFrame();
+    m_pMainFrame->Create();
+    m_pMainFrame->Init();
+
+
+	return TRUE;
+}
+
+BOOL SRReaderApp::RefreshWindows()
+{
+    return m_pMainFrame->UpdateWindow();
+}
\ No newline at end of file

Added: trunk/src/SwordReader_GUI/SRReaderApp.h
===================================================================
--- trunk/src/SwordReader_GUI/SRReaderApp.h	                        (rev 0)
+++ trunk/src/SwordReader_GUI/SRReaderApp.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -0,0 +1,23 @@
+#pragma once
+#include <swconfig.h>
+#include "SimpleNavigator.h"
+#include "SRFramework/SRApp.h"
+#include "SRMainFrame.h"
+//#include "ApplicationInterface.h"
+
+//#include "swordce.h"
+using namespace SRFramework;
+
+class SRReaderApp : SRApp
+{
+public:
+    SRReaderApp(HINSTANCE hInstance);
+    virtual ~SRReaderApp();
+    BOOL InitApp(int nCmdShow);
+    WPARAM Run();
+    BOOL RefreshWindows();
+private:
+        
+    SWConfig            *m_confOptions ;
+    SRMainFrame         *m_pMainFrame;
+};

Added: trunk/src/SwordReader_GUI/SRTextView.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SRTextView.cpp	                        (rev 0)
+++ trunk/src/SwordReader_GUI/SRTextView.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -0,0 +1,1199 @@
+/******************************************************************************
+ *  SRTextView.cpp - HTML Renderer for rendering biblical texts on Pocket PC 
+ *  devices.
+ *  Author: David C Trotz Jr. 
+ *  e-mail: dtrotzjr at crosswire.org
+ *
+ * $Id$
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ *	CrossWire Bible Society
+ *	P. O. Box 2528
+ *	Tempe, AZ  85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "SRTextView.h"
+#include "SRFramework/SRApp.h"
+using namespace SRFramework;
+
+
+VOID LOGTAG(const char *tag)
+{
+#if 0
+    FILE *fp = fopen("\\Storage Card\\tags.txt", "a");
+    fprintf(fp, "%s\n", tag);
+    fclose(fp);
+#endif
+}
+
+SRTextView::SRTextView()
+: m_fDragging(FALSE)
+, m_nTop(0)
+, m_nDragStart(0)
+, m_dwBuffSize(BTEXT_BUFF_INC)
+, m_dwBuffEnd(0)
+, m_fPreRendered(FALSE)
+, m_nRollVelocity(FALSE)
+, m_dwTrueStartPos(0)
+, m_dwTrueStartTime(0)
+, m_hCurFont(NULL)
+{
+    m_wcsClassName = "SRTextView";
+    m_wcsWindowName = "SwordReader";
+    m_hInstance = SRFramework::SRApp::GetInstanceHandle();
+
+    m_ptLastClick.x = 0; m_ptLastClick.y = 0;
+
+    // Init the current font 
+    HFONT hSystemVariableFont = (HFONT ) GetStockObject(SYSTEM_FONT);
+    GetObject(hSystemVariableFont, sizeof(LOGFONT), &m_lfCurFont);
+    m_lfCurFont.lfHeight = -11;
+    m_lfCurFont.lfQuality = CLEARTYPE_QUALITY;
+    lstrcpy(m_lfCurFont.lfFaceName, _T("Veranda"));
+
+    m_lpszBuff = new TCHAR[m_dwBuffSize];
+
+    for(DWORD i = 0; i < BTEXT_FONT_CACHE_MAX; i++)
+        m_hFontCache[i] = 0;
+}
+
+SRTextView::~SRTextView()
+{
+    if(m_lpszBuff)
+        delete [] m_lpszBuff;
+
+    DestroyWindow(m_hWnd);
+}
+
+BOOL SRTextView::Create(SRWnd *pParentWnd, RECT bounds)
+{
+    if(!Register())
+        return FALSE;
+
+    if(!SRWnd::Create(m_wcsClassName,m_wcsWindowName,WS_CHILD | WS_VISIBLE, bounds, pParentWnd, NULL, m_hInstance))
+        return FALSE;
+
+    return TRUE;
+}
+
+BOOL SRTextView::Register()
+{
+    // Register window class...
+    WNDCLASS    wc;
+    wc.style            = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
+    wc.lpfnWndProc      = (WNDPROC) MessageRoute;
+    wc.cbClsExtra       = 0;
+    wc.cbWndExtra       = 0;
+    wc.hInstance        = m_hInstance;
+    wc.hIcon            = NULL;
+    wc.hCursor          = 0;
+    wc.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH);
+    wc.lpszMenuName     = 0;
+    wc.lpszClassName    = m_wcsClassName.w_str();
+
+    if(RegisterClass(&wc) == 0) 
+        return FALSE;
+    
+    return TRUE;
+}
+
+VOID SRTextView::Show()
+{
+    ShowWindow(m_hWnd, SW_SHOW);
+    // FOR COMPARATIVE PERFORMANCE TESTING...
+    // REMOVE ONCE INTEGRATED
+    m_fPreRendered = FALSE;
+    UpdateWindow();
+}
+
+VOID SRTextView::Hide()
+{
+    ShowWindow(m_hWnd, SW_HIDE);
+}
+
+BOOL SRTextView::OnLButtonDown(WORD fwKeys, INT xPos, INT yPos)
+{
+    this->SetTapState(TRUE, xPos, yPos);
+    return TRUE;
+}
+
+BOOL SRTextView::OnLButtonUp(WORD fwKeys, INT xPos, INT yPos)
+{
+    this->SetTapState(FALSE, xPos, yPos);
+    return TRUE;
+}
+
+VOID SRTextView::MoveWindow(INT x, INT y, INT w, INT h)
+{
+    ::MoveWindow(m_hWnd, x, y, w, h, FALSE);
+}
+
+BOOL SRTextView::OnMouseMove(WORD fwKeys, INT xPos, INT yPos)
+{
+    this->DragScreenToPoint(yPos);
+    return TRUE;
+}
+
+INT SRTextView::GetHTMLTags(RenderState& rsState, DWORD &dwWordIndex)
+{
+    BOOL    fDone               = FALSE;
+    DWORD   dwBegin;
+    DWORD   dwEnd;
+    DWORD   dwIdentifyResult;
+    INT     nLineBreaks         = 0;
+
+    while(!fDone){
+        GetSpaces(rsState, dwWordIndex);
+        dwBegin = dwWordIndex + 1;
+        if(m_lpszBuff[dwWordIndex] != 0 && m_lpszBuff[dwWordIndex] == '<'){
+            while(m_lpszBuff[dwWordIndex] != 0 && m_lpszBuff[dwWordIndex] != '>')
+                dwWordIndex++;
+            dwEnd = dwWordIndex - dwBegin;
+            dwIdentifyResult = IndentifyTag(rsState, dwBegin, dwEnd);
+            dwWordIndex++;
+            switch(dwIdentifyResult){
+                case BTEXT_HTML_B_BEG:
+                    rsState.m_wBoldState++;
+                    break;
+                case BTEXT_HTML_B_END:
+                    if(rsState.m_wBoldState)
+                        rsState.m_wBoldState--;
+                    break;
+                case BTEXT_HTML_BR:
+                    nLineBreaks++;
+                    break;
+                case BTEXT_HTML_I_BEG:
+                    rsState.m_wItalicState++;
+                    break;
+                case BTEXT_HTML_I_END:
+                    if(rsState.m_wItalicState)
+                        rsState.m_wItalicState--;
+                    break;
+                case BTEXT_HTML_A_BEG:
+                    rsState.m_wAState++;
+                    rsState.m_dwlWordNum++;
+                    rsState.m_dwSubWordNum = 0;
+                    break;
+                case BTEXT_HTML_A_END:
+                    if(rsState.m_wAState)
+                        rsState.m_wAState--;
+                    rsState.m_dwlWordNum++;
+                    rsState.m_dwSubWordNum = 0;
+                    break;
+                case BTEXT_HTML_SUB_BEG:
+                    rsState.m_wSubState++;
+                    break;
+                case BTEXT_HTML_SUB_END:
+                    if(rsState.m_wSubState)
+                        rsState.m_wSubState--;
+                    break;
+                case BTEXT_HTML_SUP_BEG:
+                    rsState.m_wSuperState++;
+                    break;
+                case BTEXT_HTML_SUP_END:
+                    if(rsState.m_wSuperState)
+                        rsState.m_wSuperState--;
+                    break;
+                case BTEXT_HTML_P_BEG:
+                    rsState.m_wParagraphState++;
+                    nLineBreaks++;
+                    break;
+                case BTEXT_HTML_P_END:
+                    if(rsState.m_wParagraphState)
+                        rsState.m_wParagraphState--;
+                    nLineBreaks++;
+                    break;
+            }
+        }else
+            fDone = TRUE;
+    }
+    return nLineBreaks;
+}
+
+DWORD SRTextView::IndentifyTag(RenderState& rsState,DWORD dwWordIndex,DWORD dwWordEnd)
+{
+    DWORD dwMask      = 0x00000000;
+    DWORD dwResult    = 0x00000000;
+    DWORD dwLen       = 0;
+    DWORD dwOrigIndex = dwWordIndex;
+    DWORD dwSubIndex  = 0;
+
+    if(!dwWordEnd)
+        return BTEXT_HTML_ILLEGAL_TAG_FORMAT; // There is nothing to do here.
+
+    if((dwWordIndex - dwOrigIndex) >=  dwWordEnd)
+        return BTEXT_HTML_ILLEGAL_TAG_FORMAT;
+
+    if(m_lpszBuff[dwWordIndex] == '/'){
+        dwMask = 0xFFFFFFFF;
+        dwWordIndex++;
+    }
+
+    if((dwWordIndex - dwOrigIndex) >=  dwWordEnd)
+        return BTEXT_HTML_ILLEGAL_TAG_FORMAT;
+    // Get the token
+    while((dwWordIndex  - dwOrigIndex) + dwLen <  dwWordEnd && m_lpszBuff[dwWordIndex + dwLen] != ' '){
+        dwLen++;
+    }
+
+    // Determine the token
+    switch(dwLen){
+        case 0:
+            dwResult = BTEXT_HTML_ILLEGAL_TAG_FORMAT;
+            break;
+        case 1:
+            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"a", 1) == 0){
+                dwSubIndex = dwWordIndex + 1;
+                while(m_lpszBuff[dwSubIndex] == ' ')
+                    dwSubIndex++;
+                if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"name=\"", 6) == 0){
+                    dwSubIndex += 6;
+                    rsState.m_wVerseNum = (short)_wtoi(&m_lpszBuff[dwSubIndex]);
+                }else if(dwMask == 0){ // This is not an '/a'
+                    while(m_lpszBuff[dwSubIndex] == ' ')
+                        dwSubIndex++;
+                    if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"href=\"", 6) == 0){
+                        dwSubIndex += 6;
+                        rsState.m_lpszHref = &m_lpszBuff[dwSubIndex];
+                        rsState.m_dwHrefLen = 0;
+                        while(m_lpszBuff[dwSubIndex++] != '\"')
+                            rsState.m_dwHrefLen++;
+                    }
+                    dwResult = dwMask ^ BTEXT_HTML_A_BEG;
+                }else
+                    dwResult = dwMask ^ BTEXT_HTML_A_BEG;
+
+            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"b", 1) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_B_BEG;
+            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"i", 1) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_I_BEG;
+            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"p", 1) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_P_BEG;
+            }
+            break;
+        case 2:
+            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"br", 2) == 0){
+                dwResult = BTEXT_HTML_BR;		
+            }
+            break;
+        case 3:
+            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"sup", 3) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_SUP_BEG;	
+            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"sub", 3) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_SUB_BEG;
+            }else if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"br/", 3) == 0){
+                dwResult = BTEXT_HTML_BR;		
+            }
+            break;
+        case 4:
+            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"font", 4) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_FONT_BEG;
+                if(!dwMask){
+                    // Found a <font... element
+                    if(!rsState.m_lpftFontTagTail){
+                        rsState.m_lpftFontTagHead = new SRFontTagItem();
+                        rsState.m_lpftFontTagTail = rsState.m_lpftFontTagHead;
+                    }else{
+                        rsState.m_lpftFontTagTail->m_lpftNext = new SRFontTagItem();
+                        rsState.m_lpftFontTagTail = rsState.m_lpftFontTagTail->m_lpftNext;
+                    }
+                    dwSubIndex += dwWordIndex + 4;
+                    while(m_lpszBuff[dwSubIndex] != '>'){
+                        while(m_lpszBuff[dwSubIndex] == ' ')
+                            dwSubIndex++;
+                        if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"size=\"", 6) == 0){
+                            dwSubIndex += 6;
+                            rsState.m_lpftFontTagTail->m_siRelFontSize = (short)_wtoi(&m_lpszBuff[dwSubIndex]);
+                            while(m_lpszBuff[dwSubIndex] != '\"')
+                                dwSubIndex++;
+                            dwSubIndex++;
+                        }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"color=\"", 7) == 0){
+                            dwSubIndex += 7;
+                            if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"red\"", 4) == 0){
+                                dwSubIndex += 4;
+                                rsState.m_lpftFontTagTail->m_crFontColor = 0x000000FF;
+                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"green\"", 6) == 0){
+                                dwSubIndex += 6;
+                                rsState.m_lpftFontTagTail->m_crFontColor = 0x0000FF00;
+                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"blue\"", 5) == 0){
+                                dwSubIndex += 5;
+                                rsState.m_lpftFontTagTail->m_crFontColor = 0x00FF0000;
+                            }else if(wcsnicmp(&m_lpszBuff[dwSubIndex], L"black\"", 6) == 0){
+                                dwSubIndex += 6;
+                                rsState.m_lpftFontTagTail->m_crFontColor = 0x00000000;
+                            }
+                        }
+                    }
+                }else{ 
+                    // Its a </font pop the last item off the linked list
+                    // this has potential to be memory leak central...
+                    if(rsState.m_lpftFontTagTail){
+                        if(rsState.m_lpftFontTagHead == rsState.m_lpftFontTagTail){
+                            delete rsState.m_lpftFontTagHead;
+                            rsState.m_lpftFontTagHead = NULL;
+                            rsState.m_lpftFontTagTail = NULL;
+                        }else{
+                            SRFontTagItem *next = rsState.m_lpftFontTagHead;
+                            SRFontTagItem *prev = next;
+
+                            while(next != rsState.m_lpftFontTagTail){
+                                prev = next;
+                                next = prev->m_lpftNext;
+                            }
+                            delete next;
+                            rsState.m_lpftFontTagTail = prev;
+                        }
+                    }
+                }
+            }
+            break;
+        case 5:
+            if(wcsnicmp(&m_lpszBuff[dwWordIndex], L"small", 5) == 0){
+                dwResult = dwMask ^ BTEXT_HTML_SMALL_BEG;
+            }
+            break;
+        default:
+            dwResult = 0;
+    }
+
+    return dwResult;
+}
+
+
+INT SRTextView::NextWord(RenderState& rsState,DWORD dwWordIndex, DWORD &dwWordEnd)
+{
+    dwWordEnd = 0;
+    // Special Entities are: 
+    //      &gt; &lt; &amp; 
+    //      and others (later)
+    rsState.m_wTotalSpclEnt = 0;
+
+    while(m_lpszBuff[dwWordIndex + dwWordEnd] != 0 && m_lpszBuff[dwWordIndex + dwWordEnd] != ' ' && m_lpszBuff[dwWordIndex + dwWordEnd] != '\n' && m_lpszBuff[dwWordIndex + dwWordEnd] != '<'){
+        if(m_lpszBuff[dwWordIndex + dwWordEnd] == '&'){
+            dwWordEnd++;
+            while(m_lpszBuff[dwWordIndex + dwWordEnd] != ';'){
+                dwWordEnd++;
+                rsState.m_wTotalSpclEnt++;
+            }
+        }
+        dwWordEnd++;
+    }
+    if(m_lpszBuff[dwWordIndex + dwWordEnd] == '\n')
+        return BTEXT_NEWLINE_ENCOUNTERED;
+    else if(m_lpszBuff[dwWordIndex + dwWordEnd] == '<')
+        return BTEXT_HTML_OPEN_BRACKET;
+
+    return BTEXT_SPACE_ENCOUNTERED;
+}
+VOID SRTextView::Clear()
+{
+    m_BTLines.ClearLines();
+    m_BTLines.InitLines(0);
+    if(m_lpszBuff)
+        delete [] m_lpszBuff;
+    m_lpszBuff = NULL;
+    m_dwBuffEnd = 0;
+    m_dwBuffSize = 0;
+    m_nTop = 0;
+    m_fPreRendered = FALSE;
+}
+VOID SRTextView::PreRenderBuff(HDC hdc)
+{
+    SRTextWord   thisWord;
+    RenderState rsState;
+    memset(&rsState, 0, sizeof(rsState));
+    RECT        rectDims;
+    INT         nLineX      = BTEXT_MARGIN;
+    INT         nLineY      = BTEXT_MARGIN;
+    DWORD       dwLineNum   = 0;
+    rectDims.top            = 0; 
+    rectDims.left           = 0; 
+    rectDims.right          = 0; 
+    rectDims.bottom         = 0;
+    INT         nLineH      = (INT)(BTEXT_LINE_SPACING*(FLOAT)DrawText(hdc, L" ", 1, &rectDims, DT_CALCRECT | DT_LEFT | DT_BOTTOM | DT_SINGLELINE));
+    DWORD       dwWordIndex = 0;
+    DWORD       dwWordEnd   = 0;
+    INT         nSpaceWidth = rectDims.right - rectDims.left;
+    INT         nScreenWidth= GetSystemMetrics(SM_CXSCREEN) - BTEXT_MARGIN;
+    DWORD       dwResult    = 0;
+    INT         nAddLines   = 0;
+    DWORDLONG   dwlFontState= 0;
+    DWORDLONG   dwlFontColor;
+    DWORDLONG   dwlFontHeight;
+
+    if(m_dwBuffEnd == 0)
+        return;
+
+    m_BTLines.ClearLines();
+    m_BTLines.InitLines(nLineH);
+
+    while(TRUE){
+        thisWord.Clear();
+        rsState.m_space_encountered = FALSE;
+
+        GetSpaces(rsState, dwWordIndex);
+        nAddLines = GetHTMLTags(rsState, dwWordIndex);
+        if(nAddLines){
+            dwLineNum += nAddLines;
+            nLineX = BTEXT_MARGIN;
+            nLineY += nAddLines * nLineH;
+            rsState.m_space_encountered = FALSE;
+        }
+        GetSpaces(rsState, dwWordIndex);
+        if(rsState.m_space_encountered){
+            nLineX += nSpaceWidth;
+            rsState.m_space_encountered = FALSE;
+            rsState.m_dwlWordNum++;
+            rsState.m_dwSubWordNum = 0;
+        }else
+            rsState.m_dwSubWordNum++;
+
+        dwResult = NextWord(rsState, dwWordIndex, dwWordEnd);
+        if(dwWordEnd == 0){
+            break;
+        }
+        rectDims.left = nLineX;
+
+        // Font...
+        SRFontTagItem *tag = rsState.m_lpftFontTagHead;
+        dwlFontColor = BTEXT_DEFAULT_FONT_COLOR;
+        dwlFontHeight = abs(BTEXT_DEFAULT_FONT_HEIGHT);
+        while(tag){
+            if(tag->m_crFontColor != BTEXT_FONT_NOT_A_COLOR)
+                dwlFontColor = tag->m_crFontColor;
+            dwlFontHeight += tag->m_siRelFontSize;
+            tag = tag->m_lpftNext;
+        }
+        if(rsState.m_wSubState || rsState.m_wSuperState)
+            dwlFontHeight -= 3;
+
+        dwlFontState = 
+            ((DWORDLONG)(dwlFontColor  << 40) & 0xFFFFFF0000000000)	| 
+            ((DWORDLONG)(dwlFontHeight << 32) & 0x000000FF00000000)	|
+            (rsState.m_wAState > 0	    ? BTEXT_HTML_A_BEG : 0)	|
+            (rsState.m_wBoldState > 0   ? BTEXT_HTML_B_BEG : 0)	|
+            (rsState.m_wItalicState > 0 ? BTEXT_HTML_I_BEG : 0);
+        SetFont(hdc, dwlFontState);
+
+        rectDims.top = nLineY;
+        // Set the properties for this word.
+        thisWord.m_rect             = rectDims;
+        thisWord.m_dwlfFontState    = dwlFontState;
+        thisWord.m_lpszHref         = rsState.m_lpszHref;
+        thisWord.m_dwHrefLen        = rsState.m_dwHrefLen;
+        thisWord.m_dwlWordNum       = rsState.m_dwlWordNum;
+        thisWord.m_dwSubWordNum     = rsState.m_dwSubWordNum;
+        // Determine if we encountered any special entities...
+        if(rsState.m_wTotalSpclEnt > 0){
+            InterpretSpecialEntities(dwWordIndex, dwWordEnd, &thisWord);
+        }else{
+            thisWord.m_fOwner = FALSE;
+            thisWord.m_lpszWord = &m_lpszBuff[dwWordIndex];
+            thisWord.m_dwWordLen = dwWordEnd;
+        }
+        // Calc the text rect
+        DrawText(hdc, thisWord.m_lpszWord, thisWord.m_dwWordLen, &thisWord.m_rect, 
+            DT_CALCRECT | DT_LEFT | DT_BOTTOM | DT_SINGLELINE);
+
+        if(rsState.m_wSuperState)
+            thisWord.m_rect.top -= 1; // TODO: Determine the '1' value based upon the font size
+        else if(rsState.m_wSubState)
+            thisWord.m_rect.top = 2*thisWord.m_rect.top + nLineH - thisWord.m_rect.bottom + 1; // TODO: Same as above...
+        else
+            thisWord.m_rect.top = 2*thisWord.m_rect.top + nLineH - thisWord.m_rect.bottom; // Baseline justify
+
+        if(thisWord.m_rect.right > (nScreenWidth - BTEXT_MARGIN)){
+            // Place on next line. But...
+            // We may need to move the prefix of this word down, thus we need to adjust the left
+            // edge of this word to make room.
+            int adjustedMargin = BTEXT_MARGIN;
+            if(thisWord.m_dwSubWordNum > 0)
+                adjustedMargin = m_BTLines.ValidateNewLineWord(thisWord.m_dwlWordNum,nLineH, BTEXT_MARGIN);
+
+            dwLineNum++;
+            thisWord.m_rect.right = thisWord.m_rect.right - thisWord.m_rect.left + adjustedMargin;
+            thisWord.m_rect.left = adjustedMargin;
+            thisWord.m_rect.top += nLineH;
+            thisWord.m_rect.bottom += nLineH;
+
+            nLineY += nLineH;
+        }
+
+        // Store the line to be rendered later.
+        m_BTLines.AddWordToLine(dwLineNum, thisWord);
+
+        // Prep for next iteration
+        if(rsState.m_space_encountered)
+            nLineX = thisWord.m_rect.right + nSpaceWidth;
+        else
+            nLineX = thisWord.m_rect.right;
+
+        //curWord++;
+        dwWordIndex += dwWordEnd;
+    }
+    if(rsState.m_lpftFontTagHead) // Properly formatted text would never need this, but that cannot be assumed.
+        delete rsState.m_lpftFontTagHead; // Do not delete Tail it is a convenience pointer...
+
+    m_fPreRendered = TRUE;
+}
+
+// I wanted to use the same font setter for both prerendering and rendering
+// so I wrote this method. The first if statement will try to determine if
+// we can safely skip this call since it is a rather expensive call
+// after several thousand words are pre-rendered and rendered. But,
+// If the text is already pre-rendered and we are calling this during
+// the actual rendering stage we are sure we want to make this call already
+// and thus the !m_bnRendering statement ensures we will change the font - otherwise
+// certain lines get the wrong fonts applied to them.
+VOID SRTextView::SetFont(HDC hdc, DWORDLONG dwlFontState)
+{
+    INT     lfWeight    = dwlFontState & BTEXT_HTML_B_BEG ? FW_BOLD : FW_NORMAL;
+    UCHAR   lfItalic    = (char)((dwlFontState & BTEXT_HTML_I_BEG) > 0 ? 1 : 0);
+    UCHAR   lfUnderline = (char)((dwlFontState & BTEXT_HTML_A_BEG) > 0 ? 1 : 0); 
+    INT     lfHeight    = -1*((int)(0x000000FF & ((dwlFontState & 0x000000FF00000000) >> 32)));
+    HGDIOBJ oldFont     = 0;
+    // Compute the font cache index...
+    DWORD   dwFontCacheIndex = (DWORD) (0x000000FF & ((dwlFontState & (BTEXT_HTML_B_BEG | BTEXT_HTML_I_BEG | BTEXT_HTML_A_BEG)) | ((dwlFontState & 0x000000FF00000000) >> 24)) );
+    
+    if(!m_fPreRendered && 
+        m_lfCurFont.lfWeight    == lfWeight && 
+        m_lfCurFont.lfItalic    == lfItalic && 
+        m_lfCurFont.lfHeight    == lfHeight &&
+        m_lfCurFont.lfUnderline == lfUnderline)
+        return;
+
+    m_lfCurFont.lfWeight    = lfWeight;
+    m_lfCurFont.lfItalic    = lfItalic;
+    m_lfCurFont.lfHeight    = lfHeight;
+    m_lfCurFont.lfUnderline = lfUnderline;
+    
+    if(!m_hFontCache[dwFontCacheIndex]){
+        m_hFontCache[dwFontCacheIndex] = CreateFontIndirect(&m_lfCurFont);
+    }
+    SelectObject(hdc, m_hFontCache[dwFontCacheIndex]);
+    /*
+    m_hCurFont = CreateFontIndirect(&m_lfCurFont);
+    oldFont = SelectObject(hdc, m_hCurFont);
+    if(oldFont)
+        DeleteObject(oldFont);
+    */
+}
+
+BOOL SRTextView::GetSpaces(RenderState& rsState, DWORD &dwWordIndex){
+    DWORD i = 0;
+
+    while(m_lpszBuff[dwWordIndex] != '\0' && (m_lpszBuff[dwWordIndex] == ' ' || (m_lpszBuff[dwWordIndex] == '&' && wcsnicmp(&m_lpszBuff[dwWordIndex], L"&nbsp;", 6) == 0)) ){
+        dwWordIndex += m_lpszBuff[dwWordIndex] == '&' ? 6 : 1; // Did we find a &nbsp; then we need to increment that much.
+        i++;
+
+    }
+
+    if(i) 
+        rsState.m_space_encountered = TRUE;
+    return i > 0;
+}
+
+VOID SRTextView::InterpretSpecialEntities(DWORD dwWordIndex, DWORD dwWordLen, SRTextWord *pbtWord)
+{
+    DWORD dwSubIndex    = 0;
+    DWORD dwBufIndex    = 0;
+    TCHAR szBuf[256]    = {0};
+
+    while(dwSubIndex < dwWordLen){
+        if(m_lpszBuff[dwWordIndex + dwSubIndex] == '&'){
+            dwSubIndex++;
+            if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"lt;",3) == 0){
+                szBuf[dwBufIndex++] = '<';
+                dwSubIndex += 3;
+            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"gt;",3) == 0){
+                szBuf[dwBufIndex++] = '>';
+                dwSubIndex += 3;
+            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"amp;",4) == 0){
+                szBuf[dwBufIndex++] = '&';
+                dwSubIndex += 4;
+            }else if(wcsncmp(&m_lpszBuff[dwWordIndex + dwSubIndex], L"nbsp;",5) == 0){
+                szBuf[dwBufIndex++] = ' ';
+                dwSubIndex += 5;
+            }else{
+                // I have no idea what this is, simply display it...
+                szBuf[dwBufIndex++] = '&';
+                dwSubIndex++;
+            }
+        }
+        else
+            szBuf[dwBufIndex++] = m_lpszBuff[dwWordIndex + dwSubIndex++];
+    }
+
+    pbtWord->OwnWord(szBuf, dwBufIndex);
+}
+
+BOOL SRTextView::OnPaint()
+{
+    PAINTSTRUCT ps;
+    HDC hdc = BeginPaint(m_hWnd, &ps);
+    COLORREF    crColor     = 0x00000000;
+    COLORREF    crOldColor  = SetTextColor(hdc, crColor); 
+    INT         nSavedDC    = SaveDC(hdc);
+    RECT        rectDims;
+    rectDims.top            = 0; 
+    rectDims.left           = 0; 
+    rectDims.right          = 0; 
+    rectDims.bottom         = 0;
+
+    INT nOldBkMode = SetBkMode(hdc, TRANSPARENT);
+
+    // *TODO* The next line should not be needed, but for some strange reason its not 
+    // erasing the background. I need to look into this more.
+    FillRect(hdc, &ps.rcPaint,(HBRUSH)GetStockObject(WHITE_BRUSH));
+    
+    if(!m_fPreRendered){
+        PreRenderBuff(hdc);
+    }
+
+    for(unsigned int line = 0; line <= m_BTLines.m_dwLastLine; line++){
+        SRTextWord *pTWord = &m_BTLines.m_lpLines[line];
+        if((pTWord->m_rect.top + m_BTLines.m_nLineH + m_nTop) <= ps.rcPaint.top)
+            continue; // this line is above the region we are interested in painting
+        else if(pTWord->m_rect.top + m_nTop > ps.rcPaint.bottom)
+            break; // We are done the rest of the lines are below the region we care about.
+        while(pTWord->m_lpszWord){
+            if(!pTWord->m_lpPrevWord || pTWord->m_dwlfFontState != pTWord->m_lpPrevWord->m_dwlfFontState){
+                if(pTWord->m_dwlfFontState & BTEXT_HTML_A_BEG){ // links get priority coloring
+                    crColor = COLORREF(0x00FF0000);
+                }else{
+                    crColor = COLORREF(((pTWord->m_dwlfFontState >> 40) & 0x00FFFFFF));
+                }
+                SetTextColor(hdc, crColor);
+                SetFont(hdc, pTWord->m_dwlfFontState);
+            }
+
+            ExtTextOut(hdc,pTWord->m_rect.left, pTWord->m_rect.top + m_nTop, NULL, NULL, pTWord->m_lpszWord, pTWord->m_dwWordLen, NULL);
+            pTWord = pTWord->m_lpNextWord;
+        }
+    }
+
+    SetTextColor(hdc, crOldColor); 
+    ClearFontCache(hdc);
+    RestoreDC(hdc, nSavedDC);
+    SetBkMode(hdc,nOldBkMode); 
+    EndPaint(m_hWnd, &ps);
+    return 0;
+}
+
+VOID SRTextView::ClearFontCache(HDC hdc)
+{
+    // Clear the font from device context so it can be deleted with the rest...
+    SelectObject(hdc, GetStockObject(SYSTEM_FONT));
+    
+    for(DWORD i = 0; i < BTEXT_FONT_CACHE_MAX; i++){
+        if(m_hFontCache[i]){
+            DeleteObject(m_hFontCache[i]);
+            m_hFontCache[i] = 0;
+
+        }
+    }
+}
+
+VOID SRTextView::SetTapState(BOOL fMouseDown, INT xPos, INT yPos)
+{
+    POINT pt = {xPos, yPos};
+    DWORD dwDiffTime = 0;
+    ScreenToClient(m_hWnd, &pt);
+    // Test if the mouse moved more than some threshold value.
+    BOOL mouseMoved = (abs(m_ptLastClick.y - pt.y) > 5) || (abs(m_ptLastClick.x - pt.x) > 5);
+
+    if(!m_fDragging){	
+        m_nDragStart =  pt.y;
+    }
+
+    // If we are about to go into a dragging mode, 
+    // or we are about to leave a dragging mode,
+    // we should calculate a rolling velocity.
+    if(fMouseDown && !m_fDragging){
+        m_dwTrueStartPos = pt.y;
+        m_dwTrueStartTime = GetTickCount();
+        m_nRollVelocity = 0;
+    }else if(!fMouseDown && m_fDragging){
+        dwDiffTime = GetTickCount() - m_dwTrueStartTime;
+        if(dwDiffTime > 200)
+            m_nRollVelocity = 0;
+        else
+            m_nRollVelocity = (80*(int)(pt.y - m_dwTrueStartPos))/((int)dwDiffTime);
+    }
+
+    if(fMouseDown){
+        m_dwClickTime = GetTickCount();
+        m_fDragging = TRUE;
+        SetCapture(m_hWnd);
+    }else{
+        m_fDragging = FALSE;
+        ReleaseCapture();
+    }
+
+    // If we are absolutely positive the user wants to click...
+    if(!fMouseDown && !mouseMoved && (GetTickCount() - m_dwClickTime) < 120)
+        GetWordAtPoint(xPos, yPos);
+    m_ptLastClick = pt;
+
+    // If there is a velocity set this will use it up, otherwise it drops out nicely.
+    RollTillStopped();
+}
+
+VOID SRTextView::GetWordAtPoint(INT xPos, INT yPos)
+{
+    POINT pt = {xPos, yPos};
+    SRTextWord *pbtWord;
+    DWORD dwLineNum = 0;
+    TCHAR szWordFound[128] = {0};
+
+    while(dwLineNum <= m_BTLines.m_dwLastLine && (m_BTLines.m_lpLines[dwLineNum].m_rect.bottom + m_nTop) < pt.y)
+        dwLineNum++;
+    if(dwLineNum > m_BTLines.m_dwLastLine)
+        return;
+    pbtWord = &m_BTLines.m_lpLines[dwLineNum]; 
+    while(pbtWord->m_lpszWord && pbtWord->m_rect.right < pt.x)
+        pbtWord = pbtWord->m_lpNextWord;
+    if(pbtWord->m_lpszWord){
+        if(pbtWord->m_dwlfFontState & BTEXT_HTML_A_BEG && pbtWord->m_lpszHref){
+            wcsncpy(szWordFound, pbtWord->m_lpszHref, pbtWord->m_dwHrefLen);
+        }else{
+            wcsncpy(szWordFound, pbtWord->m_lpszWord, pbtWord->m_dwWordLen);
+        }
+        MessageBox(m_hWnd, szWordFound, L"Found...", MB_OK);
+    }
+}
+
+VOID SRTextView::DragScreenToPoint(INT yPos)
+{
+    POINT   pt;
+    RECT    rectUpdateRect;
+    INT     nDragDist = 0;
+
+    if(m_fDragging){
+        pt.x = 0;
+        pt.y = yPos;
+        ScreenToClient(m_hWnd, &pt);
+        nDragDist = pt.y - m_nDragStart;
+        m_nTop += nDragDist;
+        // Prevent rolling past top or bottom
+        if(m_nTop > 0){
+            nDragDist -= m_nTop;
+            m_nTop = 0;
+        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
+            // nDragDist does not matter here because we are Scrolling a white window, 
+            // Keeping track of m_nTop is important as it is our reference point for 
+            // scrolling later
+            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
+        }
+
+        ScrollWindowEx(m_hWnd, 0, nDragDist, NULL, NULL, NULL, &rectUpdateRect, NULL);
+        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
+        ::UpdateWindow(m_hWnd);
+
+        m_nDragStart = pt.y;
+    }
+}
+
+VOID SRTextView::RollTillStopped()
+{
+    RECT    rectUpdateRect;
+    BOOL    fDone       = FALSE;
+    INT     nDirection  = m_nRollVelocity > 0 ? 1 : -1;
+
+    while(!fDone && nDirection*m_nRollVelocity > 0){
+        m_nTop += m_nRollVelocity;
+
+        // Prevent rolling beyond the top of the page.
+        if(m_nTop > 0){
+            m_nRollVelocity -= m_nTop;
+            m_nTop = 0;
+            fDone = TRUE;
+        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
+            // dist does not matter here because we are Scrolling a white window, 
+            // Keeping track of m_nTop is important as it is our reference point for 
+            // scrolling later
+            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
+            fDone = TRUE;
+        }
+
+        ScrollWindowEx(m_hWnd, 0, m_nRollVelocity, NULL, NULL, NULL, &rectUpdateRect, NULL);
+        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
+        ::UpdateWindow(m_hWnd);
+        m_nRollVelocity = (m_nRollVelocity - m_nRollVelocity/6) - ((nDirection*m_nRollVelocity < 10) ? nDirection : 0); // the nDirection part ensures continual degrading in the velocity
+    }
+}
+
+VOID SRTextView::ScrollFullPage(INT nDirection)
+{
+    RECT    rectUpdateRect;
+    RECT    rectClientRect;
+    INT     nDist       = 0;
+    BOOL    fDone       = FALSE;
+    GetClientRect(m_hWnd,&rectClientRect);
+    INT     nRollBy     = rectClientRect.bottom - rectClientRect.top;
+    INT     nCalcDist   = 0;
+    CONST INT UPPER_SB  = 15; // Upper bound on the scrolling per iteration.
+    nDirection          = (nDirection > 0) ? 1 : -1;
+    
+    for(INT i = 0;!fDone && i < nRollBy; i+=nCalcDist){
+        nCalcDist = UPPER_SB - (int)(UPPER_SB*((float)i/(float)nRollBy)) + 1;
+        nDist = nDirection*nCalcDist;
+        m_nTop += nDist;
+        // Prevent rolling beyond the top of the page.
+        if(m_nTop > 0){
+            nDist -= m_nTop;
+            m_nTop = 0;
+            fDone = TRUE;
+        }else if(m_nTop < -m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom){
+            // nDist does not matter here because we are Scrolling a white window, 
+            // Keeping track of m_nTop is important as it is our reference point for 
+            // scrolling later
+            m_nTop = -(m_BTLines.m_lpLines[m_BTLines.m_dwLastLine].m_rect.bottom);
+            fDone = TRUE;
+        }
+        ScrollWindowEx(m_hWnd, 0, nDist, NULL, NULL, NULL, &rectUpdateRect, NULL);
+        InvalidateRect(m_hWnd, &rectUpdateRect, TRUE);
+        ::UpdateWindow(m_hWnd);
+    }
+}
+
+VOID SRTextView::AddText(const TCHAR *szText, DWORD dwSize)
+{
+    DWORD i = 0;
+
+    // Do we need to make room for the new szText
+    if((m_dwBuffEnd + dwSize) > m_dwBuffSize){
+        DWORD dwNewSize = BTEXT_BUFF_INC > dwSize ? BTEXT_BUFF_INC : dwSize;
+        TCHAR *lpszTmp = new TCHAR[dwNewSize];
+        for(i = 0; i < m_dwBuffSize; i++){
+            lpszTmp[i] = m_lpszBuff[i];
+        }
+        delete [] m_lpszBuff;
+        m_lpszBuff = lpszTmp;
+        m_dwBuffSize = dwNewSize;
+    }
+
+    // If this is a new buffer we need to
+    // discard HTML header stuff by pointing to the beginning of the <body></body>
+    i = 0;
+    if(m_dwBuffEnd == 0){ 
+        do{
+            while(szText[i] != '<' && i < dwSize) i++;
+            if(wcsnicmp(&szText[i], L"<body>", 6) == 0){
+                i += 6;
+                break;
+            }
+            while(szText[i++] != '>' && i < dwSize);
+            if(i > dwSize){
+                i = 0;
+                break;// This buffer does not appear to have a <body> tag, let's just pretend it did.
+            }
+        }while(TRUE);
+    }
+
+    // Copy it in, and ignore the closing tags, if any
+    for(; i < dwSize; i++){
+        // We arbitrarily choose to start looking at the last 100 characters for the tail end 
+        // of this HTML stream. If we fail to chop it off its not the end of the world, but
+        // it would be nice to get out of the way now.
+        if(dwSize > 100 && i > (dwSize - 100) && wcsnicmp(&szText[i], L"</body>", 7) == 0)
+            break; 
+        if(szText[i] == 0x09) // Horizontal tab, replace with a single space. (for now at least.)
+            m_lpszBuff[m_dwBuffEnd++] = ' ';
+        else if(szText[i] != '\n') // Ignore new-lines
+            m_lpszBuff[m_dwBuffEnd++] = szText[i];
+    }
+    for(i = 0; i + m_dwBuffEnd < m_dwBuffSize; i++)
+        m_lpszBuff[i + m_dwBuffEnd] = 0;
+}
+
+BOOL SRTextView::UpdateWindow()
+{
+    InvalidateRect(m_hWnd, NULL, TRUE);
+    return ::UpdateWindow(m_hWnd);
+}
+/*****************************************************************************
+ * SRTextWord                                                                 *
+ *****************************************************************************/
+
+SRTextView::SRTextWord::SRTextWord()
+: m_lpNextWord(0)
+, m_lpPrevWord(0)
+, m_lpszWord(NULL)
+, m_dwWordLen(0)
+, m_lpszHref(NULL)
+, m_dwHrefLen(0)
+, m_fOwner(FALSE)
+, m_dwlfFontState(0)
+, m_dwlWordNum(0)
+, m_dwSubWordNum(0)
+{
+    m_rect.top      = 0;
+    m_rect.left     = 0;
+    m_rect.bottom   = 0;
+    m_rect.right    = 0;
+}
+
+VOID SRTextView::SRTextWord::Clear()
+{
+    if(m_fOwner && m_lpszWord)
+        delete [] m_lpszWord;
+    m_fOwner            = FALSE;
+    m_dwlfFontState     = 0;
+    m_dwHrefLen         = 0;
+    m_dwWordLen         = 0;
+    m_lpszWord          = NULL;
+    m_lpszHref          = NULL;
+    m_rect.top          = 0;
+    m_rect.bottom       = 0;
+    m_rect.left         = 0;
+    m_rect.right        = 0;
+    m_dwlWordNum        = 0;
+    m_dwSubWordNum      = 0;
+    m_lpNextWord        = NULL;
+    m_lpPrevWord        = NULL;
+}
+
+VOID SRTextView::SRTextWord::OwnWord(TCHAR *lpszWord, DWORD dwWordLen)
+{
+    if(m_fOwner && m_lpszWord){
+        delete [] m_lpszWord;
+    }
+    m_lpszWord = new TCHAR[dwWordLen + 1];
+    for(DWORD i = 0; i < dwWordLen; i++)
+        m_lpszWord[i] = lpszWord[i];
+
+    m_lpszWord[dwWordLen]   = 0;
+    m_dwWordLen             = dwWordLen;
+    m_fOwner                = TRUE;
+}
+
+SRTextView::SRTextWord::SRTextWord(const SRTextView::SRTextWord &rhs)
+{
+    m_dwlfFontState = rhs.m_dwlfFontState;
+    m_dwHrefLen     = rhs.m_dwHrefLen;
+    m_dwWordLen     = rhs.m_dwWordLen;
+    m_lpszHref      = rhs.m_lpszHref;
+    m_lpNextWord    = rhs.m_lpNextWord;
+    m_lpPrevWord    = rhs.m_lpPrevWord;
+    m_fOwner        = rhs.m_fOwner;
+    m_rect          = rhs.m_rect;
+    m_dwlWordNum    = rhs.m_dwlWordNum;
+    m_dwSubWordNum  = rhs.m_dwSubWordNum;
+
+    if(m_fOwner && rhs.m_lpszWord){
+        m_lpszWord = new TCHAR[m_dwWordLen + 1];
+        for(DWORD i = 0; i < m_dwWordLen; i++)
+            m_lpszWord[i] = rhs.m_lpszWord[i];
+        m_lpszWord[m_dwWordLen] = 0;
+    }else{
+        m_lpszWord = rhs.m_lpszWord;
+    }
+}
+SRTextView::SRTextWord & SRTextView::SRTextWord::operator=(const SRTextView::SRTextWord &rhs)
+{
+    if(this == &rhs)
+        return *this; // We detect self assignment
+
+    m_dwlfFontState = rhs.m_dwlfFontState;
+    m_dwHrefLen     = rhs.m_dwHrefLen;
+    m_dwWordLen     = rhs.m_dwWordLen;
+    m_lpszHref      = rhs.m_lpszHref;
+    m_lpNextWord    = rhs.m_lpNextWord;
+    m_lpPrevWord    = rhs.m_lpPrevWord;
+    m_rect          = rhs.m_rect;
+    m_dwlWordNum    = rhs.m_dwlWordNum;
+    m_dwSubWordNum  = rhs.m_dwSubWordNum;
+
+    if(m_fOwner && m_lpszWord)
+        delete [] m_lpszWord;
+
+    m_fOwner        = rhs.m_fOwner;
+
+    if(m_fOwner && rhs.m_lpszWord){
+        m_lpszWord = new TCHAR[m_dwWordLen + 1];
+        for(DWORD i = 0; i < m_dwWordLen; i++)
+            m_lpszWord[i] = rhs.m_lpszWord[i];
+        m_lpszWord[m_dwWordLen] = 0;
+    }else{
+        m_lpszWord = rhs.m_lpszWord;
+    }
+    return *this;
+}
+
+SRTextView::SRTextWord::~SRTextWord()
+{
+    if(m_fOwner && m_lpszWord){
+        delete [] m_lpszWord;
+    }
+}
+/*****************************************************************************
+ * SRTextLines                                                                *
+ *****************************************************************************/
+
+SRTextView::SRTextLines::SRTextLines()
+: m_nLineH(0)
+, m_dwLastLine(0)
+{
+    InitLines(0);
+}
+
+VOID SRTextView::SRTextLines::InitLines(CONST INT nLineH)
+{
+    m_dwLines           = BTEXT_LINE_INC;
+    m_lpLines           = new SRTextWord[m_dwLines];
+    m_lppLinesLastWord  = new SRTextWord*[m_dwLines];
+    
+    for(DWORD i = 0; i < m_dwLines; i++)
+        m_lppLinesLastWord[i] = &m_lpLines[i];
+    m_nLineH = nLineH;
+}
+
+SRTextView::SRTextLines::SRTextLines(CONST SRTextView::SRTextLines &rhs)
+{
+    m_dwLastLine        = rhs.m_dwLastLine;
+    m_dwLines           = rhs.m_dwLines;
+    m_lpLines           = new SRTextWord[m_dwLines];
+    m_lppLinesLastWord  = new SRTextWord*[m_dwLines];
+
+    for(DWORD i = 0; i < m_dwLines; i++){
+        m_lpLines[i]            = rhs.m_lpLines[i];
+        m_lppLinesLastWord[i]   = rhs.m_lppLinesLastWord[i];
+    }
+}
+
+SRTextView::SRTextLines & SRTextView::SRTextLines::operator=(CONST SRTextView::SRTextLines &rhs)
+{
+    if(this == &rhs)
+        return *this; // We detect self assignment
+
+    ClearLines();
+
+    m_dwLastLine    = rhs.m_dwLastLine;
+    m_dwLines       = rhs.m_dwLines;
+
+    m_lpLines           = new SRTextWord[m_dwLines];
+    m_lppLinesLastWord  = new SRTextWord*[m_dwLines];
+
+    for(DWORD i = 0; i < m_dwLines; i++){
+        m_lpLines[i]            = rhs.m_lpLines[i];
+        m_lppLinesLastWord[i]   = rhs.m_lppLinesLastWord[i];
+    }
+
+    return *this;
+}
+
+SRTextView::SRTextLines::~SRTextLines()
+{
+    ClearLines();
+}
+
+VOID SRTextView::SRTextLines::ClearLines()
+{
+    DWORD dwCurLine = 0;
+    SRTextWord *pbtNextWord = NULL;
+    SRTextWord *pbtTempWord = NULL;
+
+    for(dwCurLine = 0; dwCurLine < m_dwLines; dwCurLine++){
+        pbtNextWord = m_lpLines[dwCurLine].m_lpNextWord;
+        // Delete all the words in this line
+        while(pbtNextWord){
+            pbtTempWord = pbtNextWord->m_lpNextWord;
+            delete pbtNextWord;
+            pbtNextWord = pbtTempWord;
+        }
+    }
+    m_dwLastLine = 0;
+    m_dwLines = 0;
+
+    delete [] m_lpLines;
+    m_lpLines = NULL;
+    delete [] m_lppLinesLastWord;
+    m_lppLinesLastWord = NULL;
+}
+
+INT SRTextView::SRTextLines::ValidateNewLineWord(CONST DWORDLONG dwlWordNum,CONST INT nLineH, CONST INT nMargin)
+{
+    if(!m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord)
+        return nMargin; // There is no word on the last line, nothing to do...
+
+    SRTextView::SRTextWord *pbtWord = m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord;
+
+    if(pbtWord->m_dwlWordNum != dwlWordNum)
+        return nMargin; // Different word, nothing to do...
+
+    pbtWord->m_rect.top     += nLineH;
+    pbtWord->m_rect.bottom  += nLineH;
+    pbtWord->m_rect.right   = nMargin + (pbtWord->m_rect.right - pbtWord->m_rect.left);
+    pbtWord->m_rect.left    = nMargin;
+
+    // break this word off the old line's chain
+    SRTextView::SRTextWord *pbtChainPrev = pbtWord->m_lpPrevWord;
+    SRTextView::SRTextWord *pbtChainNext = pbtWord->m_lpNextWord;
+
+    if(pbtWord->m_lpPrevWord)
+        pbtWord->m_lpPrevWord->m_lpNextWord = pbtChainNext;
+    if(pbtWord->m_lpNextWord)
+        pbtWord->m_lpNextWord->m_lpPrevWord = pbtChainPrev;
+
+    m_lppLinesLastWord[m_dwLastLine] = pbtChainNext;
+    pbtWord->m_lpPrevWord = NULL;
+    pbtWord->m_lpNextWord = NULL;
+    AddWordToLine(m_dwLastLine + 1, *pbtWord);
+    delete pbtWord;
+
+    return m_lppLinesLastWord[m_dwLastLine]->m_lpPrevWord->m_rect.right;
+}
+
+VOID SRTextView::SRTextLines::AddWordToLine(DWORD dwLine, CONST SRTextView::SRTextWord &btWord)
+{
+    DWORD dwLines   = 0;
+    DWORD i         = 0;
+
+    // Check if we are about to overflow the allocated lines
+    // If so resize...
+    if(dwLine >= m_dwLines){
+        dwLines = m_dwLines + BTEXT_LINE_INC;
+        //unsigned int nLastLine = m_dwLastLine;
+        i = 0;
+        SRTextWord *pbtTemp1     = new SRTextWord[dwLines];
+        SRTextWord **ppbtTemp2   = new SRTextWord*[dwLines];
+
+        for(i = 0; i <= m_dwLastLine; i++){
+            pbtTemp1[i] = m_lpLines[i];
+            // Now the next btWord doesn't know it has a new prev btWord
+            // Fixing...
+            if(pbtTemp1[i].m_lpNextWord)
+                pbtTemp1[i].m_lpNextWord->m_lpPrevWord = &pbtTemp1[i];
+            ppbtTemp2[i] = m_lppLinesLastWord[i];
+        }
+        for(;i < dwLines; i++){
+            ppbtTemp2[i] = &pbtTemp1[i];
+        }
+        m_dwLastLine = dwLine;
+        m_dwLines = dwLines;
+        delete [] m_lpLines;
+        delete [] m_lppLinesLastWord;
+        m_lpLines = pbtTemp1;
+        m_lppLinesLastWord = ppbtTemp2;
+    }else if(dwLine > m_dwLastLine){
+        m_dwLastLine = dwLine;
+    }
+    SRTextView::SRTextWord *pbtPrevWord = m_lppLinesLastWord[dwLine]->m_lpPrevWord;
+    *m_lppLinesLastWord[dwLine] = btWord;
+    m_lppLinesLastWord[dwLine]->m_lpNextWord = new SRTextWord();
+    m_lppLinesLastWord[dwLine]->m_lpPrevWord = pbtPrevWord;
+    // Create the relationship between this btWord and the next 
+    // potential btWord...
+    m_lppLinesLastWord[dwLine]->m_lpNextWord->m_lpPrevWord = m_lppLinesLastWord[dwLine];
+    m_lppLinesLastWord[dwLine] = m_lppLinesLastWord[dwLine]->m_lpNextWord;
+}
\ No newline at end of file

Added: trunk/src/SwordReader_GUI/SRTextView.h
===================================================================
--- trunk/src/SwordReader_GUI/SRTextView.h	                        (rev 0)
+++ trunk/src/SwordReader_GUI/SRTextView.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -0,0 +1,688 @@
+/******************************************************************************
+*  SRTextView.h - HTML Renderer for rendering biblical texts on Pocket PC 
+*  devices.
+*  Author: David C Trotz Jr. 
+*  e-mail: dtrotzjr at crosswire.org
+*
+* $Id$
+*
+* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+*	CrossWire Bible Society
+*	P. O. Box 2528
+*	Tempe, AZ  85280-2528
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation version 2.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+*
+*/
+
+#pragma once
+#include <windows.h>
+#include "SRFramework/SRWnd.h"
+
+using namespace SRFramework;
+
+
+//! SRTextView::m_lpszBuff gets re-sized in increments based upon this number.
+#define BTEXT_BUFF_INC              2000
+//! SRTextView::m_BTLines gets re-sized based upon this number
+#define BTEXT_LINE_INC              400
+//!  Determines the margin around the border of the display. 
+//!  May be broken into Top, Bottom, Left, and Right margins in the future.
+#define BTEXT_MARGIN                4
+
+#define BTEXT_FONT_CACHE_MAX        0x7FFF
+
+
+//! Determines the default font height. 
+//! @note Future implementations may read this from a config file.
+#define BTEXT_DEFAULT_FONT_HEIGHT   -11
+//! Flags an uninitialized color state.
+//! This is actually an invalid COLOREF Color, which makes it ideal for
+//! this type of use, as it will never come up naturally.
+#define BTEXT_FONT_NOT_A_COLOR      0xFF000000
+//! Determines the default font face color.
+//! @note Future implementations may read this from a config file.
+#define BTEXT_DEFAULT_FONT_COLOR    0x00000000
+//! Determines the line spacing factor.
+//! @note Future implementations may read this from a config file.
+#define BTEXT_LINE_SPACING          1.1
+
+//! Flag indicating a space of some sort was encountered.
+//! @deprecated Future implementations will move away from this flag
+#define BTEXT_SPACE_ENCOUNTERED     0
+//! Flag indicating a new line has been encountered
+//! @deprecated Use of this flag may not be needed in future releases.
+#define BTEXT_NEWLINE_ENCOUNTERED   -1
+//! Flag indicating we have encountered an opening bracket for HTML processing.
+#define BTEXT_HTML_OPEN_BRACKET     -2
+
+//! Flag indicating a &lt;br&gt; element was encountered
+#define BTEXT_HTML_BR               0x00000001
+//! Flag used to mask against the ..._BEG counterpart of an ..._END.
+#define BTEXT_HTML_MASK             0xFFFFFFFF
+
+//!Flag indicating we encountered a &lt;b&gt; element
+#define BTEXT_HTML_B_BEG            0x00000002
+//!Flag indicating we encountered a &lt;/b&gt; element
+#define BTEXT_HTML_B_END            BTEXT_HTML_MASK ^ BTEXT_HTML_B_BEG
+
+//!Flag indicating we encountered a &lt;i&gt; element
+#define BTEXT_HTML_I_BEG            0x00000004
+//!Flag indicating we encountered a &lt;/i&gt; element
+#define BTEXT_HTML_I_END            BTEXT_HTML_MASK ^ BTEXT_HTML_I_BEG
+
+//!Flag indicating we encountered a &lt;sup&gt; element
+#define BTEXT_HTML_SUP_BEG          0x00000008
+//!Flag indicating we encountered a &lt;/sup&gt; element
+#define BTEXT_HTML_SUP_END          BTEXT_HTML_MASK ^ BTEXT_HTML_SUP_BEG
+
+//!Flag indicating we encountered a &lt;sub&gt; element
+#define BTEXT_HTML_SUB_BEG          0x00000010
+//!Flag indicating we encountered a &lt;/sub&gt; element
+#define BTEXT_HTML_SUB_END          BTEXT_HTML_MASK ^ BTEXT_HTML_SUB_BEG
+
+//!Flag indicating we encountered a &lt;small&gt; element
+#define BTEXT_HTML_SMALL_BEG        0x00000020
+//!Flag indicating we encountered a &lt;/small&gt; element
+#define BTEXT_HTML_SMALL_END        BTEXT_HTML_MASK ^ BTEXT_HTML_SMALL_BEG
+
+//!Flag indicating we encountered a &lt;font ...&gt; element
+#define BTEXT_HTML_FONT_BEG         0x00000040
+//!Flag indicating we encountered a &lt;/font&gt; element
+#define BTEXT_HTML_FONT_END         BTEXT_HTML_MASK ^ BTEXT_HTML_FONT_BEG
+
+//!Flag indicating we encountered a &lt;a ...&gt; element
+#define BTEXT_HTML_A_BEG            0x00000080
+//!Flag indicating we encountered a &lt;/a&gt; element
+#define BTEXT_HTML_A_END            BTEXT_HTML_MASK ^ BTEXT_HTML_A_BEG
+
+//!Flag indicating we encountered a &lt;p&gt; element
+#define BTEXT_HTML_P_BEG            0x00000100
+//!Flag indicating we encountered a &lt;/p&gt; element
+#define BTEXT_HTML_P_END            BTEXT_HTML_MASK ^ BTEXT_HTML_P_BEG
+
+//! Flag indicating we encountered an illegal tag format.
+#define BTEXT_HTML_ILLEGAL_TAG_FORMAT   0x80000000
+//! Flag indicating we encountered an unknown tag.
+#define BTEXT_HTML_UNKNOWN_TAG          0x40000000
+
+//! SRTextView - A custom HTML Renderer for Biblical Texts on WinCE Platforms.
+/*!
+    SRTextView was designed to be a replacement for the built in HTML Renderer
+    on Windows CE platforms. This replacement was decided necessary due to the
+    limitations and performance issues encountered when designing a front end
+    for The SWORD Project on the Windows CE platform.
+
+    When implementing this class I have taken every precaution I could to ensure
+    the class could be easily manipulated in the future to add support for new
+    features necessary to display biblical and supporting texts. Whether I have
+    been successful at this or not is unfounded, only time will tell.
+ */
+class SRTextView : SRWnd
+{
+private:
+
+    //! SRTextWord - The most basic element of this text display. 
+    /*!	SRTextWord represents a single (whole or partial) word. Each word 
+    			contains information to describe its placement on the screen and any
+    			display characteristics it may possess such as bold, italic, font 
+    			size, etc. In order to preserve memory and time copying text from the 
+    			main buffer SRTextWord objects typically only point to the main text 
+    			buffer SRTextView::m_lpszBuff 
+    			
+    			On rare occasions it is necessary for the word to store its own copy 
+    			of the word it represents, in these cases m_fOwner will be true and 
+    			special care is taken to manage its memory.
+    			
+    			This Class also represents a doubly linked list, care must be taken 
+    			whenever a single node is removed from the list or else you risk
+    			memory leaks or dangling pointers, both of which are a death sentence
+    			on the WinCE platform.
+    				
+     */
+    class SRTextWord
+    {
+    public:
+    		//! Default Constructor
+        SRTextWord();
+        //! Copy Constructor
+        SRTextWord(CONST SRTextView::SRTextWord &rhs);
+        //! Destructor
+        ~SRTextWord();
+        //! Assignment operator
+        SRTextView::SRTextWord &operator=(CONST SRTextView::SRTextWord &rhs);
+        //! Clears the contents of this word.
+        //! This may include deleting any memory it may own.
+        VOID Clear();
+        //! Copy the pWord object internally and manage it internally.
+        //! Tells this instance of SRTextWord that it needs to make a copy of 
+        //! this word and "own" the word.
+        //! @param pWord pointer to the word being copied in.
+        //! @param dwWordLen length of the word being copied in.
+        VOID OwnWord(TCHAR *lpszWord, DWORD dwWordLen);
+        //! Points to a specific word inside a buffered string stored and 
+        //! managed outside of this class.
+        //! Thus we do not try to manage the memory, unless the m_fOwner 
+        //! flag is set.
+        TCHAR   *       m_lpszWord;
+        //! Indicates how many characters this word is in length.
+        DWORD           m_dwWordLen;
+        //! Points to a specific href inside a buffered string stored and 
+        //! managed outside of this class.
+        //! Thus we do not try to manage the memory, not even if m_fOwner is set
+        TCHAR   *       m_lpszHref;
+        //! Indicates how many characters this href is in length.
+        DWORD           m_dwHrefLen;
+        //! Indicates the on screen bounds of this word.
+        RECT            m_rect;
+        //! Flags indicating the font status of this word.
+        //! @code 
+        //! X = Reserved     H = Font Height
+        //! M = Small        B = Subscript
+        //! U = Superscript  O = Bold
+        //! I = Italic       A = Link
+        //! P = Paragraph
+        //! F = Font (not used here)
+        //! RR = Red	GG = Green BB = Blue
+        //! - = Line-break bit (not used here)
+        //! BYTE: 7[7654 3210] 6[7654 3210] 5[7654 3210] 4[7654 3210]
+        //!        [BBBB BBBB]  [GGGG GGGG]  [RRRR RRRR]  [HHHH HHHH]
+        //! BYTE: 3[7654 3210] 2[7654 3210] 1[7654 3210] 0[7654 3210]
+        //!        [XXXX XXXX]  [XXXX XXXX]  [XXXX XXXP]  [AFMB UIO-]
+        //! @endcode
+        DWORDLONG       m_dwlfFontState;
+
+				//! Indicates that this SRTextWord object should manage the memory
+				//! pointed to by m_lpszWord.
+        //! There are times when this SRTextWord needs to clean up the 
+        //! character allocation it points to, such as when Special
+        //! Entities are interpreted and stored separately from the main
+        //! text buffer.
+        BOOL            m_fOwner;
+        //! Points to the next word in the list.
+        SRTextWord *     m_lpNextWord;
+        //! Points to the previous word in the list.
+        SRTextWord *     m_lpPrevWord;
+        //! Indicates the unique number assigned to each word.
+        //! This number is helpful in keeping words together when a
+        //! html element is introduced mid-word such as 
+        //! L&lt;font size="-1"&gt;ORD&lt;/font&gt; In this case two SRTextWord
+        //! objects are created and all that ties them together is this 
+        //! variable. 
+        //! @see m_dwSubWordNum.
+        DWORDLONG       m_dwlWordNum;
+        //! Indicates which piece of a word this word is (most often it will be 0)
+        DWORD           m_dwSubWordNum;
+    };
+
+    //! SRTextLines - Stores all the words in an array of lines.
+    /*!	SRTextLines is responsible for storing the SRTextWord objects in a way that 
+    			is convenient for rendering on the display, and for x,y coordinate to 
+    			SRTextWord object look-up.
+     */
+    class SRTextLines
+    {
+    public:
+    		//! Default Constructor
+        SRTextLines();
+        // Copy Constructor
+        SRTextLines(CONST SRTextView::SRTextLines &rhs);
+        //! Destructor
+        ~SRTextLines();
+        //! Assignment operator.
+        SRTextView::SRTextLines &operator=(CONST SRTextView::SRTextLines &rhs);
+				
+				//! Adds the given word to the end of the line indicated by the line number.
+				/*! If dwLine is larger than the current m_dwLastLine property, then 
+						m_dwLastLine is changed accordingly (hence it grows). Since we do 
+						not want to thrash the heap by reallocating every time m_dwLastLine
+						increments (and we expect it will often), we instead allocate in 
+						increments of BTEXT_LINE_INC.
+						@param dwLine Indicates the line number where the new btWord is being 
+						added.
+						@param btWord The SRTextWord object we will copy into the SRTextLines
+						object.
+				*/
+        VOID    AddWordToLine(DWORD dwLine, CONST SRTextView::SRTextWord &btWord);
+        //! Clears all lines from this instance of SRTextLines. 
+        /*! BEWARE - Once this is called the object is not usable again until, 
+        		InitLines is called to re-initialize the memory for m_lpLines and 
+        		m_lppLinesLastWord
+         */	
+        VOID    ClearLines();
+        //! Initializes (or allocates) memory to store the words.
+        /*! @param nLineH indicates the physical line height in pixels. 
+        		@note Not sure how appropriate nLineH is here. Expect this to change
+        		in future releases.
+        */
+        VOID    InitLines(CONST INT nLineH);
+        //! Validates the incoming word's position on a new line.
+        /*!
+        		Checks to see if this word might be part of a word that ended on the
+        		previous line. If it is part of the previous line's word, it moves 
+        		the previous word down to the new line and prepares this word to be 
+        		inserted immediately following.
+        		@param dwWordNum indicates the word's unique number to determine if it 
+        			belongs to the word in the line above.
+        		@param nLineH indicates how far down to move the word (physically in 
+        			pixels) if it is determined that it needs to be moved.
+        		@param nMargin indicates the margin to obey when placing the word on 
+        			a new line if it is determined that it needs to be moved.
+        		@return the position in pixels that the new word can start at. If it 
+        			was determined that the word above did not need to be moved, it 
+        			simply returns nMargin as its value, if it did move down its 
+        			rightmost extent is returned instead.
+         */
+        INT     ValidateNewLineWord(CONST DWORDLONG dwlWordNum,CONST INT nLineH, CONST INT nMargin);
+        //! Indicates the total number of lines currently allocated.
+        DWORD           m_dwLines;
+        //! Indicates the last line actually being used,
+        //! hence m_dwLastLine < m_dwLines is always true!
+        DWORD           m_dwLastLine;
+        //! Indicates the physical line height in pixels. Useful for 
+        //! determining line boundaries.
+        int             m_nLineH;
+        //! Pointer to an array of SRTextWords, where each index into the array 
+        //! represents a single line of text.
+        SRTextWord*      m_lpLines;
+        //! Convenience pointer to the last word in each line.
+        //! @note Do not manage this memory!!! It is already managed 
+        //! as m_lpLines.
+        SRTextWord**     m_lppLinesLastWord;
+    };
+
+    //! SRFontTagItem - Tracks font tag elements and their respected properties.
+    /*! This simple class is a basic queue for tracking font tags and the properties related to those tags. 
+     */
+    class SRFontTagItem{
+    public:
+        //! Default Constructor
+        SRFontTagItem(){ m_siAbsFontSize = BTEXT_DEFAULT_FONT_HEIGHT; m_siRelFontSize = 0; m_crFontColor = BTEXT_FONT_NOT_A_COLOR; m_lpftNext = NULL; };
+        //! Destructor
+        ~SRFontTagItem() { if(m_lpftNext) delete m_lpftNext; };
+
+        //! Represents the absolute font size related to this font tag.
+        //! @note not fully implemented.
+        SHORT           m_siAbsFontSize;
+        //! Represents the relative font size related to this font tag.
+        //! Examples: &lt;font size="+2"&gt; -- indicates a font size +2 
+        //! greater than the current font size.
+        SHORT           m_siRelFontSize;
+        //! Represents the fore color of the font related to this font tag.
+        COLORREF        m_crFontColor;
+        //! Points to the next font tag item (if there exists one.)
+        SRFontTagItem*    m_lpftNext;
+    };
+
+    //! RenderState - Keeps track of the current rendering state.
+    /*! As new tags are encountered this structure is useful for keeping
+        track of such changes so that each word is rendered with the correct 
+        formatting tags applied.
+     */
+    struct RenderState{
+        //! Indicates that we encountered a space outside of a tag element.
+        BOOL            m_space_encountered;
+        //! Indicates the bold state.
+        /*! \code
+            m_wBoldState == 0 indicates not bold; 
+            m_wBoldState >  0 indicates bold
+            \endcode
+         */
+        WORD            m_wBoldState;
+        //! Indicates the italic state. 
+        /*! \code
+            m_wItalicState == 0 indicates not italicized; 
+            m_wItalicState >  0 indicates italicized
+            \endcode
+         */
+        WORD            m_wItalicState;
+        //! Indicates the super script state.
+        /*! \code
+            m_wSuperState == 0 indicates not super scripted; 
+            m_wSuperState >  0 indicates super scripted
+            \endcode
+         */
+        WORD            m_wSuperState;
+        //! Indicates the anchor (link) state.
+        /*! \code
+            m_wAState == 0 indicates not in anchor state
+            m_wAState >  0 indicates anchor state
+            \endcode
+            @note it is assumed that anchors are not nested 
+            thus: \code -1 < m_wAState > 1 \endcode
+         */
+        WORD            m_wAState;
+        //! Indicates the sub script state.
+        /*! \code
+            m_wSubState == 0 indicates not sub scripted
+            m_wSubState >  0 indicates sub scripted
+            \endcode
+         */
+        WORD            m_wSubState;
+        //! Indicates the paragraph state.
+        /*! \code
+            m_wParagraphState == 0 indicates not in paragraph
+            m_wParagraphState > indicates in a paragraph
+            \endcode
+         */
+        WORD            m_wParagraphState;
+        //! Tracks the font tag elements that help make the current font 
+        //! state. This linked list is treated as a last in first out (LIFO)
+        //! queue.
+        SRFontTagItem*    m_lpftFontTagHead;
+        //! This is where new elements are pushed/popped on to the queue.
+        SRFontTagItem*    m_lpftFontTagTail;
+        //! Pointer to an anchor href property the current font state
+        //! may reference.
+        TCHAR*          m_lpszHref; 
+        //! The length of that anchor href property ( m_lpszHref ) string
+        DWORD           m_dwHrefLen;
+        //! Indicates the current verse we believe we are representing.
+        WORD            m_wVerseNum;
+        //! Indicates how many HTML Special entities we have encountered and 
+        //! need to be interpreted later.
+        WORD            m_wTotalSpclEnt;
+        //! Used to compose a word that may be broken up by rendering
+        //! tags introduced mid-word such as the very common
+        //! L<font size="-1">ORD</font>
+        DWORDLONG       m_dwlWordNum;
+        //! Further helps compose words broken apart by tags.
+        DWORD           m_dwSubWordNum;
+    };
+
+public:
+    // Public Methods
+    //! Default Constructor
+    SRTextView();
+    //! Destructor
+    virtual ~SRTextView();
+    //! Adds the given text to the window control for rendering.
+    /*! The method appends the given text string to the text currently being 
+        stored in m_lpszBuff. To save on constantly resizing m_lpszBuff at 
+        each call to this method we instead re-size at increments of 
+        BTEXT_BUFF_INC
+        @param szText the text being added to this control.
+        @param dwSize the length of the text being added.
+     */
+    VOID    AddText(const TCHAR *szText, DWORD dwSize);
+    //! Scrolls the window a full height in a given direction.
+    /*! @param nDirection the direction to scroll 
+        \code
+        nDirection > 0 indicates up.
+        nDirection <= 0 indicates down.
+        \endcode
+     */
+    VOID    ScrollFullPage(INT nDirection);
+    //! Shows the window control.
+    //! Calls ShowWindow with the SW_SHOW parameter for the underlying window.
+    VOID    Show();
+    //! Hides the window control.
+    //! Calls ::ShowWindow with the SW_HIDE parameter for the underlying window.
+    VOID    Hide();
+    //! Changes the position and or size of the window.
+    //! Calls ::MoveWindow for the underlying window.
+    VOID    MoveWindow(INT x, INT y, INT w, INT h);
+    //! Clears the text from m_lpszBuff and removes the lines from m_BTLines.
+    VOID    Clear();
+    
+    BOOL UpdateWindow();
+
+    BOOL Create(SRWnd *pParentWnd, RECT bounds);
+private:
+    // Private Methods
+    //! Handles the WM_PAINT message for this window control. 
+    /*! This is the heart and soul of this window control. Well in theory it 
+        is, except most of the real work is done in PreRenderBuff. This method 
+        checks to see if the buffer has been pre-rendered, if not it calls 
+        PreRenderBuff. Once it is established that the buffer has been 
+        pre-rendered the method continues to actually render the text on 
+        screen, skipping any lines not expected to be showing on the screen.
+     */
+    BOOL     OnPaint();
+    //! Window event for mouse left button down.
+    /*! This event occurs whenever the system detects the mouse' left button is 
+        being pressed. 
+        @param fwKeys       Indicates the mouse buttons and keys that the user 
+                            pressed. See the WinCE API documentation for 
+                            WM_LBUTTONDOWN event.
+        @param xPos         indicates the x coordinate for the pen.
+        @param yPos         indicates the y coordinate for the pen.
+    */
+    BOOL OnLButtonDown(WORD fwKeys, INT xPos, INT yPos);
+    //! Window event for mouse left button up.
+    /*! This event occurs whenever the system detects the mouse' left button is 
+        being released. 
+        @param fwKeys       Indicates the mouse buttons and keys that the user 
+                            pressed. See the WinCE API documentation for 
+                            WM_LBUTTONUP event.
+        @param xPos         indicates the x coordinate for the pen.
+        @param yPos         indicates the y coordinate for the pen.
+    */
+    BOOL OnLButtonUp(WORD fwKeys, INT xPos, INT yPos);
+    //! Window event for mouse move.
+    /*! This event occurs whenever the system detects the mouse has moved, 
+        on the CE platform this generally only occurs when the stylus is 
+        pressed down and moving.
+        @param fwKeys       Indicates the mouse buttons and keys that the user 
+                            pressed. See the WinCE API documentation for 
+                            WM_MOUSEMOVE event.
+        @param xPos         indicates the x coordinate for the pen.
+        @param yPos         indicates the y coordinate for the pen.
+    */
+    BOOL OnMouseMove(WORD fwKeys, INT xPos, INT yPos);
+
+    //! Drags the text across the screen.
+    /*! Drags the text across the screen according to the point given and the 
+        current value of m_nDragStart.
+        @param xPos         indicates the x coordinate for the pen.
+        @param yPos         indicates the y coordinate for the pen.
+     */
+    VOID    DragScreenToPoint(INT yPos);
+    //! Set's the state of the pen. 
+    /*! The pen's state includes its current position and whether the pen is 
+        considered up or down. This method also tries to detect what the user 
+        is intending to do, such as tap a word or scroll a few lines or send the
+        window in a rolling motion.
+        @param fMouseDown   indicates the pen is in the down position.
+        @param xPos         indicates the x coordinate for the pen.
+        @param yPos         indicates the y coordinate for the pen.
+     */
+    VOID    SetTapState(BOOL fMouseDown, INT xPos, INT yPos);
+    //! Gets the word (if any) at the given point on the screen.
+    /*! Does a methodical search for the word that exists under the given point.
+        @param xPos x coordinate for word being queried.
+        @param yPos y coordinate for word being queried.
+        @par
+        @note Future implementations will return the word found. The current 
+        implementation only displays a MessageBox containing the word.
+     */
+    VOID    GetWordAtPoint(INT xPos, INT yPos);
+    //! Rolls the screen until the m_nRollVelocity member has reached a value of 0.
+    /*! @note Future implementations will work a little differently to allow the 
+        cancellation of a roll by replacing the main loop in this method with 
+        sending a user defined message indicating a roll is requested which will 
+        call this method until either m_nRollVelocity is 0 at which point this 
+        method will no longer send the user defined message to itself, or the 
+        user taps the screen in the middle of a roll resetting the 
+        m_nRollVelocity data member.
+     */
+    VOID    RollTillStopped();
+    //! The actual call back function for this window.
+    /*! This only acts as a mediator between the callback function we really 
+        want and the call back the Win API is expecting.
+        @param hwnd     Handle to the window.
+        @param message  Specifies the message. 
+        @param wParam   Specifies additional message information. The contents 
+                        of this parameter depend on the value of the message 
+                        parameter. 
+        @param lParam   Specifies additional message information. The contents 
+                        of this parameter depend on the value of the message 
+                        parameter. 
+     */
+    //static LRESULT CALLBACK MessageRoute(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+    //! The expected WinProc callback function.
+    /*! Handles any messages sent to this window.
+        @param hwnd     Handle to the window.
+        @param message  Specifies the message. 
+        @param wParam   Specifies additional message information. The contents 
+                        of this parameter depend on the value of the message 
+                        parameter. 
+        @param lParam   Specifies additional message information. The contents 
+                        of this parameter depend on the value of the message 
+                        parameter. 
+     */
+    //LRESULT CALLBACK WndProcBText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+    //! Sets the Font for the given device context. 
+    /*! Tries to determine if changing the font is even necessary. If not it 
+        returns immediately otherwise it proceeds to change the font based 
+        upon the dwlFontState parameter.
+        @param hdc          the device context getting the font change.
+        @param dwlFontState contains flags indicating the new state of the 
+                            font.
+        @note If called, be sure to free the last created font prior to 
+                releasing the device context otherwise a resource leak will 
+                occur. Sequential calls to this method do take care of any 
+                fonts created in prior calls. Its the last call that needs 
+                the extra attention.
+        @see SRTextView::SRTextWord::m_dwlfFontState
+     */
+    VOID    SetFont(HDC hdc, DWORDLONG dwlFontState);
+    //! Tries to detect any spaces at the current stream position.
+    /*! Spaces are then discarded (by incrementing the dwWordIndex) and their 
+        existence is recorded in the rsState.m_space_encountered parameter.
+        @param rsState      contains current rendering information. This is 
+                            where we store our 'space' encounters.
+        @param dwWordIndex  Index into the current stream m_lpszBuff indicating 
+                            where to be looking for spaces.
+        @return A BOOL value where a non-zero value indicates that spaces were 
+                encountered.
+        @note The return value is redundant information, it was the original 
+                way I dealt with acknowledging spaces. Since then I have moved 
+                onto a structure containing the overall state of the renderer, 
+                as such the return value here may change to void in future 
+                implementations.
+     */
+    BOOL    GetSpaces(RenderState& rsState, DWORD &dwWordIndex);
+    //! Determines location the next word in the stream.
+    /*! Based upon the current stream position this method will determine the 
+        extents of the word assumed to have its origin at dwWordIndex.
+        @param  rsState     the current state of the renderer.
+        @param  dwWordIndex where in m_lpszBuff to begin looking.
+        @param  dwWordEnd   the determined length of the word will land here.
+        @return An INT value indicating the character that terminated the search.
+        @note The return value was originally designed help determine what state 
+                we should be in next, but is currently unused and may end up 
+                going unused and removed in future releases.
+     */
+    INT     NextWord(RenderState& rsState,DWORD dwWordIndex, DWORD &dwWordEnd);
+    //! Determines what HTML tags are at the location in the stream.
+    /*! As HTML tags are encountered they are logged in the rsState parameter 
+        for future rendering.
+        @param rsState      the current state of the renderer
+        @param dwWordIndex  where in m_lpszBuff to begin looking. This value is
+                            also updated as the tags are being encountered and 
+                            recorded.
+        @return An INT indicating how many line breaks &lt;br&gt; were 
+                encountered during this call.
+     */
+    INT     GetHTMLTags(RenderState& rsState, DWORD &dwWordIndex);
+    //! Identifies what tag element is at the stream position.
+    /*! Once GetHTMLTags encounters a new tag it needs to know what tag it is, 
+        and that job falls to this method. This method is also the one 
+        responsible for building the SRFontTagItem linked list representing any 
+        &lt;font ...&gt; tags it encounters.
+        @param rsState      the current state of the renderer, and the recipient 
+                            of any changes to that state as a result of the tag 
+                            encountered. i.e An anchor tag may have an href 
+                            property attached to it, as such this state will 
+                            reflect that property upon return.
+        @param dwWordIndex  where in m_lpszBuff to begin looking
+        @param dwWordEnd    the predetermined length of the tag element being 
+                            examined.
+        @return A DWORD value indicating which tag was identified. 
+     */
+    DWORD   IndentifyTag(RenderState& rsState, DWORD dwWordIndex, DWORD dwWordEnd);
+    //! Looks for HTML special entities and translates them into their single character equivalents.
+    /*! @param dwWordIndex  where in m_lpszBuff to begin looking.
+        @param dwWordLen    where to stop translating
+        @param pbtWord      where the new translated string will be copied.
+        @note This causes the given pbtWord object to "own" its own copy of the 
+                newly translated string.
+     */
+    VOID    InterpretSpecialEntities(DWORD dwWordIndex, DWORD dwWordLen, SRTextWord *pbtWord);
+    //! Pre-Renders the internal buffer stream.
+    /*! @par
+        This is the big boss!
+        @par
+        This method is responsible for interpreting how the text stream is 
+        intended to be rendered.
+        @par
+        The main body of this function is a loop. At each iteration of the loop 
+        a single word is extracted. However every word has the possibility of 
+        being preceded with spaces, and/or html tags so we try to parse these 
+        out first. Once we have determined that we are at the start of a new 
+        word we call NextWord and get the actual word. If it happens that 
+        dwWordEnd is 0 after this call we exit, this is the only exit condition 
+        from this loop. Once we have the word we then set the font according 
+        to the current rendering state and do a "fake" draw of the word to 
+        determine its bounding rectangle. Now that we have the word, its font 
+        settings, and its boundaries, we store the word for actual rendering 
+        later. The loop continues to the next word, and so on...
+        @param  hdc the current device context to base our "fake" drawing on.
+     */
+    VOID    PreRenderBuff(HDC hdc);
+
+    VOID ClearFontCache(HDC hdc);
+
+    BOOL Register();
+
+    
+    // Private data members
+
+    //! Indicates whether we are in a dragging state.
+    BOOL                        m_fDragging;
+    //! 
+    POINT                       m_ptLastClick;
+    //! Indicates the yPos that the current dragging motion should start from.
+    INT                         m_nDragStart;
+    /*! Like m_nDragStart except it keeps track of the true start point 
+        as opposed to the m_nDragStart which is updated upon each WM_MOUSEMOVE 
+        message sent to this window.
+     */
+    DWORD                       m_dwTrueStartPos;
+    //! The start time related to m_dwTrueStartPos
+    DWORD                       m_dwTrueStartTime;
+    //! A virtual velocity used to do the fancy rolling motion.
+    INT                         m_nRollVelocity;
+    //! Indicates where the top of the "canvas" is in relationship to the top 
+    //! of the physical screen.
+    INT                         m_nTop;
+    //! The actual text stream is stored here.
+    TCHAR*                      m_lpszBuff;
+    //! Indicates how much memory has been allocated to the text buffer pointed 
+    //! to by m_lpszBuff
+    DWORD                       m_dwBuffSize;
+    //! Indicates the end of the text stream and the actual memory used in 
+    //! m_lpszBuff
+    DWORD                       m_dwBuffEnd;
+    //! Indicates when the time when the pen down event was first registered
+    DWORD                       m_dwClickTime;
+    //! A handle to the currently selected font.
+    HFONT                       m_hCurFont;
+    //! A LOGFONT description of the current font.
+    LOGFONT                     m_lfCurFont;
+    //! Represents rendered words sorted by line.
+    SRTextView::SRTextLines     m_BTLines;
+    //! Indicates whether the text stream has been pre-rendered according to 
+    //! the current window layout.
+    BOOL                        m_fPreRendered;
+
+    HFONT                       m_hFontCache[BTEXT_FONT_CACHE_MAX];        
+};

Deleted: trunk/src/SwordReader_GUI/SwordReaderApp.cpp
===================================================================
--- trunk/src/SwordReader_GUI/SwordReaderApp.cpp	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SwordReaderApp.cpp	2008-04-14 03:16:21 UTC (rev 117)
@@ -1,59 +0,0 @@
-#include "SwordReaderApp.h"
-#include "SwordReaderResource.h"
-
-#include <swordce.h>
-
-
-SwordReaderApp::SwordReaderApp(HINSTANCE hInstance)
-: SRFramework::SRApp(hInstance)
-, m_confOptions(NULL)
-{
-    m_hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BIBLEREADER);
-}
-
-SwordReaderApp::~SwordReaderApp()
-{
-}
-
-WPARAM SwordReaderApp::Run()
-{
-	MSG msg;
-	bool ignoreMsgs = false;
-	DWORD ignoreTill = GetTickCount();
-
-    // Main message loop:
-	while (GetMessage(&msg, NULL, 0, 0)) 
-	{
-		if(msg.message == WM_TXT_START){ 
-			ignoreMsgs = true;
-		}else if(msg.message == WM_TXT_END){
-			ignoreMsgs = false;
-			ignoreTill = msg.time;
-		}
-		// If we have a button or key event, and we are in the ignore message 
-		// window of time we ignore this message
-		if((msg.message == WM_LBUTTONDOWN || msg.message == WM_KEYDOWN) && (ignoreMsgs || msg.time < ignoreTill))
-			continue;
-
-		if (!m_hAccelTable || !TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)) 
-		{
-			TranslateMessage(&msg);
-			DispatchMessage(&msg);
-		}
-	}
-	return msg.wParam;
-}
-
-BOOL SwordReaderApp::InitApp(int nCmdShow)
-{
-    // Create a general options file for storing options 
-	// and navigaiton history
-	const char *cwd = getWorkingDirectory();
-	char confFName[MAX_PATH];
-	_snprintf(confFName, MAX_PATH, "%s\\options.conf", cwd);
-
-	m_confOptions = new SWConfig(confFName);
-	m_confOptions->Load();
-
-	return TRUE;
-}
\ No newline at end of file

Deleted: trunk/src/SwordReader_GUI/SwordReaderApp.h
===================================================================
--- trunk/src/SwordReader_GUI/SwordReaderApp.h	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SwordReaderApp.h	2008-04-14 03:16:21 UTC (rev 117)
@@ -1,22 +0,0 @@
-#pragma once
-#include <swconfig.h>
-#include "SimpleNavigator.h"
-#include "SRFramework/SRApp.h"
-#include "SRMainFrame.h"
-//#include "ApplicationInterface.h"
-
-//#include "swordce.h"
-using namespace SRFramework;
-
-class SwordReaderApp : SRApp
-{
-public:
-    SwordReaderApp(HINSTANCE hInstance);
-    virtual ~SwordReaderApp();
-    BOOL InitApp(int nCmdShow);
-    WPARAM Run();
-private:
-        
-    SWConfig            *m_confOptions ;
-    SRMainFrame         *m_pMainFrame;
-};

Modified: trunk/src/SwordReader_GUI/SwordReader_GUI.vcproj
===================================================================
--- trunk/src/SwordReader_GUI/SwordReader_GUI.vcproj	2008-04-13 19:33:00 UTC (rev 116)
+++ trunk/src/SwordReader_GUI/SwordReader_GUI.vcproj	2008-04-14 03:16:21 UTC (rev 117)
@@ -646,9 +646,13 @@
 				>
 			</File>
 			<File
-				RelativePath=".\SwordReaderApp.cpp"
+				RelativePath=".\SRReaderApp.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\SRTextView.cpp"
+				>
+			</File>
 			<Filter
 				Name="SRFramework"
 				>
@@ -695,10 +699,14 @@
 				>
 			</File>
 			<File
-				RelativePath=".\SwordReaderApp.h"
+				RelativePath=".\SRReaderApp.h"
 				>
 			</File>
 			<File
+				RelativePath=".\SRTextView.h"
+				>
+			</File>
+			<File
 				RelativePath=".\SwordReaderResource.h"
 				>
 			</File>




More information about the sword-cvs mailing list