Browse Source

show scroll bar when viewing image

ScottBrogden 9 years ago
parent
commit
1b482527fb
8 changed files with 685 additions and 76 deletions
  1. 4 0
      CP_Main.vcxproj
  2. 4 0
      CP_Main.vcxproj.filters
  3. 146 0
      ImageViewer.cpp
  4. 32 0
      ImageViewer.h
  5. 400 0
      ScrollHelper.cpp
  6. 59 0
      ScrollHelper.h
  7. 31 73
      ToolTipEx.cpp
  8. 9 3
      ToolTipEx.h

+ 4 - 0
CP_Main.vcxproj

@@ -586,6 +586,7 @@
     <ClCompile Include="GdipButton.cpp" />
     <ClCompile Include="GdipButton.cpp" />
     <ClCompile Include="GlobalClips.cpp" />
     <ClCompile Include="GlobalClips.cpp" />
     <ClCompile Include="HotKeys.cpp" />
     <ClCompile Include="HotKeys.cpp" />
+    <ClCompile Include="ImageViewer.cpp" />
     <ClCompile Include="MainFrmThread.cpp" />
     <ClCompile Include="MainFrmThread.cpp" />
     <ClCompile Include="MessagePumpThread.cpp" />
     <ClCompile Include="MessagePumpThread.cpp" />
     <ClCompile Include="MyDropTarget.cpp" />
     <ClCompile Include="MyDropTarget.cpp" />
@@ -649,6 +650,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="QuickPasteKeyboard.cpp" />
     <ClCompile Include="QuickPasteKeyboard.cpp" />
+    <ClCompile Include="ScrollHelper.cpp" />
     <ClCompile Include="Shared\TextConvert.cpp" />
     <ClCompile Include="Shared\TextConvert.cpp" />
     <ClCompile Include="Shared\Tokenizer.cpp" />
     <ClCompile Include="Shared\Tokenizer.cpp" />
     <ClCompile Include="ShowTaskBarIcon.cpp" />
     <ClCompile Include="ShowTaskBarIcon.cpp" />
@@ -1857,6 +1859,7 @@
     <ClInclude Include="GlobalClips.h" />
     <ClInclude Include="GlobalClips.h" />
     <ClInclude Include="GroupStatic.h" />
     <ClInclude Include="GroupStatic.h" />
     <ClInclude Include="HotKeys.h" />
     <ClInclude Include="HotKeys.h" />
+    <ClInclude Include="ImageViewer.h" />
     <ClInclude Include="MainFrmThread.h" />
     <ClInclude Include="MainFrmThread.h" />
     <ClInclude Include="memdc.h" />
     <ClInclude Include="memdc.h" />
     <ClInclude Include="MessagePumpThread.h" />
     <ClInclude Include="MessagePumpThread.h" />
@@ -1881,6 +1884,7 @@
     <ClInclude Include="QRCode\split.h" />
     <ClInclude Include="QRCode\split.h" />
     <ClInclude Include="QuickPasteKeyboard.h" />
     <ClInclude Include="QuickPasteKeyboard.h" />
     <ClInclude Include="RichEditCtrlEx.h" />
     <ClInclude Include="RichEditCtrlEx.h" />
+    <ClInclude Include="ScrollHelper.h" />
     <ClInclude Include="SearchEditBox.h" />
     <ClInclude Include="SearchEditBox.h" />
     <ClInclude Include="Shared\TextConvert.h" />
     <ClInclude Include="Shared\TextConvert.h" />
     <ClInclude Include="Shared\Tokenizer.h" />
     <ClInclude Include="Shared\Tokenizer.h" />

+ 4 - 0
CP_Main.vcxproj.filters

@@ -400,6 +400,8 @@
     <ClCompile Include="PowerManager.cpp" />
     <ClCompile Include="PowerManager.cpp" />
     <ClCompile Include="QuickPasteKeyboard.cpp" />
     <ClCompile Include="QuickPasteKeyboard.cpp" />
     <ClCompile Include="NTray.cpp" />
     <ClCompile Include="NTray.cpp" />
+    <ClCompile Include="ScrollHelper.cpp" />
+    <ClCompile Include="ImageViewer.cpp" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="sqlite\CppSQLite3.h">
     <ClInclude Include="sqlite\CppSQLite3.h">
@@ -852,6 +854,8 @@
     <ClInclude Include="PowerManager.h" />
     <ClInclude Include="PowerManager.h" />
     <ClInclude Include="QuickPasteKeyboard.h" />
     <ClInclude Include="QuickPasteKeyboard.h" />
     <ClInclude Include="NTray.h" />
     <ClInclude Include="NTray.h" />
+    <ClInclude Include="ScrollHelper.h" />
+    <ClInclude Include="ImageViewer.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="CP_Main.rc">
     <ResourceCompile Include="CP_Main.rc">

+ 146 - 0
ImageViewer.cpp

@@ -0,0 +1,146 @@
+// ImageViewer.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "CP_Main.h"
+#include "ImageViewer.h"
+#include "BitmapHelper.h"
+
+
+// CImageViewer
+
+IMPLEMENT_DYNAMIC(CImageViewer, CWnd)
+
+CImageViewer::CImageViewer()
+{
+	m_pBitmap = NULL;
+	m_scrollHelper.AttachWnd(this);
+}
+
+CImageViewer::~CImageViewer()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CImageViewer, CWnd)
+	ON_WM_HSCROLL()
+	ON_WM_VSCROLL()
+	ON_WM_MOUSEWHEEL()
+	ON_WM_PAINT()
+	ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+BOOL CImageViewer::Create(CWnd* pParent)
+{
+	BOOL bSuccess;
+
+	// Register window class
+	CString csClassName = AfxRegisterWndClass(CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
+		::LoadCursor(NULL, IDC_APPSTARTING),
+		CBrush(::GetSysColor(COLOR_BTNFACE)));
+
+
+
+	// If no parent supplied then try and get a pointer to it anyway
+	if (!pParent)
+		pParent = AfxGetMainWnd();
+
+	// Create popup window
+	//bSuccess = CreateEx(WS_EX_DLGMODALFRAME|WS_EX_TOPMOST, // Extended style
+	bSuccess = CreateEx(0,
+		csClassName,                       // Classname
+		_T(""),                          // Title
+		WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL,     // style
+		0, 0,                               // position - updated soon.
+		390, 130,                           // Size - updated soon
+		pParent->GetSafeHwnd(),            // handle to parent
+		0,                                 // No menu
+		NULL);
+	if (!bSuccess) return FALSE;
+
+
+
+	return TRUE;
+}
+
+void CImageViewer::UpdateBitmapSize()
+{
+	if (m_pBitmap != NULL)
+	{
+		int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
+		int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+
+		m_scrollHelper.SetDisplaySize(nWidth, nHeight);
+	}
+}
+
+void CImageViewer::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+
+	CRect rect;
+	GetClientRect(rect);	
+
+	CBrush  Brush, *pOldBrush;
+	Brush.CreateSolidBrush(GetSysColor(COLOR_INFOBK));
+
+	pOldBrush = dc.SelectObject(&Brush);
+
+	dc.FillRect(&rect, &Brush);
+
+	if (m_pBitmap)
+	{
+		CDC MemDc;
+		MemDc.CreateCompatibleDC(&dc);
+
+		CBitmap *oldBitmap = MemDc.SelectObject(m_pBitmap);
+
+		int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
+		int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+
+		if (CGetSetOptions::GetScaleImagesToDescWindow())
+		{
+			dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
+			//OutputDebugString(StrF(_T("scaling image, window size %d/%d, image %d/%d\n"), min(nWidth, rect.Width()), min(nHeight, rect.Height()), nWidth, nHeight));
+		}
+		else
+		{
+			CSize s = m_scrollHelper.GetScrollPos();
+			dc.BitBlt(rect.left, rect.top, nWidth, nHeight, &MemDc, s.cx, s.cy, SRCCOPY);
+		}
+
+		//dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
+
+		MemDc.SelectObject(oldBitmap);
+
+		rect.top += nHeight;
+	}
+	
+	// Cleanup
+	dc.SelectObject(pOldBrush);
+}
+
+
+void CImageViewer::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+	m_scrollHelper.OnHScroll(nSBCode, nPos, pScrollBar);
+}
+
+void CImageViewer::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+	m_scrollHelper.OnVScroll(nSBCode, nPos, pScrollBar);
+}
+
+BOOL CImageViewer::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+	BOOL wasScrolled = m_scrollHelper.OnMouseWheel(nFlags, zDelta, pt);
+	return wasScrolled;
+}
+
+void CImageViewer::OnSize(UINT nType, int cx, int cy)
+{
+	CWnd::OnSize(nType, cx, cy);
+	m_scrollHelper.OnSize(nType, cx, cy);
+}
+
+

+ 32 - 0
ImageViewer.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "ScrollHelper.h"
+
+
+
+class CImageViewer : public CWnd
+{
+	DECLARE_DYNAMIC(CImageViewer)
+
+public:
+	CImageViewer();
+	virtual ~CImageViewer();
+
+	CBitmap *m_pBitmap;
+	CScrollHelper m_scrollHelper;
+
+	void UpdateBitmapSize();
+
+	BOOL Create(CWnd* pParent);
+
+protected:
+	DECLARE_MESSAGE_MAP()
+
+	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnPaint();
+};
+
+

+ 400 - 0
ScrollHelper.cpp

@@ -0,0 +1,400 @@
+// Filename: ScrollHelper.cpp
+// 2005-07-01 nschan Initial revision.
+// 2005-09-08 nschan Added GetClientRectSB() function.
+
+#include "stdafx.h"
+#include "ScrollHelper.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+// Helper function to get client rect with possible
+// modification by adding scrollbar width/height.
+static void GetClientRectSB(CWnd* pWnd, CRect& rect)
+{
+    ASSERT( pWnd != NULL );
+
+    CRect winRect;
+    pWnd->GetWindowRect(&winRect);
+    pWnd->ScreenToClient(&winRect);
+
+    pWnd->GetClientRect(&rect);
+
+    int cxSB = ::GetSystemMetrics(SM_CXVSCROLL);
+    int cySB = ::GetSystemMetrics(SM_CYHSCROLL);
+
+    if ( winRect.right >= (rect.right + cxSB) )
+        rect.right += cxSB;
+    if ( winRect.bottom >= (rect.bottom + cySB) )
+        rect.bottom += cySB;
+}
+
+// CScrollHelper /////////////////////////////////////////////////////////////////////
+
+CScrollHelper::CScrollHelper()
+{
+    m_attachWnd   = NULL;
+    m_pageSize    = CSize(0,0);
+    m_displaySize = CSize(0,0);
+    m_scrollPos   = CSize(0,0);
+}
+
+CScrollHelper::~CScrollHelper()
+{
+    DetachWnd();
+}
+
+void CScrollHelper::AttachWnd(CWnd* pWnd)
+{
+    m_attachWnd = pWnd;
+}
+
+void CScrollHelper::DetachWnd()
+{
+    m_attachWnd = NULL;
+}
+
+void CScrollHelper::SetDisplaySize(int displayWidth, int displayHeight)
+{
+	int cxSB = ::GetSystemMetrics(SM_CXVSCROLL);
+	int cySB = ::GetSystemMetrics(SM_CYHSCROLL);
+
+    m_displaySize = CSize(displayWidth + cxSB, displayHeight + cySB);
+
+    if ( m_attachWnd != NULL && ::IsWindow(m_attachWnd->m_hWnd) )
+        UpdateScrollInfo();
+}
+
+const CSize& CScrollHelper::GetDisplaySize() const
+{
+    return m_displaySize;
+}
+
+const CSize& CScrollHelper::GetScrollPos() const
+{
+    return m_scrollPos;
+}
+
+const CSize& CScrollHelper::GetPageSize() const
+{
+    return m_pageSize;
+}
+
+void CScrollHelper::ScrollToOrigin(bool scrollLeft, bool scrollTop)
+{
+    if ( m_attachWnd == NULL )
+        return;
+
+    if ( scrollLeft )
+    {
+        if ( m_displaySize.cx > 0 && m_pageSize.cx > 0 && m_scrollPos.cx > 0 )
+        {
+            int deltaPos = -m_scrollPos.cx;
+            m_scrollPos.cx += deltaPos;
+            m_attachWnd->SetScrollPos(SB_HORZ, m_scrollPos.cx, TRUE);
+            m_attachWnd->ScrollWindow(-deltaPos, 0);
+        }
+    }
+
+    if ( scrollTop )
+    {
+        if ( m_displaySize.cy > 0 && m_pageSize.cy > 0 && m_scrollPos.cy > 0 )
+        {
+            int deltaPos = -m_scrollPos.cy;
+            m_scrollPos.cy += deltaPos;
+            m_attachWnd->SetScrollPos(SB_VERT, m_scrollPos.cy, TRUE);
+            m_attachWnd->ScrollWindow(0, -deltaPos);
+        }
+    }
+}
+
+void CScrollHelper::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+    if ( m_attachWnd == NULL )
+        return;
+
+    const int lineOffset = 60;
+
+    // Compute the desired change or delta in scroll position.
+    int deltaPos = 0;
+    switch( nSBCode )
+    {
+    case SB_LINELEFT:
+        // Left scroll arrow was pressed.
+        deltaPos = -lineOffset;
+        break;
+
+    case SB_LINERIGHT:
+        // Right scroll arrow was pressed.
+        deltaPos = lineOffset;
+        break;
+
+    case SB_PAGELEFT:
+        // User clicked inbetween left arrow and thumb.
+        deltaPos = -m_pageSize.cx;
+        break;
+
+    case SB_PAGERIGHT:
+        // User clicked inbetween thumb and right arrow.
+        deltaPos = m_pageSize.cx;
+        break;
+
+    case SB_THUMBTRACK:
+        // Scrollbar thumb is being dragged.
+        deltaPos = Get32BitScrollPos(SB_HORZ, pScrollBar) - m_scrollPos.cx;
+        break;
+
+    case SB_THUMBPOSITION:
+        // Scrollbar thumb was released.
+        deltaPos = Get32BitScrollPos(SB_HORZ, pScrollBar) - m_scrollPos.cx;
+        break;
+
+    default:
+        // We don't process other scrollbar messages.
+        return;
+    }
+
+    // Compute the new scroll position.
+    int newScrollPos = m_scrollPos.cx + deltaPos;
+
+    // If the new scroll position is negative, we adjust
+    // deltaPos in order to scroll the window back to origin.
+    if ( newScrollPos < 0 )
+        deltaPos = -m_scrollPos.cx;
+
+    // If the new scroll position is greater than the max scroll position,
+    // we adjust deltaPos in order to scroll the window precisely to the
+    // maximum position.
+    int maxScrollPos = m_displaySize.cx - m_pageSize.cx;
+    if ( newScrollPos > maxScrollPos )
+        deltaPos = maxScrollPos - m_scrollPos.cx;
+
+    // Scroll the window if needed.
+    if ( deltaPos != 0 )
+    {
+        m_scrollPos.cx += deltaPos;
+        m_attachWnd->SetScrollPos(SB_HORZ, m_scrollPos.cx, TRUE);
+        m_attachWnd->ScrollWindow(-deltaPos, 0);
+    }
+}
+
+void CScrollHelper::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
+{
+    if ( m_attachWnd == NULL )
+        return;
+
+    const int lineOffset = 60;
+
+    // Compute the desired change or delta in scroll position.
+    int deltaPos = 0;
+    switch( nSBCode )
+    {
+    case SB_LINEUP:
+        // Up arrow button on scrollbar was pressed.
+        deltaPos = -lineOffset;
+        break;
+
+    case SB_LINEDOWN:
+        // Down arrow button on scrollbar was pressed.
+        deltaPos = lineOffset;
+        break;
+
+    case SB_PAGEUP:
+        // User clicked inbetween up arrow and thumb.
+        deltaPos = -m_pageSize.cy;
+        break;
+
+    case SB_PAGEDOWN:
+        // User clicked inbetween thumb and down arrow.
+        deltaPos = m_pageSize.cy;
+        break;
+
+    case SB_THUMBTRACK:
+        // Scrollbar thumb is being dragged.
+        deltaPos = Get32BitScrollPos(SB_VERT, pScrollBar) - m_scrollPos.cy;
+        break;
+
+    case SB_THUMBPOSITION:
+        // Scrollbar thumb was released.
+        deltaPos = Get32BitScrollPos(SB_VERT, pScrollBar) - m_scrollPos.cy;
+        break;
+
+    default:
+        // We don't process other scrollbar messages.
+        return;
+    }
+
+    // Compute the new scroll position.
+    int newScrollPos = m_scrollPos.cy + deltaPos;
+
+    // If the new scroll position is negative, we adjust
+    // deltaPos in order to scroll the window back to origin.
+    if ( newScrollPos < 0 )
+        deltaPos = -m_scrollPos.cy;
+
+    // If the new scroll position is greater than the max scroll position,
+    // we adjust deltaPos in order to scroll the window precisely to the
+    // maximum position.
+    int maxScrollPos = m_displaySize.cy - m_pageSize.cy;
+    if ( newScrollPos > maxScrollPos )
+        deltaPos = maxScrollPos - m_scrollPos.cy;
+
+    // Scroll the window if needed.
+    if ( deltaPos != 0 )
+    {
+        m_scrollPos.cy += deltaPos;
+        m_attachWnd->SetScrollPos(SB_VERT, m_scrollPos.cy, TRUE);
+        m_attachWnd->ScrollWindow(0, -deltaPos);
+    }
+}
+
+BOOL CScrollHelper::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+    if ( m_attachWnd == NULL )
+        return FALSE;
+
+    // Don't do anything if the vertical scrollbar is not enabled.
+    int scrollMin = 0, scrollMax = 0;
+    m_attachWnd->GetScrollRange(SB_VERT, &scrollMin, &scrollMax);
+    if ( scrollMin == scrollMax )
+        return FALSE;
+
+    // Compute the number of scrolling increments requested.
+    int numScrollIncrements = abs(zDelta) / WHEEL_DELTA;
+
+    // Each scrolling increment corresponds to a certain number of
+    // scroll lines (one scroll line is like a SB_LINEUP or SB_LINEDOWN).
+    // We need to query the system parameters for this value.
+    int numScrollLinesPerIncrement = 0;
+    ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &numScrollLinesPerIncrement, 0);
+
+    // Check if a page scroll was requested.
+    if ( numScrollLinesPerIncrement == WHEEL_PAGESCROLL )
+    {
+        // Call the vscroll message handler to do the work.
+        OnVScroll(zDelta > 0 ? SB_PAGEUP : SB_PAGEDOWN, 0, NULL);
+        return TRUE;
+    }
+
+    // Compute total number of lines to scroll.
+    int numScrollLines = numScrollIncrements * numScrollLinesPerIncrement;
+
+    // Adjust numScrollLines to slow down the scrolling a bit more.
+    numScrollLines = max(numScrollLines/3, 1);
+
+    // Do the scrolling.
+    for(int i = 0; i < numScrollLines; ++i)
+    {
+        // Call the vscroll message handler to do the work.
+        OnVScroll(zDelta > 0 ? SB_LINEUP : SB_LINEDOWN, 0, NULL);
+    }
+
+    return TRUE;
+}
+
+void CScrollHelper::OnSize(UINT nType, int cx, int cy)
+{
+    UpdateScrollInfo();
+}
+
+int CScrollHelper::Get32BitScrollPos(int bar, CScrollBar* pScrollBar)
+{
+    // Code below is from MSDN Article ID 152252, "How To Get
+    // 32-bit Scroll Position During Scroll Messages".
+
+    // First determine if the user scrolled a scroll bar control
+    // on the window or scrolled the window itself.
+    ASSERT( m_attachWnd != NULL );
+    HWND hWndScroll;
+    if ( pScrollBar == NULL )
+        hWndScroll = m_attachWnd->m_hWnd;
+    else
+        hWndScroll = pScrollBar->m_hWnd;
+
+    SCROLLINFO si;
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask = SIF_TRACKPOS;
+    ::GetScrollInfo(hWndScroll, bar, &si);
+
+    int scrollPos = si.nTrackPos;
+
+    return scrollPos;
+}
+
+void CScrollHelper::UpdateScrollInfo()
+{
+    if ( m_attachWnd == NULL )
+        return;
+
+    // Get the width/height of the attached wnd that includes the area
+    // covered by the scrollbars (if any). The reason we need this is
+    // because when scrollbars are present, both cx/cy and GetClientRect()
+    // when accessed from OnSize() do not include the scrollbar covered
+    // areas. In other words, their values are smaller than what you would
+    // expect.
+    CRect rect;
+    GetClientRectSB(m_attachWnd, rect);
+    CSize windowSize(rect.Width(), rect.Height());
+
+    // Update horizontal scrollbar.
+    CSize deltaPos(0,0);
+    UpdateScrollBar(SB_HORZ, windowSize.cx, m_displaySize.cx,
+        m_pageSize.cx, m_scrollPos.cx, deltaPos.cx);
+
+    // Update vertical scrollbar.
+    UpdateScrollBar(SB_VERT, windowSize.cy, m_displaySize.cy,
+        m_pageSize.cy, m_scrollPos.cy, deltaPos.cy);
+
+    // See if we need to scroll the window back in place.
+    // This is needed to handle the case where the scrollbar is
+    // moved all the way to the right for example, and controls
+    // at the left side disappear from the view. Then the user
+    // resizes the window wider until scrollbars disappear. Without
+    // this code below, the controls off the page will be gone forever.
+    if ( deltaPos.cx != 0 || deltaPos.cy != 0 )
+    {
+        m_attachWnd->ScrollWindow(deltaPos.cx, deltaPos.cy);
+    }                                                        
+}
+
+void CScrollHelper::UpdateScrollBar(int bar, int windowSize, int displaySize,
+                                    LONG& pageSize, LONG& scrollPos, LONG& deltaPos)
+{
+    int scrollMax = 0;
+    deltaPos = 0;
+    if ( windowSize < displaySize )
+    {
+        scrollMax = displaySize - 1;
+        if ( pageSize > 0 && scrollPos > 0 )
+        {
+            // Adjust the scroll position when the window size is changed.
+            scrollPos = (LONG)(1.0 * scrollPos * windowSize / pageSize);
+        }
+        pageSize = windowSize;
+        scrollPos = min(scrollPos, displaySize - pageSize - 1);
+        deltaPos = m_attachWnd->GetScrollPos(bar) - scrollPos;
+    }
+    else
+    {
+        // Force the scrollbar to go away.
+        pageSize = 0;
+        scrollPos = 0;
+        deltaPos = m_attachWnd->GetScrollPos(bar);
+    }
+
+    SCROLLINFO si;
+    memset(&si, 0, sizeof(SCROLLINFO));
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask  = SIF_ALL;    // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
+    si.nMin   = 0;
+    si.nMax   = scrollMax;
+    si.nPage  = pageSize;
+    si.nPos   = scrollPos;
+    m_attachWnd->SetScrollInfo(bar, &si, TRUE);
+}
+
+// END
+

+ 59 - 0
ScrollHelper.h

@@ -0,0 +1,59 @@
+// Filename: ScrollHelper.h
+// S.Chan, 01 Jul 2005
+
+#ifndef SCROLL_HELPER_INCLUDED
+#define SCROLL_HELPER_INCLUDED
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+class CScrollHelper
+{
+public:
+    CScrollHelper();
+    ~CScrollHelper();
+
+    // Attach/detach a CWnd or CDialog.
+    void   AttachWnd(CWnd* pWnd);
+    void   DetachWnd();
+
+    // Set/get the virtual display size. When the dialog or window
+    // size is smaller than the display size, then that is when
+    // scrollbars will appear. Set either the display width or display
+    // height to zero if you don't want to enable the scrollbar in the
+    // corresponding direction.
+    void   SetDisplaySize(int displayWidth, int displayHeight);
+    const CSize& GetDisplaySize() const;
+
+    // Get current scroll position. This is needed if you are scrolling
+    // a custom CWnd which implements its own drawing in OnPaint().
+    const CSize& GetScrollPos() const;
+
+    // Get current page size. Useful for debugging purposes.
+    const CSize& GetPageSize() const;
+
+    // Scroll back to top, left, or top-left corner of the window.
+    void   ScrollToOrigin(bool scrollLeft, bool scrollTop);
+
+    // Message handling.
+    void   OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+    void   OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+    BOOL   OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+    void   OnSize(UINT nType, int cx, int cy);
+
+private:
+    int    Get32BitScrollPos(int bar, CScrollBar* pScrollBar);
+    void   UpdateScrollInfo();
+    void   UpdateScrollBar(int bar, int windowSize, int displaySize,
+                           LONG& pageSize, LONG& scrollPos, LONG& deltaPos);
+
+    CWnd*  m_attachWnd;
+    CSize  m_pageSize;
+    CSize  m_displaySize;
+    CSize  m_scrollPos;
+};
+
+#endif // SCROLL_HELPER_INCLUDED
+
+// END

+ 31 - 73
ToolTipEx.cpp

@@ -11,11 +11,11 @@
     static char THIS_FILE[] = __FILE__;
     static char THIS_FILE[] = __FILE__;
 #endif 
 #endif 
 
 
-#define DELETE_BITMAP	if(m_pBitmap)					\
+#define DELETE_BITMAP	if(m_imageViewer.m_pBitmap)					\
 {								\
 {								\
-m_pBitmap->DeleteObject();	\
-delete m_pBitmap;		\
-m_pBitmap = NULL;		\
+m_imageViewer.m_pBitmap->DeleteObject();	\
+delete m_imageViewer.m_pBitmap;		\
+m_imageViewer.m_pBitmap = NULL;		\
 }
 }
 
 
 
 
@@ -24,7 +24,7 @@ m_pBitmap = NULL;		\
 
 
 CToolTipEx::CToolTipEx(): m_dwTextStyle(DT_EXPANDTABS | DT_EXTERNALLEADING |
 CToolTipEx::CToolTipEx(): m_dwTextStyle(DT_EXPANDTABS | DT_EXTERNALLEADING |
                        DT_NOPREFIX | DT_WORDBREAK), m_rectMargin(2, 2, 3, 3),
                        DT_NOPREFIX | DT_WORDBREAK), m_rectMargin(2, 2, 3, 3),
-                       m_pBitmap(NULL), m_pNotifyWnd(NULL), m_clipId(0){}
+                        m_pNotifyWnd(NULL), m_clipId(0){}
 
 
 CToolTipEx::~CToolTipEx()
 CToolTipEx::~CToolTipEx()
 {
 {
@@ -36,7 +36,7 @@ CToolTipEx::~CToolTipEx()
 
 
 BEGIN_MESSAGE_MAP(CToolTipEx, CWnd)
 BEGIN_MESSAGE_MAP(CToolTipEx, CWnd)
 //{{AFX_MSG_MAP(CToolTipEx)
 //{{AFX_MSG_MAP(CToolTipEx)
-ON_WM_PAINT()
+
 ON_WM_SIZE()
 ON_WM_SIZE()
 ON_WM_NCHITTEST()
 ON_WM_NCHITTEST()
 ON_WM_ACTIVATE()
 ON_WM_ACTIVATE()
@@ -55,6 +55,9 @@ ON_COMMAND(ID_FIRST_SCALEIMAGESTOFITWINDOW, &CToolTipEx::OnScaleimagestofitwindo
 ON_COMMAND(2, OnOptions)
 ON_COMMAND(2, OnOptions)
 ON_WM_RBUTTONDOWN()
 ON_WM_RBUTTONDOWN()
 ON_WM_SETFOCUS()
 ON_WM_SETFOCUS()
+
+
+
 END_MESSAGE_MAP() 
 END_MESSAGE_MAP() 
 
 
 
 
@@ -64,8 +67,7 @@ END_MESSAGE_MAP()
 BOOL CToolTipEx::Create(CWnd *pParentWnd)
 BOOL CToolTipEx::Create(CWnd *pParentWnd)
 {
 {
     // Get the class name and create the window
     // Get the class name and create the window
-    CString szClassName = AfxRegisterWndClass(CS_CLASSDC | CS_SAVEBITS,
-        LoadCursor(NULL, IDC_ARROW));
+    CString szClassName = AfxRegisterWndClass(CS_CLASSDC | CS_SAVEBITS, LoadCursor(NULL, IDC_ARROW));
 
 
     // Create the window - just don't show it yet.
     // Create the window - just don't show it yet.
     if( !CWnd::CreateEx(WS_EX_TOPMOST, szClassName, _T(""), WS_POPUP,
     if( !CWnd::CreateEx(WS_EX_TOPMOST, szClassName, _T(""), WS_POPUP,
@@ -74,6 +76,11 @@ BOOL CToolTipEx::Create(CWnd *pParentWnd)
         return FALSE;
         return FALSE;
     }	
     }	
 
 
+	//CString szClassName2 = AfxRegisterWndClass(CS_CLASSDC | CS_SAVEBITS, LoadCursor(NULL, IDC_ARROW));
+	//BOOL b = m_imageViewer.Create(_T(""), szClassName2, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL, CRect(0, 0, 0, 0), this, 3);
+	m_imageViewer.Create(this);
+	
+	
 	m_DittoWindow.DoCreate(this);
 	m_DittoWindow.DoCreate(this);
 	m_DittoWindow.SetCaptionColors(g_Opt.m_Theme.CaptionLeft(), g_Opt.m_Theme.CaptionRight());
 	m_DittoWindow.SetCaptionColors(g_Opt.m_Theme.CaptionLeft(), g_Opt.m_Theme.CaptionRight());
 	m_DittoWindow.SetCaptionOn(this, CGetSetOptions::GetCaptionPos(), true);
 	m_DittoWindow.SetCaptionOn(this, CGetSetOptions::GetCaptionPos(), true);
@@ -102,13 +109,15 @@ BOOL CToolTipEx::Create(CWnd *pParentWnd)
 BOOL CToolTipEx::Show(CPoint point)
 BOOL CToolTipEx::Show(CPoint point)
 {
 {
 	m_reducedWindowSize = false;
 	m_reducedWindowSize = false;
-    if(m_pBitmap)
+    if(m_imageViewer.m_pBitmap)
     {
     {
         m_RichEdit.ShowWindow(SW_HIDE);
         m_RichEdit.ShowWindow(SW_HIDE);
+		m_imageViewer.ShowWindow(SW_SHOW);
     }
     }
     else
     else
     {
     {
         m_RichEdit.ShowWindow(SW_SHOW);
         m_RichEdit.ShowWindow(SW_SHOW);
+		m_imageViewer.ShowWindow(SW_HIDE);
     }
     }
 
 
 	CRect rect;
 	CRect rect;
@@ -132,10 +141,10 @@ BOOL CToolTipEx::Show(CPoint point)
 		rect.right += 20;
 		rect.right += 20;
 		rect.bottom += 20;
 		rect.bottom += 20;
 
 
-		if (m_pBitmap)
+		if (m_imageViewer.m_pBitmap)
 		{
 		{
-			int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
-			int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+			int nWidth = CBitmapHelper::GetCBitmapWidth(*m_imageViewer.m_pBitmap);
+			int nHeight = CBitmapHelper::GetCBitmapHeight(*m_imageViewer.m_pBitmap);
 
 
 			rect.right = rect.left + nWidth;
 			rect.right = rect.left + nWidth;
 			rect.bottom = rect.top + nHeight;
 			rect.bottom = rect.top + nHeight;
@@ -228,61 +237,7 @@ BOOL CToolTipEx::Hide()
     return TRUE;
     return TRUE;
 }
 }
 
 
-void CToolTipEx::OnPaint()
-{
-    CPaintDC dc(this); // device context for painting
-
-    CRect rect;
-    GetClientRect(rect);
-
-    
-
-    // Draw Text
-    //    dc.SetBkMode(TRANSPARENT);
-    //    rect.DeflateRect(m_rectMargin);
-
-    
-	CBrush  Brush, *pOldBrush;
-	Brush.CreateSolidBrush(GetSysColor(COLOR_INFOBK));
-
-	pOldBrush = dc.SelectObject(&Brush);
-	CFont *pOldFont = dc.SelectObject(&m_Font);
-
-	dc.FillRect(&rect, &Brush);
-
-	if(m_pBitmap)
-	{
-        CDC MemDc;
-        MemDc.CreateCompatibleDC(&dc);
-
-        CBitmap *oldBitmap = MemDc.SelectObject(m_pBitmap);
 
 
-        int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
-        int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
-
-		if(CGetSetOptions::GetScaleImagesToDescWindow())
-		{
-			dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
-			//OutputDebugString(StrF(_T("scaling image, window size %d/%d, image %d/%d\n"), min(nWidth, rect.Width()), min(nHeight, rect.Height()), nWidth, nHeight));
-		}
-		else
-		{
-			dc.BitBlt(rect.left, rect.top, nWidth, nHeight, &MemDc, 0, 0, SRCCOPY);
-		}
-
-		//dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &MemDc, 0, 0, nWidth, nHeight, SRCCOPY);
-
-        MemDc.SelectObject(oldBitmap);
-
-        rect.top += nHeight;
-    }
-
-    //dc.DrawText(m_csText, rect, m_dwTextStyle);
-
-    // Cleanup
-    //  dc.SelectObject(pOldBrush);
-    //	dc.SelectObject(pOldFont);
-}
 
 
 void CToolTipEx::PostNcDestroy()
 void CToolTipEx::PostNcDestroy()
 {
 {
@@ -458,10 +413,10 @@ CRect CToolTipEx::GetBoundsRect()
     rect.bottom += m_rectMargin.top + m_rectMargin.bottom;
     rect.bottom += m_rectMargin.top + m_rectMargin.bottom;
     rect.right += m_rectMargin.left + m_rectMargin.right + 2;
     rect.right += m_rectMargin.left + m_rectMargin.right + 2;
 
 
-    if(m_pBitmap)
+    if(m_imageViewer.m_pBitmap)
     {
     {
-        int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
-        int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+        int nWidth = CBitmapHelper::GetCBitmapWidth(*m_imageViewer.m_pBitmap);
+        int nHeight = CBitmapHelper::GetCBitmapHeight(*m_imageViewer.m_pBitmap);
 
 
         rect.bottom += nHeight;
         rect.bottom += nHeight;
         if((rect.left + nWidth) > rect.right)
         if((rect.left + nWidth) > rect.right)
@@ -558,12 +513,14 @@ void CToolTipEx::SetBitmap(CBitmap *pBitmap)
 {
 {
     DELETE_BITMAP 
     DELETE_BITMAP 
 
 
-    m_pBitmap = pBitmap;
+	m_imageViewer.m_pBitmap = pBitmap;
+
+	m_imageViewer.UpdateBitmapSize();
 
 
-	if (m_pBitmap != NULL)
+	if (m_imageViewer.m_pBitmap != NULL)
 	{
 	{
-		int nWidth = CBitmapHelper::GetCBitmapWidth(*m_pBitmap);
-		int nHeight = CBitmapHelper::GetCBitmapHeight(*m_pBitmap);
+		int nWidth = CBitmapHelper::GetCBitmapWidth(*m_imageViewer.m_pBitmap);
+		int nHeight = CBitmapHelper::GetCBitmapHeight(*m_imageViewer.m_pBitmap);
 
 
 		Invalidate();
 		Invalidate();
 	}
 	}
@@ -582,6 +539,7 @@ void CToolTipEx::OnSize(UINT nType, int cx, int cy)
     GetClientRect(cr);
     GetClientRect(cr);
     cr.DeflateRect(0, 0, 0, theApp.m_metrics.ScaleY(21));
     cr.DeflateRect(0, 0, 0, theApp.m_metrics.ScaleY(21));
     m_RichEdit.MoveWindow(cr);
     m_RichEdit.MoveWindow(cr);
+	m_imageViewer.MoveWindow(cr);
 
 
 	m_optionsButton.MoveWindow(cr.left, cr.bottom + theApp.m_metrics.ScaleY(2), theApp.m_metrics.ScaleX(17), theApp.m_metrics.ScaleY(17));
 	m_optionsButton.MoveWindow(cr.left, cr.bottom + theApp.m_metrics.ScaleY(2), theApp.m_metrics.ScaleX(17), theApp.m_metrics.ScaleY(17));
 
 

+ 9 - 3
ToolTipEx.h

@@ -10,6 +10,7 @@
 #include "WndEx.h"
 #include "WndEx.h"
 #include "DittoWindow.h"
 #include "DittoWindow.h"
 #include "GdipButton.h"
 #include "GdipButton.h"
+#include "ImageViewer.h"
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 // CToolTipEx window
 // CToolTipEx window
 
 
@@ -59,7 +60,6 @@ protected:
 	CRect m_rectMargin;
 	CRect m_rectMargin;
 	CString m_csText;
 	CString m_csText;
 	CFont m_Font;
 	CFont m_Font;
-	CBitmap *m_pBitmap;
 	CString m_csRTF;
 	CString m_csRTF;
 	CRichEditCtrlEx m_RichEdit;
 	CRichEditCtrlEx m_RichEdit;
 	CWnd *m_pNotifyWnd;
 	CWnd *m_pNotifyWnd;
@@ -67,9 +67,15 @@ protected:
 	CGdipButton m_optionsButton;
 	CGdipButton m_optionsButton;
 	int m_clipId;
 	int m_clipId;
 	CString m_searchText;
 	CString m_searchText;
+	CScrollBar m_vScroll;
+	CScrollBar m_hScroll;
 
 
 	CDittoWindow m_DittoWindow;
 	CDittoWindow m_DittoWindow;
 
 
+	CImageViewer m_imageViewer;
+
+	
+
 protected:
 protected:
 	CString GetFieldFromString(CString ref, int nIndex, TCHAR ch);
 	CString GetFieldFromString(CString ref, int nIndex, TCHAR ch);
 	BOOL SetLogFont(LPLOGFONT lpLogFont, BOOL bRedraw /*=TRUE*/);
 	BOOL SetLogFont(LPLOGFONT lpLogFont, BOOL bRedraw /*=TRUE*/);
@@ -80,8 +86,7 @@ protected:
 
 
 	// Generated message map functions
 	// Generated message map functions
 protected:
 protected:
-	//{{AFX_MSG(CToolTipEx)
-	afx_msg void OnPaint();
+	//{{AFX_MSG(CToolTipEx)	
 	afx_msg void OnSize(UINT nType, int cx, int cy);
 	afx_msg void OnSize(UINT nType, int cx, int cy);
 	afx_msg HITTEST_RET OnNcHitTest(CPoint point);
 	afx_msg HITTEST_RET OnNcHitTest(CPoint point);
 	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
 	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
@@ -100,6 +105,7 @@ public:
 	afx_msg void OnScaleimagestofitwindow();
 	afx_msg void OnScaleimagestofitwindow();
 	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
 	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
 	afx_msg void OnSetFocus(CWnd* pOldWnd);
 	afx_msg void OnSetFocus(CWnd* pOldWnd);
+	
 };
 };
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////