📄 sitetext.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
#include "hxcom.h"
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxmap.h"
#include "hxslist.h"
#include "ihxpckts.h"
#include "hxwin.h"
#include "hxengin.h"
#include "hxsite2.h"
#include "chxxtype.h"
#include "hxvctrl.h"
#include "hxvsurf.h"
#include "hxcodec.h"
#include "surface.h"
#include "vidosurf.h"
#include "chxpckts.h"
#include "hxevent.h"
#include "sitetext.h"
#include "platform/mac/hx_moreprocesses.h"
#define DEF_TEXT_HEIGHT 12
#define POINTS_TO_PIXELS 1.5
#define DEF_TEXT_GUTTER 1.2
#define DEF_STAT_HEIGHT (int)((double)DEF_TEXT_HEIGHT * POINTS_TO_PIXELS * DEF_TEXT_GUTTER)
#define DEF_HORZ_GUTTER 4
#define ELIPSIS "..."
#define ELIPSIS_LEN 3
CHXSiteStatusText::CHXSiteStatusText()
: m_lRefCount(0)
, m_pSite(NULL)
, m_pParentSite(NULL)
, m_rgbBkgndColor(0x00008000)
, m_rgbTextColor(0x0000FF00)
, m_pStatusImage(NULL)
{
memset(&m_statusPos, 0, sizeof(HXxPoint));
memset(&m_statusSize, 0, sizeof(HXxSize));
}
CHXSiteStatusText::~CHXSiteStatusText()
{
Destroy(); // make sure we cleanup
}
HX_RESULT
CHXSiteStatusText::Create(IHXSite* pSite)
{
IHXSite* pChildSite = NULL;
HX_RESULT hr = HXR_FAIL;
HX_ASSERT(pSite);
HX_ASSERT(!m_pSite);
// keep a ref while we use the parent site
pSite->AddRef();
if (pSite->CreateChild(pChildSite) == HXR_OK)
{
if (pChildSite->AttachUser(this) == HXR_OK)
{
m_pParentSite = pSite;
HX_ASSERT(m_StatusText.IsEmpty());
if (m_StatusText.IsEmpty())
{
Hide(); // keep hidden until we have status text
}
else
{
Show();
}
UpdatePosition();
hr = HXR_OK;
}
HX_RELEASE(pChildSite);
}
// release if we failed
if (hr != HXR_OK)
{
HX_RELEASE(pSite);
}
return hr;
}
HX_RESULT
CHXSiteStatusText::Destroy()
{
if (m_pSite)
{
if (m_pParentSite)
{
m_pParentSite->DestroyChild(m_pSite);
}
// DetachUser will call DetachSite, which will release m_pSite
m_pSite->DetachUser();
}
HX_RELEASE(m_pParentSite);
HX_DELETE(m_pStatusImage);
return HXR_OK;
}
HX_RESULT
CHXSiteStatusText::Show()
{
IHXSite2* pSite2 = NULL;
if (GetIHXSite2(pSite2) == HXR_OK)
{
pSite2->ShowSite(TRUE);
HX_RELEASE(pSite2);
}
return HXR_OK;
}
HX_RESULT
CHXSiteStatusText::Hide()
{
IHXSite2* pSite2 = NULL;
if (GetIHXSite2(pSite2) == HXR_OK)
{
pSite2->ShowSite(FALSE);
HX_RELEASE(pSite2);
}
return HXR_OK;
}
HX_RESULT
CHXSiteStatusText::ParentChangedSize()
{
UpdatePosition();
return HXR_OK;
}
HX_RESULT
CHXSiteStatusText::BringToTop()
{
IHXSite2* pSite2 = NULL;
if (GetIHXSite2(pSite2) == HXR_OK)
{
pSite2->MoveSiteToTop();
HX_RELEASE(pSite2);
}
return HXR_OK;
}
HX_RESULT
CHXSiteStatusText::UpdatePosition()
{
HX_RESULT hr = HXR_FAIL;
HXxPoint parentPos;
HXxSize parentSize;
if (m_pParentSite && m_pSite)
{
if (m_pParentSite->GetSize(parentSize) == HXR_OK &&
m_pParentSite->GetPosition(parentPos) == HXR_OK)
{
// call platform-specific code to adjust the position & size
// of our site (since fonts may require different heights on
// different platforms
_AdjustPosition(&parentPos, &parentSize);
m_pSite->SetPosition(m_statusPos);
m_pSite->SetSize(m_statusSize);
}
}
return HXR_OK;
}
void
CHXSiteStatusText::SetStatusText(const char* pText)
{
CHXString oldStatusText = m_StatusText;
m_StatusText = pText;
if (m_StatusText != oldStatusText)
{
if (m_StatusText.IsEmpty())
{
Hide();
}
else
{
if (m_pSite)
{
m_pSite->ForceRedraw();
}
if (oldStatusText.IsEmpty())
{
BringToTop();
Show();
}
}
}
}
STDMETHODIMP
CHXSiteStatusText::QueryInterface(REFIID riid, void** ppvObj)
{
if (riid == IID_IHXSiteUser)
{
*ppvObj = (IHXSiteUser*)this;
AddRef();
return HXR_OK;
}
if (riid == IID_IHXSiteWatcher)
{
*ppvObj = (IHXSiteWatcher*)this;
AddRef();
return HXR_OK;
}
else if (riid == IID_IUnknown)
{
*ppvObj = (IUnknown*)(IHXSiteUser*)this;
AddRef();
return HXR_OK;
}
return HXR_FAIL;
}
STDMETHODIMP_(ULONG32)
CHXSiteStatusText::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG32)
CHXSiteStatusText::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
STDMETHODIMP
CHXSiteStatusText::AttachSite(IHXSite* /*IN*/ pSite)
{
HX_RESULT hr = HXR_FAIL;
if (!m_pSite)
{
m_pSite = pSite;
m_pSite->AddRef();
hr = HXR_OK;
}
return hr;
}
STDMETHODIMP
CHXSiteStatusText::DetachSite()
{
HX_RESULT hr = HXR_FAIL;
if (m_pSite)
{
HX_RELEASE(m_pSite);
hr = HXR_OK;
}
return hr;
}
STDMETHODIMP
CHXSiteStatusText::HandleEvent(HXxEvent* /*IN*/ pEvent)
{
HX_RESULT hr = HXR_OK;
if (pEvent->event == HX_SURFACE_UPDATE)
{
_DrawStatusText(pEvent);
}
return hr;
}
STDMETHODIMP_(BOOL)
CHXSiteStatusText::NeedsWindowedSites()
{
return false;
}
HX_RESULT
CHXSiteStatusText::GetIHXSite2(REF(IHXSite2*) pSite2)
{
HX_RESULT hr = HXR_FAIL;
if (m_pSite)
{
hr = m_pSite->QueryInterface(IID_IHXSite2, (void**)&pSite2);
}
return hr;
}
void ConvertHXxColorToRGBColor(HXxColor& pnx, RGBColor& rgb)
{
unsigned short red, blue, green;
red = ((unsigned char*)&pnx)[1];
green = ((unsigned char*)&pnx)[2];
blue = ((unsigned char*)&pnx)[3];
rgb.red = red | (red << 8);
rgb.green = green | (green << 8);
rgb.blue = blue | (blue << 8);
}
HX_RESULT
CHXSiteStatusText::_DrawStatusText(HXxEvent* pEvent)
{
// this function is called internally and this will never be null
HX_ASSERT(pEvent);
// XXXNH: the status text does not support drawing at interrupt time
if (!IsMacInCooperativeThread())
{
return HXR_FAIL;
}
pEvent->handled = TRUE;
pEvent->result = HXR_OK;
// The rect for our status message
HXxSize sz;
m_pSite->GetSize(sz);
Rect theRect;
::SetRect(&theRect, 0, 0, sz.cx, sz.cy);
if (!m_pStatusImage || (sizeof(m_pStatusImage) < m_statusSize.cy * m_statusSize.cx * 4))
{
HX_DELETE(m_pStatusImage);
m_pStatusImage = new BYTE[m_statusSize.cy * m_statusSize.cx * 4];
}
// create offscreen graphics world
GWorldPtr offscreenGWorld;
PixMapHandle hPixMap = NULL;
long theRowBytes = sz.cx * 4;
OSType thePixelFormat = k32BGRAPixelFormat;
OSErr err = noErr;
err = NewGWorldFromPtr(
&offscreenGWorld,
thePixelFormat,
&theRect,
NULL, // color table
NULL, // GDevice handle
0, // flags
(Ptr)m_pStatusImage,
theRowBytes);
HX_ASSERT(err == noErr);
// set offscreen graphics world:
GDHandle hGDSave;
CGrafPtr pCGrafSave;
::GetGWorld(&pCGrafSave, &hGDSave);
::SetGWorld(offscreenGWorld, NULL);
// update clip region to this site's bounds
RgnHandle theNewClipRgn = ::NewRgn();
::RectRgn(theNewClipRgn, &theRect);
::SetClip(theNewClipRgn);
::DisposeRgn(theNewClipRgn);
// convert our fg & bg colors
RGBColor bgColor;
ConvertHXxColorToRGBColor(m_rgbBkgndColor, bgColor);
RGBColor fgColor;
ConvertHXxColorToRGBColor(m_rgbTextColor, fgColor);
// Draw the background rect
::RGBBackColor(&bgColor);
::RGBForeColor(&bgColor);
::PaintRect(&theRect);
::RGBBackColor(&bgColor);
::RGBForeColor(&fgColor);
// pick the font, center it and draw it
short nFontId = 0;
GetFNum("\pHelvetica", &nFontId);
TextFont(nFontId);
int nSize = DEF_TEXT_HEIGHT;
TextSize(nSize);
// keep a local copy of status text in case we need to add an elipsis
CHXString statusText = m_StatusText;
int nStrLen = statusText.GetLength();
const char* pStr = statusText;
int nElipsisLen = TextWidth(ELIPSIS, 0, ELIPSIS_LEN);
int nWidth = TextWidth(pStr, 0, nStrLen);
while (nWidth > m_statusSize.cx - DEF_HORZ_GUTTER && nStrLen > 0)
{
nStrLen--;
nWidth = TextWidth(pStr, 0, nStrLen) + nElipsisLen;
}
if (nStrLen < statusText.GetLength())
{
statusText = statusText.Left(nStrLen);
statusText += ELIPSIS;
nStrLen += ELIPSIS_LEN;
pStr = statusText;
}
int nHeight = (int)((double)nSize * POINTS_TO_PIXELS);
int nX = max(0, (m_statusSize.cx - nWidth) / 2);
int nY = (int)((double)m_statusSize.cy / 2 + (double)nSize / 2);
::MoveTo(nX, nY);
::TextMode(srcCopy);
::DrawText(pStr, 0, nStrLen);
// switch port
::SetGWorld(pCGrafSave, hGDSave);
::DisposeGWorld(offscreenGWorld);
IHXVideoSurface* pVideoSurface = (IHXVideoSurface*)pEvent->param1;
if (!pVideoSurface)
{
return HXR_FAIL;
}
pVideoSurface->AddRef();
HXxRect rDestRect;
rDestRect.left = 0;
rDestRect.top = 0;
rDestRect.right = sz.cx;
rDestRect.bottom = sz.cy;
HXxRect rSrcRect = rDestRect;
HXBitmapInfoHeader bitmapInfoHeader;
bitmapInfoHeader.biSize = sizeof(HXBitmapInfoHeader);
bitmapInfoHeader.biWidth = sz.cx;
bitmapInfoHeader.biHeight = sz.cy;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 32;
bitmapInfoHeader.biCompression = HX_RGB;
bitmapInfoHeader.biSizeImage = sz.cx * sz.cy * 4;
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
bitmapInfoHeader.rcolor = 0;
bitmapInfoHeader.gcolor = 0;
bitmapInfoHeader.bcolor = 0;
pEvent->result = pVideoSurface->Blt(m_pStatusImage, &bitmapInfoHeader, rDestRect, rSrcRect);
pVideoSurface->Release();
return pEvent->result;
}
HX_RESULT
CHXSiteStatusText::_AdjustPosition(HXxPoint* pParentPos, HXxSize* pParentSize)
{
HX_RESULT hr = HXR_OK;
// this function is called internally and these will never be null
HX_ASSERT(pParentPos && pParentSize);
// take the max width of the parent site
m_statusPos.x = 0;
m_statusSize.cx = pParentSize->cx;
// take at most the bottom DEF_STAT_HEIGHT pixels of the parent site
m_statusPos.y = max(pParentSize->cy - DEF_STAT_HEIGHT, 0);
m_statusSize.cy = pParentSize->cy - m_statusPos.y;
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -