Add Scroll Tab Bar with mouse wheel capacity

Closes #521, closes #522, closes #2071
This commit is contained in:
A-R-C-A 2016-07-11 23:33:22 +00:00 committed by Don HO
parent 9fe39017cb
commit c76981421f

View File

@ -441,6 +441,96 @@ LRESULT TabBarPlus::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPara
return TRUE;
}
case WM_MOUSEWHEEL:
{
// ..............................................................................
// MOUSEWHEEL:
// will scroll the tab bar area (similar to Firefox's tab scrolling),
// it only happens if not in multi-line mode and at least one tab is hidden
// ..............................................................................
// CTRL + MOUSEWHEEL:
// will do previous/next tab WITH scroll wrapping (endless loop)
// ..............................................................................
// SHIFT + MOUSEWHEEL:
// will do previous/next tab WITHOUT scroll wrapping (stops at first/last tab)
// ..............................................................................
// CTRL + SHIFT + MOUSEWHEEL:
// will switch to the first/last tab
// ..............................................................................
if (_isDragging)
return TRUE;
const bool isForward = ((short)HIWORD(wParam)) < 0; // wheel rotation towards the user will be considered as forward direction
const LRESULT lastTabIndex = ::SendMessage(_hSelf, TCM_GETITEMCOUNT, 0, 0) - 1;
if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT))
{
::SendMessage(_hSelf, TCM_SETCURFOCUS, (isForward ? lastTabIndex : 0), 0);
}
else if (wParam & (MK_CONTROL | MK_SHIFT))
{
LRESULT tabIndex = ::SendMessage(_hSelf, TCM_GETCURSEL, 0, 0) + (isForward ? 1 : -1);
if (tabIndex < 0)
{
if (wParam & MK_CONTROL)
tabIndex = lastTabIndex; // wrap scrolling
else
return TRUE;
}
else if (tabIndex > lastTabIndex)
{
if (wParam & MK_CONTROL)
tabIndex = 0; // wrap scrolling
else
return TRUE;
}
::SendMessage(_hSelf, TCM_SETCURFOCUS, tabIndex, 0);
}
else if (not _isMultiLine) // don't scroll if in multi-line mode
{
RECT rcTabCtrl, rcLastTab;
::SendMessage(_hSelf, TCM_GETITEMRECT, lastTabIndex, (LPARAM)&rcLastTab);
::GetClientRect(_hSelf, &rcTabCtrl);
// get index of the first visible tab
TC_HITTESTINFO hti;
LONG xy = NppParameters::getInstance()->_dpiManager.scaleX(12); // an arbitrary coordinate inside the first visible tab
hti.pt = { xy, xy };
LRESULT scrollTabIndex = ::SendMessage(_hSelf, TCM_HITTEST, 0, (LPARAM)&hti);
if (scrollTabIndex < 1 && (_isVertical ? rcLastTab.bottom < rcTabCtrl.bottom : rcLastTab.right < rcTabCtrl.right)) // nothing to scroll
return TRUE;
// maximal width/height of the msctls_updown32 class (arrow box in the tab bar),
// this area may hide parts of the last tab and needs to be excluded
LONG maxLengthUpDownCtrl = NppParameters::getInstance()->_dpiManager.scaleX(44); // sufficient static value
// scroll forward as long as the last tab is hidden; scroll backward till the first tab
if ((_isVertical ? ((rcTabCtrl.bottom - rcLastTab.bottom) < maxLengthUpDownCtrl) : ((rcTabCtrl.right - rcLastTab.right) < maxLengthUpDownCtrl)) || not isForward)
{
if (isForward)
++scrollTabIndex;
else
--scrollTabIndex;
if (scrollTabIndex < 0 || scrollTabIndex > lastTabIndex)
return TRUE;
// clear hover state of the close button,
// WM_MOUSEMOVE won't handle this properly since the tab position will change
if (_isCloseHover)
{
_isCloseHover = false;
::InvalidateRect(_hSelf, &_currentHoverTabRect, false);
}
::SendMessage(_hSelf, WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, scrollTabIndex), 0);
}
}
return TRUE;
}
case WM_LBUTTONDOWN :
{
if (_drawTabCloseButton)