/*
Module : MAPPIN.CPP
Purpose: Implementation for an MFC class to draw map pins ala AutoRoute Express
Created: PJN / 12-08-1998
History: PJN / 10-09-1998 Fixed a small redraw glitch in SetIcon
Copyright (c) 1998 by PJ Naughter.
All rights reserved.
*/
//////////////// Includes ////////////////////////////////////////////
#include "stdafx.h"
#include "MapPin.h"
//////////////// Defines /////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////// Implementation //////////////////////////////////////
BEGIN_MESSAGE_MAP(CMapPin, CWnd)
//{{AFX_MSG_MAP(CMapPin)
ON_WM_PAINT()
ON_WM_CONTEXTMENU()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETTEXT, OnSetText)
END_MESSAGE_MAP()
CMapPin::CMapPin()
{
m_hIcon = NULL;
m_nIconHeight = 0;
m_nIconWidth = 0;
m_bCaptured = FALSE;
m_bAllowDrag = TRUE;
}
CMapPin::~CMapPin()
{
//Free the icon resource that we have loaded
if (m_hIcon)
{
DestroyIcon(m_hIcon);
m_hIcon = NULL;
}
}
BOOL CMapPin::Create(LPCTSTR lpszTooltipText, DWORD dwStyle, const CPoint& p, CWnd* pParentWnd, UINT nID)
{
ASSERT(m_hIcon != NULL); //Icon must be setup before calling this function
//Work out the size to create the window based on the icon size
CRect r(p.x, p.y, p.x + m_nIconWidth, p.y + m_nIconHeight);
//Let the parent do its thing
BOOL bSuccess = CWnd::Create(NULL, lpszTooltipText, dwStyle, r, pParentWnd, nID);
//Fire off a timer to setup the tooltip for the control
m_nTimerID = SetTimer(1, 0, NULL);
return bSuccess;
}
BOOL CMapPin::SetIcon(HINSTANCE hModule, UINT nIDResource, BOOL bSmallIcon)
{
return SetIcon(hModule, MAKEINTRESOURCE(nIDResource), bSmallIcon);
}
BOOL CMapPin::SetIcon(HINSTANCE hModule, LPCTSTR lpszResourceName, BOOL bSmallIcon)
{
//Release the old icon we may have
if (m_hIcon != NULL)
{
DestroyIcon(m_hIcon);
m_hIcon = NULL;
}
//Work out the metrics of the icon we are about to load
if (bSmallIcon)
{
m_nIconWidth = GetSystemMetrics(SM_CXSMICON);
m_nIconHeight = GetSystemMetrics(SM_CYSMICON);
}
else
{
m_nIconWidth = GetSystemMetrics(SM_CXICON);
m_nIconHeight = GetSystemMetrics(SM_CYICON);
}
//Load up the new icon
if (bSmallIcon)
m_hIcon = (HICON) LoadImage(hModule, lpszResourceName, IMAGE_ICON, m_nIconWidth, m_nIconHeight, LR_DEFAULTCOLOR);
else
m_hIcon = LoadIcon(hModule, lpszResourceName);
//With an icon change, force a repaint
if (GetSafeHwnd())
{
//First the parent
CRect r;
GetClientRect(&r);
ClientToScreen(&r);
CWnd* pParent = GetParent();
pParent->ScreenToClient(&r);
pParent->InvalidateRect(r, FALSE);
//Now this window
Invalidate();
}
//return success indicator
return (m_hIcon != NULL);
}
void CMapPin::SetPopupMenu(LPCTSTR lpszResourceName)
{
m_lpszMenuResourceName = lpszResourceName;
}
void CMapPin::SetPopupMenu(UINT nIDResource)
{
m_lpszMenuResourceName = MAKEINTRESOURCE(nIDResource);
}
HICON CMapPin::GetIcon() const
{
return m_hIcon;
}
void CMapPin::OnPaint()
{
CPaintDC dc(this);
ASSERT(m_hIcon != NULL); //You forget to setup an icon
//Just draw the icon
::DrawIconEx(dc.GetSafeHdc(), 0, 0, m_hIcon, m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL);
}
void CMapPin::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
//Load up the specified menu
CMenu menu;
VERIFY(menu.LoadMenu(m_lpszMenuResourceName));
//Pull out the first popup menu from it
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
//Owner is the first non child window in the hierarchy above this window
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
//Track the menu
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, pWndPopupOwner);
}
void CMapPin::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_bAllowDrag)
{
SetCapture();
m_bCaptured = TRUE;
m_nDragOffset = point;
}
//Let the parent do its thing
CWnd::OnLButtonDown(nFlags, point);
}
void CMapPin::OnLButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
m_bCaptured = FALSE;
//let the parent do its thing
CWnd::OnLButtonUp(nFlags, point);
}
void CMapPin::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bCaptured)
{
CWnd* pParent = GetParent();
//Retrieve the old postion (in parent client coordinates)
CRect oldPos;
GetClientRect(&oldPos);
ClientToScreen(oldPos);
pParent->ScreenToClient(&oldPos);
//Work out the new position (in parent client coordinates)
CRect newPos(point.x - m_nDragOffset.x, point.y - m_nDragOffset.y,
point.x - m_nDragOffset.x + m_nIconWidth, point.y - m_nDragOffset.y + m_nIconHeight);
ClientToScreen(&newPos);
pParent->ScreenToClient(&newPos);
//Only move the pin if it is inside the client rect of the parent window
CRect clientRect;
pParent->GetClientRect(&clientRect);
if (newPos.left >= clientRect.left && newPos.top >= clientRect.top &&
newPos.right < clientRect.right && newPos.bottom < clientRect.bottom)
{
MoveWindow(newPos, FALSE);
pParent->InvalidateRect(oldPos, FALSE);
Invalidate(TRUE);
CWnd::OnMouseMove(nFlags, point); //Let the parent do its thing
}
}
else
CWnd::OnMouseMove(nFlags, point); //Let the parent do its thing
}
void CMapPin::SetAllowDrag(BOOL bAllowDrag)
{
m_bAllowDrag = bAllowDrag;
}
BOOL CMapPin::GetAllowDrag() const
{
return m_bAllowDrag;
}
BOOL CMapPin::PreTranslateMessage(MSG* pMsg)
{
//Relay the message to the tooltip if its around
if (IsWindow(m_ctrlToolTip.GetSafeHwnd()))
m_ctrlToolTip.RelayEvent(pMsg);
return CWnd::PreTranslateMessage(pMsg);
}
void CMapPin::OnTimer(UINT nIDEvent)
{
if (nIDEvent == m_nTimerID)
{
//Timer is being used as a once off, so kill it
KillTimer(m_nTimerID);
//Create the tooltip for the control
BOOL bSuccess = m_ctrlToolTip.Create(GetParent());
m_ctrlToolTip.Activate(TRUE);
CString sCaption;
GetWindowText(sCaption);
bSuccess = m_ctrlToolTip.AddTool(this, sCaption);
}
CWnd::OnTimer(nIDEvent);
}
LRESULT CMapPin::OnSetText(WPARAM /*wParam*/, LPARAM lParam)
{
//Update the tooltip text whenever the caption changes
LPCTSTR pszText = (LPCTSTR) lParam;
m_ctrlToolTip.UpdateTipText(pszText, this);
return Default();
}