From 15855fa84a09fd1fd486d357c38db0f2bd181e74 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 4 Mar 2014 23:23:45 +0000 Subject: HistoryStats compiles ok now git-svn-id: http://svn.miranda-ng.org/main/trunk@8399 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/HistoryStats/src/bandctrlimpl.cpp | 1057 +++++++++++++++++++++++++++++ 1 file changed, 1057 insertions(+) create mode 100644 plugins/HistoryStats/src/bandctrlimpl.cpp (limited to 'plugins/HistoryStats/src/bandctrlimpl.cpp') diff --git a/plugins/HistoryStats/src/bandctrlimpl.cpp b/plugins/HistoryStats/src/bandctrlimpl.cpp new file mode 100644 index 0000000000..675077d7b4 --- /dev/null +++ b/plugins/HistoryStats/src/bandctrlimpl.cpp @@ -0,0 +1,1057 @@ +#include "_globals.h" +#include "bandctrlimpl.h" + +#include "main.h" +#include "resource.h" + +/* + * BandCtrlImpl + */ + +const mu_text* BandCtrlImpl::m_ClassName = muT("HistoryStatsBand"); +const int BandCtrlImpl::m_PollId = 100; +const int BandCtrlImpl::m_PollDelay = 50; + +LRESULT CALLBACK BandCtrlImpl::staticWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + BandCtrlImpl* pCtrl = reinterpret_cast(GetWindowLong(hWnd, 0)); + + switch (msg) + { + case WM_NCCREATE: + pCtrl = new BandCtrlImpl(hWnd, reinterpret_cast(reinterpret_cast(lParam)->hMenu)); + SetWindowLong(hWnd, 0, reinterpret_cast(pCtrl)); + return TRUE; + + case WM_DESTROY: + delete pCtrl; + SetWindowLong(hWnd, 0, 0); + return 0; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS; + + case WM_SETFOCUS: + pCtrl->onWMSetFocus(); + return 0; + + case WM_KILLFOCUS: + if (pCtrl->m_nCurFocused != -1) + { + pCtrl->m_nCurFocused = -1; + InvalidateRect(pCtrl->m_hWnd, NULL, TRUE); + } + return 0; + + case WM_ENABLE: + InvalidateRect(pCtrl->m_hWnd, NULL, TRUE); + return 0; + + case WM_GETFONT: + return reinterpret_cast(pCtrl->m_hFont); + + case WM_SETFONT: + pCtrl->m_hFont = reinterpret_cast(wParam); + return 0; + + case WM_WINDOWPOSCHANGED: + pCtrl->recalcButtonRects(); + InvalidateRect(pCtrl->m_hWnd, NULL, TRUE); + return 0; + + case WM_KEYDOWN: + pCtrl->onWMKeyDown(wParam); + return 0; + + case WM_KEYUP: + pCtrl->onWMKeyUp(wParam); + return 0; + + case WM_MOUSEMOVE: + pCtrl->onWMMouseMove(MAKEPOINTS(lParam)); + return 0; + + case WM_MOUSELEAVE: + pCtrl->onWMMouseLeave(); + return 0; + + case WM_TIMER: + if (wParam == m_PollId) + { + RECT rect; + POINT pt; + + GetWindowRect(pCtrl->m_hWnd, &rect); + GetCursorPos(&pt); + + if (!PtInRect(&rect, pt)) + { + PostMessage(pCtrl->m_hWnd, WM_MOUSELEAVE, 0, 0); + KillTimer(pCtrl->m_hWnd, m_PollId); + } + } + return 0; + + case WM_LBUTTONDOWN: + pCtrl->onWMLButtonDown(MAKEPOINTS(lParam)); + return 0; + + case WM_LBUTTONUP: + pCtrl->onWMLButtonUp(MAKEPOINTS(lParam)); + return 0; + + case WM_PAINT: + pCtrl->onWMPaint(); + return 0; + + case WM_ERASEBKGND: + return TRUE; + + case WM_THEMECHANGED: + pCtrl->reloadTheme(); + return 0; + + case BCM_ADDBUTTON: + return pCtrl->onBCMAddButton(reinterpret_cast(lParam)); + + case BCM_ISBUTTONCHECKED: + assert(wParam >= 1 && wParam <= pCtrl->m_Items.size()); + return BOOL_(pCtrl->m_Items[wParam - 1].bChecked); + + case BCM_CHECKBUTTON: + pCtrl->onBCMCheckButton(wParam - 1, bool_(lParam)); + return 0; + + case BCM_GETBUTTONDATA: + assert(wParam >= 1 && wParam <= pCtrl->m_Items.size()); + return pCtrl->m_Items[wParam - 1].dwData; + + case BCM_SETBUTTONDATA: + assert(wParam >= 1 && wParam <= pCtrl->m_Items.size()); + pCtrl->m_Items[wParam - 1].dwData = static_cast(lParam); + return 0; + + case BCM_ISBUTTONVISIBLE: + assert(wParam >= 1 && wParam <= pCtrl->m_Items.size()); + return BOOL_(pCtrl->m_Items[wParam - 1].bVisible); + + case BCM_SHOWBUTTON: + pCtrl->onBCMShowButton(wParam - 1, bool_(lParam)); + return 0; + + case BCM_SETLAYOUT: + assert(static_cast(wParam) >= 0); + pCtrl->m_nLayout = wParam; + pCtrl->recalcButtonRects(); + InvalidateRect(pCtrl->m_hWnd, NULL, TRUE); + return 0; + + case BCM_GETBUTTONRECT: + pCtrl->onBCMGetButtonRect(wParam - 1, reinterpret_cast(lParam)); + return 0; + + case BCM_ISBUTTONENABLED: + assert(wParam >= 1 && wParam <= pCtrl->m_Items.size()); + return BOOL_(pCtrl->m_Items[wParam - 1].bEnabled); + + case BCM_ENABLEBUTTON: + pCtrl->onBCMEnableButton(wParam - 1, bool_(lParam)); + return 0; + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +bool BandCtrlImpl::registerClass() +{ + const WNDCLASSEX wcx = { + sizeof(wcx), // cbSize + 0, // style + staticWndProc, // lpfnWndProc + 0, // cbClsExtra + sizeof(BandCtrlImpl*), // cbWndExtra + g_hInst, // hInstance + NULL, // hIcon + NULL, // hCursor + NULL, // hbrBackground + NULL, // lpszMenuName + m_ClassName, // lpszClassName + NULL // hIconSm + }; + + if (!RegisterClassEx(&wcx)) + { + return false; + } + + return true; +} + +void BandCtrlImpl::unregisterClass() +{ + UnregisterClass(m_ClassName, g_hInst); +} + +BandCtrlImpl::BandCtrlImpl(HWND hWnd, int nOwnId) + : m_hWnd(hWnd), m_nOwnId(nOwnId), m_hFont(NULL), + m_hTheme(NULL), m_hImageList(NULL), m_hImageListD(NULL), m_hTooltip(NULL), + m_nCurHot(-1), m_nCurFocused(-1), m_nCurPressed(-1), m_bCurPressedDD(false), + m_nLayout(0), m_nDDWidth(12), m_hDDIcon(NULL) +{ + m_IconSize.cx = m_IconSize.cy; + m_hDDIcon = reinterpret_cast(LoadImage(g_hInst, MAKEINTRESOURCE(IDI_DROPDOWN), IMAGE_ICON, OS::smIconCX(), OS::smIconCY(), 0)); + + reloadTheme(); +} + +BandCtrlImpl::~BandCtrlImpl() +{ + if (m_hTooltip) + { + DestroyWindow(m_hTooltip); + m_hTooltip = NULL; + } + + if (m_hImageList) + { + ImageList_Destroy(m_hImageList); + m_hImageList = NULL; + } + + if (m_hImageListD) + { + ImageList_Destroy(m_hImageListD); + m_hImageListD = NULL; + } + + if (m_hTheme) + { + ThemeAPI::CloseThemeData(m_hTheme); + m_hTheme = NULL; + } + + if (m_hDDIcon) + { + DestroyIcon(m_hDDIcon); + m_hDDIcon; + } +} + +void BandCtrlImpl::onWMPaint() +{ + // start painting + PAINTSTRUCT ps; + HDC hRealDC; + + if (!(hRealDC = BeginPaint(m_hWnd, &ps))) + { + return; + } + + // get rect for painting + RECT rOut; + + GetClientRect(m_hWnd, &rOut); + + // setup memory DC for bufferd drawing + HDC hDC; + HBITMAP hMemBitmap, hOldBitmap; + + hDC = CreateCompatibleDC(hRealDC); + hMemBitmap = CreateCompatibleBitmap(hRealDC, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); + hOldBitmap = reinterpret_cast(SelectObject(hDC, hMemBitmap)); + SetWindowOrgEx(hDC, ps.rcPaint.left, ps.rcPaint.top, NULL); + + // fill background + bool bBandEnabled = bool_(IsWindowEnabled(m_hWnd)); + + SetBkColor(hDC, GetSysColor(bBandEnabled ? COLOR_WINDOW : COLOR_BTNFACE)); + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rOut, NULL, 0, NULL); + + // draw top and bottom line + if (bBandEnabled) + { + RECT rLine = { rOut.left, rOut.top, rOut.right, rOut.top + 1 }; + + SetBkColor(hDC, GetSysColor(COLOR_3DSHADOW)); + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rLine, NULL, 0, NULL); + + rLine.top = (rLine.bottom = rOut.bottom) - 1; + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rLine, NULL, 0, NULL); + } + + // draw items + HGDIOBJ hOldFont = SelectObject(hDC, m_hFont); + SIZE textSize; + + GetTextExtentPoint32(hDC, muT("X"), 1, &textSize); + SetBkMode(hDC, TRANSPARENT); + SetTextColor(hDC, GetSysColor(bBandEnabled ? COLOR_BTNTEXT : COLOR_GRAYTEXT)); + + vector_each_(i, m_Items) + { + if (m_Items[i].bVisible) + { + drawButton(hDC, i, textSize.cy, bBandEnabled); + } + } + + SelectObject(hDC, hOldFont); + + // write back memory DC + BitBlt(hRealDC, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + SelectObject(hDC, hOldBitmap); + DeleteObject(hOldBitmap); + DeleteDC(hDC); + + // end painting + EndPaint(m_hWnd, &ps); +} + +void BandCtrlImpl::drawButton(HDC hDC, int nItem, int textHeight, bool bBandEnabled) +{ + const ItemData& item = m_Items[nItem]; + + bool bFocused = (nItem == m_nCurFocused); + bool bHot = (nItem == m_nCurHot); + bool bPressed = (nItem == m_nCurPressed); + bool bEnabled = bBandEnabled && item.bEnabled; + + // MEMO: beautified keyboard focus, remove following two lines to get back ugly one + bHot = bHot || bFocused; + bFocused = false; + + RECT rItem = item.rItem; + + if (item.bDropDown) + { + RECT rDropDown = rItem; + + rDropDown.left = rDropDown.right - m_nDDWidth; + rItem.right -= m_nDDWidth; + + if (m_hTheme) + { + int state = TS_DISABLED; + + if (bEnabled) + { + state = bPressed ? (m_bCurPressedDD ? TS_PRESSED : TS_HOT) : (item.bChecked ? (bHot ? TS_HOTCHECKED : TS_CHECKED) : (bHot ? TS_HOT : TS_NORMAL)); + } + + ThemeAPI::DrawThemeBackground(m_hTheme, hDC, TP_SPLITBUTTONDROPDOWN, state, &rDropDown, NULL); + } + else + { + --rDropDown.left; + + UINT state = 0; + + if (bEnabled) + { + state = bPressed ? (m_bCurPressedDD ? DFCS_FLAT | DFCS_PUSHED : DFCS_FLAT) : (bHot ? DFCS_FLAT : (item.bChecked ? DFCS_FLAT | DFCS_CHECKED : 0)); + } + + if (state != 0) + { + DrawFrameControl(hDC, &rDropDown, DFC_BUTTON, DFCS_BUTTONPUSH | state); + } + + int x = rDropDown.left + (rDropDown.right - rDropDown.left - OS::smIconCX()) / 2; + int y = rDropDown.top + (rDropDown.bottom - rDropDown.top - OS::smIconCY()) / 2; + + DrawState(hDC, NULL, NULL, reinterpret_cast(m_hDDIcon), 0, x, y, m_IconSize.cx, m_IconSize.cy, DST_ICON | (bEnabled ? 0 : DSS_DISABLED)); + } + } + + if (m_hTheme) + { + int state = TS_DISABLED; + int part = item.bDropDown ? TP_SPLITBUTTON : TP_BUTTON; + + if (bEnabled) + { + state = bPressed ? (!m_bCurPressedDD ? TS_PRESSED : TS_HOT) : (item.bChecked ? (bHot ? TS_HOTCHECKED : TS_CHECKED) : (bHot ? TS_HOT : TS_NORMAL)); + } + + ThemeAPI::DrawThemeBackground(m_hTheme, hDC, part, state, &rItem, NULL); + } + else + { + UINT state = 0; + + if (bEnabled) + { + state = bPressed ? (!m_bCurPressedDD ? DFCS_FLAT | DFCS_PUSHED : DFCS_FLAT) : (bHot ? DFCS_FLAT : (item.bChecked ? DFCS_FLAT | DFCS_CHECKED : 0)); + } + + if (state != 0) + { + DrawFrameControl(hDC, &rItem, DFC_BUTTON, DFCS_BUTTONPUSH | state); + } + } + + InflateRect(&rItem, -3, -3); + + if (!item.text.empty()) + { + RECT rText = rItem; + + rText.top += (rItem.bottom - rItem.top + m_IconSize.cy - textHeight) / 2; + rItem.bottom -= textHeight; + + DrawText( + hDC, + item.text.c_str(), + item.text.length(), + &rText, + DT_TOP | DT_CENTER | DT_END_ELLIPSIS | DT_WORD_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE); + } + + if (item.nIcon != -1) + { + int x = rItem.left + (rItem.right - rItem.left - m_IconSize.cx) / 2; + int y = rItem.top + (rItem.bottom - rItem.top - m_IconSize.cy) / 2; + + if (bPressed && !m_bCurPressedDD) + { + ++x; + ++y; + } + + if (bEnabled) + { + ImageList_Draw( + m_hImageList, + item.nIcon, + hDC, + x, + y, + ILD_NORMAL); + } + else if (item.nIconD != -1) + { + ImageList_Draw( + m_hImageListD, + item.nIconD, + hDC, + x, + y, + ILD_NORMAL); + } + else + { + HICON hIcon = ImageList_GetIcon(m_hImageList, item.nIcon, 0); + + DrawState(hDC, NULL, NULL, reinterpret_cast(hIcon), 0, x, y, m_IconSize.cx, m_IconSize.cy, DST_ICON | DSS_DISABLED); + DestroyIcon(hIcon); + } + } + + if (bFocused) + { + rItem = item.rItem; + + InflateRect(&rItem, -2, -2); + DrawFocusRect(hDC, &rItem); + } +} + +void BandCtrlImpl::reloadTheme() +{ + if (m_hTheme) + { + ThemeAPI::CloseThemeData(m_hTheme); + m_hTheme = NULL; + } + + m_nDDWidth = 12; + + if (ThemeAPI::useTheme()) + { + m_hTheme = ThemeAPI::OpenThemeData(0, muW("TOOLBAR")); + + /* + SIZE sizeMin; + HDC hDC = GetDC(NULL); + + ThemeAPI::GetThemePartSize(m_hTheme, hDC, TP_SPLITBUTTONDROPDOWN, TS_NORMAL, NULL, TS_DRAW, &sizeMin); + ReleaseDC(NULL, hDC); + + m_nDDWidth = sizeMin.cx; + */ + } + + recalcButtonRects(); +} + +HICON BandCtrlImpl::convertToGray(HICON hIcon) +{ + // quick and dirty conversion to grayscale + // preserves transparency + // works only for 32bit icons + + HICON hIconDisabled = NULL; + ICONINFO ii; + + if (!GetIconInfo(hIcon, &ii)) + { + return NULL; + } + + BITMAP bmp; + + if (GetObject(ii.hbmColor, sizeof(bmp), &bmp) && bmp.bmBitsPixel == 32) + { + int nSize = bmp.bmHeight * bmp.bmWidthBytes; + BYTE* pBits = new BYTE[nSize]; + + if (GetBitmapBits(ii.hbmColor, nSize, pBits)) + { + for (int y = 0; y < bmp.bmHeight; ++y) + { + BYTE* pLine = pBits + y * bmp.bmWidthBytes; + + for (int x = 0; x < bmp.bmWidth; ++x) + { + DWORD color = reinterpret_cast(pLine)[x]; + BYTE gray = (77 * GetBValue(color) + 150 * GetGValue(color) + 28 * GetRValue(color)) / 255; + + color = (color & 0xFF000000) | RGB(gray, gray, gray); + + reinterpret_cast(pLine)[x] = color; + } + } + + SetBitmapBits(ii.hbmColor, nSize, pBits); + + hIconDisabled = CreateIconIndirect(&ii); + } + + delete pBits; + } + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + + return hIconDisabled; +} + +int BandCtrlImpl::onBCMAddButton(BCBUTTON* pButton) +{ + assert(pButton); + + m_Items.push_back(ItemData()); + + ItemData& id = m_Items.back(); + + id.bRight = bool_(pButton->dwFlags & BCF_RIGHT); + id.bChecked = bool_(pButton->dwFlags & BCF_CHECKED); + id.bVisible = !(pButton->dwFlags & BCF_HIDDEN); + id.bDropDown = bool_(pButton->dwFlags & BCF_DROPDOWN); + id.text = (pButton->dwFlags & BCF_TEXT) ? pButton->szText : muT(""); + id.tooltip = (pButton->dwFlags & BCF_TOOLTIP) ? pButton->szTooltip : muT(""); + id.uTTId = -1; + id.dwData = (pButton->dwFlags & BCF_DATA) ? pButton->dwData : 0; + id.bEnabled = !(pButton->dwFlags & BCF_DISABLED); + id.nIcon = -1; + id.nIconD = -1; + + if (pButton->dwFlags & BCF_ICON) + { + // create an image list, if needed + if (!m_hImageList) + { + // guess image size from first inserted icon + ICONINFO ii; + + if (GetIconInfo(pButton->hIcon, &ii)) + { + BITMAP bmp; + + if (GetObject(ii.hbmColor, sizeof(bmp), &bmp)) + { + m_IconSize.cx = bmp.bmWidth; + m_IconSize.cy = bmp.bmHeight; + } + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + } + + m_hImageList = ImageList_Create(m_IconSize.cx, m_IconSize.cy, OS::imageListColor() | ILC_MASK, 5, 5); + } + + // insert icon into image list + id.nIcon = ImageList_AddIcon(m_hImageList, pButton->hIcon); + + // insert disabled icon into image list + HICON hIconDisabled = convertToGray(pButton->hIcon); + + if (hIconDisabled) + { + if (!m_hImageListD) + { + m_hImageListD = ImageList_Create(m_IconSize.cx, m_IconSize.cy, OS::imageListColor() | ILC_MASK, 5, 5); + } + + id.nIconD = ImageList_AddIcon(m_hImageListD, hIconDisabled); + + DestroyIcon(hIconDisabled); + } + } + + // atomatically adds tooltip, if needed + recalcButtonRects(); + + if (id.bVisible) + { + InvalidateRect(m_hWnd, &id.rItem, TRUE); + } + + return m_Items.size(); +} + +void BandCtrlImpl::onBCMCheckButton(int nItem, bool bCheck) +{ + assert(nItem >= 0 && nItem < m_Items.size()); + + ItemData& id = m_Items[nItem]; + + if (bCheck != id.bChecked) + { + id.bChecked = bCheck; + InvalidateRect(m_hWnd, &id.rItem, TRUE); + } +} + +void BandCtrlImpl::onBCMShowButton(int nItem, bool bShow) +{ + assert(nItem >= 0 && nItem < m_Items.size()); + + ItemData& id = m_Items[nItem]; + + if (bShow != id.bVisible) + { + id.bVisible = bShow; + recalcButtonRects(); + InvalidateRect(m_hWnd, NULL, TRUE); + } +} + +void BandCtrlImpl::onBCMGetButtonRect(int nItem, RECT* pRect) +{ + assert(nItem >= 0 && nItem < m_Items.size()); + assert(pRect); + + *pRect = m_Items[nItem].rItem; +} + +void BandCtrlImpl::onBCMEnableButton(int nItem, bool bEnable) +{ + assert(nItem >= 0 && nItem < m_Items.size()); + + ItemData& id = m_Items[nItem]; + + if (bEnable != id.bEnabled) + { + id.bEnabled = bEnable; + InvalidateRect(m_hWnd, NULL, TRUE); + } +} + +void BandCtrlImpl::recalcButtonRects() +{ + RECT rOut; + + GetClientRect(m_hWnd, &rOut); + InflateRect(&rOut, -2, -3); + + int itemHeight = rOut.bottom - rOut.top; + int itemWidth = itemHeight; + + if (m_nLayout > 0) + { + itemWidth = (rOut.right - rOut.left) / m_nLayout; + } + + RECT rItemL = { rOut.left, rOut.top, rOut.left + itemWidth, rOut.top + itemHeight }; + RECT rItemR = { rOut.right - itemWidth, rOut.top, rOut.right, rOut.top + itemHeight }; + + vector_each_(i, m_Items) + { + if (m_Items[i].bVisible) + { + // visible: give it a rect and advance + int nDDWidth = (m_Items[i].bDropDown && m_nLayout == 0) ? m_nDDWidth : 0; + + if (m_Items[i].bRight) + { + m_Items[i].rItem = rItemR; + m_Items[i].rItem.left -= nDDWidth; + OffsetRect(&rItemR, -(itemWidth + nDDWidth), 0); + } + else + { + m_Items[i].rItem = rItemL; + m_Items[i].rItem.right += nDDWidth; + OffsetRect(&rItemL, itemWidth + nDDWidth, 0); + } + } + + if (m_Items[i].uTTId != -1 && m_Items[i].bVisible) + { + // update tooltip rect, if we have a tooltip and are still visible + TOOLINFO ti = { + sizeof(TOOLINFO), // cbSize + TTF_SUBCLASS, // uFlags + m_hWnd, // hwnd + m_Items[i].uTTId, // uId + m_Items[i].rItem, // rect + NULL, // hInstance + const_cast(m_Items[i].tooltip.c_str()), // lpszText + }; + + SendMessage(m_hTooltip, TTM_SETTOOLINFO, 0, reinterpret_cast(&ti)); + } + else if (m_Items[i].uTTId != -1 && !m_Items[i].bVisible) + { + // remove tooltip, if we have a tooltip but are no longer visible + TOOLINFO ti; + + ti.cbSize = sizeof(TOOLINFO); + ti.hwnd = m_hWnd; + ti.uId = m_Items[i].uTTId; + + SendMessage(m_hTooltip , TTM_DELTOOL, 0, reinterpret_cast(&ti)); + + m_Items[i].uTTId = -1; + } + else if (m_Items[i].uTTId == -1 && m_Items[i].bVisible && !m_Items[i].tooltip.empty()) + { + // add a tooltip, if we don't have a tooltip but are now visible + if (!m_hTooltip) + { + m_hTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, muT(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, g_hInst, NULL); + } + + TOOLINFO ti = { + sizeof(TOOLINFO), // cbSize + TTF_SUBCLASS, // uFlags + m_hWnd, // hwnd + i + 1, // uId + m_Items[i].rItem, // rect + NULL, // hInstance + const_cast(m_Items[i].tooltip.c_str()), // lpszText + }; + + if (SendMessage(m_hTooltip, TTM_ADDTOOL, 0, reinterpret_cast(&ti))) + { + m_Items[i].uTTId = ti.uId; + } + } + } +} + +int BandCtrlImpl::getNextButton(int nItem) +{ + if (nItem < 0 || nItem >= m_Items.size()) + { + nItem = -1; + } + + int nNext = nItem; + int nLastLeft = -1; + bool bLeft = !(nItem != -1 && m_Items[nItem].bRight); + + vector_each_(i, m_Items) + { + if (m_Items[i].bVisible && !m_Items[i].bRight) + { + nLastLeft = i; + } + } + + vector_each_(i, m_Items) + { + if (!m_Items[i].bVisible) + continue; + + if (nItem == nLastLeft) + { + if (m_Items[i].bRight) + { + nNext = i; + } + } + else if (!bLeft) + { + if (m_Items[i].bRight && i < nItem) + { + nNext = i; + break; + } + } + else + { + if (!m_Items[i].bRight && i > nNext) + { + nNext = i; + break; + } + } + } + + return nNext; +} + +int BandCtrlImpl::getPrevButton(int nItem) +{ + if (nItem < 0 || nItem >= m_Items.size()) + { + nItem = -1; + } + + int nPrev = nItem; + int nFirstRight = -1; + bool bRight = (nItem != -1 && m_Items[nItem].bRight); + + vector_each_(i, m_Items) + { + if (m_Items[i].bVisible && m_Items[i].bRight) + { + nFirstRight = i; + } + } + + vector_each_(i, m_Items) + { + if (!m_Items[i].bVisible) + continue; + + if (!bRight) + { + if (!m_Items[i].bRight && i < nItem) + { + nPrev = i; + } + } + else if (nItem == nFirstRight) + { + if (!m_Items[i].bRight) + { + nPrev = i; + } + } + else + { + if (m_Items[i].bRight && i > nPrev) + { + nPrev = i; + break; + } + } + } + + return nPrev; +} + +void BandCtrlImpl::fireEvent(UINT code, int nItem) +{ + NMBANDCTRL nmbc; + + nmbc.hdr.code = code; + nmbc.hdr.hwndFrom = m_hWnd; + nmbc.hdr.idFrom = m_nOwnId; + nmbc.hButton = reinterpret_cast(nItem + 1); + nmbc.dwData = m_Items[nItem].dwData; + + SendMessage(GetParent(m_hWnd), WM_NOTIFY, nmbc.hdr.idFrom, reinterpret_cast(&nmbc)); +} + +void BandCtrlImpl::onWMSetFocus() +{ + /* + int nFirst = getNextItem(-1); + + if (nFirst != -1) + { + m_nCurFocused = nFirst; + InvalidateRect(m_hWnd, NULL, TRUE); + } + */ + + m_nCurFocused = -1; +} + + +void BandCtrlImpl::onWMKeyDown(int nVirtKey) +{ + if (GetKeyState(VK_CONTROL) & ~1 || GetKeyState(VK_SHIFT) & ~1) + { + return; + } + + if (nVirtKey == VK_RIGHT) + { + int nNext = getNextButton(m_nCurFocused); + + if (nNext != -1 && nNext != m_nCurFocused) + { + m_nCurFocused = nNext; + InvalidateRect(m_hWnd, NULL, TRUE); + } + } + else if (nVirtKey == VK_LEFT) + { + int nPrev = getPrevButton(m_nCurFocused); + + if (nPrev != -1 && nPrev != m_nCurFocused) + { + m_nCurFocused = nPrev; + InvalidateRect(m_hWnd, NULL, TRUE); + } + } + else if (nVirtKey == VK_SPACE) + { + if (m_nCurFocused != -1 && m_nCurFocused < m_Items.size() && m_Items[m_nCurFocused].bEnabled) + { + m_nCurPressed = m_nCurFocused; + m_bCurPressedDD = false; + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + } + } + else if (nVirtKey == VK_DOWN) + { + if (m_nCurFocused != -1 && m_nCurFocused < m_Items.size() && m_Items[m_nCurFocused].bDropDown && m_Items[m_nCurFocused].bEnabled) + { + m_nCurPressed = m_nCurFocused; + m_bCurPressedDD = true; + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + + fireEvent(BCN_DROPDOWN, m_nCurPressed); + + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + m_nCurPressed = -1; + m_bCurPressedDD = false; + } + } +} + +void BandCtrlImpl::onWMKeyUp(int nVirtKey) +{ + if (GetKeyState(VK_CONTROL) & ~1 || GetKeyState(VK_SHIFT) & ~1) + { + return; + } + + if (nVirtKey == VK_SPACE && m_nCurPressed != -1 && m_nCurPressed < m_Items.size()) + { + if (m_nCurFocused == m_nCurPressed) + { + fireEvent(BCN_CLICKED, m_nCurPressed); + } + + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + m_nCurPressed = -1; + m_bCurPressedDD = false; + } +} + +void BandCtrlImpl::onWMMouseLeave() +{ + int nOldHot = m_nCurHot; + + m_nCurHot = -1; + + if (nOldHot != -1 && nOldHot < m_Items.size()) + { + InvalidateRect(m_hWnd, &m_Items[nOldHot].rItem, TRUE); + } +} + +void BandCtrlImpl::onWMMouseMove(POINTS pts) +{ + POINT pt = { pts.x, pts.y }; + + if (m_nCurHot != -1 && m_nCurHot < m_Items.size()) + { + if (!PtInRect(&m_Items[m_nCurHot].rItem, pt)) + { + InvalidateRect(m_hWnd, &m_Items[m_nCurHot].rItem, TRUE); + m_nCurHot = -1; + } + } + + if (m_nCurHot == -1) + { + vector_each_(i, m_Items) + { + if (PtInRect(&m_Items[i].rItem, pt) && m_Items[i].bVisible) + { + m_nCurHot = i; + InvalidateRect(m_hWnd, &m_Items[i].rItem, TRUE); + break; + } + } + } + + if (m_nCurHot != -1) + { + SetTimer(m_hWnd, m_PollId, m_PollDelay, NULL); + } +} + +void BandCtrlImpl::onWMLButtonDown(POINTS pts) +{ + POINT pt = { pts.x, pts.y }; + + if (m_nCurHot != -1 && m_nCurHot < m_Items.size() && m_Items[m_nCurHot].bEnabled) + { + if (PtInRect(&m_Items[m_nCurHot].rItem, pt)) + { + m_nCurPressed = m_nCurHot; + m_bCurPressedDD = false; + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + SetCapture(m_hWnd); + + if (m_Items[m_nCurHot].bDropDown) + { + RECT rDropDown = m_Items[m_nCurHot].rItem; + + rDropDown.left = rDropDown.right - m_nDDWidth; + + if (PtInRect(&rDropDown, pt)) + { + ReleaseCapture(); + m_bCurPressedDD = true; + + fireEvent(BCN_DROPDOWN, m_nCurPressed); + + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + m_nCurPressed = -1; + m_bCurPressedDD = false; + } + } + } + } +} + +void BandCtrlImpl::onWMLButtonUp(POINTS pts) +{ + POINT pt = { pts.x, pts.y }; + + if (m_nCurPressed != -1 && m_nCurPressed < m_Items.size()) + { + ReleaseCapture(); + + if (PtInRect(&m_Items[m_nCurPressed].rItem, pt)) + { + fireEvent(BCN_CLICKED, m_nCurPressed); + } + + InvalidateRect(m_hWnd, &m_Items[m_nCurPressed].rItem, TRUE); + m_nCurPressed = -1; + m_bCurPressedDD = false; + } +} -- cgit v1.2.3