summaryrefslogtreecommitdiff
path: root/plugins/HistoryStats/src/bandctrlimpl.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2014-03-04 23:23:45 +0000
committerGeorge Hazan <george.hazan@gmail.com>2014-03-04 23:23:45 +0000
commit15855fa84a09fd1fd486d357c38db0f2bd181e74 (patch)
treec98d1ae74abca41c776522059343eda13a7e0a31 /plugins/HistoryStats/src/bandctrlimpl.cpp
parent819f8efabea6b0d7d971f9e6e4b21bbc18838874 (diff)
HistoryStats compiles ok now
git-svn-id: http://svn.miranda-ng.org/main/trunk@8399 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/HistoryStats/src/bandctrlimpl.cpp')
-rw-r--r--plugins/HistoryStats/src/bandctrlimpl.cpp1057
1 files changed, 1057 insertions, 0 deletions
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<BandCtrlImpl*>(GetWindowLong(hWnd, 0));
+
+ switch (msg)
+ {
+ case WM_NCCREATE:
+ pCtrl = new BandCtrlImpl(hWnd, reinterpret_cast<int>(reinterpret_cast<CREATESTRUCT*>(lParam)->hMenu));
+ SetWindowLong(hWnd, 0, reinterpret_cast<LONG>(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<LRESULT>(pCtrl->m_hFont);
+
+ case WM_SETFONT:
+ pCtrl->m_hFont = reinterpret_cast<HFONT>(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<BCBUTTON*>(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<DWORD>(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<int>(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<RECT*>(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<HICON>(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<HBITMAP>(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<LPARAM>(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<LPARAM>(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<DWORD*>(pLine)[x];
+ BYTE gray = (77 * GetBValue(color) + 150 * GetGValue(color) + 28 * GetRValue(color)) / 255;
+
+ color = (color & 0xFF000000) | RGB(gray, gray, gray);
+
+ reinterpret_cast<DWORD*>(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<mu_text*>(m_Items[i].tooltip.c_str()), // lpszText
+ };
+
+ SendMessage(m_hTooltip, TTM_SETTOOLINFO, 0, reinterpret_cast<LPARAM>(&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<LPARAM>(&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<mu_text*>(m_Items[i].tooltip.c_str()), // lpszText
+ };
+
+ if (SendMessage(m_hTooltip, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&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<HANDLE>(nItem + 1);
+ nmbc.dwData = m_Items[nItem].dwData;
+
+ SendMessage(GetParent(m_hWnd), WM_NOTIFY, nmbc.hdr.idFrom, reinterpret_cast<LPARAM>(&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;
+ }
+}