3192 lines
No EOL
83 KiB
C++
3192 lines
No EOL
83 KiB
C++
#include "./loginTab.h"
|
|
#include "./common.h"
|
|
#include "./imageLoader.h"
|
|
#include "./loginGui.h"
|
|
#include "./graphics.h"
|
|
|
|
#include "../api.h"
|
|
#include "../resource.h"
|
|
#include "../../nu/archTheme.h"
|
|
|
|
#include <vssym32.h>
|
|
#include <vsstyle.h>
|
|
|
|
#include <malloc.h>
|
|
#include <math.h>
|
|
#include <shlwapi.h>
|
|
#include <commctrl.h>
|
|
#include <strsafe.h>
|
|
|
|
#define MAX_TEXT_AVECHAR_WIDTH 12
|
|
#define MAX_HELP_AVECHAR_WIDTH 28
|
|
#define IMAGE_MARGIN_CY 4
|
|
#define IMAGE_MARGIN_CX 4
|
|
|
|
#define NLTDS_FOCUSED 0x00000001
|
|
#define NLTDS_DISABLED 0x00000002
|
|
#define NLTDS_LOCKED 0x00000004
|
|
|
|
|
|
typedef struct __LOGINTABITEM
|
|
{
|
|
LPWSTR text;
|
|
UINT iImage;
|
|
UINT iImageActive;
|
|
UINT iImageDisabled;
|
|
LPARAM param;
|
|
LONG textWidth;
|
|
} LOGINTABITEM;
|
|
|
|
typedef struct __ITEMSTATECOLORTABLE
|
|
{
|
|
COLORREF backTop;
|
|
COLORREF backBottom;
|
|
COLORREF backAlpha;
|
|
COLORREF text;
|
|
INT frameType;
|
|
} ITEMSTATECOLORTABLE;
|
|
|
|
typedef struct __ITEMCOLORTABLE
|
|
{
|
|
ITEMSTATECOLORTABLE normal;
|
|
ITEMSTATECOLORTABLE normalPressed;
|
|
ITEMSTATECOLORTABLE normalHigh;
|
|
ITEMSTATECOLORTABLE normalDisabled;
|
|
ITEMSTATECOLORTABLE selected;
|
|
ITEMSTATECOLORTABLE selectedPressed;
|
|
ITEMSTATECOLORTABLE selectedHigh;
|
|
ITEMSTATECOLORTABLE selectedDisabled;
|
|
} ITEMCOLORTABLE;
|
|
|
|
typedef struct __COLORTABLE
|
|
{
|
|
COLORREF backTop;
|
|
COLORREF backBottom;
|
|
COLORREF backLine;
|
|
COLORREF focus;
|
|
COLORREF focusDash;
|
|
ITEMCOLORTABLE item;
|
|
} COLORTABLE;
|
|
|
|
|
|
typedef struct __LOGINTAB
|
|
{
|
|
LOGINTABITEM **items;
|
|
INT itemsCount;
|
|
INT *order;
|
|
INT iSelected;
|
|
INT iHighlighted;
|
|
INT iPressed;
|
|
INT iFocused;
|
|
HIMAGELIST imageList;
|
|
UINT drawStyle;
|
|
|
|
COLORTABLE colors;
|
|
|
|
HFONT fontText;
|
|
|
|
LONG textHeight;
|
|
LONG spacing;
|
|
RECT margins;
|
|
LONG textWidthMax;
|
|
|
|
HBITMAP chevronImage;
|
|
INT chevronWidth;
|
|
HMENU chevronMenu;
|
|
|
|
LONG chevronLeft;
|
|
LONG visibleRight;
|
|
INT lastVisible;
|
|
|
|
HBITMAP frameBitmap;
|
|
INT frameHeight;
|
|
INT frameWidth;
|
|
|
|
HBITMAP itemBitmap;
|
|
|
|
HWND hTooltip;
|
|
BSTR helpText;
|
|
|
|
} LOGINTAB;
|
|
|
|
typedef struct __CALCITEMWIDTH
|
|
{
|
|
HDC hdc;
|
|
HFONT font;
|
|
HWND hwnd;
|
|
INT textWidthMax;
|
|
INT imageWidth;
|
|
INT imageHeight;
|
|
INT itemHeight;
|
|
INT frameWidth;
|
|
INT dialogPt;
|
|
HDC ownedDC;
|
|
HFONT ownedFont;
|
|
} CALCITEMWIDTH;
|
|
|
|
#define FRAMETYPE_NONE 0
|
|
#define FRAMETYPE_SELECTED 1
|
|
#define FRAMETYPE_ACTIVE 2
|
|
#define FRAMETYPE_DISABLED 0
|
|
|
|
typedef struct __PAINTITEMPARAM
|
|
{
|
|
HWND hwndTab;
|
|
HDC hdc;
|
|
const RECT *prcPaint;
|
|
const RECT *prcClient;
|
|
HRGN clipRgn;
|
|
HRGN eraseRgn;
|
|
HDC hdcSrc;
|
|
HDC hdcItem;
|
|
} PAINTITEMPARAM;
|
|
|
|
typedef struct __GETITEMRECTPARAM
|
|
{
|
|
INT index;
|
|
RECT *rect;
|
|
} GETITEMRECTPARAM;
|
|
|
|
typedef struct __HITTESTITEMPARAM
|
|
{
|
|
POINT pt;
|
|
RECT *rect;
|
|
} HITTESTITEMPARAM;
|
|
|
|
typedef struct __UPDATELAYOUTPARAM
|
|
{
|
|
INT itemCount;
|
|
RECT visibleBox;
|
|
BOOL chevronVisible;
|
|
LONG chevronLeft;
|
|
} UPDATELAYOUTPARAM;
|
|
|
|
typedef struct __CHEVRONMENUPAINTPARAM
|
|
{
|
|
INT itemWidth;
|
|
INT itemHeight;
|
|
HDC hdcSrc;
|
|
HDC hdcItem;
|
|
RECT ownerRect;
|
|
HWND hwndMenu;
|
|
} CHEVRONMENUPAINTPARAM;
|
|
|
|
#define GetTab(__hwnd) ((LOGINTAB*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
|
|
|
|
static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
typedef INT (CALLBACK *ITEMRECTCALLBAC)(LOGINTAB* /*tab*/, LOGINTABITEM* /*item*/, INT /*iItem*/, const RECT* /*prcItem*/, ULONG_PTR /*param*/);
|
|
|
|
BOOL LoginTab_RegisterClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSW wc;
|
|
if (FALSE != GetClassInfo(hInstance, NWC_LOGINTAB, &wc))
|
|
return TRUE;
|
|
|
|
ZeroMemory(&wc, sizeof(wc));
|
|
|
|
wc.lpszClassName = NWC_LOGINTAB;
|
|
wc.lpfnWndProc = LoginTab_WindowProc;
|
|
wc.style = CS_PARENTDC;
|
|
wc.cbWndExtra = sizeof(LOGINTAB*);
|
|
wc.hInstance = hInstance;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
return ( 0 != RegisterClassW(&wc));
|
|
}
|
|
|
|
HWND LoginTab_CreateWindow(UINT styleEx, LPCWSTR pszTitle, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT_PTR controlId)
|
|
{
|
|
if (FALSE == LoginTab_RegisterClass(WASABI_API_ORIG_HINST))
|
|
return FALSE;
|
|
|
|
HWND hwnd = CreateWindowEx(styleEx, NWC_LOGINTAB, pszTitle, WS_CHILD | style,
|
|
x, y, cx, cy, hParent, (HMENU)controlId, WASABI_API_ORIG_HINST, NULL);
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
static BOOL LoginTab_IsLocked(HWND hwnd)
|
|
{
|
|
UINT windowStyle = GetWindowStyle(hwnd);
|
|
return (0 != (NLTS_LOCKED & windowStyle));
|
|
}
|
|
static BOOL LoginTab_InitCalcItemWidth(HWND hwnd, HDC hdc, CALCITEMWIDTH *pciw)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == pciw) return FALSE;
|
|
|
|
pciw->hdc = hdc;
|
|
pciw->font = tab->fontText;
|
|
pciw->hwnd = hwnd;
|
|
pciw->textWidthMax = tab->textWidthMax;
|
|
|
|
if (NULL == tab->imageList || FALSE == ImageList_GetIconSize(tab->imageList, &pciw->imageWidth, &pciw->imageHeight))
|
|
{
|
|
pciw->imageWidth = 0;
|
|
pciw->imageHeight = 0;
|
|
}
|
|
else
|
|
{
|
|
pciw->imageWidth += 2 * IMAGE_MARGIN_CX;
|
|
pciw->imageHeight += 2 * IMAGE_MARGIN_CY;
|
|
}
|
|
|
|
|
|
RECT rect;
|
|
GetClientRect(hwnd, &rect);
|
|
pciw->itemHeight = tab->frameHeight * 2 + tab->textHeight + pciw->imageHeight;
|
|
pciw->frameWidth = tab->frameWidth;
|
|
|
|
pciw->dialogPt = tab->spacing;
|
|
pciw->ownedDC = NULL;
|
|
pciw->ownedFont = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL LoginTab_DestroyCalcItemWidth(CALCITEMWIDTH *pciw)
|
|
{
|
|
if (NULL == pciw) return FALSE;
|
|
if (NULL != pciw->ownedDC)
|
|
{
|
|
SelectObject(pciw->ownedDC, pciw->ownedFont);
|
|
ReleaseDC(pciw->hwnd, pciw->ownedDC);
|
|
}
|
|
return TRUE;
|
|
}
|
|
static INT LoginTab_CalculateItemWidth(CALCITEMWIDTH *pciw, LOGINTABITEM *item)
|
|
{
|
|
if (NULL == pciw || NULL == item) return 0;
|
|
|
|
if (-1 == item->textWidth)
|
|
{
|
|
if (NULL != item->text && L'\0' != *(item->text))
|
|
{
|
|
if (NULL == pciw->hdc)
|
|
{
|
|
pciw->ownedDC = GetDCEx(pciw->hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
|
if (NULL == pciw->ownedDC) return 0;
|
|
pciw->ownedFont = (HFONT)SelectObject(pciw->ownedDC, pciw->font);
|
|
pciw->hdc = pciw->ownedDC;
|
|
}
|
|
|
|
SIZE textSize;
|
|
if (FALSE == GetTextExtentPoint(pciw->hdc, item->text, lstrlen(item->text), &textSize))
|
|
return 0;
|
|
|
|
item->textWidth = textSize.cx;
|
|
|
|
}
|
|
else
|
|
item->textWidth = 0;
|
|
}
|
|
|
|
INT width = (item->textWidth > pciw->imageWidth) ? item->textWidth : pciw->imageWidth;
|
|
if (width > pciw->textWidthMax) width = pciw->textWidthMax;
|
|
|
|
width += 2*pciw->frameWidth; // borders
|
|
|
|
if (width < pciw->itemHeight)
|
|
{
|
|
INT k = (pciw->itemHeight - width)/(2*pciw->dialogPt);
|
|
if (k > 2) k = 2;
|
|
width += 2*k*pciw->dialogPt;
|
|
}
|
|
|
|
return width;
|
|
|
|
}
|
|
static INT LoginTab_EnumerateItemRects(HWND hwnd, HDC hdc, ITEMRECTCALLBAC callback, ULONG_PTR param)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == callback) return -1;
|
|
|
|
RECT clientRect, tabRect;
|
|
LONG chevronLeft, limitRight;
|
|
GetClientRect(hwnd, &clientRect);
|
|
|
|
chevronLeft = clientRect.right - tab->chevronWidth;
|
|
|
|
clientRect.left += tab->margins.left;
|
|
clientRect.top += tab->margins.top;
|
|
clientRect.right -= tab->margins.right;
|
|
clientRect.bottom -= tab->margins.bottom;
|
|
|
|
limitRight = (chevronLeft < clientRect.right) ? chevronLeft : clientRect.right;
|
|
|
|
CALCITEMWIDTH calcWidth;
|
|
|
|
if (FALSE == LoginTab_InitCalcItemWidth(hwnd, hdc, &calcWidth))
|
|
return -1;
|
|
|
|
SetRect(&tabRect, clientRect.left, clientRect.top, clientRect.left, clientRect.bottom);
|
|
|
|
INT result, index, lastItem;
|
|
lastItem = tab->itemsCount - 1;
|
|
result = -1;
|
|
BOOL ignoreVisibleUpdate = FALSE;
|
|
|
|
for (index = 0; index < tab->itemsCount; index++)
|
|
{
|
|
tabRect.left = tabRect.right;
|
|
if (tabRect.left != clientRect.left)
|
|
tabRect.left += tab->spacing;
|
|
|
|
if (tabRect.left > limitRight)
|
|
{
|
|
tabRect.right = clientRect.right + 1;
|
|
break;
|
|
}
|
|
INT iItem = tab->order[index];
|
|
LOGINTABITEM *item = tab->items[iItem];
|
|
INT width = LoginTab_CalculateItemWidth(&calcWidth, item);
|
|
if (0 == width) break;
|
|
|
|
tabRect.right = tabRect.left + width;
|
|
if ((index == lastItem && tabRect.right > clientRect.right) ||
|
|
(index < lastItem && tabRect.right > limitRight))
|
|
{
|
|
break;
|
|
}
|
|
|
|
result = callback(tab, item, iItem, &tabRect, param);
|
|
if (-1 != result)
|
|
{
|
|
ignoreVisibleUpdate = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FALSE == ignoreVisibleUpdate)
|
|
{
|
|
if ((index == lastItem && tabRect.right > clientRect.right) ||
|
|
(index < lastItem && tabRect.right > limitRight))
|
|
{
|
|
tab->lastVisible = (index - 1);
|
|
|
|
SetRect(&tabRect, chevronLeft, clientRect.top,
|
|
clientRect.right + tab->margins.right, clientRect.bottom);
|
|
|
|
result = callback(tab, NULL, tab->itemsCount, &tabRect, param);
|
|
}
|
|
else
|
|
tab->lastVisible = lastItem;
|
|
}
|
|
|
|
LoginTab_DestroyCalcItemWidth(&calcWidth);
|
|
return result;
|
|
}
|
|
|
|
static void LoginTab_NotifySelectionChanged(HWND hwnd)
|
|
{
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
if (NULL == hParent) return;
|
|
|
|
NMHDR nmhdr;
|
|
nmhdr.code = NLTN_SELCHANGE;
|
|
nmhdr.hwndFrom = hwnd;
|
|
nmhdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
|
|
}
|
|
|
|
static HBITMAP LoginTab_GetItemBitmap(LOGINTAB *tab, HDC hdc, INT cx, INT cy)
|
|
{
|
|
if (cx < 1) cx = 1;
|
|
if (cy < 1) cy = 1;
|
|
|
|
BITMAP bm;
|
|
if (NULL == tab->itemBitmap ||
|
|
sizeof(BITMAP) != GetObject(tab->itemBitmap, sizeof(BITMAP), &bm) ||
|
|
bm.bmWidth <= cx || abs(bm.bmHeight) < cy)
|
|
{
|
|
if (NULL != tab->itemBitmap)
|
|
DeleteObject(tab->itemBitmap);
|
|
|
|
cx++; // need +1px to compose selection fill
|
|
tab->itemBitmap = CreateCompatibleBitmap(hdc, cx, cy);
|
|
}
|
|
|
|
return tab->itemBitmap;
|
|
}
|
|
static HBITMAP LoginTab_LoadChevronImage(HWND hwnd, INT *imageWidth, INT *imageHeight)
|
|
{
|
|
INT width, height;
|
|
HBITMAP hbmpDst, hbmpSrc;
|
|
hbmpSrc = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST,
|
|
MAKEINTRESOURCE(IDR_ARROW_IMAGE), FALSE, &width, &height);
|
|
|
|
if (NULL == hbmpSrc)
|
|
return NULL;
|
|
|
|
if (height < 0) height = -height;
|
|
|
|
INT frameHeight = height/2;
|
|
INT frameWidth = width;
|
|
|
|
BITMAPINFOHEADER bhi;
|
|
ZeroMemory(&bhi, sizeof(bhi));
|
|
bhi.biSize = sizeof(bhi);
|
|
bhi.biCompression = BI_RGB;
|
|
bhi.biBitCount = 32;
|
|
bhi.biPlanes = 1;
|
|
bhi.biWidth = frameWidth;
|
|
bhi.biHeight = 4 * frameHeight;
|
|
|
|
UINT *pixelData;
|
|
hbmpDst = CreateDIBSection(NULL, (LPBITMAPINFO)&bhi, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0);
|
|
if (NULL == hbmpDst)
|
|
{
|
|
DeleteObject(hbmpSrc);
|
|
return NULL;
|
|
}
|
|
|
|
BOOL resultOk = FALSE;
|
|
|
|
HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
|
if (NULL != hdc)
|
|
{
|
|
HDC hdcSrc = CreateCompatibleDC(hdc);
|
|
HDC hdcDst = CreateCompatibleDC(hdc);
|
|
|
|
if (NULL != hdcSrc && NULL != hdcDst)
|
|
{
|
|
HBITMAP hbmpSrcOrig = (HBITMAP)SelectObject(hdcSrc, hbmpSrc);
|
|
HBITMAP hbmpDstOrig = (HBITMAP)SelectObject(hdcDst, hbmpDst);
|
|
|
|
RECT imageRect;
|
|
SetRect(&imageRect, 0, 0, frameWidth, frameHeight);
|
|
|
|
BOOL blitFailed = FALSE;
|
|
// normal
|
|
if (FALSE == blitFailed &&
|
|
FALSE != BitBlt(hdcDst, 0, 0*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
|
|
{
|
|
Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -150, -100);
|
|
}
|
|
else blitFailed = TRUE;
|
|
|
|
|
|
// active
|
|
if (FALSE == blitFailed &&
|
|
FALSE == BitBlt(hdcDst, 0, 1*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
|
|
{
|
|
blitFailed = TRUE;
|
|
}
|
|
|
|
// disabled
|
|
if (FALSE == blitFailed &&
|
|
FALSE != BitBlt(hdcDst, 0, 2*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
|
|
{
|
|
OffsetRect(&imageRect, 0, 2*frameHeight);
|
|
Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -(150 + 600), -(100 + 600));
|
|
}
|
|
else blitFailed = TRUE;
|
|
|
|
|
|
// pressed
|
|
if (FALSE == blitFailed &&
|
|
FALSE == BitBlt(hdcDst, 0, 3*frameHeight, frameWidth, frameHeight, hdcSrc, 0, frameHeight, SRCCOPY))
|
|
{
|
|
blitFailed = TRUE;
|
|
}
|
|
|
|
if (FALSE == blitFailed)
|
|
{
|
|
SetRect(&imageRect, 0, 0, bhi.biWidth, -bhi.biHeight);
|
|
Image_Premultiply(hbmpDst, &imageRect);
|
|
resultOk = TRUE;
|
|
}
|
|
|
|
SelectObject(hdcSrc, hbmpSrcOrig);
|
|
SelectObject(hdcDst, hbmpDstOrig);
|
|
}
|
|
if (NULL != hdcSrc) DeleteDC(hdcSrc);
|
|
if (NULL != hdcDst) DeleteDC(hdcDst);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
|
|
DeleteObject(hbmpSrc);
|
|
|
|
if (FALSE == resultOk)
|
|
{
|
|
DeleteObject(hbmpDst);
|
|
hbmpDst = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (NULL != imageWidth) *imageWidth = width;
|
|
if (NULL != imageHeight) *imageHeight = height;
|
|
}
|
|
|
|
return hbmpDst;
|
|
}
|
|
static BOOL LoginTab_GradientFillVertRect(HDC hdc, const RECT *prcFill, COLORREF rgbTop, COLORREF rgbBottom)
|
|
{
|
|
TRIVERTEX szVertex[2];
|
|
szVertex[0].x = prcFill->left;
|
|
szVertex[0].y = prcFill->top;
|
|
szVertex[0].Red = GetRValue(rgbTop) << 8;
|
|
szVertex[0].Green = GetGValue(rgbTop) << 8;
|
|
szVertex[0].Blue = GetBValue(rgbTop) << 8;
|
|
szVertex[0].Alpha = 0x0000;
|
|
|
|
szVertex[1].x = prcFill->right;
|
|
szVertex[1].y = prcFill->bottom;
|
|
szVertex[1].Red = GetRValue(rgbBottom) << 8;
|
|
szVertex[1].Green = GetGValue(rgbBottom) << 8;
|
|
szVertex[1].Blue = GetBValue(rgbBottom) << 8;
|
|
szVertex[1].Alpha = 0x0000;
|
|
|
|
GRADIENT_RECT szMesh[1];
|
|
szMesh[0].UpperLeft = 0;
|
|
szMesh[0].LowerRight = 1;
|
|
|
|
return GdiGradientFill(hdc, szVertex, ARRAYSIZE(szVertex), szMesh, 1, GRADIENT_FILL_RECT_V);
|
|
}
|
|
|
|
static void LoginTab_EraseBkGround(HDC hdc, LOGINTAB *tab, LONG clientHeight, const RECT *prcPaint)
|
|
{
|
|
RECT rect;
|
|
LONG middleY = clientHeight/2;
|
|
|
|
COLORREF rgbOrig = SetBkColor(hdc, tab->colors.backTop);
|
|
|
|
CopyRect(&rect, prcPaint);
|
|
rect.bottom = middleY;
|
|
if (rect.top < rect.bottom)
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
SetRect(&rect, prcPaint->left, middleY, prcPaint->right, clientHeight - 1);
|
|
|
|
if (FALSE == LoginTab_GradientFillVertRect(hdc, &rect, tab->colors.backTop, tab->colors.backBottom))
|
|
{
|
|
SetBkColor(hdc, tab->colors.backBottom);
|
|
if (prcPaint->bottom < rect.bottom)
|
|
rect.bottom = prcPaint->bottom;
|
|
if (rect.top < rect.bottom)
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
}
|
|
|
|
if (prcPaint->bottom == clientHeight)
|
|
{
|
|
SetBkColor(hdc, tab->colors.backLine);
|
|
SetRect(&rect, prcPaint->left, clientHeight - 1, prcPaint->right, clientHeight);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
}
|
|
|
|
SetBkColor(hdc, rgbOrig);
|
|
}
|
|
|
|
static BOOL LoginTab_PaintItemFrame(HDC hdc, LOGINTAB *tab, INT frameType, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
|
|
{
|
|
if (NULL == tab->frameBitmap)
|
|
return FALSE;
|
|
|
|
INT offsetY;
|
|
switch(frameType)
|
|
{
|
|
case FRAMETYPE_SELECTED: offsetY = 0; break;
|
|
case FRAMETYPE_ACTIVE: offsetY = 1 * (tab->frameHeight * 2 + 1); break;
|
|
case FRAMETYPE_DISABLED: offsetY = 2 * (tab->frameHeight * 2 + 1); break;
|
|
default: return FALSE;
|
|
}
|
|
|
|
SelectObject(hdcSrc, tab->frameBitmap);
|
|
|
|
BLENDFUNCTION bf;
|
|
bf.BlendOp = AC_SRC_OVER;
|
|
bf.BlendFlags = 0;
|
|
bf.SourceConstantAlpha = 255;
|
|
bf.AlphaFormat = AC_SRC_ALPHA;
|
|
|
|
INT lineLength;
|
|
|
|
// left-top
|
|
GdiAlphaBlend(hdc, prcItem->left, prcItem->top, tab->frameWidth, tab->frameHeight,
|
|
hdcSrc, 0, offsetY + 0, tab->frameWidth, tab->frameHeight, bf);
|
|
|
|
// right-top
|
|
GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top, tab->frameWidth, tab->frameHeight,
|
|
hdcSrc, tab->frameWidth + 1, offsetY + 0, tab->frameWidth, tab->frameHeight, bf);
|
|
|
|
// right-bottom
|
|
GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight,
|
|
hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf);
|
|
|
|
// left-bottom
|
|
GdiAlphaBlend(hdc, prcItem->left, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight,
|
|
hdcSrc, 0, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf);
|
|
|
|
lineLength = (prcItem->right - prcItem->left) - tab->frameWidth * 2;
|
|
// top
|
|
GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->top, lineLength, tab->frameHeight,
|
|
hdcSrc, tab->frameWidth, offsetY + 0, 1, tab->frameHeight, bf);
|
|
// bottom
|
|
GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->bottom - tab->frameHeight, lineLength, tab->frameHeight,
|
|
hdcSrc, tab->frameWidth, offsetY + tab->frameHeight + 1, 1, tab->frameHeight, bf);
|
|
|
|
lineLength = (prcItem->bottom - prcItem->top) - tab->frameHeight * 2;
|
|
// left
|
|
GdiAlphaBlend(hdc, prcItem->left, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength,
|
|
hdcSrc, 0, offsetY + tab->frameHeight, tab->frameWidth, 1, bf);
|
|
// right
|
|
GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength,
|
|
hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight, tab->frameWidth, 1, bf);
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL LoginTab_FillItem(HDC hdc, const RECT *prcItem, const RECT *prcPaint, INT alpha, COLORREF rgbTop, COLORREF rgbBottom, INT tempX)
|
|
{
|
|
|
|
RECT rect;
|
|
SetRect(&rect, tempX, prcItem->top, tempX + 1, prcItem->bottom);
|
|
if (rgbTop == rgbBottom || FALSE == LoginTab_GradientFillVertRect(hdc, &rect, rgbTop, rgbBottom))
|
|
{
|
|
COLORREF rgbOrig = SetBkColor(hdc, rgbBottom);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
if (rgbOrig != rgbBottom) SetBkColor(hdc, rgbOrig);
|
|
}
|
|
|
|
INT height = prcPaint->bottom - prcPaint->top;
|
|
|
|
BLENDFUNCTION bf;
|
|
bf.BlendOp = AC_SRC_OVER;
|
|
bf.BlendFlags = 0;
|
|
bf.SourceConstantAlpha = alpha;
|
|
bf.AlphaFormat = 0x00;
|
|
|
|
BOOL result = GdiAlphaBlend(hdc, prcPaint->left, prcPaint->top, 1, height,
|
|
hdc, tempX, prcPaint->top, 1, height, bf);
|
|
|
|
if (FALSE != result)
|
|
{
|
|
INT stretchModeOrig = SetStretchBltMode(hdc, COLORONCOLOR);
|
|
|
|
result = StretchBlt(hdc, prcPaint->left + 1, prcPaint->top, prcPaint->right - prcPaint->left - 1, height,
|
|
hdc, prcPaint->left, prcPaint->top, 1, height, SRCCOPY);
|
|
|
|
if (COLORONCOLOR != stretchModeOrig)
|
|
SetStretchBltMode(hdc, stretchModeOrig);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
static void LoginTab_DrawRect(HDC hdc, const RECT *prc)
|
|
{
|
|
RECT rect;
|
|
SetRect(&rect, prc->left +1, prc->top, prc->right -1, prc->top + 1);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
SetRect(&rect, prc->left + 1, prc->bottom-1, prc->right -1, prc->bottom);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
SetRect(&rect, prc->left, prc->top + 1, prc->left + 1, prc->bottom - 1);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
SetRect(&rect, prc->right - 1, prc->top + 1, prc->right, prc->bottom - 1);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
}
|
|
static BOOL LoginTab_PaintChevron(HDC hdc, LOGINTAB *tab, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
|
|
{
|
|
ITEMSTATECOLORTABLE *color;
|
|
INT iItem = tab->itemsCount;
|
|
|
|
if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle))
|
|
color = &tab->colors.item.normalDisabled;
|
|
else
|
|
{
|
|
if (iItem == tab->iPressed)
|
|
color = &tab->colors.item.normalPressed;
|
|
else if (iItem == tab->iHighlighted)
|
|
color = &tab->colors.item.normalHigh;
|
|
else
|
|
color = &tab->colors.item.normal;
|
|
}
|
|
|
|
RECT rect, itemRect;
|
|
CopyRect(&itemRect, prcItem);
|
|
|
|
if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
|
|
{
|
|
CopyRect(&rect, prcItem);
|
|
InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2));
|
|
COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus);
|
|
COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash);
|
|
DrawFocusRect(hdc, &rect);
|
|
//LoginTab_DrawRect(hdc, &rect);
|
|
if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig);
|
|
if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig);
|
|
}
|
|
|
|
INT frameType = color->frameType;
|
|
if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
|
|
frameType = FRAMETYPE_ACTIVE;
|
|
|
|
|
|
if (FRAMETYPE_NONE != frameType &&
|
|
FALSE != LoginTab_PaintItemFrame(hdc, tab, frameType, prcItem, prcPaint, hdcSrc))
|
|
{
|
|
InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1));
|
|
}
|
|
|
|
if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint))
|
|
{
|
|
LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right);
|
|
}
|
|
|
|
|
|
|
|
if (NULL != tab->chevronImage)
|
|
{
|
|
BITMAP bm;
|
|
if (sizeof(bm) == GetObject(tab->chevronImage, sizeof(bm), &bm))
|
|
{
|
|
if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight;
|
|
bm.bmHeight = bm.bmHeight/4;
|
|
|
|
|
|
INT cx = bm.bmWidth;
|
|
INT cy = bm.bmHeight;
|
|
|
|
INT offsetY;
|
|
if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle))
|
|
offsetY = 2*bm.bmHeight;
|
|
else if (iItem == tab->iPressed)
|
|
offsetY = 3*bm.bmHeight;
|
|
else if (iItem == tab->iHighlighted || iItem == tab->iSelected)
|
|
offsetY = 1*bm.bmHeight;
|
|
else
|
|
offsetY = 0;
|
|
|
|
INT x = prcItem->left + ((prcItem->right - prcItem->left) - cx)/2;
|
|
if (x < prcItem->left) x = prcItem->left;
|
|
|
|
INT y = prcItem->top + ((prcItem->bottom - prcItem->top) - cy)/2;
|
|
if (y < prcItem->top) y = prcItem->top;
|
|
|
|
if ((x + cx) > prcItem->right) cx = prcItem->right - x;
|
|
if ((y + cy) > prcItem->bottom) cy = prcItem->bottom - y;
|
|
|
|
if (iItem == tab->iPressed) y++;
|
|
|
|
SelectObject(hdcSrc, tab->chevronImage);
|
|
|
|
BLENDFUNCTION bf;
|
|
bf.BlendOp = AC_SRC_OVER;
|
|
bf.BlendFlags = 0;
|
|
bf.SourceConstantAlpha = 255;
|
|
bf.AlphaFormat = AC_SRC_ALPHA;
|
|
|
|
GdiAlphaBlend(hdc, x, y, cx, cy, hdcSrc, 0, offsetY, bm.bmWidth, bm.bmHeight, bf);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
static void LoginTab_ResolveImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT requestMask)
|
|
{
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
if (NULL == hParent) return;
|
|
|
|
NMLOGINTABIMAGE request;
|
|
request.hdr.code = NLTN_GETITEMIMAGE;
|
|
request.hdr.hwndFrom = hwnd;
|
|
request.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
request.iItem = iItem;
|
|
request.param = item->param;
|
|
request.imageList = imageList;
|
|
request.maskRequest = requestMask;
|
|
request.maskUpdate = 0;
|
|
request.iImage = item->iImage;
|
|
request.iImageActive = item->iImageActive;
|
|
request.iImageDisabled = item->iImageDisabled;
|
|
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)request.hdr.idFrom, (LPARAM)&request);
|
|
|
|
if (0 != request.maskUpdate)
|
|
{
|
|
if (0 != (NLTIF_IMAGE & request.maskUpdate))
|
|
item->iImage = request.iImage;
|
|
|
|
if (0 != (NLTIF_IMAGE_ACTIVE & request.maskUpdate))
|
|
item->iImageActive = request.iImageActive;
|
|
|
|
if (0 != (NLTIF_IMAGE_DISABLED & request.maskUpdate))
|
|
item->iImageDisabled = request.iImageDisabled;
|
|
}
|
|
|
|
}
|
|
static UINT LoginTab_GetImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT imageType)
|
|
{
|
|
if (NULL == item) return NLTM_IMAGE_NONE;
|
|
switch(imageType & NLTIF_IMAGE_MASK)
|
|
{
|
|
case NLTIF_IMAGE_ACTIVE:
|
|
if (NLTM_IMAGE_CALLBACK == item->iImageActive)
|
|
{
|
|
LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_ACTIVE);
|
|
if (NLTM_IMAGE_CALLBACK == item->iImageActive)
|
|
break;
|
|
}
|
|
|
|
if (NLTM_IMAGE_NONE != item->iImageActive)
|
|
return item->iImageActive;
|
|
|
|
break;
|
|
case NLTIF_IMAGE_DISABLED:
|
|
if (NLTM_IMAGE_CALLBACK == item->iImageDisabled)
|
|
{
|
|
LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_DISABLED);
|
|
if (NLTM_IMAGE_CALLBACK == item->iImageDisabled)
|
|
break;
|
|
}
|
|
|
|
if (NLTM_IMAGE_NONE != item->iImageDisabled)
|
|
return item->iImageDisabled;
|
|
|
|
break;
|
|
}
|
|
|
|
if (NLTM_IMAGE_CALLBACK == item->iImage)
|
|
LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE);
|
|
|
|
return item->iImage;
|
|
}
|
|
|
|
static BOOL LoginTab_PaintItem(HWND hwndTab, HDC hdc, LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
|
|
{
|
|
|
|
ITEMSTATECOLORTABLE *color;
|
|
UINT imageType;
|
|
|
|
if (iItem == tab->iSelected)
|
|
{
|
|
if (0 != (NLTDS_DISABLED & tab->drawStyle))
|
|
{
|
|
color = &tab->colors.item.selectedDisabled;
|
|
imageType = NLTIF_IMAGE_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
if (0 != (NLTDS_LOCKED & tab->drawStyle))
|
|
{
|
|
color = &tab->colors.item.selected;
|
|
}
|
|
else
|
|
{
|
|
if (iItem == tab->iPressed)
|
|
color = &tab->colors.item.selectedPressed;
|
|
else if (iItem == tab->iHighlighted)
|
|
color = &tab->colors.item.selectedHigh;
|
|
else
|
|
color = &tab->colors.item.selected;
|
|
}
|
|
|
|
imageType = NLTIF_IMAGE_ACTIVE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 != ((NLTDS_DISABLED | NLTDS_LOCKED) & tab->drawStyle))
|
|
{
|
|
color = &tab->colors.item.normalDisabled;
|
|
imageType = NLTIF_IMAGE_DISABLED;
|
|
}
|
|
else if (iItem == tab->iPressed)
|
|
{
|
|
color = &tab->colors.item.normalPressed;
|
|
imageType = NLTIF_IMAGE_ACTIVE;
|
|
}
|
|
else if (iItem == tab->iHighlighted)
|
|
{
|
|
color = &tab->colors.item.normalHigh;
|
|
imageType = NLTIF_IMAGE_ACTIVE;
|
|
}
|
|
else
|
|
{
|
|
color = &tab->colors.item.normal;
|
|
imageType = NLTIF_IMAGE;
|
|
}
|
|
}
|
|
|
|
RECT rect, itemRect;
|
|
CopyRect(&itemRect, prcItem);
|
|
|
|
|
|
|
|
if (FRAMETYPE_NONE != color->frameType &&
|
|
FALSE != LoginTab_PaintItemFrame(hdc, tab, color->frameType, prcItem, prcPaint, hdcSrc))
|
|
{
|
|
InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1));
|
|
}
|
|
|
|
if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint))
|
|
{
|
|
LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right);
|
|
}
|
|
|
|
if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
|
|
{
|
|
CopyRect(&rect, prcItem);
|
|
InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2));
|
|
COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus);
|
|
COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash);
|
|
DrawFocusRect(hdc, &rect);
|
|
//LoginTab_DrawRect(hdc, &rect);
|
|
if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig);
|
|
if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig);
|
|
}
|
|
|
|
if (NULL != tab->imageList)
|
|
{
|
|
UINT iImage = LoginTab_GetImageIndex(hwndTab, tab->imageList, item, iItem, imageType);
|
|
if (NLTM_IMAGE_NONE != iImage)
|
|
{
|
|
IMAGELISTDRAWPARAMS dp;
|
|
dp.cbSize = 56/*sizeof(IMAGELISTDRAWPARAMS) - sizeof(DWORD) * 3*/;
|
|
dp.himl = tab->imageList;
|
|
dp.i = iImage;
|
|
dp.hdcDst = hdc;
|
|
|
|
ImageList_GetIconSize(tab->imageList, &dp.cx, &dp.cy);
|
|
dp.x = prcItem->left + ((prcItem->right - prcItem->left) - dp.cx)/2;
|
|
if (dp.x < (prcItem->left + tab->frameWidth)) dp.x = prcItem->left + tab->frameWidth;
|
|
if ((dp.x + dp.cx) > (prcItem->right - tab->frameWidth))
|
|
{
|
|
dp.cx = prcItem->right - tab->frameWidth - dp.x;
|
|
if (dp.cx < 0) dp.cx = 0;
|
|
}
|
|
|
|
dp.y = prcItem->top + tab->frameHeight + IMAGE_MARGIN_CY;
|
|
if ((dp.y + dp.cy) > (prcItem->bottom - tab->frameHeight))
|
|
{
|
|
dp.cy = prcItem->bottom - tab->frameHeight- dp.y;
|
|
if (dp.cy < 0) dp.cy = 0;
|
|
}
|
|
|
|
dp.xBitmap = 0;
|
|
dp.yBitmap = 0;
|
|
dp.rgbBk = CLR_NONE;
|
|
dp.rgbFg = CLR_NONE;
|
|
dp.fStyle = ILD_NORMAL;
|
|
dp.dwRop = SRCCOPY;
|
|
dp.fState = ILS_NORMAL /*| ILS_SATURATE*/ /*| ILS_ALPHA*/;
|
|
dp.Frame = 255;
|
|
dp.crEffect = 0;
|
|
|
|
if (dp.cx > 0 && dp.cy > 0)
|
|
ImageList_DrawIndirect(&dp);
|
|
}
|
|
|
|
}
|
|
if (NULL != item->text && L'\0' != *item->text)
|
|
{
|
|
LONG left = prcItem->left + ((prcItem->right - prcItem->left) - item->textWidth) / 2;
|
|
if (left < (prcItem->left + tab->frameWidth)) left = prcItem->left + tab->frameWidth;
|
|
|
|
LONG top = prcItem->bottom - tab->textHeight - tab->frameHeight + 1;
|
|
|
|
SetRect(&rect, left, top, left + item->textWidth, top + tab->textHeight);
|
|
if (rect.right > (prcItem->right - tab->frameWidth)) rect.right = prcItem->right - tab->frameWidth;
|
|
|
|
if (rect.bottom > prcPaint->bottom) rect.bottom = prcPaint->bottom;
|
|
if (rect.top < prcPaint->top) rect.top = prcPaint->top;
|
|
if (rect.right > prcPaint->right) rect.right = prcPaint->right;
|
|
if (rect.left < prcPaint->left) rect.left = prcPaint->left;
|
|
|
|
if (rect.left < rect.right && rect.top < rect.bottom)
|
|
{
|
|
SetTextColor(hdc, color->text);
|
|
INT cchText = lstrlen(item->text);
|
|
ExtTextOut(hdc, left, top, ETO_CLIPPED, &rect, item->text, cchText, NULL);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static INT CALLBACK LoginTab_PaintItemCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
|
|
{
|
|
PAINTITEMPARAM *pip = (PAINTITEMPARAM*)param;
|
|
if (NULL == pip) return -2;
|
|
|
|
RECT paintRect;
|
|
if (FALSE != IntersectRect(&paintRect, pip->prcPaint, prcItem))
|
|
{
|
|
|
|
SetRectRgn(pip->clipRgn, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom);
|
|
CombineRgn(pip->eraseRgn, pip->eraseRgn, pip->clipRgn, RGN_DIFF);
|
|
|
|
HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pip->hdc,
|
|
prcItem->right - prcItem->left,
|
|
prcItem->bottom - prcItem->top);
|
|
|
|
if (NULL != hbmp)
|
|
{
|
|
SelectObject(pip->hdcItem, hbmp);
|
|
SetViewportOrgEx(pip->hdcItem, -paintRect.left, -paintRect.top, NULL);
|
|
}
|
|
|
|
LoginTab_EraseBkGround(pip->hdcItem, tab, pip->prcClient->bottom - pip->prcClient->top, &paintRect);
|
|
|
|
if (iItem == tab->itemsCount)
|
|
LoginTab_PaintChevron(pip->hdcItem, tab, prcItem, &paintRect, pip->hdcSrc);
|
|
else
|
|
LoginTab_PaintItem(pip->hwndTab, pip->hdcItem, tab, item, iItem, prcItem, &paintRect, pip->hdcSrc);
|
|
|
|
BitBlt(pip->hdc, paintRect.left, paintRect.top, paintRect.right - paintRect.left, paintRect.bottom - paintRect.top,
|
|
pip->hdcItem, paintRect.left, paintRect.top, SRCCOPY);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static UINT LoginTab_GetDrawStyles(HWND hwnd)
|
|
{
|
|
UINT windowStyle = GetWindowStyle(hwnd);
|
|
UINT drawStyle = 0;
|
|
|
|
if (0 != (WS_DISABLED & windowStyle))
|
|
drawStyle |= NLTDS_DISABLED;
|
|
else if (hwnd == GetFocus())
|
|
{
|
|
UINT uiState = (UINT)SendMessage(hwnd, WM_QUERYUISTATE, 0, 0L);
|
|
if (0 == (UISF_HIDEFOCUS & uiState))
|
|
drawStyle |= NLTDS_FOCUSED;
|
|
}
|
|
|
|
if (0 != (NLTS_LOCKED & windowStyle))
|
|
drawStyle |= NLTDS_LOCKED;
|
|
|
|
return drawStyle;
|
|
}
|
|
|
|
static void LoginTab_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
RECT clientRect;
|
|
GetClientRect(hwnd, &clientRect);
|
|
|
|
tab->drawStyle = LoginTab_GetDrawStyles(hwnd);
|
|
|
|
HBITMAP bitmapSrcOrig, bitmapItemOrig;
|
|
HFONT fontItemOrig;
|
|
|
|
PAINTITEMPARAM param;
|
|
param.hwndTab = hwnd;
|
|
param.hdc = hdc;
|
|
param.prcPaint = prcPaint;
|
|
param.prcClient = &clientRect;
|
|
param.clipRgn = CreateRectRgn(0,0,0,0);
|
|
param.eraseRgn = CreateRectRgnIndirect(&clientRect);
|
|
param.hdcSrc = CreateCompatibleDC(hdc);
|
|
param.hdcItem = CreateCompatibleDC(hdc);
|
|
|
|
|
|
if (NULL != param.hdcSrc)
|
|
bitmapSrcOrig = (HBITMAP)GetCurrentObject(param.hdcSrc, OBJ_BITMAP);
|
|
|
|
if (NULL != param.hdcItem)
|
|
{
|
|
bitmapItemOrig = (HBITMAP)GetCurrentObject(param.hdcItem, OBJ_BITMAP);
|
|
SetBkMode(param.hdcItem, TRANSPARENT);
|
|
fontItemOrig = (HFONT)SelectObject(param.hdcItem, tab->fontText);
|
|
}
|
|
|
|
LoginTab_EnumerateItemRects(hwnd, param.hdcItem, LoginTab_PaintItemCallback, (ULONG_PTR)¶m);
|
|
|
|
if (FALSE != fErase)
|
|
{
|
|
SelectClipRgn(hdc, param.eraseRgn);
|
|
LoginTab_EraseBkGround(hdc, tab, clientRect.bottom - clientRect.top, prcPaint);
|
|
//if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed())
|
|
//{
|
|
// // CONTROLPANEL, CPANEL_NAVIGATIONPANE, 0
|
|
// //
|
|
// UXTHEME hTheme = UxOpenThemeData(hwnd, L"MENU");
|
|
// if (NULL != hTheme)
|
|
// {
|
|
// clientRect.right++;
|
|
// UxDrawThemeBackground(hTheme, hdc, MENU_BARBACKGROUND, MB_ACTIVE, &clientRect, prcPaint);
|
|
// UxCloseThemeData(hTheme);
|
|
// }
|
|
//}
|
|
}
|
|
|
|
if (NULL != param.hdcSrc)
|
|
{
|
|
SelectObject(param.hdcSrc, bitmapSrcOrig);
|
|
DeleteDC(param.hdcSrc);
|
|
}
|
|
|
|
if (NULL != param.hdcItem)
|
|
{
|
|
SelectObject(param.hdcItem, bitmapItemOrig);
|
|
SelectObject(param.hdcItem, fontItemOrig);
|
|
DeleteDC(param.hdcItem);
|
|
}
|
|
|
|
DeleteObject(param.clipRgn);
|
|
DeleteObject(param.eraseRgn);
|
|
}
|
|
|
|
static INT CALLBACK LoginTab_GetItemRectCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
|
|
{
|
|
GETITEMRECTPARAM *gip = (GETITEMRECTPARAM*)param;
|
|
if (NULL == gip) return -2;
|
|
|
|
if (iItem == gip->index)
|
|
{
|
|
CopyRect(gip->rect, prcItem);
|
|
return iItem;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static BOOL LoginTab_GetItemRect(HWND hwnd, INT iItem, RECT *itemRect)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == itemRect || iItem < 0 || iItem > tab->itemsCount)
|
|
return FALSE;
|
|
|
|
GETITEMRECTPARAM param;
|
|
param.index = iItem;
|
|
param.rect = itemRect;
|
|
|
|
INT result = LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_GetItemRectCallback, (ULONG_PTR)¶m);
|
|
|
|
return (result == iItem);
|
|
}
|
|
|
|
static INT CALLBACK LoginTab_HitTestCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
|
|
{
|
|
HITTESTITEMPARAM *htp = (HITTESTITEMPARAM*)param;
|
|
if (NULL == htp) return -2;
|
|
|
|
if (FALSE != PtInRect(prcItem, htp->pt))
|
|
{
|
|
if (NULL != htp->rect)
|
|
CopyRect(htp->rect, prcItem);
|
|
return iItem;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static INT LoginTab_HitTest(HWND hwnd, INT x, INT y, RECT *itemRect)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return -1;
|
|
|
|
HITTESTITEMPARAM param;
|
|
param.pt.x = x;
|
|
param.pt.y = y;
|
|
param.rect = itemRect;
|
|
|
|
return LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_HitTestCallback, (ULONG_PTR)¶m);
|
|
}
|
|
|
|
static INT CALLBACK LoginTab_UpdateLayoutCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
|
|
{
|
|
UPDATELAYOUTPARAM *ulp = (UPDATELAYOUTPARAM*)param;
|
|
if (NULL == ulp) return -2;
|
|
|
|
if (iItem != tab->itemsCount)
|
|
{
|
|
if (0 == ulp->itemCount)
|
|
CopyRect(&ulp->visibleBox, prcItem);
|
|
else
|
|
ulp->visibleBox.right = prcItem->right;
|
|
|
|
ulp->itemCount++;
|
|
}
|
|
else
|
|
{
|
|
ulp->chevronLeft = prcItem->left;
|
|
|
|
if (ulp->visibleBox.right > ulp->chevronLeft)
|
|
ulp->visibleBox.right = ulp->chevronLeft;
|
|
|
|
ulp->chevronVisible = TRUE;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void LoginTab_UpdateLayout(HWND hwnd, BOOL fRedraw)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
RECT clientRect, rect;
|
|
GetClientRect(hwnd, &clientRect);
|
|
|
|
UPDATELAYOUTPARAM param;
|
|
ZeroMemory(¶m, sizeof(param));
|
|
param.chevronLeft = clientRect.right;
|
|
|
|
INT *orderCopy = NULL;
|
|
if (tab->itemsCount > 0)
|
|
{
|
|
orderCopy = (INT*)calloc(tab->itemsCount, sizeof(INT));
|
|
if (NULL == orderCopy) return;
|
|
CopyMemory(orderCopy, tab->order, tab->itemsCount * sizeof(INT));
|
|
}
|
|
|
|
|
|
// for (INT i = 0; i < tab->itemsCount; i++)
|
|
// tab->order[i] = i; // reset order
|
|
|
|
LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_UpdateLayoutCallback, (ULONG_PTR)¶m);
|
|
|
|
INT selectPos = -1;
|
|
if (-1 != tab->iSelected)
|
|
{
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
{
|
|
if (tab->order[i] == tab->iSelected)
|
|
{
|
|
selectPos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tab->lastVisible < selectPos && tab->lastVisible >= 0 && selectPos >= 0)
|
|
{
|
|
CALCITEMWIDTH calcWidth;
|
|
if (FALSE != LoginTab_InitCalcItemWidth(hwnd, NULL, &calcWidth))
|
|
{
|
|
INT selectWidth = LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->iSelected]);
|
|
INT limit = param.chevronLeft - selectWidth;
|
|
INT right = param.visibleBox.right + tab->spacing;
|
|
INT pos = tab->lastVisible + 1;
|
|
|
|
while(right > limit && pos-- > 0)
|
|
{
|
|
right -= LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->order[pos]]);
|
|
if (pos > 0)
|
|
right -= tab->spacing;
|
|
}
|
|
|
|
if (pos < selectPos)
|
|
MoveMemory(tab->order + (pos + 1), tab->order + pos, (selectPos - pos) * sizeof(INT));
|
|
|
|
tab->order[pos] = tab->iSelected;
|
|
tab->lastVisible = pos;
|
|
|
|
right += selectWidth;
|
|
//if (param.visibleBox.right > right)
|
|
param.visibleBox.right = right;
|
|
|
|
LoginTab_DestroyCalcItemWidth(&calcWidth);
|
|
}
|
|
|
|
}
|
|
|
|
INT invalidLeft = clientRect.right;
|
|
if(NULL != orderCopy)
|
|
{
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
{
|
|
if (tab->order[i] != orderCopy[i])
|
|
{
|
|
if (FALSE != LoginTab_GetItemRect(hwnd, tab->order[i], &rect))
|
|
invalidLeft = rect.left;
|
|
break;
|
|
}
|
|
}
|
|
free(orderCopy);
|
|
}
|
|
|
|
if (tab->chevronLeft != param.chevronLeft)
|
|
{
|
|
SetRect(&rect, param.chevronLeft, clientRect.top, clientRect.right, clientRect.bottom);
|
|
if (rect.left > tab->chevronLeft)
|
|
rect.left = tab->chevronLeft;
|
|
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
tab->chevronLeft = param.chevronLeft;
|
|
}
|
|
|
|
if (tab->visibleRight != param.visibleBox.right || invalidLeft != clientRect.right)
|
|
{
|
|
CopyRect(&rect, ¶m.visibleBox);
|
|
rect.left = min(param.visibleBox.right, tab->visibleRight);
|
|
if (invalidLeft < rect.left) rect.left = invalidLeft;
|
|
rect.right = max(param.visibleBox.right, tab->visibleRight);
|
|
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
tab->visibleRight = param.visibleBox.right;
|
|
}
|
|
|
|
}
|
|
static void LoginTab_SetItemFocus(HWND hwnd, INT iFocus)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
INT focusPos = -1;
|
|
if (iFocus >= tab->itemsCount)
|
|
focusPos = iFocus;
|
|
else if (-1 != iFocus)
|
|
{
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
{
|
|
if (tab->order[i] == iFocus)
|
|
{
|
|
focusPos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (focusPos > tab->lastVisible)
|
|
{
|
|
if (tab->lastVisible != (tab->itemsCount -1))
|
|
{
|
|
iFocus = tab->itemsCount;
|
|
}
|
|
else
|
|
{
|
|
iFocus = tab->order[tab->lastVisible];
|
|
}
|
|
}
|
|
|
|
if (iFocus < 0)
|
|
iFocus = (tab->itemsCount > 0) ? 0 : -1;
|
|
|
|
if (iFocus != tab->iFocused)
|
|
{
|
|
INT iFocused = tab->iFocused;
|
|
INT iSelected = tab->iSelected;
|
|
|
|
tab->iFocused = iFocus;
|
|
if (iFocus < tab->itemsCount)
|
|
tab->iSelected = iFocus;
|
|
|
|
RECT rect;
|
|
if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
if (-1 != iFocused && iFocused != tab->iFocused &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
if (-1 != iSelected && iSelected != tab->iSelected && iSelected != iFocused &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
if (iSelected != tab->iSelected)
|
|
{
|
|
LoginTab_NotifySelectionChanged(hwnd);
|
|
}
|
|
}
|
|
}
|
|
static BOOL LoginTab_ShowHiddenTabs(HWND hwnd, const RECT *ownerRect)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
HMENU hMenu = CreatePopupMenu();
|
|
if (NULL == hMenu) return FALSE;
|
|
|
|
MENUINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_STYLE | MIIM_FTYPE;
|
|
mi.dwStyle = /*MNS_MODELESS | */ MNS_NOCHECK;
|
|
SetMenuInfo(hMenu, &mi);
|
|
|
|
UINT insertedCount = 0;
|
|
MENUITEMINFO mii;
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_FTYPE | MIIM_DATA;
|
|
mii.fState = MFS_UNHILITE | MFS_ENABLED;
|
|
|
|
CHEVRONMENUPAINTPARAM menuPaint;
|
|
ZeroMemory(&menuPaint, sizeof(menuPaint));
|
|
|
|
CALCITEMWIDTH calcItem;
|
|
LoginTab_InitCalcItemWidth(hwnd, NULL, &calcItem);
|
|
|
|
menuPaint.itemHeight = calcItem.itemHeight;
|
|
if (NULL != ownerRect)
|
|
CopyRect(&menuPaint.ownerRect, ownerRect);
|
|
|
|
INT width = tab->itemsCount - tab->lastVisible - 1;
|
|
if (width < 2) width = 1;
|
|
else if (width < 9) width = 2;
|
|
else width = (INT)sqrt((float)(width));
|
|
|
|
for(INT offset = 0; offset < width; offset++)
|
|
{
|
|
mii.fType = MFT_OWNERDRAW | MFT_MENUBREAK;
|
|
for(INT i = tab->lastVisible + 1 + offset; i < tab->itemsCount; i += width)
|
|
{
|
|
LOGINTABITEM *item = tab->items[tab->order[i]];
|
|
|
|
INT itemWidth = LoginTab_CalculateItemWidth(&calcItem, item);
|
|
if (menuPaint.itemWidth < itemWidth) menuPaint.itemWidth = itemWidth;
|
|
|
|
mii.wID = tab->order[i] + 1;
|
|
mii.dwTypeData = item->text;
|
|
mii.dwItemData = (ULONG_PTR)item;
|
|
|
|
if (FALSE != InsertMenuItem(hMenu, insertedCount, TRUE, &mii))
|
|
insertedCount++;
|
|
|
|
mii.fType = MFT_OWNERDRAW;
|
|
}
|
|
}
|
|
|
|
LoginTab_DestroyCalcItemWidth(&calcItem);
|
|
|
|
if (NULL != hMenu && insertedCount > 0)
|
|
{
|
|
RECT windowRect;
|
|
GetWindowRect(hwnd, &windowRect);
|
|
|
|
POINT menuOrig;
|
|
menuOrig.x = windowRect.right;
|
|
menuOrig.y = windowRect.bottom - 1;
|
|
|
|
UINT menuStyle = TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD;
|
|
|
|
|
|
TRACKMOUSEEVENT tm;
|
|
tm.cbSize = sizeof(tm);
|
|
tm.dwFlags = TME_CANCEL | TME_LEAVE;
|
|
tm.hwndTrack = hwnd;
|
|
TrackMouseEvent(&tm);
|
|
|
|
tab->chevronMenu = hMenu;
|
|
|
|
HBITMAP bitmapSrcOrig, bitmapItemOrig;
|
|
HFONT fontItemOrig;
|
|
|
|
HBRUSH hbrBack = NULL;
|
|
|
|
HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
|
if (NULL != hdc)
|
|
{
|
|
menuPaint.hdcSrc = CreateCompatibleDC(hdc);
|
|
menuPaint.hdcItem = CreateCompatibleDC(hdc);
|
|
|
|
|
|
if (NULL != menuPaint.hdcSrc)
|
|
{
|
|
bitmapSrcOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcSrc, OBJ_BITMAP);
|
|
|
|
INT menuHeight = (insertedCount /width + insertedCount%width) * menuPaint.itemHeight + 2 * 4;
|
|
HBITMAP hbmpPattern = CreateCompatibleBitmap(hdc, 1, menuHeight);
|
|
if (NULL != hbmpPattern)
|
|
{
|
|
HBITMAP bmpOrig = (HBITMAP)SelectObject(menuPaint.hdcSrc, hbmpPattern);
|
|
RECT rect;
|
|
SetRect(&rect, 0, 0, 1, menuHeight);
|
|
LoginTab_EraseBkGround(menuPaint.hdcSrc, tab, menuHeight, &rect);
|
|
SelectObject(menuPaint.hdcSrc, bmpOrig);
|
|
hbrBack = CreatePatternBrush(hbmpPattern);
|
|
DeleteObject(hbmpPattern);
|
|
}
|
|
}
|
|
|
|
if (NULL != menuPaint.hdcItem)
|
|
{
|
|
bitmapItemOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcItem, OBJ_BITMAP);
|
|
SetBkMode(menuPaint.hdcItem, TRANSPARENT);
|
|
fontItemOrig = (HFONT)SelectObject(menuPaint.hdcItem, tab->fontText);
|
|
}
|
|
|
|
|
|
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
|
|
MENUINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
|
|
mi.dwMenuData = (ULONG_PTR)&menuPaint;
|
|
mi.hbrBack = hbrBack;
|
|
SetMenuInfo(hMenu, &mi);
|
|
|
|
TPMPARAMS tpm;
|
|
tpm.cbSize =sizeof(tpm);
|
|
GetWindowRect(hwnd, &tpm.rcExclude);
|
|
tpm.rcExclude.bottom -= 2;
|
|
tpm.rcExclude.left = -20000;
|
|
tpm.rcExclude.right = 20000;
|
|
INT commandId = TrackPopupMenuEx(hMenu, menuStyle, menuOrig.x, menuOrig.y, hwnd, &tpm);
|
|
commandId--;
|
|
|
|
if ( hbrBack != NULL )
|
|
DeleteObject( hbrBack );
|
|
|
|
if (NULL != menuPaint.hdcSrc)
|
|
{
|
|
SelectObject(menuPaint.hdcSrc, bitmapSrcOrig);
|
|
DeleteDC(menuPaint.hdcSrc);
|
|
}
|
|
|
|
if (NULL != menuPaint.hdcItem)
|
|
{
|
|
SelectObject(menuPaint.hdcItem, bitmapItemOrig);
|
|
SelectObject(menuPaint.hdcItem, fontItemOrig);
|
|
DeleteDC(menuPaint.hdcItem);
|
|
}
|
|
|
|
tab->chevronMenu = NULL;
|
|
|
|
if (commandId >= 0 && commandId < tab->itemsCount && tab->iSelected != commandId)
|
|
{
|
|
LoginTab_SetCurSel(hwnd, commandId);
|
|
LoginTab_NotifySelectionChanged(hwnd);
|
|
}
|
|
}
|
|
|
|
if (NULL != hMenu)
|
|
DestroyMenu(hMenu);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void LoginTab_TrackMouseLeave(HWND hwnd)
|
|
{
|
|
TRACKMOUSEEVENT tm;
|
|
tm.cbSize = sizeof(TRACKMOUSEEVENT);
|
|
tm.dwFlags = TME_QUERY;
|
|
tm.hwndTrack = hwnd;
|
|
if (TrackMouseEvent(&tm) && 0 == (TME_LEAVE & tm.dwFlags))
|
|
{
|
|
tm.cbSize = sizeof(TRACKMOUSEEVENT);
|
|
tm.dwFlags = TME_LEAVE;
|
|
tm.hwndTrack = hwnd;
|
|
TrackMouseEvent(&tm);
|
|
}
|
|
}
|
|
|
|
|
|
static void LoginTab_UpdateColors(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
tab->colors.backTop = GetSysColor(COLOR_WINDOW);
|
|
|
|
WORD h, l, s, lBottom, lLine;
|
|
INT k;
|
|
ColorRGBToHLS(tab->colors.backTop, &h, &l, &s);
|
|
k = MulDiv(240, 50, 1000);
|
|
lBottom = l + ((l > 0) ? -k : k);
|
|
if (lBottom > 240) lBottom = 240;
|
|
|
|
k = MulDiv(240, 75, 1000);
|
|
lLine = l + ((l > 0) ? -k : k);
|
|
if (lLine > 240) lLine = 240;
|
|
|
|
tab->colors.backBottom = ColorHLSToRGB(h, lBottom, s);
|
|
tab->colors.backLine = ColorHLSToRGB(h, lLine, s);
|
|
|
|
tab->colors.focus = RGB(255, 255, 255);
|
|
tab->colors.focusDash = RGB(0, 0, 0);
|
|
|
|
COLORREF rgbTextActive = GetSysColor(COLOR_WINDOWTEXT);
|
|
COLORREF rgbText = Color_Blend(rgbTextActive, tab->colors.backBottom, 210);
|
|
|
|
|
|
tab->colors.item.normal.backAlpha = 0;
|
|
tab->colors.item.normal.backTop = 0;
|
|
tab->colors.item.normal.backBottom = 0;
|
|
tab->colors.item.normal.frameType = FRAMETYPE_NONE;
|
|
tab->colors.item.normal.text = rgbText;
|
|
|
|
tab->colors.item.normalHigh.backAlpha = tab->colors.item.normal.backAlpha;
|
|
tab->colors.item.normalHigh.backTop = tab->colors.item.normal.backTop;
|
|
tab->colors.item.normalHigh.backBottom = tab->colors.item.normal.backBottom;
|
|
tab->colors.item.normalHigh.frameType = tab->colors.item.normal.frameType;
|
|
tab->colors.item.normalHigh.text = rgbTextActive;
|
|
|
|
tab->colors.item.normalPressed.backAlpha = tab->colors.item.normal.backAlpha;
|
|
tab->colors.item.normalPressed.backTop = tab->colors.item.normal.backTop;
|
|
tab->colors.item.normalPressed.backBottom = tab->colors.item.normal.backBottom;
|
|
tab->colors.item.normalPressed.frameType = tab->colors.item.normal.frameType;
|
|
tab->colors.item.normalPressed.text = rgbTextActive;
|
|
|
|
tab->colors.item.normalDisabled.backAlpha = tab->colors.item.normal.backAlpha;
|
|
tab->colors.item.normalDisabled.backTop = tab->colors.item.normal.backTop;
|
|
tab->colors.item.normalDisabled.backBottom = tab->colors.item.normal.backBottom;
|
|
tab->colors.item.normalDisabled.frameType = tab->colors.item.normal.frameType;
|
|
tab->colors.item.normalDisabled.text = Color_Blend(GetSysColor(COLOR_GRAYTEXT), tab->colors.backBottom, 160);
|
|
|
|
tab->colors.item.selected.backAlpha = 100;
|
|
tab->colors.item.selected.backTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 100);
|
|
tab->colors.item.selected.backBottom = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 140);
|
|
|
|
tab->colors.item.selected.frameType = FRAMETYPE_SELECTED;
|
|
tab->colors.item.selected.text = rgbTextActive;
|
|
|
|
tab->colors.item.selectedHigh.backAlpha = tab->colors.item.selected.backAlpha;
|
|
tab->colors.item.selectedHigh.backTop = tab->colors.item.selected.backTop;
|
|
tab->colors.item.selectedHigh.backBottom = tab->colors.item.selected.backBottom;
|
|
tab->colors.item.selectedHigh.frameType = tab->colors.item.selected.frameType;
|
|
tab->colors.item.selectedHigh.text = tab->colors.item.selected.text;
|
|
|
|
tab->colors.item.selectedPressed.backAlpha = tab->colors.item.selected.backAlpha;
|
|
tab->colors.item.selectedPressed.backTop = tab->colors.item.selected.backTop;
|
|
tab->colors.item.selectedPressed.backBottom = tab->colors.item.selected.backBottom;
|
|
tab->colors.item.selectedPressed.frameType = tab->colors.item.selected.frameType;
|
|
tab->colors.item.selectedPressed.text = tab->colors.item.selected.text;
|
|
|
|
tab->colors.item.selectedDisabled.backAlpha = tab->colors.item.selected.backAlpha;
|
|
tab->colors.item.selectedDisabled.backTop = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 100);
|
|
tab->colors.item.selectedDisabled.backBottom = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 140);
|
|
tab->colors.item.selectedDisabled.frameType = FRAMETYPE_DISABLED;
|
|
tab->colors.item.selectedDisabled.text = tab->colors.item.normalDisabled.text;
|
|
|
|
if (NULL != tab->frameBitmap)
|
|
DeleteObject(tab->frameBitmap);
|
|
|
|
BITMAPINFOHEADER frameHeader;
|
|
BYTE *framePixels;
|
|
tab->frameBitmap = ImageLoader_LoadBitmapEx(WASABI_API_ORIG_HINST,
|
|
MAKEINTRESOURCE(IDR_SELECTIONFRAME_IMAGE), FALSE, &frameHeader, (void**)&framePixels);
|
|
if (NULL == tab->frameBitmap)
|
|
{
|
|
tab->frameWidth = 0;
|
|
tab->frameHeight = 0;
|
|
}
|
|
else
|
|
{
|
|
if (frameHeader.biHeight < 0)
|
|
frameHeader.biHeight = -frameHeader.biHeight;
|
|
|
|
tab->frameWidth = (frameHeader.biWidth - 1)/2;
|
|
tab->frameHeight = (frameHeader.biHeight/2 - 1)/2;
|
|
|
|
COLORREF rgbTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 200);
|
|
COLORREF rgbBottom = GetSysColor(COLOR_WINDOW);
|
|
|
|
Image_ColorizeEx(framePixels, frameHeader.biWidth, frameHeader.biHeight, 0, 0,
|
|
frameHeader.biWidth, frameHeader.biHeight, frameHeader.biBitCount, TRUE, rgbBottom, rgbTop);
|
|
}
|
|
|
|
if (NULL != tab->chevronImage)
|
|
{
|
|
DeleteObject(tab->chevronImage);
|
|
tab->chevronImage = NULL;
|
|
}
|
|
|
|
tab->chevronImage = LoginTab_LoadChevronImage(hwnd, &tab->chevronWidth, NULL);
|
|
if (NULL == tab->chevronImage)
|
|
{
|
|
tab->chevronWidth = 0;
|
|
}
|
|
else
|
|
{
|
|
INT k = tab->frameWidth - 2;
|
|
if (k < 0) k = 0;
|
|
tab->chevronWidth += 2 * k;
|
|
}
|
|
|
|
}
|
|
|
|
static void LoginTab_UpdateFonts(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
|
|
tab->fontText = NULL;
|
|
LoginGuiObject *loginGui;
|
|
if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui)))
|
|
{
|
|
tab->fontText = loginGui->GetTextFont();
|
|
loginGui->Release();
|
|
}
|
|
|
|
HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
|
if (NULL != hdc)
|
|
{
|
|
HFONT fontOrig = (HFONT)SelectObject(hdc, tab->fontText);
|
|
|
|
TEXTMETRIC tm;
|
|
if (FALSE != GetTextMetrics(hdc, &tm))
|
|
{
|
|
tab->textHeight = tm.tmHeight;
|
|
|
|
LONG baseunitY = tm.tmHeight;
|
|
LONG baseunitX = LoginBox_GetAveCharWidth(hdc);
|
|
|
|
tab->textWidthMax = baseunitX * MAX_TEXT_AVECHAR_WIDTH + tm.tmOverhang;
|
|
tab->margins.left = MulDiv(1, baseunitX, 4);
|
|
tab->margins.right = MulDiv(1, baseunitX, 4);
|
|
tab->margins.top = MulDiv(1, baseunitY, 8);
|
|
tab->margins.bottom = MulDiv(1, baseunitY, 8);
|
|
tab->spacing = MulDiv(1, baseunitX, 4);
|
|
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
tab->items[i]->textWidth = -1;
|
|
}
|
|
|
|
|
|
SelectObject(hdc, fontOrig);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
}
|
|
static void LoginTab_UpdateMouseInfo(HWND hwnd)
|
|
{
|
|
POINT pt;
|
|
RECT rect;
|
|
GetCursorPos(&pt);
|
|
MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
|
|
|
|
GetClientRect(hwnd, &rect);
|
|
if (FALSE == PtInRect(&rect, pt))
|
|
{
|
|
SendMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
|
|
}
|
|
else
|
|
{
|
|
UINT vKey = 0;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
|
|
vKey |= MK_CONTROL;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_LBUTTON)))
|
|
vKey |= MK_LBUTTON;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_RBUTTON)))
|
|
vKey |= MK_RBUTTON;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT)))
|
|
vKey |= MK_SHIFT;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON1)))
|
|
vKey |= MK_XBUTTON1;
|
|
if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON2)))
|
|
vKey |= MK_XBUTTON2;
|
|
|
|
SendMessage(hwnd, WM_MOUSEMOVE, vKey, MAKELPARAM(pt.x, pt.y));
|
|
}
|
|
}
|
|
static HWND LoginTab_CreateTooltip(HWND hwnd)
|
|
{
|
|
HWND hTooltip = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | WS_EX_LAYERED,
|
|
TOOLTIPS_CLASS, NULL, WS_CLIPSIBLINGS | WS_POPUP | TTS_NOPREFIX /*| TTS_ALWAYSTIP*/,
|
|
0, 0, 0, 0, hwnd, NULL, NULL, NULL);
|
|
|
|
if (NULL == hTooltip)
|
|
return NULL;
|
|
|
|
SendMessage(hTooltip, CCM_SETVERSION, 6, 0L);
|
|
SetWindowPos(hTooltip, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
|
|
SendMessage(hTooltip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1000, 0));
|
|
|
|
TOOLINFO ti;
|
|
ZeroMemory(&ti, sizeof(ti));
|
|
ti.cbSize = sizeof(TOOLINFO);
|
|
ti.hwnd = hwnd;
|
|
ti.lpszText = LPSTR_TEXTCALLBACK;
|
|
SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
|
|
|
|
|
|
INT helpWidthMax = 260;
|
|
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
OSVERSIONINFO vi;
|
|
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
if (FALSE == GetVersionEx(&vi))
|
|
ZeroMemory(&vi, sizeof(vi));
|
|
|
|
if (vi.dwMajorVersion < 6)
|
|
ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
|
|
|
|
RECT marginRect;
|
|
SetRect(&marginRect, 3, 1, 3, 1);
|
|
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
|
|
{
|
|
HFONT font = CreateFontIndirect(&ncm.lfStatusFont);
|
|
if (NULL != font)
|
|
{
|
|
HDC hdc = GetDCEx(hTooltip, NULL, DCX_CACHE);
|
|
if (NULL != hdc)
|
|
{
|
|
HFONT fontOrig = (HFONT)SelectObject(hdc, font);
|
|
TEXTMETRIC tm;
|
|
if (FALSE != GetTextMetrics(hdc, &tm))
|
|
{
|
|
INT baseunitX = LoginBox_GetAveCharWidth(hdc);
|
|
if (NULL != baseunitX)
|
|
{
|
|
helpWidthMax = baseunitX * MAX_HELP_AVECHAR_WIDTH + tm.tmOverhang;
|
|
marginRect.left = MulDiv(2, baseunitX, 4);
|
|
marginRect.right = marginRect.left;
|
|
marginRect.top = MulDiv(1, tm.tmHeight, 8);
|
|
marginRect.bottom = MulDiv(1, tm.tmHeight, 8);
|
|
}
|
|
}
|
|
SelectObject(hdc, fontOrig);
|
|
ReleaseDC(hTooltip, hdc);
|
|
}
|
|
DeleteObject(font);
|
|
}
|
|
}
|
|
|
|
SendMessage(hTooltip, TTM_SETMAXTIPWIDTH, 0, helpWidthMax);
|
|
SendMessage(hTooltip, TTM_SETMARGIN, 0, (LPARAM)&marginRect);
|
|
|
|
return hTooltip;
|
|
}
|
|
|
|
static void LoginTab_RelayTooltipMouseMsg(HWND hwnd, UINT uMsg, UINT vKey, POINTS pts)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == tab->hTooltip || -1 == tab->iHighlighted)
|
|
return;
|
|
|
|
MSG msg;
|
|
msg.hwnd = hwnd;
|
|
msg.message = uMsg;
|
|
msg.wParam = (WPARAM)vKey;
|
|
msg.lParam = MAKELPARAM(pts.x, pts.y);
|
|
|
|
SendMessage(tab->hTooltip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
|
|
}
|
|
|
|
static void LoginTab_UpdateTooltip(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
TOOLINFO ti;
|
|
ZeroMemory(&ti, sizeof(ti));
|
|
ti.cbSize = sizeof(ti);
|
|
ti.hwnd = hwnd;
|
|
ti.uId = 0;
|
|
|
|
if (FALSE == SendMessage(tab->hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
|
|
return;
|
|
|
|
INT iItem = tab->iHighlighted;
|
|
RECT rect;
|
|
if (-1 == iItem || FALSE == LoginTab_GetItemRect(hwnd, iItem, &rect))
|
|
{
|
|
SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L);
|
|
SysFreeString(tab->helpText);
|
|
tab->helpText = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
if (ti.lParam != (LPARAM)iItem || FALSE == EqualRect(&ti.rect, &rect))
|
|
{
|
|
SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L);
|
|
|
|
CopyRect(&ti.rect, &rect);
|
|
if (ti.lParam != iItem)
|
|
{
|
|
LPCWSTR pszTitle = NULL;
|
|
if (iItem >= 0 && iItem < tab->itemsCount)
|
|
pszTitle = tab->items[iItem]->text;
|
|
SendMessage(tab->hTooltip, TTM_SETTITLE, (WPARAM)TTI_NONE, (LPARAM)pszTitle);
|
|
|
|
ti.lParam = (LPARAM)iItem;
|
|
ti.lpszText = LPSTR_TEXTCALLBACK;
|
|
|
|
SysFreeString(tab->helpText);
|
|
tab->helpText = NULL;
|
|
}
|
|
SendMessage(tab->hTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&ti);
|
|
|
|
}
|
|
|
|
SendMessage(tab->hTooltip, TTM_ACTIVATE, TRUE, 0L);
|
|
}
|
|
|
|
static void LoginTab_FreeItem(LOGINTABITEM *item)
|
|
{
|
|
if (NULL == item) return;
|
|
|
|
LoginBox_FreeString(item->text);
|
|
free(item);
|
|
}
|
|
|
|
static BOOL LoginTab_SetItemInternal(LOGINTABITEM *dst, const NLTITEM *src)
|
|
{
|
|
if (NULL == dst || NULL == src)
|
|
return FALSE;
|
|
|
|
BOOL succeeded = TRUE;
|
|
|
|
if (0 != (NLTIF_TEXT & src->mask))
|
|
{
|
|
dst->textWidth = -1;
|
|
LoginBox_FreeString(dst->text);
|
|
if (NULL != src->pszText)
|
|
{
|
|
dst->text = LoginBox_CopyString(src->pszText);
|
|
if (NULL == dst->text) succeeded = FALSE;
|
|
}
|
|
else
|
|
{
|
|
dst->text = NULL;
|
|
}
|
|
}
|
|
|
|
if (0 != (NLTIF_PARAM & src->mask))
|
|
dst->param = src->param;
|
|
|
|
if (0 != (NLTIF_IMAGE & src->mask))
|
|
dst->iImage = src->iImage;
|
|
|
|
if (0 != (NLTIF_IMAGE_ACTIVE & src->mask))
|
|
dst->iImageActive = src->iImageActive;
|
|
|
|
if (0 != (NLTIF_IMAGE_DISABLED & src->mask))
|
|
dst->iImageDisabled = src->iImageDisabled;
|
|
|
|
return succeeded;
|
|
}
|
|
|
|
static LOGINTABITEM *LoginTab_CreateItem(const NLTITEM *pItem)
|
|
{
|
|
LOGINTABITEM *item = (LOGINTABITEM*)calloc(1, sizeof(LOGINTABITEM));
|
|
if (NULL == item) return NULL;
|
|
|
|
item->textWidth = -1;
|
|
item->iImage = NLTM_IMAGE_NONE;
|
|
item->iImageActive = NLTM_IMAGE_NONE;
|
|
item->iImageDisabled = NLTM_IMAGE_NONE;
|
|
|
|
if (NULL != pItem && FALSE == LoginTab_SetItemInternal(item, pItem))
|
|
{
|
|
LoginTab_FreeItem(item);
|
|
item = NULL;
|
|
}
|
|
return item;
|
|
}
|
|
|
|
static INT LoginTab_DeleteAllItemsReal(HWND hwnd, LOGINTABITEM **itemsList, INT itemsCount)
|
|
{
|
|
if (NULL == itemsList || itemsCount < 1)
|
|
return 0;
|
|
|
|
NMLOGINTAB nmp;
|
|
nmp.hdr.hwndFrom = hwnd;
|
|
nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
|
|
BOOL fNotifyItem = FALSE;
|
|
|
|
if (NULL != hParent)
|
|
{
|
|
nmp.hdr.code = NLTN_DELETEALLITEMS;
|
|
nmp.iItem = -1;
|
|
fNotifyItem = (FALSE == (BOOL)SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp));
|
|
if (FALSE != fNotifyItem)
|
|
nmp.hdr.code = NLTN_DELETEITEM;
|
|
}
|
|
|
|
INT deleted = 0;
|
|
for(; itemsCount > 0; itemsCount--)
|
|
{
|
|
nmp.iItem = itemsCount - 1;
|
|
if (FALSE != fNotifyItem)
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp);
|
|
|
|
LoginTab_FreeItem(itemsList[nmp.iItem]);
|
|
deleted++;
|
|
}
|
|
|
|
return deleted;
|
|
}
|
|
|
|
static LRESULT LoginTab_OnCreate(HWND hwnd, CREATESTRUCT* pcs)
|
|
{
|
|
LOGINTAB *tab = (LOGINTAB*)calloc(1, sizeof(LOGINTAB));
|
|
if (NULL != tab)
|
|
{
|
|
SetLastError(ERROR_SUCCESS);
|
|
if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)tab) && ERROR_SUCCESS != GetLastError())
|
|
{
|
|
free(tab);
|
|
tab = NULL;
|
|
}
|
|
}
|
|
|
|
if (NULL == tab)
|
|
return -1;
|
|
|
|
tab->iPressed = -1;
|
|
tab->iSelected = -1;
|
|
tab->iHighlighted = -1;
|
|
|
|
tab->hTooltip = LoginTab_CreateTooltip(hwnd);
|
|
|
|
LoginTab_UpdateColors(hwnd);
|
|
LoginTab_UpdateFonts(hwnd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void LoginTab_OnDestroy(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
SetWindowLongPtr(hwnd, 0, 0L);
|
|
if (NULL == tab) return;
|
|
|
|
if (NULL != tab->items)
|
|
{
|
|
tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount);
|
|
free(tab->items);
|
|
}
|
|
|
|
if (NULL != tab->order)
|
|
free(tab->order);
|
|
|
|
if (NULL != tab->frameBitmap)
|
|
DeleteObject(tab->frameBitmap);
|
|
|
|
if (NULL != tab->itemBitmap)
|
|
DeleteObject(tab->itemBitmap);
|
|
|
|
if (NULL != tab->chevronImage)
|
|
DeleteObject(tab->chevronImage);
|
|
|
|
if (NULL != tab->hTooltip)
|
|
DestroyWindow(tab->hTooltip);
|
|
|
|
SysFreeString(tab->helpText);
|
|
|
|
free(tab);
|
|
}
|
|
|
|
static void LoginTab_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
|
|
{
|
|
if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
|
|
return;
|
|
|
|
LoginTab_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
|
|
}
|
|
|
|
|
|
static void LoginTab_OnPaint(HWND hwnd)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
if (BeginPaint(hwnd, &ps))
|
|
{
|
|
if (ps.rcPaint.left != ps.rcPaint.right)
|
|
LoginTab_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
}
|
|
|
|
static void LoginTab_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
|
|
{
|
|
RECT clientRect;
|
|
if (GetClientRect(hwnd, &clientRect))
|
|
LoginTab_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
|
|
}
|
|
|
|
|
|
static void LoginTab_OnMouseMove(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
RECT rect;
|
|
|
|
INT iHighlighted = tab->iHighlighted;
|
|
|
|
tab->iHighlighted = (-1 == tab->iPressed) ?
|
|
LoginTab_HitTest(hwnd, pts.x, pts.y, &rect) : -1;
|
|
|
|
|
|
|
|
if (iHighlighted != tab->iHighlighted)
|
|
LoginTab_UpdateTooltip(hwnd);
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_MOUSEMOVE, vKey, pts);
|
|
|
|
|
|
if (iHighlighted != tab->iHighlighted)
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect))
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
if (-1 != tab->iHighlighted)
|
|
LoginTab_TrackMouseLeave(hwnd);
|
|
|
|
|
|
}
|
|
|
|
static void LoginTab_OnMouseLeave(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
INT iPressed = tab->iPressed;
|
|
INT iHighlighted = tab->iHighlighted;
|
|
|
|
tab->iPressed = -1;
|
|
tab->iHighlighted = -1;
|
|
|
|
RECT rect;
|
|
if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect))
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
if (-1 != iPressed && iPressed != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect))
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
}
|
|
|
|
static void LoginTab_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONDOWN, vKey, pts);
|
|
|
|
RECT rect, rect2;
|
|
INT iPressed, iHighlighted;
|
|
INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect);
|
|
|
|
iPressed = tab->iPressed;
|
|
iHighlighted = tab->iHighlighted;
|
|
|
|
tab->iPressed = iItem;
|
|
tab->iHighlighted = -1;
|
|
|
|
if (iPressed != iItem && -1 != iPressed &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
if (iHighlighted != iItem && -1 != iHighlighted && iHighlighted != iPressed &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
if (-1 != iItem && iPressed != iItem)
|
|
{
|
|
if (iItem == tab->itemsCount && tab->iFocused != iItem)
|
|
{
|
|
INT iFocused = tab->iFocused;
|
|
tab->iFocused = iItem;
|
|
|
|
if (-1 != iFocused && FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2))
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
if (iItem == tab->itemsCount)
|
|
{
|
|
|
|
LoginTab_ShowHiddenTabs(hwnd, &rect);
|
|
|
|
if (0 == (0x8000 & GetAsyncKeyState((FALSE == GetSystemMetrics(SM_SWAPBUTTON)) ? VK_LBUTTON : VK_RBUTTON)))
|
|
tab->iPressed = -1;
|
|
tab->iFocused = tab->itemsCount;
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
LoginTab_UpdateMouseInfo(hwnd);
|
|
|
|
}
|
|
else if (hwnd != GetCapture())
|
|
SetCapture(hwnd);
|
|
}
|
|
}
|
|
|
|
static void LoginTab_OnLButtonUp(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONUP, vKey, pts);
|
|
|
|
RECT rect, rect2;
|
|
|
|
INT iPressed = tab->iPressed;
|
|
INT iHighlighted = tab->iHighlighted;
|
|
INT iSelected = tab->iSelected;
|
|
INT iFocused = tab->iFocused;
|
|
|
|
INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect);
|
|
|
|
|
|
tab->iPressed = -1;
|
|
tab->iHighlighted = iItem;
|
|
|
|
if (iItem == iPressed && -1 != iItem)
|
|
{
|
|
if (iItem < tab->itemsCount)
|
|
tab->iSelected = iItem;
|
|
tab->iFocused = iItem;
|
|
}
|
|
|
|
if (-1 != iHighlighted && iHighlighted != tab->iHighlighted &&
|
|
iHighlighted != iPressed && iHighlighted != iFocused && iHighlighted != iSelected &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
|
|
if (-1 != iPressed && iPressed != tab->iPressed &&
|
|
(iPressed != iFocused || tab->iFocused == iFocused) &&
|
|
(iPressed != iSelected || tab->iSelected == iSelected) &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
|
|
if (-1 != iSelected && iSelected != tab->iSelected &&
|
|
iSelected != iFocused &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
if (-1 != iFocused && iFocused != tab->iFocused &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2))
|
|
{
|
|
InvalidateRect(hwnd, &rect2, FALSE);
|
|
}
|
|
|
|
|
|
|
|
if (-1 != iItem)
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
|
|
if (hwnd == GetCapture())
|
|
ReleaseCapture();
|
|
|
|
if (-1 != tab->iSelected && tab->iSelected != iSelected)
|
|
LoginTab_NotifySelectionChanged(hwnd);
|
|
}
|
|
|
|
static void LoginTab_OnRButtonDown(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONDOWN, vKey, pts);
|
|
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
if (NULL != hParent)
|
|
{
|
|
NMLOGINTABCLICK ntc;
|
|
ntc.hdr.code = NM_RCLICK;
|
|
ntc.hdr.hwndFrom = hwnd;
|
|
ntc.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
ntc.pt.x = pts.x;
|
|
ntc.pt.y = pts.y;
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)ntc.hdr.idFrom, (LPARAM)&ntc);
|
|
}
|
|
}
|
|
|
|
static void LoginTab_OnRButtonUp(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONUP, vKey, pts);
|
|
}
|
|
|
|
static void LoginTab_OnMButtonDown(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONDOWN, vKey, pts);
|
|
}
|
|
|
|
static void LoginTab_OnMButtonUp(HWND hwnd, UINT vKey, POINTS pts)
|
|
{
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONUP, vKey, pts);
|
|
}
|
|
|
|
static void LoginTab_OnCaptureChanged(HWND hwnd, HWND hCapture)
|
|
{
|
|
if (hwnd != hCapture)
|
|
LoginTab_TrackMouseLeave(hwnd);
|
|
}
|
|
|
|
static void LoginTab_OnSetFocus(HWND hwnd, HWND hFocus)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
INT iFocus = tab->iSelected;
|
|
tab->iFocused = -1;
|
|
LoginTab_SetItemFocus(hwnd, iFocus);
|
|
}
|
|
|
|
static void LoginTab_OnKillFocus(HWND hwnd, HWND hFocus)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
RECT rect;
|
|
if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
}
|
|
|
|
static void LoginTab_OnEnable(HWND hwnd, BOOL fEnabled)
|
|
{
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
}
|
|
|
|
static void LoginTab_OnKeyDown(HWND hwnd, INT vKey, UINT flags)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if (FALSE != LoginTab_IsLocked(hwnd))
|
|
return;
|
|
|
|
INT focusPos = -1;
|
|
if (tab->iFocused >= tab->itemsCount)
|
|
{
|
|
focusPos = tab->iFocused;
|
|
}
|
|
else if (-1 != tab->iFocused)
|
|
{
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
{
|
|
if (tab->order[i] == tab->iFocused)
|
|
{
|
|
focusPos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(vKey)
|
|
{
|
|
case VK_LEFT: focusPos = (focusPos > tab->lastVisible) ? tab->lastVisible : (focusPos - 1); break;
|
|
case VK_RIGHT: focusPos++; break;
|
|
case VK_PRIOR:
|
|
case VK_HOME: focusPos = 0; break;
|
|
case VK_END: focusPos = tab->itemsCount -1; break;
|
|
case VK_NEXT: focusPos = tab->lastVisible; break;
|
|
|
|
case VK_SPACE:
|
|
case VK_RETURN:
|
|
if (tab->iFocused == tab->itemsCount)
|
|
{
|
|
tab->iPressed = tab->iFocused;
|
|
RECT rect;
|
|
if (FALSE == LoginTab_GetItemRect(hwnd, tab->iPressed, &rect))
|
|
SetRectEmpty(&rect);
|
|
|
|
LoginTab_ShowHiddenTabs(hwnd, &rect);
|
|
tab->iFocused = tab->itemsCount;
|
|
tab->iPressed = -1;
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
LoginTab_UpdateMouseInfo(hwnd);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
INT iFocus;
|
|
if (focusPos >= tab->itemsCount)
|
|
iFocus = tab->itemsCount;
|
|
else if (focusPos < 0)
|
|
iFocus = 0;
|
|
else
|
|
iFocus = tab->order[focusPos];
|
|
|
|
LoginTab_SetItemFocus(hwnd, iFocus);
|
|
}
|
|
|
|
|
|
static LRESULT LoginTab_OnGetDlgCode(HWND hwnd, INT vKey, MSG *pMsg)
|
|
{
|
|
switch(vKey)
|
|
{
|
|
case VK_TAB: return 0;
|
|
}
|
|
return DLGC_WANTALLKEYS;
|
|
}
|
|
|
|
static LRESULT LoginTab_OnMenuChar(HWND hwnd, INT vkCode, INT menuType, HMENU hMenu)
|
|
{
|
|
switch(vkCode)
|
|
{
|
|
case VK_SPACE:
|
|
case VK_RETURN:
|
|
for (INT i = GetMenuItemCount(hMenu) - 1; i >= 0; i--)
|
|
{
|
|
UINT r = GetMenuState(hMenu, i, MF_BYPOSITION);
|
|
if (-1 != r && 0 != (MF_HILITE & LOWORD(r)))
|
|
return MAKELRESULT(i, MNC_EXECUTE);
|
|
}
|
|
return MAKELRESULT(0, MNC_SELECT);
|
|
}
|
|
return MAKELRESULT(0, MNC_IGNORE);
|
|
}
|
|
|
|
static void LoginTab_OnMenuSelect(HWND hwnd, INT iItem, UINT flags, HMENU hMenu)
|
|
{
|
|
MENUINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
|
|
|
|
if (FALSE != GetMenuInfo(hMenu, &mi) && NULL != mi.dwMenuData)
|
|
{
|
|
CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
|
|
if (NULL != pmp->hwndMenu)
|
|
{
|
|
UINT stateOrig = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
|
|
|
|
SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L);
|
|
|
|
UINT stateCurrent = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
|
|
if ((UISF_HIDEFOCUS & stateOrig) != (UISF_HIDEFOCUS & stateCurrent))
|
|
{
|
|
INT menuCount = GetMenuItemCount(hMenu);
|
|
while(menuCount--)
|
|
{
|
|
if (iItem == GetMenuItemID(hMenu, menuCount))
|
|
{
|
|
RECT rect;
|
|
if (FALSE != GetMenuItemRect(NULL, hMenu, menuCount, &rect))
|
|
{
|
|
MapWindowPoints(HWND_DESKTOP, pmp->hwndMenu, (POINT*)&rect, 2);
|
|
InvalidateRect(pmp->hwndMenu, &rect, FALSE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void LoginTab_GetTootipDispInfo(HWND hwnd, NMTTDISPINFO *pdisp)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return;
|
|
|
|
if(NULL == tab->helpText)
|
|
{
|
|
INT iItem = (INT)pdisp->lParam;
|
|
if (iItem >= 0 && iItem < tab->itemsCount)
|
|
{
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
if (NULL != hParent)
|
|
{
|
|
NMLOGINTABHELP help;
|
|
help.hdr.code = NLTN_GETITEMHELP;
|
|
help.hdr.hwndFrom = hwnd;
|
|
help.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
help.iItem = iItem;
|
|
help.param = tab->items[iItem]->param;
|
|
help.bstrHelp = NULL;
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)help.hdr.idFrom, (LPARAM)&help);
|
|
tab->helpText = help.bstrHelp;
|
|
}
|
|
}
|
|
else if (iItem == tab->itemsCount)
|
|
{
|
|
WCHAR szBuffer[256] = {0};
|
|
WASABI_API_LNGSTRINGW_BUF(IDS_LOGINTAB_MOREPROVIDERS, szBuffer, ARRAYSIZE(szBuffer));
|
|
tab->helpText = SysAllocString(szBuffer);
|
|
}
|
|
|
|
if (NULL == tab->helpText)
|
|
tab->helpText = SysAllocString(L" ");
|
|
}
|
|
|
|
if (NULL != tab->helpText && L'\0' != tab->helpText)
|
|
{
|
|
pdisp->lpszText = (LPWSTR)tab->helpText;
|
|
pdisp->uFlags = TTF_DI_SETITEM;
|
|
}
|
|
}
|
|
|
|
static BOOL LoginTab_OnShow(HWND hwnd, HWND hTooltip)
|
|
{
|
|
TOOLINFO ti;
|
|
ZeroMemory(&ti, sizeof(ti));
|
|
ti.cbSize = sizeof(ti);
|
|
ti.hwnd = hwnd;
|
|
ti.uId = 0;
|
|
|
|
if (FALSE == SendMessage(hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
|
|
return FALSE;
|
|
|
|
MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&ti.rect, 2);
|
|
|
|
RECT windowRect, tooltipRect;
|
|
GetWindowRect(hwnd, &windowRect);
|
|
GetWindowRect(hTooltip, &tooltipRect);
|
|
|
|
ti.rect.right = ti.rect.left + (tooltipRect.right - tooltipRect.left);
|
|
ti.rect.top = windowRect.bottom;
|
|
ti.rect.bottom = ti.rect.top + (tooltipRect.bottom - tooltipRect.top);
|
|
|
|
HMONITOR hMonitor = MonitorFromRect(&ti.rect, MONITOR_DEFAULTTONEAREST);
|
|
if (NULL != hMonitor)
|
|
{
|
|
MONITORINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
if (FALSE != GetMonitorInfo(hMonitor, &mi))
|
|
{
|
|
INT offsetX = 0;
|
|
INT offsetY = 0;
|
|
|
|
if (ti.rect.right > mi.rcWork.right)
|
|
offsetX += (mi.rcWork.right - ti.rect.right);
|
|
|
|
if (ti.rect.bottom > mi.rcWork.bottom)
|
|
{
|
|
offsetY += (mi.rcWork.bottom - ti.rect.bottom);
|
|
if ((ti.rect.top + offsetY) < windowRect.bottom && (ti.rect.bottom + offsetY) > windowRect.top)
|
|
offsetY = (windowRect.top - (ti.rect.bottom - ti.rect.top)) - ti.rect.top;
|
|
}
|
|
|
|
if ((ti.rect.left + offsetX) < mi.rcWork.left)
|
|
offsetX += (mi.rcWork.left - (ti.rect.left + offsetX));
|
|
if ((ti.rect.top + offsetY) < mi.rcWork.top)
|
|
offsetY += (mi.rcWork.top - (ti.rect.top + offsetY));
|
|
|
|
|
|
|
|
|
|
OffsetRect(&ti.rect, offsetX, offsetY);
|
|
}
|
|
}
|
|
|
|
return SetWindowPos(hTooltip, NULL, ti.rect.left, ti.rect.top, 0, 0,
|
|
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
|
|
}
|
|
|
|
static LRESULT LoginTab_OnTooltipNotify(HWND hwnd, NMHDR *pnmh)
|
|
{
|
|
switch(pnmh->code)
|
|
{
|
|
case TTN_GETDISPINFO:
|
|
LoginTab_GetTootipDispInfo(hwnd, (NMTTDISPINFO*)pnmh);
|
|
break;
|
|
case TTN_SHOW:
|
|
return LoginTab_OnShow(hwnd, pnmh->hwndFrom);
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT LoginTab_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return 0;
|
|
|
|
if (tab->hTooltip == pnmh->hwndFrom && NULL != tab->hTooltip)
|
|
return LoginTab_OnTooltipNotify(hwnd, pnmh);
|
|
|
|
return 0;
|
|
}
|
|
static INT LoginTab_OnGetIdealHeight(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return 0;
|
|
|
|
INT height = 0;
|
|
|
|
INT iconCX, iconCY;
|
|
if (NULL != tab->imageList && FALSE != ImageList_GetIconSize(tab->imageList, &iconCX, &iconCY))
|
|
{
|
|
height += (iconCY + 2 * IMAGE_MARGIN_CY);
|
|
}
|
|
|
|
height += tab->textHeight;
|
|
|
|
height += tab->margins.top + tab->margins.bottom;
|
|
height += 2 * tab->frameHeight;
|
|
|
|
return height;
|
|
}
|
|
|
|
static INT LoginTab_OnGetIdealWidth(HWND hwnd, INT itemsCount)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return 0;
|
|
|
|
INT width = 0;
|
|
|
|
if (itemsCount < 0) itemsCount = 0;
|
|
if (itemsCount > tab->itemsCount) itemsCount = tab->itemsCount;
|
|
|
|
if (itemsCount == 0)
|
|
{
|
|
width = tab->margins.left + tab->margins.right;
|
|
return width;
|
|
}
|
|
itemsCount--;
|
|
if (itemsCount <= tab->lastVisible)
|
|
{
|
|
RECT rect;
|
|
if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect))
|
|
width = rect.right;
|
|
}
|
|
else
|
|
{
|
|
RECT rect;
|
|
GetWindowRect(hwnd, &rect);
|
|
LONG origWidth = rect.right - rect.left;
|
|
LONG origHeight = rect.bottom - rect.top;
|
|
SetWindowPos(hwnd, NULL, 0, 0, 40000, origHeight,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
|
|
|
|
if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect))
|
|
width = rect.right;
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0, origWidth, origHeight,
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
|
|
}
|
|
|
|
if (0 != width)
|
|
{
|
|
width += (itemsCount < (tab->itemsCount - 1) && tab->chevronWidth > tab->margins.right) ?
|
|
tab->chevronWidth : tab->margins.right;
|
|
}
|
|
return width;
|
|
}
|
|
static INT LoginTab_OnInsertItem(HWND hwnd, INT iItem, NLTITEM *pItem)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == pItem) return -1;
|
|
if (iItem < 0) iItem = 0;
|
|
|
|
|
|
INT itemsMax = (0 != tab->items) ? (INT)(_msize(tab->items)/sizeof(LOGINTABITEM*)) : 0;
|
|
if (tab->itemsCount >= itemsMax)
|
|
{
|
|
INT k = tab->itemsCount + 1 - itemsMax;
|
|
if (k < 8) k = 8;
|
|
itemsMax += k;
|
|
void *data = realloc(tab->items, itemsMax * sizeof(LOGINTABITEM*));
|
|
if (NULL == data) return -1;
|
|
tab->items = (LOGINTABITEM**)data;
|
|
data = realloc(tab->order, itemsMax * sizeof(INT));
|
|
if (NULL == data) return -1;
|
|
tab->order = (INT*)data;
|
|
}
|
|
|
|
LOGINTABITEM *item = LoginTab_CreateItem(pItem);
|
|
if (NULL == item) return -1;
|
|
|
|
if (iItem >= tab->itemsCount)
|
|
{
|
|
iItem = tab->itemsCount;
|
|
tab->items[iItem] = item;
|
|
tab->order[iItem] = iItem;
|
|
}
|
|
else
|
|
{
|
|
MoveMemory((tab->items + iItem + 1), (tab->items + iItem), sizeof(LOGINTABITEM*) * (tab->itemsCount - iItem));
|
|
tab->items[iItem] = item;
|
|
|
|
MoveMemory((tab->order + iItem + 1), (tab->order + iItem), sizeof(INT) * (tab->itemsCount - iItem));
|
|
tab->order[iItem] = iItem;
|
|
|
|
for (INT i = 0; i <= tab->itemsCount; i++)
|
|
{
|
|
if (iItem != i && tab->order[i] >= iItem)
|
|
++(tab->order[i]);
|
|
}
|
|
}
|
|
|
|
tab->itemsCount++;
|
|
|
|
|
|
return iItem;
|
|
}
|
|
|
|
static BOOL LoginTab_OnSetItem(HWND hwnd, INT iItem, NLTITEM *pItem)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == pItem) return FALSE;
|
|
if (iItem < 0 || iItem >= tab->itemsCount) return FALSE;
|
|
|
|
BOOL result = LoginTab_SetItemInternal(tab->items[iItem], pItem);
|
|
|
|
RECT rect;
|
|
GetClientRect(hwnd, &rect);
|
|
LONG clientRight = rect.right;
|
|
|
|
if (FALSE != LoginTab_GetItemRect(hwnd, iItem, &rect))
|
|
{
|
|
rect.right = clientRight;
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
else if (NULL != tab->chevronMenu)
|
|
{
|
|
INT menuCount = GetMenuItemCount(tab->chevronMenu);
|
|
while(menuCount--)
|
|
{
|
|
if (iItem == (GetMenuItemID(tab->chevronMenu, menuCount) - 1))
|
|
{
|
|
if (FALSE != GetMenuItemRect(NULL, tab->chevronMenu, menuCount, &rect))
|
|
{
|
|
POINT ptTest;
|
|
ptTest.x = rect.left + (rect.right - rect.left)/2;
|
|
ptTest.y = rect.top + (rect.bottom - rect.top)/2;
|
|
HWND hwndMenu = WindowFromPoint(ptTest);
|
|
if (NULL != hwndMenu)
|
|
{
|
|
MapWindowPoints(HWND_DESKTOP, hwndMenu, (POINT*)&rect, 2);
|
|
InvalidateRect(hwndMenu, &rect, FALSE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static BOOL LoginTab_OnGetItem(HWND hwnd, INT iItem, NLTITEM *pItem)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab || NULL == pItem) return FALSE;
|
|
if (iItem < 0 || iItem >= tab->itemsCount) return FALSE;
|
|
|
|
LOGINTABITEM *item = tab->items[iItem];
|
|
|
|
BOOL succeeded = TRUE;
|
|
|
|
if (0 != (NLTIF_TEXT & pItem->mask))
|
|
{
|
|
if (NULL == pItem->pszText ||
|
|
FAILED(StringCchCopyEx(pItem->pszText, pItem->cchTextMax, item->text, NULL, NULL, STRSAFE_IGNORE_NULLS)))
|
|
{
|
|
succeeded = FALSE;
|
|
}
|
|
}
|
|
|
|
if (0 != (NLTIF_PARAM & pItem->mask))
|
|
pItem->param = item->param;
|
|
|
|
if (0 != (NLTIF_IMAGE & pItem->mask))
|
|
pItem->iImage = item->iImage;
|
|
|
|
if (0 != (NLTIF_IMAGE_ACTIVE & pItem->mask))
|
|
pItem->iImageActive = item->iImageActive;
|
|
|
|
if (0 != (NLTIF_IMAGE_DISABLED & pItem->mask))
|
|
pItem->iImageDisabled = item->iImageDisabled;
|
|
|
|
return succeeded;
|
|
}
|
|
|
|
static BOOL LoginTab_OnDeleteItem(HWND hwnd, INT iItem)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
if (iItem < 0 || iItem >= tab->itemsCount)
|
|
return FALSE;
|
|
|
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
|
if (NULL != hParent)
|
|
{
|
|
NMLOGINTAB nmp;
|
|
nmp.hdr.code = NLTN_DELETEITEM;
|
|
nmp.hdr.hwndFrom = hwnd;
|
|
nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
|
|
nmp.iItem = iItem;
|
|
SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp);
|
|
}
|
|
|
|
LOGINTABITEM *item = tab->items[iItem];
|
|
|
|
INT shiftLen = tab->itemsCount - iItem - 1;
|
|
if (shiftLen > 0)
|
|
{
|
|
|
|
MoveMemory((tab->items + iItem), (tab->items + (iItem + 1)), sizeof(LOGINTABITEM*)*shiftLen);
|
|
|
|
INT iOrder = tab->itemsCount - 1;
|
|
while(iOrder--)
|
|
{
|
|
if (iItem == tab->order[iOrder])
|
|
{
|
|
MoveMemory((tab->order + iOrder), (tab->order + (iOrder + 1)),
|
|
sizeof(INT)*(tab->itemsCount - iOrder - 1));
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
LoginTab_FreeItem(item);
|
|
tab->itemsCount--;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static BOOL LoginTab_OnDeleteAllItems(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount);
|
|
return TRUE;
|
|
}
|
|
|
|
static INT LoginTab_OnGetItemCount(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
return (NULL != tab) ? tab->itemsCount : -1;
|
|
}
|
|
|
|
static INT LoginTab_OnGetCurSel(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
return (NULL != tab) ? tab->iSelected : -1;
|
|
}
|
|
|
|
static INT LoginTab_OnSetCurSel(HWND hwnd, INT iItem)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return -1;
|
|
|
|
if (iItem < 0 || iItem >= tab->itemsCount)
|
|
return -1;
|
|
|
|
if (iItem == tab->iSelected)
|
|
return tab->iSelected;
|
|
|
|
INT iSelected = tab->iSelected;
|
|
INT iFocused = tab->iFocused;
|
|
|
|
tab->iSelected = iItem;
|
|
|
|
if (tab->iFocused != tab->itemsCount)
|
|
tab->iFocused = iItem;
|
|
|
|
RECT rect;
|
|
if (-1 != iSelected &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
if (iFocused != tab->iFocused && -1 != iFocused && iFocused != iSelected &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
if (-1 != tab->iSelected &&
|
|
FALSE != LoginTab_GetItemRect(hwnd, tab->iSelected, &rect))
|
|
{
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
|
|
for(INT i = (tab->lastVisible + 1); i < tab->itemsCount; i++)
|
|
{
|
|
if (tab->order[i] == tab->iSelected)
|
|
{
|
|
LoginTab_UpdateLayout(hwnd, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iSelected;
|
|
}
|
|
|
|
|
|
static HIMAGELIST LoginTab_OnSetImageList(HWND hwnd, HIMAGELIST himl)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return NULL;
|
|
|
|
HIMAGELIST old = tab->imageList;
|
|
tab->imageList = himl;
|
|
|
|
LoginTab_UpdateLayout(hwnd, TRUE);
|
|
return old;
|
|
}
|
|
|
|
static HIMAGELIST LoginTab_OnGetImageList(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
return (NULL != tab) ? tab->imageList : NULL;
|
|
}
|
|
|
|
static BOOL LoginTab_OnResetOrder(HWND hwnd)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
for (INT i = 0; i < tab->itemsCount; i++)
|
|
tab->order[i] = i;
|
|
|
|
LoginTab_UpdateLayout(hwnd, FALSE);
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
static void LoginTab_OnLockSelection(HWND hwnd, BOOL fLock)
|
|
{
|
|
UINT windowStyle = GetWindowStyle(hwnd);
|
|
if ((FALSE != fLock) != (0 != (NLTS_LOCKED & windowStyle)))
|
|
{
|
|
if (FALSE != fLock)
|
|
windowStyle |= NLTS_LOCKED;
|
|
else
|
|
windowStyle &= ~NLTS_LOCKED;
|
|
SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
}
|
|
}
|
|
static BOOL LoginTab_OnMeasureChevronItem(HWND hwnd, MEASUREITEMSTRUCT* pmis)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
MENUINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_MENUDATA;
|
|
|
|
if (FALSE != GetMenuInfo(tab->chevronMenu, &mi) && NULL != mi.dwMenuData)
|
|
{
|
|
CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
|
|
pmis->itemWidth = pmp->itemWidth;
|
|
pmis->itemHeight = pmp->itemHeight;
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static BOOL LoginTab_OnDrawChevronItem(HWND hwnd, DRAWITEMSTRUCT* pdis)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
|
|
MENUINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
|
|
|
|
if (FALSE == GetMenuInfo(tab->chevronMenu, &mi) || NULL == mi.dwMenuData)
|
|
return FALSE;
|
|
|
|
CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
|
|
|
|
if (NULL == pmp->hwndMenu)
|
|
{
|
|
pmp->hwndMenu = WindowFromDC(pdis->hDC);
|
|
if (NULL != pmp->hwndMenu)
|
|
{
|
|
SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L);
|
|
}
|
|
}
|
|
|
|
tab->drawStyle = LoginTab_GetDrawStyles(hwnd);
|
|
|
|
if (NULL != pmp->hwndMenu)
|
|
{
|
|
UINT uiState = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
|
|
if (0 == (UISF_HIDEFOCUS & uiState))
|
|
tab->drawStyle |= NLTDS_FOCUSED;
|
|
else
|
|
tab->drawStyle &= ~NLTDS_FOCUSED;
|
|
}
|
|
|
|
|
|
HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pdis->hDC,
|
|
pdis->rcItem.right - pdis->rcItem.left,
|
|
pdis->rcItem.bottom - pdis->rcItem.top);
|
|
|
|
HBITMAP hbmpOrig = NULL;
|
|
POINT viewportOrig;
|
|
if (NULL != hbmp)
|
|
{
|
|
hbmpOrig = (HBITMAP)SelectObject(pmp->hdcItem, hbmp);
|
|
SetViewportOrgEx(pmp->hdcItem, -pdis->rcItem.left, -pdis->rcItem.top, &viewportOrig);
|
|
}
|
|
|
|
if (NULL == mi.hbrBack)
|
|
mi.hbrBack = GetSysColorBrush(COLOR_MENU);
|
|
|
|
INT itemWidth = pdis->rcItem.right - pdis->rcItem.left;
|
|
INT itemHeight = pdis->rcItem.bottom - pdis->rcItem.top;
|
|
|
|
POINT brushOrgEx;
|
|
SetBrushOrgEx(pmp->hdcItem, 0, -pdis->rcItem.top, &brushOrgEx);
|
|
FillRect(pmp->hdcItem, &pdis->rcItem, mi.hbrBack);
|
|
SetBrushOrgEx(pmp->hdcItem, brushOrgEx.x, brushOrgEx.y, NULL);
|
|
|
|
LOGINTABITEM *item = (LOGINTABITEM*)pdis->itemData;
|
|
INT iItem = pdis->itemID - 1;
|
|
|
|
|
|
INT iHighlighted = tab->iHighlighted;
|
|
|
|
if (0 != (ODS_SELECTED & pdis->itemState))
|
|
{
|
|
tab->iHighlighted = iItem;
|
|
if (tab->iFocused != iItem && -1 != tab->iFocused)
|
|
{
|
|
RECT rect;
|
|
if (FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
tab->iFocused = iItem;
|
|
}
|
|
else
|
|
tab->iFocused = -1;
|
|
|
|
LoginTab_PaintItem(hwnd, pmp->hdcItem, tab, item, iItem, &pdis->rcItem, &pdis->rcItem, pmp->hdcSrc);
|
|
|
|
tab->iHighlighted = iHighlighted;
|
|
|
|
BitBlt(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, itemWidth, itemHeight,
|
|
pmp->hdcItem, pdis->rcItem.left, pdis->rcItem.top, SRCCOPY);
|
|
|
|
if (NULL != hbmp)
|
|
{
|
|
SelectObject(pmp->hdcItem, hbmpOrig);
|
|
SetViewportOrgEx(pmp->hdcItem, viewportOrig.x, viewportOrig.y, NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
static BOOL LoginTab_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT* pmis)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
switch(pmis->CtlType)
|
|
{
|
|
case ODT_MENU:
|
|
if (NULL != tab->chevronMenu)
|
|
return LoginTab_OnMeasureChevronItem(hwnd, pmis);
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL LoginTab_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT* pdis)
|
|
{
|
|
LOGINTAB *tab = GetTab(hwnd);
|
|
if (NULL == tab) return FALSE;
|
|
|
|
switch(pdis->CtlType)
|
|
{
|
|
case ODT_MENU:
|
|
if (NULL != tab->chevronMenu)
|
|
return LoginTab_OnDrawChevronItem(hwnd, pdis);
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void LoginTab_OnThemeChanged(HWND hwnd)
|
|
{
|
|
LoginTab_UpdateColors(hwnd);
|
|
OutputDebugStringA("Theme changed received\r\n");
|
|
}
|
|
|
|
void LoginTab_OnSysColorChanged(HWND hwnd)
|
|
{
|
|
LoginTab_UpdateColors(hwnd);
|
|
OutputDebugStringA("Color changed received\r\n");
|
|
}
|
|
|
|
|
|
static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_CREATE: return LoginTab_OnCreate(hwnd, (CREATESTRUCT*)lParam);
|
|
case WM_DESTROY: LoginTab_OnDestroy(hwnd); return 0;
|
|
case WM_ERASEBKGND: return 0;
|
|
case WM_PAINT: LoginTab_OnPaint(hwnd); return 0;
|
|
case WM_PRINTCLIENT: LoginTab_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
|
|
case WM_WINDOWPOSCHANGED: LoginTab_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
|
|
case WM_SIZE: return 0;
|
|
case WM_MOUSEMOVE: LoginTab_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_LBUTTONDOWN: LoginTab_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_LBUTTONUP: LoginTab_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_RBUTTONDOWN: LoginTab_OnRButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_RBUTTONUP: LoginTab_OnRButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_MBUTTONDOWN: LoginTab_OnMButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_MBUTTONUP: LoginTab_OnMButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
|
case WM_MOUSELEAVE: LoginTab_OnMouseLeave(hwnd); return 0;
|
|
case WM_CAPTURECHANGED: LoginTab_OnCaptureChanged(hwnd, (HWND)lParam); return 0;
|
|
case WM_SETFOCUS: LoginTab_OnSetFocus(hwnd, (HWND)wParam); return 0;
|
|
case WM_KILLFOCUS: LoginTab_OnKillFocus(hwnd, (HWND)wParam); return 0;
|
|
case WM_ENABLE: LoginTab_OnEnable(hwnd, (BOOL)wParam); return 0;
|
|
case WM_KEYDOWN: LoginTab_OnKeyDown(hwnd, (INT)wParam, (UINT)lParam); return 0;
|
|
case WM_GETDLGCODE: return LoginTab_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
|
|
case WM_MENUCHAR: return LoginTab_OnMenuChar(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
|
|
case WM_MENUSELECT: LoginTab_OnMenuSelect(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam); return 0;
|
|
case WM_MEASUREITEM: return LoginTab_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam);
|
|
case WM_DRAWITEM: return LoginTab_OnDrawItem(hwnd, (DRAWITEMSTRUCT*)lParam);
|
|
case WM_NOTIFY: return LoginTab_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
|
|
case WM_THEMECHANGED: LoginTab_OnThemeChanged(hwnd); return TRUE;
|
|
case WM_SYSCOLORCHANGE: LoginTab_OnSysColorChanged(hwnd); return TRUE;
|
|
|
|
|
|
case NLTM_GETIDEALHEIGHT: return LoginTab_OnGetIdealHeight(hwnd);
|
|
case NLTM_INSERTITEM: return LoginTab_OnInsertItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
|
|
case NLTM_SETITEM: return LoginTab_OnSetItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
|
|
case NLTM_GETITEM: return LoginTab_OnGetItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
|
|
case NLTM_DELETEITEM: return LoginTab_OnDeleteItem(hwnd, (INT)wParam);
|
|
case NLTM_DELETEALLITEMS: return LoginTab_OnDeleteAllItems(hwnd);
|
|
case NLTM_GETITEMCOUNT: return LoginTab_OnGetItemCount(hwnd);
|
|
case NLTM_GETCURSEL: return LoginTab_OnGetCurSel(hwnd);
|
|
case NLTM_SETCURSEL: return LoginTab_OnSetCurSel(hwnd, (INT)wParam);
|
|
case NLTM_SETIMAGELIST: return (LRESULT)LoginTab_OnSetImageList(hwnd, (HIMAGELIST)lParam);
|
|
case NLTM_GETIMAGELIST: return (LRESULT)LoginTab_OnGetImageList(hwnd);
|
|
case NLTM_RESETORDER: LoginTab_OnResetOrder(hwnd); return 0;
|
|
case NLTM_LOCKSELECTION: LoginTab_OnLockSelection(hwnd, (BOOL)wParam); return 0;
|
|
case NLTM_GETIDEALWIDTH: return LoginTab_OnGetIdealWidth(hwnd, (INT)wParam);
|
|
}
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
} |