summaryrefslogtreecommitdiff
path: root/win/wheelwnd.cpp
diff options
context:
space:
mode:
authordocwhat1999-11-14 06:43:18 +0000
committerdocwhat1999-11-14 06:43:18 +0000
commitd71eec8062e852e56f03102ba4b4e87dc485821d (patch)
tree452368ad0e7e24627e517a0c88c2508d02cea6dc /win/wheelwnd.cpp
parent2046090b7ce8dd901ce43e650be5acf44016d714 (diff)
Initial revision
git-svn-id: http://svn.leocad.org/trunk@2 c7d43263-9d01-0410-8a33-9dba5d9f93d6
Diffstat (limited to 'win/wheelwnd.cpp')
-rw-r--r--win/wheelwnd.cpp211
1 files changed, 211 insertions, 0 deletions
diff --git a/win/wheelwnd.cpp b/win/wheelwnd.cpp
new file mode 100644
index 0000000..522efed
--- /dev/null
+++ b/win/wheelwnd.cpp
@@ -0,0 +1,211 @@
+// WheelWnd.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "leocad.h"
+#include "WheelWnd.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWheelWnd
+
+// One and only origin window, used by the one and only hook.
+static CWheelWnd *g_pOriginWnd = NULL;
+static HHOOK g_hdlHook = NULL;
+
+CWheelWnd::CWheelWnd(CPoint ptOrigin)
+{
+ VERIFY(m_bitmap.LoadBitmap(IDB_AUTOPAN));
+
+ BITMAP bmp;
+ VERIFY(m_bitmap.GetBitmap(&bmp));
+ m_sizeBitmap.cx = bmp.bmWidth;
+ m_sizeBitmap.cy = bmp.bmHeight;
+
+ m_ptOrigin = ptOrigin;
+ m_ptCursorPrevious = ptOrigin;
+}
+
+CWheelWnd::~CWheelWnd()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CWheelWnd, CWnd)
+ //{{AFX_MSG_MAP(CWheelWnd)
+ ON_WM_PAINT()
+ ON_WM_TIMER()
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWheelWnd message handlers
+
+void CWheelWnd::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ // Simple drawing code, all it does is blt the bitmap we have chosen onto our window.
+ CDC dcMem;
+ VERIFY(dcMem.CreateCompatibleDC(&dc));
+ CGdiObject *pOldBmp = dcMem.SelectObject(&m_bitmap);
+ VERIFY(dc.BitBlt(0, 0, m_sizeBitmap.cx, m_sizeBitmap.cy, &dcMem, 0, 0, SRCCOPY));
+ dcMem.SelectObject(pOldBmp);
+}
+
+void CWheelWnd::OnTimer(UINT nIDEvent)
+{
+ if (nIDEvent == IDT_LC_WHEELTIMER)
+ {
+ CPoint ptCursor;
+ VERIFY(GetCursorPos(&ptCursor));
+ ASSERT_VALID(m_pParentWnd);
+ m_pParentWnd->ScreenToClient(&ptCursor);
+
+ CPoint pt = ptCursor;
+
+ // If the point is within one of our margins or we are doing one way scrolling then we correct the point
+ // by setting it's axis value to the same as our origin. This makes makes the cursor behaviour
+ // the same as IE.
+
+ CRgn rgn;
+ rgn.CreateEllipticRgn(0, 0, m_sizeBitmap.cx, m_sizeBitmap.cy);
+ rgn.OffsetRgn(m_ptOrigin.x-m_sizeBitmap.cx/2, m_ptOrigin.y-m_sizeBitmap.cy/2);
+ if (rgn.PtInRegion(pt))
+ pt = m_ptOrigin;
+
+// if (pt.x > m_rcCursorMargin.left && pt.x < m_rcCursorMargin.right)
+// pt.x = m_ptOrigin.x;
+//
+// if (pt.y > m_rcCursorMargin.top && pt.y < m_rcCursorMargin.bottom)
+// pt.y = m_ptOrigin.y;
+
+ // Now that we have our distance from our origin and we have normalised it to be within our margins
+ // where necessary we now figure out which cursor to use, this is a simple lookup into a table again.
+ if (m_ptCursorPrevious != ptCursor)
+ {
+ m_ptCursorPrevious = ptCursor;
+ const int nHoriz = max(-1, min(1, pt.x - m_ptOrigin.x)) + 1;
+ const int nVert = max(-1, min(1, pt.y - m_ptOrigin.y)) + 1;
+
+ const UINT Cursors[3][3] = { IDC_PAN_NW, IDC_PAN_LEFT, IDC_PAN_SW,
+ IDC_PAN_UP, IDC_PAN_ALL, IDC_PAN_DOWN, IDC_PAN_NE, IDC_PAN_RIGHT, IDC_PAN_SE };
+ HCURSOR hc = theApp.LoadCursor(Cursors[nHoriz][nVert]);
+ SetCursor(hc);
+ }
+
+ if (m_ptOrigin != pt)
+ m_pParentWnd->PostMessage(WM_LC_WHEEL_PAN, MAKELPARAM(m_ptOrigin.x, m_ptOrigin.y), MAKELPARAM(pt.x, pt.y));
+ }
+ else
+ CWnd::OnTimer(nIDEvent);
+}
+
+void CWheelWnd::OnDestroy()
+{
+ CWnd::OnDestroy();
+
+ VERIFY(UnhookWindowsHookEx(g_hdlHook));
+ g_hdlHook = NULL;
+ g_pOriginWnd = NULL;
+ KillTimer(IDT_LC_WHEELTIMER);
+}
+
+BOOL CWheelWnd::Create(CWnd* pParentWnd)
+{
+ // Must be a valid parent window
+ ASSERT_VALID(pParentWnd);
+
+ CPoint pt = m_ptOrigin;
+ pParentWnd->ClientToScreen(&pt);
+
+ // We create the window, the centre of the window should be the origin point so when all of the startup is done the cursor
+ // will appear over the centre of the origin window.
+ const int nHalfHeight = m_sizeBitmap.cy / 2;
+ const int nHalfWidth = m_sizeBitmap.cx / 2;
+ if(CWnd::CreateEx(WS_EX_TOOLWINDOW, AfxRegisterWndClass(CS_SAVEBITS), NULL, WS_CLIPSIBLINGS | WS_POPUP, pt.x - nHalfWidth, pt.y - nHalfHeight, m_sizeBitmap.cx, m_sizeBitmap.cy, pParentWnd->GetSafeHwnd(), 0))
+ {
+ VERIFY(SetWindowPos(&wndTopMost, 0,0,0,0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE));
+ m_pParentWnd = pParentWnd;
+
+ // Determine the thresholds for the cursor changing, while the cursor is between these points the cursor does not
+ // change to one of the diagonal cursors. I think this is how IE does it - sure looks like it.
+ m_rcCursorMargin.SetRect(m_ptOrigin.x - nHalfWidth, m_ptOrigin.y - nHalfHeight, m_ptOrigin.x + nHalfWidth, m_ptOrigin.y + nHalfHeight);
+
+ // We want a circular(or as much as the bitmap allows) window, so do the usual
+ // thing of creating a region and assigning it to the window.
+ CRgn rgn;
+ VERIFY(rgn.CreateEllipticRgn(0, 0, m_sizeBitmap.cx, m_sizeBitmap.cy));
+ VERIFY(SetWindowRgn((HRGN)rgn.Detach(), TRUE));
+
+ // Set our mouse capture so that all mouse messages go to us and also set a timer
+ // so that we can periodically send our message to our parent.
+ SetCapture();
+ VERIFY(SetTimer(IDT_LC_WHEELTIMER, 25, NULL) == IDT_LC_WHEELTIMER);
+ g_pOriginWnd = this;
+ g_hdlHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, NULL, GetCurrentThreadId());
+ return TRUE;
+ }
+ TRACE0("Failed to create Origin window\n");
+ return FALSE;
+}
+
+LRESULT CWheelWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_CANCELMODE:
+ case WM_CAPTURECHANGED:
+ VERIFY(DestroyWindow());
+ break;
+ default:
+ return CWnd::WindowProc(message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+void CWheelWnd::PostNcDestroy()
+{
+ CWnd::PostNcDestroy();
+ delete this;
+}
+
+// Hook procedure to catch messages that should terminate our window.
+LRESULT CALLBACK CWheelWnd::HookProc(int code, WPARAM wParam ,LPARAM lParam)
+{
+ MSG* pMsg = (MSG*)lParam;
+
+ ASSERT_VALID(g_pOriginWnd);
+ ASSERT_VALID(g_pOriginWnd->m_pParentWnd);
+ if(pMsg->hwnd == g_pOriginWnd->m_pParentWnd->GetSafeHwnd())
+ {
+ switch(pMsg->message)
+ {
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ case WM_CHAR:
+ case WM_KILLFOCUS:
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_MOUSEWHEEL:
+ VERIFY(g_pOriginWnd->DestroyWindow());
+ break;
+ default:
+ // Intentionally do nothing
+ ;
+ }
+ }
+ return CallNextHookEx( g_hdlHook, code, wParam, lParam );
+}