Files
Client/GameTools/EffectEditor/Bubble.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

379 lines
8.4 KiB
C++

// Bubble.cpp : implementation file
//
#include "stdafx.h"
#include "Bubble.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static CBitmap bmpShadow;
static CBrush brShadow;
#define SHADOW_SIZE 5
/////////////////////////////////////////////////////////////////////////////
// CBubble
// static members
CString CBubble::m_strClassName;
CBubble::CBubble()
{
m_iTextFormat = DT_CENTER;
m_iRowHeight = 0;
m_iImageWidth = 0;
m_iImageHeight = 0;
m_bShadow = FALSE;
}
CBubble::~CBubble()
{
}
BOOL CBubble::Create(CWnd* pWndParent, BOOL bShadow)
{
m_bShadow = bShadow;
// create our bubble window but leave it invisible
// do we need to register the class?
if (m_strClassName.IsEmpty ())
{
// first, create the background brush
CBrush brBrush;
try
{
brBrush.CreateSolidBrush (::GetSysColor (COLOR_INFOBK));
}
catch (CResourceException* pEx)
{
// brush creation failed
pEx->Delete ();
return 0;
}
// register the class name
m_strClassName = ::AfxRegisterWndClass (
CS_BYTEALIGNCLIENT | CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW,
0,
(HBRUSH)brBrush.Detach ());
// we're we successful?
if (m_strClassName.IsEmpty ())
{
return 0;
}
}
// create the bubble window and set the created flag
CRect rect;
rect.SetRectEmpty();
HWND hwndParent = (pWndParent == NULL) ? NULL :
pWndParent->GetSafeHwnd ();
if (!CreateEx (0, m_strClassName, _T (""), WS_POPUP,
rect.left, rect.top, rect.right, rect.bottom,
hwndParent, (HMENU)NULL))
{
return FALSE;
}
if (bmpShadow.GetSafeHandle () == NULL)
{
ASSERT (brShadow.GetSafeHandle () == NULL);
int aPattern[] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
bmpShadow.CreateBitmap (8, 8, 1, 1, aPattern);
brShadow.CreatePatternBrush (&bmpShadow);
}
return TRUE;
}
BEGIN_MESSAGE_MAP(CBubble, CWnd)
//{{AFX_MSG_MAP(CBubble)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETTEXT, OnSetText)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBubble message handlers
void CBubble::OnPaint()
{
CPaintDC dc(this); // device context for painting
// paint our text, centered in the window
CRect rect;
GetClientRect(rect);
if (m_bShadow)
{
rect.right -= SHADOW_SIZE;
rect.bottom -= SHADOW_SIZE;
}
dc.FillSolidRect (&rect, ::GetSysColor (COLOR_INFOBK));
dc.Draw3dRect (rect, GetSysColor (COLOR_3DSHADOW), GetSysColor (COLOR_3DDKSHADOW));
// select our font and setup for text painting
CFont *pOldFont = (CFont*) dc.SelectStockObject (DEFAULT_GUI_FONT);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(::GetSysColor (COLOR_INFOTEXT));
// paint our text
int y = rect.top + 3 * GetSystemMetrics(SM_CYBORDER);
int x;
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
for (POSITION pos = m_strTextRows.GetHeadPosition (); pos != NULL;)
{
CString strText = m_strTextRows.GetNext (pos);
x = m_iImageWidth + 5;
if (strText [0] == '\r') // Draw a line
{
dc.SelectStockObject (WHITE_PEN);
dc.MoveTo (x, y);
dc.LineTo (rect.right - x, y);
dc.SelectStockObject (BLACK_PEN);
dc.MoveTo (x, y + 1);
dc.LineTo (rect.right - 5, y + 1);
strText = strText.Right (strText.GetLength () - 1);
y += 5;
}
if (strText [0] == '\a' && // Next 2 digits - image number
m_Images.GetSafeHandle () != NULL)
{
int iImage = _ttol (strText.Mid (1, 2));
m_Images.Draw (&dc, iImage, CPoint (3, y), ILD_NORMAL);
strText = strText.Mid (3);
}
CRect rectText = rect;
rectText.top = y;
rectText.left = x;
rectText.bottom = y + tm.tmHeight + tm.tmExternalLeading;
int iFormat = m_iTextFormat | DT_SINGLELINE | DT_VCENTER;
dc.DrawText (strText, rectText, iFormat);
y += m_iRowHeight;
}
// Draw shadow:
if (m_bShadow)
{
dc.SetBkColor(RGB(255,255,255));
brShadow.UnrealizeObject ();
CBrush *pbrOld = (CBrush *) dc.SelectObject (&brShadow);
// bottom shadow
dc.PatBlt (rect.left + SHADOW_SIZE,
rect.bottom,
rect.Width (),
SHADOW_SIZE,
0xA000C9);
// right-side shadow
dc.PatBlt (rect.right,
rect.top + SHADOW_SIZE,
SHADOW_SIZE,
rect.Height (),
0xA000C9);
dc.SelectObject(pbrOld);
}
dc.SelectObject(pOldFont);
}
//*******************************************************************************************
BOOL CBubble::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
//*******************************************************************************************
afx_msg LONG CBubble::OnSetText(UINT, LONG lParam)
{
// resize the bubble window to fit the new string
int i;
m_iTextFormat = DT_CENTER;
//-----------------------------------------------------------
// Parse a text to get bitmaps + lines. For example, if text
// looks "<\a><image1-res-id>text1<\n><\a><image2-res-id>text2",
// we should create a bubble window with tow rows and draw in the
// beggining of each row a specific bitmap:
// (REMARK: image should be placed in the start of row only!)
//-----------------------------------------------------------
CString str ((LPCTSTR) lParam);
m_strTextRows.RemoveAll ();
// compute new size based on string x extent
CClientDC dc(this);
CFont *pOldFont = (CFont*) dc.SelectStockObject (DEFAULT_GUI_FONT);
// get the text metrics
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
m_iRowHeight = max (m_iImageHeight, tm.tmHeight + tm.tmExternalLeading);
int nBubbleHeight = 6*GetSystemMetrics(SM_CYBORDER);
int nMaxWidth = 0;
int nExtraHeight = 0;
CString strTmp = str;
while ((i = strTmp.Find ('\r')) != -1)
{
nExtraHeight += 5;
strTmp = strTmp.Right (strTmp.GetLength () - i - 1);
}
do
{
CString strCurrRow;
if ((i = str.Find ('\n')) == -1)
{
strCurrRow = str; // Whole string
}
else
{
m_iTextFormat = DT_LEFT;
strCurrRow = str.Left (i);
str = str.Right (str.GetLength () - i - 1);
}
if (strCurrRow.IsEmpty ())
{
strCurrRow = " ";
}
m_strTextRows.AddTail (strCurrRow);
int iCurrWidth = m_iImageWidth;
if (strCurrRow [0] == '\a')
{
strCurrRow = strCurrRow.Mid (3);
}
iCurrWidth += dc.GetTextExtent (strCurrRow).cx;
if (iCurrWidth > nMaxWidth)
{
nMaxWidth = iCurrWidth;
}
nBubbleHeight += m_iRowHeight;
}
while (i != -1);
CRect rect;
GetWindowRect(rect); // get current size and position
// compute width
rect.right = rect.left + nMaxWidth + (6*GetSystemMetrics(SM_CXBORDER)) + 10;
// set height
rect.bottom = rect.top + nBubbleHeight + nExtraHeight;
if (m_bShadow)
{
rect.right += SHADOW_SIZE;
rect.bottom += SHADOW_SIZE;
}
MoveWindow(&rect);
// clean up
dc.SelectObject(pOldFont);
// do the default processing
return CWnd::Default();
}
//*******************************************************************************************
void CBubble::Track(CPoint point, const CString& string)
{
if (m_strLastText == string &&
m_ptLastPoint == point)
{
return;
}
// set the text
SetWindowText(string);
// move the window
SetWindowPos(&wndTop, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
//-----------------------------------------------
// Adjust the window position by the screen size:
//-----------------------------------------------
CRect rectWindow;
GetWindowRect (rectWindow);
if (rectWindow.right > ::GetSystemMetrics (SM_CXFULLSCREEN))
{
point.x = ::GetSystemMetrics (SM_CXFULLSCREEN) - rectWindow.Width ();
SetWindowPos(&wndTop, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
if (rectWindow.bottom > ::GetSystemMetrics (SM_CYFULLSCREEN) - 20)
{
point.y = ::GetSystemMetrics (SM_CYFULLSCREEN) - rectWindow.Height () - 20;
SetWindowPos(&wndTop, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
}
// show the window
ShowWindow(SW_SHOWNOACTIVATE);
Invalidate ();
UpdateWindow ();
m_strLastText = string;
m_ptLastPoint = point;
}
//*******************************************************************************************
void CBubble::Hide()
{
// hide the bubble window
ShowWindow(SW_HIDE);
m_strLastText.Empty ();
}
//*******************************************************************************************
BOOL CBubble::SetImageList (UINT uiId, int iImageWidth, COLORREF cltTransparent)
{
if (!m_Images.Create (uiId, iImageWidth, 0, cltTransparent))
{
return FALSE;
}
IMAGEINFO info;
m_Images.GetImageInfo (0, &info);
CRect rect = info.rcImage;
m_iImageWidth = rect.Width () + 3;
m_iImageHeight = rect.Height ();
return TRUE;
}