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>
408 lines
11 KiB
C++
408 lines
11 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
// TitleTip.cpp : implementation file
|
|
//
|
|
// Based on code by Zafir Anjum
|
|
//
|
|
// Adapted by Chris Maunder <cmaunder@mail.com>
|
|
// Copyright (c) 1998-2002. All Rights Reserved.
|
|
//
|
|
// This code may be used in compiled form in any way you desire. This
|
|
// file may be redistributed unmodified by any means PROVIDING it is
|
|
// not sold for profit without the authors written consent, and
|
|
// providing that this notice and the authors name and all copyright
|
|
// notices remains intact.
|
|
//
|
|
// An email letting me know how you are using it would be nice as well.
|
|
//
|
|
// This file is provided "as is" with no expressed or implied warranty.
|
|
// The author accepts no liability for any damage/loss of business that
|
|
// this product may cause.
|
|
//
|
|
// For use with CGridCtrl v2.20+
|
|
//
|
|
// History
|
|
// 10 Apr 1999 Now accepts a LOGFONT pointer and
|
|
// a tracking rect in Show(...) (Chris Maunder)
|
|
// 18 Apr 1999 Resource leak in Show fixed by Daniel Gehriger
|
|
// 8 Mar 2000 Added double-click fix found on codeguru
|
|
// web site but forgot / can't find who contributed it
|
|
// 28 Mar 2000 Aqiruse (marked with //FNA)
|
|
// Titletips now use cell color
|
|
// 18 Jun 2000 Delayed window creation added
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "gridctrl.h"
|
|
|
|
#ifndef GRIDCONTROL_NO_TITLETIPS
|
|
|
|
#include "TitleTip.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTitleTip
|
|
|
|
CTitleTip::CTitleTip()
|
|
{
|
|
// Register the window class if it has not already been registered.
|
|
WNDCLASS wndcls;
|
|
HINSTANCE hInst = AfxGetInstanceHandle();
|
|
if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
|
|
{
|
|
// otherwise we need to register a new class
|
|
wndcls.style = CS_SAVEBITS;
|
|
wndcls.lpfnWndProc = ::DefWindowProc;
|
|
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
|
|
wndcls.hInstance = hInst;
|
|
wndcls.hIcon = NULL;
|
|
wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
|
|
wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK +1);
|
|
wndcls.lpszMenuName = NULL;
|
|
wndcls.lpszClassName = TITLETIP_CLASSNAME;
|
|
|
|
if (!AfxRegisterClass(&wndcls))
|
|
AfxThrowResourceException();
|
|
}
|
|
|
|
m_dwLastLButtonDown = ULONG_MAX;
|
|
m_dwDblClickMsecs = GetDoubleClickTime();
|
|
m_bCreated = FALSE;
|
|
m_pParentWnd = NULL;
|
|
}
|
|
|
|
CTitleTip::~CTitleTip()
|
|
{
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
|
|
//{{AFX_MSG_MAP(CTitleTip)
|
|
ON_WM_MOUSEMOVE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTitleTip message handlers
|
|
|
|
BOOL CTitleTip::Create(CWnd * pParentWnd)
|
|
{
|
|
ASSERT_VALID(pParentWnd);
|
|
|
|
// Already created?
|
|
if (m_bCreated)
|
|
return TRUE;
|
|
|
|
DWORD dwStyle = WS_BORDER | WS_POPUP;
|
|
DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
|
|
m_pParentWnd = pParentWnd;
|
|
|
|
m_bCreated = CreateEx(dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
NULL, NULL, NULL );
|
|
|
|
return m_bCreated;
|
|
}
|
|
|
|
BOOL CTitleTip::DestroyWindow()
|
|
{
|
|
m_bCreated = FALSE;
|
|
|
|
return CWnd::DestroyWindow();
|
|
}
|
|
|
|
// Show - Show the titletip if needed
|
|
// rectTitle - The rectangle within which the original
|
|
// title is constrained - in client coordinates
|
|
// lpszTitleText - The text to be displayed
|
|
// xoffset - Number of pixel that the text is offset from
|
|
// left border of the cell
|
|
void CTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=0*/,
|
|
LPRECT lpHoverRect /*=NULL*/,
|
|
const LOGFONT* lpLogFont /*=NULL*/,
|
|
COLORREF crTextClr /* CLR_DEFAULT */,
|
|
COLORREF crBackClr /* CLR_DEFAULT */)
|
|
{
|
|
if (!IsWindow(m_hWnd))
|
|
Create(m_pParentWnd);
|
|
|
|
ASSERT( ::IsWindow( GetSafeHwnd() ) );
|
|
|
|
if (rectTitle.IsRectEmpty())
|
|
return;
|
|
|
|
// If titletip is already displayed, don't do anything.
|
|
if( IsWindowVisible() )
|
|
return;
|
|
|
|
m_rectHover = (lpHoverRect != NULL)? lpHoverRect : rectTitle;
|
|
m_rectHover.right++; m_rectHover.bottom++;
|
|
|
|
m_pParentWnd->ClientToScreen( m_rectHover );
|
|
ScreenToClient( m_rectHover );
|
|
|
|
// Do not display the titletip is app does not have focus
|
|
if( GetFocus() == NULL )
|
|
return;
|
|
|
|
CClientDC dc(this);
|
|
CString strTitle = _T("");
|
|
strTitle += _T(" ");
|
|
strTitle += lpszTitleText;
|
|
strTitle += _T(" ");
|
|
|
|
CFont font, *pOldFont = NULL;
|
|
if (lpLogFont)
|
|
{
|
|
font.CreateFontIndirect(lpLogFont);
|
|
pOldFont = dc.SelectObject( &font );
|
|
}
|
|
else
|
|
{
|
|
// use same font as ctrl
|
|
pOldFont = dc.SelectObject( m_pParentWnd->GetFont() );
|
|
}
|
|
|
|
// 멀티라인이 몇개? 가장긴 물자열은 어떤것?
|
|
// Test Code by Ringo ----------------
|
|
TCHAR szMaxTXT[ 256 ]; // 최고긴 문자열
|
|
TCHAR szTmp [ 256 ]; // 문자열 임시보관함
|
|
|
|
TCHAR* szTitleTip = strTitle.GetBuffer();
|
|
TCHAR* nPos = szTitleTip;
|
|
TCHAR* nPosTXT = szMaxTXT;
|
|
TCHAR* szTmpTXT = szTmp;
|
|
int LineCnt = 0;
|
|
|
|
ZeroMemory( szMaxTXT, sizeof( szMaxTXT ) );
|
|
|
|
while( *nPos != '\0' )
|
|
{
|
|
if( ( *nPos == '\n' ) || ( *(nPos + 1 ) == '\0' ) )
|
|
{
|
|
if( _tcslen( szMaxTXT ) < _tcslen( szTmp ) )
|
|
{
|
|
//_strncpy( szMaxTXT, szTmp, strlen( szTmp ) );
|
|
CopyMemory( szMaxTXT, szTmp, _tcslen( szTmp ) );
|
|
szTmpTXT = szTmp;
|
|
}
|
|
LineCnt ++;
|
|
}
|
|
else
|
|
{
|
|
*szTmpTXT = *nPos;
|
|
szTmpTXT ++;
|
|
*szTmpTXT = 0;
|
|
}
|
|
|
|
nPos ++;
|
|
}
|
|
//------------------------------------
|
|
|
|
// Define the rectangle outside which the titletip will be hidden.
|
|
// We add a buffer of one pixel around the rectangle
|
|
m_rectTitle.top = -1;
|
|
m_rectTitle.left = -xoffset-1;
|
|
m_rectTitle.right = rectTitle.Width()-xoffset;
|
|
m_rectTitle.bottom = rectTitle.Height() * ( LineCnt + 1 );
|
|
|
|
CString strMax = szMaxTXT;
|
|
CSize size = dc.GetTextExtent( strMax );
|
|
|
|
TEXTMETRIC tm;
|
|
dc.GetTextMetrics(&tm);
|
|
size.cx += tm.tmOverhang;
|
|
|
|
// Determine the width of the text
|
|
rectTitle.bottom = rectTitle.top + ( ( size.cy + 3 ) * ( LineCnt + 1 ) ); // +3의 의미는 줄간격을 3픽셀로 대충~~ ㅡ.ㅡㅋ
|
|
m_pParentWnd->ClientToScreen( rectTitle );
|
|
|
|
CRect rectDisplay = rectTitle;
|
|
rectDisplay.left += xoffset;
|
|
rectDisplay.right = rectDisplay.left + size.cx + xoffset;
|
|
|
|
// Do not display if the text fits within available space
|
|
if ( rectDisplay.right > rectTitle.right-xoffset )
|
|
{
|
|
// Show the titletip
|
|
SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top,
|
|
rectDisplay.Width() + 10, rectDisplay.Height() - size.cy, // + 10의 의미? 음.. 문자열길이가 정확하게 뽑히지 않는다 다른처리를 조금더 해줘야한다.
|
|
SWP_SHOWWINDOW|SWP_NOACTIVATE );
|
|
|
|
// FNA - handle colors correctly
|
|
if (crBackClr != CLR_DEFAULT)
|
|
{
|
|
CBrush backBrush(crBackClr);
|
|
CBrush* pOldBrush = dc.SelectObject(&backBrush);
|
|
CRect rect;
|
|
dc.GetClipBox(&rect); // Erase the area needed
|
|
|
|
dc.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
|
|
dc.SelectObject(pOldBrush);
|
|
}
|
|
|
|
// Set color
|
|
if (crTextClr != CLR_DEFAULT)//FNA
|
|
dc.SetTextColor(crTextClr);//FA
|
|
|
|
dc.SetBkMode( TRANSPARENT );
|
|
|
|
// 멀티라인 그리기....
|
|
// ㅋㅋ 역시 여기도 날림 ㅡ.ㅡ ---------------------------------
|
|
nPos = szTitleTip;
|
|
nPosTXT = szMaxTXT;
|
|
szTmpTXT = szTmp;
|
|
LineCnt = 0;
|
|
|
|
while( *nPos != '\0' )
|
|
{
|
|
if( ( *nPos == '\n' ) || ( *(nPos + 1 ) == '\0' ) )
|
|
{
|
|
dc.TextOut( 0, LineCnt * ( size.cy + 3 ), szTmp );
|
|
|
|
szTmpTXT = szTmp;
|
|
*szTmpTXT = 0;
|
|
|
|
LineCnt ++;
|
|
}
|
|
else
|
|
{
|
|
*szTmpTXT = *nPos;
|
|
szTmpTXT ++;
|
|
*szTmpTXT = 0;
|
|
}
|
|
nPos ++;
|
|
}
|
|
//----------------------------------------------------------------
|
|
|
|
SetCapture();
|
|
}
|
|
|
|
dc.SelectObject( pOldFont );
|
|
}
|
|
|
|
void CTitleTip::Hide()
|
|
{
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
return;
|
|
|
|
if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
|
|
ReleaseCapture();
|
|
|
|
ShowWindow( SW_HIDE );
|
|
}
|
|
|
|
void CTitleTip::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (!m_rectHover.PtInRect(point))
|
|
{
|
|
Hide();
|
|
|
|
// Forward the message
|
|
ClientToScreen( &point );
|
|
CWnd *pWnd = WindowFromPoint( point );
|
|
if ( pWnd == this )
|
|
pWnd = m_pParentWnd;
|
|
|
|
int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
|
|
|
|
if (hittest == HTCLIENT) {
|
|
pWnd->ScreenToClient( &point );
|
|
pWnd->PostMessage( WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y) );
|
|
} else {
|
|
pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y) );
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CTitleTip::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// Used to qualify WM_LBUTTONDOWN messages as double-clicks
|
|
DWORD dwTick=0;
|
|
BOOL bDoubleClick=FALSE;
|
|
|
|
CWnd *pWnd;
|
|
int hittest;
|
|
switch (pMsg->message)
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
// Get tick count since last LButtonDown
|
|
dwTick = GetTickCount();
|
|
bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= m_dwDblClickMsecs);
|
|
m_dwLastLButtonDown = dwTick;
|
|
// NOTE: DO NOT ADD break; STATEMENT HERE! Let code fall through
|
|
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
{
|
|
POINTS pts = MAKEPOINTS( pMsg->lParam );
|
|
POINT point;
|
|
point.x = pts.x;
|
|
point.y = pts.y;
|
|
|
|
ClientToScreen( &point );
|
|
Hide();
|
|
|
|
pWnd = WindowFromPoint( point );
|
|
if (!pWnd)
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
|
|
if( pWnd->GetSafeHwnd() == GetSafeHwnd())
|
|
pWnd = m_pParentWnd;
|
|
|
|
hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
|
|
|
|
if (hittest == HTCLIENT)
|
|
{
|
|
pWnd->ScreenToClient( &point );
|
|
pMsg->lParam = MAKELONG(point.x,point.y);
|
|
}
|
|
else
|
|
{
|
|
switch (pMsg->message) {
|
|
case WM_LBUTTONDOWN:
|
|
pMsg->message = WM_NCLBUTTONDOWN;
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
pMsg->message = WM_NCRBUTTONDOWN;
|
|
break;
|
|
case WM_MBUTTONDOWN:
|
|
pMsg->message = WM_NCMBUTTONDOWN;
|
|
break;
|
|
}
|
|
pMsg->wParam = hittest;
|
|
pMsg->lParam = MAKELONG(point.x,point.y);
|
|
}
|
|
|
|
|
|
// If this is the 2nd WM_LBUTTONDOWN in x milliseconds,
|
|
// post a WM_LBUTTONDBLCLK message instead of a single click.
|
|
pWnd->PostMessage( bDoubleClick ? WM_LBUTTONDBLCLK : pMsg->message,
|
|
pMsg->wParam,
|
|
pMsg->lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
Hide();
|
|
m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
|
|
return TRUE;
|
|
}
|
|
|
|
if( GetFocus() == NULL )
|
|
{
|
|
Hide();
|
|
return TRUE;
|
|
}
|
|
|
|
return CWnd::PreTranslateMessage(pMsg);
|
|
}
|
|
|
|
#endif // GRIDCONTROL_NO_TITLETIPS
|