Пример #1
0
static int EventArea_DrawWorker(HWND hWnd, HDC hDC)
{
	RECT rc;
	HFONT hOldFont;
	GetClientRect(hWnd, &rc);
	if (g_CluiData.fDisableSkinEngine)
		sttDrawEventAreaBackground(hWnd, hDC, &rc);
	else
		SkinDrawGlyph(hDC, &rc, &rc, "Main,ID=EventArea");

	hOldFont = g_clcPainter.ChangeToFont(hDC, NULL, FONTID_EVENTAREA, NULL);
	SetBkMode(hDC, TRANSPARENT);

	int iCount = GetMenuItemCount(g_CluiData.hMenuNotify);
	rc.left += 26;
	if (g_CluiData.hUpdateContact != 0) {
		TCHAR *szName = pcli->pfnGetContactDisplayName(g_CluiData.hUpdateContact, 0);
		int iIcon = cli_GetContactIcon(g_CluiData.hUpdateContact);

		ske_ImageList_DrawEx(g_himlCListClc, iIcon, hDC, rc.left, (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), CLR_NONE, CLR_NONE, ILD_NORMAL);
		rc.left += 18;
		ske_DrawText(hDC, szName, -1, &rc, DT_VCENTER | DT_SINGLELINE);
		ske_ImageList_DrawEx(g_himlCListClc, (int)g_CluiData.iIconNotify, hDC, 4, (rc.bottom + rc.top - 16) / 2, 16, 16, CLR_NONE, CLR_NONE, ILD_NORMAL);
	}
	else if (iCount > 0) {
		MENUITEMINFO mii = { 0 };
		struct NotifyMenuItemExData *nmi;
		TCHAR *szName;
		int iIcon;

		mii.cbSize = sizeof(mii);
		mii.fMask = MIIM_DATA;
		GetMenuItemInfo(g_CluiData.hMenuNotify, iCount - 1, TRUE, &mii);
		nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
		szName = pcli->pfnGetContactDisplayName(nmi->hContact, 0);
		iIcon = cli_GetContactIcon(nmi->hContact);
		ske_ImageList_DrawEx(g_himlCListClc, iIcon, hDC, rc.left, (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), CLR_NONE, CLR_NONE, ILD_NORMAL);
		rc.left += 18;
		ske_ImageList_DrawEx(g_himlCListClc, nmi->iIcon, hDC, 4, (rc.bottom + rc.top) / 2 - 8, 16, 16, CLR_NONE, CLR_NONE, ILD_NORMAL);
		ske_DrawText(hDC, szName, -1, &rc, DT_VCENTER | DT_SINGLELINE);
	}
	else {
		HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_BLANK), IMAGE_ICON, 16, 16, 0);
		TCHAR *ptszEvents = TranslateT("No events");
		ske_DrawText(hDC, ptszEvents, (int)mir_tstrlen(ptszEvents), &rc, DT_VCENTER | DT_SINGLELINE);
		ske_DrawIconEx(hDC, 4, (rc.bottom + rc.top - 16) / 2, hIcon, 16, 16, 0, 0, DI_NORMAL | DI_COMPAT);
		DestroyIcon(hIcon);
	}

	ske_ResetTextEffect(hDC);
	SelectObject(hDC, hOldFont);
	return 0;
}
Пример #2
0
HRESULT xpt_DrawThemeText(XPTHANDLE xptHandle, HDC hdc, int type, int state, LPCTSTR lpStr, int len, DWORD flag1, DWORD flag2, const RECT *textRect)
{
	mir_cslock lck(xptCS);
	if (xpt_IsThemed(xptHandle))
		DrawThemeText(((XPTObject*)xptHandle)->hThemeHandle, hdc, type, state, (LPCWSTR)lpStr, len, flag1, flag2, textRect);
	else
		ske_DrawText(hdc, lpStr, len, (RECT*)textRect, flag1);

	return S_OK;
}
Пример #3
0
int RowHeight_CalcRowHeight(ClcData *dat, ClcContact *contact, int item)
{
	if (!RowHeights_Alloc(dat, item + 1))
		return -1;

	if (!g_clistApi.hwndContactTree)
		return 0;

	ClcCacheEntry *pdnce = contact->pce;
	if (dat->hWnd != g_clistApi.hwndContactTree || !gl_RowRoot || contact->type == CLCIT_GROUP) {
		int tmp = dat->fontModernInfo[g_clcPainter.GetBasicFontID(contact)].fontHeight;
		if (dat->text_replace_smileys && dat->first_line_draw_smileys && !dat->text_resize_smileys)
			tmp = max(tmp, contact->ssText.iMaxSmileyHeight);
		if (contact->type == CLCIT_GROUP) {
			wchar_t *szCounts = Clist_GetGroupCountsText(dat, contact);
			// Has the count?
			if (szCounts && szCounts[0])
				tmp = max(tmp, dat->fontModernInfo[contact->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS].fontHeight);
		}
		tmp = max(tmp, ICON_HEIGHT);
		tmp = max(tmp, dat->row_min_heigh);
		tmp += dat->row_border * 2;
		if (contact->type == CLCIT_GROUP && contact->group->parent->groupId == 0 && contact->group->parent->cl[0] != contact)
			tmp += dat->row_before_group_space;
		if (item != -1)
			dat->row_heights[item] = tmp;
		return tmp;
	}

	bool hasAvatar = contact->avatar_data != nullptr;
	for (int i = 0;; i++) {
		ROWCELL *pCell = gl_RowTabAccess[i];
		if (pCell == nullptr)
			break;

		if (pCell->type != TC_SPACE) {
			pCell->h = 0;
			pCell->w = 0;
			SetRect(&pCell->r, 0, 0, 0, 0);
			switch (pCell->type) {
			case TC_TEXT1:
				pCell->h = dat->fontModernInfo[g_clcPainter.GetBasicFontID(contact)].fontHeight;
				if (dat->text_replace_smileys && dat->first_line_draw_smileys && !dat->text_resize_smileys)
					pCell->h = max(pCell->h, contact->ssText.iMaxSmileyHeight);
				if (item == -1) {
					// calculate text width here
					SIZE size = { 0 };
					RECT dummyRect = { 0, 0, 1024, pCell->h };
					HDC hdc = CreateCompatibleDC(nullptr);
					g_clcPainter.ChangeToFont(hdc, dat, g_clcPainter.GetBasicFontID(contact), nullptr);
					g_clcPainter.GetTextSize(&size, hdc, dummyRect, contact->szText, contact->ssText.plText, 0, dat->text_resize_smileys ? 0 : contact->ssText.iMaxSmileyHeight);
					if (contact->type == CLCIT_GROUP) {
						wchar_t *szCounts = Clist_GetGroupCountsText(dat, contact);
						if (szCounts && mir_wstrlen(szCounts) > 0) {
							RECT count_rc = { 0 };
							// calc width and height
							g_clcPainter.ChangeToFont(hdc, dat, contact->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, nullptr);
							ske_DrawText(hdc, L" ", 1, &count_rc, DT_CALCRECT | DT_NOPREFIX);
							size.cx += count_rc.right - count_rc.left;
							count_rc.right = 0;
							count_rc.left = 0;
							ske_DrawText(hdc, szCounts, (int)mir_wstrlen(szCounts), &count_rc, DT_CALCRECT);
							size.cx += count_rc.right - count_rc.left;
							pCell->h = max(pCell->h, count_rc.bottom - count_rc.top);
						}
					}
					pCell->w = size.cx;
					SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
					ske_ResetTextEffect(hdc);
					DeleteDC(hdc);
				}
				break;

			case TC_TEXT2:
				if (dat->secondLine.show && pdnce->szSecondLineText && pdnce->szSecondLineText[0]) {
					pCell->h = dat->fontModernInfo[FONTID_SECONDLINE].fontHeight;
					if (dat->text_replace_smileys && dat->secondLine.draw_smileys && !dat->text_resize_smileys)
						pCell->h = max(pCell->h, pdnce->ssSecondLine.iMaxSmileyHeight);
					if (item == -1) {
						// calculate text width here
						SIZE size = { 0 };
						RECT dummyRect = { 0, 0, 1024, pCell->h };
						HDC hdc = CreateCompatibleDC(nullptr);
						g_clcPainter.ChangeToFont(hdc, dat, FONTID_SECONDLINE, nullptr);
						g_clcPainter.GetTextSize(&size, hdc, dummyRect, pdnce->szSecondLineText, pdnce->ssSecondLine.plText, 0, dat->text_resize_smileys ? 0 : pdnce->ssSecondLine.iMaxSmileyHeight);
						pCell->w = size.cx;
						SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
						ske_ResetTextEffect(hdc);
						DeleteDC(hdc);
					}
				}
				break;

			case TC_TEXT3:
				if (dat->thirdLine.show && pdnce->szThirdLineText && pdnce->szThirdLineText[0]) {
					pCell->h = dat->fontModernInfo[FONTID_THIRDLINE].fontHeight;
					if (dat->text_replace_smileys && dat->thirdLine.draw_smileys && !dat->text_resize_smileys)
						pCell->h = max(pCell->h, pdnce->ssThirdLine.iMaxSmileyHeight);
					if (item == -1) {
						//calculate text width here
						SIZE size = { 0 };
						RECT dummyRect = { 0, 0, 1024, pCell->h };
						HDC hdc = CreateCompatibleDC(nullptr);
						g_clcPainter.ChangeToFont(hdc, dat, FONTID_THIRDLINE, nullptr);
						g_clcPainter.GetTextSize(&size, hdc, dummyRect, pdnce->szThirdLineText, pdnce->ssThirdLine.plText, 0, dat->text_resize_smileys ? 0 : pdnce->ssThirdLine.iMaxSmileyHeight);
						pCell->w = size.cx;
						SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
						ske_ResetTextEffect(hdc);
						DeleteDC(hdc);
					}
				}
				break;

			case TC_STATUS:
				if ((contact->type == CLCIT_GROUP && !dat->row_hide_group_icon) ||
					(contact->type == CLCIT_CONTACT && contact->iImage != -1 &&
					!(dat->icon_hide_on_avatar && dat->avatars_show && (hasAvatar || (!hasAvatar && dat->icon_draw_on_avatar_space && contact->iImage != -1)) && !contact->bImageIsSpecial))) {
					pCell->h = ICON_HEIGHT;
					pCell->w = ICON_HEIGHT;
				}
				break;

			case TC_AVATAR:
				if (dat->avatars_show &&
					contact->type == CLCIT_CONTACT &&
					(hasAvatar || (dat->icon_hide_on_avatar && dat->icon_draw_on_avatar_space && contact->iImage != -1))) {
					int iW = 0, iH = 0;
					if (contact->avatar_data) {
						iH = contact->avatar_data->bmHeight;
						iW = contact->avatar_data->bmWidth;
					}

					SIZE sz = GetAvatarSize(iW, iH, dat->avatars_maxwidth_size, dat->avatars_maxheight_size);
					if ((sz.cx == 0 || sz.cy == 0) && dat->icon_hide_on_avatar && dat->icon_draw_on_avatar_space && contact->iImage != -1)
						sz.cx = ICON_HEIGHT, sz.cy = ICON_HEIGHT;

					pCell->h = sz.cy;
					pCell->w = sz.cx;
				}
				break;

			case TC_EXTRA: // Draw extra icons
				if (contact->type == CLCIT_CONTACT &&
					(!contact->iSubNumber || db_get_b(0, "CLC", "MetaHideExtra", SETTING_METAHIDEEXTRA_DEFAULT) == 0 && dat->extraColumnsCount > 0)) {
					bool hasExtra = false;
					int width = 0;
					for (int k = 0; k < dat->extraColumnsCount; k++)
						if (contact->iExtraImage[k] != EMPTY_EXTRA_ICON || !dat->bMetaIgnoreEmptyExtra) {
							hasExtra = true;
							if (item != -1) break;
							width += (width > 0) ? dat->extraColumnSpacing : (dat->extraColumnSpacing - 2);
						}
					if (hasExtra) {
						pCell->h = ICON_HEIGHT;
						pCell->w = width;
					}
				}
				break;

			case TC_EXTRA1:
			case TC_EXTRA2:
			case TC_EXTRA3:
			case TC_EXTRA4:
			case TC_EXTRA5:
			case TC_EXTRA6:
			case TC_EXTRA7:
			case TC_EXTRA8:
			case TC_EXTRA9:
				if (contact->type == CLCIT_CONTACT &&
					(!contact->iSubNumber || db_get_b(0, "CLC", "MetaHideExtra", SETTING_METAHIDEEXTRA_DEFAULT) == 0 && dat->extraColumnsCount > 0)) {
					int eNum = pCell->type - TC_EXTRA1;
					if (eNum < dat->extraColumnsCount)
						if (contact->iExtraImage[eNum] != EMPTY_EXTRA_ICON || !dat->bMetaIgnoreEmptyExtra) {
							pCell->h = ICON_HEIGHT;
							pCell->w = ICON_HEIGHT;
						}
				}
				break;

			case TC_TIME:
				if (contact->type == CLCIT_CONTACT && dat->contact_time_show && pdnce->hTimeZone) {
					pCell->h = dat->fontModernInfo[FONTID_CONTACT_TIME].fontHeight;
					if (item == -1) {
						wchar_t szResult[80];

						if (!TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", szResult, _countof(szResult), 0)) {
							SIZE text_size = { 0 };
							RECT rc = { 0 };
							// Select font
							HDC hdc = CreateCompatibleDC(nullptr);
							g_clcPainter.ChangeToFont(hdc, dat, FONTID_CONTACT_TIME, nullptr);

							// Get text size
							text_size.cy = ske_DrawText(hdc, szResult, (int)mir_wstrlen(szResult), &rc, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
							SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
							ske_ResetTextEffect(hdc);
							DeleteDC(hdc);
							text_size.cx = rc.right - rc.left;
							pCell->w = text_size.cx;
						}
					}
				}
				break;
			}
		}
	}

	int height = cppCalculateRowHeight(gl_RowRoot);
	height += dat->row_border * 2;
	height = max(height, dat->row_min_heigh);
	if (item != -1)
		dat->row_heights[item] = height;
	return height;
}
Пример #4
0
static void PaintWorker(TBBUTTONDATA *bct, HDC hdcPaint, POINT *pOffset)
{
	if (!hdcPaint)
		return;  //early exit

	POINT offset;
	if (pOffset)
		offset = *pOffset;
	else
		offset.x = offset.y = 0;

	RECT rcClient;
	GetClientRect(bct->hwnd, &rcClient);
	int width = rcClient.right - rcClient.left;
	int height = rcClient.bottom - rcClient.top;

	HBITMAP hbmMem = NULL;
	HBITMAP hbmOld = NULL;
	HDC hdcMem = pOffset ? hdcPaint : CreateCompatibleDC(hdcPaint);
	HFONT hOldFont = (HFONT)SelectObject(hdcMem, bct->hFont);
	if (!pOffset) {
		hbmMem = ske_CreateDIB32(width, height);
		hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
	}
	else OffsetRect(&rcClient, offset.x, offset.y);

	if (!g_CluiData.fDisableSkinEngine) {
		char szRequest[128];
		/* painting */
		mir_snprintf(szRequest, "Button,ID=%s,Hovered=%s,Pressed=%s,Focused=%s",
			bct->szButtonID,				// ID		
			b2str(bct->stateId == PBS_HOT),	// Hovered
			b2str(bct->stateId == PBS_PRESSED || bct->bIsPushed == TRUE),	// Pressed
			b2str(bct->bFocused));		// Focused

		SkinDrawGlyph(hdcMem, &rcClient, &rcClient, szRequest);
	}
	else if (xpt_IsThemed(bct->hThemeToolbar)) {
		RECT *rc = &rcClient;
		int state = IsWindowEnabled(bct->hwnd) ? /*(bct->stateId == PBS_PRESSED || bct->bIsPushed == TRUE) ? PBS_PRESSED :*/ (bct->stateId == PBS_NORMAL && bct->bIsDefault ? PBS_DEFAULTED : bct->stateId) : PBS_DISABLED;
		xpt_DrawTheme(bct->hThemeToolbar, bct->hwnd, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), rc, rc);
	}
	else {
		HBRUSH hbr = NULL;

		if (bct->stateId == PBS_PRESSED || bct->stateId == PBS_HOT)
			hbr = GetSysColorBrush(COLOR_3DLIGHT);
		else {
			RECT btnRect;
			POINT pt = { 0 };
			int ret;
			HWND hwndParent = GetParent(bct->hwnd);
			HDC dc = CreateCompatibleDC(NULL);
			HBITMAP memBM, oldBM;
			GetWindowRect(hwndParent, &btnRect);
			memBM = ske_CreateDIB32(btnRect.right - btnRect.left, btnRect.bottom - btnRect.top);
			oldBM = (HBITMAP)SelectObject(dc, memBM);
			ret = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM)dc, 0);
			GetWindowRect(bct->hwnd, &btnRect);
			ClientToScreen(hwndParent, &pt);
			OffsetRect(&btnRect, -pt.x, -pt.y);
			if (ret)
				BitBlt(hdcMem, 0, 0, btnRect.right - btnRect.left, btnRect.bottom - btnRect.top, dc, btnRect.left, btnRect.top, SRCCOPY);
			oldBM = (HBITMAP)SelectObject(dc, oldBM);
			DeleteObject(memBM);
			DeleteDC(dc);
			if (!ret) { //WM_ERASEBKG return false need to paint
				HDC pdc = GetDC(hwndParent);
				HBRUSH oldBrush = (HBRUSH)GetCurrentObject(pdc, OBJ_BRUSH);
				hbr = (HBRUSH)SendMessage(hwndParent, WM_CTLCOLORDLG, (WPARAM)pdc, (LPARAM)hwndParent);
				SelectObject(pdc, oldBrush);
				ReleaseDC(hwndParent, pdc);
			}
		}
		if (hbr) {
			FillRect(hdcMem, &rcClient, hbr);
			DeleteObject(hbr);
		}
		if (bct->stateId == PBS_HOT || bct->bFocused) {
			if (bct->bIsPushed)
				DrawEdge(hdcMem, &rcClient, EDGE_ETCHED, BF_RECT | BF_SOFT);
			else
				DrawEdge(hdcMem, &rcClient, BDR_RAISEDOUTER, BF_RECT | BF_SOFT | BF_FLAT);
		}
		else if (bct->stateId == PBS_PRESSED)
			DrawEdge(hdcMem, &rcClient, BDR_SUNKENOUTER, BF_RECT | BF_SOFT);
	}

	RECT  rcTemp = rcClient;  //content rect
	bool  bPressed = (bct->stateId == PBS_PRESSED || bct->bIsPushed == TRUE);
	bool  bHasText = (bct->szText[0] != '\0');

	/* formatter */
	if (!g_CluiData.fDisableSkinEngine) {
		/* correct rect according to rcMargins */

		rcTemp.left += bct->rcMargins.left;
		rcTemp.top += bct->rcMargins.top;
		rcTemp.bottom -= bct->rcMargins.bottom;
		rcTemp.right -= bct->rcMargins.right;
	}

	/* reposition button items */
	RECT rcIcon = rcTemp, rcText = rcTemp;
	if (bct->hIcon) {
		if (bHasText) {
			rcIcon.right = rcIcon.left + 16; /* CXSM_ICON */
			rcText.left = rcIcon.right + 2;
		}
		else {
			rcIcon.left += (rcIcon.right - rcIcon.left) / 2 - 8;
			rcIcon.right = rcIcon.left + 16;
		}
	}

	/*	Check sizes*/
	if (bct->hIcon && (rcIcon.right > rcTemp.right || rcIcon.bottom > rcTemp.bottom || rcIcon.left < rcTemp.left || rcIcon.top < rcTemp.top))
		bct->hIcon = NULL;

	if (bHasText && (rcText.right > rcTemp.right || rcText.bottom > rcTemp.bottom || rcText.left < rcTemp.left || rcText.top < rcTemp.top))
		bHasText = FALSE;

	if (bct->hIcon) {
		/* center icon vertically */
		rcIcon.top += (rcClient.bottom - rcClient.top) / 2 - 8; /* CYSM_ICON/2 */
		rcIcon.bottom = rcIcon.top + 16; /* CYSM_ICON */
		/* draw it */
		ske_DrawIconEx(hdcMem, rcIcon.left + bPressed, rcIcon.top + bPressed, bct->hIcon, 16, 16, 0, NULL, DI_NORMAL);
	}

	if (bHasText) {
		BOOL bCentered = TRUE;
		SetBkMode(hdcMem, TRANSPARENT);
		if (bct->nFontID >= 0)
			g_clcPainter.ChangeToFont(hdcMem, NULL, bct->nFontID, NULL);

		RECT TextRequiredRect = rcText;
		ske_DrawText(hdcMem, bct->szText, -1, &TextRequiredRect, DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_SINGLELINE);
		if (TextRequiredRect.right - TextRequiredRect.left > rcText.right - rcText.left)
			bCentered = FALSE;

		ske_DrawText(hdcMem, bct->szText, -1, &rcText, (bCentered ? DT_CENTER : 0) | DT_VCENTER | DT_SINGLELINE);
		ske_ResetTextEffect(hdcMem);
	}
	if (!pOffset)
		BitBlt(hdcPaint, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);

	// better to use try/finally but looks like last one is Microsoft specific
	SelectObject(hdcMem, hOldFont);
	if (!pOffset) {
		SelectObject(hdcMem, hbmOld);
		DeleteObject(hbmMem);
		DeleteDC(hdcMem);
	}
}
Пример #5
0
int ModernDrawStatusBarWorker(HWND hWnd, HDC hDC)
{
	int iconHeight = GetSystemMetrics(SM_CYSMICON)+2;
	int i;

	// Count visible protos
	RECT rc;
	GetClientRect(hWnd, &rc);
	if (g_CluiData.fDisableSkinEngine) {
		if (g_StatusBarData.bkUseWinColors && xpt_IsThemed(g_StatusBarData.hTheme))
			xpt_DrawTheme(g_StatusBarData.hTheme, hWnd, hDC, 0, 0, &rc, &rc);
		else
			DrawBackGround(hWnd, hDC, g_StatusBarData.hBmpBackground, g_StatusBarData.bkColour, g_StatusBarData.backgroundBmpUse);
	}
	else SkinDrawGlyph(hDC, &rc, &rc, "Main,ID=StatusBar"); //TBD

	g_StatusBarData.nProtosPerLine = db_get_b(NULL, "CLUI", "StatusBarProtosPerLine", SETTING_PROTOSPERLINE_DEFAULT);
	HFONT hOldFont = g_clcPainter.ChangeToFont(hDC, NULL, FONTID_STATUSBAR_PROTONAME, NULL);

	SIZE textSize = { 0 };
	GetTextExtentPoint32A(hDC, " ", 1, &textSize);
	int spaceWidth = textSize.cx;
	int textY = rc.top + ((rc.bottom - rc.top - textSize.cy) >> 1);
	int iconY = rc.top + ((rc.bottom - rc.top - GetSystemMetrics(SM_CXSMICON)) >> 1);

	ProtosData.destroy();

	int protoCount;
	PROTOACCOUNT **accs;
	ProtoEnumAccounts(&protoCount, &accs);
	if (protoCount == 0)
		return 0;

	int iProtoInStatusMenu = 0;
	for (int j = 0; j < protoCount; j++) {
		int i = pcli->pfnGetAccountIndexByPos(j);
		if (i == -1)
			continue;

		char *szProto = accs[i]->szModuleName;
		if (!pcli->pfnGetProtocolVisibility(szProto))
			continue;

		char buf[256];
		mir_snprintf(buf, SIZEOF(buf), "SBarAccountIsCustom_%s", szProto);

		ProtoItemData *p = NULL;

		if (g_StatusBarData.perProtoConfig && db_get_b(NULL, "CLUI", buf, SETTING_SBARACCOUNTISCUSTOM_DEFAULT)) {
			mir_snprintf(buf, SIZEOF(buf), "HideAccount_%s", szProto);
			if (db_get_b(NULL, "CLUI", buf, SETTING_SBARHIDEACCOUNT_DEFAULT)) {
				iProtoInStatusMenu++;
				continue;
			}

			mir_snprintf(buf, SIZEOF(buf), "SBarShow_%s", szProto);

			BYTE showOps = db_get_b(NULL, "CLUI", buf, SETTING_SBARSHOW_DEFAULT);
			p = new ProtoItemData;
			p->bShowProtoIcon = (showOps & 1) != 0;
			p->bShowProtoName = (showOps & 2) != 0;
			p->bShowStatusName = (showOps & 4) != 0;

			mir_snprintf(buf, SIZEOF(buf), "ShowXStatus_%s", szProto);
			p->xStatusMode = db_get_b(NULL, "CLUI", buf, SETTING_SBARSHOW_DEFAULT);

			mir_snprintf(buf, SIZEOF(buf), "UseConnectingIcon_%s", szProto);
			p->bConnectingIcon = db_get_b(NULL, "CLUI", buf, SETTING_USECONNECTINGICON_DEFAULT) != 0;

			mir_snprintf(buf, SIZEOF(buf), "ShowUnreadEmails_%s", szProto);
			p->bShowProtoEmails = db_get_b(NULL, "CLUI", buf, SETTING_SHOWUNREADEMAILS_DEFAULT) != 0;

			mir_snprintf(buf, SIZEOF(buf), "SBarRightClk_%s", szProto);
			p->SBarRightClk = db_get_b(NULL, "CLUI", buf, SETTING_SBARRIGHTCLK_DEFAULT) != 0;

			mir_snprintf(buf, SIZEOF(buf), "PaddingLeft_%s", szProto);
			p->PaddingLeft = db_get_dw(NULL, "CLUI", buf, SETTING_PADDINGLEFT_DEFAULT);

			mir_snprintf(buf, SIZEOF(buf), "PaddingRight_%s", szProto);
			p->PaddingRight = db_get_dw(NULL, "CLUI", buf, SETTING_PADDINGRIGHT_DEFAULT);
		}
		else {
			p = new ProtoItemData;
			p->bShowProtoIcon = g_StatusBarData.bShowProtoIcon;
			p->bShowProtoName = g_StatusBarData.bShowProtoName;
			p->bShowStatusName = g_StatusBarData.bShowStatusName;
			p->xStatusMode = g_StatusBarData.xStatusMode;
			p->bConnectingIcon = g_StatusBarData.bConnectingIcon;
			p->bShowProtoEmails = g_StatusBarData.bShowProtoEmails;
			p->SBarRightClk = 0;
			p->PaddingLeft = 0;
			p->PaddingRight = 0;
		}

		p->iProtoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);

		if (p->iProtoStatus > ID_STATUS_OFFLINE)
			if (p->bShowProtoEmails == 1 && ProtoServiceExists(szProto, PS_GETUNREADEMAILCOUNT)) {
				int nEmails = (int)ProtoCallService(szProto, PS_GETUNREADEMAILCOUNT, 0, 0);
				if (nEmails > 0) {
					char buf[40];
					mir_snprintf(buf, SIZEOF(buf), "[%d]", nEmails);
					p->szProtoEMailCount = mir_strdup(buf);
				}
			}

		p->tszProtoHumanName = mir_tstrdup(accs[i]->tszAccountName);
		p->szAccountName = mir_strdup(szProto);
		p->szProtoName = mir_strdup(accs[i]->szProtoName);
		p->tszProtoStatusText = mir_tstrdup(pcli->pfnGetStatusModeDescription(p->iProtoStatus, 0));
		p->iProtoPos = iProtoInStatusMenu++;

		p->bIsDimmed = 0;
		if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) {
			char szTemp[2048];
			mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", p->szAccountName);
			p->bIsDimmed = strstr(g_CluiData.protoFilter, szTemp) ? 0 : 1;
		}

		ProtosData.insert(p);
	}

	if (ProtosData.getCount() == 0)
		return 0;

	//START MULTILINE HERE 
	int orig_protoCount = protoCount;
	int orig_visProtoCount = ProtosData.getCount();
	int protosperline = 0;

	if (g_StatusBarData.nProtosPerLine)
		protosperline = g_StatusBarData.nProtosPerLine;
	else if (orig_visProtoCount)
		protosperline = orig_visProtoCount;
	else if (protoCount) {
		protosperline = protoCount;
		orig_visProtoCount = protoCount;
	}
	else {
		protosperline = 1;
		orig_visProtoCount = 1;
	}
	protosperline = min(protosperline, orig_visProtoCount);

	int linecount = protosperline ? (orig_visProtoCount + (protosperline - 1)) / protosperline : 1; //divide with rounding to up
	for (int line = 0; line < linecount; line++) {
		int rowheight = max(textSize.cy + 2, iconHeight);
		protoCount = min(protosperline, (orig_protoCount - line*protosperline));
		int visProtoCount = min(protosperline, (orig_visProtoCount - line*protosperline));
		GetClientRect(hWnd, &rc);

		rc.top += g_StatusBarData.rectBorders.top;
		rc.bottom -= g_StatusBarData.rectBorders.bottom;

		int aligndx = 0, maxwidth = 0, xstatus = 0, SumWidth = 0;

		int height = (rowheight*linecount);
		if (height > (rc.bottom - rc.top)) {
			rowheight = (rc.bottom - rc.top) / linecount;
			height = (rowheight*linecount);
		}

		int rowsdy = ((rc.bottom - rc.top) - height) / 2;
		if (rowheight*(line)+rowsdy < rc.top - rowheight) continue;
		if (rowheight*(line + 1) + rowsdy>rc.bottom + rowheight)
			break;

		if (g_StatusBarData.VAlign == 0) { //top
			rc.bottom = rc.top + rowheight*(line + 1);
			rc.top = rc.top + rowheight*line + 1;
		}
		else if (g_StatusBarData.VAlign == 1) { //center
			rc.bottom = rc.top + rowsdy + rowheight*(line + 1);
			rc.top = rc.top + rowsdy + rowheight*line + 1;
		}
		else if (g_StatusBarData.VAlign == 2) { //bottom
			rc.top = rc.bottom - (rowheight*(linecount - line));
			rc.bottom = rc.bottom - (rowheight*(linecount - line - 1) + 1);
		}

		textY = rc.top + (((rc.bottom - rc.top) - textSize.cy) / 2);
		iconY = rc.top + (((rc.bottom - rc.top) - iconHeight) / 2);

		//Code for each line
		DWORD sw;
		int rectwidth = rc.right - rc.left - g_StatusBarData.rectBorders.left - g_StatusBarData.rectBorders.right;
		if (visProtoCount > 1)
			sw = (rectwidth - (g_StatusBarData.extraspace*(visProtoCount - 1))) / visProtoCount;
		else
			sw = rectwidth;

		int *ProtoWidth = (int*)mir_alloc(sizeof(int)*visProtoCount);
		for (i = 0; i < visProtoCount; i++) {
			ProtoItemData &p = ProtosData[line*protosperline + i];

			DWORD w = p.PaddingLeft;
			w += p.PaddingRight;

			if (p.bShowProtoIcon) {
				w += GetSystemMetrics(SM_CXSMICON) + 1;

				p.extraIcon = NULL;
				if ((p.xStatusMode & 8) && p.iProtoStatus > ID_STATUS_OFFLINE) {
					TCHAR str[512];
					CUSTOM_STATUS cs = { sizeof(cs) };
					cs.flags = CSSF_MASK_NAME | CSSF_TCHAR;
					cs.ptszName = str;
					if (CallProtoService(p.szAccountName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) == 0)
						p.tszProtoXStatus = mir_tstrdup(str);
				}

				if ((p.xStatusMode & 3)) {
					if (p.iProtoStatus > ID_STATUS_OFFLINE) {
						if (ProtoServiceExists(p.szAccountName, PS_GETCUSTOMSTATUSICON))
							p.extraIcon = (HICON)ProtoCallService(p.szAccountName, PS_GETCUSTOMSTATUSICON, 0, 0);
						if (p.extraIcon && (p.xStatusMode & 3) == 3)
							w += GetSystemMetrics(SM_CXSMICON) + 1;
					}
				}
			}

			SIZE textSize;
			if (p.bShowProtoName) {
				GetTextExtentPoint32(hDC, p.tszProtoHumanName, lstrlen(p.tszProtoHumanName), &textSize);
				w += textSize.cx + 3 + spaceWidth;
			}

			if (p.bShowProtoEmails && p.szProtoEMailCount) {
				GetTextExtentPoint32A(hDC, p.szProtoEMailCount, lstrlenA(p.szProtoEMailCount), &textSize);
				w += textSize.cx + 3 + spaceWidth;
			}

			if (p.bShowStatusName) {
				GetTextExtentPoint32(hDC, p.tszProtoStatusText, lstrlen(p.tszProtoStatusText), &textSize);
				w += textSize.cx + 3 + spaceWidth;
			}

			if ((p.xStatusMode & 8) && p.tszProtoXStatus) {
				GetTextExtentPoint32(hDC, p.tszProtoXStatus, lstrlen(p.tszProtoXStatus), &textSize);
				w += textSize.cx + 3 + spaceWidth;
			}

			if (p.bShowProtoName || (p.bShowProtoEmails && p.szProtoEMailCount) || p.bShowStatusName || ((p.xStatusMode & 8) && p.tszProtoXStatus))
				w -= spaceWidth;

			p.fullWidth = w;
			if (g_StatusBarData.sameWidth) {
				ProtoWidth[i] = sw;
				SumWidth += w;
			}
			else {
				ProtoWidth[i] = w;
				SumWidth += w;
			}
		}

		// Reposition rects
		for (i = 0; i < visProtoCount; i++)
			if (ProtoWidth[i] > maxwidth)
				maxwidth = ProtoWidth[i];

		if (g_StatusBarData.sameWidth) {
			for (i = 0; i < visProtoCount; i++)
				ProtoWidth[i] = maxwidth;
			SumWidth = maxwidth * visProtoCount;
		}
		SumWidth += (visProtoCount - 1) * (g_StatusBarData.extraspace + 1);

		if (SumWidth > rectwidth) {
			float f = (float)rectwidth / SumWidth;
			SumWidth = 0;
			for (i = 0; i < visProtoCount; i++) {
				ProtoWidth[i] = (int)((float)ProtoWidth[i] * f);
				SumWidth += ProtoWidth[i];
			}
			SumWidth += (visProtoCount - 1)*(g_StatusBarData.extraspace + 1);
		}

		if (g_StatusBarData.Align == 1) //center
			aligndx = (rectwidth - SumWidth) >> 1;
		else if (g_StatusBarData.Align == 2) //right
			aligndx = (rectwidth - SumWidth);

		// Draw in rects
		RECT r = rc;
		r.left += g_StatusBarData.rectBorders.left + aligndx;
		for (i = 0; i < visProtoCount; i++) {
			ProtoItemData& p = ProtosData[line*protosperline + i];
			HRGN rgn;
			HICON hIcon = NULL;
			HICON hxIcon = NULL;
			BOOL NeedDestroy = FALSE;
			int x = r.left;
			x += p.PaddingLeft;
			r.right = r.left + ProtoWidth[i];

			if (p.bShowProtoIcon) {
				if (p.iProtoStatus > ID_STATUS_OFFLINE && (p.xStatusMode & 3) > 0) {
					if (ProtoServiceExists(p.szAccountName, PS_GETCUSTOMSTATUSICON)) {
						hxIcon = p.extraIcon;
						if (hxIcon) {
							if ((p.xStatusMode & 3) == 2) {
								hIcon = GetMainStatusOverlay(p.iProtoStatus);
								NeedDestroy = TRUE;
							}
							else if ((p.xStatusMode & 3) == 1) {
								hIcon = hxIcon;
								NeedDestroy = TRUE;
								hxIcon = NULL;
							}
						}
					}
				}

				if (hIcon == NULL && (hxIcon == NULL || ((p.xStatusMode & 3) == 3))) {
					if ((p.bConnectingIcon == 1) && p.iProtoStatus >= ID_STATUS_CONNECTING && p.iProtoStatus <= ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES) {
						hIcon = (HICON)CLUI_GetConnectingIconService((WPARAM)p.szAccountName, 0);
						if (hIcon)
							NeedDestroy = TRUE;
						else
							hIcon = LoadSkinnedProtoIcon(p.szAccountName, p.iProtoStatus);
					}
					else hIcon = LoadSkinnedProtoIcon(p.szAccountName, p.iProtoStatus);
				}

				rgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);

				if (g_StatusBarData.sameWidth) {
					int fw = p.fullWidth;
					int rw = r.right - r.left;
					if (g_StatusBarData.Align == 1)
						x = r.left + ((rw - fw) / 2);
					else if (g_StatusBarData.Align == 2)
						x = r.left + ((rw - fw));
					else
						x = r.left;
				}

				SelectClipRgn(hDC, rgn);
				p.bDoubleIcons = false;

				DWORD dim = p.bIsDimmed ? ((64 << 24) | 0x80) : 0;

				if ((p.xStatusMode & 3) == 3) {
					if (hIcon)
						mod_DrawIconEx_helper(hDC, x, iconY, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | dim);
					if (hxIcon) {
						mod_DrawIconEx_helper(hDC, x + GetSystemMetrics(SM_CXSMICON) + 1, iconY, hxIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | dim);
						x += GetSystemMetrics(SM_CXSMICON) + 1;
					}
					p.bDoubleIcons = hIcon && hxIcon;
				}
				else {
					if (hxIcon)
						mod_DrawIconEx_helper(hDC, x, iconY, hxIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | dim);
					if (hIcon)
						mod_DrawIconEx_helper(hDC, x, iconY, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | ((hxIcon && (p.xStatusMode & 4)) ? (192 << 24) : 0) | dim);
				}

				if (hxIcon || hIcon) { /* TODO g_StatusBarData.bDrawLockOverlay  options to draw locked proto*/
					if (db_get_b(NULL, p.szAccountName, "LockMainStatus", 0)) {
						HICON hLockOverlay = LoadSkinnedIcon(SKINICON_OTHER_STATUS_LOCKED);
						if (hLockOverlay != NULL) {
							mod_DrawIconEx_helper(hDC, x, iconY, hLockOverlay, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | dim);
							Skin_ReleaseIcon(hLockOverlay);
						}
					}
				}
				if (hxIcon) DestroyIcon_protect(hxIcon);
				if (NeedDestroy) DestroyIcon_protect(hIcon);
				else Skin_ReleaseIcon(hIcon);
				x += GetSystemMetrics(SM_CXSMICON) + 1;
			}

			if (p.bShowProtoName) {
				SIZE textSize;
				RECT rt = r;
				rt.left = x + (spaceWidth >> 1);
				rt.top = textY;
				ske_DrawText(hDC, p.tszProtoHumanName, lstrlen(p.tszProtoHumanName), &rt, 0);

				if ((p.bShowProtoEmails && p.szProtoEMailCount != NULL) || p.bShowStatusName || ((p.xStatusMode & 8) && p.tszProtoXStatus)) {
					GetTextExtentPoint32(hDC, p.tszProtoHumanName, lstrlen(p.tszProtoHumanName), &textSize);
					x += textSize.cx + 3;
				}
			}

			if (p.bShowProtoEmails && p.szProtoEMailCount != NULL) {
				SIZE textSize;
				RECT rt = r;
				rt.left = x + (spaceWidth >> 1);
				rt.top = textY;
				ske_DrawTextA(hDC, p.szProtoEMailCount, lstrlenA(p.szProtoEMailCount), &rt, 0);
				if (p.bShowStatusName || ((p.xStatusMode & 8) && p.tszProtoXStatus)) {
					GetTextExtentPoint32A(hDC, p.szProtoEMailCount, lstrlenA(p.szProtoEMailCount), &textSize);
					x += textSize.cx + 3;
				}
			}