windows-nt/Source/XPSP1/NT/shell/osshell/accesory/mspaint/thumnail.cpp
2020-09-26 16:20:57 +08:00

742 lines
24 KiB
C++

/******************************************************************************/
/* 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 );
}
/******************************************************************************/