void UpdateCurrentTabBgColor(WindowInfo *win) { TabPainter *tab = (TabPainter *)GetWindowLongPtr(win->hwndTabBar, GWLP_USERDATA); if (win->AsEbook()) { COLORREF txtCol; GetEbookUiColors(txtCol, tab->currBgCol); } else { // TODO: match either the toolbar (if shown) or background tab->currBgCol = DEFAULT_CURRENT_BG_COL; } tab->EvaluateColors(true); RepaintNow(win->hwndTabBar); }
static LRESULT CALLBACK WndProcTabBar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; int index; LPTCITEM tcs; TabPainter *tab = (TabPainter *)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (msg) { case WM_DESTROY: delete tab; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)0); break; case TCM_INSERTITEM: index = (int)wParam; tcs = (LPTCITEM)lParam; CrashIf(!(TCIF_TEXT & tcs->mask)); tab->Insert(index, tcs->pszText); if ((int)index <= tab->current) tab->current++; tab->xClicked = -1; if (tab->isMouseInClientArea) PostMessage(hwnd, WM_MOUSEMOVE, 0, tab->mouseCoordinates); InvalidateRgn(hwnd, nullptr, FALSE); UpdateWindow(hwnd); break; case TCM_SETITEM: index = (int)wParam; tcs = (LPTCITEM)lParam; if (TCIF_TEXT & tcs->mask) { if (tab->Set(index, tcs->pszText)) tab->Invalidate(index); } break; case TCM_DELETEITEM: index = (int)wParam; if (tab->Delete(index)) { if ((int)index < tab->current) tab->current--; else if ((int)index == tab->current) tab->current = -1; tab->xClicked = -1; if (tab->isMouseInClientArea) PostMessage(hwnd, WM_MOUSEMOVE, 0, tab->mouseCoordinates); if (tab->Count()) { InvalidateRgn(hwnd, nullptr, FALSE); UpdateWindow(hwnd); } } break; case TCM_DELETEALLITEMS: tab->DeleteAll(); tab->current = tab->highlighted = tab->xClicked = tab->xHighlighted = -1; break; case TCM_SETITEMSIZE: if (tab->Reshape(LOWORD(lParam), HIWORD(lParam))) { tab->xClicked = -1; if (tab->isMouseInClientArea) PostMessage(hwnd, WM_MOUSEMOVE, 0, tab->mouseCoordinates); if (tab->Count()) { InvalidateRgn(hwnd, nullptr, FALSE); UpdateWindow(hwnd); } } break; case TCM_GETCURSEL: return tab->current; case TCM_SETCURSEL: { index = (int)wParam; if (index >= tab->Count()) return -1; int previous = tab->current; if ((int)index != tab->current) { tab->Invalidate(tab->current); tab->Invalidate(index); tab->current = index; UpdateWindow(hwnd); } return previous; } case WM_NCHITTEST: { if (!tab->inTitlebar || hwnd == GetCapture()) return HTCLIENT; POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; ScreenToClient(hwnd, &pt); if (-1 != tab->IndexFromPoint(pt.x, pt.y)) return HTCLIENT; } return HTTRANSPARENT; case WM_MOUSELEAVE: PostMessage(hwnd, WM_MOUSEMOVE, 0xFF, 0); return 0; case WM_MOUSEMOVE: { tab->mouseCoordinates = lParam; if (!tab->isMouseInClientArea) { // Track the mouse for leaving the client area. TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hwnd; if (TrackMouseEvent(&tme)) tab->isMouseInClientArea = true; } if (wParam == 0xFF) // The mouse left the client area. tab->isMouseInClientArea = false; bool inX = false; int hl = wParam == 0xFF ? -1 : tab->IndexFromPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &inX); if (tab->isDragging && hl == -1) { // preserve the highlighted tab if it's dragged outside the tabs' area hl = tab->highlighted; } if (tab->highlighted != hl) { if (tab->isDragging) { // send notification if the highlighted tab is dragged over another WindowInfo *win = FindWindowInfoByHwnd(hwnd); int tabNo = tab->highlighted; uitask::Post([=] { TabNotification(win, T_DRAG, tabNo, hl); }); } tab->Invalidate(hl); tab->Invalidate(tab->highlighted); tab->highlighted = hl; } int xHl = inX && !tab->isDragging ? hl : -1; if (tab->xHighlighted != xHl) { tab->Invalidate(xHl); tab->Invalidate(tab->xHighlighted); tab->xHighlighted = xHl; } if (!inX) tab->xClicked = -1; } return 0; case WM_LBUTTONDOWN: bool inX; tab->nextTab = tab->IndexFromPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &inX); if (inX) { // send request to close the tab WindowInfo *win = FindWindowInfoByHwnd(hwnd); int next = tab->nextTab; uitask::Post([=] { TabNotification(win, T_CLOSING, next, -1); }); } else if (tab->nextTab != -1) { if (tab->nextTab != tab->current) { // send request to select tab WindowInfo *win = FindWindowInfoByHwnd(hwnd); uitask::Post([=] { TabNotification(win, TCN_SELCHANGING, -1, -1); }); } tab->isDragging = true; SetCapture(hwnd); } return 0; case WM_LBUTTONUP: if (tab->xClicked != -1) { // send notification that the tab is closed WindowInfo *win = FindWindowInfoByHwnd(hwnd); int clicked = tab->xClicked; uitask::Post([=] { TabNotification(win, T_CLOSE, clicked, -1); }); tab->Invalidate(clicked); tab->xClicked = -1; } if (tab->isDragging) { tab->isDragging = false; ReleaseCapture(); } return 0; case WM_MBUTTONDOWN: // middle-clicking unconditionally closes the tab { tab->nextTab = tab->IndexFromPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); // send request to close the tab WindowInfo *win = FindWindowInfoByHwnd(hwnd); int next = tab->nextTab; uitask::Post([=] { TabNotification(win, T_CLOSING, next, -1); }); } return 0; case WM_MBUTTONUP: if (tab->xClicked != -1) { // send notification that the tab is closed WindowInfo *win = FindWindowInfoByHwnd(hwnd); int clicked = tab->xClicked; uitask::Post([=] { TabNotification(win, T_CLOSE, clicked, -1); }); tab->Invalidate(clicked); tab->xClicked = -1; } return 0; case WM_ERASEBKGND: return TRUE; case WM_PAINT: { RECT rc; GetUpdateRect(hwnd, &rc, FALSE); // TODO: when is wParam != nullptr? hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps); DoubleBuffer buffer(hwnd, RectI::FromRECT(rc)); tab->EvaluateColors(); tab->Paint(buffer.GetDC(), rc); buffer.Flush(hdc); ValidateRect(hwnd, nullptr); if (!wParam) EndPaint(hwnd, &ps); return 0; } case WM_SIZE: { WindowInfo *win = FindWindowInfoByHwnd(hwnd); if (win) UpdateTabWidth(win); } break; } return CallWindowProc(DefWndProcTabBar, hwnd, msg, wParam, lParam); }
void SetCurrentTabBgCol(WindowInfo *win, COLORREF bgCol) { TabPainter *tab = (TabPainter *)GetWindowLongPtr(win->hwndTabBar, GWLP_USERDATA); tab->currBgCol = bgCol; tab->EvaluateColors(true); }