[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:
- // > < &
- // 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" ", 6) == 0)) ){
- dwWordIndex += m_lpszBuff[dwWordIndex] == '&' ? 6 : 1; // Did we find a 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 <br> 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 <b> element
-#define BTEXT_HTML_B_BEG 0x00000002
-//!Flag indicating we encountered a </b> element
-#define BTEXT_HTML_B_END BTEXT_HTML_MASK ^ BTEXT_HTML_B_BEG
-
-//!Flag indicating we encountered a <i> element
-#define BTEXT_HTML_I_BEG 0x00000004
-//!Flag indicating we encountered a </i> element
-#define BTEXT_HTML_I_END BTEXT_HTML_MASK ^ BTEXT_HTML_I_BEG
-
-//!Flag indicating we encountered a <sup> element
-#define BTEXT_HTML_SUP_BEG 0x00000008
-//!Flag indicating we encountered a </sup> element
-#define BTEXT_HTML_SUP_END BTEXT_HTML_MASK ^ BTEXT_HTML_SUP_BEG
-
-//!Flag indicating we encountered a <sub> element
-#define BTEXT_HTML_SUB_BEG 0x00000010
-//!Flag indicating we encountered a </sub> element
-#define BTEXT_HTML_SUB_END BTEXT_HTML_MASK ^ BTEXT_HTML_SUB_BEG
-
-//!Flag indicating we encountered a <small> element
-#define BTEXT_HTML_SMALL_BEG 0x00000020
-//!Flag indicating we encountered a </small> element
-#define BTEXT_HTML_SMALL_END BTEXT_HTML_MASK ^ BTEXT_HTML_SMALL_BEG
-
-//!Flag indicating we encountered a <font ...> element
-#define BTEXT_HTML_FONT_BEG 0x00000040
-//!Flag indicating we encountered a </font> element
-#define BTEXT_HTML_FONT_END BTEXT_HTML_MASK ^ BTEXT_HTML_FONT_BEG
-
-//!Flag indicating we encountered a <a ...> element
-#define BTEXT_HTML_A_BEG 0x00000080
-//!Flag indicating we encountered a </a> element
-#define BTEXT_HTML_A_END BTEXT_HTML_MASK ^ BTEXT_HTML_A_BEG
-
-//!Flag indicating we encountered a <p> element
-#define BTEXT_HTML_P_BEG 0x00000100
-//!Flag indicating we encountered a </p> 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<font size="-1">ORD</font> 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: <font size="+2"> -- 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 <br> 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
- <font ...> 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:
+ // > < &
+ // 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" ", 6) == 0)) ){
+ dwWordIndex += m_lpszBuff[dwWordIndex] == '&' ? 6 : 1; // Did we find a 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 <br> 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 <b> element
+#define BTEXT_HTML_B_BEG 0x00000002
+//!Flag indicating we encountered a </b> element
+#define BTEXT_HTML_B_END BTEXT_HTML_MASK ^ BTEXT_HTML_B_BEG
+
+//!Flag indicating we encountered a <i> element
+#define BTEXT_HTML_I_BEG 0x00000004
+//!Flag indicating we encountered a </i> element
+#define BTEXT_HTML_I_END BTEXT_HTML_MASK ^ BTEXT_HTML_I_BEG
+
+//!Flag indicating we encountered a <sup> element
+#define BTEXT_HTML_SUP_BEG 0x00000008
+//!Flag indicating we encountered a </sup> element
+#define BTEXT_HTML_SUP_END BTEXT_HTML_MASK ^ BTEXT_HTML_SUP_BEG
+
+//!Flag indicating we encountered a <sub> element
+#define BTEXT_HTML_SUB_BEG 0x00000010
+//!Flag indicating we encountered a </sub> element
+#define BTEXT_HTML_SUB_END BTEXT_HTML_MASK ^ BTEXT_HTML_SUB_BEG
+
+//!Flag indicating we encountered a <small> element
+#define BTEXT_HTML_SMALL_BEG 0x00000020
+//!Flag indicating we encountered a </small> element
+#define BTEXT_HTML_SMALL_END BTEXT_HTML_MASK ^ BTEXT_HTML_SMALL_BEG
+
+//!Flag indicating we encountered a <font ...> element
+#define BTEXT_HTML_FONT_BEG 0x00000040
+//!Flag indicating we encountered a </font> element
+#define BTEXT_HTML_FONT_END BTEXT_HTML_MASK ^ BTEXT_HTML_FONT_BEG
+
+//!Flag indicating we encountered a <a ...> element
+#define BTEXT_HTML_A_BEG 0x00000080
+//!Flag indicating we encountered a </a> element
+#define BTEXT_HTML_A_END BTEXT_HTML_MASK ^ BTEXT_HTML_A_BEG
+
+//!Flag indicating we encountered a <p> element
+#define BTEXT_HTML_P_BEG 0x00000100
+//!Flag indicating we encountered a </p> 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<font size="-1">ORD</font> 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: <font size="+2"> -- 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 <br> 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
+ <font ...> 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