/******************************************************************************/ /* THUMNAIL.CPP: IMPLEMENTATION OF THE CThumbNailView and CFloatThumNailView */ /* and CFullScreenThumbNailView Classes */ /* */ /******************************************************************************/ /* */ /* Methods in this file */ /* */ /* CThumbNailView Class Object */ /* CThumbNailView::CThumbNailView */ /* CThumbNailView::CThumbNailView */ /* CThumbNailView::~CThumbNailView */ /* CThumbNailView::Create */ /* CThumbNailView::OnSize */ /* CThumbNailView::OnPaint */ /* CThumbNailView::DrawImage */ /* CThumbNailView::DrawTracker */ /* CThumbNailView::RefreshImage */ /* CThumbNailView::GetImgWnd */ /* CThumbNailView::OnKeyDown */ /* CThumbNailView::OnLButtonDown */ /* CThumbNailView::OnRButtonDown */ /* CThumbNailView::OnThumbnailThumbnail */ /* CThumbNailView::OnUpdateThumbnailThumbnail */ /* */ /* CFloatThumbNailView Class Object */ /* CFloatThumbNailView::CFloatThumbNailView */ /* CFloatThumbNailView::~CFloatThumbNailView */ /* CFloatThumbNailView::Create */ /* CFloatThumbNailView::OnClose */ /* CFloatThumbNailView::OnSize */ /* */ /* CFullScreenThumbNailView Class Object */ /* CFullScreenThumbNailView::CFullScreenThumbNailView */ /* CFullScreenThumbNailView::CFullScreenThumbNailView */ /* CFullScreenThumbNailView::~CFullScreenThumbNailView */ /* CFullScreenThumbNailView::Create */ /* CFullScreenThumbNailView::OnLButtonDown */ /* CFullScreenThumbNailView::OnKeyDown */ /* */ /******************************************************************************/ /* */ /* These 3 objects provide a layer around the thumbnail view window, which */ /* allow it to easily be a child, floating or a full screen. The ThumbNail */ /* View Window is just a CWnd Window which on paints does a BitBlt from the */ /* CImgWnd it was passsed on construction. */ /* */ /* The structure of the objects is as follows: */ /* */ /* CFullScreenThumbNailView is a Frame Window (with no border and sized to */ /* full screen). It destroys itself on any keystroke or button click */ /* while visible, it dissables the main application window. It contains */ /* a CThumbNailView object as a child window. */ /* */ /* CFloatThumbNailView is a MiniFrame Window */ /* CThumbNailView is a Child Window (which is sizable) A child of the */ /* the CFloatThumbNailView window. This can be created */ /* independent if a floating window is not desired (i.e. */ /* for the docked view). It is this window which has the */ /* image drawn into it. */ /* */ /* */ /******************************************************************************/ #include "stdafx.h" #include "global.h" #include "pbrush.h" #include "pbrusdoc.h" #include "pbrusfrm.h" #include "pbrusvw.h" #include "minifwnd.h" #include "docking.h" #include "bmobject.h" #include "imgsuprt.h" #include "imgwnd.h" #include "imgcolor.h" #include "imgbrush.h" #include "imgwell.h" #include "imgtools.h" #include "imgwnd.h" #include "thumnail.h" #ifdef _DEBUG #undef THIS_FILE static CHAR BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CThumbNailView, CWnd) IMPLEMENT_DYNAMIC(CFloatThumbNailView, CMiniFrmWnd) IMPLEMENT_DYNAMIC(CFullScreenThumbNailView, CFrameWnd) #include "memtrace.h" /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ BEGIN_MESSAGE_MAP(CThumbNailView, CWnd) //{{AFX_MSG_MAP(CThumbNailView) ON_WM_PAINT() ON_WM_KEYDOWN() ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_COMMAND(ID_THUMBNAIL_THUMBNAIL, OnThumbnailThumbnail) ON_UPDATE_COMMAND_UI(ID_THUMBNAIL_THUMBNAIL, OnUpdateThumbnailThumbnail) ON_WM_CLOSE() //}}AFX_MSG_MAP END_MESSAGE_MAP() /******************************************************************************/ CThumbNailView::CThumbNailView(CImgWnd *pcImgWnd) { m_pcImgWnd = pcImgWnd; } /******************************************************************************/ CThumbNailView::CThumbNailView() { m_pcImgWnd = NULL; } /******************************************************************************/ CThumbNailView::~CThumbNailView(void) { } /******************************************************************************/ BOOL CThumbNailView::Create(DWORD dwStyle, CRect cRectWindow, CWnd *pcParentWnd) { return( CWnd::Create(NULL, TEXT(""), dwStyle, cRectWindow, pcParentWnd, NULL) ); } /***************************************************************************/ void CThumbNailView::OnClose() { ShowWindow(SW_HIDE); } /******************************************************************************/ void CThumbNailView::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here #ifdef USE_MIRRORING // // Disable RTL mirroring on full screen window // if (PBGetLayout(dc.GetSafeHdc()) & LAYOUT_RTL) { PBSetLayout(dc.GetSafeHdc(), 0); } #endif // Do not call CWnd::OnPaint() for painting messages DrawImage(&dc); } /******************************************************************************/ void CThumbNailView::DrawImage(CDC* pDC) { /* ** when there is nothing to do, then don't do it */ if (! theApp.m_bShowThumbnail || m_pcImgWnd == NULL || m_pcImgWnd->m_pImg == NULL ) return; CRect crectClient; int iMinWidth; int iMinHeight; int iLeft; int iTop; CSize cSizeScrollPos = m_pcImgWnd->GetScrollPos(); cSizeScrollPos.cx = abs( cSizeScrollPos.cx ) - CTracker::HANDLE_SIZE; cSizeScrollPos.cy = abs( cSizeScrollPos.cy ) - CTracker::HANDLE_SIZE; GetClientRect(crectClient); // find the smaller of the two the real image or the thumbnail window. iMinWidth = min( crectClient.Width() , m_pcImgWnd->m_pImg->cxWidth ); iMinHeight = min( crectClient.Height(), m_pcImgWnd->m_pImg->cyHeight ); if (crectClient.Width() >= m_pcImgWnd->m_pImg->cxWidth) { iLeft = 0; // can fit the whole image width into the thumbnail } else // image width greater than thumbnail width { // does thumbnail extend past end if started at scroll pos? if (cSizeScrollPos.cx + crectClient.Width() > m_pcImgWnd->m_pImg->cxWidth) { iLeft = cSizeScrollPos.cx - ( (cSizeScrollPos.cx + crectClient.Width() - m_pcImgWnd->m_pImg->cxWidth)); } else { iLeft = cSizeScrollPos.cx; } } if (crectClient.Height() >= m_pcImgWnd->m_pImg->cyHeight) { iTop = 0; // can fit the whole image height into the thumbnail } else // image height greater than thumbnail height { // does thumbnail extend past bottom if started at scroll pos? if (cSizeScrollPos.cy + crectClient.Height() > m_pcImgWnd->m_pImg->cyHeight) { iTop = cSizeScrollPos.cy - ( (cSizeScrollPos.cy + crectClient.Height() - m_pcImgWnd->m_pImg->cyHeight)); } else { iTop = cSizeScrollPos.cy; } } CDC cDC; cDC.Attach(m_pcImgWnd->m_pImg->hDC); CPalette* ppalOldSrc = theImgBrush.SetBrushPalette(&cDC, FALSE); CPalette* ppalOldDst = theImgBrush.SetBrushPalette( pDC, FALSE); pDC->BitBlt(0, 0, iMinWidth, iMinHeight, &cDC, iLeft, iTop, SRCCOPY); if (ppalOldDst) { pDC->SelectPalette(ppalOldDst, FALSE); } if (ppalOldSrc) { cDC.SelectPalette(ppalOldSrc, FALSE); } cDC.Detach(); DrawTracker(pDC); } /******************************************************************************/ /* basically the same processing as the imgwnd::drawtracker method, without */ /* the zoom */ void CThumbNailView::DrawTracker(CDC *pDC) { // BOOL bDrawTrackerRgn = FALSE; if (m_pcImgWnd->GetCurrent() != m_pcImgWnd || theImgBrush.m_bMoveSel || theImgBrush.m_bSmearSel || theImgBrush.m_bMakingSelection) { // This is not the active view, or the user is doing something // to prevent the tracker from appearing. return; } BOOL bReleaseDC = FALSE; CRect clientRect; if (pDC == NULL) { pDC = GetDC(); if (pDC == NULL) { theApp.SetGdiEmergency(FALSE); return; } bReleaseDC = TRUE; } GetClientRect(&clientRect); CRect trackerRect; m_pcImgWnd->GetImageRect(trackerRect); trackerRect.InflateRect(CTracker::HANDLE_SIZE, CTracker::HANDLE_SIZE); CTracker::EDGES edges = (CTracker::EDGES)(CTracker::right | CTracker::bottom); // if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL) // { // bDrawTrackerRgn = TRUE; // } if (m_pcImgWnd->m_pImg == theImgBrush.m_pImg) { edges = CTracker::all; CSize cSzScroll = m_pcImgWnd->GetScrollPos(); trackerRect = theImgBrush.m_rcSelection; // trackerRect.InflateRect( CTracker::HANDLE_SIZE, // CTracker::HANDLE_SIZE); trackerRect.OffsetRect( cSzScroll.cx, cSzScroll.cy); } if (m_pcImgWnd->m_pImg == theImgBrush.m_pImg) { // if (bDrawTrackerRgn) // { // CTracker::DrawBorderRgn( pDC, trackerRect, &(theImgBrush.m_cRgnPolyFreeHandSel) ); // } // else // { CTracker::DrawBorder( pDC, trackerRect ); // } } if (bReleaseDC) { ReleaseDC(pDC); } } /******************************************************************************/ /* Basically Do a paint without an erase background to prevent blinking */ void CThumbNailView::RefreshImage(void) { if (theApp.m_bShowThumbnail) { TRY { CClientDC dc(this); DrawImage(&dc); } CATCH(CResourceException,e) { } END_CATCH } } /******************************************************************************/ CImgWnd* CThumbNailView::GetImgWnd(void) { return m_pcImgWnd; } /******************************************************************************/ void CThumbNailView::UpdateThumbNailView() { CPBView* pcbActiveView = (CPBView*)((CFrameWnd*)AfxGetMainWnd())->GetActiveView(); m_pcImgWnd = pcbActiveView->m_pImgWnd; } /******************************************************************************/ void CThumbNailView::OnKeyDown(UINT /*nChar*/, UINT /*nRepCnt*/, UINT /*nFlags*/) { const MSG* pmsg = GetCurrentMessage(); GetParent()->SendMessage( pmsg->message, pmsg->wParam, pmsg->lParam ); } /******************************************************************************/ void CThumbNailView::OnLButtonDown(UINT /*nFlags*/, CPoint /*point*/) { const MSG* pmsg = GetCurrentMessage(); GetParent()->SendMessage(pmsg->message, pmsg->wParam, pmsg->lParam); } /******************************************************************************/ void CThumbNailView::OnRButtonDown(UINT /*nFlags*/, CPoint point) { HWND hwnd = GetSafeHwnd(); // must do this before calling SendMsg to parent, since it could delete us, const MSG* pmsg = GetCurrentMessage(); GetParent()->SendMessage(pmsg->message, pmsg->wParam, pmsg->lParam); // the window is destroyed by the parent if FullScreenView if (::IsWindow(hwnd) != FALSE) // window still exists => object still valid, put up pop up menu. { CMenu cMenuPopup; CMenu *pcContextMenu; BOOL bRC; CRect cRectClient; GetClientRect(&cRectClient); bRC = cMenuPopup.LoadMenu( IDR_THUMBNAIL_POPUP ); ASSERT(bRC != 0); if (bRC != 0) { pcContextMenu = cMenuPopup.GetSubMenu(0); ASSERT(pcContextMenu != NULL); if (pcContextMenu != NULL) { // update the check marks ClientToScreen(&point); ClientToScreen(&cRectClient); pcContextMenu->CheckMenuItem(ID_THUMBNAIL_THUMBNAIL, MF_BYCOMMAND | MF_CHECKED); pcContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this, &cRectClient); } } } } /******************************************************************************/ void CThumbNailView::OnThumbnailThumbnail() { CPBView* pView = (CPBView*)(((CFrameWnd*)AfxGetMainWnd())->GetActiveView()); if (pView != NULL && pView->IsKindOf( RUNTIME_CLASS( CPBView ) )) pView->HideThumbNailView(); } /******************************************************************************/ void CThumbNailView::OnUpdateThumbnailThumbnail(CCmdUI* pCmdUI) { pCmdUI->SetCheck(); } /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ BEGIN_MESSAGE_MAP(CFloatThumbNailView, CMiniFrmWnd) //{{AFX_MSG_MAP(CFloatThumbNailView) ON_WM_CLOSE() ON_WM_SIZE() ON_WM_GETMINMAXINFO() //}}AFX_MSG_MAP END_MESSAGE_MAP() /******************************************************************************/ CFloatThumbNailView::CFloatThumbNailView(CImgWnd *pcMainImgWnd) { m_pcThumbNailView = new CThumbNailView(pcMainImgWnd); if (m_pcThumbNailView == NULL) { theApp.SetMemoryEmergency(); TRACE( TEXT("New Thumbnail View faild\n") ); } } /******************************************************************************/ CFloatThumbNailView::CFloatThumbNailView() { m_pcThumbNailView = NULL; } /******************************************************************************/ CFloatThumbNailView::~CFloatThumbNailView(void) { } /******************************************************************************/ BOOL CFloatThumbNailView::Create(CWnd* pParentWnd) { BOOL bRC; CRect cWindowRect; pParentWnd->GetWindowRect( &cWindowRect ); cWindowRect.BottomRight() = cWindowRect.TopLeft(); cWindowRect.right += 120; cWindowRect.bottom += 120; cWindowRect.OffsetRect( 15, 15 ); if (! theApp.m_rectFloatThumbnail.IsRectEmpty()) { cWindowRect = theApp.m_rectFloatThumbnail; } CString pWindowName; pWindowName.LoadString( IDS_VIEW ); bRC = CMiniFrmWnd::Create( pWindowName, WS_THICKFRAME, cWindowRect, pParentWnd ); if (bRC) { ASSERT( m_pcThumbNailView ); GetClientRect( &cWindowRect ); if (!m_pcThumbNailView->Create( WS_CHILD | WS_VISIBLE, cWindowRect, this )) { bRC = FALSE; theApp.SetMemoryEmergency(); TRACE( TEXT("New Thumbnail View faild\n") ); } } GetWindowRect( &theApp.m_rectFloatThumbnail ); return bRC; } /******************************************************************************/ // OnClose // // A Colorsbox is usally created by the parent, and will be destroyed // specifically by the parent upon leaving the app. When the user closes // the Colorsbox, it is simply hidden. The parent can then reshow it without // recreating it. // void CFloatThumbNailView::OnClose() { theApp.m_bShowThumbnail = FALSE; ShowWindow(SW_HIDE); } /******************************************************************************/ void CFloatThumbNailView::PostNcDestroy() { if (m_pcThumbNailView != NULL) { delete m_pcThumbNailView; m_pcThumbNailView = NULL; } CWnd::PostNcDestroy(); } /******************************************************************************/ void CFloatThumbNailView::OnSize(UINT nType, int cx, int cy) { CMiniFrmWnd::OnSize(nType, cx, cy); if (m_pcThumbNailView != NULL && m_pcThumbNailView->GetSafeHwnd() != NULL) { m_pcThumbNailView->SetWindowPos( &wndTop, 0, 0, cx, cy, SWP_NOACTIVATE ); } theApp.m_rectFloatThumbnail.right = theApp.m_rectFloatThumbnail.left + cx; theApp.m_rectFloatThumbnail.bottom = theApp.m_rectFloatThumbnail.top + cy; } /******************************************************************************/ void CFloatThumbNailView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { lpMMI->ptMinTrackSize.x = 2 * GetSystemMetrics( SM_CXICON ); lpMMI->ptMinTrackSize.y = 2 * GetSystemMetrics( SM_CYICON ); CWnd::OnGetMinMaxInfo( lpMMI ); } /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ BEGIN_MESSAGE_MAP(CFullScreenThumbNailView, CFrameWnd) //{{AFX_MSG_MAP(CFullScreenThumbNailView) ON_WM_LBUTTONDOWN() ON_WM_KEYDOWN() ON_WM_RBUTTONDOWN() ON_WM_ERASEBKGND() ON_WM_CLOSE() //}}AFX_MSG_MAP END_MESSAGE_MAP() /******************************************************************************/ CFullScreenThumbNailView::CFullScreenThumbNailView(CImgWnd *pcMainImgWnd) { m_bSaveShowFlag = theApp.m_bShowThumbnail; theApp.m_bShowThumbnail = TRUE; // m_brBackground.CreateSolidBrush( ::GetSysColor( COLOR_BACKGROUND ) ); m_pcThumbNailView = new CThumbNailView(pcMainImgWnd); if (m_pcThumbNailView == NULL) { theApp.SetMemoryEmergency(); TRACE( TEXT("New Thumbnail View faild\n") ); } } /******************************************************************************/ CFullScreenThumbNailView::CFullScreenThumbNailView() { m_hOldIcon = 0; m_pcThumbNailView = NULL; } /******************************************************************************/ CFullScreenThumbNailView::~CFullScreenThumbNailView(void) { if (m_hOldIcon) { SetClassLongPtr (((CFrameWnd*)this)->GetSafeHwnd(), GCLP_HICON, (LONG_PTR)m_hOldIcon); } if (m_pcThumbNailView != NULL) { delete m_pcThumbNailView; theApp.m_bShowThumbnail = m_bSaveShowFlag; } // if (m_brBackground.m_hObject != NULL) // m_brBackground.DeleteObject(); } /******************************************************************************/ BOOL CFullScreenThumbNailView::Create(LPCTSTR szCaption) { ASSERT( m_pcThumbNailView ); TCHAR szFileName[MAX_PATH]; HICON hIcon; CRect cWindowRect( 0, 0, ::GetSystemMetrics( SM_CXSCREEN ), ::GetSystemMetrics( SM_CYSCREEN ) ); // // Use the current file name as the caption of the window so // it shows up in alt-tab if (szCaption && *szCaption) { GetFileTitle (szCaption, szFileName, MAX_PATH); } else { LoadString (GetModuleHandle (NULL), AFX_IDS_UNTITLED, szFileName, MAX_PATH); } BOOL bRC = CFrameWnd::Create( NULL, szFileName, WS_POPUP|WS_VISIBLE | WS_CLIPCHILDREN, cWindowRect ); // // This window needs a Paint icon instead of a boring icon // So set the class's icon to the Paint icon // We want alt-tab to work decently hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE(ID_MAINFRAME)); m_hOldIcon = SetClassLongPtr (((CFrameWnd*)this)->GetSafeHwnd(), GCLP_HICON, (LONG_PTR)hIcon); if (bRC) { ASSERT( m_pcThumbNailView ); AfxGetMainWnd()->EnableWindow( FALSE ); CImgWnd* pcImgWnd = m_pcThumbNailView->GetImgWnd(); if (pcImgWnd != NULL) { // find the smaller of the two the real image or the full screen window size. int iMinWidth = min( cWindowRect.Width(), pcImgWnd->m_pImg->cxWidth ); int iMinHeight = min( cWindowRect.Height(), pcImgWnd->m_pImg->cyHeight ); // center the image in the full screen window. cWindowRect.left = (cWindowRect.Width() - iMinWidth) / 2; cWindowRect.top = (cWindowRect.Height() - iMinHeight) / 2; cWindowRect.right = cWindowRect.left + iMinWidth; cWindowRect.bottom = cWindowRect.top + iMinHeight; m_pcThumbNailView->Create( WS_CHILD | WS_VISIBLE, cWindowRect, this ); } } return bRC; } /******************************************************************************/ BOOL CFullScreenThumbNailView::OnEraseBkgnd( CDC* pDC ) { CBrush* pbr = GetSysBrush( COLOR_BACKGROUND ); // if (m_brBackground.m_hObject == NULL) if (! pbr) return CFrameWnd::OnEraseBkgnd( pDC ); CRect cRectClient; GetClientRect( &cRectClient ); pDC->FillRect( &cRectClient, pbr /* &m_brBackground */ ); return TRUE; } /******************************************************************************/ void CFullScreenThumbNailView::OnLButtonDown(UINT /*nFlags*/, CPoint /*point*/) { PostMessage (WM_CLOSE, 0, 0); } /******************************************************************************/ void CFullScreenThumbNailView::OnKeyDown(UINT /*nChar*/, UINT /*nRepCnt*/, UINT /*nFlags*/) { PostMessage (WM_CLOSE, 0, 0); } /******************************************************************************/ void CFullScreenThumbNailView::OnClose () { AfxGetMainWnd()->EnableWindow( TRUE ); ::DestroyWindow( m_hWnd ); } /******************************************************************************/