Pan and zoom commands
ZoomOut.cpp
// Copyright 2011 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

  
#include "ZoomOut.h"

ZoomOut::ZoomOut()
{
  m_ipHookHelper.CreateInstance(CLSID_HookHelper);

  // Load the cursors
  ISystemMouseCursorPtr ipSysMouseCur(CLSID_SystemMouseCursor);
  ipSysMouseCur->LoadFromFile(CComBSTR(L"./Res/ZoomOut.CUR"));
  OLE_HANDLE hTmp;
  HRESULT hr = ipSysMouseCur->get_Cursor(&hTmp);
  if (SUCCEEDED(hr))
    m_hCursor = hTmp;
  ipSysMouseCur->LoadFromFile(CComBSTR(L"./Res/MoveZoomOut.cur"));
  hr = ipSysMouseCur->get_Cursor(&hTmp);
  if (SUCCEEDED(hr))
    m_hCursorMove = hTmp;

  // Load the bitmap
  IRasterPicturePtr ipRastPict(CLSID_BasicRasterPicture);
  IPicturePtr ipPict;
  hr = ipRastPict->LoadPicture(CComBSTR(L"./Res/ZoomOut.bmp"), &ipPict);
  if (SUCCEEDED(hr))
  {
    OLE_HANDLE hBitmap;
    hr = ipPict->get_Handle(&hBitmap);
    if (SUCCEEDED(hr))
      m_hBitmap = hBitmap;
  }
}

ZoomOut::~ZoomOut()
{
  m_ipHookHelper = 0;
  m_hBitmap = 0;
  m_hCursor = 0;
  m_hCursorMove = 0;
  m_ipPoint = 0;
  m_ipFeedback = 0;
}

HRESULT ZoomOut::get_Enabled(VARIANT_BOOL* Enabled)
{
  if (!Enabled)
    return E_POINTER;
  
  IMapPtr ipMap;
  m_ipHookHelper->get_FocusMap(&ipMap);
  if (ipMap == 0)
    return S_OK;

  *Enabled = VARIANT_TRUE;
  return S_OK;
}

HRESULT ZoomOut::get_Checked(VARIANT_BOOL* Checked)
{
  if (!Checked)
    return E_POINTER;

  *Checked = VARIANT_FALSE;
  return S_OK;
}

HRESULT ZoomOut::get_Name(BSTR* Name)
{
  if (!Name)
    return E_POINTER;
  
  *Name = ::AoAllocBSTR(L"Sample_Pan/Zoom_Zoom Out");
  return S_OK;
}

HRESULT ZoomOut::get_Caption(BSTR* Caption) 
{
  if (!Caption)
    return E_POINTER;
  
  *Caption = ::AoAllocBSTR(L"Zoom Out");
  return S_OK;
}

HRESULT ZoomOut::get_Tooltip(BSTR* Tooltip) 
{
  if (!Tooltip)
    return E_POINTER;
  
  *Tooltip = ::AoAllocBSTR(L"Zoom Out");
  return S_OK;
}

HRESULT ZoomOut::get_Message(BSTR* Message) 
{
  if (!Message)
    return E_POINTER;
  
  *Message = ::AoAllocBSTR(L"Zooms the Display Out By Rectangle Or Single Click");
  return S_OK;
}

HRESULT ZoomOut::get_Bitmap(OLE_HANDLE* bitmap) 
{
  if (!bitmap)
    return E_POINTER;
  
  if (m_hBitmap != 0)
  {
    *bitmap = m_hBitmap;
    return S_OK;
  }

  return E_FAIL;
}

HRESULT  ZoomOut::get_Category(BSTR* categoryName) 
{
  if (!categoryName)
    return E_POINTER;
  
  *categoryName = ::AoAllocBSTR(L"Sample_Pan/Zoom");
  return S_OK;
}

// Create the command and set who it will work with
HRESULT ZoomOut::OnCreate(IDispatch* hook) 
{
  if (!hook)
    return E_POINTER;
  
  m_ipHookHelper->putref_Hook(hook);
  return S_OK;
}

// When clicked, the button appears pressed
HRESULT ZoomOut::OnClick() 
{
  return S_OK;
}

HRESULT ZoomOut::get_Cursor(OLE_HANDLE* cursorName)
{
  if (cursorName == NULL)
    return E_POINTER;

  if (m_hCursor != 0 && !m_bInUse)
  {
    *cursorName = m_hCursor;
    return S_OK;
  }
  else if (m_hCursorMove !=0 && m_bInUse)
  {
    *cursorName = m_hCursorMove;
    return S_OK;
  }
                
  return E_FAIL;
}

HRESULT ZoomOut::OnMouseDown(LONG Button, LONG Shift, LONG X, LONG Y)
{
  IActiveViewPtr ipActiveView;
  m_ipHookHelper->get_ActiveView(&ipActiveView);
  if (ipActiveView == 0)
    return S_OK;

  // If the active view is a page layout
  IPageLayoutPtr ipPageLayout(ipActiveView);
  if (ipPageLayout != 0)
  {
    // Create a point in map coordinates
    IScreenDisplayPtr ipPLScreenDisp;
    ipActiveView->get_ScreenDisplay(&ipPLScreenDisp);
    IDisplayTransformationPtr ipPLDispTrans;
    ipPLScreenDisp->get_DisplayTransformation(&ipPLDispTrans);
    IPointPtr ipPLPoint;
    ipPLDispTrans->ToMapPoint(X, Y, &ipPLPoint);

    // Get the map if the point is within a data frame
    IMapPtr ipMap;
    ipActiveView->HitTestMap(ipPLPoint, &ipMap);
    if (ipMap == 0)
      return S_OK;

    // Set the map to be the page layout's focus map
    IMapPtr ipFocusMap;
    m_ipHookHelper->get_FocusMap(&ipFocusMap);
    if (ipMap != ipFocusMap)
    {
      ipActiveView->putref_FocusMap(ipMap);  
      ipActiveView->PartialRefresh(esriViewGraphics, NULL, NULL);
    }
  }

  // Create a point in map coordinates
  IMapPtr ipMap;
  m_ipHookHelper->get_FocusMap(&ipMap);
  IActiveViewPtr ipAVFocusMap(ipMap);
  IScreenDisplayPtr ipScreenDisp;
  ipAVFocusMap->get_ScreenDisplay(&ipScreenDisp);
  IDisplayTransformationPtr ipDispTrans;
  ipScreenDisp->get_DisplayTransformation(&ipDispTrans);
  ipDispTrans->ToMapPoint(X, Y, &m_ipPoint);

  m_bInUse = true;

  // Start capturing mouse events
//*************************************

  return S_OK;
}

HRESULT ZoomOut::OnMouseMove(LONG Button, LONG Shift, LONG X, LONG Y)
{
  if (!m_bInUse)
    return S_OK;
  
  // Get the focus map
  IMapPtr ipMap;
  m_ipHookHelper->get_FocusMap(&ipMap);
  IActiveViewPtr ipActiveView(ipMap);
  
  // Start an envelope feedback
  if (m_ipFeedback == 0)
  {
    m_ipFeedback.CreateInstance(CLSID_NewEnvelopeFeedback);
    IScreenDisplayPtr ipScreenDisp;
    ipActiveView->get_ScreenDisplay(&ipScreenDisp);
    m_ipFeedback->putref_Display(ipScreenDisp);
    m_ipFeedback->Start(m_ipPoint);
  }

  // Move the envelope feedback
  IPointPtr ipMoveTo;
  IScreenDisplayPtr ipScreenDisp;
  ipActiveView->get_ScreenDisplay(&ipScreenDisp);
  IDisplayTransformationPtr ipDispTrans;
  ipScreenDisp->get_DisplayTransformation(&ipDispTrans);
  ipDispTrans->ToMapPoint(X, Y, &ipMoveTo);
  m_ipFeedback->MoveTo(ipMoveTo);

  return S_OK;
}

HRESULT ZoomOut::OnMouseUp(LONG Button, LONG Shift, LONG X, LONG Y)
{
  if (!m_bInUse)
    return S_OK;
  
  // Stop capturing mouse events 
//*************************************

  IEnvelopePtr ipEnv;
  IEnvelopePtr ipFeedEnv;
  // Get the focus map
  IMapPtr ipMap;
  m_ipHookHelper->get_FocusMap(&ipMap);
  IActiveViewPtr ipActiveView(ipMap);
  if (m_ipFeedback == 0)   // If an envelope has not been tracked
  {
    // Zoom out from the mouse click
    ipActiveView->get_Extent(&ipEnv);
    ipEnv->Expand(2, 2, VARIANT_TRUE);
    ipEnv->CenterAt(m_ipPoint);
  }
  else                     // An env is being tracked
  {
    // Stop the envelope feedback
    m_ipFeedback->Stop(&ipFeedEnv);
    // Exit if the envelope height or width is 0
    double dHeight;
    double dWidth;
    ipFeedEnv->get_Width(&dWidth);
    ipFeedEnv->get_Height(&dHeight);
    if (dWidth == 0 || dHeight == 0)
    {
      m_ipFeedback = 0;
      m_bInUse = false;
      return S_OK;
    }

    // Create new extent height and width
    double dExtWidth;
    double dExtHeight;
    double dNewWidth;
    double dNewHeight;
    IEnvelopePtr ipExtEnv;
    ipActiveView->get_Extent(&ipExtEnv);
    ipExtEnv->get_Width(&dExtWidth);
    dNewWidth = dExtWidth * (dExtWidth / dWidth);
    ipExtEnv->get_Height(&dExtHeight);
    dNewHeight = dExtHeight * (dExtHeight / dHeight);

    // Set the new extent coordinates
    ipEnv.CreateInstance(CLSID_Envelope);
    double dExtXMin;
    ipExtEnv->get_XMin(&dExtXMin);
    double dExtYMin;
    ipExtEnv->get_YMin(&dExtYMin);
    double dFeedXMin;
    ipFeedEnv->get_XMin(&dFeedXMin);
    double dFeedYMin;
    ipFeedEnv->get_YMin(&dFeedYMin);
    double dFeedWidth;
    ipFeedEnv->get_Width(&dFeedWidth);
    double dFeedHeight;
    ipFeedEnv->get_Height(&dFeedHeight);

    double dBaseXMin = dExtXMin - ((dFeedXMin - dExtXMin) * (dExtWidth / dFeedWidth));
    double dBaseYMin = dExtYMin - ((dFeedYMin - dExtYMin) * (dExtHeight / dFeedHeight));
    ipEnv->PutCoords(dBaseXMin, dBaseYMin, dBaseXMin + dNewWidth, dBaseYMin + dNewHeight); 
  }

  // Set the new extent
  ipActiveView->put_Extent(ipEnv);
  ipActiveView->Refresh();

  m_ipFeedback = 0;
  m_bInUse = false;

  return S_OK;
}

HRESULT ZoomOut::OnDblClick()
{
  return E_NOTIMPL;
}

HRESULT ZoomOut::OnKeyDown(LONG keyCode, LONG Shift)
{
  if (m_bInUse)
    if (keyCode == 27)    // ESC key
    {
//*****************************
      // RELEASE CAPTURE
//*****************************
      m_ipFeedback = 0;
      m_bInUse = false;
      IActiveViewPtr ipActiveView;
      m_ipHookHelper->get_ActiveView(&ipActiveView);
      ipActiveView->PartialRefresh(esriViewForeground, NULL, NULL);
    }
    
  return S_OK;
}

HRESULT ZoomOut::OnKeyUp(LONG keyCode, LONG Shift)
{
  return E_NOTIMPL;
}

HRESULT ZoomOut::OnContextMenu(LONG X, LONG Y, VARIANT_BOOL* handled)
{
  return E_NOTIMPL;
}

HRESULT ZoomOut::Refresh(OLE_HANDLE ole)
{
  return E_NOTIMPL;
}

HRESULT ZoomOut::Deactivate(VARIANT_BOOL* complete)
{
  if (!complete)
    return E_POINTER;
  
  *complete = VARIANT_TRUE;
  return S_OK;
}