/************************************************************************************** TDE_DRAWTEXT.C ***************************************************************************************/ #include "tde.h" /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_bIsBreakChar VERSION : 1.0 / Yan AIM : Tells if a character can be a breakpoint of the line, in DT_WORDBREAK mode **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ BOOL TDE_bIsBreakChar (char c) { // Any control character breaks the word if (c < 0x20) return TRUE; // ' ' and '-' break the word. Other characters don't. switch (c) { case ' ': case '-': return TRUE; break; default: return FALSE; break; } } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_xGetVerticalOffset VERSION : 1.0 / Yan AIM : Get the first vertical offset and the maximal number of lines for a character string **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ TDE_tdxValue TDE_xGetVerticalOffset (TDE_tdsTextBox *pTextBox, long *p_lNbLines) { unsigned long ulStyle; // Format attributes TDE_tdxValue xTopRect; // Top of the format rectangle TDE_tdxValue xBottomRect; // Bottom of the format rectangle TDE_tdxValue xHMax; // Maximum high part in the font TDE_tdxValue xVAMax; // Maximum low part (vertical alignment) in the font TDE_tdsBitmapFont *pFont; // Pointer to the bitmap font #ifdef TDE_DEBUG // Tests for reliability if (p_lNbLines == NULL) // NULL pointer to number of lines return 0; if (pTextBox == NULL) // NULL pointer to text box { *p_lNbLines = 0; return 0; } if (pTextBox->eFontType != TDE_eFT_BITMAP) // Non-bitmap font { *p_lNbLines = 0; return 0; } if (pTextBox->p_stBFont == NULL) // NULL pointer to bitmap font { *p_lNbLines = 0; return 0; } if (pTextBox->p_stFormatRect == NULL) // NULL pointer to format rectangle { *p_lNbLines = 0; return 0; } #endif // Short cuts ulStyle = pTextBox->ulStyle; xTopRect = pTextBox->p_stFormatRect->tdsSommet[0].xY; xBottomRect = pTextBox->p_stFormatRect->tdsSommet[2].xY; pFont = pTextBox->p_stBFont; xHMax = (TDE_tdxValue)pFont->usHMax; xVAMax = (TDE_tdxValue)pFont->usVAMax; // Is the format rectangle high enough for at least one line ? if ((xBottomRect-xTopRect) < (xVAMax+xHMax)) { *p_lNbLines = 0; return 0; } if (ulStyle & DT_VCENTER) // Vertically centered, single line { *p_lNbLines = 1; return ((xBottomRect + xTopRect + (xHMax + xVAMax)*0.5) * 0.5); } else if (ulStyle & DT_BOTTOM) // Bottom, single line { *p_lNbLines = 1; return (xBottomRect - xVAMax); } else // Top (default), either single or multiple line(s) { if (ulStyle & DT_SINGLELINE) // Single line *p_lNbLines = 1; else // Multiple lines *p_lNbLines = (xBottomRect-xTopRect)/(xVAMax+xHMax); return (xTopRect + xHMax); } } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_xGetHorizontalOffset VERSION : 1.0 / Yan AIM : Get the horizontal offset and the number of characters for the current line of a character string **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ TDE_tdxValue TDE_xGetHorizontalOffset (TDE_tdsTextBox *pTextBox, long lStartIndex, long *p_lEndIndex) { unsigned long ulStyle; // Format attributes TDE_tdxValue xLeftRect; // Left of the format rectangle TDE_tdxValue xRightRect; // Right of the format rectangle TDE_tdxValue xRectWidth; // Width of the format rectangle TDE_tdxValue xStrWidth; // Width of the text-line TDE_tdxValue xSpacing; // Horizontal spacing between two characters TDE_tdsBitmapFont *pFont; // Pointer to the bitmap font TDE_tdsBitmapLetter **pLetter; // Pointer to the array of pointers to bitmap letters char *pString; // Text string long i, j; // Counters unsigned char c; // Current char BOOL bIsThereABreakChar; #ifdef TDE_DEBUG // Tests for reliability if (p_lNbChar == NULL) // NULL pointer to number of characters return 0; if (pTextBox == NULL) // NULL pointer to text box { *p_lNbChar = 0; return 0; } if (pTextBox->eFontType != TDE_eFT_BITMAP) // Non-bitmap font { *p_lNbChar = 0; return 0; } if (pTextBox->p_stBFont == NULL) // NULL pointer to bitmap font { *p_lNbChar = 0; return 0; } if (pTextBox->p_stFormatRect == NULL) // NULL pointer to format rectangle { *p_lNbChar = 0; return 0; } #endif // Short cuts pFont = pTextBox->p_stBFont; // Pointer to the bitmap font pLetter = pFont->p_stMBLetter; // Pointer to the array of bitmap letters xSpacing = (TDE_tdxValue) pFont->usHorzSep; // Horizontal spacing between two characters pString = pTextBox->p_cText; // Text string ulStyle = pTextBox->ulStyle; // Format attributes xLeftRect = pTextBox->p_stFormatRect->tdsSommet[0].xX; // Left of format rectangle xRightRect = pTextBox->p_stFormatRect->tdsSommet[1].xX; // Right of format rectangle xRectWidth = xRightRect - xLeftRect + xSpacing; // Width of format rectangle xStrWidth = 0; // Loop through the string until it exceeds the rect width // or it is finished or there is a carriage return for (i=lStartIndex; (pString[i]!='\0') && // End of string (pString[i]!=13) && // Carriage return (xStrWidthstBLetter.p_stSprite->stDim.xX + xSpacing; } // If carriage return, take also the line feed if (pString[i] == 13) if (pString[i+1] == 10) i++; // If it exceeds the rect width, remove the last character if (xStrWidth>xRectWidth) { i--; if (c < TDE_kNBLETTERS) if (pLetter[c]) xStrWidth -= pLetter[c]->stBLetter.p_stSprite->stDim.xX + xSpacing; } // If we must keep word's integrity, do it ! if (ulStyle & DT_WORDBREAK) { // Look for a break char in the line // (if there is no break char, we can't process // DT_WORDBREAK) bIsThereABreakChar = FALSE; for (j=lStartIndex; jstBLetter.p_stSprite->stDim.xX + xSpacing; } // Remove from the width (but not from the count) // spaces before end on line (if any) if (pLetter[' ']) { for (j=1; (pString[i-j]==' ') && ((i-j)>lStartIndex); j++) { xStrWidth -= pLetter[' ']->stBLetter.p_stSprite->stDim.xX + xSpacing; } if ((i-j) == lStartIndex) if (pString[i-j]==' ') xStrWidth -= pLetter[' ']->stBLetter.p_stSprite->stDim.xX + xSpacing; } } // Add to the count (but not to the width) spaces after // end of line (if any) while (pString[i] == ' ') i++; } // Set number of characters *p_lEndIndex = i; // Compute horizontal offset if (ulStyle & DT_RIGHT) return (xRightRect - xStrWidth + xSpacing); else if (ulStyle & DT_CENTER) return xLeftRect + 0.5 * (xRectWidth - xStrWidth); else return xLeftRect; } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_vDrawBitmapText VERSION : 2.0 / Yan 1.0 / Franck AIM : Bitmap font rendering. **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ void TDE_vDrawBitmapText (GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsTextBox *pTextBox) { TDE_tdsBitmapFont *pFont; // Pointer to the bitmap font TDE_tdsBitmapLetter **pLetter; // Pointer to the array of pointers to bitmap letters long lNbLines; // Number of displayable lines long lCharIndex; // Char index in the string long lEndCharIndex; // Char index of end of current line in the string long lLineIndex; // Line index in the string char *pString; // Text string char cColorMode; // Color mode (normal or reverse) TDE_tdxValue xHOffset, xVOffset; // Horizontal and vertical offsets TDE_tdxValue xHSpacing; // Horizontal spacing between two characters TDE_tdxValue xHeightLine; // Height of a line TDE_tdxValue xHalfWidthChar; // Half of the width of current char TDE_tdeCursorType eCursorType; // Type of the cursor (insert, overwrite, no cursor) long lCursorIndex; // Position of the cursor in the string long i; // Counter unsigned char c; // Current character #ifdef TDE_DEBUG // Tests for reliability if (p_stViewAttrib == NULL) // NULL pointer to viewport attributes return; if (pTextBox == NULL) // NULL pointer to text box return; if (pTextBox->eFontType != TDE_eFT_BITMAP) // Not a bitmap font return; if (pTextBox->p_stBFont == NULL) // NULL pointer to font return; #endif // Shortcuts pString = pTextBox->p_cText; // Pointer to the string if (pString == NULL) // Test if the string is NULL return; cColorMode = pTextBox->cColorMode; // Color mode (normal or reverse) lCursorIndex = pTextBox->lCursorPosition; // Cursor position eCursorType = pTextBox->eCursorType; // Cursor type pFont = pTextBox->p_stBFont; // Pointer to the font pLetter = pFont->p_stMBLetter; // Pointer to the array of bitmap letters xHSpacing = (TDE_tdxValue) pFont->usHorzSep; // Horizontal spacing between two characters xHeightLine = (TDE_tdxValue) (pFont->usVertSep + pFont->usHMax + pFont->usVAMax); // Height of a line // Initialize the index at the beginning of the string lCharIndex = 0; // Compute initial vertical offset xVOffset = TDE_xGetVerticalOffset (pTextBox, &lNbLines); // Loop on the displayable lines (while the string is not terminated) for (lLineIndex=0; (lLineIndexstBLetter.p_stSprite->stDim.xX) * 0.5; // Move horizontally to the center of the letter xHOffset += xHalfWidthChar; // Set coordinates of the center of the letter pLetter[c]->stBLetter.stModifiedMatrix.stTranslateVertex.xX = xHOffset; pLetter[c]->stBLetter.stModifiedMatrix.stTranslateVertex.xY = xVOffset - 0.5*(pLetter[c]->stBLetter.p_stSprite->stDim.xY) + (TDE_tdxValue)(pLetter[c]->usVAlign); // Different cases depending on the type of cursor switch (eCursorType) { // No cursor case TDE_eCT_NOCURSOR: // Draw the character the normal way if (cColorMode == 0) // Normal color mode { TDE_vFastDrawMemorySpriteAbsolute (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } else // Negative color mode { TDE_vFastDrawMemorySpriteAbsoluteInvert (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } break; // Draw overwrite cursor case TDE_eCT_OVERWRITE: // If the current position is the position of the cursor... if (i == lCursorIndex) { // If the flicking state is set as 'show'... if (TDE_g_cFlick) { // Draw the character inverted and without transparency pLetter[c]->stBLetter.p_stSprite->c_NZ = 0; TDE_vFastDrawMemorySpriteAbsoluteInvert (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); pLetter[c]->stBLetter.p_stSprite->c_NZ = 1; } // If the flicking state is set as 'hide'... else { // Draw the character the normal way TDE_vFastDrawMemorySpriteAbsolute (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } } // If the current position is not the position of the cursor, else { // Draw the character the normal way if (cColorMode == 0) // Normal color mode { TDE_vFastDrawMemorySpriteAbsolute (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } else // Negative color mode { TDE_vFastDrawMemorySpriteAbsoluteInvert (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } } break; // Draw insert cursor case TDE_eCT_INSERT: // Draw the character the normal way if (cColorMode == 0) // Normal color mode { TDE_vFastDrawMemorySpriteAbsolute (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } else // Negative color mode { TDE_vFastDrawMemorySpriteAbsoluteInvert (p_stViewAttrib, &(pLetter[c]->stBLetter), pTextBox->p_stClipRect); } // If the current position is the position of the cursor... if (i == lCursorIndex) { // If the flicking state is set as 'show'... if (TDE_g_cFlick) { // Set coordinates of the insert cursor pLetter[TDE_kINSERTCURSOR]->stBLetter.stModifiedMatrix.stTranslateVertex.xX = xHOffset - xHalfWidthChar; pLetter[TDE_kINSERTCURSOR]->stBLetter.stModifiedMatrix.stTranslateVertex.xY = xVOffset - 0.5*(pLetter[TDE_kINSERTCURSOR]->stBLetter.p_stSprite->stDim.xY) + (TDE_tdxValue)(pLetter[TDE_kINSERTCURSOR]->usVAlign); // Draw the insert cursor TDE_vFastDrawMemorySpriteAbsolute (p_stViewAttrib, &(pLetter[TDE_kINSERTCURSOR]->stBLetter), pTextBox->p_stClipRect); } } break; default: break; } // switch // Move horizontally to the beginning of next letter xHOffset += xHalfWidthChar + xHSpacing; } // if the current character is defined } // loop on the characters in the current line // Update current character-index and vertical offset lCharIndex = lEndCharIndex; xVOffset += xHeightLine; } // loop on each line } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_vDrawBitmapTextWithRectAdjustment VERSION : 2.0 / Yan 1.0 / Franck AIM : Set the height of a format rect depending on what you want to put into .... **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ void TDE_vTDE_vAdjustTextBoxFormatRect( TDE_tdsTextBox *pTextBox) { TDE_tdsBitmapFont *pFont; // Pointer to the bitmap font long lNbLines; // Number of displayable lines long lCharIndex; // Char index in the string long lEndCharIndex; // Char index of end of current line in the string char *pString; // Text string TDE_tdxValue xHOffset; TDE_tdxValue xHeightLine; // Height of a line long lTextLenght; #ifdef TDE_DEBUG // Tests for reliability if (p_stViewAttrib == NULL) // NULL pointer to viewport attributes return; if (pTextBox == NULL) // NULL pointer to text box return; if (pTextBox->eFontType != TDE_eFT_BITMAP) // Not a bitmap font return; if (pTextBox->p_stBFont == NULL) // NULL pointer to font return; #endif // Shortcuts pString = pTextBox->p_cText; // Pointer to the string if (pString == NULL) // Test if the string is NULL return; lTextLenght = strlen(pString); if ( lTextLenght == 0 ) return; pFont = pTextBox->p_stBFont; // Pointer to the font xHeightLine = (TDE_tdxValue) (pFont->usVertSep + pFont->usHMax + pFont->usVAMax); // Height of a line lCharIndex = 0; lNbLines = 0; do { // Compute initial horizontal offset for the current line xHOffset = TDE_xGetHorizontalOffset (pTextBox, lCharIndex, &lEndCharIndex); // Update current character-index and vertical offset lCharIndex = lEndCharIndex; lNbLines++; }while ( lEndCharIndexp_stFormatRect->tdsSommet[2].xY = pTextBox->p_stFormatRect->tdsSommet[0].xY + (lNbLines*xHeightLine); pTextBox->p_stFormatRect->tdsSommet[3].xY = pTextBox->p_stFormatRect->tdsSommet[2].xY; } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_vDrawTrueTypeText VERSION : 2.0 / Yan 1.0 / Franck AIM : True type font rendering. **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ void TDE_vDrawTrueTypeText (GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsTextBox *pTextBox) { char *pString; // Text string TDE_tdsRect *pFormatRect; // Pointer to format rectangle (TDE structure) TDE_tdsRect *pClipRect; // Pointer to clipping rectangle (TDE structure) RECT stFormatRect; // Format rectangle (WINDOWS structure) RECT stClipRect; // Clipping rectangle (WINDOWS structure) LPDIRECTDRAWSURFACE lpBackSurf; // Direct draw surface on which we must draw HDC hdc = NULL; // Handle to DC (Display Context) TDE_tdsTrueTypeFont *pFont; // Pointer to the true type font #ifdef TDE_DEBUG // Tests for reliability if (p_stViewAttrib == NULL) // NULL pointer to viewport attributes return; if (pTextBox == NULL) // NULL pointer to text box return; if (pTextBox->eFontType != TDE_eFT_TRUETYPE)// Not a true type font return; if (pTextBox->p_stTFont == NULL) // NULL pointer to font return; if (pTextBox->p_stFormatRect == NULL) // NULL pointer to format rectangle return; if (pTextBox->p_stClipRect == NULL) // NULL pointer to clipping rectangle return; #endif // Pointer to the string pString = pTextBox->p_cText; // Pointer to the string if (pString == NULL) // Test if the string is NULL return; pFont = pTextBox->p_stTFont; // Format rectangle pFormatRect = pTextBox->p_stFormatRect; stFormatRect.top = (long) pFormatRect->tdsSommet[0].xY; stFormatRect.bottom = (long) pFormatRect->tdsSommet[2].xY; stFormatRect.left = (long) pFormatRect->tdsSommet[0].xX; stFormatRect.right = (long) pFormatRect->tdsSommet[1].xX; // Clipping rectangle pClipRect = pTextBox->p_stClipRect; stClipRect.top = (long) pClipRect->tdsSommet[0].xY; stClipRect.bottom = (long) pClipRect->tdsSommet[2].xY; stClipRect.left = (long) pClipRect->tdsSommet[0].xX; stClipRect.right = (long) pClipRect->tdsSommet[1].xX; // Get DC lpBackSurf = (LPDIRECTDRAWSURFACE)p_stViewAttrib->p_vReserved; IDirectDrawSurface_GetDC(lpBackSurf, &hdc); if (!hdc) return; // Set boundaries // SetBoundsRect (hdc, &stClipRect, DCB_RESET|DCB_ACCUMULATE); // Configure the DC to render text SetMapMode (hdc, MM_TEXT); SetBkMode (hdc, TRANSPARENT); // Select the font SelectObject (hdc, (HGDIOBJ)pFont->hFont); // Select the color if (pTextBox->cColorMode == 0) // Normal color mode SetTextColor (hdc, pFont->lColor); else // Reverse color mode SetTextColor (hdc, ~(pFont->lColor)); // Let Windows do the job for us DrawText (hdc, pTextBox->p_cText, -1, &stFormatRect, pTextBox->ulStyle); // Release DC IDirectDrawSurface_ReleaseDC(lpBackSurf, hdc); } /**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~** NAME : TDE_vDrawTextInABox VERSION : 2.0 / Yan 1.0 / Franck AIM : Display a text in a box. Formatting flags : DT_BOTTOM DT_CENTER DT_LEFT DT_RIGHT DT_SINGLELINE DT_TOP DT_VCENTER DT_WORDBREAK **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~**/ void TDE_vDrawTextInABox (GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsSuperObject *p_stSuperObject, BOOL bViewPortLocked) { TDE_tdsTextBox *pTextBox; // Pointer to the text box #ifdef TDE_DEBUG // Tests for reliability if (p_stSuperObject == NULL) // NULL pointer to super object return; if (p_stViewAttrib == NULL) // NULL pointer to viewport attributes return; if (p_stSuperObject->eType != TDE_eOT_TEXTBOX) // The super object is not a text box return; if (p_stSuperObject->p_stTextBox == NULL) // NULL pointer to text box return; #endif pTextBox = p_stSuperObject->p_stTextBox; switch (pTextBox->eFontType) { case TDE_eFT_BITMAP: if (bViewPortLocked) // Viewport must be locked TDE_vDrawBitmapText (p_stViewAttrib, pTextBox); break; case TDE_eFT_TRUETYPE: if (!bViewPortLocked) // Viewport must not be locked TDE_vDrawTrueTypeText (p_stViewAttrib, pTextBox); break; } }