void PZoomInteraction::RepeatZoom(const PZoomInteraction& inZoomInteraction, int off_x, int off_y)
{
  if (inZoomInteraction.mLastZoomIn)
  {
    mX1 = inZoomInteraction.mX1-off_x;
    mX2 = inZoomInteraction.mX2-off_x;
    mY1 = inZoomInteraction.mY1-off_y;
    mY2 = inZoomInteraction.mY2-off_y;
    DoZoomIn();
  }
  else
    DoZoomOut();
}
/*
	OnChar()
*/
void CWallBrowserStretchView::OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
{
	switch(nChar)
	{
		case '+':
		{
			if(m_nViewType==VIEWTYPE_SCROLL)
			{
				SetZoomMode(MODE_ZOOMIN);
				TRACE("zoom ratio: %.2f\n",GetZoomRatio());
				if(GetZoomRatio() <= 28.42)
					DoZoomIn();
				return;
			}
		}
		case '-':
		{
			if(m_nViewType==VIEWTYPE_SCROLL)
			{
				SetZoomMode(MODE_ZOOMOUT);
				TRACE("zoom ratio: %.2f\n",GetZoomRatio());
				if(GetZoomRatio() >= 0.04)
					DoZoomOut();
				return;
			}
		}
		case '=':
		{
			if(m_nViewType==VIEWTYPE_SCROLL)
			{
				SetZoomMode(MODE_ZOOMOFF);
				NotifyRanges();
				Invalidate(TRUE);
				return;
			}
		}
	}
	
	CZoomView::OnChar(nChar,nRepCnt,nFlags);
}
bool PZoomInteraction::HandleMouseEvent (const PMouseEvent &inEvent) {
  if (!mDragging) {
    if (inEvent.IsMouseDown ()) {
      /*      if (inEvent.IsOnlyShiftKeyDown ()) {
        DoZoomOut ();
        return true;
        }*/
      if (inEvent.HasModifierKeys ()) {
        return false;
      }
      mDragging = true;
      mX1 = mX2 = inEvent.mX;
      mY1 = mY2 = inEvent.mY;
      return true;
    }
  }
  else {
    if (inEvent.IsMouseUp ()) {
      // here we should zoom

      if (mX1 == mX2 && mY1 == mY2) {
        mDragging = false;
        DoZoomOut ();
        return true;
        //      return false;// emtpy area                                 
      }

      DoZoomIn ();
      mDragging = false;
      return true;
    }
    if (inEvent.IsMouseMove ()) {
      mX2 = inEvent.mX;
      mY2 = inEvent.mY;
      return true;
    }
  }
  return false;
}
/*
	OnUpdate()
*/
void CWallBrowserStretchView::OnUpdate(CView* pSender,LPARAM lHint,CObject* pHint)
{
	CWaitCursor cursor;
	BOOL bHint = FALSE;
	static BOOL bTreeExpandedEx = FALSE;

	if(lHint & ONUPDATE_FLAG_TREEEXPANDEDEX)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_TREEEXPANDEDEX\n",__FILE__,__LINE__);
		bTreeExpandedEx = TRUE;
	}

	if(!bTreeExpandedEx)
		goto done;

	// cambio immagine/libreria correnti
	if((lHint & ONUPDATE_FLAG_FILECHANGED) || (lHint & ONUPDATE_FLAG_DEFAULTLIBRARY))
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_FILECHANGED || ONUPDATE_FLAG_DEFAULTLIBRARY\n",__FILE__,__LINE__);

		m_bLoaded = FALSE;
		CWallBrowserDoc* pDoc = (CWallBrowserDoc*)GetDocument();
		CImage* pImage = NULL;

		memset(m_szStatus,'\0',sizeof(m_szStatus));

		if(pDoc)
		{
			// salva l'immagine se e' stata modificata
			if(pDoc->IsModified())
				pDoc->SaveModified(m_szFileName);

			pImage = pDoc->GetImage();
			if(pImage)
			{
				if(pDoc->HaveFileName())
				{
					// ricava il nome del file da caricare
					_snprintf(m_szFileName,
							sizeof(m_szFileName)-1,
							"%s%s",
							pDoc->GetPathName(),
							pDoc->GetFileName()
							);

					strcpyn(m_szStatus,"loading...",sizeof(m_szStatus));
					if(m_pMainFrameStatusBar)
						m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_FILENAME_ID,m_szStatus);
					pDoc->SetTitle(m_szStatus);
					
					// carica l'immagine
					m_bHavePicture = TRUE;

					if(pImage->Load(m_szFileName))
					{
						m_bLoaded = TRUE;
						strcpyn(m_szStatus,pDoc->GetFileName(),sizeof(m_szStatus));
					}
					else
					{
						m_bLoaded = FALSE;
						_snprintf(m_szStatus,sizeof(m_szStatus)-1,"load failed - %s",pDoc->GetFileName());
					}

					pDoc->SetTitle(m_szStatus);
					pDoc->SetPictureFlag(m_bLoaded);
					if(!m_bLoaded)
						pDoc->ResetFileName();
				}
			}
		}
		
		// caricamento dell'immagine riuscito
		if(m_bLoaded)
		{
			if(m_pMainFrameStatusBar)
			{
				EnableMenu();
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_FILENAME_ID,m_szStatus);
			}
		}
		else // caricamento fallito
		{
			if(m_pMainFrameStatusBar)
			{
				DisableMenu();
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_FILENAME_ID,"");
				//m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_FILES_ID,"");
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_INFO_ID,"");
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_LIBRARY_ID,"");
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_MEM_ID,"");
				//m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_PICTURES_ID,"");
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_RATIO_ID,"");
				m_pMainFrameStatusBar->SetPaneText(ID_INDICATOR_ZOOM_ID,"");
			}
		}
		
		// aggiorna la GUI
		CWnd* pWnd = AfxGetMainWnd();
		if(pWnd)
		{
			pWnd->SendMessage(WM_FILE_SAVE,FALSE,0L);
			pWnd->SendMessage(WM_FILE_SAVE_AS,m_bLoaded,0L);
			pWnd->SendMessage(WM_FILE_MOVE,m_bHavePicture,0L);
			pWnd->SendMessage(WM_FILE_DELETE,m_bHavePicture,0L);
			pWnd->SendMessage(WM_EDIT_COPY,m_bLoaded,0L);
			pWnd->SendMessage(WM_EDIT_PASTE,m_bLoaded ? ::IsClipboardFormatAvailable(CF_DIB) : FALSE,0L);
			pWnd->SendMessage(WM_EDIT_UNDO,FALSE,0L);
			pWnd->PostMessage(WM_EDIT_REDO,FALSE,0L);
			UndoEmpty();
			RedoEmpty();
		}

		// per evitare di cancellare il fondo se la nuova immagine e' piu' grande della precedente
		BOOL bEraseOnInvalidate = TRUE;

		// modalita' stretch, calcola la dimensione dello stretch
		if(m_nViewType==VIEWTYPE_STRETCH)
		{
			// modalita' visualizzazione (centrato/text)
			SetCenterMode(FALSE);
			SetMapMode(MM_TEXT);
			SetCursorZoomMode(CURSOR_MODE_NONE);

			// elimina le barre dello scroll
			CSize size(0,0);
			SetZoomSizes(size);

			bEraseOnInvalidate = m_bLoaded ? ((lHint & ONUPDATE_FLAG_DEFAULTLIBRARY) ? FALSE : TRUE) : TRUE;

			if(bEraseOnInvalidate && m_rcInvalid.right!=-1 && m_rcInvalid.bottom!=-1 && pImage)
			{
				double nRemains = 0.0;
				double nWidth   = (double)pImage->GetWidth();
				double nHeight  = (double)pImage->GetHeight();

				GetClientRect(&m_rcClient);

				if(nHeight > (double)m_rcClient.bottom)
				{
					nRemains = FDIV(nHeight,(double)m_rcClient.bottom);
					if(nRemains > 0.0)
					{
						nHeight = FDIV(nHeight,nRemains);
						nWidth  = FDIV(nWidth,nRemains);
					}
				}
				if(nWidth > (double)m_rcClient.right)
				{
					nRemains = FDIV(nWidth,(double)m_rcClient.right);
					if(nRemains > 0.0)
					{
						nHeight = FDIV(nHeight,nRemains);
						nWidth  = FDIV(nWidth,nRemains);
					}
				}

				if((int)nWidth >= m_rcInvalid.right && (int)nHeight >= m_rcInvalid.bottom)
					bEraseOnInvalidate = FALSE;
			}
		}
		// modalita' scroll
		else if(m_nViewType==VIEWTYPE_SCROLL)
		{
			// deve cancellare lo sfondo e riposizionare le barre dello scroll a 0,0
			bEraseOnInvalidate = TRUE;
			POINT point = {0,0};
			ScrollToPosition(point);
			NotifyRanges();
		}

		// (ri)disegna l'immagine
		Invalidate(bEraseOnInvalidate);

		bHint = TRUE;
	}
	// click sull'immagine gia' selezionata (ma non attiva)
	if(lHint & ONUPDATE_FLAG_FILESELECTED)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_FILESELECTED\n",__FILE__,__LINE__);

		CWallBrowserDoc* pDoc = (CWallBrowserDoc*)GetDocument();
		if(pDoc)
		{
			CImage* pImage = pDoc->GetImage();
			if(pImage && pImage->GetWidth() > 0 && pImage->GetHeight() > 0)
			{
				// aggiorna la GUI
				CWnd* pWnd = AfxGetMainWnd();
				if(pWnd)
				{
					m_bLoaded = pDoc->GetPictureFlag();
					pWnd->SendMessage(WM_FILE_SAVE,pDoc->IsModified(),0L);
					pWnd->SendMessage(WM_FILE_SAVE_AS,m_bLoaded,0L);
					pWnd->SendMessage(WM_FILE_MOVE,m_bHavePicture,0L);
					pWnd->SendMessage(WM_FILE_DELETE,m_bHavePicture,0L);
					pWnd->SendMessage(WM_EDIT_COPY,m_bLoaded,0L);
					pWnd->SendMessage(WM_EDIT_PASTE,m_bLoaded ? ::IsClipboardFormatAvailable(CF_DIB) : FALSE,0L);
					pWnd->SendMessage(WM_EDIT_UNDO,UndoEnabled(),0L);
					pWnd->PostMessage(WM_EDIT_REDO,RedoEnabled(),0L);
				}
			}
		}

		//Invalidate(FALSE);

		bHint = TRUE;
	}
	// eliminazione dell'immagine corrente
	if(lHint & ONUPDATE_FLAG_FILEDELETED)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_FILEDELETED\n",__FILE__,__LINE__);

		// se l'immagine e' stata modificata resetta il flag
		CWallBrowserDoc* pDoc = (CWallBrowserDoc*)GetDocument();
		if(pDoc->IsModified())
			pDoc->SetModifiedFlag(FALSE);

		// aggiorna la GUI
		CWnd* pWnd = AfxGetMainWnd();
		if(pWnd)
		{
			pWnd->SendMessage(WM_FILE_SAVE,FALSE,0L);
			pWnd->SendMessage(WM_FILE_SAVE_AS,FALSE,0L);
			pWnd->SendMessage(WM_FILE_MOVE,FALSE,0L);
			pWnd->SendMessage(WM_FILE_DELETE,FALSE,0L);
			pWnd->SendMessage(WM_EDIT_COPY,FALSE,0L);
			pWnd->SendMessage(WM_EDIT_PASTE,FALSE,0L);
			pWnd->SendMessage(WM_EDIT_UNDO,FALSE,0L);
			pWnd->PostMessage(WM_EDIT_REDO,FALSE,0L);
			UndoEmpty();
			RedoEmpty();
		}

		// deve disegnare il contenuto della nuova immagine o ripulire l'area client se era l'unica immagine della directory
		Invalidate(TRUE);

		// se il file era l'unico nella directory
		pDoc->SetTitle(pDoc->GetPathName());
		
		bHint = TRUE;
	}
	// cambio della directory corrente
	if(lHint & ONUPDATE_FLAG_DIRCHANGED || lHint & ONUPDATE_FLAG_DIRSELECTED)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_DIRCHANGED || ONUPDATE_FLAG_DIRSELECTED\n",__FILE__,__LINE__);

		m_bLoaded = FALSE;

		// salva l'immagine se e' stata modificata
		CWallBrowserDoc* pDoc = (CWallBrowserDoc*)GetDocument();
		if(pDoc)
		{
			if(pDoc->IsModified())
				pDoc->SaveModified(m_szFileName);
			
			m_bLoaded = pDoc->GetPictureFlag();
		}

		// aggiorna la GUI
		CWnd* pWnd = AfxGetMainWnd();
		if(pWnd)
		{
			pWnd->SendMessage(WM_FILE_SAVE,FALSE,0L);
			pWnd->SendMessage(WM_FILE_SAVE_AS,m_bLoaded,0L);
			pWnd->SendMessage(WM_FILE_MOVE,m_bHavePicture,0L);
			pWnd->SendMessage(WM_FILE_DELETE,m_bHavePicture,0L);
			pWnd->SendMessage(WM_EDIT_COPY,m_bLoaded,0L);
			pWnd->SendMessage(WM_EDIT_PASTE,m_bLoaded ? ::IsClipboardFormatAvailable(CF_DIB) : FALSE,0L);
			pWnd->SendMessage(WM_EDIT_UNDO,FALSE,0L);
			pWnd->PostMessage(WM_EDIT_REDO,FALSE,0L);
			UndoEmpty();
			RedoEmpty();
		}

		// deve ripulire l'area client
		if(m_nViewType==VIEWTYPE_SCROLL)
			NotifyRanges();

		Invalidate(TRUE);
		
		bHint = TRUE;
	}
	// e' stato svuotato lo stack per l'undo/redo
	if(lHint & ONUPDATE_FLAG_EMPTYSTACK)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_EMPTYSTACK\n",__FILE__,__LINE__);

		CWnd* pWnd = AfxGetMainWnd();
		if(pWnd)
		{
			pWnd->SendMessage(WM_EDIT_UNDO,FALSE,0L);
			pWnd->PostMessage(WM_EDIT_REDO,FALSE,0L);
		}

		UndoEmpty();
		RedoEmpty();
		
		bHint = TRUE;
	}
	// e' stata cambiata la modalita' di visualizzazione (stretch/scroll)
	if(lHint & ONUPDATE_FLAG_VIEWTYPE)
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_VIEWTYPE\n",__FILE__,__LINE__);

		m_nViewType = m_pWinAppEx->m_Config.GetNumber(WALLBROWSER_OPTIONS_KEY,WALLBROWSER_VIEWTYPE_KEY);
		
		if(m_nViewType==VIEWTYPE_SCROLL)
		{
			// modalita' visualizzazione (centrato/isotropic)
			SetCenterMode(TRUE);
			SetMapMode(MM_ANISOTROPIC);
			SetCursorZoomMode(CURSOR_MODE_BYCLICK);

			// risposiziona le barre dello scroll a 0,0
			POINT point = {0,0};
			ScrollToPosition(point);
			
			SetZoomMode(MODE_ZOOMOFF);
			NotifyRanges();
		}
		else if(m_nViewType==VIEWTYPE_STRETCH)
		{
			// modalita' visualizzazione (centrato/text)
			SetCenterMode(FALSE);
			SetMapMode(MM_TEXT);
			SetCursorZoomMode(CURSOR_MODE_NONE);

			// elimina le barre dello scroll
			CSize size(0,0);
			SetZoomSizes(size);
		}

		// deve ridisegnare l'immagine ripulendo l'area client (dato che passa da una modalita' all'altra)
		Invalidate(TRUE);

		bHint = TRUE;
	}
	// e' stata cambiata la modalita' di disegno
	if((lHint & ONUPDATE_FLAG_DRAWSTRETCHDIBITS) || (lHint & ONUPDATE_FLAG_DRAWSTRETCHBLT) || (lHint & ONUPDATE_FLAG_DRAWVFWDRAWDIB))
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_DRAWSTRETCHDIBITS || ONUPDATE_FLAG_DRAWSTRETCHBLT || ONUPDATE_FLAG_DRAWVFWDRAWDIB\n",__FILE__,__LINE__);

		if(lHint & ONUPDATE_FLAG_DRAWSTRETCHDIBITS)
			m_nDrawMode = DRAW_STRETCHDIBITS;
		else if(lHint & ONUPDATE_FLAG_DRAWSTRETCHBLT)
			m_nDrawMode = DRAW_STRETCHBLT;
		else if (lHint & ONUPDATE_FLAG_DRAWVFWDRAWDIB)
			m_nDrawMode = DRAW_VFWDRAWDIB;
		else
			m_nDrawMode = DEFAULT_DRAWMODE;

		// deve ridisegnare l'immagine senza ripulire l'area client (cambia solo la modalita' di disegno, non quella di visualizzazione)
		Invalidate(FALSE);

		bHint = TRUE;
	}
	// e' stato cambiato il fattore di zoom
	if((lHint & ONUPDATE_FLAG_ZOOMIN) || (lHint & ONUPDATE_FLAG_ZOOMOUT) || (lHint & ONUPDATE_FLAG_ZOOMRESET))
	{
		TRACE("%s(%d): receiving ONUPDATE_FLAG_ZOOMIN || ONUPDATE_FLAG_ZOOMOUT || ONUPDATE_FLAG_ZOOMRESET\n",__FILE__,__LINE__);

		if(lHint & ONUPDATE_FLAG_ZOOMIN)
		{
			SetZoomMode(MODE_ZOOMIN);
			TRACE("zoom ratio: %.2f\n",GetZoomRatio());
			if(GetZoomRatio() <= 28.42)
				DoZoomIn();
		}
		else if(lHint & ONUPDATE_FLAG_ZOOMOUT)
		{
			SetZoomMode(MODE_ZOOMOUT);
			TRACE("zoom ratio: %.2f\n",GetZoomRatio());
			if(GetZoomRatio() >= 0.04)
				DoZoomOut();
		}
		else if(lHint & ONUPDATE_FLAG_ZOOMRESET)
		{
			SetZoomMode(MODE_ZOOMOFF);
			NotifyRanges();
			Invalidate(TRUE);
		}

		bHint = TRUE;
	}

done:

	// classe base
	if(!bHint)
		CZoomView::OnUpdate(pSender,lHint,pHint);
}