editctl.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 72k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //-------------------------------------------------------------------------//
  2. //
  3. //  EditCtl.cpp
  4. //
  5. //-------------------------------------------------------------------------//
  6. #include "pch.h"
  7. #include "PropVar.h"
  8. #include "EditCtl.h"
  9. //-------------------------------------------------------------------------//
  10. const TCHAR  szEDITCLASS[]           = TEXT("Edit"),
  11.              szBUTTONCLASS[]         = TEXT("Button"),
  12.              szCOMBOBOXCLASS[]       = TEXT("Combobox"),
  13.              szDROPWINDOWCLASS[]     = TEXT("DropWindow");
  14. //-------------------------------------------------------------------------//
  15. void GetNcBorderSize( HWND hwnd, SIZE* pSize )
  16. {
  17.     ASSERT( hwnd );
  18.     ASSERT( pSize );
  19.     RECT rcWnd, rcClient;
  20.     
  21.     ::GetWindowRect( hwnd, &rcWnd );
  22.     ::GetClientRect( hwnd, &rcClient );
  23.     pSize->cx = RECTWIDTH( &rcWnd ) - RECTWIDTH( &rcClient );
  24.     pSize->cy = RECTHEIGHT( &rcWnd ) - RECTHEIGHT( &rcClient );
  25. }
  26. //-------------------------------------------------------------------------//
  27. //  Formats in place a buffer containing multiline text to
  28. //  a form suitable for displaying as a single line.
  29. void MakeSingleLine( LPTSTR pszText, int cchText, int cchBuf )
  30. {
  31.     LPCTSTR pszEllipsis = TEXT(" ...");
  32.     ASSERT( cchBuf - cchText > lstrlen(pszEllipsis) );
  33.     if( pszText && *pszText )    {
  34.         for( int i = 0; i<cchText; i++ )   {
  35.             if( pszText[i]==TEXT('r') || pszText[i]==TEXT('n') )
  36.             {
  37.                 lstrcpy( &pszText[i], pszEllipsis );
  38.                 return;
  39.             }
  40.         }
  41.     }
  42. }
  43. //-------------------------------------------------------------------------//
  44. //  CInPlaceBase - base class for in-place edit controls.
  45. //-------------------------------------------------------------------------//
  46. //-------------------------------------------------------------------------//
  47. typedef struct tagENUMCHILD
  48. {
  49.     CInPlaceBase* pThis;
  50.     BOOL          bSubclassed;
  51. } ENUMCHILD, *PENUMCHILD;
  52. //-------------------------------------------------------------------------//
  53. BOOL CInPlaceBase::enumChildProc( HWND hwnd, LPARAM lParam )
  54. {
  55.     PENUMCHILD pEC = (PENUMCHILD)lParam;
  56.     if( (pEC->bSubclassed = pEC->pThis->subclassCtl( hwnd )) )
  57.         return TRUE;
  58.     return FALSE;
  59. }
  60. //-------------------------------------------------------------------------//
  61. BOOL CInPlaceBase::subclassCtl( HWND hwnd )
  62. {
  63.     TCHAR szBuf[128];
  64.     *szBuf = 0;
  65.     if( GetClassName( hwnd, szBuf, sizeof(szBuf)/sizeof(TCHAR) ) )
  66.     {
  67.         if( lstrcmpi( szBuf, TEXT("Edit") )==0 )
  68.         {
  69.             if( CWindowImpl<CInPlaceBase>::SubclassWindow( hwnd ) )
  70.             {
  71.                 m_type = CT_EDIT;
  72.                 return TRUE;
  73.             }
  74.         }
  75.         if( lstrcmpi( szBuf, TEXT("ComboBox") )==0 )
  76.         {
  77.             //  BUGBUG: Sublassing a combo box results in a crash
  78.             //  when it is repositioned.  Why?  We need to sublass
  79.             //  the droplist type to process directional keys!  The
  80.             //  code is commented out here; but need to get this working.
  81.             DWORD dwStyle = ::GetWindowLong( hwnd, GWL_STYLE );
  82.             if( (dwStyle & 0xF)==CBS_DROPDOWNLIST /*&&
  83.                 CWindowImpl<CInPlaceBase>::SubclassWindow( hwnd )*/ )
  84.             {
  85.                 //TRACE( TEXT("Sublassing CBS_DROPDOWNLIST combon") );
  86.                 m_type = CT_CBDROPLIST;
  87.                 return TRUE;
  88.             }
  89.             else if( (dwStyle & 0xF)==CBS_DROPDOWN )
  90.             {
  91.                 m_type = CT_CBDROPDOWN;
  92.             }
  93.         }
  94.     }
  95.     return FALSE;
  96. }
  97. //-------------------------------------------------------------------------//
  98. BOOL CInPlaceBase::SubclassWindow( HWND hwnd, BOOL bSearchChildren ) 
  99. {
  100.     if( !( subclassCtl( hwnd ) || bSearchChildren ) )
  101.         return FALSE;
  102.     ENUMCHILD ec;
  103.     memset( &ec, 0, sizeof(ec) );
  104.     ec.pThis = this;
  105.     EnumChildWindows( hwnd, enumChildProc, (LPARAM)&ec );
  106.     return ec.bSubclassed;
  107. }
  108. //-------------------------------------------------------------------------//
  109. //  Transmits a WM_COMMAND message to its source child in-place control
  110. LRESULT CInPlaceBase::ReflectWM_COMMAND( HWND hwndCtl, UINT nCode, BOOL* pbHandled )
  111. {
  112.     *pbHandled = FALSE;
  113.     return ::SendMessage( hwndCtl, WMU_SELFCOMMAND, (WPARAM)nCode, (LPARAM)pbHandled );
  114. }
  115. //-------------------------------------------------------------------------//
  116. //  Transmits a WM_NOTIFY message back to its source child in-place control
  117. LRESULT CInPlaceBase::ReflectWM_NOTIFY( NMHDR* pHdr, BOOL* pbHandled )
  118. {
  119.     REFLECTNOTIFY notify;
  120.     *pbHandled = FALSE;
  121.     notify.pbHandled = pbHandled;
  122.     notify.pHdr      = pHdr;
  123.     return ::SendMessage( pHdr->hwndFrom, WMU_SELFNOTIFY, 0L, (LPARAM)&notify );
  124. }
  125. //-------------------------------------------------------------------------//
  126. //  WMU_SELFCOMMAND message handler
  127. LRESULT CInPlaceBase::_selfCommand( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  128. {
  129.     BOOL* pbHandled = (BOOL*)lParam;
  130.     bHandled = TRUE;
  131.     *pbHandled = FALSE;
  132.     return OnSelfCommand( (UINT)wParam, *pbHandled );
  133. }
  134. //-------------------------------------------------------------------------//
  135. //  WMU_SELFNOTIFY message handler
  136. LRESULT CInPlaceBase::_selfNotify( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  137. {
  138.     bHandled = TRUE;
  139.     REFLECTNOTIFY* pNotify = (REFLECTNOTIFY*)lParam;
  140.     return OnSelfNotify( pNotify->pHdr, *pNotify->pbHandled );
  141. }
  142. //-------------------------------------------------------------------------//
  143. //  Handles WM_COMMAND messages reflected back to control
  144. LRESULT CInPlaceBase::OnSelfCommand( UINT nCode, BOOL& bHandled )
  145. {
  146.     bHandled = FALSE;
  147.     return 0L;
  148. }
  149. //-------------------------------------------------------------------------//
  150. //  Handles WM_NOTIFY messages reflected back to control
  151. LRESULT CInPlaceBase::OnSelfNotify( NMHDR* pHdr, BOOL& bHandled )
  152. {
  153.     bHandled = FALSE;
  154.     return 0L;
  155. }
  156. //-------------------------------------------------------------------------//
  157. LRESULT CInPlaceBase::OnGetDlgCode( UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  158. {
  159.     if( 0L != lParam && 
  160.         WM_KEYDOWN == ((LPMSG)lParam)->message && VK_TAB == ((LPMSG)lParam)->wParam )
  161.     {
  162.         bHandled = FALSE;
  163.         return 0L;
  164.     }
  165.     
  166.     return DLGC_WANTALLKEYS;
  167. }
  168. //-------------------------------------------------------------------------//
  169. UINT CInPlaceBase::GetDropState() const
  170. {
  171.     if( m_hWnd && m_type == CT_EDIT )
  172.     {
  173.         HWND    hwndParent;
  174.         TCHAR   szClass[64];
  175.         if( (hwndParent = GetParent())!=NULL &&
  176.             GetClassName( hwndParent, szClass, sizeof(szClass) ) &&
  177.             lstrcmpi( szClass, szCOMBOBOXCLASS )==0 )
  178.         {
  179.             if( ::SendMessage( hwndParent, CB_GETDROPPEDSTATE, 0, 0L ) )
  180.                 return DROPSTATE_DROPPED;
  181.         }
  182.     }
  183.     return DROPSTATE_CLOSED;
  184. }
  185. //-------------------------------------------------------------------------//
  186. LRESULT CInPlaceBase::OnKey( UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  187. {
  188.     NAVIGATION_KEY_INFO nki;
  189.     UINT nDropState = GetDropState();
  190.     //  If we've subclassed a droplist combo box and its listbox is dropped, 
  191.     //  we'll let the control's default wndproc handle all keys.
  192.     if( nDropState & DROPSTATE_DROPPED )
  193.     {
  194.         bHandled = FALSE;
  195.         return 0L;
  196.     }
  197.     //  Otherwise, defer to control window for processing
  198.     InitNavigationKeyInfo( &nki, m_hWnd, nMsg, virtKey, lParam );
  199.     LRESULT lRet = ::SendMessage( m_hwndTree, WMU_NAVIGATION_KEY, 
  200.                                   GetDlgCtrlID(), (LPARAM)&nki );
  201.     if( (bHandled = nki.bHandled) )
  202.         return lRet;
  203.     return 0L;
  204. }
  205. //-------------------------------------------------------------------------//
  206. LRESULT CInPlaceBase::OnFocusChange( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  207. {
  208.     LRESULT lRet = DefWindowProc( nMsg, wParam, lParam );
  209.     HWND hwndOther = (HWND)wParam;
  210.     if( nMsg == WM_SETFOCUS || !IsChild( hwndOther ) )
  211.         ::SendMessage( m_hwndTree, WMU_CTLFOCUS, wParam, (LPARAM)nMsg );
  212.     
  213.     return lRet;
  214. }
  215. //-------------------------------------------------------------------------//
  216. LRESULT CInPlaceBase::OnGetObject( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  217. {
  218.     HRESULT hr = E_INVALIDARG;
  219.     bHandled = FALSE;
  220.     if( OBJID_CLIENT == lParam )
  221.     {
  222.         IAccessible* paccProxy;
  223.         if( SUCCEEDED( (hr = _CreateStdAccessibleProxy( m_hWnd, wParam, &paccProxy )) ) )
  224.         {
  225.             CAccessibleBase* pacc = new CAccessibleBase;
  226.             if( pacc )
  227.             {
  228.                 pacc->Initialize( m_hwndTree, paccProxy );
  229.                 hr = (HRESULT)_LresultFromObject( IID_IAccessible, wParam, (IAccessible*)pacc );
  230.                 bHandled = SUCCEEDED(hr);
  231.             }
  232.             else
  233.                 hr = E_OUTOFMEMORY;
  234.             
  235.             paccProxy->Release();
  236.         }
  237.     }
  238.     return (LRESULT)hr;
  239. }
  240. //-------------------------------------------------------------------------//
  241. LRESULT CInPlaceBase::OnPostNcDestroy( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  242. {
  243.     m_hwndTree = NULL;
  244.     LRESULT lRet = DefWindowProc( nMsg, wParam, lParam );
  245.     bHandled = TRUE;
  246.     delete this;
  247.     return 0L;
  248. }
  249. //-------------------------------------------------------------------------//
  250. //  CInPlaceDropList  (standard CBS_DROPLIST combobox)
  251. //-------------------------------------------------------------------------//
  252. //-------------------------------------------------------------------------//
  253. BOOL CInPlaceDropList::SubclassWindow( HWND hwnd, BOOL bSearchChildren )
  254. {
  255.     //  Bypass base class's subclassing routine, because droplist combos
  256.     //  have no embedded edit control.
  257.     UNREFERENCED_PARAMETER( bSearchChildren );
  258.     if( CWindowImpl< CInPlaceBase >::SubclassWindow( hwnd ) )   {
  259.         m_type = CT_CBDROPLIST;
  260.         return TRUE;
  261.     }
  262.     return FALSE;
  263. }
  264. //-------------------------------------------------------------------------//
  265. UINT CInPlaceDropList::GetDropState() const
  266. {
  267.     if( m_hWnd && ::SendMessage( m_hWnd, CB_GETDROPPEDSTATE, 0, 0L ) )
  268.         return DROPSTATE_DROPPED;
  269.     return DROPSTATE_CLOSED;
  270. }
  271. //-------------------------------------------------------------------------//
  272. LRESULT CInPlaceDropList::OnKey( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  273. {
  274.     if( (bHandled = (BOOL)SendMessage( CB_GETDROPPEDSTATE, 0,0 )) )
  275.         return DefWindowProc( nMsg, wParam, lParam );
  276.     
  277.     return 0L;
  278. }
  279. //-------------------------------------------------------------------------//
  280. LRESULT CInPlaceDropList::OnSelfCommand( UINT nCode, BOOL& bHandled )
  281. {
  282.     return CInPlaceBase::OnSelfCommand( nCode, bHandled );
  283. }
  284. //-------------------------------------------------------------------------//
  285. //  CCaptureTracker class implementation
  286. //-------------------------------------------------------------------------//
  287. UINT CCaptureTracker::m_registeredMsg = 0;
  288. //-------------------------------------------------------------------------//
  289. UINT CCaptureTracker::NotifyMsg()
  290. {
  291.     if( !m_registeredMsg )
  292.     {
  293.         m_registeredMsg = RegisterWindowMessage( TEXT("CaptureTrackerMsg") );
  294.         ASSERT( m_registeredMsg!=NULL );
  295.     }
  296.     return m_registeredMsg;
  297. }
  298. //-------------------------------------------------------------------------//
  299. BOOL CCaptureTracker::Track( HWND hwndChild, HWND hwndClient )
  300. {
  301.     ASSERT( m_hWnd==NULL );
  302.     if( hwndChild == NULL )
  303.         return FALSE;
  304.     
  305.     m_hwndClient = hwndClient;
  306.     return CWindowImpl<CCaptureTracker>::SubclassWindow( hwndChild );
  307. }
  308. //-------------------------------------------------------------------------//
  309. LRESULT CCaptureTracker::OnSomeButtonDown( 
  310.     UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  311. {
  312.     HWND hwndTarget;
  313.     POINT  pt;
  314.     POINTS pts = MAKEPOINTS( lParam );
  315.     POINTSTOPOINT( pt, pts );
  316.     MapWindowPoints( HWND_DESKTOP, &pt, 1 );
  317.     if( (hwndTarget = WindowFromPoint( pt ))==NULL ||
  318.         (hwndTarget != m_hwndClient && !::IsChild( m_hwndClient, hwndTarget )) )
  319.     {
  320.         //  Some other non-child window got clicked on
  321.         NotifyClient( ForeignClick, hwndTarget );
  322.     }
  323.     
  324.     bHandled = TRUE;
  325.     return DefWindowProc( nMsg, wParam, lParam );
  326. }
  327. //-------------------------------------------------------------------------//
  328. LRESULT CCaptureTracker::OnCaptureChanged( 
  329.     UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  330. {
  331.     LRESULT lRet = DefWindowProc( nMsg, wParam, lParam );
  332.     bHandled = TRUE;
  333.     HWND hwndCaptureOwner = (HWND)lParam;
  334.     //  We've lost capture, so stop filtering messages
  335.     UnsubclassWindow();
  336.     //  Evaluate who we lost capture to, and act accordingly.
  337.     if( hwndCaptureOwner == NULL )
  338.     {
  339.         //  the subclassed window called ReleaseCapture()
  340.         //TRACE(TEXT("CaptureTracker: child released capture.n"));
  341.         AsyncNotifyClient( Released, NULL );
  342.     }
  343.     else if( ::IsChild( m_hwndClient, hwndCaptureOwner ) )
  344.     {
  345.         //  Some other child window captured the mouse;
  346.         //  we now turn our attention to this window...
  347.         //TRACE(TEXT("CaptureTracking shifted to child control %08lXn"), hwndCaptureOwner);
  348.         CWindowImpl<CCaptureTracker>::SubclassWindow( hwndCaptureOwner );
  349.     }
  350.     else
  351.     {
  352.         //  Some non-child window captured the mouse
  353.         //TRACE(TEXT("CaptureTracker: non-child window has taken capture.n"));
  354.         AsyncNotifyClient( Lost, hwndCaptureOwner );
  355.     }
  356.     return lRet;
  357. }
  358. //-------------------------------------------------------------------------//
  359. LRESULT CCaptureTracker::OnDestroy( 
  360.     UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& )
  361. {
  362.     UnsubclassWindow();
  363.     NotifyClient( Released, NULL );
  364.     BOOL bHandled = FALSE;
  365.     return 0L;
  366. }
  367. //-------------------------------------------------------------------------//
  368. //  CInPlaceDropWindow - custom combo box look-alike window object
  369. //-------------------------------------------------------------------------//
  370. //  BUGBUG: need to replace drop down pushbutton with GDI-drawn button that
  371. //  exactly mimics combo box button.
  372. static const TCHAR  szCLOSED[] = TEXT("+"), // BUGBUG: needless if mimics combo box button (see above).
  373.                     szOPEN[]   = TEXT("-");// BUGBUG: needless if mimics combo box button (see above).
  374. static const UINT   IDC_DROPWINDOWCHILDBASE  = 4001,    // arbitrary
  375.                     IDC_DROPBTN  = IDC_DROPWINDOWCHILDBASE + 1, // BUGBUG: needless if mimics combo box button (see above).
  376.                     IDC_DROPHOST = IDC_DROPWINDOWCHILDBASE + 2;
  377. static const UINT   DWHN_APPDEACTIVATE = 1;   // drop window notification code
  378. //-------------------------------------------------------------------------//
  379. CInPlaceDropWindow::CInPlaceDropWindow( HWND hwndTree )
  380.     :   CInPlaceBase(hwndTree),
  381.         m_fBtnPressed(FALSE),
  382.         m_fDestroyed(FALSE),
  383.         m_nDropState(DROPSTATE_CLOSED),
  384.         m_nDropAnchor(DROPANCHOR_TOP),
  385.         m_hfText(NULL),
  386.         m_lParam(0L),
  387.         m_cyDrop(150),
  388.         m_bExtendedUI(FALSE),
  389.         m_cy(21)
  390. {
  391.     SetRect( &m_rcBtn, 0,0,0,0 );
  392. }
  393. //-------------------------------------------------------------------------//
  394. //  WM_CREATE handler.
  395. LRESULT CInPlaceDropWindow::OnCreate( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  396. {
  397.     LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
  398.     bHandled = TRUE;
  399.     //  Create the dropdown push button.
  400.     //  BUGBUG: needless if mimics combo box button (see above).
  401.     PositionControls( lpcs->cx, lpcs->cy );
  402.     //  Calculate rectangle for drop host window.
  403.     RECT rc;
  404.     SetRect( &rc, lpcs->x, lpcs->y, lpcs->x + lpcs->cx, lpcs->x + lpcs->cx );
  405.     OffsetRect( &rc, 0, RECTHEIGHT( &rc ) );
  406.     rc.bottom += m_cyDrop;
  407.     m_fDestroyed = FALSE;
  408.     return 0;
  409. }
  410. //-------------------------------------------------------------------------//
  411. //  WM_CREATE handler.
  412. LRESULT CInPlaceDropWindow::OnDestroy( UINT, WPARAM, LPARAM, BOOL& )    
  413.     m_fDestroyed = TRUE;
  414.     HWND hwndDrop;
  415.     if( NULL != (hwndDrop = DropHwnd()) )
  416.         ::DestroyWindow( hwndDrop );
  417.     return 0L; 
  418. }
  419. //-------------------------------------------------------------------------//
  420. void CInPlaceDropWindow::OnClick( 
  421.     HWND hwndTarget, 
  422.     UINT uMsg, 
  423.     const POINT& pt, 
  424.     UINT nDropState )
  425. {
  426.     if( hwndTarget == m_hWnd  )
  427.     {
  428.         ClickButton();
  429.         ToggleDrop( FALSE );
  430.     }
  431.     else if( IsChild( hwndTarget ) )
  432.     {
  433.         if( nDropState & DROPSTATE_CLOSED )
  434.             ClickButton();
  435.         ToggleDrop( 0 == (nDropState & DROPSTATE_CLOSED) );
  436.     }
  437. }
  438. //-------------------------------------------------------------------------//
  439. //  Handle mouse button down messages.  Note: we may or may not be the
  440. //  focus window when this takes place; we may have mouse capture, so
  441. //  we must be prepared to propagate the message to its true destination.
  442. LRESULT CInPlaceDropWindow::OnLButtonDown( UINT nMsg, WPARAM nFlags, LPARAM lParam, BOOL& bHandled )
  443. {
  444.     HWND    hwndTarget = NULL,
  445.             hwndDrop = NULL;
  446.     POINT  pt;
  447.     POINTS pts = MAKEPOINTS( lParam );
  448.     POINTSTOPOINT( pt, pts );
  449.     if( (hwndTarget = ChildWindowFromPoint( pt ))!=NULL )
  450.     {
  451.         if( hwndTarget == m_hWnd || IsChild( hwndTarget ) )
  452.         {
  453.             DefWindowProc( nMsg, nFlags, lParam );
  454.             OnClick( hwndTarget, nMsg, pt, GetDropState() );
  455.         }
  456.         else
  457.         {
  458.             ::MapWindowPoints( HWND_DESKTOP, hwndTarget, &pt, 1 );
  459.             ::SendMessage( hwndTarget, WM_LBUTTONDOWN, nFlags, MAKELPARAM( pt.x, pt.y ) );
  460.         }
  461.     }
  462.     else 
  463.     {
  464.         MapWindowPoints( HWND_DESKTOP, &pt, 1 );
  465.         if( (hwndTarget = WindowFromPoint( pt )) !=NULL )
  466.         {
  467.             if( (hwndDrop = DropHwnd())!=NULL )
  468.             {
  469.                 if( hwndTarget != hwndDrop && !IsChildOfDrop( hwndTarget ) )
  470.                     ShowDrop( FALSE, TRUE );
  471.             }
  472.             
  473.             ::MapWindowPoints( HWND_DESKTOP, hwndTarget, &pt, 1 );
  474.             ::PostMessage( hwndTarget, WM_LBUTTONDOWN, nFlags, MAKELPARAM( pt.x, pt.y ) );
  475.         }
  476.     }
  477.     bHandled = FALSE;
  478.     return 0L;
  479. }
  480. //-------------------------------------------------------------------------//
  481. //  WM_SIZE handler.
  482. LRESULT CInPlaceDropWindow::OnSize( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  483. {
  484.     LRESULT lRet = CInPlaceDropWindow::DefWindowProc( nMsg, wParam, lParam );
  485.     int     cx = LOWORD( lParam ),
  486.             cy = HIWORD( lParam );
  487.     
  488.     PositionControls( cx, cy );
  489.     bHandled = TRUE;
  490.     return 0L;
  491. }
  492. //-------------------------------------------------------------------------//
  493. //  WM_PAINT handler.
  494. LRESULT CInPlaceDropWindow::OnPaint( 
  495.     UINT nMsg, 
  496.     WPARAM wParam, 
  497.     LPARAM lParam, 
  498.     BOOL& bHandled )
  499. {
  500.     PAINTSTRUCT ps;
  501.     HDC         hdc;
  502.     bHandled = FALSE;
  503.     if( (hdc = BeginPaint( &ps ))!=NULL )
  504.     {
  505.         HWND        hwndFocus = ::GetFocus();
  506.         BOOL        bFocus  = hwndFocus == m_hWnd || IsChild( hwndFocus );
  507.         LPTSTR      pszText = NULL;
  508.         RECT        rcText;
  509.         //  Draw dropdown button
  510.         DrawFrameControl( hdc, &m_rcBtn, DFC_SCROLL, 
  511.                           DFCS_SCROLLDOWN | (m_fBtnPressed ? DFCS_PUSHED : 0) );
  512.         
  513.         if( DrawTextBox() )
  514.         {
  515.             COLORREF rgbBk   = SetBkColor(   hdc, GetSysColor( bFocus ? COLOR_HIGHLIGHT :     COLOR_WINDOW ) ), 
  516.                      rgbText = SetTextColor( hdc, GetSysColor( bFocus ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT ) );
  517.         
  518.             //  Draw highlight box
  519.             GetTextBox( &rcText );
  520.             InflateRect( &rcText, -1, -1 );
  521.             ExtTextOut( hdc, rcText.left, rcText.top, ETO_OPAQUE, &rcText, NULL, 0, NULL ); 
  522.             //  Draw focus rectangle
  523.             if( bFocus )
  524.                 DrawFocusRect( hdc, &rcText );
  525.             //  Make a copy of the text
  526.             int cch = GetWindowTextLength();
  527.             if( (pszText = new TCHAR[cch+5])!=NULL ) 
  528.             {
  529.                 *pszText = 0;
  530.                 GetWindowText( pszText, cch+1 );
  531.             
  532.                 //  If multiline, prepare for display as single line.
  533.                 if( IsMultiline() )
  534.                     MakeSingleLine( pszText, cch, cch+5 );
  535.                 if( *pszText )
  536.                 {
  537.                     HFONT   hfOld = (HFONT)SelectObject( hdc, m_hfText );
  538.                     InflateRect( &rcText, -1, -1 );
  539.                     DrawText( hdc, pszText, lstrlen(pszText), &rcText, 
  540.                               DT_END_ELLIPSIS|DT_NOPREFIX|DT_SINGLELINE|DT_TOP );
  541.                     SelectObject( hdc, hfOld );
  542.                 }
  543.                 delete [] pszText;
  544.             }
  545.             SetBkColor( hdc, rgbBk );
  546.             SetTextColor( hdc, rgbText );
  547.         }
  548.         EndPaint( &ps );
  549.         bHandled = TRUE;
  550.     }
  551.     return 0L;
  552. }
  553. //-------------------------------------------------------------------------//
  554. LRESULT CInPlaceDropWindow::OnSetFocus( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  555. {
  556.     Invalidate( FALSE );
  557.     
  558.     bHandled = FALSE;  // let CInPlaceBase have a crack
  559.     return 0L;
  560. }
  561. //-------------------------------------------------------------------------//
  562. LRESULT CInPlaceDropWindow::OnKillFocus( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  563. {
  564.     Invalidate( FALSE );
  565.     
  566.     bHandled = FALSE;  // let CInPlaceBase have a crack
  567.     return 0L;
  568. }
  569. //-------------------------------------------------------------------------//
  570. LRESULT CInPlaceDropWindow::OnShowWindow( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  571. {
  572.     if( wParam==FALSE )    
  573.     {
  574.         if( m_nDropState & DROPSTATE_DROPPED )
  575.             ShowDrop( FALSE, TRUE );
  576.     }
  577.     bHandled = FALSE;
  578.     return 0L;
  579. }
  580. //-------------------------------------------------------------------------//
  581. //  Handle keyboard input directly for drop down acceleration.
  582. LRESULT CInPlaceDropWindow::OnKey( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  583. {
  584.     //TRACE( TEXT("CInPlaceDropWindow keydown/up/charn") );
  585.     bHandled = FALSE;
  586.     if( nMsg == WM_KEYDOWN && wParam==VK_F4 && !m_bExtendedUI )
  587.     {
  588.         ShowDrop( (m_nDropState & DROPSTATE_CLOSED)!=0, FALSE );
  589.         bHandled = TRUE;
  590.         return 0L;
  591.     }
  592.     bHandled = (m_nDropState & DROPSTATE_DROPPED) ? TRUE : FALSE;
  593.     return 0L;
  594. }
  595. //-------------------------------------------------------------------------//
  596. //  Enforce optimum control height.
  597. LRESULT CInPlaceDropWindow::OnWindowPosChanging( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  598. {
  599.     WINDOWPOS* pWP = (WINDOWPOS*)lParam;
  600.     if( (pWP->flags & SWP_NOSIZE)==0 && pWP->cy < m_cy )
  601.     {
  602.         if( (pWP->flags & SWP_NOMOVE)==0 )
  603.             pWP->y -= (m_cy - pWP->cy)/2;
  604.         
  605.         pWP->cy = m_cy;
  606.         bHandled = TRUE;
  607.         return 0L;
  608.     }
  609.     bHandled = FALSE;
  610.     return 0L;
  611. }
  612. //-------------------------------------------------------------------------//
  613. //  When our app loses activation, close the drop window.
  614. LRESULT CInPlaceDropWindow::OnActivateApp( 
  615.     UINT nMsg, 
  616.     WPARAM wParam, 
  617.     LPARAM lParam, 
  618.     BOOL& bHandled )
  619. {
  620.     bHandled = FALSE;
  621.     
  622.     if( wParam==FALSE )
  623.         ShowDrop( FALSE, TRUE );
  624.     return 0L;
  625. }
  626. //-------------------------------------------------------------------------//
  627. //  ALT-Down and ALT-Up open and close the drop host window, resp.
  628. LRESULT CInPlaceDropWindow::OnSysKeyDown( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  629. {
  630.     if( wParam==VK_DOWN || wParam==VK_UP )
  631.     {
  632.         ShowDrop( (m_nDropState & DROPSTATE_DROPPED)==0 ? TRUE : FALSE, FALSE );
  633.         bHandled = TRUE;
  634.         return 0L;
  635.     }
  636.     bHandled = FALSE;
  637.     return 0L;
  638. }
  639. //-------------------------------------------------------------------------//
  640. //  Intercept font assignment to calculate and enforce control height.
  641. LRESULT CInPlaceDropWindow::OnSetFont( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  642. {
  643.     m_hfText = (HFONT)wParam;
  644.     CalcHeight( NULL );
  645.     AdjustSize();
  646.     Invalidate( TRUE );
  647.     
  648.     bHandled = FALSE;    
  649.     return 0L;
  650. }
  651. //-------------------------------------------------------------------------//
  652. //  Intercept text assignment to calculate ideal control height.
  653. LRESULT CInPlaceDropWindow::OnSetText( 
  654.     UINT nMsg, 
  655.     WPARAM wParam, 
  656.     LPARAM lParam, 
  657.     BOOL& bHandled )
  658. {
  659.     CalcHeight( (LPCTSTR)lParam );
  660.     Invalidate( TRUE );
  661.     
  662.     bHandled = FALSE;
  663.     return 0L;
  664. }
  665. //-------------------------------------------------------------------------//
  666. //  WM_COMMAND handler.
  667. LRESULT CInPlaceDropWindow::OnCommand( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  668. {
  669.     bHandled = FALSE;
  670.     switch( LOWORD( wParam ) )
  671.     {
  672.         case IDC_DROPHOST:
  673.             bHandled = TRUE;
  674.             ShowDrop( FALSE, TRUE );
  675.             return TRUE;
  676.     }
  677.     return 0L;
  678. }
  679. //-------------------------------------------------------------------------//
  680. LRESULT CInPlaceDropWindow::OnSelfCommand( UINT nCode, BOOL& bHandled )
  681. {
  682.     return CInPlaceBase::OnSelfCommand( nCode, bHandled );
  683. }
  684. //-------------------------------------------------------------------------//
  685. //  Shows or hides the control's drop down window, and updates related
  686. //  state information.
  687. //
  688. //  BUGBUG: Need to adjust drop host rectangle to contain it
  689. //          within virtual desktop window boundaries.
  690. BOOL CInPlaceDropWindow::ShowDrop( BOOL bDrop, BOOL bCanceled )
  691. {
  692.     HWND hwndDrop = DropHwnd();
  693.     RECT rc;
  694.     memset( &rc, 0, sizeof(rc) );
  695.     //  If we're dropping...
  696.     if( bDrop && (m_nDropState & DROPSTATE_CLOSED)!=0 )
  697.     {
  698.         //  Calculate rectangle for drop host window.
  699.         GetWindowRect( &rc );
  700.         OffsetRect( &rc, 0, RECTHEIGHT( &rc ) );
  701.         rc.bottom += m_cyDrop;
  702.         m_nDropAnchor = DROPANCHOR_TOP;
  703.         //  Allow derivatives a chance at modifiying the drop host and/or
  704.         //  vetoing its display.
  705.         bCanceled = FALSE;
  706.         if( OnShowDrop( hwndDrop, TRUE, bCanceled, &rc ) )
  707.         {
  708.             m_nDropState = DROPSTATE_DROPPED;
  709.             if( hwndDrop )
  710.             {
  711.                 ::SetWindowPos( hwndDrop, HWND_TOPMOST, 
  712.                                 rc.left, rc.top, 
  713.                                 RECTWIDTH( &rc ), RECTHEIGHT( &rc ), 0 );
  714.                 AnimateDrop( hwndDrop );
  715.             }
  716.             Capture( TRUE );                    // take over the mouse
  717.             PostNotifyCommand( CBN_DROPDOWN );  // notify our parent 
  718.             return TRUE;
  719.         }
  720.         return FALSE;
  721.     }
  722.     
  723.     else 
  724.     //  If we're closing...
  725.     if( bDrop==FALSE && (m_nDropState & DROPSTATE_DROPPED)!=0 )
  726.     {
  727.         BOOL fCloseUp = TRUE;
  728.              
  729.         if( !m_fDestroyed )
  730.         {
  731.             //  Allow derivatives an opportunity to modifiy the drop host, 
  732.             //  veto its closing, and/or adjust the canceled status before closing up.
  733.             if( IsWindow( hwndDrop ) )
  734.             {
  735.                 ::GetWindowRect( hwndDrop, &rc );
  736.                 if( (fCloseUp = OnShowDrop( hwndDrop, FALSE, bCanceled, &rc )) )
  737.                     ::ShowWindow( hwndDrop, SW_HIDE );
  738.             }
  739.         }
  740.         if( fCloseUp )
  741.         {
  742.             m_nDropState = DROPSTATE_CLOSED|
  743.                            (bCanceled ? DROPSTATE_CANCEL : DROPSTATE_OK );
  744.             Capture( FALSE );                  // release the mouse.
  745.             if( !m_fDestroyed )
  746.                 PostNotifyCommand( CBN_CLOSEUP );  // notify our parent
  747.         }
  748.         
  749.     }
  750.     return TRUE;
  751. }
  752. //-------------------------------------------------------------------------//
  753. BOOL CInPlaceDropWindow::ToggleDrop( BOOL bCanceled )
  754. {
  755.     if( m_nDropState & DROPSTATE_CLOSED )
  756.         return ShowDrop( TRUE, FALSE );
  757.     else if( m_nDropState & DROPSTATE_DROPPED )
  758.         return ShowDrop( FALSE, bCanceled );
  759.     return FALSE;
  760. }
  761. //-------------------------------------------------------------------------//
  762. BOOL CInPlaceDropWindow::AnimateDrop( HWND hwndDrop, ULONG dwTime )
  763. {
  764.     ASSERT( hwndDrop );
  765.     ULONG dwDirection = (m_nDropAnchor == DROPANCHOR_TOP) ?
  766.                         AW_VER_POSITIVE : AW_VER_NEGATIVE;
  767.     return AnimateWindow( hwndDrop, dwTime, AW_SLIDE | dwDirection );
  768. }
  769. #define IPDW_CLICKTIMER 1
  770. //-------------------------------------------------------------------------//
  771. void CInPlaceDropWindow::ClickButton()
  772. {
  773.     if( m_fBtnPressed )
  774.     {
  775.         KillTimer( IPDW_CLICKTIMER );
  776.         m_fBtnPressed = FALSE;
  777.     }
  778.     m_fBtnPressed = TRUE;
  779.     InvalidateRect( &m_rcBtn, TRUE );
  780.     UpdateWindow();
  781.     SetTimer( IPDW_CLICKTIMER, 125, NULL );
  782. }
  783. //-------------------------------------------------------------------------//
  784. LRESULT CInPlaceDropWindow::OnTimer( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  785. {
  786.     if( wParam == IPDW_CLICKTIMER )
  787.     {
  788.         KillTimer( IPDW_CLICKTIMER );
  789.         m_fBtnPressed = FALSE;
  790.         InvalidateRect( &m_rcBtn, TRUE );
  791.         UpdateWindow();
  792.         bHandled = TRUE;
  793.     }
  794.     return 0L;
  795. }
  796. //-------------------------------------------------------------------------//
  797. //  Message handler: reports the drop state of the control
  798. LRESULT CInPlaceDropWindow::OnCBGetDropState( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  799. {
  800.     bHandled = TRUE;
  801.     return (m_nDropState & DROPSTATE_DROPPED) ? TRUE : FALSE;
  802. }
  803. //-------------------------------------------------------------------------//
  804. BOOL CInPlaceDropWindow::GetMonitorRect( OUT RECT& rcMonitor ) const
  805. {
  806.     HMONITOR hMonitor;
  807.     if( (hMonitor = MonitorFromWindow( *this, MONITOR_DEFAULTTONEAREST ))!=NULL )
  808.     {
  809.         MONITORINFO mi;
  810.         mi.cbSize = sizeof(mi);
  811.         if( GetMonitorInfo( hMonitor, &mi ) )
  812.         {
  813.             rcMonitor = mi.rcMonitor;
  814.             return TRUE;
  815.         }
  816.     }
  817.     return FALSE;
  818. }
  819. //-------------------------------------------------------------------------//
  820. void CInPlaceDropWindow::NormalizeDropRect( 
  821.     IN OUT RECT& rcDrop, 
  822.     OUT OPTIONAL UINT* pnAnchorBorder ) const
  823. {
  824.     RECT rcThis, rcMonitor;
  825.     if( pnAnchorBorder ) *pnAnchorBorder = DROPANCHOR_TOP;
  826.     if( GetWindowRect( &rcThis ) && GetMonitorRect( rcMonitor ) )
  827.     {
  828.         if( rcDrop.bottom > rcMonitor.bottom )
  829.         {
  830.             OffsetRect( &rcDrop, 0, rcThis.top - rcDrop.bottom );
  831.             if( pnAnchorBorder ) *pnAnchorBorder = DROPANCHOR_BOTTOM;
  832.         }
  833.     }
  834. }
  835. //-------------------------------------------------------------------------//
  836. //  Retrieves text rectangle within control
  837. BOOL CInPlaceDropWindow::GetTextBox( LPRECT prc )
  838. {
  839.     RECT rcText;
  840.     
  841.     //  Retrieve text box metrics in client coordinates
  842.     if( !GetClientRect( &rcText ) )
  843.         return FALSE;
  844.     return GetTextBox( RECTWIDTH( &rcText ), RECTHEIGHT( &rcText ), prc );
  845. }
  846. //-------------------------------------------------------------------------//
  847. //  Calculates available text rectangle within control
  848. BOOL CInPlaceDropWindow::GetTextBox( int cx, int cy, LPRECT prc )
  849. {
  850.     ASSERT( prc );
  851.     RECT rcText;
  852.     SetRect( &rcText, 0, 0, cx, cy );
  853.     //  Adjust subtract button rectangle from text rectangle
  854.     rcText.right = m_rcBtn.left;
  855.     if( rcText.left < rcText.right || rcText.top < rcText.bottom )
  856.     {
  857.         *prc = rcText;
  858.         return TRUE;
  859.     }
  860.     
  861.     SetRectEmpty( prc );
  862.     return FALSE;
  863. }
  864. //-------------------------------------------------------------------------//
  865. //  Calculates optimum window height based on current window font
  866. void CInPlaceDropWindow::CalcHeight( LPCTSTR pszWindowText )
  867. {
  868.     HDC hdc;
  869.     if( (hdc = GetDC())!=NULL )
  870.     {
  871.         SIZE    sizeText;
  872.         sizeText.cx = sizeText.cy = 0;
  873.         if( !(pszWindowText && *pszWindowText) ) 
  874.             pszWindowText = TEXT("|");
  875.         HFONT hfText = (HFONT)SelectObject( hdc, m_hfText );
  876.         if( GetTextExtentPoint32( hdc, pszWindowText, lstrlen(pszWindowText), &sizeText ) )
  877.             m_cy = sizeText.cy + 8 /*(2-pixel NC border, 2-pixel client border)*/;
  878.         SelectObject( hdc, hfText );
  879.         ReleaseDC( hdc );
  880.     }
  881. }
  882. //-------------------------------------------------------------------------//
  883. //  Adjusts window height to precalculated value
  884. void CInPlaceDropWindow::AdjustSize()
  885. {
  886.     RECT rcSave, rc;
  887.     GetWindowRect( &rc );
  888.     ::MapWindowPoints( HWND_DESKTOP, GetParent(), (LPPOINT)&rc, 2 );
  889.     CopyRect( &rcSave, &rc );
  890.     rc.bottom = rc.top + m_cy; // adjust for text height.
  891.     if( !EqualRect( &rcSave, &rc ) )
  892.         SetWindowPos( NULL, 0,0, RECTWIDTH( &rc ), RECTHEIGHT( &rc ),
  893.                       SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
  894. }
  895. //-------------------------------------------------------------------------//
  896. //  Adjusts window layout
  897. void CInPlaceDropWindow::PositionControls( int cx, int cy )
  898. {
  899.     SetRect( &m_rcBtn, 
  900.              max( 0, cx - GetSystemMetrics( SM_CXVSCROLL )), 0, 
  901.              cx, cy );
  902.     Invalidate( TRUE );
  903. }
  904. //-------------------------------------------------------------------------//
  905. //  Internal helper: captures or releases the mouse.
  906. BOOL CInPlaceDropWindow::Capture( BOOL bCapture )
  907. {
  908.     if( bCapture )
  909.     {
  910.         //TRACE( TEXT("CInPlaceDropWindow %08lX capturing mousen"), m_hWnd );
  911.         SetCapture();
  912.         return TRUE;
  913.     }
  914.     //TRACE( TEXT("CInPlaceDropWindow %08lX releasing mousen"), m_hWnd );
  915.     return ReleaseCapture();
  916. }
  917. //-------------------------------------------------------------------------//
  918. //  Message handler: if mouse capture is lost to a child window, 
  919. //  we must subclass that window in order to continue to be apprised of
  920. //  mouse activity.
  921. LRESULT CInPlaceDropWindow::OnCaptureChanged( UINT, WPARAM, LPARAM lParam, BOOL& bHandled )
  922. {
  923.     HWND hwndCapture = (HWND)lParam;
  924.     
  925.     bHandled = FALSE;
  926.     //TRACE( TEXT("CInPlaceDropWindow %08lX losing capture to %08lXn"), m_hWnd, lParam );
  927.     if( hwndCapture && hwndCapture != m_hWnd && IsChildOfDrop( hwndCapture ) )
  928.     {
  929.         //TRACE( TEXT("CInPlaceDropWindow %08lX subclassing capture window %08lXn"), m_hWnd, lParam );
  930.         m_wndCaptureAgent.Track( (HWND)lParam, m_hWnd );
  931.         bHandled = TRUE;
  932.     }
  933.     return 0L;
  934. }
  935. //-------------------------------------------------------------------------//
  936. //  Message handler: recieves notifications of mouse activity from a
  937. //  subclassed child window which has directly or indirectly acquired mouse 
  938. //  capture from us.
  939. LRESULT CInPlaceDropWindow::OnCaptureMsg( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  940. {
  941.     switch( wParam )
  942.     {
  943.         case CCaptureTracker::Released:
  944.             if( m_nDropState & DROPSTATE_DROPPED )
  945.                 Capture( TRUE );
  946.             break;
  947.         case CCaptureTracker::Lost:
  948.         case CCaptureTracker::ForeignClick:
  949.             ShowDrop( FALSE, TRUE );
  950.             break;
  951.     }
  952.     bHandled = TRUE;
  953.     return 0L;
  954. }
  955. //-------------------------------------------------------------------------//
  956. //  class CInPlaceDropCalendar : public CInPlaceDropWindow
  957. //  (specialized to manipulate a CCalendarDrop dropdown host window)
  958. //-------------------------------------------------------------------------//
  959. //-------------------------------------------------------------------------//
  960. //  Constructor 
  961. CInPlaceDropCalendar::CInPlaceDropCalendar( HWND hwndTree ) 
  962.     :   CInPlaceDropWindow( hwndTree ),
  963.         m_wndPick( DATETIMEPICK_CLASS, this, DATEPICK_MSGMAP ) 
  964. {
  965.     m_wndDrop.SetOwner( this );
  966.     memset( &m_st, 0, sizeof(m_st) );
  967.     SystemTimeMakeTimeless( &m_st );
  968. }
  969. //-------------------------------------------------------------------------//
  970. //  WM_CREATE handler; creates child window controls
  971. LRESULT CInPlaceDropCalendar::OnCreate( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  972. {
  973.     LRESULT        lRet;
  974.     LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam;
  975.     if( (lRet = CInPlaceDropWindow::OnCreate( nMsg, wParam, lParam, bHandled ))!=0L )
  976.         return lRet;
  977.     bHandled = TRUE;
  978.     RECT rc, rcText;
  979.     GetClientRect( &rc );
  980.     GetTextBox( RECTWIDTH( &rc ), RECTHEIGHT( &rc ), &rcText );
  981.     //  Create date picker
  982.     if( m_wndPick.Create( m_hWnd, rcText, NULL,  
  983.                           DTS_SHORTDATEFORMAT|DTS_UPDOWN|WS_CHILD|WS_VISIBLE, 
  984.                           0L, IDC_DATEPICK )==NULL )
  985.         return -1;
  986.     //  Remove bordered styles
  987.     DWORD dwStyle   = m_wndPick.GetWindowLong( GWL_STYLE ),
  988.           dwStyleEx = m_wndPick.GetWindowLong( GWL_EXSTYLE );
  989.     dwStyle     &= ~ (WS_BORDER|WS_OVERLAPPED);
  990.     dwStyleEx   &= ~ (WS_EX_CLIENTEDGE|WS_EX_WINDOWEDGE);
  991.     m_wndPick.SetWindowLong( GWL_STYLE, dwStyle );
  992.     m_wndPick.SetWindowLong( GWL_EXSTYLE, dwStyleEx );
  993.     HWND hwndSpinner;
  994.     for( hwndSpinner = m_wndPick.GetWindow( GW_CHILD );
  995.          hwndSpinner != NULL;
  996.          hwndSpinner = ::GetWindow( hwndSpinner, GW_HWNDNEXT ) )
  997.     {
  998.         ::ShowWindow( hwndSpinner, SW_HIDE );
  999.     }
  1000.     //  Create drop window
  1001.     if( m_wndDrop.Create( m_hWnd, NULL )==NULL )
  1002.         return -1;
  1003.     m_wndPick.SetFocus();
  1004.     PositionControls( RECTWIDTH( &rc ), RECTHEIGHT( &rc ) );
  1005.     return 0L;
  1006. }
  1007. //-------------------------------------------------------------------------//
  1008. //  Date time picker control's WM_GETDLGCODE handler 
  1009. LRESULT CInPlaceDropCalendar::OnPickerGetDlgCode( UINT, WPARAM, LPARAM lParam, BOOL& bHandled )
  1010. {
  1011.     if( 0L != lParam && 
  1012.         WM_KEYDOWN == ((LPMSG)lParam)->message && VK_TAB == ((LPMSG)lParam)->wParam )
  1013.     {
  1014.         bHandled = FALSE;
  1015.         return 0L;
  1016.     }
  1017.     
  1018.     return DLGC_WANTALLKEYS;
  1019. }
  1020. //-------------------------------------------------------------------------//
  1021. //  Date time picker control's WM_SHOWWINDOW hander
  1022. LRESULT CInPlaceDropCalendar::OnPickerShowWindow( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1023. {
  1024.     LRESULT lRet = DefWindowProc( nMsg, wParam, lParam );
  1025.     bHandled = TRUE;
  1026.     
  1027.     HWND hwndChild = NULL;
  1028.     for( hwndChild = GetWindow( GW_CHILD );
  1029.          hwndChild != NULL;
  1030.          hwndChild = ::GetWindow( hwndChild, GW_HWNDNEXT ) )
  1031.     {
  1032.         ::ShowWindow( hwndChild, SW_HIDE );
  1033.     }
  1034.     return lRet; 
  1035. }
  1036. //-------------------------------------------------------------------------//
  1037. //  WM_NOTIFY handler for IDC_DATEPICK
  1038. LRESULT CInPlaceDropCalendar::OnPickerNotify( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
  1039. {
  1040.     SYSTEMTIME st;
  1041.     bHandled = FALSE;
  1042.     switch( pnmh->code )
  1043.     {
  1044.         case DTN_DATETIMECHANGE:    
  1045.             if( !GetPickDate( st ) )
  1046.                 memset( &st, 0, sizeof(st) );
  1047.             SystemTimeMakeTimeless( &st );
  1048.             m_wndDrop.SetDate( st );
  1049.             UpdateDisplayDate( st, UDDF_WINDOWTEXT /*avoid circular logic w/SetPickDate()*/ );
  1050.             bHandled = TRUE;
  1051.             break;
  1052.             
  1053.         case NM_SETFOCUS:
  1054.             ::SendMessage( m_hwndTree, WMU_CTLFOCUS, 0, (LPARAM)WM_SETFOCUS );
  1055.             break;
  1056.         case NM_KILLFOCUS:
  1057.             ::SendMessage( m_hwndTree, WMU_CTLFOCUS, 0, (LPARAM)WM_KILLFOCUS );
  1058.             break;
  1059.     }
  1060.     return 0L;
  1061. }
  1062. //-------------------------------------------------------------------------//
  1063. //  WM_SIZE handler.
  1064. LRESULT CInPlaceDropCalendar::OnSize( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1065. {
  1066.     CInPlaceDropWindow::OnSize( nMsg, wParam, lParam, bHandled );
  1067.     PositionControls( LOWORD(lParam), HIWORD(lParam) );
  1068.     return 0L;
  1069. }
  1070. //-------------------------------------------------------------------------//
  1071. void CInPlaceDropCalendar::PositionControls( int cx, int cy )
  1072. {
  1073.     if( ::IsWindow( m_wndPick.m_hWnd ) )
  1074.     {
  1075.         RECT rc;
  1076.         GetTextBox( cx, cy, &rc );
  1077.         m_wndPick.SetWindowPos( NULL, 0, 0, 
  1078.                                 RECTWIDTH( &rc ), RECTHEIGHT( &rc ),
  1079.                                 SWP_NOZORDER|SWP_NOACTIVATE );
  1080.     }
  1081.     InvalidateRect( &m_rcBtn );
  1082. }
  1083. //-------------------------------------------------------------------------//
  1084. //  WM_SETFOCUS handler.
  1085. LRESULT CInPlaceDropCalendar::OnSetFocus( UINT, WPARAM, LPARAM, BOOL& bHandled )
  1086. {
  1087.     bHandled = FALSE;
  1088.     m_wndPick.SetFocus();  // give it to date picker.
  1089.     return 0L;
  1090. }
  1091. //-------------------------------------------------------------------------//
  1092. //  WMU_SETITEMDATA handler; caches the assigned date.
  1093. LRESULT CInPlaceDropCalendar::OnSetItemData( UINT, WPARAM, LPARAM lParam, BOOL& bHandled )
  1094. {
  1095.     SYSTEMTIME* pst = (SYSTEMTIME*)lParam;
  1096.     if( pst )
  1097.     {
  1098.         m_st = *pst;
  1099.         SystemTimeMakeTimeless( &m_st );
  1100.         SetPickDate( m_st );
  1101.         m_wndDrop.SetDate( m_st );
  1102.     }
  1103.     bHandled = TRUE;
  1104.     return 1L;
  1105. }
  1106. //-------------------------------------------------------------------------//
  1107. //  Overriden to adjust drop window, recalc child layout, veto drop/closeup
  1108. BOOL CInPlaceDropCalendar::OnShowDrop( HWND hwndDrop, BOOL bDrop, BOOL& bCanceled, LPRECT prcDrop )
  1109. {
  1110.     if( bDrop )
  1111.     {
  1112.         SIZE sizeCal, sizeDropNc;
  1113.         //  Reinitialize layout (who knows where and how we're being dropped!) before
  1114.         //  being displayed
  1115.         m_wndDrop.GetClientSize( &sizeCal );
  1116.         GetNcBorderSize( hwndDrop, &sizeDropNc );
  1117.         
  1118.         prcDrop->left   = prcDrop->right - (sizeCal.cx + sizeDropNc.cx);
  1119.         prcDrop->bottom = prcDrop->top   + (sizeCal.cy + sizeDropNc.cy);
  1120.         NormalizeDropRect( *prcDrop, &m_nDropAnchor );
  1121.         
  1122.         m_wndDrop.SetDate( m_st );
  1123.     }
  1124.         
  1125.     return CInPlaceDropWindow::OnShowDrop( hwndDrop, bDrop, bCanceled, prcDrop );
  1126. }
  1127. //-------------------------------------------------------------------------//
  1128. //  Keyboard message handler; passes appropriate keys to common calendar
  1129. //  control child window.
  1130. LRESULT CInPlaceDropCalendar::OnKey( UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  1131. {
  1132.     //  Route key messages to child controls
  1133.     return HandleKeyMessage( m_hWnd, nMsg, virtKey, lParam, bHandled );
  1134. }
  1135. //-------------------------------------------------------------------------//
  1136. //  WM_CHAR, WM_KEYUP, WM_KEYDOWN handler for Date/Time Picker control.
  1137. LRESULT CInPlaceDropCalendar::OnPickerKey( UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  1138. {
  1139.     LRESULT lRet = 0;
  1140.     bHandled = FALSE;
  1141.     //  Pass directional keys to calendar drop
  1142.     lRet = HandleKeyMessage( m_wndPick, nMsg, virtKey, lParam, bHandled );
  1143.     if( bHandled ) 
  1144.         return lRet;
  1145.     //  Let input (i.e., numeric) keys go to picker control.
  1146.     if( IsInputKey( virtKey ) )
  1147.     {
  1148.         bHandled = TRUE;
  1149.         return m_wndPick.DefWindowProc( nMsg, virtKey, lParam );
  1150.     }
  1151.     //  Pass other keys to CInPlaceDropCalendar (picker's parent)
  1152.     bHandled = TRUE;
  1153.     return SendMessage( nMsg, virtKey, lParam );
  1154. }
  1155. //-------------------------------------------------------------------------//
  1156. //  WM_SYSKEYDOWN handler for Date/Time Picker control.
  1157. LRESULT CInPlaceDropCalendar::OnPickerSysKeyDown( UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  1158. {
  1159.     //  Pass WM_SYSKEYDOWN messages to CInPlaceDropCalendar (picker's parent)
  1160.     bHandled = TRUE;
  1161.     return SendMessage( nMsg, virtKey, lParam );
  1162. }
  1163. //-------------------------------------------------------------------------//
  1164. //  Determines whether the specified virtual key code represents a directional key.
  1165. BOOL CInPlaceDropCalendar::IsDirectionalKey( WPARAM virtKey ) const
  1166. {
  1167.     switch( virtKey )
  1168.     {
  1169.         case VK_PRIOR:
  1170.         case VK_NEXT:
  1171.         case VK_END:
  1172.         case VK_HOME:
  1173.         case VK_LEFT:
  1174.         case VK_UP:
  1175.         case VK_RIGHT:
  1176.         case VK_DOWN:
  1177.         return TRUE;
  1178.     }
  1179.     return FALSE;
  1180. }
  1181. //-------------------------------------------------------------------------//
  1182. //  Determines whether the specified virtual key code represents a numeric key.
  1183. BOOL CInPlaceDropCalendar::IsInputKey( WPARAM virtKey ) const
  1184. {
  1185.     if( (virtKey >= '0' && virtKey <= '9') || 
  1186.         (virtKey >= VK_NUMPAD0 && virtKey <= VK_NUMPAD9) )
  1187.         return TRUE;
  1188.     if( virtKey == VK_RIGHT || virtKey == VK_LEFT )
  1189.         return TRUE;
  1190.     return FALSE;
  1191. }
  1192. //-------------------------------------------------------------------------//
  1193. LRESULT CInPlaceDropCalendar::HandleKeyMessage( HWND hwndFrom, UINT nMsg, WPARAM virtKey, LPARAM lParam, BOOL& bHandled )
  1194. {
  1195.     LRESULT lRet = 0L;
  1196.     bHandled = FALSE;
  1197.     //  calendar drop key?
  1198.     if( 0 !=(m_nDropState & DROPSTATE_DROPPED) &&
  1199.         IsDirectionalKey( virtKey ) )
  1200.     {
  1201.         //  Pass directional keys to calendar drop control
  1202.         bHandled = TRUE;
  1203.         return ::SendMessage( m_wndDrop.CalHwnd(), nMsg, virtKey, lParam );
  1204.     }
  1205.     else // calendar is closed up...
  1206.     {
  1207.         //  ESC or ENTER?
  1208.         if( nMsg==WM_KEYDOWN )
  1209.         {
  1210.             switch( virtKey )
  1211.             {
  1212.                 case VK_ESCAPE:
  1213.                     ShowDrop( FALSE, TRUE );
  1214.                     UpdateDisplayDate( m_st, UDDF_PICKERDATE|UDDF_WINDOWTEXT );
  1215.                     break;
  1216.                 case VK_RETURN:
  1217.                     ShowDrop( FALSE, FALSE );
  1218.                     if( hwndFrom == m_wndPick )
  1219.                     {
  1220.                         GetPickDate( m_st );
  1221.                         UpdateDisplayDate( m_st, UDDF_WINDOWTEXT );
  1222.                     }
  1223.                     else
  1224.                     {
  1225.                         m_wndDrop.GetDate( m_st );
  1226.                         UpdateDisplayDate( m_st, UDDF_PICKERDATE|UDDF_WINDOWTEXT );
  1227.                     }
  1228.                     break;
  1229.             }
  1230.         }
  1231.         NAVIGATION_KEY_INFO nki;
  1232.         InitNavigationKeyInfo( &nki, m_hWnd, nMsg, virtKey, lParam );
  1233.         lRet = ::SendMessage( m_hwndTree, WMU_NAVIGATION_KEY, 
  1234.                               GetDlgCtrlID(), (LPARAM)&nki );
  1235.         bHandled = nki.bHandled;
  1236.     }
  1237.     return lRet;
  1238. }
  1239. //-------------------------------------------------------------------------//
  1240. //  Extracts and assigns calendar date members from the provided SYSTEMTIME object.
  1241. void CInPlaceDropCalendar::AssignCalendarDate( IN SYSTEMTIME& stSrc, OUT SYSTEMTIME& stDest )
  1242. {
  1243.     stDest.wYear      = stSrc.wYear;
  1244.     stDest.wMonth     = stSrc.wMonth;
  1245.     stDest.wDay       = stSrc.wDay;
  1246.     stDest.wDayOfWeek = stSrc.wDayOfWeek;
  1247.     SystemTimeMakeTimeless( &stDest );
  1248. }
  1249. //-------------------------------------------------------------------------//
  1250. //  Displays the specified date in the drop calendard window.
  1251. //  Flags member: UDDF_WINDOWTEXT, UDDF_PICKERDATE
  1252. void CInPlaceDropCalendar::UpdateDisplayDate( IN SYSTEMTIME& stSrc, ULONG dwFlags )
  1253. {
  1254.     DATE date = 0;
  1255.     SystemTimeMakeTimeless( &stSrc );
  1256.     if( dwFlags & UDDF_WINDOWTEXT )
  1257.     {
  1258.         if( SystemTimeToVariantTime( &stSrc, &date ) )
  1259.         {
  1260.             BSTR bstrDate;
  1261.             if( SUCCEEDED( VarBstrFromDate( date, GetUserDefaultLCID(), 
  1262.                                             VAR_DATEVALUEONLY, &bstrDate ) ) )
  1263.             {
  1264.                 USES_CONVERSION;
  1265.                 SetWindowText( W2T( bstrDate ) );
  1266.                 Invalidate();
  1267.                 SysFreeString( bstrDate );
  1268.             }
  1269.         }
  1270.     }
  1271.     if( dwFlags & UDDF_PICKERDATE )
  1272.         SetPickDate( stSrc );
  1273. }
  1274. //-------------------------------------------------------------------------//
  1275. BOOL CInPlaceDropCalendar::GetPickDate( OUT SYSTEMTIME& stDest )
  1276. {
  1277.     if( IsWindow( m_wndPick.m_hWnd ) &&
  1278.         DateTime_GetSystemtime( m_wndPick, &stDest )==GDT_VALID )
  1279.     {
  1280.         SystemTimeMakeTimeless( &stDest );
  1281.         return TRUE;
  1282.     }
  1283.     return FALSE;
  1284. }
  1285. //-------------------------------------------------------------------------//
  1286. BOOL CInPlaceDropCalendar::SetPickDate( IN SYSTEMTIME& stSrc ) 
  1287. {
  1288.     if( !::IsWindow( m_wndPick.m_hWnd ) )
  1289.         return FALSE;
  1290.     
  1291.     WPARAM wPickFlag = (stSrc.wMonth==0 || stSrc.wDay==0 || stSrc.wYear == 0) ? 
  1292.                         GDT_NONE : GDT_VALID;
  1293.     SystemTimeMakeTimeless( &stSrc );
  1294.     return DateTime_SetSystemtime( m_wndPick, wPickFlag, &stSrc );
  1295. }
  1296. //-------------------------------------------------------------------------//
  1297. //  class CCalendarDrop : public CDialogImpl<CCalendarDrop>
  1298. //-------------------------------------------------------------------------//
  1299. //-------------------------------------------------------------------------//
  1300. //  Creates calendar drop child window and subordinates
  1301. HWND CCalendarDrop::Create( HWND hwndParent, LPPOINT ptMouseActivate )
  1302. {
  1303.     HWND hwndThis;
  1304.     RECT rc = {0,0,0,0};
  1305.     if( (hwndThis = CDialogImpl<CCalendarDrop>::Create( hwndParent ))==NULL )
  1306.         return hwndThis;
  1307.     //  Fake out USER and add illegal style combinations after creation...
  1308.     DWORD dwStyle   = ::GetWindowLong( hwndThis, GWL_STYLE ),
  1309.           dwExStyle = ::GetWindowLong( hwndThis, GWL_EXSTYLE );
  1310.     dwStyle   |= WS_CHILD;
  1311.     dwExStyle |= WS_EX_TOOLWINDOW;
  1312.    
  1313.     ::SetWindowLong( hwndThis, GWL_STYLE, dwStyle );
  1314.     ::SetWindowLong( hwndThis, GWL_EXSTYLE, dwExStyle );
  1315.     SetWindowPos( HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE );
  1316.     SetParent( HWND_DESKTOP );
  1317.     
  1318.     if( (m_hwndCal = GetDlgItem( IDC_CALENDAR ))==NULL )
  1319.     {
  1320.         DestroyWindow();
  1321.         return NULL;
  1322.     }
  1323.     
  1324.     MonthCal_SetColor( m_hwndCal, MCSC_BACKGROUND, GetSysColor( COLOR_3DFACE ) );
  1325.     MonthCal_SetColor( m_hwndCal, MCSC_TITLEBK ,   GetSysColor( COLOR_HIGHLIGHT ) );
  1326.     MonthCal_SetColor( m_hwndCal, MCSC_TITLETEXT,  GetSysColor( COLOR_HIGHLIGHTTEXT ) );
  1327.     MonthCal_SetColor( m_hwndCal, MCSC_MONTHBK,    GetSysColor( COLOR_WINDOW ) );
  1328.     MonthCal_SetColor( m_hwndCal, MCSC_TEXT,       GetSysColor( COLOR_WINDOWTEXT ) ); 
  1329.     
  1330.     SIZE sizeCal;
  1331.     if( GetClientSize( &sizeCal ) )
  1332.     {
  1333.        ::SetWindowPos( m_hwndCal, NULL, 0, 0, sizeCal.cx, sizeCal.cy,
  1334.                        SWP_NOZORDER|SWP_NOACTIVATE );
  1335.     }
  1336.     return hwndThis;
  1337. }
  1338. //-------------------------------------------------------------------------//
  1339. //  Calculates optimum client size
  1340. BOOL CCalendarDrop::GetClientSize( OUT LPSIZE pSize )
  1341. {
  1342.     RECT rcClient;
  1343.     ASSERT( m_hWnd );
  1344.     SIZE sizeNc;
  1345.     
  1346.     if( MonthCal_GetMinReqRect( m_hwndCal, &rcClient ) )
  1347.     {
  1348.         GetNcBorderSize( m_hwndCal, &sizeNc );
  1349.         pSize->cx = RECTWIDTH( &rcClient ) + sizeNc.cx;
  1350.         pSize->cy = RECTHEIGHT( &rcClient ) + sizeNc.cy;
  1351.         return TRUE;
  1352.     }
  1353.     pSize->cx = pSize->cy = 0;
  1354.     return FALSE;
  1355. }
  1356. //-------------------------------------------------------------------------//
  1357. //  Assigns a date/time to the calendar
  1358. BOOL CCalendarDrop::SetDate( IN SYSTEMTIME&  st )
  1359. {
  1360.     CInPlaceDropCalendar::AssignCalendarDate( st, m_st );
  1361.     if( !m_hWnd ) 
  1362.         return TRUE;
  1363.     return Update();
  1364. }
  1365. //-------------------------------------------------------------------------//
  1366. //  Retrieves the date/time from the calendar
  1367. BOOL CCalendarDrop::GetDate( OUT SYSTEMTIME& st )
  1368. {
  1369.     if( m_hWnd )
  1370.     {
  1371.         SYSTEMTIME stCurSel;
  1372.         if( MonthCal_GetCurSel( m_hwndCal, &stCurSel ) )
  1373.             CInPlaceDropCalendar::AssignCalendarDate( stCurSel, m_st );
  1374.     }
  1375.     st = m_st;
  1376.     return TRUE;
  1377. }
  1378. //-------------------------------------------------------------------------//
  1379. BOOL CCalendarDrop::Update()
  1380. {
  1381.     return MonthCal_SetCurSel( m_hwndCal, &m_st );
  1382. }
  1383. //-------------------------------------------------------------------------//
  1384. //  MCN_SELCHANGE handler.  
  1385. //  Responds to calendar selection changes by updating the owner drop window's
  1386. //  text.
  1387. LRESULT CCalendarDrop::OnCalSelChange( int nIDCtl, LPNMHDR pNMH, BOOL& bHandled )
  1388. {
  1389.     LPNMSELCHANGE pNMS = (LPNMSELCHANGE)pNMH;
  1390.     CInPlaceDropCalendar::AssignCalendarDate( pNMS->stSelStart, m_st );
  1391.     m_pOwner->UpdateDisplayDate( m_st, UDDF_PICKERDATE|UDDF_WINDOWTEXT );
  1392.     bHandled = TRUE;
  1393.     return 0L;
  1394. }
  1395. //-------------------------------------------------------------------------//
  1396. //  MCN_SELECT handler.  
  1397. LRESULT CCalendarDrop::OnCalSelect( int nIDCtl, LPNMHDR pNMH, BOOL& bHandled )
  1398. {
  1399.     OnCalSelChange( nIDCtl, pNMH, bHandled );
  1400.     m_pOwner->ShowDrop( FALSE, FALSE );
  1401.     return 0L;
  1402. }
  1403. //-------------------------------------------------------------------------//
  1404. //  class CInPlaceDropEdit : public CInPlaceDropWindow
  1405. //  (specialized to manipulate a CEditDrop dropdown host window)
  1406. //-------------------------------------------------------------------------//
  1407. //-------------------------------------------------------------------------//
  1408. //  Constructor
  1409. CInPlaceDropEdit::CInPlaceDropEdit( HWND hwndTree ) 
  1410.     :   CInPlaceDropWindow( hwndTree )
  1411. {
  1412.     m_wndDrop.SetOwner( this );
  1413. }
  1414. //#define  __MODELESS_EDITDLG_
  1415. //-------------------------------------------------------------------------//
  1416. //  Overriden to present CEditDrop as modal dialog.
  1417. BOOL CInPlaceDropEdit::OnShowDrop( HWND hwndDrop, BOOL bDrop, BOOL& bCanceled, LPRECT prcDrop )
  1418. {
  1419. #ifdef __MODELESS_EDITDLG_
  1420.     if( bDrop )
  1421.         return m_wndDrop.Create( *this )!=NULL;
  1422.     
  1423.     return m_wndDrop.DestroyWindow();
  1424. #else
  1425.     m_wndDrop.DoModal( *this );
  1426.     SetFocus();
  1427.     return FALSE;
  1428. #endif __MODELESS_EDITDLG_
  1429. }
  1430. //-------------------------------------------------------------------------//
  1431. LRESULT CInPlaceDropEdit::OnChar( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1432. {
  1433.     //TRACE( TEXT("CInPlaceDropEdit::OnChar( %08lX, '%04X' )n"), nMsg, wParam );
  1434.     bHandled = FALSE;
  1435.     
  1436.     if( GetDropState() & DROPSTATE_CLOSED )
  1437.     {
  1438.         switch( wParam )
  1439.         {
  1440.             case VK_BACK:
  1441.             case VK_TAB:
  1442.             case VK_CLEAR:
  1443.             case VK_RETURN:
  1444.             case VK_ESCAPE:
  1445.             case 0x0A:  // line feed
  1446.                 return 0L;
  1447.         }
  1448.         m_wndDrop.QueueCharMsg( nMsg, wParam, lParam );
  1449.         ShowDrop( TRUE, FALSE );
  1450.         bHandled = TRUE;
  1451.     }
  1452.     return 0L;    
  1453. }
  1454. //-------------------------------------------------------------------------//
  1455. LRESULT CInPlaceDropEdit::OnImeComposition( UINT, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1456. {
  1457.     //  The IME window is about to submit its composition string to us.
  1458.     //  If we don't intercept this message and handle it ourselves, DefWindowProc
  1459.     //  will start feeding us the string in a series of WM_CHARs, which will 
  1460.     //  errantly open our drop-down window and cause us to hang.
  1461.     //  (NT raid# 295062).   
  1462.     //  We can either get the string ourselves and assign it as our window text, or
  1463.     //  we can simply drop the edit control and have the IME latch to that.   We tried
  1464.     //  the first way, which worked with all IMEs except CHS.   So now we're opening
  1465.     //  the edit drop as soon as we get IME input, which makes the drop similar in 
  1466.     //  behavior to direct input.
  1467.     
  1468.     bHandled = FALSE;
  1469. #ifdef _DEAL_WITH_IME_COMPOSITION_STRING_WITHOUT_DROPDOWN 
  1470.  
  1471.     if( GetDropState() & DROPSTATE_CLOSED )
  1472.     {
  1473.         HIMC himc;
  1474.         if( (himc = ImmGetContext( m_hWnd )) != NULL )
  1475.         {
  1476.             LPWSTR pwsz = NULL;
  1477.             int    cch  = ImmGetCompositionStringW( himc, GCS_RESULTSTR, NULL, 0 )/sizeof(WCHAR);
  1478.             if( cch && (pwsz = new WCHAR[cch+1]) != NULL )
  1479.             {
  1480.                 ImmGetCompositionStringW( himc, GCS_RESULTSTR, pwsz, (cch + 1) * sizeof(WCHAR) );
  1481.                 pwsz[cch] = L''; // null terminate the string
  1482.                 SetWindowText( pwsz );
  1483.                 delete [] pwsz;
  1484.             }
  1485.             ImmReleaseContext( m_hWnd, himc );
  1486.         }
  1487.         bHandled = TRUE;
  1488.     }
  1489. #else _DEAL_WITH_IME_COMPOSITION_STRING_WITHOUT_DROPDOWN 
  1490.     //  Drop the edit drop if it's not dropped already, 
  1491.     //  like we do upon receiving direct input characters.
  1492.     if( GetDropState() & DROPSTATE_CLOSED )
  1493.         ShowDrop( TRUE, FALSE );
  1494.         
  1495. #endif _DEAL_WITH_IME_COMPOSITION_STRING_WITHOUT_DROPDOWN 
  1496.     return 0L;
  1497. }
  1498. //-------------------------------------------------------------------------//
  1499. //  class CEditDrop
  1500. //-------------------------------------------------------------------------//
  1501. const int nEditDropCtlMargin = 2;
  1502. CEditDrop::CEditDrop()
  1503.     :   m_pOwner(NULL), 
  1504.         m_pszUndo(NULL),
  1505.         m_fEndDlg(FALSE)
  1506. {
  1507.     memset( &m_msgChar, 0, sizeof(m_msgChar) );
  1508. }
  1509. //-------------------------------------------------------------------------//
  1510. void CEditDrop::QueueCharMsg( UINT nMsg, WPARAM wParam, LPARAM lParam )
  1511. {
  1512.     ASSERT( nMsg == WM_CHAR || nMsg == WM_DEADCHAR );
  1513.     m_msgChar.message = nMsg;
  1514.     m_msgChar.wParam = wParam;
  1515.     m_msgChar.lParam = lParam;
  1516. }
  1517. //-------------------------------------------------------------------------//
  1518. //  Computes minimum drop window width.
  1519. void CEditDrop::EnforceMinWidth( LPRECT prcThis /* in screen coords */)
  1520. {
  1521.     ASSERT( prcThis );
  1522.     ASSERT( IsWindow( GetDlgItem( IDOK ) ) );
  1523.     ASSERT( IsWindow( GetDlgItem( IDOK ) ) );
  1524.     RECT rcOK, rcCancel, rc, rcClient;
  1525.     ::GetWindowRect( GetDlgItem( IDOK ), &rcOK );
  1526.     ::GetWindowRect( GetDlgItem( IDCANCEL ), &rcCancel );
  1527.     
  1528.     GetWindowRect( &rc );
  1529.     GetClientRect( &rcClient );
  1530.     int cxMin = (rcCancel.right - rcOK.left) + nEditDropCtlMargin +
  1531.                 (RECTWIDTH(&rc) - RECTWIDTH(&rcClient)) /* non-client dim */ ;
  1532.     if( RECTWIDTH(prcThis) < cxMin )
  1533.         prcThis->right = prcThis->left + cxMin;
  1534. }
  1535. //-------------------------------------------------------------------------//
  1536. //  WM_INITDLG handler; initializes the dialog
  1537. LRESULT CEditDrop::OnInitDlg( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1538. {
  1539.     RECT rcDlg, rcClient, rcOwner;
  1540.     HWND hwndEdit = GetDlgItem( IDC_EDIT );
  1541.     m_pOwner->GetWindowRect( &rcOwner );
  1542.     GetWindowRect( &rcDlg );
  1543.     
  1544.     //  Modify screen size, position
  1545.     rcDlg.left  = rcOwner.left;
  1546.     rcDlg.right = rcOwner.right; 
  1547.     EnforceMinWidth( &rcDlg );
  1548.     OffsetRect( &rcDlg, 0, rcOwner.bottom - rcDlg.top );
  1549.     
  1550.     //  adjust drop rect to fit the screen.
  1551.     m_pOwner->NormalizeDropRect( rcDlg, &m_pOwner->GetDropAnchor() );
  1552.     
  1553.     SetWindowPos( NULL, rcDlg.left, rcDlg.top, 
  1554.                   RECTWIDTH( &rcDlg ), RECTHEIGHT( &rcDlg ), 
  1555.                   SWP_NOACTIVATE|SWP_NOZORDER );
  1556.     //  Do internal layout
  1557.     GetClientRect( &rcClient );
  1558.     PositionControls( RECTWIDTH( &rcClient ), RECTHEIGHT( &rcClient ) );
  1559.     //  Assign text
  1560.     TextFromOwner();
  1561.     //  Reveal ourselves
  1562.     m_pOwner->AnimateDrop( *this );
  1563.     SetWindowPos( HWND_TOPMOST, 0,0,0,0, 
  1564.                   SWP_NOMOVE|SWP_NOSIZE );
  1565.     //  Dequeue pending character keystrokes
  1566.     if( m_msgChar.message )
  1567.         ::PostMessage( hwndEdit, m_msgChar.message, m_msgChar.wParam, m_msgChar.lParam );
  1568.     memset( &m_msgChar, 0, sizeof(m_msgChar) );
  1569.     //  Remind ourselves to set mouse capture. (USER won't let us have it right now).
  1570.     PostMessage( WMU_SETCAPTURE );
  1571.     bHandled = TRUE;
  1572.     return TRUE;
  1573. }
  1574. //-------------------------------------------------------------------------//
  1575. //  WM_SIZE handler; invokes layout management routine
  1576. LRESULT CEditDrop::OnSize( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1577. {
  1578.     PositionControls( LOWORD( lParam ), HIWORD( lParam ) );
  1579.         
  1580.     bHandled = FALSE;
  1581.     return 0L;
  1582. }
  1583. //-------------------------------------------------------------------------//
  1584. //  WM_WINDOWPOSCHANGING handler; restricts resizing to within logical
  1585. //  bounds.
  1586. LRESULT CEditDrop::OnWindowPosChanging( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1587. {
  1588.     LPWINDOWPOS pWP = (LPWINDOWPOS)lParam;
  1589.     if( (pWP->flags & SWP_NOSIZE)==0 )
  1590.     {
  1591.         RECT rcOwner;
  1592.         m_pOwner->GetWindowRect( &rcOwner );
  1593.         if( pWP->x > rcOwner.right )
  1594.         {
  1595.             RECT rcThis;
  1596.             GetWindowRect( &rcThis );
  1597.             pWP->x = rcOwner.right;
  1598.             pWP->cx= rcThis.right - pWP->x;
  1599.         }
  1600.         if( (pWP->x + pWP->cx) < rcOwner.left )
  1601.             pWP->cx = rcOwner.left - pWP->x;
  1602.     }
  1603.     bHandled = FALSE;
  1604.     return 0L;
  1605. }
  1606. //-------------------------------------------------------------------------//
  1607. //  Child window layout management routine.
  1608. void CEditDrop::PositionControls( int cx, int cy )
  1609. {
  1610.     HWND hwndEdit   = GetDlgItem( IDC_EDIT ), 
  1611.          hwndOk     = GetDlgItem( IDOK ), 
  1612.          hwndCancel = GetDlgItem( IDCANCEL );
  1613.     RECT rcEdit, rcOk, rcCancel;
  1614.     HDWP hdwp;
  1615.     if( !( hwndEdit && hwndOk && hwndCancel ) )
  1616.         return;
  1617.         
  1618.     ::GetWindowRect( hwndEdit,   &rcEdit );
  1619.     ::GetWindowRect( hwndCancel, &rcCancel );
  1620.     ::MapWindowPoints( HWND_DESKTOP, m_hWnd, (LPPOINT)&rcEdit, 2 );
  1621.     ::MapWindowPoints( HWND_DESKTOP, m_hWnd, (LPPOINT)&rcCancel, 2 );
  1622.     SetRect( &rcEdit,   nEditDropCtlMargin, nEditDropCtlMargin, cx - nEditDropCtlMargin * 2, 
  1623.                         cy - (RECTHEIGHT( &rcCancel ) + nEditDropCtlMargin * 2) );
  1624.     SetRect( &rcCancel, cx - ( RECTWIDTH( &rcCancel ) + nEditDropCtlMargin ), rcEdit.bottom + nEditDropCtlMargin,
  1625.                         cx - nEditDropCtlMargin, cy - nEditDropCtlMargin );
  1626.     SetRect( &rcOk,     rcCancel.left - ( RECTWIDTH( &rcCancel ) + nEditDropCtlMargin ), rcCancel.top,
  1627.                         rcCancel.left - nEditDropCtlMargin, cy - nEditDropCtlMargin );
  1628.     
  1629.     if( (hdwp = ::BeginDeferWindowPos( 3 )) != NULL )
  1630.     {
  1631.         //  Lazy man's macro...
  1632.         #define EDITDLG_SETCTLPOS( hwnd, rc ) ::DeferWindowPos( hdwp,(hwnd),NULL,
  1633.                 (rc).left,(rc).top, RECTWIDTH( &(rc) ), RECTHEIGHT( &(rc) ), 
  1634.                 SWP_NOZORDER|SWP_NOACTIVATE )
  1635.         EDITDLG_SETCTLPOS( hwndEdit,    rcEdit );
  1636.         EDITDLG_SETCTLPOS( hwndOk,      rcOk );
  1637.         EDITDLG_SETCTLPOS( hwndCancel,  rcCancel );
  1638.         ::EndDeferWindowPos( hdwp );
  1639.     }
  1640. }
  1641. //-------------------------------------------------------------------------//
  1642. //  WM_ACTIVATEAPP handler: Closes the dialog when host thread loses
  1643. //  activation.
  1644. LRESULT CEditDrop::OnActivateApp( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
  1645. {
  1646.     BOOL fActive = (BOOL)wParam;
  1647.     bHandled = FALSE;
  1648.     if( !fActive )
  1649.     {
  1650.         bHandled = TRUE;
  1651.         EndDialogCancel();
  1652.     }
  1653.     return 0L;
  1654. }
  1655. BOOL _ClientToNcMouseMsg( 
  1656.     HWND hwndCapture,
  1657.     LRESULT nHitTest,
  1658.     UINT nMsgIn, UINT* pnMsgOut,
  1659.     WPARAM wParamIn, WPARAM* pwParamOut,
  1660.     LPARAM lParamIn, LPARAM* plParamOut )
  1661. {
  1662.     *pnMsgOut = 0;
  1663.     switch( nMsgIn )
  1664.     {
  1665.         case WM_MOUSEMOVE:
  1666.             *pnMsgOut = WM_NCMOUSEMOVE;
  1667.             break;
  1668.         
  1669.         case WM_LBUTTONDOWN:
  1670.             *pnMsgOut = WM_NCLBUTTONDOWN;
  1671.             break;
  1672.         
  1673.         case WM_LBUTTONUP:
  1674.             *pnMsgOut = WM_NCLBUTTONUP;
  1675.             break;
  1676.         
  1677.         case WM_LBUTTONDBLCLK:
  1678.             *pnMsgOut = WM_NCLBUTTONDBLCLK;
  1679.             break;
  1680.     }
  1681.     if( *pnMsgOut )
  1682.     {
  1683.         POINTS ptsIn = MAKEPOINTS(lParamIn);
  1684.         POINT  pt;
  1685.         POINTSTOPOINT(pt, ptsIn);
  1686.         MapWindowPoints( hwndCapture, HWND_DESKTOP, &pt, 1 );
  1687.         *pwParamOut = nHitTest;
  1688.         *plParamOut = POINTTOPOINTS(pt);
  1689.         return TRUE;
  1690.     }
  1691.     return FALSE;
  1692. }
  1693. //-------------------------------------------------------------------------//
  1694. //  WM_MOUSEFIRST - WM_MOUSELAST message handler.  Note: most are all messages 
  1695. //  arise from captured mouse activity.
  1696. LRESULT CEditDrop::OnMouseMsg( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1697. {
  1698.     LRESULT lRet = 0L;
  1699.     POINT   ptScrn;
  1700.     POINTS  pts = MAKEPOINTS( lParam );
  1701.     bHandled = FALSE;
  1702.     //  Map points to screen and determine what window the message may
  1703.     //  have been destined for:
  1704.     POINTSTOPOINT( ptScrn, pts );
  1705.     ::MapWindowPoints( m_hWnd, HWND_DESKTOP, &ptScrn, 1 );
  1706.     HWND hwndTarget = WindowFromPoint( ptScrn );
  1707.     //  If it's not for us, pass it off to the target window.
  1708.     if( hwndTarget != NULL && hwndTarget != m_hWnd )
  1709.     {
  1710.         //  Determine the hittest code
  1711.         LRESULT nHitTest   = ::SendMessage( hwndTarget, WM_NCHITTEST, 0L, MAKELPARAM( ptScrn.x, ptScrn.y ) );
  1712.         //  First, on a WM_MOUSEMOVE, establish the correct cursor.
  1713.         if( nMsg == WM_MOUSEMOVE )
  1714.             ::SendMessage( hwndTarget, WM_SETCURSOR, (WPARAM)hwndTarget, MAKELPARAM( nHitTest, nMsg ) );
  1715.         //  If it's a non-client hit test, convert to a non-client message and 
  1716.         //  send down to target window.
  1717.         if( nHitTest != HTCLIENT )
  1718.         {
  1719.             //  BUGBUG: This non-client chit doesn't work.  
  1720.             //  If you have a scroll bar in a multiline edit child, the bar is unresponsive to
  1721.             //  mouse movement. We've got to figure out what the message sequence is to make 
  1722.             //  this work!
  1723.             UINT   nNcMsg;
  1724.             WPARAM wNcParam;
  1725.             LPARAM lNcParam;
  1726.             if( _ClientToNcMouseMsg( m_hWnd, nHitTest, nMsg, &nNcMsg, wParam, &wNcParam, lParam, &lNcParam ) )
  1727.             {
  1728.                 lRet = ::SendMessage( hwndTarget, nNcMsg, wNcParam, lNcParam );
  1729.                 UINT uSysCmd = (nHitTest == HTVSCROLL) ? SC_VSCROLL :
  1730.                                (nHitTest == HTHSCROLL) ? SC_HSCROLL : 0;
  1731.                 if( uSysCmd )
  1732.                     ::SendMessage( hwndTarget, WM_SYSCOMMAND, uSysCmd, lNcParam );
  1733.                 bHandled = TRUE;
  1734.             }
  1735.         }
  1736.         
  1737.         //  If the user clicked outside us, close the dialog.
  1738.         if( !IsChild( hwndTarget ) )
  1739.         {
  1740.             switch( nMsg )
  1741.             {
  1742.                 case WM_LBUTTONDOWN:
  1743.                 case WM_RBUTTONDOWN:
  1744.                 case WM_MBUTTONDOWN:
  1745.                     EndDialogCancel();
  1746.                     bHandled = TRUE;
  1747.             }
  1748.         }
  1749.         //  If we didn't send a non-client message, deal with it as a client message:
  1750.         if( !bHandled )
  1751.         {
  1752.             POINT pt = ptScrn;
  1753.             ::MapWindowPoints( HWND_DESKTOP, hwndTarget, &pt, 1 );
  1754.             lRet = ::SendMessage( hwndTarget, nMsg, wParam, MAKELPARAM( pt.x, pt.y ) );
  1755.             bHandled = TRUE;
  1756.         }
  1757.     }
  1758.     return lRet;
  1759. }
  1760. //-------------------------------------------------------------------------//
  1761. //  WMU_SETCURSOR private message handler.  This self-posted message
  1762. //  instructs the dialog to capture mouse activity.  
  1763. LRESULT CEditDrop::OnSetCapture( UINT, WPARAM, LPARAM, BOOL& bHandled )
  1764. {
  1765.     SetCapture(); 
  1766.     bHandled = TRUE; 
  1767.     return 0L;
  1768. }
  1769. //-------------------------------------------------------------------------//
  1770. //  WM_CAPTURECHANGED handler.  If the capture is lost to a child window,
  1771. //  we'll light up our capture tracker to retain knowledge of mouse activity.
  1772. LRESULT CEditDrop::OnCaptureChanged( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1773. {
  1774.     HWND hwndOther = (HWND)lParam;
  1775.     if( hwndOther && IsChild( hwndOther ) )
  1776.     {
  1777.         //TRACE(TEXT("Tracking capture lost to child control %08lXn"), hwndOther);
  1778.         m_captureTrack.Track( hwndOther, m_hWnd );
  1779.     }
  1780.     bHandled = FALSE;
  1781.     return 0L;
  1782. }
  1783. //-------------------------------------------------------------------------//
  1784. //  CCaptureTracker::NotifyMsg() handler.  Handles mouse activity messages
  1785. //  sent by our capture tracker.
  1786. LRESULT CEditDrop::OnCaptureMsg( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1787. {
  1788.     switch( wParam )
  1789.     {
  1790.         case CCaptureTracker::ForeignClick:
  1791.         case CCaptureTracker::Lost:
  1792.             EndDialogCancel();
  1793.             break;
  1794.         case CCaptureTracker::Released:
  1795.             PostMessage( WMU_SETCAPTURE );
  1796.             break;
  1797.     }
  1798.     
  1799.     bHandled = TRUE;
  1800.     return 0L;
  1801. }
  1802. //-------------------------------------------------------------------------//
  1803. void CEditDrop::CommonEndDialog( int nResult )
  1804. {
  1805.     m_fEndDlg = TRUE ;
  1806.     ReleaseCapture();
  1807.     EndDialog( nResult );
  1808. }
  1809.         
  1810. //-------------------------------------------------------------------------//
  1811. //  WM_DESTROY handler.
  1812. LRESULT CEditDrop::OnDestroy( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1813. {
  1814.     if( GetCapture()== m_hWnd )
  1815.         ReleaseCapture();
  1816.     
  1817.     bHandled = FALSE;
  1818.     return 0L;
  1819. }
  1820. //-------------------------------------------------------------------------//
  1821. //  WM_NCHITTEST handler; prevents resizing when mouse is tracking locked border.
  1822. LRESULT CEditDrop::OnNcHitTest( UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
  1823. {
  1824.     LRESULT lRet = DefWindowProc( m_hWnd, nMsg, wParam, lParam );
  1825.     UINT    nDropAnchor = m_pOwner->GetDropAnchor();
  1826.     if( nDropAnchor == DROPANCHOR_TOP )
  1827.     {
  1828.         switch( lRet ) {
  1829.             case HTTOPLEFT: case HTTOP: case HTTOPRIGHT:
  1830.                 lRet = HTNOWHERE;    
  1831.         }
  1832.     }
  1833.     else if( nDropAnchor == DROPANCHOR_BOTTOM )
  1834.     {
  1835.         switch( lRet ) {
  1836.             case HTBOTTOMLEFT: case HTBOTTOM: case HTBOTTOMRIGHT:
  1837.                 lRet = HTNOWHERE;    
  1838.         }
  1839.     }
  1840.     bHandled = TRUE;
  1841.     return lRet;
  1842. }
  1843. //-------------------------------------------------------------------------//
  1844. //  Transfers text from the owner CInPlaceDropWindow object to child edit control.
  1845. void CEditDrop::TextFromOwner()
  1846. {
  1847.     LPTSTR  pszBuf = NULL;
  1848.     int     cchBuf = m_pOwner->GetWindowTextLength();
  1849.     if( m_pszUndo )
  1850.     {
  1851.         delete [] m_pszUndo;
  1852.         m_pszUndo = NULL;
  1853.     }
  1854.     if( cchBuf > 0 &&
  1855.         (pszBuf = new TCHAR[cchBuf+1]) )
  1856.     {
  1857.         m_pOwner->GetWindowText( pszBuf, cchBuf + 1 );
  1858.         SetDlgItemText( IDC_EDIT, pszBuf );
  1859.         m_pszUndo = pszBuf;
  1860.     }
  1861.     
  1862. }
  1863. //-------------------------------------------------------------------------//
  1864. //  Transfers text from the child edit control to the owner CInPlaceDropWindow
  1865. //  object.  Returns TRUE if a change was detected, otherwise FALSE.
  1866. BOOL CEditDrop::TextToOwner()
  1867. {
  1868.     HWND    hwndEdit = GetDlgItem( IDC_EDIT );
  1869.     LPTSTR  pszEdit  = NULL;
  1870.     int     cchEdit  = hwndEdit ? ::GetWindowTextLength( hwndEdit ) : 0L;
  1871.     BOOL    bRet     = TRUE;
  1872.     if( cchEdit > 0 && (pszEdit = new TCHAR[cchEdit+1]) )
  1873.         GetDlgItemText( IDC_EDIT, pszEdit, cchEdit + 1 );
  1874.     if( m_pszUndo && pszEdit )
  1875.     {
  1876.         if( lstrcmp( m_pszUndo, pszEdit )==0 )
  1877.             bRet = FALSE;
  1878.     }
  1879.     else if( m_pszUndo == pszEdit /*NULL*/)
  1880.         bRet = FALSE;
  1881.     if( bRet )
  1882.     {
  1883.         m_pOwner->SetWindowText( pszEdit );
  1884.         if( m_pszUndo )
  1885.         {
  1886.             delete [] m_pszUndo;
  1887.             m_pszUndo = NULL;
  1888.         }
  1889.         if( pszEdit && *pszEdit )
  1890.         {
  1891.             m_pszUndo = pszEdit;
  1892.             pszEdit = NULL;
  1893.         }
  1894.     }
  1895.     if( pszEdit ) delete [] pszEdit;
  1896.     return bRet;
  1897. }
  1898. //-------------------------------------------------------------------------//
  1899. //  WM_COMMAND:EN_CHANGE handler.
  1900. LRESULT CEditDrop::OnEditChange( WORD, WORD, HWND hwndEdit, BOOL& bHandled )
  1901. {
  1902.     if( !m_fEndDlg ) // avoid processing any edit changes when we're on our way down.
  1903.     {
  1904.         LPTSTR  pszBuf = NULL;
  1905.         int     cch       = ::GetWindowTextLength( hwndEdit );
  1906.         if( (pszBuf = new TCHAR[cch+1])!=NULL )
  1907.         {
  1908.             *pszBuf = 0;
  1909.             if( cch )
  1910.                 ::GetWindowText( hwndEdit, pszBuf, cch+1 );
  1911.             m_pOwner->SetWindowText( pszBuf );
  1912.             delete [] pszBuf;
  1913.         }
  1914.     }
  1915.     return 0L;
  1916. }
  1917. //-------------------------------------------------------------------------//
  1918. //  WM_COMMAND:IDCANCEL handler.
  1919. LRESULT CEditDrop::OnCancel( WORD, WORD, HWND, BOOL& bHandled )
  1920. {
  1921.     bHandled = TRUE;
  1922.     EndDialogCancel();
  1923.     return 0L;
  1924. }
  1925. //-------------------------------------------------------------------------//
  1926. //  WM_COMMAND:IDOK handler.
  1927. LRESULT CEditDrop::OnOk( WORD, WORD, HWND, BOOL& bHandled )
  1928. {
  1929.     bHandled = TRUE;
  1930.     EndDialogOK();
  1931.     return 0L;
  1932. }