/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bagel/hodjnpodj/hnplibs/stdafx.h"
#include "bagel/hodjnpodj/hnplibs/text.h"
namespace Bagel {
namespace HodjNPodj {
int CText::m_nTabStop = 20; // tabstops every 20 pixels
bool CText::m_bFontLoaded = false; // no font initially loaded
IMPLEMENT_DYNCREATE(CText, CObject)
/*************************************************************************
*
* CText()
*
* Parameters: none
*
* Return Value: none
*
* Description: Constructor for text class. Initialize all fields.
* SetupText must be called next to build the primary
* data objects and work areas.
*
************************************************************************/
CText::CText() {
InitializeFields(); // initialize stuff
}
/*************************************************************************
*
* CText()
*
* Parameters:
*
* CDC *pDC device context where the text will be displayed
* CPalette *pPalette palette to associate with the device context
* CRect *pRect rectangular area encompassed by the text object
* int nJustify alignment of text in the rectangle
*
* Return Value: none
*
* Description: Constructor for text class. Initialize all fields,
* and then build primary data objects and work areas.
*
************************************************************************/
CText::CText(CDC *pDC, CPalette *pPalette, CRect *pRect, int nJustify) {
InitializeFields(); // initialize stuff
SetupText(pDC, pPalette, pRect, nJustify); // build the work areas
}
/*************************************************************************
*
* ~CText()
*
* Parameters: none
*
* Return Value: none
*
* Description: Destructor for text class. Tears down all objects created
* for use by the text object; e.g. device contexts, bitmaps,
* and palettes.
*
************************************************************************/
CText::~CText() {
ReleaseContexts();
if (m_pWork != nullptr) {
(*m_pWork).DeleteObject();
delete m_pWork;
}
if (m_pBackground != nullptr) {
(*m_pBackground).DeleteObject();
delete m_pBackground;
}
}
/*************************************************************************
*
* InitializeFields
*
* Parameters: none
*
* Return Value: none
*
* Description: Initializes key fields to zero or nullptr states.
*
************************************************************************/
void CText::InitializeFields() {
m_pBackgroundDC = nullptr;
m_pBackground = nullptr;
m_pBackgroundOld = nullptr;
m_pWorkDC = nullptr;
m_pWork = nullptr;
m_pWorkOld = nullptr;
m_pPalette = nullptr;
m_pPalBackOld = nullptr;
m_pPalWorkOld = nullptr;
m_cPosition = CPoint(0, 0);
m_cSize = CSize(0, 0);
m_cRect.SetRect(0, 0, 0, 0);
m_cShadowColor = RGB(0, 0, 0);
m_nShadow_DX = 0;
m_nShadow_DY = 0;
m_bBounded = true;
m_bHaveBackground = false;
m_nJustify = JUSTIFY_LEFT;
m_pFont = nullptr;
}
/*************************************************************************
*
* SetupText()
*
* Parameters:
*
* CDC *pDC device context where the text will be displayed
* CPalette *pPalette palette to associate with the device context
* CRect *pRect rectangular area encompassed by the text object
* int nJustify alignment of text in the rectangle
*
* Return Value:
*
* bool success/failure condition
*
* Description: build primary data objects and work areas; text
* will be displayed centered within the defined
* rectangular area, hence it is up to the caller to
* ensure that the text fits (excess is cropped).
*
************************************************************************/
bool CText::SetupText(CDC *pDC, CPalette *pPalette, CRect *pRect, int nJustify) {
CPalette *pPalOld = nullptr;
m_bBounded = true; // set for bounded area painting
m_pPalette = pPalette;
m_nJustify = nJustify;
if (m_pPalette != nullptr) {
pPalOld = (*pDC).SelectPalette(m_pPalette, false);
(*pDC).RealizePalette();
}
if (!m_bFontLoaded) { // load the font if we have not
m_bFontLoaded = true; // ... done so already
AddFontResource("msserif.fon");
}
m_cRect = *pRect; // setup the fields for location
m_cSize.cx = m_cRect.right - m_cRect.left; // ... and size of the text area
m_cSize.cy = m_cRect.bottom - m_cRect.top;
m_pWork = new CBitmap(); // create a bitmap to serve as our
if ((m_pWork == nullptr) || // ... work area as we output text
!(*m_pWork).CreateCompatibleBitmap(pDC, m_cSize.cx, m_cSize.cy))
return false;
m_pBackground = new CBitmap(); // create a bitmap to hold the
if ((m_pBackground == nullptr) || // ... background we overwrite
!(*m_pBackground).CreateCompatibleBitmap(pDC, m_cSize.cx, m_cSize.cy))
return false;
if (m_pPalette != nullptr)
(*pDC).SelectPalette(pPalOld, false);
return true; // return status
}
/*************************************************************************
*
* RestoreBackground()
*
* Parameters:
*
* CDC *pDC device context where the text was displayed
*
* Return Value:
*
* bool success/failure condition
*
* Description: repaint the background art, thereby erasing the text.
*
************************************************************************/
bool CText::RestoreBackground(CDC *pDC) {
bool bSuccess = false;
CPalette *pPalOld = nullptr;
if (m_pPalette != nullptr) {
pPalOld = (*pDC).SelectPalette(m_pPalette, false);
(*pDC).RealizePalette();
}
if ((m_pBackground != nullptr) &&
SetupContexts(pDC)) {
bSuccess = (*pDC).BitBlt( // simply splat the background art
m_cRect.left, // ... back where it came from
m_cRect.top,
m_cSize.cx,
m_cSize.cy,
m_pBackgroundDC,
0,
0,
SRCCOPY);
ReleaseContexts();
}
if (m_pPalette != nullptr)
(*pDC).SelectPalette(pPalOld, false);
return bSuccess;
}
/*************************************************************************
*
* DisplayString()
*
* Parameters:
*
* CDC *pDC device context where the text was displayed
* char *pszText point to text string to be displayed
* int nSize point size of the text to be used
* int nWeight weighting of the font (FW_ identifier)
* COLORREF crColor color that the text will be
*
* Return Value:
*
* bool success/failure condition
*
* Description: display a text string, formatted in the text object area.
*
************************************************************************/
bool CText::DisplayString(CDC *pDC, const char *pszText, const int nSize, const int nWeight, const COLORREF crColor) {
bool bSuccess;
m_cTextColor = crColor;
bSuccess = DisplayText(pDC, pszText, nSize, nWeight, false);
return bSuccess;
}
/*************************************************************************
*
* DisplayShadowedString()
*
* Parameters:
*
* CDC *pDC evice context where the text was displayed
* char *pszText point to text string to be displayed
* int nSize point size of the text to be used
* int nWeight weighting of the font (FW_ identifier)
* COLORREF crColor color that the text will be
* COLORREF crShadow color that the text's shadow will be
*
* Return Value:
*
* bool success/failure condition
*
* Description: display a shadowed text string, formatted in the text object area.
*
************************************************************************/
bool CText::DisplayShadowedString(CDC *pDC, const char *pszText, const int nSize, const int nWeight, const COLORREF crColor, const COLORREF crShadow, const int nDX, const int nDY) {
bool bSuccess;
m_cTextColor = crColor;
m_cShadowColor = crShadow;
m_nShadow_DX = nDX;
m_nShadow_DY = nDY;
bSuccess = DisplayText(pDC, pszText, nSize, nWeight, true);
return bSuccess;
}
/*************************************************************************
*
* DisplayText()
*
* Parameters:
*
* CDC *pDC evice context where the text was displayed
* char *pszText point to text string to be displayed
* int nSize point size of the text to be used
* int nWeight weighting of the font (FW_ identifier)
* bool bShadowed whether the text is shadowed
*
* Return Value:
*
* bool success/failure condition
*
* Description: display a text string, formatted in the text object area.
*
************************************************************************/
bool CText::DisplayText(CDC *pDC, const char *pszText, const int nSize, const int nWeight, const bool bShadowed) {
CFont *pFontOld = nullptr; // font that was mapped to the context
CSize textInfo; // font info about the text to be displayed
TEXTMETRIC fontMetrics; // info about the font itself
CRect unionRect;
CRect newRect;
CPalette *pPalOld = nullptr;
if (m_pPalette != nullptr) {
pPalOld = (*pDC).SelectPalette(m_pPalette, false);
(*pDC).RealizePalette();
}
if (!SetupContexts(pDC)) // setup the device contexts and map in
return false; // ... the various bitmaps
if (!m_bHaveBackground) {
(*m_pBackgroundDC).BitBlt( // grab what the background looks like
0, // ... putting it in the work area
0,
m_cSize.cx,
m_cSize.cy,
pDC,
m_cRect.left,
m_cRect.top,
SRCCOPY);
m_bHaveBackground = true;
}
// Create an instance of the specified font
m_pFont = new CFont();
(*m_pFont).CreateFont(nSize, 0, 0, 0, nWeight,
0, 0, 0, 0, OUT_RASTER_PRECIS, 0,
PROOF_QUALITY, FF_ROMAN, "MS Sans Serif");
pFontOld = (*m_pWorkDC).SelectObject(m_pFont); // select it into our context
(*m_pWorkDC).GetTextMetrics(&fontMetrics); // get some info about the font
(*m_pWorkDC).SetBkMode(TRANSPARENT); // make the text overlay transparently
textInfo = (*m_pWorkDC).GetTextExtent(pszText, strlen(pszText)); // get the area spanned by the text
(*m_pWorkDC).BitBlt( // copy the saved background to the work area
0,
0,
m_cSize.cx,
m_cSize.cy,
m_pBackgroundDC,
0,
0,
SRCCOPY);
m_cPosition.y = (m_cSize.cy - textInfo.cy) >> 1;
switch (m_nJustify) {
case JUSTIFY_CENTER:
m_cPosition.x = (m_cSize.cx - textInfo.cx) >> 1;
break;
case JUSTIFY_LEFT:
m_cPosition.x = 0;
break;
case JUSTIFY_RIGHT:
m_cPosition.x = m_cSize.cx - textInfo.cx;
}
m_cPosition.x = MAX(m_cPosition.x, 0);
m_cPosition.y = MAX(m_cPosition.y, 0);
if (bShadowed) {
(*m_pWorkDC).SetTextColor(m_cShadowColor); // set the color of the shadow
(*m_pWorkDC).TabbedTextOut( // zap the shadow to the work area
m_cPosition.x + m_nShadow_DX,
m_cPosition.y + m_nShadow_DY,
(const char *)pszText,
strlen(pszText),
1, &m_nTabStop, 0);
}
(*m_pWorkDC).SetTextColor(m_cTextColor); // set the color of the text
(*m_pWorkDC).TabbedTextOut( // zap the text to the work area
m_cPosition.x,
m_cPosition.y,
(const char *)pszText,
strlen(pszText),
1, &m_nTabStop, 0);
(*m_pWorkDC).SelectObject(pFontOld); // map out the font
delete m_pFont; // release the font instance
m_pFont = nullptr;
(*pDC).BitBlt( // copy the result to the destination context
m_cRect.left,
m_cRect.top,
m_cSize.cx,
m_cSize.cy,
m_pWorkDC,
0,
0,
SRCCOPY);
ReleaseContexts();
if (m_pPalette != nullptr)
(*pDC).SelectPalette(pPalOld, false);
return true;
}
/*************************************************************************
*
* SetupContexts()
*
* Parameters:
*
* CDC *pDC device context where the text is displayed
*
* Return Value:
*
* bool success/failure condition
*
* Description: create compatible device contexts for the background
* and work areas, and map in their bitmaps.
*
************************************************************************/
bool CText::SetupContexts(CDC *pDC) {
if (m_pWorkDC == nullptr) {
m_pWorkDC = new CDC();
if ((m_pWorkDC == nullptr) ||
!(*m_pWorkDC).CreateCompatibleDC(pDC))
return false;
if (m_pPalette != nullptr) {
m_pPalWorkOld = (*m_pWorkDC).SelectPalette(m_pPalette, false);
(*m_pWorkDC).RealizePalette();
}
m_pWorkOld = (*m_pWorkDC).SelectObject(m_pWork);
if (m_pWorkOld == nullptr)
return false;
}
if (m_pBackgroundDC == nullptr) {
m_pBackgroundDC = new CDC();
if ((m_pBackgroundDC == nullptr) ||
!(*m_pBackgroundDC).CreateCompatibleDC(pDC))
return false;
if (m_pPalette != nullptr) {
m_pPalBackOld = (*m_pBackgroundDC).SelectPalette(m_pPalette, false);
(*m_pBackgroundDC).RealizePalette();
}
m_pBackgroundOld = (*m_pBackgroundDC).SelectObject(m_pBackground);
if (m_pBackgroundOld == nullptr)
return false;
}
return true;
}
/*************************************************************************
*
* ReleaseContexts()
*
* Parameters: none
*
* Return Value: none
*
* Description: release all device contexts after mapping out palettes
* and bitmaps.
*
************************************************************************/
void CText::ReleaseContexts() {
if (m_pWorkOld != nullptr) {
(*m_pWorkDC).SelectObject(m_pWorkOld);
m_pWorkOld = nullptr;
}
if (m_pBackgroundOld != nullptr) {
(*m_pBackgroundDC).SelectObject(m_pBackgroundOld);
m_pBackgroundOld = nullptr;
}
if (m_pPalWorkOld != nullptr) {
(*m_pWorkDC).SelectPalette(m_pPalWorkOld, false);
m_pPalWorkOld = nullptr;
}
if (m_pPalBackOld != nullptr) {
(*m_pBackgroundDC).SelectPalette(m_pPalBackOld, false);
m_pPalBackOld = nullptr;
}
if (m_pWorkDC != nullptr) {
(*m_pWorkDC).DeleteDC();
delete m_pWorkDC;
m_pWorkDC = nullptr;
}
if (m_pBackgroundDC != nullptr) {
(*m_pBackgroundDC).DeleteDC();
delete m_pBackgroundDC;
m_pBackgroundDC = nullptr;
}
}
} // namespace HodjNPodj
} // namespace Bagel