Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4495 lines
132 KiB

  1. //---------------------------------------------------------------------------
  2. #include "stdafx.h"
  3. #include "scroll.h"
  4. #if defined(_UXTHEME_)
  5. // non-client scrollbar
  6. #include "nctheme.h"
  7. #include "scrollp.h"
  8. #else
  9. // scrollbar control
  10. #include "usrctl32.h"
  11. #endif _UXTHEME_
  12. // comment this out to visually match user32 scrollbar:
  13. //#define _VISUAL_DELTA_
  14. #ifdef _VISUAL_DELTA_
  15. #define CARET_BORDERWIDTH 2
  16. #endif _VISUAL_DELTA_
  17. //-------------------------------------------------------------------------//
  18. #define FNID_SCROLLBAR 0x0000029A // UxScrollBarWndProc;
  19. #define GetOwner(hwnd) GetWindow(hwnd, GW_OWNER)
  20. #define HW(x) x
  21. #define HWq(x) x
  22. #define RIPERR0(s1,s2,errno)
  23. #define RIPMSG1(errno,fmt,arg1)
  24. #define RIPMSG2(errno,fmt,arg1,arg2)
  25. #define RIPMSG3(errno,fmt,arg1,arg2,arg3)
  26. #define RIP_VERBOSE()
  27. #define ClrWF ClearWindowState
  28. #define SetWF SetWindowState
  29. #define Lock(phwnd, hwnd) InterlockedExchangePointer((PVOID*)(phwnd), (PVOID)hwnd)
  30. #define Unlock(phwnd) Lock(phwnd, NULL)
  31. #define CheckLock(hwnd)
  32. #define ThreadLock(w,t)
  33. #define ThreadUnlock(t)
  34. #define VALIDATECLASSANDSIZE
  35. #define DTTIME (MulDiv( GetDoubleClickTime(), 4, 5 ))
  36. #define _KillSystemTimer KillTimer
  37. #define _SetSystemTimer SetTimer
  38. #define IsWinEventNotifyDeferredOK() TRUE
  39. #define IsWinEventNotifyDeferred() FALSE
  40. //-------------------------------------------------------------------------//
  41. // scroll type flags userk.h
  42. #define SCROLL_NORMAL 0
  43. #define SCROLL_DIRECT 1
  44. #define SCROLL_MENU 2
  45. //-------------------------------------------------------------------------//
  46. // internal Scrollbar state/style bits
  47. //#define SBFSIZEBOXTOPLEFT 0x0C02
  48. //#define SBFSIZEBOXBOTTOMRIGHT 0x0C04
  49. //#define SBFSIZEBOX 0x0C08
  50. #define SBFSIZEGRIP 0x0C10
  51. //----------------------------------//
  52. // Scrollbar arrow disable flags
  53. #define LTUPFLAG 0x0001 // Left/Up arrow disable flag.
  54. #define RTDNFLAG 0x0002 // Right/Down arrow disable flag.
  55. //----------------------------------//
  56. // function forwards
  57. UINT _SysToChar(UINT message, LPARAM lParam);
  58. //-------------------------------------------------------------------------//
  59. // private hittest codes
  60. //#define HTEXSCROLLFIRST 60
  61. #define HTSCROLLUP 60
  62. #define HTSCROLLDOWN 61
  63. #define HTSCROLLUPPAGE 62
  64. #define HTSCROLLDOWNPAGE 63
  65. #define HTSCROLLTHUMB 64
  66. //#define HTEXSCROLLLAST 64
  67. //#define HTEXMENUFIRST 65
  68. //#define HTMDISYSMENU 65
  69. //#define HTMDIMAXBUTTON 66
  70. //#define HTMDIMINBUTTON 67
  71. //#define HTMDICLOSE 68
  72. //#define HTMENUITEM 69
  73. //#define HTEXMENULAST 69
  74. #define IDSYS_SCROLL 0x0000FFFEL // timer ID, user.h
  75. typedef HWND SBHWND;
  76. typedef HMENU PMENU;
  77. //-------------------------------------------------------------------------//
  78. // SBDATA
  79. typedef struct tagSBDATA
  80. {
  81. int posMin;
  82. int posMax;
  83. int page;
  84. int pos;
  85. } SBDATA, *PSBDATA;
  86. //-------------------------------------------------------------------------//
  87. // SBINFO is the set of values that hang off of a window structure,
  88. // if the window has scrollbars.
  89. typedef struct tagSBINFO
  90. {
  91. int WSBflags;
  92. SBDATA Horz;
  93. SBDATA Vert;
  94. } SBINFO, * PSBINFO;
  95. //-------------------------------------------------------------------------//
  96. // SBCALC
  97. // Scrollbar metrics block.
  98. typedef struct tagSBCALC
  99. {
  100. SBDATA data; /* this must be first -- we cast structure pointers */
  101. int pxTop;
  102. int pxBottom;
  103. int pxLeft;
  104. int pxRight;
  105. int cpxThumb;
  106. int pxUpArrow;
  107. int pxDownArrow;
  108. int pxStart; /* Initial position of thumb */
  109. int pxThumbBottom;
  110. int pxThumbTop;
  111. int cpx;
  112. int pxMin;
  113. } SBCALC, *PSBCALC;
  114. //-------------------------------------------------------------------------//
  115. // SBTRACK
  116. // Scrollbar thumb-tracking state block.
  117. typedef struct tagSBTRACK {
  118. DWORD fHitOld : 1;
  119. DWORD fTrackVert : 1;
  120. DWORD fCtlSB : 1;
  121. DWORD fTrackRecalc: 1;
  122. HWND hwndTrack;
  123. HWND hwndSB;
  124. HWND hwndSBNotify;
  125. RECT rcTrack;
  126. VOID (CALLBACK *pfnSB)(HWND, UINT, WPARAM, LPARAM, PSBCALC);
  127. UINT cmdSB;
  128. UINT_PTR hTimerSB;
  129. int dpxThumb; /* Offset from mouse point to start of thumb box */
  130. int pxOld; /* Previous position of thumb */
  131. int posOld;
  132. int posNew;
  133. int nBar;
  134. PSBCALC pSBCalc;
  135. } SBTRACK, *PSBTRACK;
  136. //-------------------------------------------------------------------------//
  137. // Window scrollbars, control base.
  138. class CUxScrollBar
  139. //-------------------------------------------------------------------------//
  140. {
  141. public:
  142. CUxScrollBar();
  143. virtual ~CUxScrollBar() {}
  144. virtual BOOL IsCtl() const { return FALSE;}
  145. operator HWND() { return _hwnd; }
  146. static CUxScrollBar* Calc( HWND hwnd, PSBCALC pSBCalc, LPRECT prcOverrideClient, BOOL fVert);
  147. virtual void Calc2( PSBCALC pSBCalc, LPRECT lprc, CONST PSBDATA pw, BOOL fVert);
  148. virtual void DoScroll( HWND hwndNotify, int cmd, int pos, BOOL fVert );
  149. virtual void ClearTrack() { ZeroMemory( &_track, sizeof(_track) ); }
  150. SBTRACK* GetTrack() { return &_track; }
  151. SBINFO* GetInfo() { return &_info; }
  152. HTHEME GetTheme() { return _hTheme; }
  153. BOOL IsAttaching() { return _fAttaching; }
  154. INT GetHotComponent(BOOL fVert) { return fVert ? _htVert : _htHorz; }
  155. VOID SetHotComponent(INT ht, BOOL fVert) { (fVert ? _htVert : _htHorz) = ht; }
  156. virtual void ChangeSBTheme();
  157. virtual BOOL FreshenSBData( int nBar, BOOL fRedraw );
  158. // UxScrollBar API.
  159. static CUxScrollBar* Attach( HWND hwnd, BOOL bCtl, BOOL fRedraw );
  160. static CUxScrollBar* FromHwnd( HWND hwnd );
  161. static void Detach( HWND hwnd );
  162. static SBTRACK* GetSBTrack( HWND hwnd );
  163. static void ClearSBTrack( HWND hwnd );
  164. static SBINFO* GetSBInfo( HWND hwnd );
  165. static HTHEME GetSBTheme( HWND hwnd );
  166. static INT GetSBHotComponent( HWND hwnd, BOOL fVert);
  167. protected:
  168. HWND _hwnd;
  169. SBTRACK _track;
  170. SBINFO _info;
  171. INT _htVert; // Scroll bar part the mouse is currently over
  172. INT _htHorz; // Scroll bar part the mouse is currently over
  173. HTHEME _hTheme;// Handle to theme manager
  174. BOOL _fAttaching;
  175. };
  176. //-------------------------------------------------------------------------//
  177. // Scrollbar control
  178. class CUxScrollBarCtl : public CUxScrollBar
  179. //-------------------------------------------------------------------------//
  180. {
  181. public:
  182. CUxScrollBarCtl();
  183. virtual BOOL IsCtl() const { return TRUE;}
  184. BOOL AddRemoveDisableFlags( UINT wAdd, UINT wRemove );
  185. // UxScrollBarCtl API.
  186. static CUxScrollBarCtl* FromHwnd( HWND hwnd );
  187. static UINT GetDisableFlags( HWND hwnd );
  188. static SBCALC* GetCalc( HWND hwnd );
  189. static BOOL AddRemoveDisableFlags( HWND, UINT, UINT );
  190. static LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
  191. BOOL _fVert;
  192. UINT _wDisableFlags; // Indicates which arrow is disabled;
  193. SBCALC _calc;
  194. };
  195. //-------------------------------------------------------------------------//
  196. // IsScrollBarControl
  197. #ifdef PORTPORT
  198. #define IsScrollBarControl(h) (GETFNID(h) == FNID_SCROLLBAR)
  199. #else //PORTPORT
  200. inline BOOL IsScrollBarControl(HWND hwnd) {
  201. return CUxScrollBarCtl::FromHwnd( hwnd ) != NULL;
  202. }
  203. #endif //PORTPORT
  204. //-------------------------------------------------------------------------//
  205. // Forwards:
  206. void DrawScrollBar( HWND hwnd, HDC hdc, LPRECT prcOverrideClient, BOOL fVert);
  207. HWND SizeBoxHwnd( HWND hwnd );
  208. VOID _DrawPushButton( HWND hwnd, HDC hdc, LPRECT lprc, UINT state, UINT flags, BOOL fVert);
  209. UINT _GetWndSBDisableFlags(HWND, BOOL);
  210. void CALLBACK _TrackThumb( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc);
  211. void CALLBACK _TrackBox( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc);
  212. void _RedrawFrame( HWND hwnd );
  213. BOOL _FChildVisible( HWND hwnd );
  214. LONG _SetScrollBar( HWND hwnd, int code, LPSCROLLINFO lpsi, BOOL fRedraw);
  215. HBRUSH _UxGrayBrush(VOID);
  216. void _UxFreeGDIResources();
  217. //-------------------------------------------------------------------------//
  218. BOOL WINAPI InitScrollBarClass( HINSTANCE hInst )
  219. {
  220. WNDCLASSEX wc;
  221. ZeroMemory( &wc, sizeof(wc) );
  222. wc.cbSize = sizeof(wc);
  223. wc.style = CS_GLOBALCLASS|CS_PARENTDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
  224. wc.lpfnWndProc = CUxScrollBarCtl::WndProc;
  225. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  226. wc.hInstance = hInst;
  227. wc.lpszClassName = WC_SCROLLBAR;
  228. wc.cbWndExtra = max(sizeof(CUxScrollBar), sizeof(CUxScrollBarCtl));
  229. return RegisterClassEx( &wc ) != 0;
  230. }
  231. //-------------------------------------------------------------------------//
  232. // CUxScrollBar impl
  233. //-------------------------------------------------------------------------//
  234. //-------------------------------------------------------------------------//
  235. CUxScrollBar::CUxScrollBar()
  236. : _hwnd(NULL),
  237. _hTheme(NULL),
  238. _htVert(HTNOWHERE),
  239. _htHorz(HTNOWHERE),
  240. _fAttaching(FALSE)
  241. {
  242. ClearTrack();
  243. ZeroMemory( &_info, sizeof(_info) );
  244. _info.Vert.posMax = 100; // ported from _InitPwSB
  245. _info.Horz.posMax = 100; // ported from _InitPwSB
  246. }
  247. //-------------------------------------------------------------------------//
  248. CUxScrollBar* CUxScrollBar::Attach( HWND hwnd, BOOL bCtl, BOOL fRedraw )
  249. {
  250. CUxScrollBar* psb = FromHwnd( hwnd );
  251. if( NULL == psb )
  252. {
  253. psb = bCtl ? new CUxScrollBarCtl : new CUxScrollBar;
  254. if( psb != NULL )
  255. {
  256. ASSERT( psb->IsCtl() == bCtl );
  257. if( (! hwnd) || (! SetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_SCROLLBAR)), (HANDLE)psb ) ))
  258. {
  259. delete psb;
  260. psb = NULL;
  261. }
  262. else
  263. {
  264. psb->_hwnd = hwnd;
  265. psb->_fAttaching = TRUE;
  266. if (psb->IsCtl())
  267. {
  268. psb->_hTheme = OpenThemeData(hwnd, L"ScrollBar");
  269. }
  270. else
  271. {
  272. psb->_hTheme = OpenNcThemeData(hwnd, L"ScrollBar");
  273. //
  274. // window SBs must grovel for state data each
  275. // time attached [scotthan]
  276. //
  277. SCROLLINFO si;
  278. ZeroMemory(&si, sizeof(si));
  279. si.cbSize = sizeof(si);
  280. si.fMask = SIF_ALL;
  281. if (GetScrollInfo(hwnd, SB_VERT, &si))
  282. {
  283. si.fMask |= SIF_DISABLENOSCROLL;
  284. _SetScrollBar(hwnd, SB_VERT, &si, FALSE);
  285. }
  286. ZeroMemory(&si, sizeof(si));
  287. si.cbSize = sizeof(si);
  288. si.fMask = SIF_ALL;
  289. if (GetScrollInfo(hwnd, SB_HORZ, &si))
  290. {
  291. si.fMask |= SIF_DISABLENOSCROLL;
  292. _SetScrollBar(hwnd, SB_HORZ, &si, FALSE);
  293. }
  294. }
  295. psb->_fAttaching = FALSE;
  296. }
  297. }
  298. }
  299. return psb;
  300. }
  301. //-------------------------------------------------------------------------//
  302. CUxScrollBar* CUxScrollBar::FromHwnd( HWND hwnd )
  303. {
  304. if (! hwnd)
  305. return NULL;
  306. return (CUxScrollBar*)GetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_SCROLLBAR)));
  307. }
  308. //-------------------------------------------------------------------------//
  309. void CUxScrollBar::Detach( HWND hwnd )
  310. {
  311. CUxScrollBar* psb = FromHwnd( hwnd );
  312. if ( psb == NULL || !psb->_fAttaching )
  313. {
  314. if (hwnd)
  315. {
  316. RemoveProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_SCROLLBAR)));
  317. }
  318. if( psb != NULL )
  319. {
  320. if ( psb->_hTheme )
  321. {
  322. CloseThemeData(psb->_hTheme);
  323. }
  324. delete psb;
  325. }
  326. }
  327. }
  328. //-------------------------------------------------------------------------//
  329. void WINAPI AttachScrollBars( HWND hwnd )
  330. {
  331. ASSERT( GetWindowLong( hwnd, GWL_STYLE ) & (WS_HSCROLL|WS_VSCROLL) );
  332. CUxScrollBar::Attach( hwnd, FALSE, FALSE );
  333. }
  334. //-------------------------------------------------------------------------//
  335. void WINAPI DetachScrollBars( HWND hwnd )
  336. {
  337. CUxScrollBar::Detach( hwnd );
  338. }
  339. //-------------------------------------------------------------------------//
  340. SBTRACK* CUxScrollBar::GetSBTrack( HWND hwnd )
  341. {
  342. CUxScrollBar* psb = FromHwnd( hwnd );
  343. if( psb )
  344. return &psb->_track;
  345. return NULL;
  346. }
  347. //-------------------------------------------------------------------------//
  348. void CUxScrollBar::ClearSBTrack( HWND hwnd )
  349. {
  350. CUxScrollBar* psb = FromHwnd( hwnd );
  351. if( psb )
  352. psb->ClearTrack();
  353. }
  354. //-------------------------------------------------------------------------//
  355. SBINFO* CUxScrollBar::GetSBInfo( HWND hwnd )
  356. {
  357. CUxScrollBar* psb = FromHwnd( hwnd );
  358. if( psb )
  359. return &psb->_info;
  360. return NULL;
  361. }
  362. //-------------------------------------------------------------------------//
  363. HTHEME CUxScrollBar::GetSBTheme( HWND hwnd )
  364. {
  365. CUxScrollBar* psb = FromHwnd( hwnd );
  366. if( psb )
  367. return psb->_hTheme;
  368. return NULL;
  369. }
  370. //-------------------------------------------------------------------------//
  371. INT CUxScrollBar::GetSBHotComponent( HWND hwnd, BOOL fVert )
  372. {
  373. CUxScrollBar* psb = FromHwnd( hwnd );
  374. if( psb )
  375. return psb->GetHotComponent(fVert);
  376. return 0;
  377. }
  378. //-------------------------------------------------------------------------//
  379. BOOL CUxScrollBar::FreshenSBData( int nBar, BOOL fRedraw )
  380. {
  381. #ifdef __POLL_FOR_SCROLLINFO__
  382. ASSERT(IsWindow(_hwnd));
  383. if( !IsCtl() )
  384. {
  385. // Note scrollbar ctls don't go stale because
  386. // they receive SBM notifications
  387. SCROLLINFO si;
  388. si.cbSize = sizeof(si);
  389. si.fMask = SIF_ALL;
  390. switch(nBar)
  391. {
  392. case SB_VERT:
  393. case SB_HORZ:
  394. if( GetScrollInfo( _hwnd, nBar, &si ) )
  395. {
  396. _SetScrollBar( _hwnd, nBar, &si, fRedraw );
  397. }
  398. break;
  399. case SB_BOTH:
  400. return FreshenSBData( SB_VERT, fRedraw ) &&
  401. FreshenSBData( SB_HORZ, fRedraw );
  402. break;
  403. default: return FALSE;
  404. }
  405. }
  406. #endif __POLL_FOR_SCROLLINFO__
  407. return TRUE;
  408. }
  409. //-------------------------------------------------------------------------//
  410. void CUxScrollBar::ChangeSBTheme()
  411. {
  412. if ( _hTheme )
  413. {
  414. CloseThemeData(_hTheme);
  415. }
  416. _hTheme = NULL;
  417. if (IsCtl())
  418. _hTheme = OpenThemeData(_hwnd, L"ScrollBar");
  419. else
  420. _hTheme = OpenNcThemeData(_hwnd, L"ScrollBar");
  421. }
  422. //-------------------------------------------------------------------------//
  423. // CUxScrollBarCtl impl
  424. //-------------------------------------------------------------------------//
  425. //-------------------------------------------------------------------------//
  426. CUxScrollBarCtl::CUxScrollBarCtl()
  427. : _wDisableFlags(0), _fVert(FALSE)
  428. {
  429. ZeroMemory( &_calc, sizeof(_calc) );
  430. }
  431. //-------------------------------------------------------------------------//
  432. CUxScrollBarCtl* CUxScrollBarCtl::FromHwnd( HWND hwnd )
  433. {
  434. CUxScrollBarCtl* psb = (CUxScrollBarCtl*)CUxScrollBar::FromHwnd( hwnd );
  435. if( psb )
  436. return psb->IsCtl() ? psb : NULL;
  437. return NULL;
  438. }
  439. //-------------------------------------------------------------------------//
  440. UINT CUxScrollBarCtl::GetDisableFlags( HWND hwnd )
  441. {
  442. CUxScrollBarCtl* psb = FromHwnd( hwnd );
  443. if( psb )
  444. return psb->_wDisableFlags;
  445. return 0;
  446. }
  447. //-------------------------------------------------------------------------//
  448. SBCALC* CUxScrollBarCtl::GetCalc( HWND hwnd )
  449. {
  450. CUxScrollBarCtl* psb = FromHwnd( hwnd );
  451. if( psb )
  452. return &psb->_calc;
  453. return NULL;
  454. }
  455. //-------------------------------------------------------------------------//
  456. // CUxScrollBarCtl::AddRemoveDisableFlags() - static
  457. BOOL CUxScrollBarCtl::AddRemoveDisableFlags( HWND hwnd, UINT wAdd, UINT wRemove )
  458. {
  459. CUxScrollBarCtl* psb = FromHwnd( hwnd );
  460. if( psb )
  461. return psb->AddRemoveDisableFlags( wAdd, wRemove );
  462. return FALSE;
  463. }
  464. //-------------------------------------------------------------------------//
  465. // CUxScrollBarCtl::AddRemoveDisableFlags() - instance member
  466. BOOL CUxScrollBarCtl::AddRemoveDisableFlags( UINT wAdd, UINT wRemove )
  467. {
  468. // returns TRUE if flags changed, otherwise FALSE.
  469. UINT wOld = _wDisableFlags;
  470. _wDisableFlags |= wAdd;
  471. _wDisableFlags &= ~wRemove;
  472. return _wDisableFlags != wOld;
  473. }
  474. //-------------------------------------------------------------------------//
  475. // CUxScrollBar::Calc(). computes metrics for window SBs only.
  476. // derives rect and calls Calc2.
  477. CUxScrollBar* CUxScrollBar::Calc(
  478. HWND hwnd,
  479. PSBCALC pSBCalc,
  480. LPRECT prcOverrideClient,
  481. BOOL fVert)
  482. {
  483. RECT rcT;
  484. #ifdef USE_MIRRORING
  485. int cx, iTemp;
  486. #endif
  487. //
  488. // Get client rectangle in window-relative coords.
  489. // We know that window scrollbars always align to the right
  490. // and to the bottom of the client area.
  491. //
  492. WINDOWINFO wi;
  493. wi.cbSize = sizeof(wi);
  494. if( !GetWindowInfo( hwnd, &wi ) )
  495. return NULL;
  496. OffsetRect( &wi.rcClient, -wi.rcWindow.left, -wi.rcWindow.top );
  497. #ifdef USE_MIRRORING
  498. if (TestWF(hwnd, WEFLAYOUTRTL)) {
  499. cx = wi.rcWindow.right - wi.rcWindow.left;
  500. iTemp = wi.rcClient.left;
  501. wi.rcClient.left = cx - wi.rcClient.right;
  502. wi.rcClient.right = cx - iTemp;
  503. }
  504. #endif
  505. if (fVert) {
  506. // Only add on space if vertical scrollbar is really there.
  507. if (TestWF(hwnd, WEFLEFTSCROLL)) {
  508. rcT.right = rcT.left = wi.rcClient.left;
  509. if (TestWF(hwnd, WFVPRESENT))
  510. rcT.left -= SYSMET(CXVSCROLL);
  511. } else {
  512. rcT.right = rcT.left = wi.rcClient.right;
  513. if (TestWF(hwnd, WFVPRESENT))
  514. rcT.right += SYSMET(CXVSCROLL);
  515. }
  516. rcT.top = wi.rcClient.top;
  517. rcT.bottom = wi.rcClient.bottom;
  518. } else {
  519. // Only add on space if horizontal scrollbar is really there.
  520. rcT.bottom = rcT.top = wi.rcClient.bottom;
  521. if (TestWF(hwnd, WFHPRESENT))
  522. rcT.bottom += SYSMET(CYHSCROLL);
  523. rcT.left = wi.rcClient.left;
  524. rcT.right = wi.rcClient.right;
  525. }
  526. if (prcOverrideClient)
  527. {
  528. rcT = *prcOverrideClient;
  529. }
  530. // If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
  531. // we can do here, so just let it go through. We won't fault but the scrollbar won't work
  532. // properly either...
  533. CUxScrollBar* psb = CUxScrollBar::Attach( hwnd, FALSE, FALSE );
  534. if( psb )
  535. {
  536. SBDATA* pData = fVert ? &psb->_info.Vert : &psb->_info.Horz;
  537. if( psb )
  538. psb->Calc2( pSBCalc, &rcT, pData, fVert );
  539. return psb;
  540. }
  541. return NULL;
  542. }
  543. //-------------------------------------------------------------------------//
  544. // CUxScrollBar::Calc2(). computes metrics for window SBs or SB ctls.
  545. void CUxScrollBar::Calc2( PSBCALC pSBCalc, LPRECT lprc, CONST PSBDATA pw, BOOL fVert)
  546. {
  547. int cpx;
  548. DWORD dwRange;
  549. int denom;
  550. if (fVert) {
  551. pSBCalc->pxTop = lprc->top;
  552. pSBCalc->pxBottom = lprc->bottom;
  553. pSBCalc->pxLeft = lprc->left;
  554. pSBCalc->pxRight = lprc->right;
  555. pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
  556. } else {
  557. /*
  558. * For horiz scroll bars, "left" & "right" are "top" and "bottom",
  559. * and vice versa.
  560. */
  561. pSBCalc->pxTop = lprc->left;
  562. pSBCalc->pxBottom = lprc->right;
  563. pSBCalc->pxLeft = lprc->top;
  564. pSBCalc->pxRight = lprc->bottom;
  565. pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
  566. }
  567. pSBCalc->data.pos = pw->pos;
  568. pSBCalc->data.page = pw->page;
  569. pSBCalc->data.posMin = pw->posMin;
  570. pSBCalc->data.posMax = pw->posMax;
  571. dwRange = ((DWORD)(pSBCalc->data.posMax - pSBCalc->data.posMin)) + 1;
  572. //
  573. // For the case of short scroll bars that don't have enough
  574. // room to fit the full-sized up and down arrows, shorten
  575. // their sizes to make 'em fit
  576. //
  577. cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
  578. pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx;
  579. pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
  580. if ((pw->page != 0) && (dwRange != 0)) {
  581. // JEFFBOG -- This is the one and only place where we should
  582. // see 'range'. Elsewhere it should be 'range - page'.
  583. /*
  584. * The minimun thumb size used to depend on the frame/edge metrics.
  585. * People that increase the scrollbar width/height expect the minimun
  586. * to grow with proportianally. So NT5 bases the minimun on
  587. * CXH/YVSCROLL, which is set by default in cpxThumb.
  588. */
  589. /*
  590. * i is used to keep the macro "max" from executing MulDiv twice.
  591. */
  592. int i = MulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
  593. pw->page, dwRange);
  594. pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
  595. }
  596. pSBCalc->pxMin = pSBCalc->pxTop + cpx;
  597. pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
  598. denom = dwRange - (pw->page ? pw->page : 1);
  599. if (denom)
  600. pSBCalc->pxThumbTop = MulDiv(pw->pos - pw->posMin,
  601. pSBCalc->cpx, denom) +
  602. pSBCalc->pxMin;
  603. else
  604. pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
  605. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  606. }
  607. //-------------------------------------------------------------------------//
  608. void CUxScrollBar::DoScroll( HWND hwndNotify, int cmd, int pos, BOOL fVert )
  609. {
  610. HWND hwnd = _hwnd;
  611. //
  612. // Send scroll notification to the scrollbar owner. If this is a control
  613. // the lParam is the control's handle, NULL otherwise.
  614. //
  615. SendMessage(hwndNotify,
  616. (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
  617. MAKELONG(cmd, pos),
  618. (LPARAM)(IsCtl() ? _hwnd : NULL));
  619. //
  620. // The hwnd can have it's scrollbar removed as the result
  621. // of the previous sendmessge.
  622. //
  623. if( CUxScrollBar::GetSBTrack(hwnd) && !IsCtl() )
  624. {
  625. FreshenSBData( fVert ? SB_VERT : SB_HORZ, TRUE );
  626. }
  627. }
  628. /*
  629. * Now it is possible to selectively Enable/Disable just one arrow of a Window
  630. * scroll bar; Various bits in the 7th word in the rgwScroll array indicates which
  631. * one of these arrows are disabled; The following masks indicate which bit of the
  632. * word indicates which arrow;
  633. */
  634. #define WSB_HORZ_LF 0x0001 // Represents the Left arrow of the horizontal scroll bar.
  635. #define WSB_HORZ_RT 0x0002 // Represents the Right arrow of the horizontal scroll bar.
  636. #define WSB_VERT_UP 0x0004 // Represents the Up arrow of the vert scroll bar.
  637. #define WSB_VERT_DN 0x0008 // Represents the Down arrow of the vert scroll bar.
  638. #define WSB_VERT (WSB_VERT_UP | WSB_VERT_DN)
  639. #define WSB_HORZ (WSB_HORZ_LF | WSB_HORZ_RT)
  640. void DrawCtlThumb( SBHWND );
  641. /*
  642. * RETURN_IF_PSBTRACK_INVALID:
  643. * This macro tests whether the pSBTrack we have is invalid, which can happen
  644. * if it gets freed during a callback.
  645. * This protects agains the original pSBTrack being freed and no new one
  646. * being allocated or a new one being allocated at a different address.
  647. * This does not protect against the original pSBTrack being freed and a new
  648. * one being allocated at the same address.
  649. * If pSBTrack has changed, we assert that there is not already a new one
  650. * because we are really not expecting this.
  651. */
  652. #define RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd) \
  653. if ((pSBTrack) != CUxScrollBar::GetSBTrack(hwnd)) { \
  654. ASSERT(CUxScrollBar::GetSBTrack(hwnd) == NULL); \
  655. return; \
  656. }
  657. /*
  658. * REEVALUATE_PSBTRACK
  659. * This macro just refreshes the local variable pSBTrack, in case it has
  660. * been changed during a callback. After performing this operation, pSBTrack
  661. * should be tested to make sure it is not now NULL.
  662. */
  663. #if (defined(DBG) || defined(DEBUG) || defined(_DEBUG))
  664. #define REEVALUATE_PSBTRACK(pSBTrack, hwnd, str) \
  665. if ((pSBTrack) != CUxScrollBar::GetSBTrack(hwnd)) { \
  666. RIPMSG3(RIP_WARNING, \
  667. "%s: pSBTrack changed from %#p to %#p", \
  668. (str), (pSBTrack), CUxScrollBar::GetSBTrack(hwnd)); \
  669. } \
  670. (pSBTrack) = CUxScrollBar::GetSBTrack(hwnd)
  671. #else
  672. #define REEVALUATE_PSBTRACK(pSBTrack, hwnd, str) \
  673. (pSBTrack) = CUxScrollBar::GetSBTrack(hwnd)
  674. #endif
  675. /***************************************************************************\
  676. * HitTestScrollBar
  677. *
  678. * 11/15/96 vadimg ported from Memphis sources
  679. \***************************************************************************/
  680. int HitTestScrollBar(HWND hwnd, BOOL fVert, POINT pt)
  681. {
  682. UINT wDisable;
  683. int px;
  684. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  685. CUxScrollBarCtl* psbCtl = CUxScrollBarCtl::FromHwnd( hwnd );
  686. BOOL fCtl = psbCtl != NULL;
  687. SBCALC SBCalc = {0};
  688. SBCALC *pSBCalc = NULL;
  689. if (fCtl) {
  690. wDisable = psbCtl->_wDisableFlags;
  691. } else {
  692. RECT rcWindow;
  693. GetWindowRect( hwnd, &rcWindow );
  694. #ifdef USE_MIRRORING
  695. //
  696. // Reflect the click coordinates on the horizontal
  697. // scroll bar if the window is mirrored
  698. //
  699. if (TestWF(hwnd,WEFLAYOUTRTL) && !fVert) {
  700. pt.x = rcWindow.right - pt.x;
  701. }
  702. else
  703. #endif
  704. pt.x -= rcWindow.left;
  705. pt.y -= rcWindow.top;
  706. wDisable = _GetWndSBDisableFlags(hwnd, fVert);
  707. }
  708. if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  709. return HTERROR;
  710. }
  711. if (fCtl) {
  712. pSBCalc = CUxScrollBarCtl::GetCalc(hwnd);
  713. } else {
  714. pSBCalc = &SBCalc;
  715. psb->FreshenSBData( SB_BOTH, FALSE );
  716. psb->Calc(hwnd, pSBCalc, NULL, fVert);
  717. }
  718. px = fVert ? pt.y : pt.x;
  719. if( pSBCalc )
  720. {
  721. if (px < pSBCalc->pxUpArrow) {
  722. if (wDisable & LTUPFLAG) {
  723. return HTERROR;
  724. }
  725. return HTSCROLLUP;
  726. } else if (px >= pSBCalc->pxDownArrow) {
  727. if (wDisable & RTDNFLAG) {
  728. return HTERROR;
  729. }
  730. return HTSCROLLDOWN;
  731. } else if (px < pSBCalc->pxThumbTop) {
  732. return HTSCROLLUPPAGE;
  733. } else if (px < pSBCalc->pxThumbBottom) {
  734. return HTSCROLLTHUMB;
  735. } else if (px < pSBCalc->pxDownArrow) {
  736. return HTSCROLLDOWNPAGE;
  737. }
  738. }
  739. return HTERROR;
  740. }
  741. BOOL _SBGetParms(
  742. HWND hwnd,
  743. int code,
  744. PSBDATA pw,
  745. LPSCROLLINFO lpsi)
  746. {
  747. PSBTRACK pSBTrack;
  748. pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  749. if (lpsi->fMask & SIF_RANGE) {
  750. lpsi->nMin = pw->posMin;
  751. lpsi->nMax = pw->posMax;
  752. }
  753. if (lpsi->fMask & SIF_PAGE)
  754. lpsi->nPage = pw->page;
  755. if (lpsi->fMask & SIF_POS) {
  756. lpsi->nPos = pw->pos;
  757. }
  758. if (lpsi->fMask & SIF_TRACKPOS)
  759. {
  760. if (pSBTrack && (pSBTrack->nBar == code) && (pSBTrack->hwndTrack == hwnd)) {
  761. // posNew is in the context of psbiSB's window and bar code
  762. lpsi->nTrackPos = pSBTrack->posNew;
  763. } else {
  764. lpsi->nTrackPos = pw->pos;
  765. }
  766. }
  767. return ((lpsi->fMask & SIF_ALL) ? TRUE : FALSE);
  768. }
  769. //-------------------------------------------------------------------------//
  770. BOOL WINAPI ThemeGetScrollInfo( HWND hwnd, int nBar, LPSCROLLINFO psi )
  771. {
  772. CUxScrollBar* psb = CUxScrollBar::FromHwnd(hwnd);
  773. if((psb != NULL) && (psb->IsAttaching() == FALSE))
  774. {
  775. #ifdef DEBUG
  776. if( psb->IsCtl() )
  777. {
  778. ASSERT(FALSE); // controls cooperate through an SBM_GETSCROLLINFO message.
  779. }
  780. else
  781. #endif DEBUG
  782. {
  783. SBINFO* psbi;
  784. if( (psbi = psb->GetInfo()) != NULL )
  785. {
  786. SBDATA* psbd = SB_VERT == nBar ? &psbi->Vert :
  787. SB_HORZ == nBar ? &psbi->Horz : NULL;
  788. if( psbd )
  789. return _SBGetParms( hwnd, nBar, psbd, psi );
  790. }
  791. }
  792. }
  793. return FALSE;
  794. }
  795. /***************************************************************************\
  796. * _GetWndSBDisableFlags
  797. *
  798. * This returns the scroll bar Disable flags of the scroll bars of a
  799. * given Window.
  800. *
  801. *
  802. * History:
  803. * 4-18-91 MikeHar Ported for the 31 merge
  804. \***************************************************************************/
  805. UINT _GetWndSBDisableFlags(
  806. HWND hwnd, // The window whose scroll bar Disable Flags are to be returned;
  807. BOOL fVert) // If this is TRUE, it means Vertical scroll bar.
  808. {
  809. PSBINFO pw;
  810. if ((pw = CUxScrollBar::GetSBInfo( hwnd )) == NULL) {
  811. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  812. return 0;
  813. }
  814. return (fVert ? (pw->WSBflags & WSB_VERT) >> 2 : pw->WSBflags & WSB_HORZ);
  815. }
  816. /***************************************************************************\
  817. * xxxEnableSBCtlArrows()
  818. *
  819. * This function can be used to selectively Enable/Disable
  820. * the arrows of a scroll bar Control
  821. *
  822. * History:
  823. * 04-18-91 MikeHar Ported for the 31 merge
  824. \***************************************************************************/
  825. BOOL xxxEnableSBCtlArrows(
  826. HWND hwnd,
  827. UINT wArrows)
  828. {
  829. UINT wOldFlags = CUxScrollBarCtl::GetDisableFlags( hwnd ); // Get the original status
  830. BOOL bChanged = FALSE;
  831. if (wArrows == ESB_ENABLE_BOTH) { // Enable both the arrows
  832. bChanged = CUxScrollBarCtl::AddRemoveDisableFlags( hwnd, 0, SB_DISABLE_MASK );
  833. } else {
  834. bChanged = CUxScrollBarCtl::AddRemoveDisableFlags( hwnd, wArrows, 0 );
  835. }
  836. /*
  837. * Check if the status has changed because of this call
  838. */
  839. if (!bChanged)
  840. return FALSE;
  841. /*
  842. * Else, redraw the scroll bar control to reflect the new state
  843. */
  844. if (IsWindowVisible(hwnd))
  845. InvalidateRect(hwnd, NULL, TRUE);
  846. UINT wNewFlags = CUxScrollBarCtl::GetDisableFlags(hwnd);
  847. // state change notifications
  848. if ((wOldFlags & ESB_DISABLE_UP) != (wNewFlags & ESB_DISABLE_UP))
  849. {
  850. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_CLIENT, INDEX_SCROLLBAR_UP);
  851. }
  852. if ((wOldFlags & ESB_DISABLE_DOWN) != (wNewFlags & ESB_DISABLE_DOWN))
  853. {
  854. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_CLIENT, INDEX_SCROLLBAR_DOWN);
  855. }
  856. return TRUE;
  857. }
  858. /***************************************************************************\
  859. * xxxEnableWndSBArrows()
  860. *
  861. * This function can be used to selectively Enable/Disable
  862. * the arrows of a Window Scroll bar(s)
  863. *
  864. * History:
  865. * 4-18-91 MikeHar Ported for the 31 merge
  866. \***************************************************************************/
  867. BOOL xxxEnableWndSBArrows(
  868. HWND hwnd,
  869. UINT wSBflags,
  870. UINT wArrows)
  871. {
  872. INT wOldFlags;
  873. PSBINFO pw;
  874. BOOL bRetValue = FALSE;
  875. HDC hdc;
  876. CheckLock(hwnd);
  877. ASSERT(IsWinEventNotifyDeferredOK());
  878. if ((pw = CUxScrollBar::GetSBInfo( hwnd )) != NULL)
  879. {
  880. wOldFlags = pw->WSBflags;
  881. }
  882. else
  883. {
  884. // Originally everything is enabled; Check to see if this function is
  885. // asked to disable anything; Otherwise, no change in status; So, must
  886. // return immediately;
  887. if(!wArrows)
  888. return FALSE; // No change in status!
  889. wOldFlags = 0; // Both are originally enabled;
  890. CUxScrollBar::Attach( hwnd, FALSE, FALSE );
  891. if((pw = CUxScrollBar::GetSBInfo(hwnd)) == NULL) // Allocate the pSBInfo for hWnd
  892. return FALSE;
  893. }
  894. hdc = GetWindowDC(hwnd);
  895. if (hdc != NULL)
  896. {
  897. /*
  898. * First Take care of the Horizontal Scroll bar, if one exists.
  899. */
  900. if((wSBflags == SB_HORZ) || (wSBflags == SB_BOTH)) {
  901. if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
  902. pw->WSBflags &= ~SB_DISABLE_MASK;
  903. else
  904. pw->WSBflags |= wArrows;
  905. /*
  906. * Update the display of the Horizontal Scroll Bar;
  907. */
  908. if(pw->WSBflags != wOldFlags) {
  909. bRetValue = TRUE;
  910. wOldFlags = pw->WSBflags;
  911. if (TestWF(hwnd, WFHPRESENT) && !TestWF(hwnd, WFMINIMIZED) &&
  912. IsWindowVisible(hwnd)) {
  913. DrawScrollBar(hwnd, hdc, NULL, FALSE); // Horizontal Scroll Bar.
  914. }
  915. }
  916. // Left button
  917. if ((wOldFlags & ESB_DISABLE_LEFT) != (pw->WSBflags & ESB_DISABLE_LEFT))
  918. {
  919. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_HSCROLL, INDEX_SCROLLBAR_UP);
  920. }
  921. // Right button
  922. if ((wOldFlags & ESB_DISABLE_RIGHT) != (pw->WSBflags & ESB_DISABLE_RIGHT))
  923. {
  924. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_HSCROLL, INDEX_SCROLLBAR_DOWN);
  925. }
  926. }
  927. // Then take care of the Vertical Scroll bar, if one exists.
  928. if ((wSBflags == SB_VERT) || (wSBflags == SB_BOTH))
  929. {
  930. if (wArrows == ESB_ENABLE_BOTH)
  931. {
  932. // Enable both the arrows
  933. pw->WSBflags &= ~(SB_DISABLE_MASK << 2);
  934. }
  935. else
  936. {
  937. pw->WSBflags |= (wArrows << 2);
  938. }
  939. // Update the display of the Vertical Scroll Bar;
  940. if(pw->WSBflags != wOldFlags)
  941. {
  942. bRetValue = TRUE;
  943. if (TestWF(hwnd, WFVPRESENT) && !TestWF(hwnd, WFMINIMIZED) && IsWindowVisible(hwnd))
  944. {
  945. // Vertical Scroll Bar
  946. DrawScrollBar(hwnd, hdc, NULL, TRUE);
  947. }
  948. // Up button
  949. if ((wOldFlags & (ESB_DISABLE_UP << 2)) != (pw->WSBflags & (ESB_DISABLE_UP << 2)))
  950. {
  951. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_VSCROLL, INDEX_SCROLLBAR_UP);
  952. }
  953. // Down button
  954. if ((wOldFlags & (ESB_DISABLE_DOWN << 2)) != (pw->WSBflags & (ESB_DISABLE_DOWN << 2)))
  955. {
  956. NotifyWinEvent(EVENT_OBJECT_STATECHANGE, hwnd, OBJID_VSCROLL, INDEX_SCROLLBAR_DOWN);
  957. }
  958. }
  959. }
  960. ReleaseDC(hwnd,hdc);
  961. }
  962. return bRetValue;
  963. }
  964. /***************************************************************************\
  965. * EnableScrollBar()
  966. *
  967. * This function can be used to selectively Enable/Disable
  968. * the arrows of a scroll bar; It could be used with Windows Scroll
  969. * bars as well as scroll bar controls
  970. *
  971. * History:
  972. * 4-18-91 MikeHar Ported for the 31 merge
  973. \***************************************************************************/
  974. BOOL xxxEnableScrollBar(
  975. HWND hwnd,
  976. UINT wSBflags, // Whether it is a Window Scroll Bar; if so, HORZ or VERT?
  977. // Possible values are SB_HORZ, SB_VERT, SB_CTL or SB_BOTH
  978. UINT wArrows) // Which arrows must be enabled/disabled:
  979. // ESB_ENABLE_BOTH = > Enable both arrows.
  980. // ESB_DISABLE_LTUP = > Disable Left/Up arrow;
  981. // ESB_DISABLE_RTDN = > DIsable Right/Down arrow;
  982. // ESB_DISABLE_BOTH = > Disable both the arrows;
  983. {
  984. #define ES_NOTHING 0
  985. #define ES_DISABLE 1
  986. #define ES_ENABLE 2
  987. UINT wOldFlags;
  988. UINT wEnableWindow;
  989. CheckLock(hwnd);
  990. if(wSBflags != SB_CTL) {
  991. return xxxEnableWndSBArrows(hwnd, wSBflags, wArrows);
  992. }
  993. /*
  994. * Let us assume that we don't have to call EnableWindow
  995. */
  996. wEnableWindow = ES_NOTHING;
  997. wOldFlags = CUxScrollBarCtl::GetDisableFlags( hwnd ) & (UINT)SB_DISABLE_MASK;
  998. /*
  999. * Check if the present state of the arrows is exactly the same
  1000. * as what the caller wants:
  1001. */
  1002. if (wOldFlags == wArrows)
  1003. return FALSE ; // If so, nothing needs to be done;
  1004. /*
  1005. * Check if the caller wants to disable both the arrows
  1006. */
  1007. if (wArrows == ESB_DISABLE_BOTH) {
  1008. wEnableWindow = ES_DISABLE; // Yes! So, disable the whole SB Ctl.
  1009. } else {
  1010. /*
  1011. * Check if the caller wants to enable both the arrows
  1012. */
  1013. if(wArrows == ESB_ENABLE_BOTH) {
  1014. /*
  1015. * We need to enable the SB Ctl only if it was already disabled.
  1016. */
  1017. if(wOldFlags == ESB_DISABLE_BOTH)
  1018. wEnableWindow = ES_ENABLE;// EnableWindow(.., TRUE);
  1019. } else {
  1020. /*
  1021. * Now, Caller wants to disable only one arrow;
  1022. * Check if one of the arrows was already disabled and we want
  1023. * to disable the other;If so, the whole SB Ctl will have to be
  1024. * disabled; Check if this is the case:
  1025. */
  1026. if((wOldFlags | wArrows) == ESB_DISABLE_BOTH)
  1027. wEnableWindow = ES_DISABLE; // EnableWindow(, FALSE);
  1028. }
  1029. }
  1030. if(wEnableWindow != ES_NOTHING) {
  1031. /*
  1032. * EnableWindow returns old state of the window; We must return
  1033. * TRUE only if the Old state is different from new state.
  1034. */
  1035. if(EnableWindow(hwnd, (BOOL)(wEnableWindow == ES_ENABLE))) {
  1036. return !(TestWF(hwnd, WFDISABLED));
  1037. } else {
  1038. return TestWF(hwnd, WFDISABLED);
  1039. }
  1040. }
  1041. return (BOOL)SendMessage(hwnd, SBM_ENABLE_ARROWS, (DWORD)wArrows, 0);
  1042. #undef ES_NOTHING
  1043. #undef ES_DISABLE
  1044. #undef ES_ENABLE
  1045. }
  1046. //-------------------------------------------------------------------------
  1047. BOOL WINAPI ThemeEnableScrollBar( HWND hwnd, UINT nSBFlags, UINT nArrows )
  1048. {
  1049. return xxxEnableScrollBar( hwnd, nSBFlags, nArrows );
  1050. }
  1051. //-------------------------------------------------------------------------
  1052. //
  1053. // DrawSizeBox() - paints the scrollbar sizebox/gripper given top, left
  1054. // point in window coords.
  1055. //
  1056. void DrawSizeBox(HWND hwnd, HDC hdc, int x, int y)
  1057. {
  1058. RECT rc;
  1059. SetRect(&rc, x, y, x + SYSMET(CXVSCROLL), y + SYSMET(CYHSCROLL));
  1060. FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
  1061. //
  1062. // If we have a scrollbar control, or the sizebox is not associated with
  1063. // a sizeable window, draw the flat gray sizebox. Otherwise, use the
  1064. // sizing grip.
  1065. //
  1066. if ((IsScrollBarControl(hwnd) && TestWF(hwnd, SBFSIZEGRIP)) || SizeBoxHwnd(hwnd))
  1067. {
  1068. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1069. if (!hTheme)
  1070. {
  1071. // Blt out the grip bitmap.
  1072. DrawFrameControl( hdc, &rc, DFC_SCROLL,
  1073. TestWF(hwnd, WEFLEFTSCROLL) ? DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP );
  1074. //user: BitBltSysBmp(hdc, x, y, TestWF(hwnd, WEFLEFTSCROLL) ? OBI_NCGRIP_L : OBI_NCGRIP);
  1075. }
  1076. else
  1077. {
  1078. DrawThemeBackground(hTheme, hdc, SBP_SIZEBOX, TestWF(hwnd, WEFLEFTSCROLL) ? SZB_LEFTALIGN : SZB_RIGHTALIGN, &rc, 0);
  1079. }
  1080. }
  1081. }
  1082. //-------------------------------------------------------------------------
  1083. //
  1084. // _DrawSizeBoxFromFrame
  1085. //
  1086. // Calculates position and draws of sizebox/gripper at fixed offset from
  1087. // perimeter of host window frame.
  1088. //
  1089. // This, combined with implementation of DrawSizeBox(),
  1090. // was the original DrawSize() port. Needed to expost method to
  1091. // draw sizebox at absolute position. [scotthan]
  1092. //
  1093. void _DrawSizeBoxFromFrame(HWND hwnd, HDC hdc, int cxFrame,int cyFrame )
  1094. {
  1095. int x, y;
  1096. RECT rcWindow;
  1097. GetWindowRect(hwnd, &rcWindow);
  1098. if (TestWF(hwnd, WEFLEFTSCROLL))
  1099. {
  1100. x = cxFrame;
  1101. }
  1102. else
  1103. {
  1104. x = rcWindow.right - rcWindow.left - cxFrame - SYSMET(CXVSCROLL);
  1105. }
  1106. y = rcWindow.bottom - rcWindow.top - cyFrame - SYSMET(CYHSCROLL);
  1107. DrawSizeBox(hwnd, hdc, x, y);
  1108. }
  1109. //-------------------------------------------------------------------------
  1110. HBRUSH ScrollBar_GetControlColor(HWND hwndParent, HWND hwndCtl, HDC hdc, UINT uMsg, BOOL *pfOwnerBrush)
  1111. {
  1112. HBRUSH hbrush;
  1113. BOOL fOwnerBrush = FALSE;
  1114. //
  1115. // If we're sending to a window of another thread, don't send this message
  1116. // but instead call DefWindowProc(). New rule about the CTLCOLOR messages.
  1117. // Need to do this so that we don't send an hdc owned by one thread to
  1118. // another thread. It is also a harmless change.
  1119. //
  1120. if (GetWindowThreadProcessId(hwndParent, NULL) != GetCurrentThreadId())
  1121. {
  1122. hbrush = (HBRUSH)DefWindowProc(hwndParent, uMsg, (WPARAM)hdc, (LPARAM)hwndCtl);
  1123. }
  1124. else
  1125. {
  1126. hbrush = (HBRUSH)SendMessage(hwndParent, uMsg, (WPARAM)hdc, (LPARAM)hwndCtl);
  1127. //
  1128. // If the brush returned from the parent is invalid, get a valid brush from
  1129. // DefWindowProc.
  1130. //
  1131. if (hbrush == NULL)
  1132. {
  1133. hbrush = (HBRUSH)DefWindowProc(hwndParent, uMsg, (WPARAM)hdc, (LPARAM)hwndCtl);
  1134. }
  1135. else
  1136. {
  1137. fOwnerBrush = TRUE;
  1138. }
  1139. }
  1140. if (pfOwnerBrush)
  1141. {
  1142. *pfOwnerBrush = fOwnerBrush;
  1143. }
  1144. return hbrush;
  1145. }
  1146. //-------------------------------------------------------------------------
  1147. HBRUSH ScrollBar_GetControlBrush(HWND hwnd, HDC hdc, UINT uMsg, BOOL *pfOwnerBrush)
  1148. {
  1149. HWND hwndSend;
  1150. hwndSend = TESTFLAG(GetWindowStyle(hwnd), WS_POPUP) ? GetOwner(hwnd) : GetParent(hwnd);
  1151. if (hwndSend == NULL)
  1152. {
  1153. hwndSend = hwnd;
  1154. }
  1155. return ScrollBar_GetControlColor(hwndSend, hwnd, hdc, uMsg, pfOwnerBrush);
  1156. }
  1157. //-------------------------------------------------------------------------
  1158. HBRUSH ScrollBar_GetColorObjects(HWND hwnd, HDC hdc, BOOL *pfOwnerBrush)
  1159. {
  1160. HBRUSH hbrRet;
  1161. CheckLock(hwnd);
  1162. // Use the scrollbar color even if the scrollbar is disabeld.
  1163. if (!IsScrollBarControl(hwnd))
  1164. {
  1165. hbrRet = (HBRUSH)DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(hwnd));
  1166. }
  1167. else
  1168. {
  1169. // B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
  1170. // owner. If the app doesn't process the message, DefWindowProc32
  1171. // will always return the appropriate system brush. If the app.
  1172. // returns an invalid object, GetControlBrush will call DWP for
  1173. // the default brush. Thus hbrRet doesn't need any validation
  1174. // here.
  1175. hbrRet = ScrollBar_GetControlBrush(hwnd, hdc, WM_CTLCOLORSCROLLBAR, pfOwnerBrush);
  1176. }
  1177. return hbrRet;
  1178. }
  1179. //-------------------------------------------------------------------------
  1180. //
  1181. // ScrollBar_PaintTrack
  1182. //
  1183. // Draws lines & middle of thumb groove
  1184. // Note that pw points into prc. Moreover, note that both pw & prc are
  1185. // pointers, so *prc better not be on the stack.
  1186. //
  1187. void ScrollBar_PaintTrack(HWND hwnd, HDC hdc, HBRUSH hbr, LPRECT prc, BOOL fVert, INT iPartId, BOOL fOwnerBrush)
  1188. {
  1189. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1190. // If the scrollbar is unthemed or
  1191. // #374054 we've been passed an brush defined by the owner, paint
  1192. // the shaft using the brush
  1193. if ((hTheme == NULL) || (fOwnerBrush == TRUE))
  1194. {
  1195. if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == SYSHBR(SCROLLBAR)) || (hbr == _UxGrayBrush()) )
  1196. {
  1197. FillRect(hdc, prc, hbr);
  1198. }
  1199. else
  1200. {
  1201. #ifdef PORTPORT // we need SystemParametersInfo for _UxGrayBrush
  1202. // Draw sides
  1203. CopyRect(&rc, prc);
  1204. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT |
  1205. (fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
  1206. #endif PORTPORT
  1207. // Fill middle
  1208. FillRect(hdc, prc, hbr);
  1209. }
  1210. }
  1211. else
  1212. {
  1213. INT iStateId;
  1214. INT ht = CUxScrollBar::GetSBHotComponent(hwnd, fVert);
  1215. if ((CUxScrollBarCtl::GetDisableFlags(hwnd) & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
  1216. {
  1217. iStateId = SCRBS_DISABLED;
  1218. }
  1219. else if ((((iPartId == SBP_LOWERTRACKHORZ) || (iPartId == SBP_LOWERTRACKVERT)) && (ht == HTSCROLLUPPAGE)) ||
  1220. (((iPartId == SBP_UPPERTRACKHORZ) || (iPartId == SBP_UPPERTRACKVERT)) && (ht == HTSCROLLDOWNPAGE)))
  1221. {
  1222. iStateId = SCRBS_HOT;
  1223. }
  1224. else
  1225. {
  1226. iStateId = SCRBS_NORMAL;
  1227. }
  1228. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, prc, 0);
  1229. }
  1230. }
  1231. /***************************************************************************\
  1232. * CalcTrackDragRect
  1233. *
  1234. * Give the rectangle for a scrollbar in pSBTrack->pSBCalc,
  1235. * calculate pSBTrack->rcTrack, the rectangle where tracking
  1236. * may occur without cancelling the thumbdrag operation.
  1237. *
  1238. \***************************************************************************/
  1239. void CalcTrackDragRect(PSBTRACK pSBTrack) {
  1240. int cx;
  1241. int cy;
  1242. LPINT pwX, pwY;
  1243. //
  1244. // Point pwX and pwY at the parts of the rectangle
  1245. // corresponding to pSBCalc->pxLeft, pxTop, etc.
  1246. //
  1247. // pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
  1248. // scrollbar and the top edge of horizontal one.
  1249. // pSBTrack->pSBCalc->pxTop is the top of a vertical
  1250. // scrollbar and the left of horizontal one.
  1251. // etc...
  1252. //
  1253. // Point pwX and pwY to the corresponding parts
  1254. // of pSBTrack->rcTrack.
  1255. //
  1256. pwX = pwY = (LPINT)&pSBTrack->rcTrack;
  1257. if (pSBTrack->fTrackVert) {
  1258. cy = SYSMET(CYVTHUMB);
  1259. pwY++;
  1260. } else {
  1261. cy = SYSMET(CXHTHUMB);
  1262. pwX++;
  1263. }
  1264. /*
  1265. * Later5.0 GerardoB: People keep complaining about this tracking region
  1266. * being too narrow so let's make it wider while PM decides what to do
  1267. * about it.
  1268. * We also used to have some hard coded min and max values but that should
  1269. * depend on some metric, if at all needed.
  1270. */
  1271. cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8;
  1272. cy *= 2;
  1273. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx;
  1274. *(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy;
  1275. *(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx;
  1276. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy;
  1277. }
  1278. void RecalcTrackRect(PSBTRACK pSBTrack) {
  1279. LPINT pwX, pwY;
  1280. RECT rcSB;
  1281. if (!pSBTrack->fCtlSB)
  1282. CUxScrollBar::Calc(pSBTrack->hwndTrack, pSBTrack->pSBCalc, NULL, pSBTrack->fTrackVert);
  1283. pwX = (LPINT)&rcSB;
  1284. pwY = pwX + 1;
  1285. if (!pSBTrack->fTrackVert)
  1286. pwX = pwY--;
  1287. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft;
  1288. *(pwY + 0) = pSBTrack->pSBCalc->pxTop;
  1289. *(pwX + 2) = pSBTrack->pSBCalc->pxRight;
  1290. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
  1291. switch(pSBTrack->cmdSB) {
  1292. case SB_LINEUP:
  1293. *(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow;
  1294. break;
  1295. case SB_LINEDOWN:
  1296. *(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow;
  1297. break;
  1298. case SB_PAGEUP:
  1299. *(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow;
  1300. *(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop;
  1301. break;
  1302. case SB_THUMBPOSITION:
  1303. CalcTrackDragRect(pSBTrack);
  1304. break;
  1305. case SB_PAGEDOWN:
  1306. *(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom;
  1307. *(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow;
  1308. break;
  1309. }
  1310. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  1311. CopyRect(&pSBTrack->rcTrack, &rcSB);
  1312. }
  1313. }
  1314. //-------------------------------------------------------------------------
  1315. void DrawThumb2(
  1316. HWND hwnd,
  1317. PSBCALC pSBCalc,
  1318. HDC hdc,
  1319. HBRUSH hbr,
  1320. BOOL fVert,
  1321. UINT wDisable, // Disabled flags for the scroll bar
  1322. BOOL fOwnerBrush)
  1323. {
  1324. int *pLength;
  1325. int *pWidth;
  1326. RECT rcSB;
  1327. PSBTRACK pSBTrack;
  1328. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1329. //
  1330. // Bail out if the scrollbar has an empty rect
  1331. //
  1332. if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight))
  1333. {
  1334. return;
  1335. }
  1336. pLength = (LPINT)&rcSB;
  1337. if (fVert)
  1338. {
  1339. pWidth = pLength++;
  1340. }
  1341. else
  1342. {
  1343. pWidth = pLength + 1;
  1344. }
  1345. pWidth[0] = pSBCalc->pxLeft;
  1346. pWidth[2] = pSBCalc->pxRight;
  1347. // If were're not themed and both buttons are disabled OR there isn't
  1348. // enough room to draw a thumb just draw the track and run.
  1349. //
  1350. // When we are themed the thumb can be drawn disabled.
  1351. if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
  1352. ((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb))
  1353. {
  1354. // draw the entire track
  1355. pLength[0] = pSBCalc->pxUpArrow;
  1356. pLength[2] = pSBCalc->pxDownArrow;
  1357. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ, fOwnerBrush);
  1358. return;
  1359. }
  1360. if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop)
  1361. {
  1362. // draw the track above the thumb
  1363. pLength[0] = pSBCalc->pxUpArrow;
  1364. pLength[2] = pSBCalc->pxThumbTop;
  1365. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ, fOwnerBrush);
  1366. }
  1367. if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow)
  1368. {
  1369. // draw the track below the thumb
  1370. pLength[0] = pSBCalc->pxThumbBottom;
  1371. pLength[2] = pSBCalc->pxDownArrow;
  1372. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ, fOwnerBrush);
  1373. }
  1374. //
  1375. // Draw elevator
  1376. //
  1377. pLength[0] = pSBCalc->pxThumbTop;
  1378. pLength[2] = pSBCalc->pxThumbBottom;
  1379. // Not soft!
  1380. _DrawPushButton(hwnd, hdc, &rcSB, 0, 0, fVert);
  1381. #ifdef _VISUAL_DELTA_
  1382. InflateRect( &rcSB, -CARET_BORDERWIDTH, -CARET_BORDERWIDTH);
  1383. DrawEdge( hdc, &rcSB, EDGE_SUNKEN, BF_RECT );
  1384. #endif _VISUAL_DELTA_
  1385. /*
  1386. * If we're tracking a page scroll, then we've obliterated the hilite.
  1387. * We need to correct the hiliting rectangle, and rehilite it.
  1388. */
  1389. pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  1390. if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) &&
  1391. (hwnd == pSBTrack->hwndTrack) &&
  1392. (BOOL)pSBTrack->fTrackVert == fVert) {
  1393. if (pSBTrack->fTrackRecalc) {
  1394. RecalcTrackRect(pSBTrack);
  1395. pSBTrack->fTrackRecalc = FALSE;
  1396. }
  1397. pLength = (int *)&pSBTrack->rcTrack;
  1398. if (fVert)
  1399. pLength++;
  1400. if (pSBTrack->cmdSB == SB_PAGEUP)
  1401. pLength[2] = pSBCalc->pxThumbTop;
  1402. else
  1403. pLength[0] = pSBCalc->pxThumbBottom;
  1404. if (pLength[0] < pLength[2])
  1405. {
  1406. if (!hTheme)
  1407. {
  1408. InvertRect(hdc, &pSBTrack->rcTrack);
  1409. }
  1410. else
  1411. {
  1412. DrawThemeBackground(hTheme,
  1413. hdc,
  1414. pSBTrack->cmdSB == SB_PAGEUP ?
  1415. (fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ) :
  1416. (fVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ),
  1417. SCRBS_PRESSED,
  1418. &pSBTrack->rcTrack,
  1419. 0);
  1420. }
  1421. }
  1422. }
  1423. }
  1424. /***************************************************************************\
  1425. * xxxDrawSB2
  1426. *
  1427. *
  1428. *
  1429. * History:
  1430. \***************************************************************************/
  1431. void xxxDrawSB2(
  1432. HWND hwnd,
  1433. PSBCALC pSBCalc,
  1434. HDC hdc,
  1435. BOOL fVert,
  1436. UINT wDisable)
  1437. {
  1438. int cLength;
  1439. int cWidth;
  1440. int *pwX;
  1441. int *pwY;
  1442. HBRUSH hbr;
  1443. HBRUSH hbrSave;
  1444. int cpxArrow;
  1445. RECT rc, rcSB;
  1446. COLORREF crText, crBk;
  1447. HTHEME hTheme;
  1448. INT ht;
  1449. INT iStateId;
  1450. BOOL fOwnerBrush = FALSE;
  1451. CheckLock(hwnd);
  1452. cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2;
  1453. cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
  1454. if ((cLength <= 0) || (cWidth <= 0)) {
  1455. return;
  1456. }
  1457. if (fVert)
  1458. {
  1459. cpxArrow = SYSMET(CYVSCROLL);
  1460. }
  1461. else
  1462. {
  1463. cpxArrow = SYSMET(CXHSCROLL);
  1464. }
  1465. // Save background and DC color, since they get changed in
  1466. // ScrollBar_GetColorObjects. Restore before we return.
  1467. crBk = GetBkColor(hdc);
  1468. crText = GetTextColor(hdc);
  1469. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1470. if (cLength > cpxArrow)
  1471. {
  1472. cLength = cpxArrow;
  1473. }
  1474. pwX = (int *)&rcSB;
  1475. pwY = pwX + 1;
  1476. if (!fVert)
  1477. {
  1478. pwX = pwY--;
  1479. }
  1480. pwX[0] = pSBCalc->pxLeft;
  1481. pwY[0] = pSBCalc->pxTop;
  1482. pwX[2] = pSBCalc->pxRight;
  1483. pwY[2] = pSBCalc->pxBottom;
  1484. hbrSave = SelectBrush(hdc, SYSHBR(BTNTEXT));
  1485. //
  1486. // BOGUS
  1487. // Draw scrollbar arrows as disabled if the scrollbar itself is
  1488. // disabled OR if the window it is a part of is disabled?
  1489. //
  1490. hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1491. ht = CUxScrollBar::GetSBHotComponent(hwnd, fVert);
  1492. if (fVert)
  1493. {
  1494. // up button
  1495. CopyRect(&rc, &rcSB);
  1496. rc.bottom = rc.top + cLength;
  1497. if (!hTheme)
  1498. {
  1499. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1500. DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1501. }
  1502. else
  1503. {
  1504. iStateId = (wDisable & LTUPFLAG) ? ABS_UPDISABLED : (ht == HTSCROLLUP) ? ABS_UPHOT : ABS_UPNORMAL;
  1505. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1506. }
  1507. // down button
  1508. rc.bottom = rcSB.bottom;
  1509. rc.top = rcSB.bottom - cLength;
  1510. if (!hTheme)
  1511. {
  1512. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1513. DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1514. }
  1515. else
  1516. {
  1517. iStateId = (wDisable & RTDNFLAG) ? ABS_DOWNDISABLED : (ht == HTSCROLLDOWN) ? ABS_DOWNHOT : ABS_DOWNNORMAL;
  1518. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1519. }
  1520. }
  1521. else
  1522. {
  1523. // left button
  1524. CopyRect(&rc, &rcSB);
  1525. rc.right = rc.left + cLength;
  1526. if (!hTheme)
  1527. {
  1528. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1529. DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1530. }
  1531. else
  1532. {
  1533. iStateId = (wDisable & LTUPFLAG) ? ABS_LEFTDISABLED : (ht == HTSCROLLUP) ? ABS_LEFTHOT : ABS_LEFTNORMAL;
  1534. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1535. }
  1536. // right button
  1537. rc.right = rcSB.right;
  1538. rc.left = rcSB.right - cLength;
  1539. if (!hTheme)
  1540. {
  1541. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1542. DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1543. }
  1544. else
  1545. {
  1546. iStateId = (wDisable & RTDNFLAG) ? ABS_RIGHTDISABLED : (ht == HTSCROLLDOWN) ? ABS_RIGHTHOT : ABS_RIGHTNORMAL;
  1547. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1548. }
  1549. }
  1550. hbrSave = SelectBrush(hdc, hbrSave);
  1551. DrawThumb2(hwnd, pSBCalc, hdc, hbr, fVert, wDisable, fOwnerBrush);
  1552. SelectBrush(hdc, hbrSave);
  1553. SetBkColor(hdc, crBk);
  1554. SetTextColor(hdc, crText);
  1555. }
  1556. /***************************************************************************\
  1557. * zzzSetSBCaretPos
  1558. *
  1559. *
  1560. *
  1561. * History:
  1562. \***************************************************************************/
  1563. void zzzSetSBCaretPos(
  1564. SBHWND hwndSB)
  1565. {
  1566. if (GetFocus() == hwndSB) {
  1567. CUxScrollBarCtl* psb = CUxScrollBarCtl::FromHwnd( hwndSB );
  1568. if( psb )
  1569. {
  1570. int x = (psb->_fVert ? psb->_calc.pxLeft : psb->_calc.pxThumbTop) + SYSMET(CXEDGE);
  1571. int y = (psb->_fVert ? psb->_calc.pxThumbTop : psb->_calc.pxLeft) + SYSMET(CYEDGE);
  1572. #ifdef _VISUAL_DELTA_
  1573. x += CARET_BORDERWIDTH;
  1574. y += CARET_BORDERWIDTH;
  1575. #endif _VISUAL_DELTA_
  1576. SetCaretPos( x, y );
  1577. }
  1578. }
  1579. }
  1580. /***************************************************************************\
  1581. * CalcSBStuff2
  1582. *
  1583. *
  1584. *
  1585. * History:
  1586. \***************************************************************************/
  1587. void CalcSBStuff2(
  1588. PSBCALC pSBCalc,
  1589. LPRECT lprc,
  1590. CONST PSBDATA pw,
  1591. BOOL fVert)
  1592. {
  1593. int cpx;
  1594. DWORD dwRange;
  1595. int denom;
  1596. if (fVert) {
  1597. pSBCalc->pxTop = lprc->top;
  1598. pSBCalc->pxBottom = lprc->bottom;
  1599. pSBCalc->pxLeft = lprc->left;
  1600. pSBCalc->pxRight = lprc->right;
  1601. pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
  1602. } else {
  1603. /*
  1604. * For horiz scroll bars, "left" & "right" are "top" and "bottom",
  1605. * and vice versa.
  1606. */
  1607. pSBCalc->pxTop = lprc->left;
  1608. pSBCalc->pxBottom = lprc->right;
  1609. pSBCalc->pxLeft = lprc->top;
  1610. pSBCalc->pxRight = lprc->bottom;
  1611. pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
  1612. }
  1613. pSBCalc->data.pos = pw->pos;
  1614. pSBCalc->data.page = pw->page;
  1615. pSBCalc->data.posMin = pw->posMin;
  1616. pSBCalc->data.posMax = pw->posMax;
  1617. dwRange = ((DWORD)(pSBCalc->data.posMax - pSBCalc->data.posMin)) + 1;
  1618. //
  1619. // For the case of short scroll bars that don't have enough
  1620. // room to fit the full-sized up and down arrows, shorten
  1621. // their sizes to make 'em fit
  1622. //
  1623. cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
  1624. pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx;
  1625. pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
  1626. if ((pw->page != 0) && (dwRange != 0)) {
  1627. // JEFFBOG -- This is the one and only place where we should
  1628. // see 'range'. Elsewhere it should be 'range - page'.
  1629. /*
  1630. * The minimun thumb size used to depend on the frame/edge metrics.
  1631. * People that increase the scrollbar width/height expect the minimun
  1632. * to grow with proportianally. So NT5 bases the minimun on
  1633. * CXH/YVSCROLL, which is set by default in cpxThumb.
  1634. */
  1635. /*
  1636. * i is used to keep the macro "max" from executing MulDiv twice.
  1637. */
  1638. int i = MulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
  1639. pw->page, dwRange);
  1640. pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
  1641. }
  1642. pSBCalc->pxMin = pSBCalc->pxTop + cpx;
  1643. pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
  1644. denom = dwRange - (pw->page ? pw->page : 1);
  1645. if (denom)
  1646. pSBCalc->pxThumbTop = MulDiv(pw->pos - pw->posMin,
  1647. pSBCalc->cpx, denom) +
  1648. pSBCalc->pxMin;
  1649. else
  1650. pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
  1651. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  1652. }
  1653. /***************************************************************************\
  1654. * SBCtlSetup
  1655. *
  1656. *
  1657. *
  1658. * History:
  1659. \***************************************************************************/
  1660. CUxScrollBarCtl* SBCtlSetup(
  1661. SBHWND hwndSB)
  1662. {
  1663. RECT rc;
  1664. GetClientRect( hwndSB, &rc );
  1665. CUxScrollBarCtl* psb = (CUxScrollBarCtl*)CUxScrollBar::Attach( hwndSB, TRUE, FALSE );
  1666. if( psb )
  1667. {
  1668. psb->Calc2( &psb->_calc, &rc, &psb->_calc.data, psb->_fVert );
  1669. }
  1670. return psb;
  1671. }
  1672. /***************************************************************************\
  1673. * HotTrackSB
  1674. *
  1675. \***************************************************************************/
  1676. #ifdef COLOR_HOTTRACKING
  1677. DWORD GetTrackFlags(int ht, BOOL fDraw)
  1678. {
  1679. if (fDraw) {
  1680. switch(ht) {
  1681. case HTSCROLLUP:
  1682. case HTSCROLLUPPAGE:
  1683. return LTUPFLAG;
  1684. case HTSCROLLDOWN:
  1685. case HTSCROLLDOWNPAGE:
  1686. return RTDNFLAG;
  1687. case HTSCROLLTHUMB:
  1688. return LTUPFLAG | RTDNFLAG;
  1689. default:
  1690. return 0;
  1691. }
  1692. } else {
  1693. return 0;
  1694. }
  1695. }
  1696. BOOL xxxHotTrackSB(HWND hwnd, int htEx, BOOL fDraw)
  1697. {
  1698. SBCALC SBCalc;
  1699. HDC hdc;
  1700. BOOL fVert = HIWORD(htEx);
  1701. int ht = LOWORD(htEx);
  1702. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  1703. CheckLock(hwnd);
  1704. /*
  1705. * xxxDrawSB2 does not callback or leave the critical section when it's
  1706. * not a SB control and the window belongs to a different thread. It
  1707. * calls DefWindowProc which simply returns the brush color.
  1708. */
  1709. CalcSBStuff(hwnd, &SBCalc, fVert);
  1710. hdc = _GetDCEx(hwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  1711. xxxDrawSB2(hwnd, &SBCalc, hdc, fVert, _GetWndSBDisableFlags(hwnd, fVert), dwTrack);
  1712. ReleaseDC(hwnd, hdc);
  1713. return TRUE;
  1714. }
  1715. void xxxHotTrackSBCtl(SBHWND hwndSB, int ht, BOOL fDraw)
  1716. {
  1717. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  1718. HDC hdc;
  1719. CheckLock(hwndSB);
  1720. SBCtlSetup(hwndSB);
  1721. hdc = _GetDCEx((HWND)hwndSB, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  1722. xxxDrawSB2((HWND)hwndSB, &psb->_calc, hdc, psb->_fVert, psb->_wDisableFlags, dwTrack);
  1723. ReleaseDC(hwnd, hdc);
  1724. }
  1725. #endif // COLOR_HOTTRACKING
  1726. BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres)
  1727. {
  1728. // pass the struct because we modify the struct but don't want that
  1729. // modified version to get back to the calling app
  1730. BOOL fChanged = FALSE;
  1731. if (lpsi->fMask & SIF_RETURNOLDPOS)
  1732. // save previous position
  1733. *lplres = pw->pos;
  1734. if (lpsi->fMask & SIF_RANGE) {
  1735. // if the range MAX is below the range MIN -- then treat is as a
  1736. // zero range starting at the range MIN.
  1737. if (lpsi->nMax < lpsi->nMin)
  1738. lpsi->nMax = lpsi->nMin;
  1739. if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) {
  1740. pw->posMin = lpsi->nMin;
  1741. pw->posMax = lpsi->nMax;
  1742. if (!(lpsi->fMask & SIF_PAGE)) {
  1743. lpsi->fMask |= SIF_PAGE;
  1744. lpsi->nPage = pw->page;
  1745. }
  1746. if (!(lpsi->fMask & SIF_POS)) {
  1747. lpsi->fMask |= SIF_POS;
  1748. lpsi->nPos = pw->pos;
  1749. }
  1750. fChanged = TRUE;
  1751. }
  1752. }
  1753. if (lpsi->fMask & SIF_PAGE) {
  1754. DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
  1755. // Clip page to 0, posMax - posMin + 1
  1756. if (lpsi->nPage > dwMaxPage)
  1757. lpsi->nPage = dwMaxPage;
  1758. if (pw->page != (int)(lpsi->nPage)) {
  1759. pw->page = lpsi->nPage;
  1760. if (!(lpsi->fMask & SIF_POS)) {
  1761. lpsi->fMask |= SIF_POS;
  1762. lpsi->nPos = pw->pos;
  1763. }
  1764. fChanged = TRUE;
  1765. }
  1766. }
  1767. if (lpsi->fMask & SIF_POS) {
  1768. int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0);
  1769. // Clip pos to posMin, posMax - (page - 1).
  1770. if (lpsi->nPos < pw->posMin)
  1771. lpsi->nPos = pw->posMin;
  1772. else if (lpsi->nPos > iMaxPos)
  1773. lpsi->nPos = iMaxPos;
  1774. if (pw->pos != lpsi->nPos) {
  1775. pw->pos = lpsi->nPos;
  1776. fChanged = TRUE;
  1777. }
  1778. }
  1779. if (!(lpsi->fMask & SIF_RETURNOLDPOS)) {
  1780. // Return the new position
  1781. *lplres = pw->pos;
  1782. }
  1783. /*
  1784. * This was added by JimA as Cairo merge but will conflict
  1785. * with the documentation for SetScrollPos
  1786. */
  1787. /*
  1788. else if (*lplres == pw->pos)
  1789. *lplres = 0;
  1790. */
  1791. if (lpsi->fMask & SIF_RANGE) {
  1792. *lpfScroll = (pw->posMin != pw->posMax);
  1793. if (*lpfScroll)
  1794. goto checkPage;
  1795. } else if (lpsi->fMask & SIF_PAGE)
  1796. checkPage:
  1797. *lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
  1798. return fChanged;
  1799. }
  1800. /***************************************************************************\
  1801. * CalcSBStuff
  1802. *
  1803. *
  1804. *
  1805. * History:
  1806. \***************************************************************************/
  1807. #if 0
  1808. void CalcSBStuff(
  1809. HWND hwnd,
  1810. PSBCALC pSBCalc,
  1811. BOOL fVert)
  1812. {
  1813. RECT rcT;
  1814. RECT rcClient;
  1815. #ifdef USE_MIRRORING
  1816. int cx, iTemp;
  1817. #endif
  1818. //
  1819. // Get client rectangle. We know that scrollbars always align to the right
  1820. // and to the bottom of the client area.
  1821. //
  1822. GetClientRect( hwnd, &rcClient );
  1823. ClientToScreen( hwnd, (LPPOINT)&rcClient.left );
  1824. ClientToScreen( hwnd, (LPPOINT)&rcClient.right );
  1825. MapWindowPoints( HWND_DESKTOP, hwnd, (LPPOINT)&rcClient, 2 );
  1826. // GetRect(hwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS);
  1827. #ifdef USE_MIRRORING
  1828. if (TestWF(hwnd, WEFLAYOUTRTL)) {
  1829. cx = hwnd->rcWindow.right - hwnd->rcWindow.left;
  1830. iTemp = rcClient.left;
  1831. rcClient.left = cx - rcClient.right;
  1832. rcClient.right = cx - iTemp;
  1833. }
  1834. #endif
  1835. if (fVert) {
  1836. // Only add on space if vertical scrollbar is really there.
  1837. if (TestWF(hwnd, WEFLEFTSCROLL)) {
  1838. rcT.right = rcT.left = rcClient.left;
  1839. if (TestWF(hwnd, WFVPRESENT))
  1840. rcT.left -= SYSMET(CXVSCROLL);
  1841. } else {
  1842. rcT.right = rcT.left = rcClient.right;
  1843. if (TestWF(hwnd, WFVPRESENT))
  1844. rcT.right += SYSMET(CXVSCROLL);
  1845. }
  1846. rcT.top = rcClient.top;
  1847. rcT.bottom = rcClient.bottom;
  1848. } else {
  1849. // Only add on space if horizontal scrollbar is really there.
  1850. rcT.bottom = rcT.top = rcClient.bottom;
  1851. if (TestWF(hwnd, WFHPRESENT))
  1852. rcT.bottom += SYSMET(CYHSCROLL);
  1853. rcT.left = rcClient.left;
  1854. rcT.right = rcClient.right;
  1855. }
  1856. // If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
  1857. // we can do here, so just let it go through. We won't fault but the scrollbar won't work
  1858. // properly either...
  1859. if (_InitPwSB(hwnd))
  1860. CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &CUxScrollBar::GetSBInfo( hwnd )->Vert : &CUxScrollBar::GetSBInfo( hwnd )->Horz, fVert);
  1861. }
  1862. #endif 0
  1863. /***************************************************************************\
  1864. *
  1865. * DrawCtlThumb()
  1866. *
  1867. \***************************************************************************/
  1868. void DrawCtlThumb(SBHWND hwnd)
  1869. {
  1870. HBRUSH hbr, hbrSave;
  1871. HDC hdc = (HDC) GetWindowDC(hwnd);
  1872. if ( hdc != NULL )
  1873. {
  1874. CUxScrollBarCtl* psb = SBCtlSetup(hwnd);
  1875. if (psb)
  1876. {
  1877. BOOL fOwnerBrush = FALSE;
  1878. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1879. hbrSave = SelectBrush(hdc, hbr);
  1880. DrawThumb2(hwnd, &psb->_calc, hdc, hbr, psb->_fVert, psb->_wDisableFlags, fOwnerBrush);
  1881. SelectBrush(hdc, hbrSave);
  1882. }
  1883. ReleaseDC(hwnd, hdc);
  1884. }
  1885. }
  1886. //-------------------------------------------------------------------------
  1887. void xxxDrawThumb(HWND hwnd, PSBCALC pSBCalc, BOOL fVert)
  1888. {
  1889. HBRUSH hbr, hbrSave;
  1890. HDC hdc;
  1891. UINT wDisableFlags;
  1892. SBCALC SBCalc;
  1893. CheckLock(hwnd);
  1894. if (!pSBCalc)
  1895. {
  1896. pSBCalc = &SBCalc;
  1897. }
  1898. CUxScrollBar::Calc( hwnd, pSBCalc, NULL, fVert );
  1899. wDisableFlags = _GetWndSBDisableFlags(hwnd, fVert);
  1900. hdc = GetWindowDC(hwnd);
  1901. if ( hdc != NULL )
  1902. {
  1903. BOOL fOwnerBrush = FALSE;
  1904. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1905. hbrSave = SelectBrush(hdc, hbr);
  1906. DrawThumb2(hwnd, pSBCalc, hdc, hbr, fVert, wDisableFlags, fOwnerBrush);
  1907. SelectBrush(hdc, hbrSave);
  1908. ReleaseDC(hwnd, hdc);
  1909. }
  1910. }
  1911. //-------------------------------------------------------------------------
  1912. UINT _GetArrowEnableFlags(HWND hwnd, BOOL fVert)
  1913. {
  1914. SCROLLBARINFO sbi = {0};
  1915. UINT uFlags = ESB_ENABLE_BOTH;
  1916. sbi.cbSize = sizeof(sbi);
  1917. if ( GetScrollBarInfo(hwnd, fVert ? OBJID_VSCROLL : OBJID_HSCROLL, &sbi) )
  1918. {
  1919. if ( TESTFLAG(sbi.rgstate[INDEX_SCROLLBAR_UP], (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE)) )
  1920. {
  1921. uFlags |= ESB_DISABLE_UP;
  1922. }
  1923. if ( TESTFLAG(sbi.rgstate[INDEX_SCROLLBAR_DOWN], (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE)) )
  1924. {
  1925. uFlags |= ESB_DISABLE_DOWN;
  1926. }
  1927. }
  1928. return uFlags;
  1929. }
  1930. /***************************************************************************\
  1931. * _SetScrollBar
  1932. *
  1933. *
  1934. *
  1935. * History:
  1936. \***************************************************************************/
  1937. LONG _SetScrollBar(
  1938. HWND hwnd,
  1939. int code,
  1940. LPSCROLLINFO lpsi,
  1941. BOOL fRedraw)
  1942. {
  1943. BOOL fVert;
  1944. PSBDATA pw;
  1945. PSBINFO pSBInfo;
  1946. BOOL fOldScroll;
  1947. BOOL fScroll;
  1948. WORD wfScroll;
  1949. LONG lres;
  1950. BOOL fNewScroll;
  1951. CheckLock(hwnd);
  1952. ASSERT(IsWinEventNotifyDeferredOK());
  1953. if (fRedraw)
  1954. // window must be visible to redraw
  1955. fRedraw = IsWindowVisible(hwnd);
  1956. if (code == SB_CTL)
  1957. #ifdef FE_SB // xxxSetScrollBar()
  1958. // scroll bar control; send the control a message
  1959. if(GETPTI(hwnd)->TIF_flags & TIF_16BIT) {
  1960. //
  1961. // If the target application is 16bit apps, we don't pass win40's message.
  1962. // This fix for Ichitaro v6.3. It eats the message. It never forwards
  1963. // the un-processed messages to original windows procedure via
  1964. // CallWindowProc().
  1965. //
  1966. // Is this from xxxSetScrollPos() ?
  1967. if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) {
  1968. return (int)SendMessage(hwnd, SBM_SETPOS, lpsi->nPos, fRedraw);
  1969. // Is this from xxxSetScrollRange() ?
  1970. } else if(lpsi->fMask == SIF_RANGE) {
  1971. SendMessage(hwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax);
  1972. return TRUE;
  1973. // Others...
  1974. } else {
  1975. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1976. }
  1977. } else {
  1978. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1979. }
  1980. #else
  1981. // scroll bar control; send the control a message
  1982. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1983. #endif // FE_SB
  1984. fVert = (code != SB_HORZ);
  1985. wfScroll = (WORD)((fVert) ? WFVSCROLL : WFHSCROLL);
  1986. fScroll = fOldScroll = (TestWF(hwnd, wfScroll)) ? TRUE : FALSE;
  1987. /*
  1988. * Don't do anything if we're setting position of a nonexistent scroll bar.
  1989. */
  1990. if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (CUxScrollBar::GetSBInfo( hwnd ) == NULL)) {
  1991. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  1992. return 0;
  1993. }
  1994. pSBInfo = CUxScrollBar::GetSBInfo( hwnd );
  1995. fNewScroll = !pSBInfo;
  1996. if (fNewScroll) {
  1997. CUxScrollBar* psb = CUxScrollBar::Attach( hwnd, FALSE, fRedraw );
  1998. if( NULL == psb )
  1999. return 0;
  2000. pSBInfo = psb->GetInfo();
  2001. }
  2002. pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
  2003. if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll)
  2004. {
  2005. // no change -- but if REDRAW is specified and there's a scrollbar,
  2006. // redraw the thumb
  2007. if (fOldScroll && fRedraw)
  2008. {
  2009. goto redrawAfterSet;
  2010. }
  2011. if (lpsi->fMask & SIF_DISABLENOSCROLL)
  2012. {
  2013. xxxEnableWndSBArrows(hwnd, code, _GetArrowEnableFlags(hwnd, fVert));
  2014. }
  2015. return lres;
  2016. }
  2017. ClrWF(hwnd, wfScroll);
  2018. if (fScroll)
  2019. SetWF(hwnd, wfScroll);
  2020. else if (!TestWF(hwnd, (WFHSCROLL | WFVSCROLL)))
  2021. {
  2022. // if neither scroll bar is set and both ranges are 0, then free up the
  2023. // scroll info
  2024. CUxScrollBar::Detach( hwnd );
  2025. }
  2026. if (lpsi->fMask & SIF_DISABLENOSCROLL)
  2027. {
  2028. if (fOldScroll)
  2029. {
  2030. SetWF(hwnd, wfScroll);
  2031. xxxEnableWndSBArrows(hwnd, code, _GetArrowEnableFlags(hwnd, fVert));
  2032. }
  2033. }
  2034. else if (fOldScroll ^ fScroll)
  2035. {
  2036. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2037. if (pSBTrack && (hwnd == pSBTrack->hwndTrack))
  2038. {
  2039. pSBTrack->fTrackRecalc = TRUE;
  2040. }
  2041. _RedrawFrame(hwnd);
  2042. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2043. return lres;
  2044. }
  2045. if (fScroll && fRedraw && (fVert ? TestWF(hwnd, WFVPRESENT) : TestWF(hwnd, WFHPRESENT)))
  2046. {
  2047. PSBTRACK pSBTrack;
  2048. redrawAfterSet:
  2049. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE,
  2050. hwnd,
  2051. (fVert ? OBJID_VSCROLL : OBJID_HSCROLL),
  2052. INDEX_SCROLLBAR_SELF);
  2053. pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2054. // Bail out if the caller is trying to change the position of
  2055. // a scrollbar that is in the middle of tracking. We'll hose
  2056. // TrackThumb() otherwise.
  2057. if (pSBTrack && (hwnd == pSBTrack->hwndTrack) &&
  2058. ((BOOL)(pSBTrack->fTrackVert) == fVert) &&
  2059. (pSBTrack->pfnSB == _TrackThumb)) {
  2060. return lres;
  2061. }
  2062. xxxDrawThumb(hwnd, NULL, fVert);
  2063. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2064. }
  2065. return lres;
  2066. }
  2067. //-------------------------------------------------------------------------//
  2068. LONG WINAPI ThemeSetScrollInfo( HWND hwnd, int nBar, LPCSCROLLINFO psi, BOOL bRedraw )
  2069. {
  2070. return _SetScrollBar( hwnd, nBar, (LPSCROLLINFO)psi, bRedraw );
  2071. }
  2072. //-------------------------------------------------------------------------//
  2073. BOOL WINAPI ScrollBar_MouseMove( HWND hwnd, LPPOINT ppt, BOOL fVert )
  2074. {
  2075. BOOL fRet = FALSE;
  2076. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2077. if (psb)
  2078. {
  2079. int htScroll = (ppt != NULL) ? HitTestScrollBar(hwnd, fVert, *ppt) : HTNOWHERE;
  2080. //
  2081. // Redraw the scroll bar if the mouse is over something different
  2082. //
  2083. if (htScroll != psb->GetHotComponent(fVert))
  2084. {
  2085. HDC hdc;
  2086. //
  2087. // save the hittest code of the Scrollbar element the mouse is
  2088. // currently over
  2089. //
  2090. psb->SetHotComponent(htScroll, fVert);
  2091. hdc = GetDCEx(hwnd, NULL, DCX_USESTYLE|DCX_WINDOW|DCX_LOCKWINDOWUPDATE);
  2092. if (hdc != NULL)
  2093. {
  2094. DrawScrollBar(hwnd, hdc, NULL, fVert);
  2095. ReleaseDC(hwnd, hdc);
  2096. }
  2097. fRet = TRUE;
  2098. }
  2099. }
  2100. return fRet;
  2101. }
  2102. //-------------------------------------------------------------------------//
  2103. void DrawScrollBar(HWND hwnd, HDC hdc, LPRECT prcOverrideClient, BOOL fVert)
  2104. {
  2105. SBCALC SBCalc = {0};
  2106. PSBCALC pSBCalc;
  2107. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2108. CheckLock(hwnd);
  2109. if (pSBTrack && (hwnd == pSBTrack->hwndTrack) && (pSBTrack->fCtlSB == FALSE)
  2110. && (fVert == (BOOL)pSBTrack->fTrackVert))
  2111. {
  2112. pSBCalc = pSBTrack->pSBCalc;
  2113. }
  2114. else
  2115. {
  2116. pSBCalc = &SBCalc;
  2117. }
  2118. CUxScrollBar::Calc(hwnd, pSBCalc, prcOverrideClient, fVert);
  2119. xxxDrawSB2(hwnd, pSBCalc, hdc, fVert, _GetWndSBDisableFlags(hwnd, fVert));
  2120. }
  2121. /***************************************************************************\
  2122. * SBPosFromPx
  2123. *
  2124. * Compute scroll bar position from pixel location
  2125. *
  2126. * History:
  2127. \***************************************************************************/
  2128. int SBPosFromPx(
  2129. PSBCALC pSBCalc,
  2130. int px)
  2131. {
  2132. if (px < pSBCalc->pxMin) {
  2133. return pSBCalc->data.posMin;
  2134. }
  2135. if (px >= pSBCalc->pxMin + pSBCalc->cpx) {
  2136. return (pSBCalc->data.posMax - (pSBCalc->data.page ? pSBCalc->data.page - 1 : 0));
  2137. }
  2138. if (pSBCalc->cpx)
  2139. return (pSBCalc->data.posMin + MulDiv(pSBCalc->data.posMax - pSBCalc->data.posMin -
  2140. (pSBCalc->data.page ? pSBCalc->data.page - 1 : 0),
  2141. px - pSBCalc->pxMin, pSBCalc->cpx));
  2142. else
  2143. return (pSBCalc->data.posMin - 1);
  2144. }
  2145. /***************************************************************************\
  2146. * InvertScrollHilite
  2147. *
  2148. *
  2149. *
  2150. * History:
  2151. \***************************************************************************/
  2152. void InvertScrollHilite(
  2153. HWND hwnd,
  2154. PSBTRACK pSBTrack)
  2155. {
  2156. HDC hdc;
  2157. /*
  2158. * Don't invert if the thumb is all the way at the top or bottom
  2159. * or you will end up inverting the line between the arrow and the thumb.
  2160. */
  2161. if (!IsRectEmpty(&pSBTrack->rcTrack))
  2162. {
  2163. if (pSBTrack->fTrackRecalc) {
  2164. RecalcTrackRect(pSBTrack);
  2165. pSBTrack->fTrackRecalc = FALSE;
  2166. }
  2167. hdc = (HDC)GetWindowDC(hwnd);
  2168. if( hdc )
  2169. {
  2170. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  2171. if (!hTheme)
  2172. {
  2173. InvertRect(hdc, &pSBTrack->rcTrack);
  2174. }
  2175. else
  2176. {
  2177. DrawThemeBackground(hTheme,
  2178. hdc,
  2179. pSBTrack->cmdSB == SB_PAGEUP ?
  2180. (pSBTrack->fTrackVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ) :
  2181. (pSBTrack->fTrackVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ),
  2182. SCRBS_NORMAL,
  2183. &pSBTrack->rcTrack,
  2184. 0);
  2185. }
  2186. ReleaseDC(hwnd, hdc);
  2187. }
  2188. }
  2189. }
  2190. /***************************************************************************\
  2191. * xxxDoScroll
  2192. *
  2193. * Sends scroll notification to the scroll bar owner
  2194. *
  2195. * History:
  2196. \***************************************************************************/
  2197. void xxxDoScroll(
  2198. HWND hwnd,
  2199. HWND hwndNotify,
  2200. int cmd,
  2201. int pos,
  2202. BOOL fVert
  2203. )
  2204. {
  2205. //
  2206. // Send scroll notification to the scrollbar owner. If this is a control
  2207. // the lParam is the control's handle, NULL otherwise.
  2208. //
  2209. SendMessage(hwndNotify,
  2210. (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
  2211. MAKELONG(cmd, pos),
  2212. (LPARAM)(IsScrollBarControl(hwnd) ? hwnd : NULL));
  2213. }
  2214. // -------------------------------------------------------------------------
  2215. //
  2216. // CheckScrollRecalc()
  2217. //
  2218. // -------------------------------------------------------------------------
  2219. //void CheckScrollRecalc(HWND hwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
  2220. //{
  2221. // if ((pSBState->pwndCalc != hwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
  2222. // {
  2223. // // Calculate SB stuff based on whether it's a control or in a window
  2224. // if (pSBState->fCtlSB)
  2225. // SBCtlSetup((SBHWND) hwnd);
  2226. // else
  2227. // CalcSBStuff(hwnd, pSBCalc, pSBState->fVertSB);
  2228. // }
  2229. //}
  2230. /***************************************************************************\
  2231. * xxxMoveThumb
  2232. *
  2233. * History:
  2234. \***************************************************************************/
  2235. void xxxMoveThumb(
  2236. HWND hwnd,
  2237. PSBCALC pSBCalc,
  2238. int px)
  2239. {
  2240. HBRUSH hbr, hbrSave;
  2241. HDC hdc;
  2242. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2243. PSBTRACK pSBTrack = psb->GetTrack();
  2244. CheckLock(hwnd);
  2245. if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
  2246. return;
  2247. pxReCalc:
  2248. pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
  2249. /* Tentative position changed -- notify the guy. */
  2250. if (pSBTrack->posNew != pSBTrack->posOld) {
  2251. if (pSBTrack->hwndSBNotify != NULL) {
  2252. psb->DoScroll(pSBTrack->hwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert
  2253. );
  2254. }
  2255. // After xxxDoScroll, re-evaluate pSBTrack
  2256. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxMoveThumb(1)");
  2257. if ((pSBTrack == NULL) || (pSBTrack->pfnSB == NULL))
  2258. return;
  2259. pSBTrack->posOld = pSBTrack->posNew;
  2260. //
  2261. // Anything can happen after the SendMessage above!
  2262. // Make sure that the SBINFO structure contains data for the
  2263. // window being tracked -- if not, recalculate data in SBINFO
  2264. //
  2265. // CheckScrollRecalc(hwnd, pSBState, pSBCalc);
  2266. // when we yield, our range can get messed with
  2267. // so make sure we handle this
  2268. if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  2269. {
  2270. px = pSBCalc->pxMin + pSBCalc->cpx;
  2271. goto pxReCalc;
  2272. }
  2273. }
  2274. hdc = GetWindowDC(hwnd);
  2275. if ( hdc != NULL )
  2276. {
  2277. BOOL fOwnerBrush = FALSE;
  2278. pSBCalc->pxThumbTop = px;
  2279. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  2280. // at this point, the disable flags are always going to be 0 --
  2281. // we're in the middle of tracking.
  2282. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  2283. hbrSave = SelectBrush(hdc, hbr);
  2284. // After ScrollBar_GetColorObjects, re-evaluate pSBTrack
  2285. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxMoveThumb(2)");
  2286. if (pSBTrack == NULL)
  2287. {
  2288. RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ;
  2289. ReleaseDC(hwnd, hdc);
  2290. return;
  2291. }
  2292. DrawThumb2(hwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0, fOwnerBrush);
  2293. SelectBrush(hdc, hbrSave);
  2294. ReleaseDC(hwnd, hdc);
  2295. }
  2296. pSBTrack->pxOld = px;
  2297. }
  2298. /***************************************************************************\
  2299. * zzzDrawInvertScrollArea
  2300. *
  2301. *
  2302. *
  2303. * History:
  2304. \***************************************************************************/
  2305. void zzzDrawInvertScrollArea(
  2306. HWND hwnd,
  2307. PSBTRACK pSBTrack,
  2308. BOOL fHit,
  2309. UINT cmd)
  2310. {
  2311. HDC hdc;
  2312. RECT rcTemp;
  2313. int cx, cy;
  2314. HTHEME hTheme;
  2315. if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN)) {
  2316. // not hitting on arrow -- just invert the area and return
  2317. InvertScrollHilite(hwnd, pSBTrack);
  2318. if (cmd == SB_PAGEUP)
  2319. {
  2320. if (fHit)
  2321. SetWF(hwnd, WFPAGEUPBUTTONDOWN);
  2322. else
  2323. ClrWF(hwnd, WFPAGEUPBUTTONDOWN);
  2324. }
  2325. else
  2326. {
  2327. if (fHit)
  2328. SetWF(hwnd, WFPAGEDNBUTTONDOWN);
  2329. else
  2330. ClrWF(hwnd, WFPAGEDNBUTTONDOWN);
  2331. }
  2332. NotifyWinEvent(EVENT_OBJECT_STATECHANGE,
  2333. hwnd,
  2334. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2335. ((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE));
  2336. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  2337. return;
  2338. }
  2339. if (pSBTrack->fTrackRecalc) {
  2340. RecalcTrackRect(pSBTrack);
  2341. pSBTrack->fTrackRecalc = FALSE;
  2342. }
  2343. CopyRect(&rcTemp, &pSBTrack->rcTrack);
  2344. hdc = GetWindowDC(hwnd);
  2345. if( hdc != NULL )
  2346. {
  2347. if (pSBTrack->fTrackVert) {
  2348. cx = SYSMET(CXVSCROLL);
  2349. cy = SYSMET(CYVSCROLL);
  2350. } else {
  2351. cx = SYSMET(CXHSCROLL);
  2352. cy = SYSMET(CYHSCROLL);
  2353. }
  2354. hTheme = CUxScrollBar::GetSBTheme(hwnd);
  2355. if (!hTheme)
  2356. {
  2357. DrawFrameControl(hdc, &rcTemp, DFC_SCROLL,
  2358. ((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) |
  2359. ((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) |
  2360. ((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX));
  2361. }
  2362. else
  2363. {
  2364. INT iStateId;
  2365. // Determine the pressed state of the button
  2366. iStateId = fHit ? SCRBS_PRESSED : SCRBS_NORMAL;
  2367. // Determine which kind of button it is.
  2368. // NOTE: (phellyar) this is dependant on the order of
  2369. // the ARROWBTNSTATE enum
  2370. if (pSBTrack->fTrackVert)
  2371. {
  2372. if (cmd == SB_LINEUP)
  2373. {
  2374. // Up button states are the first four entries
  2375. // in the enum
  2376. iStateId += 0;
  2377. }
  2378. else
  2379. {
  2380. // Down button states are the second four entries
  2381. // in the enum
  2382. iStateId += 4;
  2383. }
  2384. }
  2385. else
  2386. {
  2387. if (cmd == SB_LINEUP)
  2388. {
  2389. // Left button states are the third four entries
  2390. // in the enum
  2391. iStateId += 8;
  2392. }
  2393. else
  2394. {
  2395. // Right button states are the last four entries
  2396. // in the enum
  2397. iStateId += 12;
  2398. }
  2399. }
  2400. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rcTemp, 0);
  2401. }
  2402. ReleaseDC(hwnd, hdc);
  2403. }
  2404. if (cmd == SB_LINEUP) {
  2405. if (fHit)
  2406. SetWF(hwnd, WFLINEUPBUTTONDOWN);
  2407. else
  2408. ClrWF(hwnd, WFLINEUPBUTTONDOWN);
  2409. } else {
  2410. if (fHit)
  2411. SetWF(hwnd, WFLINEDNBUTTONDOWN);
  2412. else
  2413. ClrWF(hwnd, WFLINEDNBUTTONDOWN);
  2414. }
  2415. NotifyWinEvent(EVENT_OBJECT_STATECHANGE,
  2416. hwnd,
  2417. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2418. (cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN));
  2419. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  2420. }
  2421. /***************************************************************************\
  2422. * xxxEndScroll
  2423. *
  2424. *
  2425. *
  2426. * History:
  2427. \***************************************************************************/
  2428. void xxxEndScroll(
  2429. HWND hwnd,
  2430. BOOL fCancel)
  2431. {
  2432. UINT oldcmd;
  2433. PSBTRACK pSBTrack;
  2434. CheckLock(hwnd);
  2435. ASSERT(!IsWinEventNotifyDeferred());
  2436. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2437. ASSERT(psb != NULL);
  2438. pSBTrack = psb->GetTrack();
  2439. if (pSBTrack && GetCapture() == hwnd && pSBTrack->pfnSB != NULL) {
  2440. oldcmd = pSBTrack->cmdSB;
  2441. pSBTrack->cmdSB = 0;
  2442. ReleaseCapture();
  2443. // After ReleaseCapture, revalidate pSBTrack
  2444. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2445. if (pSBTrack->pfnSB == _TrackThumb) {
  2446. if (fCancel) {
  2447. pSBTrack->posOld = pSBTrack->pSBCalc->data.pos;
  2448. }
  2449. /*
  2450. * DoScroll does thread locking on these two pwnds -
  2451. * this is ok since they are not used after this
  2452. * call.
  2453. */
  2454. if (pSBTrack->hwndSBNotify != NULL) {
  2455. psb->DoScroll( pSBTrack->hwndSBNotify,
  2456. SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert
  2457. );
  2458. // After xxxDoScroll, revalidate pSBTrack
  2459. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2460. }
  2461. if (pSBTrack->fCtlSB) {
  2462. DrawCtlThumb((SBHWND) hwnd);
  2463. } else {
  2464. xxxDrawThumb(hwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
  2465. // Note: after xxx, pSBTrack may no longer be valid
  2466. }
  2467. } else if (pSBTrack->pfnSB == _TrackBox) {
  2468. DWORD lParam;
  2469. POINT ptMsg;
  2470. RECT rcWindow;
  2471. if (pSBTrack->hTimerSB != 0) {
  2472. _KillSystemTimer(hwnd, IDSYS_SCROLL);
  2473. pSBTrack->hTimerSB = 0;
  2474. }
  2475. lParam = GetMessagePos();
  2476. GetWindowRect( hwnd, &rcWindow );
  2477. #ifdef USE_MIRRORING
  2478. if (TestWF(hwnd, WEFLAYOUTRTL)) {
  2479. ptMsg.x = rcWindow.right - GET_X_LPARAM(lParam);
  2480. } else
  2481. #endif
  2482. {
  2483. ptMsg.x = GET_X_LPARAM(lParam) - rcWindow.left;
  2484. }
  2485. ptMsg.y = GET_Y_LPARAM(lParam) - rcWindow.top;
  2486. if (PtInRect(&pSBTrack->rcTrack, ptMsg)) {
  2487. zzzDrawInvertScrollArea(hwnd, pSBTrack, FALSE, oldcmd);
  2488. // Note: after zzz, pSBTrack may no longer be valid
  2489. }
  2490. }
  2491. /*
  2492. * Always send SB_ENDSCROLL message.
  2493. *
  2494. * DoScroll does thread locking on these two pwnds -
  2495. * this is ok since they are not used after this
  2496. * call.
  2497. */
  2498. // After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
  2499. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2500. if (pSBTrack->hwndSBNotify != NULL) {
  2501. psb->DoScroll( pSBTrack->hwndSBNotify,
  2502. SB_ENDSCROLL, 0, pSBTrack->fTrackVert);
  2503. // After xxxDoScroll, revalidate pSBTrack
  2504. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2505. }
  2506. ClrWF(hwnd, WFSCROLLBUTTONDOWN);
  2507. ClrWF(hwnd, WFVERTSCROLLTRACK);
  2508. NotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND,
  2509. hwnd,
  2510. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2511. INDEXID_CONTAINER);
  2512. // After xxxWindowEvent, revalidate pSBTrack
  2513. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2514. // If this is a Scroll Bar Control, turn the caret back on.
  2515. if (pSBTrack->hwndSB != NULL)
  2516. {
  2517. ShowCaret(pSBTrack->hwndSB);
  2518. // After zzz, revalidate pSBTrack
  2519. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2520. }
  2521. pSBTrack->pfnSB = NULL;
  2522. /*
  2523. * Unlock structure members so they are no longer holding down windows.
  2524. */
  2525. Unlock(&pSBTrack->hwndSB);
  2526. Unlock(&pSBTrack->hwndSBNotify);
  2527. Unlock(&pSBTrack->hwndTrack);
  2528. CUxScrollBar::ClearSBTrack( hwnd );
  2529. }
  2530. }
  2531. //-------------------------------------------------------------------------//
  2532. VOID CALLBACK xxxContScroll(HWND hwnd, UINT message, UINT_PTR ID, DWORD dwTime)
  2533. {
  2534. UNREFERENCED_PARAMETER(message);
  2535. UNREFERENCED_PARAMETER(ID);
  2536. UNREFERENCED_PARAMETER(dwTime);
  2537. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2538. if ( psb != NULL )
  2539. {
  2540. PSBTRACK pSBTrack = psb->GetTrack();
  2541. if ( pSBTrack != NULL )
  2542. {
  2543. LONG pt;
  2544. RECT rcWindow;
  2545. CheckLock(hwnd);
  2546. pt = GetMessagePos();
  2547. GetWindowRect( hwnd, &rcWindow );
  2548. if (TestWF(hwnd, WEFLAYOUTRTL))
  2549. {
  2550. pt = MAKELONG(rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - rcWindow.top);
  2551. }
  2552. else
  2553. {
  2554. pt = MAKELONG( GET_X_LPARAM(pt) - rcWindow.left, GET_Y_LPARAM(pt) - rcWindow.top);
  2555. }
  2556. _TrackBox(hwnd, WM_NULL, 0, pt, NULL);
  2557. // After _TrackBox, revalidate pSBTrack
  2558. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2559. if (pSBTrack->fHitOld)
  2560. {
  2561. pSBTrack->hTimerSB = _SetSystemTimer(hwnd, IDSYS_SCROLL, DTTIME/8, xxxContScroll);
  2562. // DoScroll does thread locking on these two pwnds -
  2563. // this is ok since they are not used after this call.
  2564. if (pSBTrack->hwndSBNotify != NULL)
  2565. {
  2566. psb->DoScroll(pSBTrack->hwndSBNotify, pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
  2567. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2568. }
  2569. }
  2570. }
  2571. }
  2572. }
  2573. //-------------------------------------------------------------------------//
  2574. void CALLBACK _TrackBox(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc)
  2575. {
  2576. CUxScrollBar* psb = CUxScrollBar::FromHwnd(hwnd);
  2577. UNREFERENCED_PARAMETER(wParam);
  2578. UNREFERENCED_PARAMETER(pSBCalc);
  2579. CheckLock(hwnd);
  2580. ASSERT(IsWinEventNotifyDeferredOK());
  2581. if ( psb )
  2582. {
  2583. PSBTRACK pSBTrack = psb->GetTrack();
  2584. if ( pSBTrack )
  2585. {
  2586. BOOL fHit;
  2587. POINT ptHit;
  2588. int cmsTimer;
  2589. if ((uMsg != WM_NULL) && (HIBYTE(uMsg) != HIBYTE(WM_MOUSEFIRST)))
  2590. {
  2591. return;
  2592. }
  2593. if (pSBTrack->fTrackRecalc)
  2594. {
  2595. RecalcTrackRect(pSBTrack);
  2596. pSBTrack->fTrackRecalc = FALSE;
  2597. }
  2598. ptHit.x = GET_X_LPARAM(lParam);
  2599. ptHit.y = GET_Y_LPARAM(lParam);
  2600. fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
  2601. if (fHit != (BOOL)pSBTrack->fHitOld)
  2602. {
  2603. zzzDrawInvertScrollArea(hwnd, pSBTrack, fHit, pSBTrack->cmdSB);
  2604. // After zzz, pSBTrack may no longer be valid
  2605. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2606. }
  2607. cmsTimer = DTTIME/8;
  2608. switch (uMsg)
  2609. {
  2610. case WM_LBUTTONUP:
  2611. xxxEndScroll(hwnd, FALSE);
  2612. // Note: after xxx, pSBTrack may no longer be valid
  2613. break;
  2614. case WM_LBUTTONDOWN:
  2615. pSBTrack->hTimerSB = 0;
  2616. cmsTimer = DTTIME;
  2617. //
  2618. // FALL THRU
  2619. //
  2620. case WM_MOUSEMOVE:
  2621. if (fHit && fHit != (BOOL)pSBTrack->fHitOld)
  2622. {
  2623. //
  2624. // We moved back into the normal rectangle: reset timer
  2625. //
  2626. pSBTrack->hTimerSB = _SetSystemTimer(hwnd, IDSYS_SCROLL,
  2627. cmsTimer, xxxContScroll);
  2628. //
  2629. // DoScroll does thread locking on these two pwnds -
  2630. // this is ok since they are not used after this
  2631. // call.
  2632. //
  2633. if (pSBTrack->hwndSBNotify != NULL)
  2634. {
  2635. psb->DoScroll( pSBTrack->hwndSBNotify, pSBTrack->cmdSB,
  2636. 0, pSBTrack->fTrackVert);
  2637. // Note: after xxx, pSBTrack may no longer be valid
  2638. }
  2639. }
  2640. break;
  2641. }
  2642. // After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
  2643. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2644. pSBTrack->fHitOld = fHit;
  2645. }
  2646. }
  2647. }
  2648. /***************************************************************************\
  2649. * _TrackThumb
  2650. *
  2651. *
  2652. *
  2653. * History:
  2654. \***************************************************************************/
  2655. void CALLBACK _TrackThumb(
  2656. HWND hwnd,
  2657. UINT message,
  2658. WPARAM wParam,
  2659. LPARAM lParam,
  2660. PSBCALC pSBCalc)
  2661. {
  2662. int px;
  2663. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2664. ASSERT(psb);
  2665. PSBTRACK pSBTrack = psb->GetTrack();
  2666. POINT pt;
  2667. UNREFERENCED_PARAMETER(wParam);
  2668. CheckLock(hwnd);
  2669. if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
  2670. return;
  2671. if (pSBTrack == NULL)
  2672. return;
  2673. // Make sure that the SBINFO structure contains data for the
  2674. // window being tracked -- if not, recalculate data in SBINFO
  2675. // CheckScrollRecalc(hwnd, pSBState, pSBCalc);
  2676. if (pSBTrack->fTrackRecalc) {
  2677. RecalcTrackRect(pSBTrack);
  2678. pSBTrack->fTrackRecalc = FALSE;
  2679. }
  2680. pt.y = GET_Y_LPARAM(lParam);
  2681. pt.x = GET_X_LPARAM(lParam);
  2682. if (!PtInRect(&pSBTrack->rcTrack, pt))
  2683. px = pSBCalc->pxStart;
  2684. else {
  2685. px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
  2686. if (px < pSBCalc->pxMin)
  2687. px = pSBCalc->pxMin;
  2688. else if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  2689. px = pSBCalc->pxMin + pSBCalc->cpx;
  2690. }
  2691. xxxMoveThumb(hwnd, pSBCalc, px);
  2692. /*
  2693. * We won't get the WM_LBUTTONUP message if we got here through
  2694. * the scroll menu, so test the button state directly.
  2695. */
  2696. if (message == WM_LBUTTONUP || GetKeyState(VK_LBUTTON) >= 0) {
  2697. xxxEndScroll(hwnd, FALSE);
  2698. }
  2699. }
  2700. /***************************************************************************\
  2701. * _ClientToWindow
  2702. * History:
  2703. \***************************************************************************/
  2704. BOOL _ClientToWindow( HWND hwnd, LPPOINT ppt )
  2705. {
  2706. WINDOWINFO wi;
  2707. wi.cbSize = sizeof(wi);
  2708. if( GetWindowInfo( hwnd, &wi ) )
  2709. {
  2710. ppt->x += (wi.rcClient.left - wi.rcWindow.left);
  2711. ppt->y += (wi.rcClient.top - wi.rcWindow.top);
  2712. return TRUE;
  2713. }
  2714. return FALSE;
  2715. }
  2716. /***************************************************************************\
  2717. * xxxSBTrackLoop
  2718. *
  2719. *
  2720. *
  2721. * History:
  2722. \***************************************************************************/
  2723. void xxxSBTrackLoop(
  2724. HWND hwnd,
  2725. LPARAM lParam,
  2726. PSBCALC pSBCalc)
  2727. {
  2728. MSG msg;
  2729. UINT cmd;
  2730. VOID (*pfnSB)(HWND, UINT, WPARAM, LPARAM, PSBCALC);
  2731. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2732. PSBTRACK pSBTrack = psb->GetSBTrack(hwnd);
  2733. CheckLock(hwnd);
  2734. ASSERT(IsWinEventNotifyDeferredOK());
  2735. if (pSBTrack == NULL)
  2736. // mode cancelled -- exit track loop
  2737. return;
  2738. pfnSB = pSBTrack->pfnSB;
  2739. if (pfnSB == NULL)
  2740. // mode cancelled -- exit track loop
  2741. return;
  2742. if (pSBTrack->fTrackVert)
  2743. SetWF(hwnd, WFVERTSCROLLTRACK);
  2744. NotifyWinEvent(EVENT_SYSTEM_SCROLLINGSTART,
  2745. hwnd,
  2746. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2747. INDEXID_CONTAINER);
  2748. // Note: after xxx, pSBTrack may no longer be valid
  2749. (*pfnSB)(hwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc);
  2750. // Note: after xxx, pSBTrack may no longer be valid
  2751. while (GetCapture() == hwnd) {
  2752. if (!GetMessage(&msg, NULL, 0, 0)) {
  2753. // Note: after xxx, pSBTrack may no longer be valid
  2754. break;
  2755. }
  2756. if (!CallMsgFilter(&msg, MSGF_SCROLLBAR))
  2757. {
  2758. BOOL bTrackMsg = FALSE;
  2759. cmd = msg.message;
  2760. lParam = msg.lParam;
  2761. if (msg.hwnd == HWq(hwnd))
  2762. {
  2763. if( cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST )
  2764. {
  2765. if( !psb->IsCtl() )
  2766. {
  2767. POINT pt;
  2768. pt.x = GET_X_LPARAM(msg.lParam);
  2769. pt.y = GET_Y_LPARAM(msg.lParam);
  2770. _ClientToWindow( hwnd, &pt );
  2771. lParam = MAKELPARAM(pt.x, pt.y);
  2772. }
  2773. bTrackMsg = TRUE;
  2774. }
  2775. else if( cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST )
  2776. {
  2777. cmd = _SysToChar(cmd, msg.lParam);
  2778. bTrackMsg = TRUE;
  2779. }
  2780. }
  2781. if( bTrackMsg )
  2782. {
  2783. // After NotifyWinEvent, pfnSB, TranslateMessage or
  2784. // DispatchMessage, re-evaluate pSBTrack.
  2785. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxTrackLoop");
  2786. if ((pSBTrack == NULL) || (NULL == (pfnSB = pSBTrack->pfnSB)))
  2787. // mode cancelled -- exit track loop
  2788. return;
  2789. (*pfnSB)(hwnd, cmd, msg.wParam, lParam, pSBCalc);
  2790. }
  2791. else
  2792. {
  2793. TranslateMessage(&msg);
  2794. DispatchMessage(&msg);
  2795. }
  2796. }
  2797. }
  2798. }
  2799. /***************************************************************************\
  2800. * _SBTrackInit
  2801. *
  2802. * History:
  2803. \***************************************************************************/
  2804. void _SBTrackInit(
  2805. HWND hwnd,
  2806. LPARAM lParam,
  2807. int curArea,
  2808. UINT uType)
  2809. {
  2810. int px;
  2811. LPINT pwX;
  2812. LPINT pwY;
  2813. UINT wDisable; // Scroll bar disable flags;
  2814. SBCALC SBCalc = {0};
  2815. PSBCALC pSBCalc;
  2816. RECT rcSB;
  2817. PSBTRACK pSBTrack;
  2818. CheckLock(hwnd);
  2819. #ifdef PORTPORT // unneccessary dbgchk w/ port
  2820. if (CUxScrollBar::GetSBTrack(hwnd)) {
  2821. RIPMSG1(RIP_WARNING, "_SBTrackInit: CUxScrollBar::GetSBTrack(hwnd) == %#p",
  2822. CUxScrollBar::GetSBTrack(hwnd));
  2823. return;
  2824. }
  2825. #endif PORTPORT
  2826. CUxScrollBar* psb = CUxScrollBar::Attach( hwnd, !curArea, TRUE );
  2827. if (!psb)
  2828. {
  2829. return;
  2830. }
  2831. CUxScrollBarCtl* psbCtl = psb->IsCtl() ? (CUxScrollBarCtl*)psb : NULL;
  2832. pSBTrack = psb->GetTrack();
  2833. if (pSBTrack == NULL)
  2834. return;
  2835. pSBTrack->hTimerSB = 0;
  2836. pSBTrack->fHitOld = FALSE;
  2837. pSBTrack->pfnSB = _TrackBox;
  2838. pSBTrack->hwndTrack = NULL;
  2839. pSBTrack->hwndSB = NULL;
  2840. pSBTrack->hwndSBNotify = NULL;
  2841. Lock(&pSBTrack->hwndTrack, hwnd); // pSBTrack->hwndTrack = hwnd;
  2842. pSBTrack->fCtlSB = (!curArea);
  2843. if (pSBTrack->fCtlSB)
  2844. {
  2845. /*
  2846. * This is a scroll bar control.
  2847. */
  2848. ASSERT(psbCtl != NULL);
  2849. pSBTrack->hwndSB = hwnd; //Lock(&pSBTrack->hwndSB, hwnd);
  2850. pSBTrack->fTrackVert = psbCtl->_fVert;
  2851. Lock(&pSBTrack->hwndSBNotify, GetParent(hwnd)); // pSBTrack->hwndSBNotify = GetParent( hwnd );
  2852. wDisable = psbCtl->_wDisableFlags;
  2853. pSBCalc = &psbCtl->_calc;
  2854. pSBTrack->nBar = SB_CTL;
  2855. } else {
  2856. /*
  2857. * This is a scroll bar that is part of the window frame.
  2858. */
  2859. RECT rcWindow;
  2860. GetWindowRect( hwnd, &rcWindow );
  2861. int x = GET_X_LPARAM(lParam);
  2862. int y = GET_Y_LPARAM(lParam);
  2863. #ifdef USE_MIRRORING
  2864. //
  2865. // Mirror the window coord of the scroll bar,
  2866. // if it is a mirrored one
  2867. //
  2868. if (TestWF(hwnd,WEFLAYOUTRTL)) {
  2869. lParam = MAKELONG(
  2870. rcWindow.right - x,
  2871. y - rcWindow.top);
  2872. }
  2873. else {
  2874. #endif
  2875. lParam = MAKELONG( x - rcWindow.left, y - rcWindow.top);
  2876. #ifdef USE_MIRRORING
  2877. }
  2878. #endif
  2879. Lock(&pSBTrack->hwndSBNotify, hwnd); // pSBTrack->hwndSBNotify = hwnd; //
  2880. Lock(&pSBTrack->hwndSB, NULL); // pSBTrack->hwndSB = NULL;
  2881. pSBTrack->fTrackVert = (curArea - HTHSCROLL);
  2882. wDisable = _GetWndSBDisableFlags(hwnd, pSBTrack->fTrackVert);
  2883. pSBCalc = &SBCalc;
  2884. pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ;
  2885. }
  2886. pSBTrack->pSBCalc = pSBCalc;
  2887. /*
  2888. * Check if the whole scroll bar is disabled
  2889. */
  2890. if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  2891. CUxScrollBar::Detach( hwnd );
  2892. return; // It is a disabled scroll bar; So, do not respond.
  2893. }
  2894. if (!pSBTrack->fCtlSB) {
  2895. psb->FreshenSBData( pSBTrack->nBar, FALSE );
  2896. CUxScrollBar::Calc(hwnd, pSBCalc, NULL, pSBTrack->fTrackVert);
  2897. }
  2898. pwX = (LPINT)&rcSB;
  2899. pwY = pwX + 1;
  2900. if (!pSBTrack->fTrackVert)
  2901. pwX = pwY--;
  2902. px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
  2903. *(pwX + 0) = pSBCalc->pxLeft;
  2904. *(pwY + 0) = pSBCalc->pxTop;
  2905. *(pwX + 2) = pSBCalc->pxRight;
  2906. *(pwY + 2) = pSBCalc->pxBottom;
  2907. pSBTrack->cmdSB = (UINT)-1;
  2908. if (px < pSBCalc->pxUpArrow) {
  2909. /*
  2910. * The click occurred on Left/Up arrow; Check if it is disabled
  2911. */
  2912. if(wDisable & LTUPFLAG) {
  2913. if(pSBTrack->fCtlSB) { // If this is a scroll bar control,
  2914. ShowCaret(pSBTrack->hwndSB); // show the caret before returning;
  2915. // After ShowCaret, revalidate pSBTrack
  2916. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2917. }
  2918. CUxScrollBar::Detach( hwnd );
  2919. return; // Yes! disabled. Do not respond.
  2920. }
  2921. // LINEUP -- make rcSB the Up Arrow's Rectangle
  2922. pSBTrack->cmdSB = SB_LINEUP;
  2923. *(pwY + 2) = pSBCalc->pxUpArrow;
  2924. } else if (px >= pSBCalc->pxDownArrow) {
  2925. /*
  2926. * The click occurred on Right/Down arrow; Check if it is disabled
  2927. */
  2928. if (wDisable & RTDNFLAG) {
  2929. if (pSBTrack->fCtlSB) { // If this is a scroll bar control,
  2930. ShowCaret(pSBTrack->hwndSB); // show the caret before returning;
  2931. // After ShowCaret, revalidate pSBTrack
  2932. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2933. }
  2934. CUxScrollBar::Detach( hwnd );
  2935. return;// Yes! disabled. Do not respond.
  2936. }
  2937. // LINEDOWN -- make rcSB the Down Arrow's Rectangle
  2938. pSBTrack->cmdSB = SB_LINEDOWN;
  2939. *(pwY + 0) = pSBCalc->pxDownArrow;
  2940. } else if (px < pSBCalc->pxThumbTop) {
  2941. // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
  2942. pSBTrack->cmdSB = SB_PAGEUP;
  2943. *(pwY + 0) = pSBCalc->pxUpArrow;
  2944. *(pwY + 2) = pSBCalc->pxThumbTop;
  2945. } else if (px < pSBCalc->pxThumbBottom) {
  2946. DoThumbPos:
  2947. /*
  2948. * Elevator isn't there if there's no room.
  2949. */
  2950. if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) {
  2951. CUxScrollBar::Detach( hwnd );
  2952. return;
  2953. }
  2954. // THUMBPOSITION -- we're tracking with the thumb
  2955. pSBTrack->cmdSB = SB_THUMBPOSITION;
  2956. CalcTrackDragRect(pSBTrack);
  2957. pSBTrack->pfnSB = _TrackThumb;
  2958. pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop;
  2959. pSBTrack->posNew = pSBTrack->posOld = pSBCalc->data.pos;
  2960. pSBTrack->dpxThumb = pSBCalc->pxStart - px;
  2961. SetCapture( hwnd ); //xxxCapture(PtiCurrent(), hwnd, WINDOW_CAPTURE);
  2962. // After xxxCapture, revalidate pSBTrack
  2963. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2964. /*
  2965. * DoScroll does thread locking on these two pwnds -
  2966. * this is ok since they are not used after this
  2967. * call.
  2968. */
  2969. if (pSBTrack->hwndSBNotify != NULL) {
  2970. psb->DoScroll( pSBTrack->hwndSBNotify, SB_THUMBTRACK,
  2971. pSBTrack->posOld, pSBTrack->fTrackVert
  2972. );
  2973. // Note: after xxx, pSBTrack may no longer be valid
  2974. }
  2975. } else if (px < pSBCalc->pxDownArrow) {
  2976. // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
  2977. pSBTrack->cmdSB = SB_PAGEDOWN;
  2978. *(pwY + 0) = pSBCalc->pxThumbBottom;
  2979. *(pwY + 2) = pSBCalc->pxDownArrow;
  2980. }
  2981. /*
  2982. * If the shift key is down, we'll position the thumb directly so it's
  2983. * centered on the click point.
  2984. */
  2985. if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) ||
  2986. (uType == SCROLL_MENU)) {
  2987. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  2988. goto DoThumbPos;
  2989. }
  2990. pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2);
  2991. }
  2992. SetCapture( hwnd ); // xxxCapture(PtiCurrent(), hwnd, WINDOW_CAPTURE);
  2993. // After xxxCapture, revalidate pSBTrack
  2994. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2995. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  2996. CopyRect(&pSBTrack->rcTrack, &rcSB);
  2997. }
  2998. xxxSBTrackLoop(hwnd, lParam, pSBCalc);
  2999. // After xxx, re-evaluate pSBTrack
  3000. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxTrackLoop");
  3001. if (pSBTrack)
  3002. {
  3003. CUxScrollBar::ClearSBTrack( hwnd );
  3004. }
  3005. }
  3006. /***************************************************************************\
  3007. * HandleScrollCmd
  3008. *
  3009. * History: added to support and encap SB tracking initialization originating
  3010. * from WM_SYSCOMMAND::SC_VSCROLL/SC_HSCROLL [scotthan]
  3011. \***************************************************************************/
  3012. void WINAPI HandleScrollCmd( HWND hwnd, WPARAM wParam, LPARAM lParam )
  3013. {
  3014. UINT uArea = (UINT)(wParam & 0x0F);
  3015. _SBTrackInit( hwnd, lParam, uArea,
  3016. (GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  3017. }
  3018. //-------------------------------------------------------------------------
  3019. HMENU ScrollBar_GetMenu(HWND hwnd, BOOL fVert)
  3020. {
  3021. static HMODULE hModUser = NULL;
  3022. HMENU hMenu = NULL;
  3023. if ( !hModUser )
  3024. {
  3025. hModUser = GetModuleHandle(TEXT("user32"));
  3026. }
  3027. #define ID_HSCROLLMENU 0x40
  3028. #define ID_VSCROLLMENU 0x50
  3029. if ( hModUser )
  3030. {
  3031. hMenu = LoadMenu(hModUser, MAKEINTRESOURCE((fVert ? ID_VSCROLLMENU : ID_HSCROLLMENU)));
  3032. if ( hMenu )
  3033. {
  3034. hMenu = GetSubMenu(hMenu, 0);
  3035. }
  3036. }
  3037. return hMenu;
  3038. }
  3039. //-------------------------------------------------------------------------
  3040. VOID ScrollBar_Menu(HWND hwndNotify, HWND hwnd, LPARAM lParam, BOOL fVert)
  3041. {
  3042. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  3043. CUxScrollBarCtl* psbCtl = CUxScrollBarCtl::FromHwnd( hwnd );
  3044. BOOL fCtl = (psbCtl != NULL);
  3045. if ( psb || psbCtl )
  3046. {
  3047. UINT wDisable;
  3048. RECT rcWindow;
  3049. POINT pt;
  3050. GetWindowRect(hwnd, &rcWindow);
  3051. POINTSTOPOINT(pt, lParam);
  3052. if ( TestWF(hwnd, WEFLAYOUTRTL) && !fVert )
  3053. {
  3054. MIRROR_POINT(rcWindow, pt);
  3055. }
  3056. pt.x -= rcWindow.left;
  3057. pt.y -= rcWindow.top;
  3058. if ( fCtl )
  3059. {
  3060. wDisable = psbCtl->_wDisableFlags;
  3061. }
  3062. else
  3063. {
  3064. wDisable = _GetWndSBDisableFlags(hwndNotify, fVert);
  3065. }
  3066. // Make sure the scrollbar isn't disabled.
  3067. if ( (wDisable & SB_DISABLE_MASK) != SB_DISABLE_MASK)
  3068. {
  3069. HMENU hMenu = ScrollBar_GetMenu(hwndNotify, fVert);
  3070. // Put up a menu and scroll accordingly.
  3071. if (hMenu != NULL)
  3072. {
  3073. int iCmd;
  3074. iCmd = TrackPopupMenuEx(hMenu,
  3075. TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
  3076. GET_X_LPARAM(lParam),
  3077. GET_Y_LPARAM(lParam),
  3078. hwndNotify,
  3079. NULL);
  3080. DestroyMenu(hMenu);
  3081. if (iCmd)
  3082. {
  3083. if ((iCmd & 0x00FF) == SB_THUMBPOSITION)
  3084. {
  3085. if ( fCtl )
  3086. {
  3087. _SBTrackInit(hwnd, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU);
  3088. }
  3089. else
  3090. {
  3091. _SBTrackInit(hwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU);
  3092. }
  3093. }
  3094. else
  3095. {
  3096. xxxDoScroll(hwnd, hwndNotify, (iCmd & 0x00FF), 0, fVert);
  3097. xxxDoScroll(hwnd, hwndNotify, SB_ENDSCROLL, 0, fVert);
  3098. }
  3099. }
  3100. }
  3101. }
  3102. }
  3103. }
  3104. //-------------------------------------------------------------------------
  3105. LRESULT CUxScrollBarCtl::WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  3106. {
  3107. LONG l;
  3108. LONG lres = 0;
  3109. int cx, cy;
  3110. UINT cmd;
  3111. UINT uSide;
  3112. HDC hdc;
  3113. RECT rc;
  3114. POINT pt;
  3115. BOOL fSizeReal;
  3116. HBRUSH hbrSave;
  3117. BOOL fSize;
  3118. PAINTSTRUCT ps;
  3119. DWORD dwStyle;
  3120. SCROLLINFO si;
  3121. LPSCROLLINFO lpsi = &si;
  3122. BOOL fRedraw = FALSE;
  3123. BOOL fScroll;
  3124. CUxScrollBarCtl* psb = CUxScrollBarCtl::FromHwnd( hwnd );
  3125. if (!psb && uMsg != WM_NCCREATE)
  3126. {
  3127. goto CallDWP;
  3128. }
  3129. CheckLock(hwnd);
  3130. ASSERT(IsWinEventNotifyDeferredOK());
  3131. VALIDATECLASSANDSIZE(((HWND)hwnd), uMsg, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
  3132. dwStyle = GetWindowStyle(hwnd);
  3133. fSize = (((LOBYTE(dwStyle)) & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
  3134. switch (uMsg)
  3135. {
  3136. case WM_NCCREATE:
  3137. if( NULL == psb )
  3138. {
  3139. psb = (CUxScrollBarCtl*)CUxScrollBar::Attach( hwnd, TRUE, FALSE );
  3140. }
  3141. goto CallDWP;
  3142. case WM_NCDESTROY:
  3143. CUxScrollBar::Detach(hwnd);
  3144. psb = NULL;
  3145. goto CallDWP;
  3146. case WM_CREATE:
  3147. /*
  3148. * Guard against lParam being NULL since the thunk allows it [51986]
  3149. */
  3150. if (lParam)
  3151. {
  3152. rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) +
  3153. ((LPCREATESTRUCT)lParam)->cx;
  3154. rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) +
  3155. ((LPCREATESTRUCT)lParam)->cy;
  3156. // This is because we can't just rev CardFile -- we should fix the
  3157. // problem here in case anyone else happened to have some EXTRA
  3158. // scroll styles on their scroll bar controls (jeffbog 03/21/94)
  3159. if (!TestWF((HWND)hwnd, WFWIN40COMPAT))
  3160. dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
  3161. if (!fSize)
  3162. {
  3163. l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams);
  3164. psb->_calc.data.pos = psb->_calc.data.posMin = LOWORD(l);
  3165. psb->_calc.data.posMax = HIWORD(l);
  3166. psb->_fVert = ((LOBYTE(dwStyle) & SBS_VERT) != 0);
  3167. psb->_calc.data.page = 0;
  3168. }
  3169. if (dwStyle & WS_DISABLED)
  3170. psb->_wDisableFlags = SB_DISABLE_MASK;
  3171. if (LOBYTE(dwStyle) & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) {
  3172. if (fSize) {
  3173. if (LOBYTE(dwStyle) & SBS_SIZEBOXBOTTOMRIGHTALIGN) {
  3174. rc.left = rc.right - SYSMET(CXVSCROLL);
  3175. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  3176. }
  3177. rc.right = rc.left + SYSMET(CXVSCROLL);
  3178. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  3179. } else {
  3180. if (LOBYTE(dwStyle) & SBS_VERT) {
  3181. if (LOBYTE(dwStyle) & SBS_LEFTALIGN)
  3182. rc.right = rc.left + SYSMET(CXVSCROLL);
  3183. else
  3184. rc.left = rc.right - SYSMET(CXVSCROLL);
  3185. } else {
  3186. if (LOBYTE(dwStyle) & SBS_TOPALIGN)
  3187. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  3188. else
  3189. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  3190. }
  3191. }
  3192. MoveWindow((HWND)hwnd, rc.left, rc.top, rc.right - rc.left,
  3193. rc.bottom - rc.top, FALSE);
  3194. }
  3195. } /* if */
  3196. else {
  3197. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING,
  3198. "UxScrollBarCtlWndProc - NULL lParam for WM_CREATE\n") ;
  3199. } /* else */
  3200. break;
  3201. case WM_SIZE:
  3202. if (GetFocus() != (HWND)hwnd)
  3203. break;
  3204. // scroll bar has the focus -- recalc it's thumb caret size
  3205. // no need to DeferWinEventNotify() - see CreateCaret below.
  3206. DestroyCaret();
  3207. // | |
  3208. // | FALL THRU |
  3209. // V V
  3210. case WM_SETFOCUS:
  3211. {
  3212. // REVIEW (phellyar) Do we want themed scroll bars to have
  3213. // a caret?
  3214. if ( !psb->GetTheme() )
  3215. {
  3216. SBCtlSetup(hwnd);
  3217. RECT rcWindow;
  3218. GetWindowRect( hwnd, &rcWindow );
  3219. cx = (psb->_fVert ? rcWindow.right - rcWindow.left
  3220. : psb->_calc.cpxThumb) - 2 * SYSMET(CXEDGE);
  3221. cy = (psb->_fVert ? psb->_calc.cpxThumb
  3222. : rcWindow.bottom - rcWindow.top) - 2 * SYSMET(CYEDGE);
  3223. #ifdef _VISUAL_DELTA_
  3224. cx -= (CARET_BORDERWIDTH * 2);
  3225. cy -= (CARET_BORDERWIDTH * 2);
  3226. #endif _VISUAL_DELTA_
  3227. CreateCaret((HWND)hwnd, (HBITMAP)1, cx, cy);
  3228. zzzSetSBCaretPos(hwnd);
  3229. ShowCaret((HWND)hwnd);
  3230. }
  3231. break;
  3232. }
  3233. case WM_KILLFOCUS:
  3234. DestroyCaret();
  3235. break;
  3236. case WM_ERASEBKGND:
  3237. /*
  3238. * Do nothing, but don't let DefWndProc() do it either.
  3239. * It will be erased when its painted.
  3240. */
  3241. return (LONG)TRUE;
  3242. case WM_PRINTCLIENT:
  3243. case WM_PAINT:
  3244. if ((hdc = (HDC)wParam) == NULL) {
  3245. hdc = BeginPaint((HWND)hwnd, (LPPAINTSTRUCT)&ps);
  3246. }
  3247. if (!fSize) {
  3248. SBCtlSetup(hwnd);
  3249. xxxDrawSB2((HWND)hwnd, &psb->_calc, hdc, psb->_fVert, psb->_wDisableFlags);
  3250. } else {
  3251. fSizeReal = TestWF((HWND)hwnd, WFSIZEBOX);
  3252. if (!fSizeReal)
  3253. SetWF((HWND)hwnd, WFSIZEBOX);
  3254. _DrawSizeBoxFromFrame((HWND)hwnd, hdc, 0, 0);
  3255. if (!fSizeReal)
  3256. ClrWF((HWND)hwnd, WFSIZEBOX);
  3257. }
  3258. if (wParam == 0L)
  3259. EndPaint((HWND)hwnd, (LPPAINTSTRUCT)&ps);
  3260. break;
  3261. case WM_GETDLGCODE:
  3262. return DLGC_WANTARROWS;
  3263. case WM_CONTEXTMENU:
  3264. {
  3265. HWND hwndParent = GetParent(hwnd);
  3266. if (hwndParent)
  3267. {
  3268. ScrollBar_Menu(hwndParent, hwnd, lParam, psb->_fVert);
  3269. }
  3270. break;
  3271. }
  3272. case WM_NCHITTEST:
  3273. if (LOBYTE(dwStyle) & SBS_SIZEGRIP) {
  3274. #ifdef USE_MIRRORING
  3275. /*
  3276. * If the scroll bar is RTL mirrored, then
  3277. * mirror the hittest of the grip location.
  3278. */
  3279. if (TestWF((HWND)hwnd, WEFLAYOUTRTL))
  3280. return HTBOTTOMLEFT;
  3281. else
  3282. #endif
  3283. return HTBOTTOMRIGHT;
  3284. } else {
  3285. goto CallDWP;
  3286. }
  3287. break;
  3288. case WM_MOUSELEAVE:
  3289. //xxxHotTrackSBCtl(hwnd, 0, FALSE);
  3290. psb->SetHotComponent(HTNOWHERE, psb->_fVert);
  3291. InvalidateRect(hwnd, NULL, TRUE);
  3292. break;
  3293. case WM_MOUSEMOVE:
  3294. {
  3295. INT ht;
  3296. if (psb->GetHotComponent(psb->_fVert) == 0)
  3297. {
  3298. TRACKMOUSEEVENT tme;
  3299. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  3300. tme.dwFlags = TME_LEAVE;
  3301. tme.hwndTrack = hwnd;
  3302. tme.dwHoverTime = 0;
  3303. TrackMouseEvent(&tme);
  3304. }
  3305. pt.x = GET_X_LPARAM(lParam);
  3306. pt.y = GET_Y_LPARAM(lParam);
  3307. ht = HitTestScrollBar((HWND)hwnd, psb->_fVert, pt);
  3308. if (psb->GetHotComponent(psb->_fVert) != ht)
  3309. {
  3310. //xxxHotTrackSBCtl(hwnd, ht, TRUE);
  3311. psb->SetHotComponent(ht, psb->_fVert);
  3312. InvalidateRect(hwnd, NULL, TRUE);
  3313. }
  3314. break;
  3315. }
  3316. case WM_LBUTTONDBLCLK:
  3317. cmd = SC_ZOOM;
  3318. if (fSize)
  3319. goto postmsg;
  3320. /*
  3321. *** FALL THRU **
  3322. */
  3323. case WM_LBUTTONDOWN:
  3324. //
  3325. // Note that SBS_SIZEGRIP guys normally won't ever see button
  3326. // downs. This is because they return HTBOTTOMRIGHT to
  3327. // WindowHitTest handling. This will walk up the parent chain
  3328. // to the first sizeable ancestor, bailing out at caption windows
  3329. // of course. That dude, if he exists, will handle the sizing
  3330. // instead.
  3331. //
  3332. if (!fSize) {
  3333. if (TestWF((HWND)hwnd, WFTABSTOP)) {
  3334. SetFocus((HWND)hwnd);
  3335. }
  3336. HideCaret((HWND)hwnd);
  3337. SBCtlSetup(hwnd);
  3338. /*
  3339. * SBCtlSetup enters SEM_SB, and _SBTrackInit leaves it.
  3340. */
  3341. _SBTrackInit((HWND)hwnd, lParam, 0, (GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  3342. break;
  3343. } else {
  3344. cmd = SC_SIZE;
  3345. postmsg:
  3346. pt.x = GET_X_LPARAM(lParam);
  3347. pt.y = GET_Y_LPARAM(lParam);
  3348. ClientToScreen((HWND)hwnd, &pt);
  3349. lParam = MAKELONG(pt.x, pt.y);
  3350. /*
  3351. * convert HT value into a move value. This is bad,
  3352. * but this is purely temporary.
  3353. */
  3354. #ifdef USE_MIRRORING
  3355. if (TestWF(GetParent(hwnd),WEFLAYOUTRTL))
  3356. {
  3357. uSide = HTBOTTOMLEFT;
  3358. }
  3359. else
  3360. #endif
  3361. {
  3362. uSide = HTBOTTOMRIGHT;
  3363. }
  3364. ThreadLock(((HWND)hwnd)->hwndParent, &tlpwndParent);
  3365. SendMessage(GetParent(hwnd), WM_SYSCOMMAND,
  3366. (cmd | (uSide - HTSIZEFIRST + 1)), lParam);
  3367. ThreadUnlock(&tlpwndParent);
  3368. }
  3369. break;
  3370. case WM_KEYUP:
  3371. switch (wParam) {
  3372. case VK_HOME:
  3373. case VK_END:
  3374. case VK_PRIOR:
  3375. case VK_NEXT:
  3376. case VK_LEFT:
  3377. case VK_UP:
  3378. case VK_RIGHT:
  3379. case VK_DOWN:
  3380. /*
  3381. * Send end scroll uMsg when user up clicks on keyboard
  3382. * scrolling.
  3383. *
  3384. * DoScroll does thread locking on these two pwnds -
  3385. * this is ok since they are not used after this
  3386. * call.
  3387. */
  3388. xxxDoScroll( (HWND)hwnd, GetParent(hwnd),
  3389. SB_ENDSCROLL, 0, psb->_fVert
  3390. );
  3391. break;
  3392. default:
  3393. break;
  3394. }
  3395. break;
  3396. case WM_KEYDOWN:
  3397. switch (wParam) {
  3398. case VK_HOME:
  3399. wParam = SB_TOP;
  3400. goto KeyScroll;
  3401. case VK_END:
  3402. wParam = SB_BOTTOM;
  3403. goto KeyScroll;
  3404. case VK_PRIOR:
  3405. wParam = SB_PAGEUP;
  3406. goto KeyScroll;
  3407. case VK_NEXT:
  3408. wParam = SB_PAGEDOWN;
  3409. goto KeyScroll;
  3410. case VK_LEFT:
  3411. case VK_UP:
  3412. wParam = SB_LINEUP;
  3413. goto KeyScroll;
  3414. case VK_RIGHT:
  3415. case VK_DOWN:
  3416. wParam = SB_LINEDOWN;
  3417. KeyScroll:
  3418. /*
  3419. * DoScroll does thread locking on these two pwnds -
  3420. * this is ok since they are not used after this
  3421. * call.
  3422. */
  3423. xxxDoScroll((HWND)hwnd, GetParent(hwnd), (int)wParam, 0, psb->_fVert
  3424. );
  3425. break;
  3426. default:
  3427. break;
  3428. }
  3429. break;
  3430. case WM_ENABLE:
  3431. return SendMessage((HWND)hwnd, SBM_ENABLE_ARROWS,
  3432. (wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
  3433. case SBM_ENABLE_ARROWS:
  3434. /*
  3435. * This is used to enable/disable the arrows in a SB ctrl
  3436. */
  3437. return (LONG)xxxEnableSBCtlArrows((HWND)hwnd, (UINT)wParam);
  3438. case SBM_GETPOS:
  3439. return (LONG)psb->_calc.data.pos;
  3440. case SBM_GETRANGE:
  3441. *((LPINT)wParam) = psb->_calc.data.posMin;
  3442. *((LPINT)lParam) = psb->_calc.data.posMax;
  3443. return MAKELRESULT(LOWORD(psb->_calc.data.posMin), LOWORD(psb->_calc.data.posMax));
  3444. case SBM_GETSCROLLINFO:
  3445. return (LONG)_SBGetParms((HWND)hwnd, SB_CTL, (PSBDATA)&psb->_calc, (LPSCROLLINFO) lParam);
  3446. case SBM_SETRANGEREDRAW:
  3447. fRedraw = TRUE;
  3448. case SBM_SETRANGE:
  3449. // Save the old values of Min and Max for return value
  3450. si.cbSize = sizeof(si);
  3451. // si.nMin = LOWORD(lParam);
  3452. // si.nMax = HIWORD(lParam);
  3453. si.nMin = (int)wParam;
  3454. si.nMax = (int)lParam;
  3455. si.fMask = SIF_RANGE | SIF_RETURNOLDPOS;
  3456. goto SetInfo;
  3457. case SBM_SETPOS:
  3458. fRedraw = (BOOL) lParam;
  3459. si.cbSize = sizeof(si);
  3460. si.fMask = SIF_POS | SIF_RETURNOLDPOS;
  3461. si.nPos = (int)wParam;
  3462. goto SetInfo;
  3463. case SBM_SETSCROLLINFO:
  3464. {
  3465. lpsi = (LPSCROLLINFO) lParam;
  3466. fRedraw = (BOOL) wParam;
  3467. SetInfo:
  3468. fScroll = TRUE;
  3469. lres = SBSetParms((PSBDATA)&psb->_calc, lpsi, &fScroll, &lres);
  3470. if (SBSetParms((PSBDATA)&psb->_calc, lpsi, &fScroll, &lres))
  3471. {
  3472. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, hwnd, OBJID_CLIENT, INDEX_SCROLLBAR_SELF);
  3473. }
  3474. if (!fRedraw)
  3475. return lres;
  3476. /*
  3477. * We must set the new position of the caret irrespective of
  3478. * whether the window is visible or not;
  3479. * Still, this will work only if the app has done a xxxSetScrollPos
  3480. * with fRedraw = TRUE;
  3481. * Fix for Bug #5188 --SANKAR-- 10-15-89
  3482. * No need to DeferWinEventNotify since hwnd is locked.
  3483. */
  3484. HideCaret((HWND)hwnd);
  3485. SBCtlSetup(hwnd);
  3486. zzzSetSBCaretPos(hwnd);
  3487. /*
  3488. ** The following ShowCaret() must be done after the DrawThumb2(),
  3489. ** otherwise this caret will be erased by DrawThumb2() resulting
  3490. ** in this bug:
  3491. ** Fix for Bug #9263 --SANKAR-- 02-09-90
  3492. *
  3493. */
  3494. /*
  3495. *********** ShowCaret((HWND)hwnd); ******
  3496. */
  3497. if (_FChildVisible((HWND)hwnd) && fRedraw)
  3498. {
  3499. UINT wDisable;
  3500. HBRUSH hbrUse;
  3501. if (!fScroll)
  3502. fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
  3503. wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
  3504. xxxEnableScrollBar((HWND) hwnd, SB_CTL, wDisable);
  3505. hdc = GetWindowDC((HWND)hwnd);
  3506. if (hdc)
  3507. {
  3508. BOOL fOwnerBrush = FALSE;
  3509. hbrUse = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  3510. hbrSave = SelectBrush(hdc, hbrUse);
  3511. // Before we used to only hideshowthumb() if the mesage was
  3512. // not SBM_SETPOS. I am not sure why but this case was ever
  3513. // needed for win 3.x but on NT it resulted in trashing the border
  3514. // of the scrollbar when the app called SetScrollPos() during
  3515. // scrollbar tracking. - mikehar 8/26
  3516. DrawThumb2((HWND)hwnd, &psb->_calc, hdc, hbrUse, psb->_fVert, psb->_wDisableFlags, fOwnerBrush);
  3517. SelectBrush(hdc, hbrSave);
  3518. ReleaseDC(hwnd, hdc);
  3519. }
  3520. }
  3521. /*
  3522. * This ShowCaret() has been moved to this place from above
  3523. * Fix for Bug #9263 --SANKAR-- 02-09-90
  3524. */
  3525. ShowCaret((HWND)hwnd);
  3526. return lres;
  3527. }
  3528. case WM_GETOBJECT:
  3529. if(lParam == OBJID_QUERYCLASSNAMEIDX)
  3530. {
  3531. return MSAA_CLASSNAMEIDX_SCROLLBAR;
  3532. }
  3533. break;
  3534. case WM_THEMECHANGED:
  3535. psb->ChangeSBTheme();
  3536. InvalidateRect(hwnd, NULL, TRUE);
  3537. break;
  3538. default:
  3539. CallDWP:
  3540. return DefWindowProc((HWND)hwnd, uMsg, wParam, lParam);
  3541. }
  3542. return 0L;
  3543. }
  3544. //-------------------------------------------------------------------------//
  3545. // Globals
  3546. static HBRUSH g_hbrGray = NULL;
  3547. //-------------------------------------------------------------------------//
  3548. HBRUSH _UxGrayBrush(VOID)
  3549. {
  3550. if( NULL == g_hbrGray )
  3551. {
  3552. CONST static WORD patGray[8] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
  3553. HBITMAP hbmGray;
  3554. /*
  3555. * Create a gray brush to be used with GrayString
  3556. */
  3557. if( (hbmGray = CreateBitmap(8, 8, 1, 1, (LPBYTE)patGray)) != NULL )
  3558. {
  3559. g_hbrGray = CreatePatternBrush(hbmGray);
  3560. DeleteObject( hbmGray );
  3561. }
  3562. }
  3563. return g_hbrGray;
  3564. }
  3565. //-------------------------------------------------------------------------//
  3566. void _UxFreeGDIResources()
  3567. {
  3568. DeleteObject( g_hbrGray );
  3569. }
  3570. //-------------------------------------------------------------------------//
  3571. void _RedrawFrame( HWND hwnd )
  3572. {
  3573. CheckLock(hwnd);
  3574. /*
  3575. * We always want to call xxxSetWindowPos, even if invisible or iconic,
  3576. * because we need to make sure the WM_NCCALCSIZE message gets sent.
  3577. */
  3578. SetWindowPos( hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
  3579. SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
  3580. }
  3581. //-------------------------------------------------------------------------//
  3582. // from winmgr.c
  3583. BOOL _FChildVisible( HWND hwnd )
  3584. {
  3585. while (GetWindowStyle( hwnd ) & WS_CHILD )
  3586. {
  3587. if( NULL == (hwnd = GetParent(hwnd)) )
  3588. if (!TestWF(hwnd, WFVISIBLE))
  3589. return FALSE;
  3590. }
  3591. return TRUE;
  3592. }
  3593. //-------------------------------------------------------------------------//
  3594. //
  3595. // SizeBoxHwnd
  3596. //
  3597. // Returns the HWND that will be sized if the user drags in the given window's
  3598. // sizebox -- If NULL, then the sizebox is not needed
  3599. //
  3600. // Criteria for choosing what window will be sized:
  3601. // find first sizeable parent; if that parent is not maximized and the child's
  3602. // bottom, right corner is within a scroll bar height and width of the parent's
  3603. //
  3604. HWND SizeBoxHwnd(HWND hwnd)
  3605. {
  3606. BOOL bMirroredSizeBox = (BOOL)TestWF(hwnd, WEFLAYOUTRTL);
  3607. RECT rc;
  3608. int xbrChild;
  3609. int ybrChild;
  3610. GetWindowRect(hwnd, &rc);
  3611. xbrChild = bMirroredSizeBox ? rc.left : rc.right;
  3612. ybrChild = rc.bottom;
  3613. while (hwnd != HWND_DESKTOP)
  3614. {
  3615. if (TestWF(hwnd, WFSIZEBOX))
  3616. {
  3617. //
  3618. // First sizeable parent found
  3619. //
  3620. int xbrParent;
  3621. int ybrParent;
  3622. if (TestWF(hwnd, WFMAXIMIZED))
  3623. {
  3624. return NULL;
  3625. }
  3626. GetWindowRect(hwnd, &rc);
  3627. xbrParent = bMirroredSizeBox ? rc.left : rc.right;
  3628. ybrParent = rc.bottom;
  3629. //
  3630. // the sizebox dude is within an EDGE of the client's bottom
  3631. // right corner (left corner for mirrored windows), let this succeed.
  3632. // That way people who draw their own sunken clients will be happy.
  3633. //
  3634. if (bMirroredSizeBox)
  3635. {
  3636. if ((xbrChild - SYSMETRTL(CXFRAME) > xbrParent) || (ybrChild + SYSMETRTL(CYFRAME) < ybrParent))
  3637. {
  3638. //
  3639. // Child's bottom, left corner of SIZEBOX isn't close enough
  3640. // to bottom left of parent's client.
  3641. //
  3642. return NULL;
  3643. }
  3644. }
  3645. else
  3646. {
  3647. if ((xbrChild + SYSMETRTL(CXFRAME) < xbrParent) || (ybrChild + SYSMETRTL(CYFRAME) < ybrParent))
  3648. {
  3649. //
  3650. // Child's bottom, right corner of SIZEBOX isn't close enough
  3651. // to bottom right of parent's client.
  3652. //
  3653. return NULL;
  3654. }
  3655. }
  3656. return hwnd;
  3657. }
  3658. if (!TestWF(hwnd, WFCHILD) || TestWF(hwnd, WFCPRESENT))
  3659. {
  3660. break;
  3661. }
  3662. hwnd = GetParent(hwnd);
  3663. }
  3664. return NULL;
  3665. }
  3666. //-------------------------------------------------------------------------//
  3667. //
  3668. // _DrawPushButton
  3669. //
  3670. // From ntuser\rtl\draw.c
  3671. // Draws a push style button in the given state. Adjusts passed in rectangle
  3672. // if desired.
  3673. //
  3674. // Algorithm:
  3675. // Depending on the state we either draw
  3676. // - raised edge (undepressed)
  3677. // - sunken edge with extra shadow (depressed)
  3678. // If it is an option push button (a push button that is
  3679. // really a check button or a radio button like buttons
  3680. // in tool bars), and it is checked, then we draw it
  3681. // depressed with a different fill in the middle.
  3682. //
  3683. VOID _DrawPushButton(HWND hwnd, HDC hdc, LPRECT lprc, UINT state, UINT flags, BOOL fVert)
  3684. {
  3685. RECT rc;
  3686. HBRUSH hbrMiddle;
  3687. DWORD rgbBack = 0;
  3688. DWORD rgbFore = 0;
  3689. BOOL fDither;
  3690. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  3691. if ( !hTheme )
  3692. {
  3693. rc = *lprc;
  3694. DrawEdge(hdc,
  3695. &rc,
  3696. (state & (DFCS_PUSHED | DFCS_CHECKED)) ? EDGE_SUNKEN : EDGE_RAISED,
  3697. (UINT)(BF_ADJUST | BF_RECT | (flags & (BF_SOFT | BF_FLAT | BF_MONO))));
  3698. //
  3699. // BOGUS
  3700. // On monochrome, need to do something to make pushed buttons look
  3701. // better.
  3702. //
  3703. //
  3704. // Fill in middle. If checked, use dither brush (gray brush) with
  3705. // black becoming normal color.
  3706. //
  3707. fDither = FALSE;
  3708. if (state & DFCS_CHECKED)
  3709. {
  3710. if ((GetDeviceCaps(hdc, BITSPIXEL) /*gpsi->BitCount*/ < 8) || (SYSRGBRTL(3DHILIGHT) == RGB(255,255,255)))
  3711. {
  3712. hbrMiddle = _UxGrayBrush();
  3713. rgbBack = SetBkColor(hdc, SYSRGBRTL(3DHILIGHT));
  3714. rgbFore = SetTextColor(hdc, SYSRGBRTL(3DFACE));
  3715. fDither = TRUE;
  3716. }
  3717. else
  3718. {
  3719. hbrMiddle = SYSHBR(3DHILIGHT);
  3720. }
  3721. }
  3722. else
  3723. {
  3724. hbrMiddle = SYSHBR(3DFACE);
  3725. }
  3726. FillRect(hdc, &rc, hbrMiddle);
  3727. if (fDither)
  3728. {
  3729. SetBkColor(hdc, rgbBack);
  3730. SetTextColor(hdc, rgbFore);
  3731. }
  3732. if (flags & BF_ADJUST)
  3733. {
  3734. *lprc = rc;
  3735. }
  3736. }
  3737. else
  3738. {
  3739. INT iStateId;
  3740. INT iPartId;
  3741. SIZE sizeGrip;
  3742. RECT rcContent;
  3743. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  3744. if ((CUxScrollBarCtl::GetDisableFlags(hwnd) & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
  3745. {
  3746. iStateId = SCRBS_DISABLED;
  3747. }
  3748. else if (pSBTrack && ((BOOL)pSBTrack->fTrackVert == fVert) && (pSBTrack->cmdSB == SB_THUMBPOSITION))
  3749. {
  3750. iStateId = SCRBS_PRESSED;
  3751. }
  3752. else if (CUxScrollBar::GetSBHotComponent(hwnd, fVert) == HTSCROLLTHUMB)
  3753. {
  3754. iStateId = SCRBS_HOT;
  3755. }
  3756. else
  3757. {
  3758. iStateId = SCRBS_NORMAL;
  3759. }
  3760. iPartId = fVert ? SBP_THUMBBTNVERT : SBP_THUMBBTNHORZ;
  3761. //
  3762. // Draw the thumb
  3763. //
  3764. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, lprc, 0);
  3765. //
  3766. // Lastly draw the little gripper image, if there is enough room
  3767. //
  3768. if ( SUCCEEDED(GetThemeBackgroundContentRect(hTheme, hdc, iPartId, iStateId, lprc, &rcContent)) )
  3769. {
  3770. iPartId = fVert ? SBP_GRIPPERVERT : SBP_GRIPPERHORZ;
  3771. if ( SUCCEEDED(GetThemePartSize(hTheme, hdc, iPartId, iStateId, &rcContent, TS_TRUE, &sizeGrip)) )
  3772. {
  3773. if ( (sizeGrip.cx < RECTWIDTH(&rcContent)) && (sizeGrip.cy < RECTHEIGHT(&rcContent)) )
  3774. {
  3775. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, &rcContent, 0);
  3776. }
  3777. }
  3778. }
  3779. }
  3780. }
  3781. // user.h
  3782. #define CheckMsgFilter(wMsg, wMsgFilterMin, wMsgFilterMax) \
  3783. ( ((wMsgFilterMin) == 0 && (wMsgFilterMax) == 0xFFFFFFFF) \
  3784. || ( ((wMsgFilterMin) > (wMsgFilterMax)) \
  3785. ? (((wMsg) < (wMsgFilterMax)) || ((wMsg) > (wMsgFilterMin))) \
  3786. : (((wMsg) >= (wMsgFilterMin)) && ((wMsg) <= (wMsgFilterMax)))))
  3787. #define SYS_ALTERNATE 0x2000
  3788. #define SYS_PREVKEYSTATE 0x4000
  3789. // mnaccel.h
  3790. /***************************************************************************\
  3791. * _SysToChar
  3792. *
  3793. * EXIT: If the message was not made with the ALT key down, convert
  3794. * the message from a WM_SYSKEY* to a WM_KEY* message.
  3795. *
  3796. * IMPLEMENTATION:
  3797. * The 0x2000 bit in the hi word of lParam is set if the key was
  3798. * made with the ALT key down.
  3799. *
  3800. * History:
  3801. * 11/30/90 JimA Ported.
  3802. \***************************************************************************/
  3803. UINT _SysToChar(
  3804. UINT message,
  3805. LPARAM lParam)
  3806. {
  3807. if (CheckMsgFilter(message, WM_SYSKEYDOWN, WM_SYSDEADCHAR) &&
  3808. !(HIWORD(lParam) & SYS_ALTERNATE))
  3809. return (message - (WM_SYSKEYDOWN - WM_KEYDOWN));
  3810. return message;
  3811. }