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.

4486 lines
131 KiB

  1. //---------------------------------------------------------------------------
  2. #include "ctlspriv.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(
  1111. HWND hwndOwner,
  1112. HWND hwndCtl,
  1113. HDC hdc,
  1114. UINT uMsg,
  1115. BOOL* pfOwnerBrush)
  1116. {
  1117. HBRUSH hbrRet = (HBRUSH)DefWindowProc(hwndOwner, uMsg, (WPARAM)hdc, (LPARAM)hwndCtl);
  1118. BOOL fOwnerBrush = FALSE;
  1119. if (hwndOwner && (GetWindowThreadProcessId(hwndOwner, NULL) == GetCurrentThreadId()))
  1120. {
  1121. HBRUSH hbrOwner = (HBRUSH)SendMessage(hwndOwner, uMsg, (WPARAM)hdc, (LPARAM)hwndCtl);
  1122. if (hbrOwner && (hbrOwner != hbrRet))
  1123. {
  1124. fOwnerBrush = TRUE;
  1125. hbrRet = hbrOwner;
  1126. }
  1127. }
  1128. if (pfOwnerBrush)
  1129. {
  1130. *pfOwnerBrush = fOwnerBrush;
  1131. }
  1132. return hbrRet;
  1133. }
  1134. //-------------------------------------------------------------------------
  1135. HBRUSH ScrollBar_GetControlBrush(HWND hwnd, HDC hdc, UINT uMsg, BOOL *pfOwnerBrush)
  1136. {
  1137. HWND hwndSend;
  1138. hwndSend = TESTFLAG(GetWindowStyle(hwnd), WS_POPUP) ? GetOwner(hwnd) : GetParent(hwnd);
  1139. if (hwndSend == NULL)
  1140. {
  1141. hwndSend = hwnd;
  1142. }
  1143. return ScrollBar_GetControlColor(hwndSend, hwnd, hdc, uMsg, pfOwnerBrush);
  1144. }
  1145. //-------------------------------------------------------------------------
  1146. HBRUSH ScrollBar_GetColorObjects(HWND hwnd, HDC hdc, BOOL *pfOwnerBrush)
  1147. {
  1148. HBRUSH hbrRet;
  1149. CheckLock(hwnd);
  1150. // Use the scrollbar color even if the scrollbar is disabeld.
  1151. if (!IsScrollBarControl(hwnd))
  1152. {
  1153. hbrRet = (HBRUSH)DefWindowProc(hwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(hwnd));
  1154. }
  1155. else
  1156. {
  1157. // B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
  1158. // owner. If the app doesn't process the message, DefWindowProc32
  1159. // will always return the appropriate system brush. If the app.
  1160. // returns an invalid object, GetControlBrush will call DWP for
  1161. // the default brush. Thus hbrRet doesn't need any validation
  1162. // here.
  1163. hbrRet = ScrollBar_GetControlBrush(hwnd, hdc, WM_CTLCOLORSCROLLBAR, pfOwnerBrush);
  1164. }
  1165. return hbrRet;
  1166. }
  1167. //-------------------------------------------------------------------------
  1168. //
  1169. // ScrollBar_PaintTrack
  1170. //
  1171. // Draws lines & middle of thumb groove
  1172. // Note that pw points into prc. Moreover, note that both pw & prc are
  1173. // pointers, so *prc better not be on the stack.
  1174. //
  1175. void ScrollBar_PaintTrack(HWND hwnd, HDC hdc, HBRUSH hbr, LPRECT prc, BOOL fVert, INT iPartId, BOOL fOwnerBrush)
  1176. {
  1177. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1178. // If the scrollbar is unthemed or
  1179. // #374054 we've been passed an brush defined by the owner, paint
  1180. // the shaft using the brush
  1181. if ((hTheme == NULL) || (fOwnerBrush == TRUE))
  1182. {
  1183. if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == SYSHBR(SCROLLBAR)) || (hbr == _UxGrayBrush()) )
  1184. {
  1185. FillRect(hdc, prc, hbr);
  1186. }
  1187. else
  1188. {
  1189. #ifdef PORTPORT // we need SystemParametersInfo for _UxGrayBrush
  1190. // Draw sides
  1191. CopyRect(&rc, prc);
  1192. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT |
  1193. (fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
  1194. #endif PORTPORT
  1195. // Fill middle
  1196. FillRect(hdc, prc, hbr);
  1197. }
  1198. }
  1199. else
  1200. {
  1201. INT iStateId;
  1202. INT ht = CUxScrollBar::GetSBHotComponent(hwnd, fVert);
  1203. if ((CUxScrollBarCtl::GetDisableFlags(hwnd) & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
  1204. {
  1205. iStateId = SCRBS_DISABLED;
  1206. }
  1207. else if ((((iPartId == SBP_LOWERTRACKHORZ) || (iPartId == SBP_LOWERTRACKVERT)) && (ht == HTSCROLLUPPAGE)) ||
  1208. (((iPartId == SBP_UPPERTRACKHORZ) || (iPartId == SBP_UPPERTRACKVERT)) && (ht == HTSCROLLDOWNPAGE)))
  1209. {
  1210. iStateId = SCRBS_HOT;
  1211. }
  1212. else
  1213. {
  1214. iStateId = SCRBS_NORMAL;
  1215. }
  1216. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, prc, 0);
  1217. }
  1218. }
  1219. /***************************************************************************\
  1220. * CalcTrackDragRect
  1221. *
  1222. * Give the rectangle for a scrollbar in pSBTrack->pSBCalc,
  1223. * calculate pSBTrack->rcTrack, the rectangle where tracking
  1224. * may occur without cancelling the thumbdrag operation.
  1225. *
  1226. \***************************************************************************/
  1227. void CalcTrackDragRect(PSBTRACK pSBTrack) {
  1228. int cx;
  1229. int cy;
  1230. LPINT pwX, pwY;
  1231. //
  1232. // Point pwX and pwY at the parts of the rectangle
  1233. // corresponding to pSBCalc->pxLeft, pxTop, etc.
  1234. //
  1235. // pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
  1236. // scrollbar and the top edge of horizontal one.
  1237. // pSBTrack->pSBCalc->pxTop is the top of a vertical
  1238. // scrollbar and the left of horizontal one.
  1239. // etc...
  1240. //
  1241. // Point pwX and pwY to the corresponding parts
  1242. // of pSBTrack->rcTrack.
  1243. //
  1244. pwX = pwY = (LPINT)&pSBTrack->rcTrack;
  1245. if (pSBTrack->fTrackVert) {
  1246. cy = SYSMET(CYVTHUMB);
  1247. pwY++;
  1248. } else {
  1249. cy = SYSMET(CXHTHUMB);
  1250. pwX++;
  1251. }
  1252. /*
  1253. * Later5.0 GerardoB: People keep complaining about this tracking region
  1254. * being too narrow so let's make it wider while PM decides what to do
  1255. * about it.
  1256. * We also used to have some hard coded min and max values but that should
  1257. * depend on some metric, if at all needed.
  1258. */
  1259. cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8;
  1260. cy *= 2;
  1261. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx;
  1262. *(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy;
  1263. *(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx;
  1264. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy;
  1265. }
  1266. void RecalcTrackRect(PSBTRACK pSBTrack) {
  1267. LPINT pwX, pwY;
  1268. RECT rcSB;
  1269. if (!pSBTrack->fCtlSB)
  1270. CUxScrollBar::Calc(pSBTrack->hwndTrack, pSBTrack->pSBCalc, NULL, pSBTrack->fTrackVert);
  1271. pwX = (LPINT)&rcSB;
  1272. pwY = pwX + 1;
  1273. if (!pSBTrack->fTrackVert)
  1274. pwX = pwY--;
  1275. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft;
  1276. *(pwY + 0) = pSBTrack->pSBCalc->pxTop;
  1277. *(pwX + 2) = pSBTrack->pSBCalc->pxRight;
  1278. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
  1279. switch(pSBTrack->cmdSB) {
  1280. case SB_LINEUP:
  1281. *(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow;
  1282. break;
  1283. case SB_LINEDOWN:
  1284. *(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow;
  1285. break;
  1286. case SB_PAGEUP:
  1287. *(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow;
  1288. *(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop;
  1289. break;
  1290. case SB_THUMBPOSITION:
  1291. CalcTrackDragRect(pSBTrack);
  1292. break;
  1293. case SB_PAGEDOWN:
  1294. *(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom;
  1295. *(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow;
  1296. break;
  1297. }
  1298. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  1299. CopyRect(&pSBTrack->rcTrack, &rcSB);
  1300. }
  1301. }
  1302. //-------------------------------------------------------------------------
  1303. void DrawThumb2(
  1304. HWND hwnd,
  1305. PSBCALC pSBCalc,
  1306. HDC hdc,
  1307. HBRUSH hbr,
  1308. BOOL fVert,
  1309. UINT wDisable, // Disabled flags for the scroll bar
  1310. BOOL fOwnerBrush)
  1311. {
  1312. int *pLength;
  1313. int *pWidth;
  1314. RECT rcSB;
  1315. PSBTRACK pSBTrack;
  1316. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1317. //
  1318. // Bail out if the scrollbar has an empty rect
  1319. //
  1320. if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight))
  1321. {
  1322. return;
  1323. }
  1324. pLength = (LPINT)&rcSB;
  1325. if (fVert)
  1326. {
  1327. pWidth = pLength++;
  1328. }
  1329. else
  1330. {
  1331. pWidth = pLength + 1;
  1332. }
  1333. pWidth[0] = pSBCalc->pxLeft;
  1334. pWidth[2] = pSBCalc->pxRight;
  1335. // If were're not themed and both buttons are disabled OR there isn't
  1336. // enough room to draw a thumb just draw the track and run.
  1337. //
  1338. // When we are themed the thumb can be drawn disabled.
  1339. if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
  1340. ((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb))
  1341. {
  1342. // draw the entire track
  1343. pLength[0] = pSBCalc->pxUpArrow;
  1344. pLength[2] = pSBCalc->pxDownArrow;
  1345. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ, fOwnerBrush);
  1346. return;
  1347. }
  1348. if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop)
  1349. {
  1350. // draw the track above the thumb
  1351. pLength[0] = pSBCalc->pxUpArrow;
  1352. pLength[2] = pSBCalc->pxThumbTop;
  1353. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ, fOwnerBrush);
  1354. }
  1355. if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow)
  1356. {
  1357. // draw the track below the thumb
  1358. pLength[0] = pSBCalc->pxThumbBottom;
  1359. pLength[2] = pSBCalc->pxDownArrow;
  1360. ScrollBar_PaintTrack(hwnd, hdc, hbr, &rcSB, fVert, fVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ, fOwnerBrush);
  1361. }
  1362. //
  1363. // Draw elevator
  1364. //
  1365. pLength[0] = pSBCalc->pxThumbTop;
  1366. pLength[2] = pSBCalc->pxThumbBottom;
  1367. // Not soft!
  1368. _DrawPushButton(hwnd, hdc, &rcSB, 0, 0, fVert);
  1369. #ifdef _VISUAL_DELTA_
  1370. InflateRect( &rcSB, -CARET_BORDERWIDTH, -CARET_BORDERWIDTH);
  1371. DrawEdge( hdc, &rcSB, EDGE_SUNKEN, BF_RECT );
  1372. #endif _VISUAL_DELTA_
  1373. /*
  1374. * If we're tracking a page scroll, then we've obliterated the hilite.
  1375. * We need to correct the hiliting rectangle, and rehilite it.
  1376. */
  1377. pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  1378. if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) &&
  1379. (hwnd == pSBTrack->hwndTrack) &&
  1380. (BOOL)pSBTrack->fTrackVert == fVert) {
  1381. if (pSBTrack->fTrackRecalc) {
  1382. RecalcTrackRect(pSBTrack);
  1383. pSBTrack->fTrackRecalc = FALSE;
  1384. }
  1385. pLength = (int *)&pSBTrack->rcTrack;
  1386. if (fVert)
  1387. pLength++;
  1388. if (pSBTrack->cmdSB == SB_PAGEUP)
  1389. pLength[2] = pSBCalc->pxThumbTop;
  1390. else
  1391. pLength[0] = pSBCalc->pxThumbBottom;
  1392. if (pLength[0] < pLength[2])
  1393. {
  1394. if (!hTheme)
  1395. {
  1396. InvertRect(hdc, &pSBTrack->rcTrack);
  1397. }
  1398. else
  1399. {
  1400. DrawThemeBackground(hTheme,
  1401. hdc,
  1402. pSBTrack->cmdSB == SB_PAGEUP ?
  1403. (fVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ) :
  1404. (fVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ),
  1405. SCRBS_PRESSED,
  1406. &pSBTrack->rcTrack,
  1407. 0);
  1408. }
  1409. }
  1410. }
  1411. }
  1412. /***************************************************************************\
  1413. * xxxDrawSB2
  1414. *
  1415. *
  1416. *
  1417. * History:
  1418. \***************************************************************************/
  1419. void xxxDrawSB2(
  1420. HWND hwnd,
  1421. PSBCALC pSBCalc,
  1422. HDC hdc,
  1423. BOOL fVert,
  1424. UINT wDisable)
  1425. {
  1426. int cLength;
  1427. int cWidth;
  1428. int *pwX;
  1429. int *pwY;
  1430. HBRUSH hbr;
  1431. HBRUSH hbrSave;
  1432. int cpxArrow;
  1433. RECT rc, rcSB;
  1434. COLORREF crText, crBk;
  1435. HTHEME hTheme;
  1436. INT ht;
  1437. INT iStateId;
  1438. BOOL fOwnerBrush = FALSE;
  1439. CheckLock(hwnd);
  1440. cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2;
  1441. cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
  1442. if ((cLength <= 0) || (cWidth <= 0)) {
  1443. return;
  1444. }
  1445. if (fVert)
  1446. {
  1447. cpxArrow = SYSMET(CYVSCROLL);
  1448. }
  1449. else
  1450. {
  1451. cpxArrow = SYSMET(CXHSCROLL);
  1452. }
  1453. // Save background and DC color, since they get changed in
  1454. // ScrollBar_GetColorObjects. Restore before we return.
  1455. crBk = GetBkColor(hdc);
  1456. crText = GetTextColor(hdc);
  1457. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1458. if (cLength > cpxArrow)
  1459. {
  1460. cLength = cpxArrow;
  1461. }
  1462. pwX = (int *)&rcSB;
  1463. pwY = pwX + 1;
  1464. if (!fVert)
  1465. {
  1466. pwX = pwY--;
  1467. }
  1468. pwX[0] = pSBCalc->pxLeft;
  1469. pwY[0] = pSBCalc->pxTop;
  1470. pwX[2] = pSBCalc->pxRight;
  1471. pwY[2] = pSBCalc->pxBottom;
  1472. hbrSave = SelectBrush(hdc, SYSHBR(BTNTEXT));
  1473. //
  1474. // BOGUS
  1475. // Draw scrollbar arrows as disabled if the scrollbar itself is
  1476. // disabled OR if the window it is a part of is disabled?
  1477. //
  1478. hTheme = CUxScrollBar::GetSBTheme(hwnd);
  1479. ht = CUxScrollBar::GetSBHotComponent(hwnd, fVert);
  1480. if (fVert)
  1481. {
  1482. // up button
  1483. CopyRect(&rc, &rcSB);
  1484. rc.bottom = rc.top + cLength;
  1485. if (!hTheme)
  1486. {
  1487. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1488. DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1489. }
  1490. else
  1491. {
  1492. iStateId = (wDisable & LTUPFLAG) ? ABS_UPDISABLED : (ht == HTSCROLLUP) ? ABS_UPHOT : ABS_UPNORMAL;
  1493. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1494. }
  1495. // down button
  1496. rc.bottom = rcSB.bottom;
  1497. rc.top = rcSB.bottom - cLength;
  1498. if (!hTheme)
  1499. {
  1500. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1501. DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1502. }
  1503. else
  1504. {
  1505. iStateId = (wDisable & RTDNFLAG) ? ABS_DOWNDISABLED : (ht == HTSCROLLDOWN) ? ABS_DOWNHOT : ABS_DOWNNORMAL;
  1506. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1507. }
  1508. }
  1509. else
  1510. {
  1511. // left button
  1512. CopyRect(&rc, &rcSB);
  1513. rc.right = rc.left + cLength;
  1514. if (!hTheme)
  1515. {
  1516. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1517. DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1518. }
  1519. else
  1520. {
  1521. iStateId = (wDisable & LTUPFLAG) ? ABS_LEFTDISABLED : (ht == HTSCROLLUP) ? ABS_LEFTHOT : ABS_LEFTNORMAL;
  1522. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1523. }
  1524. // right button
  1525. rc.right = rcSB.right;
  1526. rc.left = rcSB.right - cLength;
  1527. if (!hTheme)
  1528. {
  1529. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  1530. DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1531. }
  1532. else
  1533. {
  1534. iStateId = (wDisable & RTDNFLAG) ? ABS_RIGHTDISABLED : (ht == HTSCROLLDOWN) ? ABS_RIGHTHOT : ABS_RIGHTNORMAL;
  1535. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rc, 0);
  1536. }
  1537. }
  1538. hbrSave = SelectBrush(hdc, hbrSave);
  1539. DrawThumb2(hwnd, pSBCalc, hdc, hbr, fVert, wDisable, fOwnerBrush);
  1540. SelectBrush(hdc, hbrSave);
  1541. SetBkColor(hdc, crBk);
  1542. SetTextColor(hdc, crText);
  1543. }
  1544. /***************************************************************************\
  1545. * zzzSetSBCaretPos
  1546. *
  1547. *
  1548. *
  1549. * History:
  1550. \***************************************************************************/
  1551. void zzzSetSBCaretPos(
  1552. SBHWND hwndSB)
  1553. {
  1554. if (GetFocus() == hwndSB) {
  1555. CUxScrollBarCtl* psb = CUxScrollBarCtl::FromHwnd( hwndSB );
  1556. if( psb )
  1557. {
  1558. int x = (psb->_fVert ? psb->_calc.pxLeft : psb->_calc.pxThumbTop) + SYSMET(CXEDGE);
  1559. int y = (psb->_fVert ? psb->_calc.pxThumbTop : psb->_calc.pxLeft) + SYSMET(CYEDGE);
  1560. #ifdef _VISUAL_DELTA_
  1561. x += CARET_BORDERWIDTH;
  1562. y += CARET_BORDERWIDTH;
  1563. #endif _VISUAL_DELTA_
  1564. SetCaretPos( x, y );
  1565. }
  1566. }
  1567. }
  1568. /***************************************************************************\
  1569. * CalcSBStuff2
  1570. *
  1571. *
  1572. *
  1573. * History:
  1574. \***************************************************************************/
  1575. void CalcSBStuff2(
  1576. PSBCALC pSBCalc,
  1577. LPRECT lprc,
  1578. CONST PSBDATA pw,
  1579. BOOL fVert)
  1580. {
  1581. int cpx;
  1582. DWORD dwRange;
  1583. int denom;
  1584. if (fVert) {
  1585. pSBCalc->pxTop = lprc->top;
  1586. pSBCalc->pxBottom = lprc->bottom;
  1587. pSBCalc->pxLeft = lprc->left;
  1588. pSBCalc->pxRight = lprc->right;
  1589. pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
  1590. } else {
  1591. /*
  1592. * For horiz scroll bars, "left" & "right" are "top" and "bottom",
  1593. * and vice versa.
  1594. */
  1595. pSBCalc->pxTop = lprc->left;
  1596. pSBCalc->pxBottom = lprc->right;
  1597. pSBCalc->pxLeft = lprc->top;
  1598. pSBCalc->pxRight = lprc->bottom;
  1599. pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
  1600. }
  1601. pSBCalc->data.pos = pw->pos;
  1602. pSBCalc->data.page = pw->page;
  1603. pSBCalc->data.posMin = pw->posMin;
  1604. pSBCalc->data.posMax = pw->posMax;
  1605. dwRange = ((DWORD)(pSBCalc->data.posMax - pSBCalc->data.posMin)) + 1;
  1606. //
  1607. // For the case of short scroll bars that don't have enough
  1608. // room to fit the full-sized up and down arrows, shorten
  1609. // their sizes to make 'em fit
  1610. //
  1611. cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
  1612. pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx;
  1613. pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
  1614. if ((pw->page != 0) && (dwRange != 0)) {
  1615. // JEFFBOG -- This is the one and only place where we should
  1616. // see 'range'. Elsewhere it should be 'range - page'.
  1617. /*
  1618. * The minimun thumb size used to depend on the frame/edge metrics.
  1619. * People that increase the scrollbar width/height expect the minimun
  1620. * to grow with proportianally. So NT5 bases the minimun on
  1621. * CXH/YVSCROLL, which is set by default in cpxThumb.
  1622. */
  1623. /*
  1624. * i is used to keep the macro "max" from executing MulDiv twice.
  1625. */
  1626. int i = MulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
  1627. pw->page, dwRange);
  1628. pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
  1629. }
  1630. pSBCalc->pxMin = pSBCalc->pxTop + cpx;
  1631. pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
  1632. denom = dwRange - (pw->page ? pw->page : 1);
  1633. if (denom)
  1634. pSBCalc->pxThumbTop = MulDiv(pw->pos - pw->posMin,
  1635. pSBCalc->cpx, denom) +
  1636. pSBCalc->pxMin;
  1637. else
  1638. pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
  1639. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  1640. }
  1641. /***************************************************************************\
  1642. * SBCtlSetup
  1643. *
  1644. *
  1645. *
  1646. * History:
  1647. \***************************************************************************/
  1648. CUxScrollBarCtl* SBCtlSetup(
  1649. SBHWND hwndSB)
  1650. {
  1651. RECT rc;
  1652. GetClientRect( hwndSB, &rc );
  1653. CUxScrollBarCtl* psb = (CUxScrollBarCtl*)CUxScrollBar::Attach( hwndSB, TRUE, FALSE );
  1654. if( psb )
  1655. {
  1656. psb->Calc2( &psb->_calc, &rc, &psb->_calc.data, psb->_fVert );
  1657. }
  1658. return psb;
  1659. }
  1660. /***************************************************************************\
  1661. * HotTrackSB
  1662. *
  1663. \***************************************************************************/
  1664. #ifdef COLOR_HOTTRACKING
  1665. DWORD GetTrackFlags(int ht, BOOL fDraw)
  1666. {
  1667. if (fDraw) {
  1668. switch(ht) {
  1669. case HTSCROLLUP:
  1670. case HTSCROLLUPPAGE:
  1671. return LTUPFLAG;
  1672. case HTSCROLLDOWN:
  1673. case HTSCROLLDOWNPAGE:
  1674. return RTDNFLAG;
  1675. case HTSCROLLTHUMB:
  1676. return LTUPFLAG | RTDNFLAG;
  1677. default:
  1678. return 0;
  1679. }
  1680. } else {
  1681. return 0;
  1682. }
  1683. }
  1684. BOOL xxxHotTrackSB(HWND hwnd, int htEx, BOOL fDraw)
  1685. {
  1686. SBCALC SBCalc;
  1687. HDC hdc;
  1688. BOOL fVert = HIWORD(htEx);
  1689. int ht = LOWORD(htEx);
  1690. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  1691. CheckLock(hwnd);
  1692. /*
  1693. * xxxDrawSB2 does not callback or leave the critical section when it's
  1694. * not a SB control and the window belongs to a different thread. It
  1695. * calls DefWindowProc which simply returns the brush color.
  1696. */
  1697. CalcSBStuff(hwnd, &SBCalc, fVert);
  1698. hdc = _GetDCEx(hwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  1699. xxxDrawSB2(hwnd, &SBCalc, hdc, fVert, _GetWndSBDisableFlags(hwnd, fVert), dwTrack);
  1700. ReleaseDC(hwnd, hdc);
  1701. return TRUE;
  1702. }
  1703. void xxxHotTrackSBCtl(SBHWND hwndSB, int ht, BOOL fDraw)
  1704. {
  1705. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  1706. HDC hdc;
  1707. CheckLock(hwndSB);
  1708. SBCtlSetup(hwndSB);
  1709. hdc = _GetDCEx((HWND)hwndSB, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  1710. xxxDrawSB2((HWND)hwndSB, &psb->_calc, hdc, psb->_fVert, psb->_wDisableFlags, dwTrack);
  1711. ReleaseDC(hwnd, hdc);
  1712. }
  1713. #endif // COLOR_HOTTRACKING
  1714. BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres)
  1715. {
  1716. // pass the struct because we modify the struct but don't want that
  1717. // modified version to get back to the calling app
  1718. BOOL fChanged = FALSE;
  1719. if (lpsi->fMask & SIF_RETURNOLDPOS)
  1720. // save previous position
  1721. *lplres = pw->pos;
  1722. if (lpsi->fMask & SIF_RANGE) {
  1723. // if the range MAX is below the range MIN -- then treat is as a
  1724. // zero range starting at the range MIN.
  1725. if (lpsi->nMax < lpsi->nMin)
  1726. lpsi->nMax = lpsi->nMin;
  1727. if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) {
  1728. pw->posMin = lpsi->nMin;
  1729. pw->posMax = lpsi->nMax;
  1730. if (!(lpsi->fMask & SIF_PAGE)) {
  1731. lpsi->fMask |= SIF_PAGE;
  1732. lpsi->nPage = pw->page;
  1733. }
  1734. if (!(lpsi->fMask & SIF_POS)) {
  1735. lpsi->fMask |= SIF_POS;
  1736. lpsi->nPos = pw->pos;
  1737. }
  1738. fChanged = TRUE;
  1739. }
  1740. }
  1741. if (lpsi->fMask & SIF_PAGE) {
  1742. DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
  1743. // Clip page to 0, posMax - posMin + 1
  1744. if (lpsi->nPage > dwMaxPage)
  1745. lpsi->nPage = dwMaxPage;
  1746. if (pw->page != (int)(lpsi->nPage)) {
  1747. pw->page = lpsi->nPage;
  1748. if (!(lpsi->fMask & SIF_POS)) {
  1749. lpsi->fMask |= SIF_POS;
  1750. lpsi->nPos = pw->pos;
  1751. }
  1752. fChanged = TRUE;
  1753. }
  1754. }
  1755. if (lpsi->fMask & SIF_POS) {
  1756. int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0);
  1757. // Clip pos to posMin, posMax - (page - 1).
  1758. if (lpsi->nPos < pw->posMin)
  1759. lpsi->nPos = pw->posMin;
  1760. else if (lpsi->nPos > iMaxPos)
  1761. lpsi->nPos = iMaxPos;
  1762. if (pw->pos != lpsi->nPos) {
  1763. pw->pos = lpsi->nPos;
  1764. fChanged = TRUE;
  1765. }
  1766. }
  1767. if (!(lpsi->fMask & SIF_RETURNOLDPOS)) {
  1768. // Return the new position
  1769. *lplres = pw->pos;
  1770. }
  1771. /*
  1772. * This was added by JimA as Cairo merge but will conflict
  1773. * with the documentation for SetScrollPos
  1774. */
  1775. /*
  1776. else if (*lplres == pw->pos)
  1777. *lplres = 0;
  1778. */
  1779. if (lpsi->fMask & SIF_RANGE) {
  1780. *lpfScroll = (pw->posMin != pw->posMax);
  1781. if (*lpfScroll)
  1782. goto checkPage;
  1783. } else if (lpsi->fMask & SIF_PAGE)
  1784. checkPage:
  1785. *lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
  1786. return fChanged;
  1787. }
  1788. /***************************************************************************\
  1789. * CalcSBStuff
  1790. *
  1791. *
  1792. *
  1793. * History:
  1794. \***************************************************************************/
  1795. #if 0
  1796. void CalcSBStuff(
  1797. HWND hwnd,
  1798. PSBCALC pSBCalc,
  1799. BOOL fVert)
  1800. {
  1801. RECT rcT;
  1802. RECT rcClient;
  1803. #ifdef USE_MIRRORING
  1804. int cx, iTemp;
  1805. #endif
  1806. //
  1807. // Get client rectangle. We know that scrollbars always align to the right
  1808. // and to the bottom of the client area.
  1809. //
  1810. GetClientRect( hwnd, &rcClient );
  1811. ClientToScreen( hwnd, (LPPOINT)&rcClient.left );
  1812. ClientToScreen( hwnd, (LPPOINT)&rcClient.right );
  1813. MapWindowPoints( HWND_DESKTOP, hwnd, (LPPOINT)&rcClient, 2 );
  1814. // GetRect(hwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS);
  1815. #ifdef USE_MIRRORING
  1816. if (TestWF(hwnd, WEFLAYOUTRTL)) {
  1817. cx = hwnd->rcWindow.right - hwnd->rcWindow.left;
  1818. iTemp = rcClient.left;
  1819. rcClient.left = cx - rcClient.right;
  1820. rcClient.right = cx - iTemp;
  1821. }
  1822. #endif
  1823. if (fVert) {
  1824. // Only add on space if vertical scrollbar is really there.
  1825. if (TestWF(hwnd, WEFLEFTSCROLL)) {
  1826. rcT.right = rcT.left = rcClient.left;
  1827. if (TestWF(hwnd, WFVPRESENT))
  1828. rcT.left -= SYSMET(CXVSCROLL);
  1829. } else {
  1830. rcT.right = rcT.left = rcClient.right;
  1831. if (TestWF(hwnd, WFVPRESENT))
  1832. rcT.right += SYSMET(CXVSCROLL);
  1833. }
  1834. rcT.top = rcClient.top;
  1835. rcT.bottom = rcClient.bottom;
  1836. } else {
  1837. // Only add on space if horizontal scrollbar is really there.
  1838. rcT.bottom = rcT.top = rcClient.bottom;
  1839. if (TestWF(hwnd, WFHPRESENT))
  1840. rcT.bottom += SYSMET(CYHSCROLL);
  1841. rcT.left = rcClient.left;
  1842. rcT.right = rcClient.right;
  1843. }
  1844. // If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
  1845. // we can do here, so just let it go through. We won't fault but the scrollbar won't work
  1846. // properly either...
  1847. if (_InitPwSB(hwnd))
  1848. CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &CUxScrollBar::GetSBInfo( hwnd )->Vert : &CUxScrollBar::GetSBInfo( hwnd )->Horz, fVert);
  1849. }
  1850. #endif 0
  1851. /***************************************************************************\
  1852. *
  1853. * DrawCtlThumb()
  1854. *
  1855. \***************************************************************************/
  1856. void DrawCtlThumb(SBHWND hwnd)
  1857. {
  1858. HBRUSH hbr, hbrSave;
  1859. HDC hdc = (HDC) GetWindowDC(hwnd);
  1860. if ( hdc != NULL )
  1861. {
  1862. CUxScrollBarCtl* psb = SBCtlSetup(hwnd);
  1863. if (psb)
  1864. {
  1865. BOOL fOwnerBrush = FALSE;
  1866. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1867. hbrSave = SelectBrush(hdc, hbr);
  1868. DrawThumb2(hwnd, &psb->_calc, hdc, hbr, psb->_fVert, psb->_wDisableFlags, fOwnerBrush);
  1869. SelectBrush(hdc, hbrSave);
  1870. }
  1871. ReleaseDC(hwnd, hdc);
  1872. }
  1873. }
  1874. //-------------------------------------------------------------------------
  1875. void xxxDrawThumb(HWND hwnd, PSBCALC pSBCalc, BOOL fVert)
  1876. {
  1877. HBRUSH hbr, hbrSave;
  1878. HDC hdc;
  1879. UINT wDisableFlags;
  1880. SBCALC SBCalc;
  1881. CheckLock(hwnd);
  1882. if (!pSBCalc)
  1883. {
  1884. pSBCalc = &SBCalc;
  1885. }
  1886. CUxScrollBar::Calc( hwnd, pSBCalc, NULL, fVert );
  1887. wDisableFlags = _GetWndSBDisableFlags(hwnd, fVert);
  1888. hdc = GetWindowDC(hwnd);
  1889. if ( hdc != NULL )
  1890. {
  1891. BOOL fOwnerBrush = FALSE;
  1892. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  1893. hbrSave = SelectBrush(hdc, hbr);
  1894. DrawThumb2(hwnd, pSBCalc, hdc, hbr, fVert, wDisableFlags, fOwnerBrush);
  1895. SelectBrush(hdc, hbrSave);
  1896. ReleaseDC(hwnd, hdc);
  1897. }
  1898. }
  1899. //-------------------------------------------------------------------------
  1900. UINT _GetArrowEnableFlags(HWND hwnd, BOOL fVert)
  1901. {
  1902. SCROLLBARINFO sbi = {0};
  1903. UINT uFlags = ESB_ENABLE_BOTH;
  1904. sbi.cbSize = sizeof(sbi);
  1905. if ( GetScrollBarInfo(hwnd, fVert ? OBJID_VSCROLL : OBJID_HSCROLL, &sbi) )
  1906. {
  1907. if ( TESTFLAG(sbi.rgstate[INDEX_SCROLLBAR_UP], (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE)) )
  1908. {
  1909. uFlags |= ESB_DISABLE_UP;
  1910. }
  1911. if ( TESTFLAG(sbi.rgstate[INDEX_SCROLLBAR_DOWN], (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE)) )
  1912. {
  1913. uFlags |= ESB_DISABLE_DOWN;
  1914. }
  1915. }
  1916. return uFlags;
  1917. }
  1918. /***************************************************************************\
  1919. * _SetScrollBar
  1920. *
  1921. *
  1922. *
  1923. * History:
  1924. \***************************************************************************/
  1925. LONG _SetScrollBar(
  1926. HWND hwnd,
  1927. int code,
  1928. LPSCROLLINFO lpsi,
  1929. BOOL fRedraw)
  1930. {
  1931. BOOL fVert;
  1932. PSBDATA pw;
  1933. PSBINFO pSBInfo;
  1934. BOOL fOldScroll;
  1935. BOOL fScroll;
  1936. WORD wfScroll;
  1937. LONG lres;
  1938. BOOL fNewScroll;
  1939. CheckLock(hwnd);
  1940. ASSERT(IsWinEventNotifyDeferredOK());
  1941. if (fRedraw)
  1942. // window must be visible to redraw
  1943. fRedraw = IsWindowVisible(hwnd);
  1944. if (code == SB_CTL)
  1945. #ifdef FE_SB // xxxSetScrollBar()
  1946. // scroll bar control; send the control a message
  1947. if(GETPTI(hwnd)->TIF_flags & TIF_16BIT) {
  1948. //
  1949. // If the target application is 16bit apps, we don't pass win40's message.
  1950. // This fix for Ichitaro v6.3. It eats the message. It never forwards
  1951. // the un-processed messages to original windows procedure via
  1952. // CallWindowProc().
  1953. //
  1954. // Is this from xxxSetScrollPos() ?
  1955. if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) {
  1956. return (int)SendMessage(hwnd, SBM_SETPOS, lpsi->nPos, fRedraw);
  1957. // Is this from xxxSetScrollRange() ?
  1958. } else if(lpsi->fMask == SIF_RANGE) {
  1959. SendMessage(hwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax);
  1960. return TRUE;
  1961. // Others...
  1962. } else {
  1963. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1964. }
  1965. } else {
  1966. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1967. }
  1968. #else
  1969. // scroll bar control; send the control a message
  1970. return (LONG)SendMessage(hwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1971. #endif // FE_SB
  1972. fVert = (code != SB_HORZ);
  1973. wfScroll = (WORD)((fVert) ? WFVSCROLL : WFHSCROLL);
  1974. fScroll = fOldScroll = (TestWF(hwnd, wfScroll)) ? TRUE : FALSE;
  1975. /*
  1976. * Don't do anything if we're setting position of a nonexistent scroll bar.
  1977. */
  1978. if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (CUxScrollBar::GetSBInfo( hwnd ) == NULL)) {
  1979. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  1980. return 0;
  1981. }
  1982. pSBInfo = CUxScrollBar::GetSBInfo( hwnd );
  1983. fNewScroll = !pSBInfo;
  1984. if (fNewScroll) {
  1985. CUxScrollBar* psb = CUxScrollBar::Attach( hwnd, FALSE, fRedraw );
  1986. if( NULL == psb )
  1987. return 0;
  1988. pSBInfo = psb->GetInfo();
  1989. }
  1990. pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
  1991. if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll)
  1992. {
  1993. // no change -- but if REDRAW is specified and there's a scrollbar,
  1994. // redraw the thumb
  1995. if (fOldScroll && fRedraw)
  1996. {
  1997. goto redrawAfterSet;
  1998. }
  1999. if (lpsi->fMask & SIF_DISABLENOSCROLL)
  2000. {
  2001. xxxEnableWndSBArrows(hwnd, code, _GetArrowEnableFlags(hwnd, fVert));
  2002. }
  2003. return lres;
  2004. }
  2005. ClrWF(hwnd, wfScroll);
  2006. if (fScroll)
  2007. SetWF(hwnd, wfScroll);
  2008. else if (!TestWF(hwnd, (WFHSCROLL | WFVSCROLL)))
  2009. {
  2010. // if neither scroll bar is set and both ranges are 0, then free up the
  2011. // scroll info
  2012. CUxScrollBar::Detach( hwnd );
  2013. }
  2014. if (lpsi->fMask & SIF_DISABLENOSCROLL)
  2015. {
  2016. if (fOldScroll)
  2017. {
  2018. SetWF(hwnd, wfScroll);
  2019. xxxEnableWndSBArrows(hwnd, code, _GetArrowEnableFlags(hwnd, fVert));
  2020. }
  2021. }
  2022. else if (fOldScroll ^ fScroll)
  2023. {
  2024. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2025. if (pSBTrack && (hwnd == pSBTrack->hwndTrack))
  2026. {
  2027. pSBTrack->fTrackRecalc = TRUE;
  2028. }
  2029. _RedrawFrame(hwnd);
  2030. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2031. return lres;
  2032. }
  2033. if (fScroll && fRedraw && (fVert ? TestWF(hwnd, WFVPRESENT) : TestWF(hwnd, WFHPRESENT)))
  2034. {
  2035. PSBTRACK pSBTrack;
  2036. redrawAfterSet:
  2037. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE,
  2038. hwnd,
  2039. (fVert ? OBJID_VSCROLL : OBJID_HSCROLL),
  2040. INDEX_SCROLLBAR_SELF);
  2041. pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2042. // Bail out if the caller is trying to change the position of
  2043. // a scrollbar that is in the middle of tracking. We'll hose
  2044. // TrackThumb() otherwise.
  2045. if (pSBTrack && (hwnd == pSBTrack->hwndTrack) &&
  2046. ((BOOL)(pSBTrack->fTrackVert) == fVert) &&
  2047. (pSBTrack->pfnSB == _TrackThumb)) {
  2048. return lres;
  2049. }
  2050. xxxDrawThumb(hwnd, NULL, fVert);
  2051. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2052. }
  2053. return lres;
  2054. }
  2055. //-------------------------------------------------------------------------//
  2056. LONG WINAPI ThemeSetScrollInfo( HWND hwnd, int nBar, LPCSCROLLINFO psi, BOOL bRedraw )
  2057. {
  2058. return _SetScrollBar( hwnd, nBar, (LPSCROLLINFO)psi, bRedraw );
  2059. }
  2060. //-------------------------------------------------------------------------//
  2061. BOOL WINAPI ScrollBar_MouseMove( HWND hwnd, LPPOINT ppt, BOOL fVert )
  2062. {
  2063. BOOL fRet = FALSE;
  2064. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2065. if (psb)
  2066. {
  2067. int htScroll = (ppt != NULL) ? HitTestScrollBar(hwnd, fVert, *ppt) : HTNOWHERE;
  2068. //
  2069. // Redraw the scroll bar if the mouse is over something different
  2070. //
  2071. if (htScroll != psb->GetHotComponent(fVert))
  2072. {
  2073. HDC hdc;
  2074. //
  2075. // save the hittest code of the Scrollbar element the mouse is
  2076. // currently over
  2077. //
  2078. psb->SetHotComponent(htScroll, fVert);
  2079. hdc = GetDCEx(hwnd, NULL, DCX_USESTYLE|DCX_WINDOW|DCX_LOCKWINDOWUPDATE);
  2080. if (hdc != NULL)
  2081. {
  2082. DrawScrollBar(hwnd, hdc, NULL, fVert);
  2083. ReleaseDC(hwnd, hdc);
  2084. }
  2085. fRet = TRUE;
  2086. }
  2087. }
  2088. return fRet;
  2089. }
  2090. //-------------------------------------------------------------------------//
  2091. void DrawScrollBar(HWND hwnd, HDC hdc, LPRECT prcOverrideClient, BOOL fVert)
  2092. {
  2093. SBCALC SBCalc = {0};
  2094. PSBCALC pSBCalc;
  2095. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  2096. CheckLock(hwnd);
  2097. if (pSBTrack && (hwnd == pSBTrack->hwndTrack) && (pSBTrack->fCtlSB == FALSE)
  2098. && (fVert == (BOOL)pSBTrack->fTrackVert))
  2099. {
  2100. pSBCalc = pSBTrack->pSBCalc;
  2101. }
  2102. else
  2103. {
  2104. pSBCalc = &SBCalc;
  2105. }
  2106. CUxScrollBar::Calc(hwnd, pSBCalc, prcOverrideClient, fVert);
  2107. xxxDrawSB2(hwnd, pSBCalc, hdc, fVert, _GetWndSBDisableFlags(hwnd, fVert));
  2108. }
  2109. /***************************************************************************\
  2110. * SBPosFromPx
  2111. *
  2112. * Compute scroll bar position from pixel location
  2113. *
  2114. * History:
  2115. \***************************************************************************/
  2116. int SBPosFromPx(
  2117. PSBCALC pSBCalc,
  2118. int px)
  2119. {
  2120. if (px < pSBCalc->pxMin) {
  2121. return pSBCalc->data.posMin;
  2122. }
  2123. if (px >= pSBCalc->pxMin + pSBCalc->cpx) {
  2124. return (pSBCalc->data.posMax - (pSBCalc->data.page ? pSBCalc->data.page - 1 : 0));
  2125. }
  2126. if (pSBCalc->cpx)
  2127. return (pSBCalc->data.posMin + MulDiv(pSBCalc->data.posMax - pSBCalc->data.posMin -
  2128. (pSBCalc->data.page ? pSBCalc->data.page - 1 : 0),
  2129. px - pSBCalc->pxMin, pSBCalc->cpx));
  2130. else
  2131. return (pSBCalc->data.posMin - 1);
  2132. }
  2133. /***************************************************************************\
  2134. * InvertScrollHilite
  2135. *
  2136. *
  2137. *
  2138. * History:
  2139. \***************************************************************************/
  2140. void InvertScrollHilite(
  2141. HWND hwnd,
  2142. PSBTRACK pSBTrack)
  2143. {
  2144. HDC hdc;
  2145. /*
  2146. * Don't invert if the thumb is all the way at the top or bottom
  2147. * or you will end up inverting the line between the arrow and the thumb.
  2148. */
  2149. if (!IsRectEmpty(&pSBTrack->rcTrack))
  2150. {
  2151. if (pSBTrack->fTrackRecalc) {
  2152. RecalcTrackRect(pSBTrack);
  2153. pSBTrack->fTrackRecalc = FALSE;
  2154. }
  2155. hdc = (HDC)GetWindowDC(hwnd);
  2156. if( hdc )
  2157. {
  2158. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  2159. if (!hTheme)
  2160. {
  2161. InvertRect(hdc, &pSBTrack->rcTrack);
  2162. }
  2163. else
  2164. {
  2165. DrawThemeBackground(hTheme,
  2166. hdc,
  2167. pSBTrack->cmdSB == SB_PAGEUP ?
  2168. (pSBTrack->fTrackVert ? SBP_LOWERTRACKVERT : SBP_LOWERTRACKHORZ) :
  2169. (pSBTrack->fTrackVert ? SBP_UPPERTRACKVERT : SBP_UPPERTRACKHORZ),
  2170. SCRBS_NORMAL,
  2171. &pSBTrack->rcTrack,
  2172. 0);
  2173. }
  2174. ReleaseDC(hwnd, hdc);
  2175. }
  2176. }
  2177. }
  2178. /***************************************************************************\
  2179. * xxxDoScroll
  2180. *
  2181. * Sends scroll notification to the scroll bar owner
  2182. *
  2183. * History:
  2184. \***************************************************************************/
  2185. void xxxDoScroll(
  2186. HWND hwnd,
  2187. HWND hwndNotify,
  2188. int cmd,
  2189. int pos,
  2190. BOOL fVert
  2191. )
  2192. {
  2193. //
  2194. // Send scroll notification to the scrollbar owner. If this is a control
  2195. // the lParam is the control's handle, NULL otherwise.
  2196. //
  2197. SendMessage(hwndNotify,
  2198. (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
  2199. MAKELONG(cmd, pos),
  2200. (LPARAM)(IsScrollBarControl(hwnd) ? hwnd : NULL));
  2201. }
  2202. // -------------------------------------------------------------------------
  2203. //
  2204. // CheckScrollRecalc()
  2205. //
  2206. // -------------------------------------------------------------------------
  2207. //void CheckScrollRecalc(HWND hwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
  2208. //{
  2209. // if ((pSBState->pwndCalc != hwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
  2210. // {
  2211. // // Calculate SB stuff based on whether it's a control or in a window
  2212. // if (pSBState->fCtlSB)
  2213. // SBCtlSetup((SBHWND) hwnd);
  2214. // else
  2215. // CalcSBStuff(hwnd, pSBCalc, pSBState->fVertSB);
  2216. // }
  2217. //}
  2218. /***************************************************************************\
  2219. * xxxMoveThumb
  2220. *
  2221. * History:
  2222. \***************************************************************************/
  2223. void xxxMoveThumb(
  2224. HWND hwnd,
  2225. PSBCALC pSBCalc,
  2226. int px)
  2227. {
  2228. HBRUSH hbr, hbrSave;
  2229. HDC hdc;
  2230. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2231. PSBTRACK pSBTrack = psb->GetTrack();
  2232. CheckLock(hwnd);
  2233. if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
  2234. return;
  2235. pxReCalc:
  2236. pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
  2237. /* Tentative position changed -- notify the guy. */
  2238. if (pSBTrack->posNew != pSBTrack->posOld) {
  2239. if (pSBTrack->hwndSBNotify != NULL) {
  2240. psb->DoScroll(pSBTrack->hwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert
  2241. );
  2242. }
  2243. // After xxxDoScroll, re-evaluate pSBTrack
  2244. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxMoveThumb(1)");
  2245. if ((pSBTrack == NULL) || (pSBTrack->pfnSB == NULL))
  2246. return;
  2247. pSBTrack->posOld = pSBTrack->posNew;
  2248. //
  2249. // Anything can happen after the SendMessage above!
  2250. // Make sure that the SBINFO structure contains data for the
  2251. // window being tracked -- if not, recalculate data in SBINFO
  2252. //
  2253. // CheckScrollRecalc(hwnd, pSBState, pSBCalc);
  2254. // when we yield, our range can get messed with
  2255. // so make sure we handle this
  2256. if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  2257. {
  2258. px = pSBCalc->pxMin + pSBCalc->cpx;
  2259. goto pxReCalc;
  2260. }
  2261. }
  2262. hdc = GetWindowDC(hwnd);
  2263. if ( hdc != NULL )
  2264. {
  2265. BOOL fOwnerBrush = FALSE;
  2266. pSBCalc->pxThumbTop = px;
  2267. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  2268. // at this point, the disable flags are always going to be 0 --
  2269. // we're in the middle of tracking.
  2270. hbr = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  2271. hbrSave = SelectBrush(hdc, hbr);
  2272. // After ScrollBar_GetColorObjects, re-evaluate pSBTrack
  2273. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxMoveThumb(2)");
  2274. if (pSBTrack == NULL)
  2275. {
  2276. RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ;
  2277. ReleaseDC(hwnd, hdc);
  2278. return;
  2279. }
  2280. DrawThumb2(hwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0, fOwnerBrush);
  2281. SelectBrush(hdc, hbrSave);
  2282. ReleaseDC(hwnd, hdc);
  2283. }
  2284. pSBTrack->pxOld = px;
  2285. }
  2286. /***************************************************************************\
  2287. * zzzDrawInvertScrollArea
  2288. *
  2289. *
  2290. *
  2291. * History:
  2292. \***************************************************************************/
  2293. void zzzDrawInvertScrollArea(
  2294. HWND hwnd,
  2295. PSBTRACK pSBTrack,
  2296. BOOL fHit,
  2297. UINT cmd)
  2298. {
  2299. HDC hdc;
  2300. RECT rcTemp;
  2301. int cx, cy;
  2302. HTHEME hTheme;
  2303. if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN))
  2304. {
  2305. // not hitting on arrow -- just invert the area and return
  2306. InvertScrollHilite(hwnd, pSBTrack);
  2307. if (cmd == SB_PAGEUP)
  2308. {
  2309. if (fHit)
  2310. SetWF(hwnd, WFPAGEUPBUTTONDOWN);
  2311. else
  2312. ClrWF(hwnd, WFPAGEUPBUTTONDOWN);
  2313. }
  2314. else
  2315. {
  2316. if (fHit)
  2317. SetWF(hwnd, WFPAGEDNBUTTONDOWN);
  2318. else
  2319. ClrWF(hwnd, WFPAGEDNBUTTONDOWN);
  2320. }
  2321. NotifyWinEvent(EVENT_OBJECT_STATECHANGE,
  2322. hwnd,
  2323. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2324. ((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE));
  2325. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  2326. return;
  2327. }
  2328. if (pSBTrack->fTrackRecalc) {
  2329. RecalcTrackRect(pSBTrack);
  2330. pSBTrack->fTrackRecalc = FALSE;
  2331. }
  2332. CopyRect(&rcTemp, &pSBTrack->rcTrack);
  2333. hdc = GetWindowDC(hwnd);
  2334. if( hdc != NULL )
  2335. {
  2336. if (pSBTrack->fTrackVert) {
  2337. cx = SYSMET(CXVSCROLL);
  2338. cy = SYSMET(CYVSCROLL);
  2339. } else {
  2340. cx = SYSMET(CXHSCROLL);
  2341. cy = SYSMET(CYHSCROLL);
  2342. }
  2343. hTheme = CUxScrollBar::GetSBTheme(hwnd);
  2344. if (!hTheme)
  2345. {
  2346. DrawFrameControl(hdc, &rcTemp, DFC_SCROLL,
  2347. ((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) |
  2348. ((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) |
  2349. ((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX));
  2350. }
  2351. else
  2352. {
  2353. INT iStateId;
  2354. // Determine the pressed state of the button
  2355. iStateId = fHit ? SCRBS_PRESSED : SCRBS_NORMAL;
  2356. // Determine which kind of button it is.
  2357. // NOTE: (phellyar) this is dependant on the order of
  2358. // the ARROWBTNSTATE enum
  2359. if (pSBTrack->fTrackVert)
  2360. {
  2361. if (cmd == SB_LINEUP)
  2362. {
  2363. // Up button states are the first four entries
  2364. // in the enum
  2365. iStateId += 0;
  2366. }
  2367. else
  2368. {
  2369. // Down button states are the second four entries
  2370. // in the enum
  2371. iStateId += 4;
  2372. }
  2373. }
  2374. else
  2375. {
  2376. if (cmd == SB_LINEUP)
  2377. {
  2378. // Left button states are the third four entries
  2379. // in the enum
  2380. iStateId += 8;
  2381. }
  2382. else
  2383. {
  2384. // Right button states are the last four entries
  2385. // in the enum
  2386. iStateId += 12;
  2387. }
  2388. }
  2389. DrawThemeBackground(hTheme, hdc, SBP_ARROWBTN, iStateId, &rcTemp, 0);
  2390. }
  2391. ReleaseDC(hwnd, hdc);
  2392. }
  2393. if (cmd == SB_LINEUP) {
  2394. if (fHit)
  2395. SetWF(hwnd, WFLINEUPBUTTONDOWN);
  2396. else
  2397. ClrWF(hwnd, WFLINEUPBUTTONDOWN);
  2398. } else {
  2399. if (fHit)
  2400. SetWF(hwnd, WFLINEDNBUTTONDOWN);
  2401. else
  2402. ClrWF(hwnd, WFLINEDNBUTTONDOWN);
  2403. }
  2404. NotifyWinEvent(EVENT_OBJECT_STATECHANGE,
  2405. hwnd,
  2406. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2407. (cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN));
  2408. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  2409. }
  2410. /***************************************************************************\
  2411. * xxxEndScroll
  2412. *
  2413. *
  2414. *
  2415. * History:
  2416. \***************************************************************************/
  2417. void xxxEndScroll(
  2418. HWND hwnd,
  2419. BOOL fCancel)
  2420. {
  2421. UINT oldcmd;
  2422. PSBTRACK pSBTrack;
  2423. CheckLock(hwnd);
  2424. ASSERT(!IsWinEventNotifyDeferred());
  2425. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2426. ASSERT(psb != NULL);
  2427. pSBTrack = psb->GetTrack();
  2428. if (pSBTrack && GetCapture() == hwnd && pSBTrack->pfnSB != NULL) {
  2429. oldcmd = pSBTrack->cmdSB;
  2430. pSBTrack->cmdSB = 0;
  2431. ReleaseCapture();
  2432. // After ReleaseCapture, revalidate pSBTrack
  2433. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2434. if (pSBTrack->pfnSB == _TrackThumb) {
  2435. if (fCancel) {
  2436. pSBTrack->posOld = pSBTrack->pSBCalc->data.pos;
  2437. }
  2438. /*
  2439. * DoScroll does thread locking on these two pwnds -
  2440. * this is ok since they are not used after this
  2441. * call.
  2442. */
  2443. if (pSBTrack->hwndSBNotify != NULL) {
  2444. psb->DoScroll( pSBTrack->hwndSBNotify,
  2445. SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert
  2446. );
  2447. // After xxxDoScroll, revalidate pSBTrack
  2448. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2449. }
  2450. if (pSBTrack->fCtlSB) {
  2451. DrawCtlThumb((SBHWND) hwnd);
  2452. } else {
  2453. xxxDrawThumb(hwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
  2454. // Note: after xxx, pSBTrack may no longer be valid
  2455. }
  2456. } else if (pSBTrack->pfnSB == _TrackBox) {
  2457. DWORD lParam;
  2458. POINT ptMsg;
  2459. RECT rcWindow;
  2460. if (pSBTrack->hTimerSB != 0) {
  2461. _KillSystemTimer(hwnd, IDSYS_SCROLL);
  2462. pSBTrack->hTimerSB = 0;
  2463. }
  2464. lParam = GetMessagePos();
  2465. GetWindowRect( hwnd, &rcWindow );
  2466. #ifdef USE_MIRRORING
  2467. if (TestWF(hwnd, WEFLAYOUTRTL)) {
  2468. ptMsg.x = rcWindow.right - GET_X_LPARAM(lParam);
  2469. } else
  2470. #endif
  2471. {
  2472. ptMsg.x = GET_X_LPARAM(lParam) - rcWindow.left;
  2473. }
  2474. ptMsg.y = GET_Y_LPARAM(lParam) - rcWindow.top;
  2475. if (PtInRect(&pSBTrack->rcTrack, ptMsg)) {
  2476. zzzDrawInvertScrollArea(hwnd, pSBTrack, FALSE, oldcmd);
  2477. // Note: after zzz, pSBTrack may no longer be valid
  2478. }
  2479. }
  2480. /*
  2481. * Always send SB_ENDSCROLL message.
  2482. *
  2483. * DoScroll does thread locking on these two pwnds -
  2484. * this is ok since they are not used after this
  2485. * call.
  2486. */
  2487. // After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
  2488. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2489. if (pSBTrack->hwndSBNotify != NULL) {
  2490. psb->DoScroll( pSBTrack->hwndSBNotify,
  2491. SB_ENDSCROLL, 0, pSBTrack->fTrackVert);
  2492. // After xxxDoScroll, revalidate pSBTrack
  2493. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2494. }
  2495. ClrWF(hwnd, WFSCROLLBUTTONDOWN);
  2496. ClrWF(hwnd, WFVERTSCROLLTRACK);
  2497. NotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND,
  2498. hwnd,
  2499. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2500. INDEXID_CONTAINER);
  2501. // After NotifyWinEvent, revalidate pSBTrack
  2502. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2503. // If this is a Scroll Bar Control, turn the caret back on.
  2504. if (pSBTrack->hwndSB != NULL)
  2505. {
  2506. ShowCaret(pSBTrack->hwndSB);
  2507. // After zzz, revalidate pSBTrack
  2508. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2509. }
  2510. pSBTrack->pfnSB = NULL;
  2511. /*
  2512. * Unlock structure members so they are no longer holding down windows.
  2513. */
  2514. Unlock(&pSBTrack->hwndSB);
  2515. Unlock(&pSBTrack->hwndSBNotify);
  2516. Unlock(&pSBTrack->hwndTrack);
  2517. CUxScrollBar::ClearSBTrack( hwnd );
  2518. }
  2519. }
  2520. //-------------------------------------------------------------------------//
  2521. VOID CALLBACK xxxContScroll(HWND hwnd, UINT message, UINT_PTR ID, DWORD dwTime)
  2522. {
  2523. UNREFERENCED_PARAMETER(message);
  2524. UNREFERENCED_PARAMETER(ID);
  2525. UNREFERENCED_PARAMETER(dwTime);
  2526. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2527. if ( psb != NULL )
  2528. {
  2529. PSBTRACK pSBTrack = psb->GetTrack();
  2530. if ( pSBTrack != NULL )
  2531. {
  2532. LONG pt;
  2533. RECT rcWindow;
  2534. CheckLock(hwnd);
  2535. pt = GetMessagePos();
  2536. GetWindowRect( hwnd, &rcWindow );
  2537. if (TestWF(hwnd, WEFLAYOUTRTL))
  2538. {
  2539. pt = MAKELONG(rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - rcWindow.top);
  2540. }
  2541. else
  2542. {
  2543. pt = MAKELONG( GET_X_LPARAM(pt) - rcWindow.left, GET_Y_LPARAM(pt) - rcWindow.top);
  2544. }
  2545. _TrackBox(hwnd, WM_NULL, 0, pt, NULL);
  2546. // After _TrackBox, revalidate pSBTrack
  2547. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2548. if (pSBTrack->fHitOld)
  2549. {
  2550. pSBTrack->hTimerSB = _SetSystemTimer(hwnd, IDSYS_SCROLL, DTTIME/8, xxxContScroll);
  2551. // DoScroll does thread locking on these two pwnds -
  2552. // this is ok since they are not used after this call.
  2553. if (pSBTrack->hwndSBNotify != NULL)
  2554. {
  2555. psb->DoScroll(pSBTrack->hwndSBNotify, pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
  2556. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  2557. }
  2558. }
  2559. }
  2560. }
  2561. }
  2562. //-------------------------------------------------------------------------//
  2563. void CALLBACK _TrackBox(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc)
  2564. {
  2565. CUxScrollBar* psb = CUxScrollBar::FromHwnd(hwnd);
  2566. UNREFERENCED_PARAMETER(wParam);
  2567. UNREFERENCED_PARAMETER(pSBCalc);
  2568. CheckLock(hwnd);
  2569. ASSERT(IsWinEventNotifyDeferredOK());
  2570. if ( psb )
  2571. {
  2572. PSBTRACK pSBTrack = psb->GetTrack();
  2573. if ( pSBTrack )
  2574. {
  2575. BOOL fHit;
  2576. POINT ptHit;
  2577. int cmsTimer;
  2578. if ((uMsg != WM_NULL) && (HIBYTE(uMsg) != HIBYTE(WM_MOUSEFIRST)))
  2579. {
  2580. return;
  2581. }
  2582. if (pSBTrack->fTrackRecalc)
  2583. {
  2584. RecalcTrackRect(pSBTrack);
  2585. pSBTrack->fTrackRecalc = FALSE;
  2586. }
  2587. ptHit.x = GET_X_LPARAM(lParam);
  2588. ptHit.y = GET_Y_LPARAM(lParam);
  2589. fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
  2590. if (fHit != (BOOL)pSBTrack->fHitOld)
  2591. {
  2592. zzzDrawInvertScrollArea(hwnd, pSBTrack, fHit, pSBTrack->cmdSB);
  2593. // After zzz, pSBTrack may no longer be valid
  2594. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2595. }
  2596. cmsTimer = DTTIME/8;
  2597. switch (uMsg)
  2598. {
  2599. case WM_LBUTTONUP:
  2600. xxxEndScroll(hwnd, FALSE);
  2601. // Note: after xxx, pSBTrack may no longer be valid
  2602. break;
  2603. case WM_LBUTTONDOWN:
  2604. pSBTrack->hTimerSB = 0;
  2605. cmsTimer = DTTIME;
  2606. //
  2607. // FALL THRU
  2608. //
  2609. case WM_MOUSEMOVE:
  2610. if (fHit && fHit != (BOOL)pSBTrack->fHitOld)
  2611. {
  2612. //
  2613. // We moved back into the normal rectangle: reset timer
  2614. //
  2615. pSBTrack->hTimerSB = _SetSystemTimer(hwnd, IDSYS_SCROLL,
  2616. cmsTimer, xxxContScroll);
  2617. //
  2618. // DoScroll does thread locking on these two pwnds -
  2619. // this is ok since they are not used after this
  2620. // call.
  2621. //
  2622. if (pSBTrack->hwndSBNotify != NULL)
  2623. {
  2624. psb->DoScroll( pSBTrack->hwndSBNotify, pSBTrack->cmdSB,
  2625. 0, pSBTrack->fTrackVert);
  2626. // Note: after xxx, pSBTrack may no longer be valid
  2627. }
  2628. }
  2629. break;
  2630. }
  2631. // After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
  2632. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2633. pSBTrack->fHitOld = fHit;
  2634. }
  2635. }
  2636. }
  2637. /***************************************************************************\
  2638. * _TrackThumb
  2639. *
  2640. *
  2641. *
  2642. * History:
  2643. \***************************************************************************/
  2644. void CALLBACK _TrackThumb(
  2645. HWND hwnd,
  2646. UINT message,
  2647. WPARAM wParam,
  2648. LPARAM lParam,
  2649. PSBCALC pSBCalc)
  2650. {
  2651. int px;
  2652. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2653. ASSERT(psb);
  2654. PSBTRACK pSBTrack = psb->GetTrack();
  2655. POINT pt;
  2656. UNREFERENCED_PARAMETER(wParam);
  2657. CheckLock(hwnd);
  2658. if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
  2659. return;
  2660. if (pSBTrack == NULL)
  2661. return;
  2662. // Make sure that the SBINFO structure contains data for the
  2663. // window being tracked -- if not, recalculate data in SBINFO
  2664. // CheckScrollRecalc(hwnd, pSBState, pSBCalc);
  2665. if (pSBTrack->fTrackRecalc) {
  2666. RecalcTrackRect(pSBTrack);
  2667. pSBTrack->fTrackRecalc = FALSE;
  2668. }
  2669. pt.y = GET_Y_LPARAM(lParam);
  2670. pt.x = GET_X_LPARAM(lParam);
  2671. if (!PtInRect(&pSBTrack->rcTrack, pt))
  2672. px = pSBCalc->pxStart;
  2673. else {
  2674. px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
  2675. if (px < pSBCalc->pxMin)
  2676. px = pSBCalc->pxMin;
  2677. else if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  2678. px = pSBCalc->pxMin + pSBCalc->cpx;
  2679. }
  2680. xxxMoveThumb(hwnd, pSBCalc, px);
  2681. /*
  2682. * We won't get the WM_LBUTTONUP message if we got here through
  2683. * the scroll menu, so test the button state directly.
  2684. */
  2685. if (message == WM_LBUTTONUP || GetKeyState(VK_LBUTTON) >= 0) {
  2686. xxxEndScroll(hwnd, FALSE);
  2687. }
  2688. }
  2689. /***************************************************************************\
  2690. * _ClientToWindow
  2691. * History:
  2692. \***************************************************************************/
  2693. BOOL _ClientToWindow( HWND hwnd, LPPOINT ppt )
  2694. {
  2695. WINDOWINFO wi;
  2696. wi.cbSize = sizeof(wi);
  2697. if( GetWindowInfo( hwnd, &wi ) )
  2698. {
  2699. ppt->x += (wi.rcClient.left - wi.rcWindow.left);
  2700. ppt->y += (wi.rcClient.top - wi.rcWindow.top);
  2701. return TRUE;
  2702. }
  2703. return FALSE;
  2704. }
  2705. /***************************************************************************\
  2706. * xxxSBTrackLoop
  2707. *
  2708. *
  2709. *
  2710. * History:
  2711. \***************************************************************************/
  2712. void xxxSBTrackLoop(
  2713. HWND hwnd,
  2714. LPARAM lParam,
  2715. PSBCALC pSBCalc)
  2716. {
  2717. MSG msg;
  2718. UINT cmd;
  2719. VOID (*pfnSB)(HWND, UINT, WPARAM, LPARAM, PSBCALC);
  2720. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  2721. PSBTRACK pSBTrack = psb->GetSBTrack(hwnd);
  2722. CheckLock(hwnd);
  2723. ASSERT(IsWinEventNotifyDeferredOK());
  2724. if (pSBTrack == NULL)
  2725. // mode cancelled -- exit track loop
  2726. return;
  2727. pfnSB = pSBTrack->pfnSB;
  2728. if (pfnSB == NULL)
  2729. // mode cancelled -- exit track loop
  2730. return;
  2731. if (pSBTrack->fTrackVert)
  2732. SetWF(hwnd, WFVERTSCROLLTRACK);
  2733. NotifyWinEvent(EVENT_SYSTEM_SCROLLINGSTART,
  2734. hwnd,
  2735. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  2736. INDEXID_CONTAINER);
  2737. // Note: after xxx, pSBTrack may no longer be valid
  2738. (*pfnSB)(hwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc);
  2739. // Note: after xxx, pSBTrack may no longer be valid
  2740. while (GetCapture() == hwnd) {
  2741. if (!GetMessage(&msg, NULL, 0, 0)) {
  2742. // Note: after xxx, pSBTrack may no longer be valid
  2743. break;
  2744. }
  2745. if (!CallMsgFilter(&msg, MSGF_SCROLLBAR))
  2746. {
  2747. BOOL bTrackMsg = FALSE;
  2748. cmd = msg.message;
  2749. lParam = msg.lParam;
  2750. if (msg.hwnd == HWq(hwnd))
  2751. {
  2752. if( cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST )
  2753. {
  2754. if( !psb->IsCtl() )
  2755. {
  2756. POINT pt;
  2757. pt.x = GET_X_LPARAM(msg.lParam);
  2758. pt.y = GET_Y_LPARAM(msg.lParam);
  2759. _ClientToWindow( hwnd, &pt );
  2760. lParam = MAKELPARAM(pt.x, pt.y);
  2761. }
  2762. bTrackMsg = TRUE;
  2763. }
  2764. else if( cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST )
  2765. {
  2766. cmd = _SysToChar(cmd, msg.lParam);
  2767. bTrackMsg = TRUE;
  2768. }
  2769. }
  2770. if( bTrackMsg )
  2771. {
  2772. // After NotifyWinEvent, pfnSB, TranslateMessage or
  2773. // DispatchMessage, re-evaluate pSBTrack.
  2774. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxTrackLoop");
  2775. if ((pSBTrack == NULL) || (NULL == (pfnSB = pSBTrack->pfnSB)))
  2776. // mode cancelled -- exit track loop
  2777. return;
  2778. (*pfnSB)(hwnd, cmd, msg.wParam, lParam, pSBCalc);
  2779. }
  2780. else
  2781. {
  2782. TranslateMessage(&msg);
  2783. DispatchMessage(&msg);
  2784. }
  2785. }
  2786. }
  2787. }
  2788. /***************************************************************************\
  2789. * _SBTrackInit
  2790. *
  2791. * History:
  2792. \***************************************************************************/
  2793. void _SBTrackInit(
  2794. HWND hwnd,
  2795. LPARAM lParam,
  2796. int curArea,
  2797. UINT uType)
  2798. {
  2799. int px;
  2800. LPINT pwX;
  2801. LPINT pwY;
  2802. UINT wDisable; // Scroll bar disable flags;
  2803. SBCALC SBCalc = {0};
  2804. PSBCALC pSBCalc;
  2805. RECT rcSB;
  2806. PSBTRACK pSBTrack;
  2807. CheckLock(hwnd);
  2808. #ifdef PORTPORT // unneccessary dbgchk w/ port
  2809. if (CUxScrollBar::GetSBTrack(hwnd)) {
  2810. RIPMSG1(RIP_WARNING, "_SBTrackInit: CUxScrollBar::GetSBTrack(hwnd) == %#p",
  2811. CUxScrollBar::GetSBTrack(hwnd));
  2812. return;
  2813. }
  2814. #endif PORTPORT
  2815. CUxScrollBar* psb = CUxScrollBar::Attach( hwnd, !curArea, TRUE );
  2816. if (!psb)
  2817. {
  2818. return;
  2819. }
  2820. CUxScrollBarCtl* psbCtl = psb->IsCtl() ? (CUxScrollBarCtl*)psb : NULL;
  2821. pSBTrack = psb->GetTrack();
  2822. if (pSBTrack == NULL)
  2823. return;
  2824. pSBTrack->hTimerSB = 0;
  2825. pSBTrack->fHitOld = FALSE;
  2826. pSBTrack->pfnSB = _TrackBox;
  2827. pSBTrack->hwndTrack = NULL;
  2828. pSBTrack->hwndSB = NULL;
  2829. pSBTrack->hwndSBNotify = NULL;
  2830. Lock(&pSBTrack->hwndTrack, hwnd); // pSBTrack->hwndTrack = hwnd;
  2831. pSBTrack->fCtlSB = (!curArea);
  2832. if (pSBTrack->fCtlSB)
  2833. {
  2834. /*
  2835. * This is a scroll bar control.
  2836. */
  2837. ASSERT(psbCtl != NULL);
  2838. pSBTrack->hwndSB = hwnd; //Lock(&pSBTrack->hwndSB, hwnd);
  2839. pSBTrack->fTrackVert = psbCtl->_fVert;
  2840. Lock(&pSBTrack->hwndSBNotify, GetParent(hwnd)); // pSBTrack->hwndSBNotify = GetParent( hwnd );
  2841. wDisable = psbCtl->_wDisableFlags;
  2842. pSBCalc = &psbCtl->_calc;
  2843. pSBTrack->nBar = SB_CTL;
  2844. } else {
  2845. /*
  2846. * This is a scroll bar that is part of the window frame.
  2847. */
  2848. RECT rcWindow;
  2849. GetWindowRect( hwnd, &rcWindow );
  2850. int x = GET_X_LPARAM(lParam);
  2851. int y = GET_Y_LPARAM(lParam);
  2852. #ifdef USE_MIRRORING
  2853. //
  2854. // Mirror the window coord of the scroll bar,
  2855. // if it is a mirrored one
  2856. //
  2857. if (TestWF(hwnd,WEFLAYOUTRTL)) {
  2858. lParam = MAKELONG(
  2859. rcWindow.right - x,
  2860. y - rcWindow.top);
  2861. }
  2862. else {
  2863. #endif
  2864. lParam = MAKELONG( x - rcWindow.left, y - rcWindow.top);
  2865. #ifdef USE_MIRRORING
  2866. }
  2867. #endif
  2868. Lock(&pSBTrack->hwndSBNotify, hwnd); // pSBTrack->hwndSBNotify = hwnd; //
  2869. Lock(&pSBTrack->hwndSB, NULL); // pSBTrack->hwndSB = NULL;
  2870. pSBTrack->fTrackVert = (curArea - HTHSCROLL);
  2871. wDisable = _GetWndSBDisableFlags(hwnd, pSBTrack->fTrackVert);
  2872. pSBCalc = &SBCalc;
  2873. pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ;
  2874. }
  2875. pSBTrack->pSBCalc = pSBCalc;
  2876. /*
  2877. * Check if the whole scroll bar is disabled
  2878. */
  2879. if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  2880. CUxScrollBar::Detach( hwnd );
  2881. return; // It is a disabled scroll bar; So, do not respond.
  2882. }
  2883. if (!pSBTrack->fCtlSB) {
  2884. psb->FreshenSBData( pSBTrack->nBar, FALSE );
  2885. CUxScrollBar::Calc(hwnd, pSBCalc, NULL, pSBTrack->fTrackVert);
  2886. }
  2887. pwX = (LPINT)&rcSB;
  2888. pwY = pwX + 1;
  2889. if (!pSBTrack->fTrackVert)
  2890. pwX = pwY--;
  2891. px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
  2892. *(pwX + 0) = pSBCalc->pxLeft;
  2893. *(pwY + 0) = pSBCalc->pxTop;
  2894. *(pwX + 2) = pSBCalc->pxRight;
  2895. *(pwY + 2) = pSBCalc->pxBottom;
  2896. pSBTrack->cmdSB = (UINT)-1;
  2897. if (px < pSBCalc->pxUpArrow) {
  2898. /*
  2899. * The click occurred on Left/Up arrow; Check if it is disabled
  2900. */
  2901. if(wDisable & LTUPFLAG) {
  2902. if(pSBTrack->fCtlSB) { // If this is a scroll bar control,
  2903. ShowCaret(pSBTrack->hwndSB); // show the caret before returning;
  2904. // After ShowCaret, revalidate pSBTrack
  2905. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2906. }
  2907. CUxScrollBar::Detach( hwnd );
  2908. return; // Yes! disabled. Do not respond.
  2909. }
  2910. // LINEUP -- make rcSB the Up Arrow's Rectangle
  2911. pSBTrack->cmdSB = SB_LINEUP;
  2912. *(pwY + 2) = pSBCalc->pxUpArrow;
  2913. } else if (px >= pSBCalc->pxDownArrow) {
  2914. /*
  2915. * The click occurred on Right/Down arrow; Check if it is disabled
  2916. */
  2917. if (wDisable & RTDNFLAG) {
  2918. if (pSBTrack->fCtlSB) { // If this is a scroll bar control,
  2919. ShowCaret(pSBTrack->hwndSB); // show the caret before returning;
  2920. // After ShowCaret, revalidate pSBTrack
  2921. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2922. }
  2923. CUxScrollBar::Detach( hwnd );
  2924. return;// Yes! disabled. Do not respond.
  2925. }
  2926. // LINEDOWN -- make rcSB the Down Arrow's Rectangle
  2927. pSBTrack->cmdSB = SB_LINEDOWN;
  2928. *(pwY + 0) = pSBCalc->pxDownArrow;
  2929. } else if (px < pSBCalc->pxThumbTop) {
  2930. // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
  2931. pSBTrack->cmdSB = SB_PAGEUP;
  2932. *(pwY + 0) = pSBCalc->pxUpArrow;
  2933. *(pwY + 2) = pSBCalc->pxThumbTop;
  2934. } else if (px < pSBCalc->pxThumbBottom) {
  2935. DoThumbPos:
  2936. /*
  2937. * Elevator isn't there if there's no room.
  2938. */
  2939. if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) {
  2940. CUxScrollBar::Detach( hwnd );
  2941. return;
  2942. }
  2943. // THUMBPOSITION -- we're tracking with the thumb
  2944. pSBTrack->cmdSB = SB_THUMBPOSITION;
  2945. CalcTrackDragRect(pSBTrack);
  2946. pSBTrack->pfnSB = _TrackThumb;
  2947. pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop;
  2948. pSBTrack->posNew = pSBTrack->posOld = pSBCalc->data.pos;
  2949. pSBTrack->dpxThumb = pSBCalc->pxStart - px;
  2950. SetCapture( hwnd ); //xxxCapture(PtiCurrent(), hwnd, WINDOW_CAPTURE);
  2951. // After xxxCapture, revalidate pSBTrack
  2952. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2953. /*
  2954. * DoScroll does thread locking on these two pwnds -
  2955. * this is ok since they are not used after this
  2956. * call.
  2957. */
  2958. if (pSBTrack->hwndSBNotify != NULL) {
  2959. psb->DoScroll( pSBTrack->hwndSBNotify, SB_THUMBTRACK,
  2960. pSBTrack->posOld, pSBTrack->fTrackVert
  2961. );
  2962. // Note: after xxx, pSBTrack may no longer be valid
  2963. }
  2964. } else if (px < pSBCalc->pxDownArrow) {
  2965. // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
  2966. pSBTrack->cmdSB = SB_PAGEDOWN;
  2967. *(pwY + 0) = pSBCalc->pxThumbBottom;
  2968. *(pwY + 2) = pSBCalc->pxDownArrow;
  2969. }
  2970. /*
  2971. * If the shift key is down, we'll position the thumb directly so it's
  2972. * centered on the click point.
  2973. */
  2974. if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) ||
  2975. (uType == SCROLL_MENU)) {
  2976. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  2977. goto DoThumbPos;
  2978. }
  2979. pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2);
  2980. }
  2981. SetCapture( hwnd ); // xxxCapture(PtiCurrent(), hwnd, WINDOW_CAPTURE);
  2982. // After xxxCapture, revalidate pSBTrack
  2983. RETURN_IF_PSBTRACK_INVALID(pSBTrack, hwnd);
  2984. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  2985. CopyRect(&pSBTrack->rcTrack, &rcSB);
  2986. }
  2987. xxxSBTrackLoop(hwnd, lParam, pSBCalc);
  2988. // After xxx, re-evaluate pSBTrack
  2989. REEVALUATE_PSBTRACK(pSBTrack, hwnd, "xxxTrackLoop");
  2990. if (pSBTrack)
  2991. {
  2992. CUxScrollBar::ClearSBTrack( hwnd );
  2993. }
  2994. }
  2995. /***************************************************************************\
  2996. * HandleScrollCmd
  2997. *
  2998. * History: added to support and encap SB tracking initialization originating
  2999. * from WM_SYSCOMMAND::SC_VSCROLL/SC_HSCROLL [scotthan]
  3000. \***************************************************************************/
  3001. void WINAPI HandleScrollCmd( HWND hwnd, WPARAM wParam, LPARAM lParam )
  3002. {
  3003. UINT uArea = (UINT)(wParam & 0x0F);
  3004. _SBTrackInit( hwnd, lParam, uArea,
  3005. (GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  3006. }
  3007. //-------------------------------------------------------------------------
  3008. HMENU ScrollBar_GetMenu(HWND hwnd, BOOL fVert)
  3009. {
  3010. static HMODULE hModUser = NULL;
  3011. HMENU hMenu = NULL;
  3012. if ( !hModUser )
  3013. {
  3014. hModUser = GetModuleHandle(TEXT("user32"));
  3015. }
  3016. #define ID_HSCROLLMENU 0x40
  3017. #define ID_VSCROLLMENU 0x50
  3018. if ( hModUser )
  3019. {
  3020. hMenu = LoadMenu(hModUser, MAKEINTRESOURCE((fVert ? ID_VSCROLLMENU : ID_HSCROLLMENU)));
  3021. if ( hMenu )
  3022. {
  3023. hMenu = GetSubMenu(hMenu, 0);
  3024. }
  3025. }
  3026. return hMenu;
  3027. }
  3028. //-------------------------------------------------------------------------
  3029. VOID ScrollBar_Menu(HWND hwndNotify, HWND hwnd, LPARAM lParam, BOOL fVert)
  3030. {
  3031. CUxScrollBar* psb = CUxScrollBar::FromHwnd( hwnd );
  3032. CUxScrollBarCtl* psbCtl = CUxScrollBarCtl::FromHwnd( hwnd );
  3033. BOOL fCtl = (psbCtl != NULL);
  3034. if ( psb || psbCtl )
  3035. {
  3036. UINT wDisable;
  3037. RECT rcWindow;
  3038. POINT pt;
  3039. GetWindowRect(hwnd, &rcWindow);
  3040. POINTSTOPOINT(pt, lParam);
  3041. if ( TestWF(hwnd, WEFLAYOUTRTL) && !fVert )
  3042. {
  3043. MIRROR_POINT(rcWindow, pt);
  3044. }
  3045. pt.x -= rcWindow.left;
  3046. pt.y -= rcWindow.top;
  3047. if ( fCtl )
  3048. {
  3049. wDisable = psbCtl->_wDisableFlags;
  3050. }
  3051. else
  3052. {
  3053. wDisable = _GetWndSBDisableFlags(hwndNotify, fVert);
  3054. }
  3055. // Make sure the scrollbar isn't disabled.
  3056. if ( (wDisable & SB_DISABLE_MASK) != SB_DISABLE_MASK)
  3057. {
  3058. HMENU hMenu = ScrollBar_GetMenu(hwndNotify, fVert);
  3059. // Put up a menu and scroll accordingly.
  3060. if (hMenu != NULL)
  3061. {
  3062. int iCmd;
  3063. iCmd = TrackPopupMenuEx(hMenu,
  3064. TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
  3065. GET_X_LPARAM(lParam),
  3066. GET_Y_LPARAM(lParam),
  3067. hwndNotify,
  3068. NULL);
  3069. DestroyMenu(hMenu);
  3070. if (iCmd)
  3071. {
  3072. if ((iCmd & 0x00FF) == SB_THUMBPOSITION)
  3073. {
  3074. if ( fCtl )
  3075. {
  3076. _SBTrackInit(hwnd, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU);
  3077. }
  3078. else
  3079. {
  3080. _SBTrackInit(hwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU);
  3081. }
  3082. }
  3083. else
  3084. {
  3085. xxxDoScroll(hwnd, hwndNotify, (iCmd & 0x00FF), 0, fVert);
  3086. xxxDoScroll(hwnd, hwndNotify, SB_ENDSCROLL, 0, fVert);
  3087. }
  3088. }
  3089. }
  3090. }
  3091. }
  3092. }
  3093. //-------------------------------------------------------------------------
  3094. LRESULT CUxScrollBarCtl::WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  3095. {
  3096. LONG l;
  3097. LONG lres = 0;
  3098. int cx, cy;
  3099. UINT cmd;
  3100. UINT uSide;
  3101. HDC hdc;
  3102. RECT rc;
  3103. POINT pt;
  3104. BOOL fSizeReal;
  3105. HBRUSH hbrSave;
  3106. BOOL fSize;
  3107. PAINTSTRUCT ps;
  3108. DWORD dwStyle;
  3109. SCROLLINFO si;
  3110. LPSCROLLINFO lpsi = &si;
  3111. BOOL fRedraw = FALSE;
  3112. BOOL fScroll;
  3113. CUxScrollBarCtl* psb = CUxScrollBarCtl::FromHwnd( hwnd );
  3114. if (!psb && uMsg != WM_NCCREATE)
  3115. {
  3116. goto CallDWP;
  3117. }
  3118. CheckLock(hwnd);
  3119. ASSERT(IsWinEventNotifyDeferredOK());
  3120. VALIDATECLASSANDSIZE(((HWND)hwnd), uMsg, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
  3121. dwStyle = GetWindowStyle(hwnd);
  3122. fSize = (((LOBYTE(dwStyle)) & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
  3123. switch (uMsg)
  3124. {
  3125. case WM_NCCREATE:
  3126. if( NULL == psb )
  3127. {
  3128. psb = (CUxScrollBarCtl*)CUxScrollBar::Attach( hwnd, TRUE, FALSE );
  3129. }
  3130. goto CallDWP;
  3131. case WM_NCDESTROY:
  3132. CUxScrollBar::Detach(hwnd);
  3133. psb = NULL;
  3134. goto CallDWP;
  3135. case WM_CREATE:
  3136. /*
  3137. * Guard against lParam being NULL since the thunk allows it [51986]
  3138. */
  3139. if (lParam)
  3140. {
  3141. rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) +
  3142. ((LPCREATESTRUCT)lParam)->cx;
  3143. rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) +
  3144. ((LPCREATESTRUCT)lParam)->cy;
  3145. // This is because we can't just rev CardFile -- we should fix the
  3146. // problem here in case anyone else happened to have some EXTRA
  3147. // scroll styles on their scroll bar controls (jeffbog 03/21/94)
  3148. if (!TestWF((HWND)hwnd, WFWIN40COMPAT))
  3149. dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
  3150. if (!fSize)
  3151. {
  3152. l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams);
  3153. psb->_calc.data.pos = psb->_calc.data.posMin = LOWORD(l);
  3154. psb->_calc.data.posMax = HIWORD(l);
  3155. psb->_fVert = ((LOBYTE(dwStyle) & SBS_VERT) != 0);
  3156. psb->_calc.data.page = 0;
  3157. }
  3158. if (dwStyle & WS_DISABLED)
  3159. psb->_wDisableFlags = SB_DISABLE_MASK;
  3160. if (LOBYTE(dwStyle) & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) {
  3161. if (fSize) {
  3162. if (LOBYTE(dwStyle) & SBS_SIZEBOXBOTTOMRIGHTALIGN) {
  3163. rc.left = rc.right - SYSMET(CXVSCROLL);
  3164. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  3165. }
  3166. rc.right = rc.left + SYSMET(CXVSCROLL);
  3167. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  3168. } else {
  3169. if (LOBYTE(dwStyle) & SBS_VERT) {
  3170. if (LOBYTE(dwStyle) & SBS_LEFTALIGN)
  3171. rc.right = rc.left + SYSMET(CXVSCROLL);
  3172. else
  3173. rc.left = rc.right - SYSMET(CXVSCROLL);
  3174. } else {
  3175. if (LOBYTE(dwStyle) & SBS_TOPALIGN)
  3176. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  3177. else
  3178. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  3179. }
  3180. }
  3181. MoveWindow((HWND)hwnd, rc.left, rc.top, rc.right - rc.left,
  3182. rc.bottom - rc.top, FALSE);
  3183. }
  3184. } /* if */
  3185. else {
  3186. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING,
  3187. "UxScrollBarCtlWndProc - NULL lParam for WM_CREATE\n") ;
  3188. } /* else */
  3189. break;
  3190. case WM_SIZE:
  3191. if (GetFocus() != (HWND)hwnd)
  3192. break;
  3193. // scroll bar has the focus -- recalc it's thumb caret size
  3194. // no need to DeferWinEventNotify() - see CreateCaret below.
  3195. DestroyCaret();
  3196. // | |
  3197. // | FALL THRU |
  3198. // V V
  3199. case WM_SETFOCUS:
  3200. {
  3201. // REVIEW (phellyar) Do we want themed scroll bars to have
  3202. // a caret?
  3203. if ( !psb->GetTheme() )
  3204. {
  3205. SBCtlSetup(hwnd);
  3206. RECT rcWindow;
  3207. GetWindowRect( hwnd, &rcWindow );
  3208. cx = (psb->_fVert ? rcWindow.right - rcWindow.left
  3209. : psb->_calc.cpxThumb) - 2 * SYSMET(CXEDGE);
  3210. cy = (psb->_fVert ? psb->_calc.cpxThumb
  3211. : rcWindow.bottom - rcWindow.top) - 2 * SYSMET(CYEDGE);
  3212. #ifdef _VISUAL_DELTA_
  3213. cx -= (CARET_BORDERWIDTH * 2);
  3214. cy -= (CARET_BORDERWIDTH * 2);
  3215. #endif _VISUAL_DELTA_
  3216. CreateCaret((HWND)hwnd, (HBITMAP)1, cx, cy);
  3217. zzzSetSBCaretPos(hwnd);
  3218. ShowCaret((HWND)hwnd);
  3219. }
  3220. break;
  3221. }
  3222. case WM_KILLFOCUS:
  3223. DestroyCaret();
  3224. break;
  3225. case WM_ERASEBKGND:
  3226. /*
  3227. * Do nothing, but don't let DefWndProc() do it either.
  3228. * It will be erased when its painted.
  3229. */
  3230. return (LONG)TRUE;
  3231. case WM_PRINTCLIENT:
  3232. case WM_PAINT:
  3233. if ((hdc = (HDC)wParam) == NULL) {
  3234. hdc = BeginPaint((HWND)hwnd, (LPPAINTSTRUCT)&ps);
  3235. }
  3236. if (!fSize) {
  3237. SBCtlSetup(hwnd);
  3238. xxxDrawSB2((HWND)hwnd, &psb->_calc, hdc, psb->_fVert, psb->_wDisableFlags);
  3239. } else {
  3240. fSizeReal = TestWF((HWND)hwnd, WFSIZEBOX);
  3241. if (!fSizeReal)
  3242. SetWF((HWND)hwnd, WFSIZEBOX);
  3243. _DrawSizeBoxFromFrame((HWND)hwnd, hdc, 0, 0);
  3244. if (!fSizeReal)
  3245. ClrWF((HWND)hwnd, WFSIZEBOX);
  3246. }
  3247. if (wParam == 0L)
  3248. EndPaint((HWND)hwnd, (LPPAINTSTRUCT)&ps);
  3249. break;
  3250. case WM_GETDLGCODE:
  3251. return DLGC_WANTARROWS;
  3252. case WM_CONTEXTMENU:
  3253. {
  3254. HWND hwndParent = GetParent(hwnd);
  3255. if (hwndParent)
  3256. {
  3257. ScrollBar_Menu(hwndParent, hwnd, lParam, psb->_fVert);
  3258. }
  3259. break;
  3260. }
  3261. case WM_NCHITTEST:
  3262. if (LOBYTE(dwStyle) & SBS_SIZEGRIP) {
  3263. #ifdef USE_MIRRORING
  3264. /*
  3265. * If the scroll bar is RTL mirrored, then
  3266. * mirror the hittest of the grip location.
  3267. */
  3268. if (TestWF((HWND)hwnd, WEFLAYOUTRTL))
  3269. return HTBOTTOMLEFT;
  3270. else
  3271. #endif
  3272. return HTBOTTOMRIGHT;
  3273. } else {
  3274. goto CallDWP;
  3275. }
  3276. break;
  3277. case WM_MOUSELEAVE:
  3278. //xxxHotTrackSBCtl(hwnd, 0, FALSE);
  3279. psb->SetHotComponent(HTNOWHERE, psb->_fVert);
  3280. InvalidateRect(hwnd, NULL, TRUE);
  3281. break;
  3282. case WM_MOUSEMOVE:
  3283. {
  3284. INT ht;
  3285. if (psb->GetHotComponent(psb->_fVert) == 0)
  3286. {
  3287. TRACKMOUSEEVENT tme;
  3288. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  3289. tme.dwFlags = TME_LEAVE;
  3290. tme.hwndTrack = hwnd;
  3291. tme.dwHoverTime = 0;
  3292. TrackMouseEvent(&tme);
  3293. }
  3294. pt.x = GET_X_LPARAM(lParam);
  3295. pt.y = GET_Y_LPARAM(lParam);
  3296. ht = HitTestScrollBar((HWND)hwnd, psb->_fVert, pt);
  3297. if (psb->GetHotComponent(psb->_fVert) != ht)
  3298. {
  3299. //xxxHotTrackSBCtl(hwnd, ht, TRUE);
  3300. psb->SetHotComponent(ht, psb->_fVert);
  3301. InvalidateRect(hwnd, NULL, TRUE);
  3302. }
  3303. break;
  3304. }
  3305. case WM_LBUTTONDBLCLK:
  3306. cmd = SC_ZOOM;
  3307. if (fSize)
  3308. goto postmsg;
  3309. /*
  3310. *** FALL THRU **
  3311. */
  3312. case WM_LBUTTONDOWN:
  3313. //
  3314. // Note that SBS_SIZEGRIP guys normally won't ever see button
  3315. // downs. This is because they return HTBOTTOMRIGHT to
  3316. // WindowHitTest handling. This will walk up the parent chain
  3317. // to the first sizeable ancestor, bailing out at caption windows
  3318. // of course. That dude, if he exists, will handle the sizing
  3319. // instead.
  3320. //
  3321. if (!fSize) {
  3322. if (TestWF((HWND)hwnd, WFTABSTOP)) {
  3323. SetFocus((HWND)hwnd);
  3324. }
  3325. HideCaret((HWND)hwnd);
  3326. SBCtlSetup(hwnd);
  3327. /*
  3328. * SBCtlSetup enters SEM_SB, and _SBTrackInit leaves it.
  3329. */
  3330. _SBTrackInit((HWND)hwnd, lParam, 0, (GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  3331. break;
  3332. } else {
  3333. cmd = SC_SIZE;
  3334. postmsg:
  3335. pt.x = GET_X_LPARAM(lParam);
  3336. pt.y = GET_Y_LPARAM(lParam);
  3337. ClientToScreen((HWND)hwnd, &pt);
  3338. lParam = MAKELONG(pt.x, pt.y);
  3339. /*
  3340. * convert HT value into a move value. This is bad,
  3341. * but this is purely temporary.
  3342. */
  3343. #ifdef USE_MIRRORING
  3344. if (TestWF(GetParent(hwnd),WEFLAYOUTRTL))
  3345. {
  3346. uSide = HTBOTTOMLEFT;
  3347. }
  3348. else
  3349. #endif
  3350. {
  3351. uSide = HTBOTTOMRIGHT;
  3352. }
  3353. ThreadLock(((HWND)hwnd)->hwndParent, &tlpwndParent);
  3354. SendMessage(GetParent(hwnd), WM_SYSCOMMAND,
  3355. (cmd | (uSide - HTSIZEFIRST + 1)), lParam);
  3356. ThreadUnlock(&tlpwndParent);
  3357. }
  3358. break;
  3359. case WM_KEYUP:
  3360. switch (wParam) {
  3361. case VK_HOME:
  3362. case VK_END:
  3363. case VK_PRIOR:
  3364. case VK_NEXT:
  3365. case VK_LEFT:
  3366. case VK_UP:
  3367. case VK_RIGHT:
  3368. case VK_DOWN:
  3369. /*
  3370. * Send end scroll uMsg when user up clicks on keyboard
  3371. * scrolling.
  3372. *
  3373. * DoScroll does thread locking on these two pwnds -
  3374. * this is ok since they are not used after this
  3375. * call.
  3376. */
  3377. xxxDoScroll( (HWND)hwnd, GetParent(hwnd),
  3378. SB_ENDSCROLL, 0, psb->_fVert
  3379. );
  3380. break;
  3381. default:
  3382. break;
  3383. }
  3384. break;
  3385. case WM_KEYDOWN:
  3386. switch (wParam) {
  3387. case VK_HOME:
  3388. wParam = SB_TOP;
  3389. goto KeyScroll;
  3390. case VK_END:
  3391. wParam = SB_BOTTOM;
  3392. goto KeyScroll;
  3393. case VK_PRIOR:
  3394. wParam = SB_PAGEUP;
  3395. goto KeyScroll;
  3396. case VK_NEXT:
  3397. wParam = SB_PAGEDOWN;
  3398. goto KeyScroll;
  3399. case VK_LEFT:
  3400. case VK_UP:
  3401. wParam = SB_LINEUP;
  3402. goto KeyScroll;
  3403. case VK_RIGHT:
  3404. case VK_DOWN:
  3405. wParam = SB_LINEDOWN;
  3406. KeyScroll:
  3407. /*
  3408. * DoScroll does thread locking on these two pwnds -
  3409. * this is ok since they are not used after this
  3410. * call.
  3411. */
  3412. xxxDoScroll((HWND)hwnd, GetParent(hwnd), (int)wParam, 0, psb->_fVert
  3413. );
  3414. break;
  3415. default:
  3416. break;
  3417. }
  3418. break;
  3419. case WM_ENABLE:
  3420. return SendMessage((HWND)hwnd, SBM_ENABLE_ARROWS,
  3421. (wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
  3422. case SBM_ENABLE_ARROWS:
  3423. /*
  3424. * This is used to enable/disable the arrows in a SB ctrl
  3425. */
  3426. return (LONG)xxxEnableSBCtlArrows((HWND)hwnd, (UINT)wParam);
  3427. case SBM_GETPOS:
  3428. return (LONG)psb->_calc.data.pos;
  3429. case SBM_GETRANGE:
  3430. *((LPINT)wParam) = psb->_calc.data.posMin;
  3431. *((LPINT)lParam) = psb->_calc.data.posMax;
  3432. return MAKELRESULT(LOWORD(psb->_calc.data.posMin), LOWORD(psb->_calc.data.posMax));
  3433. case SBM_GETSCROLLINFO:
  3434. return (LONG)_SBGetParms((HWND)hwnd, SB_CTL, (PSBDATA)&psb->_calc, (LPSCROLLINFO) lParam);
  3435. case SBM_SETRANGEREDRAW:
  3436. fRedraw = TRUE;
  3437. case SBM_SETRANGE:
  3438. // Save the old values of Min and Max for return value
  3439. si.cbSize = sizeof(si);
  3440. // si.nMin = LOWORD(lParam);
  3441. // si.nMax = HIWORD(lParam);
  3442. si.nMin = (int)wParam;
  3443. si.nMax = (int)lParam;
  3444. si.fMask = SIF_RANGE | SIF_RETURNOLDPOS;
  3445. goto SetInfo;
  3446. case SBM_SETPOS:
  3447. fRedraw = (BOOL) lParam;
  3448. si.cbSize = sizeof(si);
  3449. si.fMask = SIF_POS | SIF_RETURNOLDPOS;
  3450. si.nPos = (int)wParam;
  3451. goto SetInfo;
  3452. case SBM_SETSCROLLINFO:
  3453. {
  3454. lpsi = (LPSCROLLINFO) lParam;
  3455. fRedraw = (BOOL) wParam;
  3456. SetInfo:
  3457. fScroll = TRUE;
  3458. lres = SBSetParms((PSBDATA)&psb->_calc, lpsi, &fScroll, &lres);
  3459. if (SBSetParms((PSBDATA)&psb->_calc, lpsi, &fScroll, &lres))
  3460. {
  3461. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, hwnd, OBJID_CLIENT, INDEX_SCROLLBAR_SELF);
  3462. }
  3463. if (!fRedraw)
  3464. return lres;
  3465. /*
  3466. * We must set the new position of the caret irrespective of
  3467. * whether the window is visible or not;
  3468. * Still, this will work only if the app has done a xxxSetScrollPos
  3469. * with fRedraw = TRUE;
  3470. * Fix for Bug #5188 --SANKAR-- 10-15-89
  3471. * No need to DeferWinEventNotify since hwnd is locked.
  3472. */
  3473. HideCaret((HWND)hwnd);
  3474. SBCtlSetup(hwnd);
  3475. zzzSetSBCaretPos(hwnd);
  3476. /*
  3477. ** The following ShowCaret() must be done after the DrawThumb2(),
  3478. ** otherwise this caret will be erased by DrawThumb2() resulting
  3479. ** in this bug:
  3480. ** Fix for Bug #9263 --SANKAR-- 02-09-90
  3481. *
  3482. */
  3483. /*
  3484. *********** ShowCaret((HWND)hwnd); ******
  3485. */
  3486. if (_FChildVisible((HWND)hwnd) && fRedraw)
  3487. {
  3488. UINT wDisable;
  3489. HBRUSH hbrUse;
  3490. if (!fScroll)
  3491. fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
  3492. wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
  3493. xxxEnableScrollBar((HWND) hwnd, SB_CTL, wDisable);
  3494. hdc = GetWindowDC((HWND)hwnd);
  3495. if (hdc)
  3496. {
  3497. BOOL fOwnerBrush = FALSE;
  3498. hbrUse = ScrollBar_GetColorObjects(hwnd, hdc, &fOwnerBrush);
  3499. hbrSave = SelectBrush(hdc, hbrUse);
  3500. // Before we used to only hideshowthumb() if the mesage was
  3501. // not SBM_SETPOS. I am not sure why but this case was ever
  3502. // needed for win 3.x but on NT it resulted in trashing the border
  3503. // of the scrollbar when the app called SetScrollPos() during
  3504. // scrollbar tracking. - mikehar 8/26
  3505. DrawThumb2((HWND)hwnd, &psb->_calc, hdc, hbrUse, psb->_fVert, psb->_wDisableFlags, fOwnerBrush);
  3506. SelectBrush(hdc, hbrSave);
  3507. ReleaseDC(hwnd, hdc);
  3508. }
  3509. }
  3510. /*
  3511. * This ShowCaret() has been moved to this place from above
  3512. * Fix for Bug #9263 --SANKAR-- 02-09-90
  3513. */
  3514. ShowCaret((HWND)hwnd);
  3515. return lres;
  3516. }
  3517. case WM_GETOBJECT:
  3518. if(lParam == OBJID_QUERYCLASSNAMEIDX)
  3519. {
  3520. return MSAA_CLASSNAMEIDX_SCROLLBAR;
  3521. }
  3522. break;
  3523. case WM_THEMECHANGED:
  3524. psb->ChangeSBTheme();
  3525. InvalidateRect(hwnd, NULL, TRUE);
  3526. break;
  3527. default:
  3528. CallDWP:
  3529. return DefWindowProc((HWND)hwnd, uMsg, wParam, lParam);
  3530. }
  3531. return 0L;
  3532. }
  3533. //-------------------------------------------------------------------------//
  3534. // Globals
  3535. static HBRUSH g_hbrGray = NULL;
  3536. //-------------------------------------------------------------------------//
  3537. HBRUSH _UxGrayBrush(VOID)
  3538. {
  3539. if( NULL == g_hbrGray )
  3540. {
  3541. CONST static WORD patGray[8] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
  3542. HBITMAP hbmGray;
  3543. /*
  3544. * Create a gray brush to be used with GrayString
  3545. */
  3546. if( (hbmGray = CreateBitmap(8, 8, 1, 1, (LPBYTE)patGray)) != NULL )
  3547. {
  3548. g_hbrGray = CreatePatternBrush(hbmGray);
  3549. DeleteObject( hbmGray );
  3550. }
  3551. }
  3552. return g_hbrGray;
  3553. }
  3554. //-------------------------------------------------------------------------//
  3555. void _UxFreeGDIResources()
  3556. {
  3557. DeleteObject( g_hbrGray );
  3558. }
  3559. //-------------------------------------------------------------------------//
  3560. void _RedrawFrame( HWND hwnd )
  3561. {
  3562. CheckLock(hwnd);
  3563. /*
  3564. * We always want to call xxxSetWindowPos, even if invisible or iconic,
  3565. * because we need to make sure the WM_NCCALCSIZE message gets sent.
  3566. */
  3567. SetWindowPos( hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER |
  3568. SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_DRAWFRAME);
  3569. }
  3570. //-------------------------------------------------------------------------//
  3571. // from winmgr.c
  3572. BOOL _FChildVisible( HWND hwnd )
  3573. {
  3574. while (GetWindowStyle( hwnd ) & WS_CHILD )
  3575. {
  3576. if( NULL == (hwnd = GetParent(hwnd)) )
  3577. if (!TestWF(hwnd, WFVISIBLE))
  3578. return FALSE;
  3579. }
  3580. return TRUE;
  3581. }
  3582. //-------------------------------------------------------------------------//
  3583. //
  3584. // SizeBoxHwnd
  3585. //
  3586. // Returns the HWND that will be sized if the user drags in the given window's
  3587. // sizebox -- If NULL, then the sizebox is not needed
  3588. //
  3589. // Criteria for choosing what window will be sized:
  3590. // find first sizeable parent; if that parent is not maximized and the child's
  3591. // bottom, right corner is within a scroll bar height and width of the parent's
  3592. //
  3593. HWND SizeBoxHwnd(HWND hwnd)
  3594. {
  3595. BOOL bMirroredSizeBox = (BOOL)TestWF(hwnd, WEFLAYOUTRTL);
  3596. RECT rc;
  3597. int xbrChild;
  3598. int ybrChild;
  3599. GetWindowRect(hwnd, &rc);
  3600. xbrChild = bMirroredSizeBox ? rc.left : rc.right;
  3601. ybrChild = rc.bottom;
  3602. while (hwnd != HWND_DESKTOP)
  3603. {
  3604. if (TestWF(hwnd, WFSIZEBOX))
  3605. {
  3606. //
  3607. // First sizeable parent found
  3608. //
  3609. int xbrParent;
  3610. int ybrParent;
  3611. if (TestWF(hwnd, WFMAXIMIZED))
  3612. {
  3613. return NULL;
  3614. }
  3615. GetWindowRect(hwnd, &rc);
  3616. xbrParent = bMirroredSizeBox ? rc.left : rc.right;
  3617. ybrParent = rc.bottom;
  3618. //
  3619. // the sizebox dude is within an EDGE of the client's bottom
  3620. // right corner (left corner for mirrored windows), let this succeed.
  3621. // That way people who draw their own sunken clients will be happy.
  3622. //
  3623. if (bMirroredSizeBox)
  3624. {
  3625. if ((xbrChild - SYSMETRTL(CXFRAME) > xbrParent) || (ybrChild + SYSMETRTL(CYFRAME) < ybrParent))
  3626. {
  3627. //
  3628. // Child's bottom, left corner of SIZEBOX isn't close enough
  3629. // to bottom left of parent's client.
  3630. //
  3631. return NULL;
  3632. }
  3633. }
  3634. else
  3635. {
  3636. if ((xbrChild + SYSMETRTL(CXFRAME) < xbrParent) || (ybrChild + SYSMETRTL(CYFRAME) < ybrParent))
  3637. {
  3638. //
  3639. // Child's bottom, right corner of SIZEBOX isn't close enough
  3640. // to bottom right of parent's client.
  3641. //
  3642. return NULL;
  3643. }
  3644. }
  3645. return hwnd;
  3646. }
  3647. if (!TestWF(hwnd, WFCHILD) || TestWF(hwnd, WFCPRESENT))
  3648. {
  3649. break;
  3650. }
  3651. hwnd = GetParent(hwnd);
  3652. }
  3653. return NULL;
  3654. }
  3655. //-------------------------------------------------------------------------//
  3656. //
  3657. // _DrawPushButton
  3658. //
  3659. // From ntuser\rtl\draw.c
  3660. // Draws a push style button in the given state. Adjusts passed in rectangle
  3661. // if desired.
  3662. //
  3663. // Algorithm:
  3664. // Depending on the state we either draw
  3665. // - raised edge (undepressed)
  3666. // - sunken edge with extra shadow (depressed)
  3667. // If it is an option push button (a push button that is
  3668. // really a check button or a radio button like buttons
  3669. // in tool bars), and it is checked, then we draw it
  3670. // depressed with a different fill in the middle.
  3671. //
  3672. VOID _DrawPushButton(HWND hwnd, HDC hdc, LPRECT lprc, UINT state, UINT flags, BOOL fVert)
  3673. {
  3674. RECT rc;
  3675. HBRUSH hbrMiddle;
  3676. DWORD rgbBack = 0;
  3677. DWORD rgbFore = 0;
  3678. BOOL fDither;
  3679. HTHEME hTheme = CUxScrollBar::GetSBTheme(hwnd);
  3680. if ( !hTheme )
  3681. {
  3682. rc = *lprc;
  3683. DrawEdge(hdc,
  3684. &rc,
  3685. (state & (DFCS_PUSHED | DFCS_CHECKED)) ? EDGE_SUNKEN : EDGE_RAISED,
  3686. (UINT)(BF_ADJUST | BF_RECT | (flags & (BF_SOFT | BF_FLAT | BF_MONO))));
  3687. //
  3688. // BOGUS
  3689. // On monochrome, need to do something to make pushed buttons look
  3690. // better.
  3691. //
  3692. //
  3693. // Fill in middle. If checked, use dither brush (gray brush) with
  3694. // black becoming normal color.
  3695. //
  3696. fDither = FALSE;
  3697. if (state & DFCS_CHECKED)
  3698. {
  3699. if ((GetDeviceCaps(hdc, BITSPIXEL) /*gpsi->BitCount*/ < 8) || (SYSRGBRTL(3DHILIGHT) == RGB(255,255,255)))
  3700. {
  3701. hbrMiddle = _UxGrayBrush();
  3702. rgbBack = SetBkColor(hdc, SYSRGBRTL(3DHILIGHT));
  3703. rgbFore = SetTextColor(hdc, SYSRGBRTL(3DFACE));
  3704. fDither = TRUE;
  3705. }
  3706. else
  3707. {
  3708. hbrMiddle = SYSHBR(3DHILIGHT);
  3709. }
  3710. }
  3711. else
  3712. {
  3713. hbrMiddle = SYSHBR(3DFACE);
  3714. }
  3715. FillRect(hdc, &rc, hbrMiddle);
  3716. if (fDither)
  3717. {
  3718. SetBkColor(hdc, rgbBack);
  3719. SetTextColor(hdc, rgbFore);
  3720. }
  3721. if (flags & BF_ADJUST)
  3722. {
  3723. *lprc = rc;
  3724. }
  3725. }
  3726. else
  3727. {
  3728. INT iStateId;
  3729. INT iPartId;
  3730. SIZE sizeGrip;
  3731. RECT rcContent;
  3732. PSBTRACK pSBTrack = CUxScrollBar::GetSBTrack(hwnd);
  3733. if ((CUxScrollBarCtl::GetDisableFlags(hwnd) & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
  3734. {
  3735. iStateId = SCRBS_DISABLED;
  3736. }
  3737. else if (pSBTrack && ((BOOL)pSBTrack->fTrackVert == fVert) && (pSBTrack->cmdSB == SB_THUMBPOSITION))
  3738. {
  3739. iStateId = SCRBS_PRESSED;
  3740. }
  3741. else if (CUxScrollBar::GetSBHotComponent(hwnd, fVert) == HTSCROLLTHUMB)
  3742. {
  3743. iStateId = SCRBS_HOT;
  3744. }
  3745. else
  3746. {
  3747. iStateId = SCRBS_NORMAL;
  3748. }
  3749. iPartId = fVert ? SBP_THUMBBTNVERT : SBP_THUMBBTNHORZ;
  3750. //
  3751. // Draw the thumb
  3752. //
  3753. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, lprc, 0);
  3754. //
  3755. // Lastly draw the little gripper image, if there is enough room
  3756. //
  3757. if ( SUCCEEDED(GetThemeBackgroundContentRect(hTheme, hdc, iPartId, iStateId, lprc, &rcContent)) )
  3758. {
  3759. iPartId = fVert ? SBP_GRIPPERVERT : SBP_GRIPPERHORZ;
  3760. if ( SUCCEEDED(GetThemePartSize(hTheme, hdc, iPartId, iStateId, &rcContent, TS_TRUE, &sizeGrip)) )
  3761. {
  3762. if ( (sizeGrip.cx < RECTWIDTH(&rcContent)) && (sizeGrip.cy < RECTHEIGHT(&rcContent)) )
  3763. {
  3764. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, &rcContent, 0);
  3765. }
  3766. }
  3767. }
  3768. }
  3769. }
  3770. // user.h
  3771. #define CheckMsgFilter(wMsg, wMsgFilterMin, wMsgFilterMax) \
  3772. ( ((wMsgFilterMin) == 0 && (wMsgFilterMax) == 0xFFFFFFFF) \
  3773. || ( ((wMsgFilterMin) > (wMsgFilterMax)) \
  3774. ? (((wMsg) < (wMsgFilterMax)) || ((wMsg) > (wMsgFilterMin))) \
  3775. : (((wMsg) >= (wMsgFilterMin)) && ((wMsg) <= (wMsgFilterMax)))))
  3776. #define SYS_ALTERNATE 0x2000
  3777. #define SYS_PREVKEYSTATE 0x4000
  3778. // mnaccel.h
  3779. /***************************************************************************\
  3780. * _SysToChar
  3781. *
  3782. * EXIT: If the message was not made with the ALT key down, convert
  3783. * the message from a WM_SYSKEY* to a WM_KEY* message.
  3784. *
  3785. * IMPLEMENTATION:
  3786. * The 0x2000 bit in the hi word of lParam is set if the key was
  3787. * made with the ALT key down.
  3788. *
  3789. * History:
  3790. * 11/30/90 JimA Ported.
  3791. \***************************************************************************/
  3792. UINT _SysToChar(
  3793. UINT message,
  3794. LPARAM lParam)
  3795. {
  3796. if (CheckMsgFilter(message, WM_SYSKEYDOWN, WM_SYSDEADCHAR) &&
  3797. !(HIWORD(lParam) & SYS_ALTERNATE))
  3798. return (message - (WM_SYSKEYDOWN - WM_KEYDOWN));
  3799. return message;
  3800. }