diff options
author | Tobias Weimer <wishmaster51@googlemail.com> | 2015-07-12 14:10:16 +0000 |
---|---|---|
committer | Tobias Weimer <wishmaster51@googlemail.com> | 2015-07-12 14:10:16 +0000 |
commit | f4ce2b5c214cce406dbd7a73dc7f35ae409546ad (patch) | |
tree | 533cc821ffc9c5664c075930be6a40fde9593aba /plugins/Clist_ng/SRC | |
parent | 71a88c6d8c4578ca24e02a5c6f4860c206e7c6da (diff) |
Clist NG:
Commit of CList NG by silvercircle from https://github.com/silvercircle/miranda-ng
This is based on clist_nicer and Anti-Grain Geometry: http://www.antigrain.com/
This is the first version that actually compiles.
Do NOT use it in production environment!
git-svn-id: http://svn.miranda-ng.org/main/trunk@14543 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Clist_ng/SRC')
28 files changed, 17617 insertions, 0 deletions
diff --git a/plugins/Clist_ng/SRC/CLCButton.cpp b/plugins/Clist_ng/SRC/CLCButton.cpp new file mode 100644 index 0000000000..e470b58e19 --- /dev/null +++ b/plugins/Clist_ng/SRC/CLCButton.cpp @@ -0,0 +1,705 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: CLCButton.cpp 135 2010-10-06 13:13:51Z silvercircle $
+ *
+ * skinable button control for clist NG. Based on the original MButtonCtrl
+ * for Miranda by Robert Rainwater
+ *
+ */
+
+#include <commonheaders.h>
+
+static LRESULT CALLBACK TSButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+struct MButtonCtrl {
+ HWND hwnd;
+ int stateId; // button state
+ int focus; // has focus (1 or 0)
+ HFONT hFont; // font
+ HICON arrow; // uses down arrow
+ int defbutton; // default button
+ HICON hIcon, hIconPrivate;
+ HBITMAP hBitmap;
+ int pushBtn;
+ int pbState;
+ HANDLE hThemeButton;
+ HANDLE hThemeToolbar;
+ BOOL bThemed;
+ DWORD bSkinned;
+ char cHot;
+ int flatBtn;
+ wchar_t szText[128];
+ SIZE sLabel;
+ HIMAGELIST hIml;
+ int iIcon;
+ BOOL bSendOnDown;
+ TButtonItem *buttonItem;
+ LONG lastGlyphMetrics[4];
+};
+
+static HWND hwndToolTips = NULL;
+
+int LoadCLCButtonModule(void)
+{
+ WNDCLASSEXW wc = {0};
+
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = L"CLCButtonClass";
+ wc.lpfnWndProc = TSButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MButtonCtrl *);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+// Used for our own cheap TrackMouseEvent
+#define BUTTON_POLLID 100
+#define BUTTON_POLLDELAY 50
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+
+static void DestroyTheme(MButtonCtrl *ctl)
+{
+ if(Api::pfnCloseThemeData) {
+ if(ctl->hThemeButton) {
+ Api::pfnCloseThemeData(ctl->hThemeButton);
+ ctl->hThemeButton = 0;
+ }
+ if(ctl->hThemeToolbar) {
+ Api::pfnCloseThemeData(ctl->hThemeToolbar);
+ ctl->hThemeToolbar = 0;
+ }
+ ctl->bThemed = 0;
+ }
+}
+
+static void LoadTheme(MButtonCtrl *ctl)
+{
+ DestroyTheme(ctl);
+ if(IS_THEMED) {
+ ctl->hThemeButton = Api::pfnOpenThemeData(ctl->hwnd, L"BUTTON");
+ ctl->hThemeToolbar = Api::pfnOpenThemeData(ctl->hwnd, L"TOOLBAR");
+ ctl->bThemed = TRUE;
+ }
+}
+
+static int TBStateConvert2Flat(int state)
+{
+ switch(state) {
+ case PBS_NORMAL:
+ return TS_NORMAL;
+ case PBS_HOT:
+ return TS_HOT;
+ case PBS_PRESSED:
+ return TS_PRESSED;
+ case PBS_DISABLED:
+ return TS_DISABLED;
+ case PBS_DEFAULTED:
+ return TS_NORMAL;
+ }
+ return TS_NORMAL;
+}
+
+static void PaintWorker(MButtonCtrl *ctl, HDC hdcPaint)
+{
+ if(hdcPaint) {
+ HDC hdcMem;
+ RECT rcClient, rcBp;
+ HFONT hOldFont = 0;
+ int xOffset = 0;
+ HANDLE hbp = 0;
+ GetClientRect(ctl->hwnd, &rcClient);
+#ifndef _USE_D2D
+ rcBp = rcClient;
+ INIT_PAINT(hdcPaint, rcBp, hdcMem);
+#else
+ hdcMem = cfg::dat.hdcBg;
+ MapWindowPoints(ctl->hwnd, pcli->hwndContactList, reinterpret_cast<POINT *>(&rcClient), 2);
+#endif
+
+ hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, ctl->hFont));
+ // If its a push button, check to see if it should stay pressed
+ if(ctl->pushBtn && ctl->pbState)
+ ctl->stateId = PBS_PRESSED;
+
+ // Draw the flat button
+ if(ctl->flatBtn) {
+ if(ctl->hThemeToolbar && ctl->bThemed) {
+ RECT rc = rcClient;
+ int state = IsWindowEnabled(ctl->hwnd) ? (ctl->stateId == PBS_NORMAL && ctl->defbutton ? PBS_DEFAULTED : ctl->stateId) : PBS_DISABLED;
+ Gfx::drawBGFromSurface(ctl->hwnd, rc, hdcMem);
+ if(Api::pfnIsThemeBackgroundPartiallyTransparent(ctl->hThemeToolbar, TP_BUTTON, TBStateConvert2Flat(state))) {
+ Api::pfnDrawThemeParentBackground(ctl->hwnd, hdcMem, &rc);
+ }
+ Api::pfnDrawThemeBackground(ctl->hThemeToolbar, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), &rc, &rc);
+ } else {
+ HBRUSH hbr;
+ RECT rc = rcClient;
+
+ if(ctl->buttonItem) {
+ RECT rcParent;
+ POINT pt;
+ TImageItem *imgItem = ctl->stateId == PBS_HOT ? ctl->buttonItem->imgHover : (ctl->stateId == PBS_PRESSED ? ctl->buttonItem->imgPressed : ctl->buttonItem->imgNormal);
+ LONG *glyphMetrics = ctl->stateId == PBS_HOT ? ctl->buttonItem->hoverGlyphMetrics : (ctl->stateId == PBS_PRESSED ? ctl->buttonItem->pressedGlyphMetrics : ctl->buttonItem->normalGlyphMetrics);
+#ifndef _USE_D2D
+ GetWindowRect(ctl->hwnd, &rcParent);
+ pt.x = rcParent.left;
+ pt.y = rcParent.top;
+ ScreenToClient(pcli->hwndContactList, &pt);
+ Gfx::drawBGFromSurface(ctl->hwnd, rc, hdcMem);
+#endif
+ if(imgItem)
+ Gfx::renderSkinItem(hdcMem, &rc, imgItem);
+ if(Skin::glyphItem) {
+ Api::pfnAlphaBlend(hdcMem, (rc.right - glyphMetrics[2]) / 2, (rc.bottom - glyphMetrics[3]) / 2,
+ glyphMetrics[2], glyphMetrics[3], Skin::glyphItem->hdc,
+ glyphMetrics[0], glyphMetrics[1], glyphMetrics[2],
+ glyphMetrics[3], Skin::glyphItem->bf);
+ }
+ } else if(ctl->bSkinned) { // skinned
+ RECT rcParent;
+ TStatusItem *item;
+ int item_id;
+
+ GetWindowRect(ctl->hwnd, &rcParent);
+
+ Gfx::drawBGFromSurface(ctl->hwnd, rc, hdcMem);
+ item_id = ctl->stateId == PBS_HOT ? ID_EXTBKBUTTONSMOUSEOVER : (ctl->stateId == PBS_PRESSED ? ID_EXTBKBUTTONSPRESSED : ID_EXTBKBUTTONSNPRESSED);
+ item = &Skin::statusItems[item_id];
+ Gfx::setTextColor(item->TEXTCOLOR);
+ if(item->IGNORED)
+ FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE));
+ else {
+ rc.top += item->MARGIN_TOP;
+ rc.bottom -= item->MARGIN_BOTTOM;
+ rc.left += item->MARGIN_LEFT;
+ rc.right -= item->MARGIN_RIGHT;
+ Gfx::renderSkinItem(hdcMem, &rc, item->imageItem);
+ }
+ } else {
+ if(ctl->stateId == PBS_PRESSED || ctl->stateId == PBS_HOT)
+ hbr = GetSysColorBrush(COLOR_3DFACE);
+ else {
+ HDC dc;
+ HWND hwndParent;
+
+ hwndParent = GetParent(ctl->hwnd);
+ dc = GetDC(hwndParent);
+ hbr = (HBRUSH) SendMessage(hwndParent, WM_CTLCOLORDLG, (WPARAM) dc, (LPARAM) hwndParent);
+ ReleaseDC(hwndParent, dc);
+ }
+ if(hbr) {
+ FillRect(hdcMem, &rc, hbr);
+ DeleteObject(hbr);
+ }
+ }
+ if(!ctl->bSkinned && ctl->buttonItem == 0) {
+ if(ctl->stateId == PBS_HOT || ctl->focus) {
+ if(ctl->pbState)
+ DrawEdge(hdcMem, &rc, EDGE_ETCHED, BF_RECT | BF_SOFT);
+ else
+ DrawEdge(hdcMem, &rc, BDR_RAISEDOUTER, BF_RECT | BF_SOFT);
+ } else if(ctl->stateId == PBS_PRESSED)
+ DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT | BF_SOFT);
+ }
+ }
+ } else {
+ // Draw background/border
+ if(ctl->hThemeButton && ctl->bThemed) {
+ int state = IsWindowEnabled(ctl->hwnd) ? (ctl->stateId == PBS_NORMAL && ctl->defbutton ? PBS_DEFAULTED : ctl->stateId) : PBS_DISABLED;
+ POINT pt;
+ RECT rcParent;
+
+ GetWindowRect(ctl->hwnd, &rcParent);
+ pt.x = rcParent.left;
+ pt.y = rcParent.top;
+ ScreenToClient(pcli->hwndContactList, &pt);
+ BitBlt(hdcMem, 0, 0, rcClient.right, rcClient.bottom, cfg::dat.hdcBg, pt.x, pt.y, SRCCOPY);
+
+ if(Api::pfnIsThemeBackgroundPartiallyTransparent(ctl->hThemeButton, BP_PUSHBUTTON, state)) {
+ Api::pfnDrawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ Api::pfnDrawThemeBackground(ctl->hThemeButton, hdcMem, BP_PUSHBUTTON, state, &rcClient, &rcClient);
+ } else {
+ UINT uState = DFCS_BUTTONPUSH | ((ctl->stateId == PBS_HOT) ? DFCS_HOT : 0) | ((ctl->stateId == PBS_PRESSED) ? DFCS_PUSHED : 0);
+ if(ctl->defbutton && ctl->stateId == PBS_NORMAL)
+ uState |= DLGC_DEFPUSHBUTTON;
+ DrawFrameControl(hdcMem, &rcClient, DFC_BUTTON, uState);
+ }
+
+ // Draw focus rectangle if button has focus
+ if(ctl->focus) {
+ RECT focusRect = rcClient;
+ InflateRect(&focusRect, -3, -3);
+ DrawFocusRect(hdcMem, &focusRect);
+ }
+ }
+
+ // If we have an icon or a bitmap, ignore text and only draw the image on the button
+ if(ctl->hIcon || ctl->hIconPrivate || ctl->iIcon) {
+ int ix = (rcClient.right - rcClient.left) / 2 - (CXSMICON / 2);
+ int iy = (rcClient.bottom - rcClient.top) / 2 - (CXSMICON / 2);
+ HICON hIconNew = ctl->hIconPrivate != 0 ? ctl->hIconPrivate : ctl->hIcon;
+ if(lstrlen(ctl->szText) == 0) {
+ if(ctl->iIcon)
+ ImageList_DrawEx(ctl->hIml, ctl->iIcon, hdcMem, ix, iy, CXSMICON, CYSMICON, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ else
+ DrawState(hdcMem, NULL, NULL, (LPARAM) hIconNew, 0, ix, iy, CXSMICON, CYSMICON, IsWindowEnabled(ctl->hwnd) ? DST_ICON | DSS_NORMAL : DST_ICON | DSS_DISABLED);
+ ctl->sLabel.cx = ctl->sLabel.cy = 0;
+ } else {
+ GetTextExtentPoint32(hdcMem, ctl->szText, lstrlen(ctl->szText), &ctl->sLabel);
+
+ if(CXSMICON + ctl->sLabel.cx + 8 > rcClient.right - rcClient.left)
+ ctl->sLabel.cx = (rcClient.right - rcClient.left) - CXSMICON - 8;
+ else
+ ctl->sLabel.cx += 4;
+
+ ix = (rcClient.right - rcClient.left) / 2 - ((CXSMICON + ctl->sLabel.cx) / 2);
+ if(ctl->iIcon)
+ ImageList_DrawEx(ctl->hIml, ctl->iIcon, hdcMem, ix, iy, CXSMICON, CYSMICON, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ else
+ DrawState(hdcMem, NULL, NULL, (LPARAM) hIconNew, 0, ix, iy, CXSMICON, CYSMICON, IsWindowEnabled(ctl->hwnd) ? DST_ICON | DSS_NORMAL : DST_ICON | DSS_DISABLED);
+ xOffset = ix + CXSMICON + 4;
+ }
+ } else if(ctl->hBitmap) {
+ BITMAP bminfo;
+ int ix, iy;
+
+ GetObject(ctl->hBitmap, sizeof(bminfo), &bminfo);
+ ix = (rcClient.right - rcClient.left) / 2 - (bminfo.bmWidth / 2);
+ iy = (rcClient.bottom - rcClient.top) / 2 - (bminfo.bmHeight / 2);
+ if(ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ DrawState(hdcMem, NULL, NULL, (LPARAM) ctl->hBitmap, 0, ix, iy, bminfo.bmWidth, bminfo.bmHeight, IsWindowEnabled(ctl->hwnd) ? DST_BITMAP : DST_BITMAP | DSS_DISABLED);
+ }
+ if(GetWindowTextLength(ctl->hwnd)) {
+ // Draw the text and optinally the arrow
+ RECT rcText;
+
+ CopyRect(&rcText, &rcClient);
+ SetBkMode(hdcMem, TRANSPARENT);
+ if(!ctl->bSkinned)
+ Gfx::setTextColor(IsWindowEnabled(ctl->hwnd) || !ctl->hThemeButton ? GetSysColor(COLOR_BTNTEXT) : GetSysColor(COLOR_GRAYTEXT));
+ if(ctl->arrow) {
+ DrawState(hdcMem, NULL, NULL, (LPARAM) ctl->arrow, 0, rcClient.right - rcClient.left - 5 - CXSMICON + (!ctl->hThemeButton && ctl->stateId == PBS_PRESSED ? 1 : 0), (rcClient.bottom - rcClient.top) / 2 - CYSMICON / 2 + (!ctl->hThemeButton && ctl->stateId == PBS_PRESSED ? 1 : 0), CXSMICON, CYSMICON, IsWindowEnabled(ctl->hwnd) ? DST_ICON : DST_ICON | DSS_DISABLED);
+ rcText.left += (4 + CXSMICON);
+ }
+ if(xOffset)
+ rcText.left += (4 + CXSMICON);
+ Gfx::renderText(hdcMem, ctl->hThemeButton, ctl->szText, &rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE, 0);
+ }
+ if(hOldFont)
+ SelectObject(hdcMem, hOldFont);
+#ifndef _USE_D2D
+ FINALIZE_PAINT(hbp, &rcBp, 0);
+#endif
+ }
+}
+
+static LRESULT CALLBACK TSButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MButtonCtrl *bct = (MButtonCtrl *) GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE: {
+ SetWindowLong(hwndDlg, GWL_STYLE, GetWindowLong(hwndDlg, GWL_STYLE) | BS_OWNERDRAW);
+ bct = reinterpret_cast<MButtonCtrl *>(malloc(sizeof(MButtonCtrl)));
+ if(bct == NULL)
+ return FALSE;
+ bct->hwnd = hwndDlg;
+ bct->stateId = PBS_NORMAL;
+ bct->focus = 0;
+ bct->hFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
+ bct->arrow = NULL;
+ bct->defbutton = 0;
+ bct->hIcon = bct->hIconPrivate = 0;
+ bct->iIcon = 0;
+ bct->hIml = 0;
+ bct->hBitmap = NULL;
+ bct->pushBtn = 0;
+ bct->pbState = 0;
+ bct->hThemeButton = NULL;
+ bct->hThemeToolbar = NULL;
+ bct->cHot = 0;
+ bct->flatBtn = 0;
+ bct->bThemed = FALSE;
+ bct->bSkinned = bct->bSendOnDown = 0;
+ bct->buttonItem = NULL;
+ LoadTheme(bct);
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR) bct);
+ if(((CREATESTRUCTA *) lParam)->lpszName)
+ SetWindowText(hwndDlg, ((CREATESTRUCT *) lParam)->lpszName);
+ return TRUE;
+ }
+
+ case WM_DESTROY: {
+ if(bct) {
+ if(hwndToolTips) {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR) bct->hwnd;
+ if(SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM) &ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM) &ti);
+ }
+ if(SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM) &ti) == 0) {
+ DestroyWindow(hwndToolTips);
+ hwndToolTips = NULL;
+ }
+ }
+ if(bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ DestroyTheme(bct);
+ free(bct);
+ }
+ SetWindowLongPtr(hwndDlg, 0, 0);
+ break; // DONT! fall thru
+ }
+
+ case WM_SETTEXT: {
+ bct->cHot = 0;
+ if((char*) lParam) {
+ char *tmp = (char *) lParam;
+ while(*tmp) {
+ if(*tmp == '&' && *(tmp + 1)) {
+ bct->cHot = tolower(*(tmp + 1));
+ break;
+ }
+ tmp++;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ lstrcpyn(bct->szText, (wchar_t *)lParam, 127);
+ bct->szText[127] = 0;
+ }
+ break;
+ }
+
+ case WM_SYSKEYUP:
+ if(bct->stateId != PBS_DISABLED && bct->cHot && bct->cHot == tolower((int) wParam)) {
+ if(bct->pushBtn) {
+ if(bct->pbState)
+ bct->pbState = 0;
+ else
+ bct->pbState = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ if(!bct->bSendOnDown)
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM) hwndDlg);
+ return 0;
+ }
+ break;
+
+ case WM_THEMECHANGED: {
+ if(bct->bThemed)
+ LoadTheme(bct);
+ InvalidateRect(bct->hwnd, NULL, TRUE); // repaint it
+ break;
+ }
+
+ case WM_SETFONT: {
+ bct->hFont = (HFONT) wParam; // maybe we should redraw?
+ break;
+ }
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ HDC hdcPaint;
+
+ hdcPaint = BeginPaint(hwndDlg, &ps);
+ if(hdcPaint) {
+ PaintWorker(bct, hdcPaint);
+ EndPaint(hwndDlg, &ps);
+ }
+ break;
+ }
+
+ case BM_GETIMAGE:
+ if(wParam == IMAGE_ICON)
+ return (LRESULT)(bct->hIconPrivate ? bct->hIconPrivate : bct->hIcon);
+ break;
+
+ case BM_SETIMAGE:
+ if(!lParam)
+ break;
+ bct->hIml = 0;
+ bct->iIcon = 0;
+ if(wParam == IMAGE_ICON) {
+ ICONINFO ii = {0};
+ BITMAP bm = {0};
+
+ if(bct->hIconPrivate) {
+ DestroyIcon(bct->hIconPrivate);
+ bct->hIconPrivate = 0;
+ }
+
+ GetIconInfo((HICON) lParam, &ii);
+ GetObject(ii.hbmColor, sizeof(bm), &bm);
+ if(bm.bmWidth > CXSMICON || bm.bmHeight > CYSMICON) {
+ HIMAGELIST hImageList;
+ hImageList = ImageList_Create(CXSMICON, CYSMICON, ILC_COLOR32 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, (HICON) lParam);
+ bct->hIconPrivate = ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ bct->hIcon = 0;
+ } else {
+ bct->hIcon = (HICON) lParam;
+ bct->hIconPrivate = 0;
+ }
+
+ DeleteObject(ii.hbmMask);
+ DeleteObject(ii.hbmColor);
+ bct->hBitmap = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ } else if(wParam == IMAGE_BITMAP) {
+ bct->hBitmap = (HBITMAP) lParam;
+ if(bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ bct->hIcon = bct->hIconPrivate = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+
+ case BM_SETPRIVATEICON:
+ bct->hIml = 0;
+ bct->iIcon = 0;
+ {
+ if(bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ bct->hIconPrivate = DuplicateIcon(g_hInst, (HICON) lParam);
+ bct->hIcon = 0;
+ break;
+ }
+
+ case BM_SETIMLICON: {
+ if(bct->hIconPrivate)
+ DestroyIcon(bct->hIconPrivate);
+ bct->hIml = (HIMAGELIST) wParam;
+ bct->iIcon = (int) lParam;
+ bct->hIcon = bct->hIconPrivate = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ }
+
+ case BM_SETSKINNED:
+ bct->bSkinned = (DWORD)lParam;
+ bct->bThemed = bct->bSkinned ? FALSE : bct->bThemed;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BM_SETBTNITEM:
+ bct->buttonItem = (TButtonItem *)lParam;
+ break;
+
+ case BM_SETASMENUACTION:
+ bct->bSendOnDown = wParam ? TRUE : FALSE;
+ return 0;
+
+ case BM_SETCHECK:
+ if(!bct->pushBtn)
+ break;
+ if(wParam == BST_CHECKED) {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ } else if(wParam == BST_UNCHECKED) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BM_GETCHECK:
+ if(bct->pushBtn) {
+ return bct->pbState ? BST_CHECKED : BST_UNCHECKED;
+ }
+ return 0;
+
+ case BUTTONSETARROW:
+ // turn arrow on/off
+ if(wParam) {
+ if(!bct->arrow)
+ bct->arrow = (HICON) LoadImage(g_hInst, MAKEINTRESOURCE(IDI_MINIMIZE), IMAGE_ICON, CXSMICON, CYSMICON, 0);
+ } else {
+ if(bct->arrow) {
+ DestroyIcon(bct->arrow);
+ bct->arrow = NULL;
+ }
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BUTTONSETDEFAULT:
+ bct->defbutton = wParam ? 1 : 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BUTTONSETASPUSHBTN:
+ bct->pushBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BUTTONSETASFLATBTN:
+ bct->flatBtn = lParam == 0 ? 1 : 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case BUTTONSETASFLATBTN + 10:
+ bct->bThemed = lParam ? TRUE : FALSE;
+ bct->bSkinned = bct->bThemed ? 0 : bct->bSkinned;
+ break;
+
+ case BUTTONADDTOOLTIP: {
+ TOOLINFO ti;
+
+ if(!(char*) wParam)
+ break;
+ if(!hwndToolTips) {
+ hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+ SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ }
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR) bct->hwnd;
+ if(SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM) &ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM) &ti);
+ }
+ ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
+ ti.uId = (UINT_PTR) bct->hwnd;
+ ti.lpszText = (wchar_t *) wParam;
+ SendMessage(hwndToolTips, TTM_ADDTOOL, 0, (LPARAM) &ti);
+ break;
+ }
+ case WM_SETFOCUS:
+ // set keybord focus and redraw
+ bct->focus = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_KILLFOCUS:
+ // kill focus and redraw
+ bct->focus = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_ENABLE: {
+ bct->stateId = wParam ? PBS_NORMAL : PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ }
+
+ case WM_MOUSELEAVE: {
+ if(bct->stateId != PBS_DISABLED) {
+ // don't change states if disabled
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+ }
+
+ case WM_LBUTTONDOWN: {
+ if(bct->stateId != PBS_DISABLED && bct->stateId != PBS_PRESSED) {
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ if(bct->bSendOnDown) {
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM) hwndDlg);
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ }
+ break;
+ }
+
+ case WM_LBUTTONUP: {
+ if(bct->pushBtn) {
+ if(bct->pbState)
+ bct->pbState = 0;
+ else
+ bct->pbState = 1;
+ }
+ if(bct->stateId != PBS_DISABLED) {
+ // don't change states if disabled
+ if(msg == WM_LBUTTONUP)
+ bct->stateId = PBS_HOT;
+ else
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ if(!bct->bSendOnDown)
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM) hwndDlg);
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ if(bct->stateId == PBS_NORMAL) {
+ bct->stateId = PBS_HOT;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Call timer, used to start cheesy TrackMouseEvent faker
+ SetTimer(hwndDlg, BUTTON_POLLID, BUTTON_POLLDELAY, NULL);
+ break;
+
+ case WM_NCHITTEST: {
+ LRESULT lr = SendMessage(GetParent(hwndDlg), WM_NCHITTEST, wParam, lParam);
+ if(lr == HTLEFT || lr == HTRIGHT || lr == HTBOTTOM || lr == HTTOP || lr == HTTOPLEFT || lr == HTTOPRIGHT
+ || lr == HTBOTTOMLEFT || lr == HTBOTTOMRIGHT)
+ return HTTRANSPARENT;
+ break;
+ }
+ case WM_TIMER: {
+ if(wParam == BUTTON_POLLID) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(hwndDlg, &rc);
+ GetCursorPos(&pt);
+ if(!PtInRect(&rc, pt)) {
+ // mouse must be gone, trigger mouse leave
+ PostMessage(hwndDlg, WM_MOUSELEAVE, 0, 0L);
+ KillTimer(hwndDlg, BUTTON_POLLID);
+ }
+ }
+ break;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/plugins/Clist_ng/SRC/Docking.cpp b/plugins/Clist_ng/SRC/Docking.cpp new file mode 100644 index 0000000000..a26bf0089f --- /dev/null +++ b/plugins/Clist_ng/SRC/Docking.cpp @@ -0,0 +1,292 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: Docking.cpp 102 2010-08-31 02:48:29Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+#define WM_DOCKCALLBACK (WM_USER+121)
+#define WM_CREATEDOCKED (WM_USER+122)
+#define EDGESENSITIVITY 3
+
+#define DOCKED_NONE 0
+#define DOCKED_LEFT 1
+#define DOCKED_RIGHT 2
+static int docked;
+
+extern RECT cluiPos;
+
+static void Docking_GetMonitorRectFromPoint(POINT pt, RECT *rc)
+{
+ MONITORINFO monitorInfo;
+ HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); // always returns a valid value
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+
+ if (GetMonitorInfo( hMonitor, &monitorInfo)) {
+ CopyMemory(rc, &monitorInfo.rcMonitor, sizeof(RECT));
+ return;
+ }
+
+ // "generic" win95/NT support, also serves as failsafe
+ rc->left = 0;
+ rc->top = 0;
+ rc->bottom = GetSystemMetrics(SM_CYSCREEN);
+ rc->right = GetSystemMetrics(SM_CXSCREEN);
+}
+
+static void Docking_GetMonitorRectFromWindow(HWND hWnd, RECT *rc)
+{
+ POINT ptWindow;
+ GetWindowRect(hWnd, rc);
+ ptWindow.x = rc->left;
+ ptWindow.y = rc->top;
+ Docking_GetMonitorRectFromPoint(ptWindow, rc);
+}
+
+static void Docking_AdjustPosition(HWND hwnd, RECT *rcDisplay, RECT *rc)
+{
+ APPBARDATA abd;
+
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = hwnd;
+ abd.uEdge = docked == DOCKED_LEFT ? ABE_LEFT : ABE_RIGHT;
+ abd.rc = *rc;
+ abd.rc.top = rcDisplay->top;
+ abd.rc.bottom = rcDisplay->bottom;
+ if (docked == DOCKED_LEFT) {
+ abd.rc.right = rcDisplay->left + (abd.rc.right - abd.rc.left);
+ abd.rc.left = rcDisplay->left;
+ } else {
+ abd.rc.left = rcDisplay->right - (abd.rc.right - abd.rc.left);
+ abd.rc.right = rcDisplay->right;
+ }
+ SHAppBarMessage(ABM_SETPOS, &abd);
+ *rc = abd.rc;
+}
+
+int Docking_IsDocked(WPARAM wParam, LPARAM lParam)
+{
+ return docked;
+}
+
+int Docking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam)
+{
+ APPBARDATA abd;
+ static int draggingTitle;
+ MSG *msg = (MSG *) wParam;
+
+ if (msg->message == WM_DESTROY)
+ cfg::writeByte("CList", "Docked", (BYTE) docked);
+ if (!docked && msg->message != WM_CREATE && msg->message != WM_MOVING && msg->message != WM_CREATEDOCKED && msg->message != WM_MOVE)
+ return 0;
+ switch (msg->message) {
+ case WM_CREATE:
+ //if(GetSystemMetrics(SM_CMONITORS)>1) return 0;
+ if (cfg::getByte("CList", "Docked", 0))
+ PostMessage(msg->hwnd, WM_CREATEDOCKED, 0, 0);
+ draggingTitle = 0;
+ return 0;
+ case WM_CREATEDOCKED:
+ //we need to post a message just after creation to let main message function do some work
+ docked = (int) (char) cfg::getByte("CList", "Docked", 0);
+ if (IsWindowVisible(msg->hwnd) && !IsIconic(msg->hwnd)) {
+ RECT rc, rcMonitor;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ }
+ break;
+ case WM_ACTIVATE:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_ACTIVATE, &abd);
+ return 0;
+ case WM_WINDOWPOSCHANGED:
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
+ return 0;
+ case WM_MOVING:
+ {
+ RECT rcMonitor;
+ POINT ptCursor;
+
+ // stop early
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ return 0;
+
+ // GetMessagePos() is no good, position is always unsigned
+ GetCursorPos(&ptCursor);
+ Docking_GetMonitorRectFromPoint(ptCursor, &rcMonitor);
+
+ if ((ptCursor.x < rcMonitor.left + EDGESENSITIVITY) || (ptCursor.x >= rcMonitor.right - EDGESENSITIVITY)) {
+ if(!(GetWindowLong(msg->hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)) {
+ SendMessage(msg->hwnd, CLUIINTM_REDRAW, 0, 0);
+ MessageBox(0, TranslateT("The clist cannot be docked when using the default title bar and border. Use a toolwindow or borderless style instead."),
+ TranslateT("Clist docking"), MB_OK);
+ return 0;
+ }
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ if (ptCursor.x < rcMonitor.left + EDGESENSITIVITY)
+ docked = DOCKED_LEFT;
+ else
+ docked = DOCKED_RIGHT;
+ SendMessage(msg->hwnd, WM_LBUTTONUP, 0, MAKELPARAM(ptCursor.x, ptCursor.y));
+ GetWindowRect(msg->hwnd, (LPRECT) msg->lParam);
+ Docking_AdjustPosition(msg->hwnd, (LPRECT) &rcMonitor, (LPRECT) msg->lParam);
+ PostMessage(msg->hwnd, CLUIINTM_REDRAW, 0, 0);
+ return TRUE;
+ }
+ return 0;
+ }
+ case WM_MOVE:
+ {
+ if (docked) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ return 1;
+ }
+ return 0;
+ }
+ case WM_SIZING:
+ {
+ RECT rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, (LPRECT) msg->lParam);
+ *((LRESULT *) lParam) = TRUE;
+ return TRUE;
+ }
+ case WM_SHOWWINDOW:
+ if (msg->lParam)
+ return 0;
+ if ((msg->wParam && docked < 0) || (!msg->wParam && docked > 0))
+ docked = -docked;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ if (msg->wParam) {
+ RECT rc, rcMonitor;
+ Docking_GetMonitorRectFromWindow(msg->hwnd, &rcMonitor);
+ abd.lParam = 0;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ SHAppBarMessage(ABM_NEW, &abd);
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, &rc);
+ MoveWindow(msg->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
+ } else {
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ case WM_NCHITTEST:
+ {
+ LONG result;
+ result = DefWindowProc(msg->hwnd, WM_NCHITTEST, msg->wParam, msg->lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT || result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT; return TRUE;
+ }
+ if (docked == DOCKED_LEFT && result == HTLEFT) {
+ *((LRESULT *) lParam) = HTCLIENT; return TRUE;
+ }
+ if (docked == DOCKED_RIGHT && result == HTRIGHT) {
+ *((LRESULT *) lParam) = HTCLIENT; return TRUE;
+ }
+ return 0;
+ }
+ case WM_SYSCOMMAND:
+ if ((msg->wParam & 0xFFF0) != SC_MOVE)
+ return 0;
+ SetActiveWindow(msg->hwnd);
+ SetCapture(msg->hwnd);
+ draggingTitle = 1;
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ case WM_MOUSEMOVE:
+ if (!draggingTitle)
+ return 0; {
+ RECT rc;
+ POINT pt;
+ GetClientRect(msg->hwnd, &rc);
+ if (((docked == DOCKED_LEFT || docked == -DOCKED_LEFT) && (short) LOWORD(msg->lParam) > rc.right) || ((docked == DOCKED_RIGHT || docked == -DOCKED_RIGHT) && (short) LOWORD(msg->lParam) < 0)) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ docked = 0;
+ GetCursorPos(&pt);
+ PostMessage(msg->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ SetWindowPos(msg->hwnd, 0, pt.x - rc.right / 2, pt.y - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYSMCAPTION) / 2,
+ CLUI::cluiPos.right, CLUI::cluiPos.bottom, SWP_NOZORDER);
+ }
+ return 1;
+ }
+ case WM_LBUTTONUP:
+ if (draggingTitle) {
+ ReleaseCapture();
+ draggingTitle = 0;
+ }
+ return 0;
+ case WM_DOCKCALLBACK:
+ switch (msg->wParam) {
+ case ABN_WINDOWARRANGE:
+ ShowWindow(msg->hwnd, msg->lParam ? SW_HIDE : SW_SHOW);
+ break;
+ }
+ return TRUE;
+ case WM_DESTROY:
+ if (docked > 0) {
+ ZeroMemory(&abd, sizeof(abd));
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = msg->hwnd;
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ }
+ return 0;
+ }
+ return 0;
+}
diff --git a/plugins/Clist_ng/SRC/clc.cpp b/plugins/Clist_ng/SRC/clc.cpp new file mode 100644 index 0000000000..1ec6eb5bb8 --- /dev/null +++ b/plugins/Clist_ng/SRC/clc.cpp @@ -0,0 +1,934 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_nicer plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clc.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <resource.h>
+#include <m_userinfo.h>
+#include "../coolsb/coolscroll.h"
+
+/*
+ * static function pointers for Clist interface
+ */
+LRESULT (CALLBACK* CLC::saveContactListControlWndProc) (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) = 0;
+
+bool CLC::fHottrackDone = false, CLC::fInPaint = false;
+int CLC::iHottrackItem = 0;
+HANDLE CLC::hSettingsChanged = 0, CLC::hDBEvent = 0;
+HIMAGELIST CLC::hClistImages = 0;
+unsigned CLC::uNrAvatars = 0;
+
+TDisplayProfile CLC::dsp_default = {0};
+
+int CLC::_status2onlineness[] = {
+ 100, // ID_STATUS_ONLINE
+ 30, // ID_STATUS_AWAY
+ 40, // ID_STATUS_DND
+ 10, // ID_STATUS_NA
+ 60, // ID_STATUS_OCCUPIED
+ 110, // ID_STATUS_FREECHAT
+ 5, // ID_STATUS_INVISIBLE
+ 50, // ID_STATUS_ONTHEPHONE
+ 20 // ID_STATUS_OUTTOLUNCH
+};
+
+extern HANDLE hExtraImageApplying;
+extern FRAMEWND *wndFrameCLC;
+
+extern int during_sizing;
+
+HANDLE hSoundHook = 0, hIcoLibChanged = 0, hSvc_GetContactStatusMsg = 0;
+
+HMENU BuildGroupPopupMenu(struct ClcGroup* group)
+{
+ return Menu_BuildSubGroupMenu(group);
+}
+
+int AvatarChanged(WPARAM wParam, LPARAM lParam)
+{
+ pcli->pfnClcBroadcast(INTM_AVATARCHANGED, wParam, lParam);
+ return 0;
+}
+
+int __forceinline __strcmp(const char * src, const char * dst)
+{
+ int ret = 0 ;
+
+ while (!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
+ ++src, ++dst;
+ return(ret);
+}
+
+static int ClcEventAdded(WPARAM hContact, LPARAM lParam)
+{
+ DWORD new_freq = 0;
+ cfg::dat.t_now = time(NULL);
+
+ if (hContact && lParam) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get((MEVENT)lParam, &dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ DWORD firstTime = cfg::getDword(hContact, "CList", "mf_firstEvent", 0);
+ DWORD count = cfg::getDword(hContact, "CList", "mf_count", 0);
+ count++;
+ new_freq = count ? (dbei.timestamp - firstTime) / count : 0x7fffffff;
+ cfg::writeDword(hContact, "CList", "mf_freq", new_freq);
+ cfg::writeDword(hContact, "CList", "mf_count", count);
+ int iEntry = cfg::getCache(hContact, NULL);
+ if (iEntry >= 0 && iEntry < cfg::nextCacheEntry) {
+ cfg::eCache[iEntry].dwLastMsgTime = dbei.timestamp;
+ if (new_freq)
+ cfg::eCache[iEntry].msgFrequency = new_freq;
+ pcli->pfnClcBroadcast(INTM_FORCESORT, 0, 1);
+ }
+ }
+ }
+ return 0;
+}
+
+int ClcSoundHook(WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+int CLC::SettingChanged(WPARAM hContact, LPARAM lParam)
+{
+ char *szProto = NULL;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+
+ if (hContact) {
+ if (!__strcmp(cws->szModule, "CList")) {
+ if (!__strcmp(cws->szSetting, "StatusMsg"))
+ SendMessage(pcli->hwndContactTree, INTM_STATUSMSGCHANGED, hContact, lParam);
+ }
+ else if (!__strcmp(cws->szModule, "UserInfo")) {
+ if (!__strcmp(cws->szSetting, "Timezone") || !__strcmp(cws->szSetting, "TzName"))
+ ReloadExtraInfo(hContact);
+ }
+ else if (hContact != 0 && (szProto = GetContactProto(hContact)) != NULL) {
+ if (!__strcmp(cws->szModule, "Protocol") && !__strcmp(cws->szSetting, "p")) {
+ char *szProto_s;
+ pcli->pfnClcBroadcast(INTM_PROTOCHANGED, hContact, lParam);
+ if (cws->value.type == DBVT_DELETED)
+ szProto_s = NULL;
+ else
+ szProto_s = cws->value.pszVal;
+ pcli->pfnChangeContactIcon(hContact, IconFromStatusMode(szProto_s, szProto_s == NULL ? ID_STATUS_OFFLINE : cfg::getWord(hContact, szProto_s, "Status", ID_STATUS_OFFLINE), hContact, NULL), 0);
+ }
+ // something is being written to a protocol module
+ if (!__strcmp(szProto, cws->szModule)) {
+ // was a unique setting key written?
+ pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
+ if (!__strcmp(cws->szSetting, "Status")) {
+ if (!cfg::getByte(hContact, "CList", "Hidden", 0)) {
+ if (cfg::getByte("CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)) {
+ // User's state is changing, and we are hideOffline-ing
+ if (cws->value.wVal == ID_STATUS_OFFLINE) {
+ pcli->pfnChangeContactIcon(hContact, IconFromStatusMode(cws->szModule, cws->value.wVal, hContact, NULL), 0);
+ CallService(MS_CLUI_CONTACTDELETED, hContact, 0);
+ return 0;
+ }
+ pcli->pfnChangeContactIcon(hContact, IconFromStatusMode(cws->szModule, cws->value.wVal, hContact, NULL), 1);
+ }
+ pcli->pfnChangeContactIcon(hContact, IconFromStatusMode(cws->szModule, cws->value.wVal, hContact, NULL), 0);
+ }
+ SendMessage(pcli->hwndContactTree, INTM_STATUSCHANGED, hContact, lParam);
+ return 0;
+ } else if (strstr("YMsg|StatusDescr|XStatusMsg", cws->szSetting))
+ SendMessage(pcli->hwndContactTree, INTM_STATUSMSGCHANGED, hContact, lParam);
+ else if (strstr(cws->szSetting, "XStatus"))
+ SendMessage(pcli->hwndContactTree, INTM_XSTATUSCHANGED, hContact, lParam);
+ else if (!__strcmp(cws->szSetting, "Timezone") || !__strcmp(cws->szSetting, "TzName"))
+ ReloadExtraInfo(hContact);
+ else if (!__strcmp(cws->szSetting, "MirVer"))
+ NotifyEventHooks(hExtraImageApplying, hContact, 0);
+
+ if (cfg::dat.bMetaAvail && !__strcmp(szProto, cfg::dat.szMetaName)) {
+ if ((lstrlenA(cws->szSetting) > 6 && !strncmp(cws->szSetting, "Status", 6)) || strstr("Default,ForceSend,Nick", cws->szSetting))
+ pcli->pfnClcBroadcast(INTM_NAMEORDERCHANGED, hContact, lParam);
+ }
+ }
+ if (cfg::dat.bMetaAvail && cfg::dat.bMetaEnabled && !__strcmp(cws->szModule, cfg::dat.szMetaName) && !__strcmp(cws->szSetting, "IsSubcontact"))
+ pcli->pfnClcBroadcast(INTM_HIDDENCHANGED, hContact, lParam);
+ }
+ } else if (hContact == 0 && !__strcmp(cws->szModule, cfg::dat.szMetaName)) {
+ BYTE bMetaEnabled = cfg::getByte(cfg::dat.szMetaName, "Enabled", 1);
+ if (bMetaEnabled != (BYTE)cfg::dat.bMetaEnabled) {
+ cfg::dat.bMetaEnabled = bMetaEnabled;
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ }
+ } else if (hContact == 0 && !__strcmp(cws->szModule, "Skin")) {
+ if (!__strcmp(cws->szSetting, "UseSound")) {
+ if (hSoundHook) {
+ UnhookEvent(hSoundHook);
+ hSoundHook = 0;
+ }
+ cfg::dat.soundsOff = cfg::getByte(cws->szModule, cws->szSetting, 0) ? 0 : 1;
+ if (cfg::dat.soundsOff && hSoundHook == 0)
+ hSoundHook = HookEvent(ME_SKIN_PLAYINGSOUND, ClcSoundHook);
+ CheckDlgButton(pcli->hwndContactList, IDC_TBSOUND, cfg::dat.soundsOff ? BST_UNCHECKED : BST_CHECKED);
+ CLUI::setButtonStates(pcli->hwndContactList);
+ }
+ } else if (szProto == NULL && hContact == 0) {
+ if (!__strcmp(cws->szSetting, "XStatusId"))
+ CluiProtocolStatusChanged(0, cws->szModule);
+ return 0;
+ }
+ return 0;
+}
+
+static int ClcModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+int CLC::preshutdown(WPARAM wParam, LPARAM lParam)
+{
+ SFL_Destroy();
+ cfg::shutDown = TRUE;
+ if (hSvc_GetContactStatusMsg)
+ DestroyServiceFunction(hSvc_GetContactStatusMsg);
+ UnhookEvent(hSettingsChanged);
+ UnhookEvent(hDBEvent);
+ if (hIcoLibChanged)
+ UnhookEvent(hIcoLibChanged);
+ return 0;
+}
+
+int CLC::shutDown(WPARAM wParam, LPARAM lParam)
+{
+ if (cfg::dat.hIconInvisible)
+ DestroyIcon(cfg::dat.hIconInvisible);
+ if (cfg::dat.hIconVisible)
+ DestroyIcon(cfg::dat.hIconVisible);
+ if (cfg::dat.hIconChatactive)
+ DestroyIcon(cfg::dat.hIconChatactive);
+
+ DeleteObject(cfg::dat.hBrushCLCBk);
+ DeleteObject(cfg::dat.hBrushCLCGroupsBk);
+ DeleteObject(cfg::dat.hBrushAvatarBorder);
+ DestroyMenu(cfg::dat.hMenuNotify);
+ ClearIcons(1);
+ SFL_UnregisterWindowClass();
+ if (cfg::eCache) {
+ int i;
+
+ for (i = 0; i < cfg::nextCacheEntry; i++) {
+ if (cfg::eCache[i].statusMsg)
+ free(cfg::eCache[i].statusMsg);
+ if (cfg::eCache[i].status_item) {
+ TStatusItem *item = cfg::eCache[i].status_item;
+ int j;
+
+ free(cfg::eCache[i].status_item);
+ cfg::eCache[i].status_item = 0;
+ for (j = i; j < cfg::nextCacheEntry; j++) { // avoid duplicate free()'ing status item pointers (there are references from sub to master contacts, so compare the pointers...
+ if (cfg::eCache[j].status_item == item)
+ cfg::eCache[j].status_item = 0;
+ }
+ }
+ }
+ free(cfg::eCache);
+ cfg::eCache = NULL;
+ }
+ Skin::Unload();
+ DeleteCriticalSection(&cfg::cachecs);
+ return 0;
+}
+
+int CLC::loadModule(void)
+{
+ CLC::hClistImages = (HIMAGELIST) CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ClcModulesLoaded);
+ hSettingsChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, CLC::SettingChanged);
+ hDBEvent = HookEvent(ME_DB_EVENT_ADDED, ClcEventAdded);
+ HookEvent(ME_OPT_INITIALISE, ClcOptInit);
+ HookEvent(ME_SYSTEM_SHUTDOWN, preshutdown);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// clist_nicer+ control window procedure
+
+LRESULT CALLBACK CLC::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ClcData *dat;
+ BOOL frameHasTitlebar = FALSE;
+
+ if (wndFrameCLC)
+ frameHasTitlebar = wndFrameCLC->TitleBar.ShowTitleBar;
+
+ dat = (struct ClcData *) GetWindowLongPtr(hwnd, 0);
+ if (msg >= CLM_FIRST && msg < CLM_LAST)
+ return ProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+
+ switch (msg) {
+ case WM_NCCREATE:
+ dat = (struct ClcData *)mir_alloc(sizeof(struct ClcData));
+ memset(dat, 0, sizeof(struct ClcData));
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat);
+ dat->ph = new CLCPaintHelper(hwnd, dat, 0, 0, 0, 0, 0);
+ RowHeight::Init(dat);
+ break;
+ case WM_CREATE:
+ dat->forceScroll = 0;
+ dat->lastRepaint = 0;
+ dat->needsResort = false;
+ dat->himlExtraColumns = CLUI::hExtraImages;
+ dat->hwndParent = GetParent(hwnd);
+ dat->lastSort = GetTickCount();
+ dat->ph = new CLCPaintHelper(hwnd, dat, 0, 0, 0, 0, 0);
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ if (cs->lpCreateParams == (LPVOID)0xff00ff00) {
+ dat->bisEmbedded = FALSE;
+ dat->bHideSubcontacts = TRUE;
+ cfg::clcdat = dat;
+ if (cfg::dat.bShowLocalTime)
+ SetTimer(hwnd, TIMERID_REFRESH, 65000, NULL);
+ } else
+ dat->bisEmbedded = TRUE;
+ }
+ break;
+ case WM_SIZE:
+ pcli->pfnEndRename(hwnd, dat, 1);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+LBL_Def:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_NCCALCSIZE: {
+ return FrameNCCalcSize(hwnd, DefWindowProc, wParam, lParam, frameHasTitlebar);
+ }
+
+ /*
+ * scroll bar handling
+ */
+ case WM_NCPAINT:
+ return FrameNCPaint(hwnd, DefWindowProc, wParam, lParam, frameHasTitlebar);
+ case INTM_SCROLLBARCHANGED:
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (!cfg::getByte("CLC", "NoVScrollBar", 0)) {
+ CoolSB_SetupScrollBar(hwnd);
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ }
+ else
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ }
+ break;
+ case INTM_GROUPCHANGED: {
+ ClcContact *contact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ BYTE flags = 0;
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ memset(iExtraImage, 0xFF, sizeof(iExtraImage));
+ else {
+ CopyMemory(iExtraImage, contact->iExtraImage, sizeof(iExtraImage));
+ flags = contact->flags;
+ }
+ pcli->pfnDeleteItemFromTree(hwnd, (MCONTACT)wParam);
+ if (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !CLVM_GetContactHiddenStatus(wParam, NULL, dat)) {
+ NMCLISTCONTROL nm;
+ pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1);
+ if (findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL)) {
+ CopyMemory(contact->iExtraImage, iExtraImage, sizeof(iExtraImage));
+ if (flags & CONTACTF_CHECKED)
+ contact->flags |= CONTACTF_CHECKED;
+ }
+ nm.hdr.code = CLN_CONTACTMOVED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (HANDLE) wParam;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) &nm);
+ }
+ dat->needsResort = true;
+ PostMessage(hwnd, INTM_SORTCLC, 0, 1);
+ goto LBL_Def;
+ }
+
+ case INTM_ICONCHANGED: {
+ struct ClcContact *contact = NULL;
+ struct ClcGroup *group = NULL;
+ int recalcScrollBar = 0, shouldShow;
+ WORD status = ID_STATUS_OFFLINE;
+ char *szProto;
+ int contactRemoved = 0;
+ DWORD hSelItem = 0;
+ struct ClcContact *selcontact = NULL;
+
+ szProto = GetContactProto(wParam);
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = cfg::getWord(wParam, szProto, "Status", ID_STATUS_OFFLINE);
+
+ shouldShow = (GetWindowLong(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !CLVM_GetContactHiddenStatus(wParam, szProto, dat)) && ((cfg::dat.bFilterEffective ? TRUE : !pcli->pfnIsHiddenMode(dat, status)) || CallService(MS_CLIST_GETCONTACTICON, wParam, 0) != lParam);// XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL)) {
+ if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
+ if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
+ pcli->pfnAddContactToTree(hwnd, dat, wParam, 0, 0);
+ recalcScrollBar = 1;
+ findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL);
+ if (contact) {
+ contact->iImage = (WORD) lParam;
+ pcli->pfnNotifyNewContact(hwnd, wParam);
+ }
+ }
+ } else {
+ //item in list already
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ if (contact->iImage == (WORD) lParam)
+ break;
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline || cfg::dat.bFilterEffective)) { // CLVM changed
+ if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
+ pcli->pfnRemoveItemFromGroup(hwnd, group, contact, 0);
+ contactRemoved = TRUE;
+ recalcScrollBar = 1;
+ } else {
+ contact->iImage = (WORD) lParam;
+ if (!pcli->pfnIsHiddenMode(dat, status))
+ contact->flags |= CONTACTF_ONLINE;
+ else
+ contact->flags &= ~CONTACTF_ONLINE;
+ }
+ }
+ if (hSelItem) {
+ struct ClcGroup *selgroup;
+ if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*) & selgroup->cl, selcontact));
+ else
+ dat->selection = -1;
+ }
+ dat->needsResort = true;
+ PostMessage(hwnd, INTM_SORTCLC, 0, recalcScrollBar);
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contactRemoved ? 0 : wParam));
+ if (recalcScrollBar)
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ goto LBL_Def;
+ }
+ case INTM_METACHANGED: {
+ struct ClcContact *contact;
+ if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL))
+ break;
+ if (contact->bIsMeta && cfg::dat.bMetaAvail) {
+ contact->hSubContact = (MCONTACT) CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM) contact->hContact, 0);
+ contact->metaProto = GetContactProto(contact->hSubContact);
+ contact->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) contact->hSubContact, 0);
+ if (contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry) {
+ int subIndex = cfg::getCache(contact->hSubContact, contact->metaProto);
+ cfg::eCache[contact->extraCacheEntry].proto_status_item = GetProtocolStatusItem(contact->metaProto);
+ if (subIndex >= 0 && subIndex <= cfg::nextCacheEntry) {
+ cfg::eCache[contact->extraCacheEntry].status_item = cfg::eCache[subIndex].status_item;
+ CopyMemory(cfg::eCache[contact->extraCacheEntry].iExtraImage, cfg::eCache[subIndex].iExtraImage, MAXEXTRACOLUMNS);
+ cfg::eCache[contact->extraCacheEntry].iExtraValid = cfg::eCache[subIndex].iExtraValid;
+ }
+ }
+ }
+ SendMessage(hwnd, INTM_NAMEORDERCHANGED, wParam, lParam);
+ goto LBL_Def;
+ }
+ case INTM_METACHANGEDEVENT: {
+ struct ClcContact *contact;
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (lParam == 0)
+ pcli->pfnInitAutoRebuild(hwnd);
+ goto LBL_Def;
+ }
+ case INTM_NAMECHANGED: {
+ struct ClcContact *contact;
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), safe_sizeof(contact->szText));
+ RTL_DetectAndSet(contact, 0);
+ dat->needsResort = true;
+ PostMessage(hwnd, INTM_SORTCLC, 0, 0);
+ goto LBL_Def;
+ }
+
+ case INTM_AVATARCHANGED: {
+ struct avatarCacheEntry *cEntry = (struct avatarCacheEntry *)lParam;
+ struct ClcContact *contact = NULL;
+
+ if (wParam == 0) {
+ cfg::dat.bForceRefetchOnPaint = TRUE;
+ RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
+ cfg::dat.bForceRefetchOnPaint = FALSE;
+ goto LBL_Def;
+ }
+
+ if (!findItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
+ return 0;
+ contact->ace = cEntry;
+ if (cEntry == NULL)
+ contact->cFlags &= ~ECF_AVATAR;
+ else {
+ if (cfg::dat.dwFlags & CLUI_FRAME_AVATARS)
+ contact->cFlags = (contact->dwDFlags & ECF_HIDEAVATAR ? contact->cFlags & ~ECF_AVATAR : contact->cFlags | ECF_AVATAR);
+ else
+ contact->cFlags = (contact->dwDFlags & ECF_FORCEAVATAR ? contact->cFlags | ECF_AVATAR : contact->cFlags & ~ECF_AVATAR);
+ }
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)contact->hContact);
+
+ goto LBL_Def;
+ }
+ case INTM_STATUSMSGCHANGED: {
+ struct ClcContact *contact = NULL;
+ int index = -1;
+ char *szProto = NULL;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ index = cfg::getCache(wParam, NULL);
+ else {
+ index = contact->extraCacheEntry;
+ szProto = contact->proto;
+ }
+ GetCachedStatusMsg(index, szProto);
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contact ? contact->hContact : 0));
+ goto LBL_Def;
+ }
+ case INTM_STATUSCHANGED: {
+ struct ClcContact *contact = NULL;
+ WORD wStatus;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+
+ wStatus = cfg::getWord(wParam, contact->proto, "Status", ID_STATUS_OFFLINE);
+ if (cfg::dat.bNoOfflineAvatars && wStatus != ID_STATUS_OFFLINE && contact->wStatus == ID_STATUS_OFFLINE) {
+ contact->wStatus = wStatus;
+ if (contact->ace == 0)
+ LoadAvatarForContact(contact);
+ }
+ contact->wStatus = wStatus;
+ goto LBL_Def;
+ }
+ case INTM_PROTOCHANGED: {
+ struct ClcContact *contact = NULL;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ contact->proto = GetContactProto(wParam);
+ CallService(MS_CLIST_INVALIDATEDISPLAYNAME, wParam, 0);
+ lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), safe_sizeof(contact->szText));
+ RTL_DetectAndSet(contact, 0);
+ dat->needsResort = TRUE;
+ PostMessage(hwnd, INTM_SORTCLC, 0, 0);
+ goto LBL_Def;
+ }
+
+ case INTM_INVALIDATE:
+ if (!dat->bNeedPaint) {
+ KillTimer(hwnd, TIMERID_PAINT);
+ SetTimer(hwnd, TIMERID_PAINT, 100, NULL);
+ dat->bNeedPaint = TRUE;
+ }
+
+ if (lParam && !dat->bisEmbedded) {
+ struct ClcContact *contact = NULL;
+
+ if (findItem(hwnd, dat, (HANDLE)lParam, &contact, NULL, 0)) {
+ if (contact && contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry && cfg::eCache[contact->extraCacheEntry].floater)
+ FLT_Update(dat, contact);
+ }
+ }
+ goto LBL_Def;
+
+ case INTM_INVALIDATECONTACT: {
+ struct ClcContact *contact = 0;
+ struct ClcGroup *group = 0;
+ int iItem;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+
+ if (contact == 0 || group == 0)
+ break;
+
+ iItem = pcli->pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*) & group->cl, contact));
+ pcli->pfnInvalidateItem(hwnd, dat, iItem);
+ goto LBL_Def;
+ }
+ case INTM_FORCESORT:
+ dat->needsResort = TRUE;
+ return SendMessage(hwnd, INTM_SORTCLC, wParam, lParam);
+ case INTM_SORTCLC:
+ if (dat->needsResort) {
+ pcli->pfnSortCLC(hwnd, dat, TRUE);
+ dat->needsResort = FALSE;
+ }
+ if (lParam)
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ goto LBL_Def;
+
+ case INTM_IDLECHANGED: {
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ char *szProto;
+ struct ClcContact *contact = NULL;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char*)cws->szModule;
+ if (szProto == NULL)
+ break;
+ contact->flags &= ~CONTACTF_IDLE;
+ if (cfg::getDword(wParam, szProto, "IdleTS", 0)) {
+ contact->flags |= CONTACTF_IDLE;
+ }
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)contact->hContact);
+ goto LBL_Def;
+ }
+ case INTM_XSTATUSCHANGED: {
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ char *szProto;
+ struct ClcContact *contact = NULL;
+ int index;
+
+ szProto = (char *)cws->szModule;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL)) {
+ index = cfg::getCache(wParam, szProto);
+ if (!dat->bisEmbedded && cfg::dat.bMetaAvail && szProto) { // may be a subcontact, forward the xstatus
+ if (cfg::getByte(wParam, cfg::dat.szMetaName, "IsSubcontact", 0)) {
+ MCONTACT hMasterContact = cfg::getDword(wParam, cfg::dat.szMetaName, "Handle", 0);
+ if (hMasterContact && hMasterContact != wParam) // avoid recursive call of settings handler
+ cfg::writeByte(hMasterContact, cfg::dat.szMetaName, "XStatusId", (BYTE)cfg::getByte(wParam, szProto, "XStatusId", 0));
+ break;
+ }
+ }
+ } else {
+ contact->xStatus = cfg::getByte(wParam, szProto, "XStatusId", 0);
+ index = contact->extraCacheEntry;
+ }
+ if (szProto == NULL)
+ break;
+ GetCachedStatusMsg(index, szProto);
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contact ? contact->hContact : 0));
+ goto LBL_Def;
+ }
+ case WM_PAINT: {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ ULONGLONG ulTick;
+ hdc = BeginPaint(hwnd, &ps);
+ if (IsWindowVisible(hwnd) && !CLUI::fInSizing && !cfg::shutDown && dat->ph) {
+ ulTick = Api::pfnGetTickCount64();
+ if(ulTick - dat->lastRepaint > 2000) {
+ countAvatars(dat);
+ dat->lastRepaint = ulTick;
+ }
+ Paint(hwnd, dat, hdc, &ps.rcPaint);
+ dat->bNeedPaint = FALSE;
+ }
+ EndPaint(hwnd, &ps);
+ if (dat->selection != dat->oldSelection && !dat->bisEmbedded && CLUI::buttonItems != NULL) {
+ CLUI::setFrameButtonStates(0);
+ dat->oldSelection = dat->selection;
+ }
+ goto LBL_Def;
+ }
+
+ case WM_MOUSEWHEEL:
+ dat->forceScroll = TRUE;
+ break;
+
+ case WM_TIMER:
+ if (wParam == TIMERID_PAINT) {
+ KillTimer(hwnd, TIMERID_PAINT);
+ InvalidateRect(hwnd, NULL, FALSE);
+ goto LBL_Def;
+ }
+
+ if (wParam == TIMERID_REFRESH) {
+ InvalidateRect(hwnd, NULL, FALSE);
+ goto LBL_Def;
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK: {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ pcli->pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ dat->szQuickSearch[0] = 0;
+ dat->selection = HitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ if (hitFlags & CLCHT_ONITEMEXTRAEX && hwnd == pcli->hwndContactTree && contact != 0) {
+ int column = hitFlags >> 24;
+ if (column-- > 0) {
+ if (contact->type == CLCIT_CONTACT) {
+ CONTACTINFO ci;
+ ZeroMemory(&ci,sizeof(CONTACTINFO));
+ ci.cbSize = sizeof(CONTACTINFO);
+ ci.hContact = contact->hContact;
+ ci.szProto = contact->proto;
+
+ if (column == 0) {
+ ci.dwFlag = CNF_EMAIL;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,(WPARAM)0,(LPARAM)&ci)) {
+ char buf[4096];
+ mir_snprintf(buf, sizeof(buf), "mailto:%s", (LPCSTR)ci.pszVal);
+ mir_free(ci.pszVal);
+ ShellExecuteA(hwnd, "open", buf, NULL, NULL, SW_SHOW);
+ }
+ return TRUE;
+ }
+ if (column == 1) {
+ ci.dwFlag = CNF_HOMEPAGE;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,(WPARAM)0,(LPARAM)&ci)) {
+ ShellExecuteA(hwnd, "open", (LPCSTR)ci.pszVal, NULL, NULL, SW_SHOW);
+ mir_free(ci.pszVal);
+ }
+ return TRUE;
+ }
+ }
+ }
+ }
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ if (hitFlags & CLCHT_ONAVATAR && cfg::dat.bDblClkAvatars) {
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)contact->hContact, 0);
+ return TRUE;
+ }
+ if (hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMSPACE)) {
+ UpdateWindow(hwnd);
+ pcli->pfnDoSelectionDefaultAction(hwnd, dat);
+ }
+ return TRUE;
+ }
+ case WM_CONTEXTMENU: {
+ struct ClcContact *contact;
+ HMENU hMenu = NULL;
+ POINT pt;
+ DWORD hitFlags;
+
+ pcli->pfnEndRename(hwnd, dat, 1);
+ pcli->pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ dat->iHotTrack = -1;
+ dat->szQuickSearch[0] = 0;
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ if (pt.x == -1 && pt.y == -1) {
+ dat->selection = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (dat->selection != -1)
+ pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ pt.x = dat->iconXSpace + 15;
+ pt.y = RowHeight::getItemTopY(dat, dat->selection) - dat->yScroll + (int)(dat->row_heights[dat->selection] * .7);
+ hitFlags = dat->selection == -1 ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL;
+ } else {
+ ScreenToClient(hwnd, &pt);
+ dat->selection = HitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags);
+ }
+ InvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+
+ if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) {
+ if (contact->type == CLCIT_GROUP) {
+ HMENU hMenu = Menu_BuildSubGroupMenu(contact->group);
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, pcli->hwndContactList, NULL);
+ CheckMenuItem(hMenu, POPUP_GROUPHIDEOFFLINE, contact->group->hideOffline ? MF_CHECKED : MF_UNCHECKED);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ else if (contact->type == CLCIT_CONTACT)
+ hMenu = Menu_BuildContactMenu(contact->hContact);
+ } else {
+ //call parent for new group/hide offline menu
+ PostMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam);
+ return 0;
+ }
+ if (hMenu != NULL) {
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_COMMAND:
+ if (LOWORD(wParam) == POPUP_NEWGROUP)
+ SendMessage(GetParent(hwnd), msg, wParam, lParam);
+ break;
+
+ case WM_MOUSEMOVE: {
+ int iOldHT = dat->iHotTrack;
+ LRESULT result = saveContactListControlWndProc(hwnd, msg, wParam, lParam);
+ if(dat->iHotTrack != iOldHT)
+ InvalidateRect(hwnd, 0, FALSE);
+ return(result);
+ }
+
+ case WM_NCHITTEST: {
+ LRESULT lr = SendMessage(GetParent(hwnd), WM_NCHITTEST, wParam, lParam);
+ if (lr == HTLEFT || lr == HTRIGHT || lr == HTBOTTOM || lr == HTTOP || lr == HTTOPLEFT || lr == HTTOPRIGHT
+ || lr == HTBOTTOMLEFT || lr == HTBOTTOMRIGHT)
+ return HTTRANSPARENT;
+ break;
+ }
+ case WM_DESTROY: {
+ int i;
+
+ if (!dat->bisEmbedded) {
+ for (i = 0; i < cfg::nextCacheEntry; i++) {
+ if (cfg::eCache[i].floater && cfg::eCache[i].floater->hwnd)
+ DestroyWindow(cfg::eCache[i].floater->hwnd);
+ }
+ }
+ RowHeight::Free(dat);
+ if(dat->ph) {
+ delete dat->ph;
+ dat->ph = 0;
+ }
+ break;
+ }
+ }
+
+ {
+ LRESULT result = coreCli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ return result;
+ }
+}
+
+int CLC::findItem(HWND hwnd, ClcData *dat, HANDLE hItem, ClcContact **contact, ClcGroup **subgroup, int *isVisible)
+{
+ int index = 0;
+ int nowVisible = 1;
+ ClcGroup *group = &dat->list;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ ClcGroup *tgroup;
+ group = group->parent;
+ if (group == NULL)
+ break;
+ nowVisible = 1;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent) {
+ if (!(group->expanded)) {
+ nowVisible = 0; break;
+ }
+ }
+ group->scanIndex++;
+ continue;
+ }
+ if (nowVisible)
+ index++;
+ if ((IsHContactGroup(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_GROUP && ((UINT_PTR)hItem & ~HCONTACT_ISGROUP) == group->cl.items[group->scanIndex]->groupId) ||
+ (IsHContactContact(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_CONTACT && group->cl.items[group->scanIndex]->hContact == (MCONTACT)hItem) ||
+ (IsHContactInfo(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_INFO && group->cl.items[group->scanIndex]->hContact == (MCONTACT)((UINT_PTR)hItem & ~HCONTACT_ISINFO)))
+ {
+ if (isVisible) {
+ if (!nowVisible)
+ *isVisible = 0;
+ else {
+ int posy = RowHeight::getItemTopY(dat, index + 1);
+ if (posy < dat->yScroll)
+ *isVisible = 0;
+ //if ((index + 1) * dat->rowHeight< dat->yScroll)
+ // *isVisible = 0;
+ else {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ //if (index * dat->rowHeight >= dat->yScroll + clRect.bottom)
+ if (posy >= dat->yScroll + clRect.bottom)
+ *isVisible = 0;
+ else
+ *isVisible = 1;
+ }
+ }
+ }
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return 1;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ nowVisible &= (group->expanded);
+ continue;
+ }
+ group->scanIndex++;
+ }
+
+ if (isVisible) *isVisible = FALSE;
+ if (contact) *contact = NULL;
+ if (subgroup) *subgroup = NULL;
+ return 0;
+}
+
+void CLC::countAvatars(ClcData *dat)
+{
+ if(dat->bisEmbedded)
+ return;
+
+ CLC::uNrAvatars = 0;
+ ClcGroup* group;
+
+ group = &dat->list;
+ group->scanIndex = 0;
+
+ while(TRUE) {
+ if (group->scanIndex==group->cl.count)
+ {
+ group=group->parent;
+ if(group==NULL)
+ break; // Finished list
+ group->scanIndex++;
+ continue;
+ }
+
+ if(group->cl.items[group->scanIndex]->cFlags & ECF_AVATAR)
+ CLC::uNrAvatars++;
+
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded)) {
+ group=group->cl.items[group->scanIndex]->group;
+ group->scanIndex=0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+}
diff --git a/plugins/Clist_ng/SRC/clcitems.cpp b/plugins/Clist_ng/SRC/clcitems.cpp new file mode 100644 index 0000000000..99aadd11c7 --- /dev/null +++ b/plugins/Clist_ng/SRC/clcitems.cpp @@ -0,0 +1,543 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clcitems.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <m_icq.h>
+
+extern HANDLE hExtraImageListRebuilding, hExtraImageApplying;
+
+static void TZ_LoadTimeZone(MCONTACT hContact, struct TExtraCache *c, const char *szProto);
+
+//routines for managing adding/removal of items in the list, including sorting
+
+ClcContact* CLC::CreateClcContact()
+{
+ struct ClcContact* p = (struct ClcContact*)mir_alloc( sizeof( struct ClcContact ) );
+ if ( p != NULL ) {
+ ZeroMemory(p, sizeof(struct ClcContact));
+ //p->clientId = -1;
+ p->extraCacheEntry = -1;
+ p->avatarLeft = p->extraIconRightBegin = -1;
+ p->isRtl = 0;
+ p->ace = 0;
+ }
+ return p;
+}
+
+int CLC::AddInfoItemToGroup(ClcGroup *group, int flags, const wchar_t *pszText)
+{
+ int i = coreCli.pfnAddInfoItemToGroup(group, flags, pszText);
+ ClcContact* p = group->cl.items[i];
+ p->bIsMeta = 0;
+ p->xStatus = 0;
+ p->ace = NULL;
+ p->extraCacheEntry = -1;
+ p->avatarLeft = p->extraIconRightBegin = -1;
+ return i;
+}
+
+ClcGroup* CLC::AddGroup(HWND hwnd, struct ClcData *dat, const wchar_t *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ struct ClcGroup *p = coreCli.pfnAddGroup( hwnd, dat, szName, flags, groupId, calcTotalMembers);
+
+ if ( p && p->parent )
+ RTL_DetectGroupName( p->parent->cl.items[ p->parent->cl.count-1] );
+ return p;
+}
+
+ClcGroup* CLC::RemoveItemFromGroup(HWND hwnd, ClcGroup *group, ClcContact *contact, int updateTotalCount)
+{
+ if(contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry) {
+ if(cfg::eCache[contact->extraCacheEntry].floater && cfg::eCache[contact->extraCacheEntry].floater->hwnd)
+ ShowWindow(cfg::eCache[contact->extraCacheEntry].floater->hwnd, SW_HIDE);
+ }
+ return(coreCli.pfnRemoveItemFromGroup(hwnd, group, contact, updateTotalCount));
+}
+
+void LoadAvatarForContact(struct ClcContact *p)
+{
+ if(cfg::dat.dwFlags & CLUI_FRAME_AVATARS)
+ p->cFlags = (p->dwDFlags & ECF_HIDEAVATAR ? p->cFlags & ~ECF_AVATAR : p->cFlags | ECF_AVATAR);
+ else
+ p->cFlags = (p->dwDFlags & ECF_FORCEAVATAR ? p->cFlags | ECF_AVATAR : p->cFlags & ~ECF_AVATAR);
+
+ p->ace = NULL;
+ if(/*(p->cFlags & ECF_AVATAR) && */(!cfg::dat.bNoOfflineAvatars || p->wStatus != ID_STATUS_OFFLINE)) {
+ p->ace = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)p->hContact, 0);
+ if(CALLSERVICE_NOTFOUND == (INT_PTR)p->ace)
+ p->ace = 0;
+ if (p->ace != NULL && p->ace->cbSize != sizeof(struct avatarCacheEntry))
+ p->ace = NULL;
+ if (p->ace != NULL)
+ p->ace->t_lastAccess = cfg::dat.t_now;
+ }
+ if(p->ace == NULL)
+ p->cFlags &= ~ECF_AVATAR;
+}
+
+int CLC::AddContactToGroup(struct ClcData *dat, struct ClcGroup *group, MCONTACT hContact)
+{
+ int i = coreCli.pfnAddContactToGroup( dat, group, hContact );
+ struct ClcContact* p = group->cl.items[i];
+
+ p->wStatus = cfg::getWord(hContact, p->proto, "Status", ID_STATUS_OFFLINE);
+ p->xStatus = cfg::getByte(hContact, p->proto, "XStatusId", 0);
+ //p->iRowHeight = -1;
+
+ if (p->proto)
+ p->bIsMeta = !strcmp(p->proto, cfg::dat.szMetaName);
+ else
+ p->bIsMeta = FALSE;
+ if (p->bIsMeta && cfg::dat.bMetaAvail) {
+ p->hSubContact = db_mc_getMostOnline(hContact);
+ p->metaProto = GetContactProto(p->hSubContact);
+ p->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) p->hSubContact, 0);
+ } else {
+ p->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) hContact, 0);
+ p->metaProto = NULL;
+ }
+ p->bSecondLine = cfg::dat.dualRowMode;
+ p->bSecondLineLocal = cfg::getByte(hContact, "CList", "CLN_2ndline", -1);
+
+ p->dwDFlags = cfg::getDword(hContact, "CList", "CLN_Flags", 0);
+
+ if(dat->bisEmbedded)
+ p->extraCacheEntry = -1;
+ else {
+ p->extraCacheEntry = cfg::getCache(p->hContact, p->proto);
+ GetExtendedInfo( p, dat);
+ if(p->extraCacheEntry >= 0 && p->extraCacheEntry < cfg::nextCacheEntry) {
+ cfg::eCache[p->extraCacheEntry].proto_status_item = GetProtocolStatusItem(p->bIsMeta ? p->metaProto : p->proto);
+ if(cfg::getByte(p->hContact, "CList", "floating", 0) && g_floatoptions.enabled) {
+ if(cfg::eCache[p->extraCacheEntry].floater == NULL)
+ FLT_Create(p->extraCacheEntry);
+ else {
+ ShowWindow(cfg::eCache[p->extraCacheEntry].floater->hwnd, SW_SHOWNOACTIVATE);
+ FLT_Update(dat, p);
+ }
+ }
+ }
+ LoadAvatarForContact(p);
+ // notify other plugins to re-supply their extra images (icq for xstatus, mBirthday etc...)
+ pcli->pfnSetAllExtraIcons(hContact);
+ }
+ RTL_DetectAndSet( p, p->hContact);
+ p->avatarLeft = p->extraIconRightBegin = -1;
+ p->flags |= cfg::getByte(p->hContact, "CList", "Priority", 0) ? CONTACTF_PRIORITY : 0;
+
+ return i;
+}
+
+void CLC::RebuildEntireList(HWND hwnd, ClcData *dat)
+{
+ char *szProto;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ MCONTACT hContact;
+ ClcGroup *group;
+ DBVARIANT dbv = {0};
+
+ RowHeight::Clear(dat);
+ RowHeight::getMaxRowHeight(dat, hwnd);
+
+ dat->list.expanded = 1;
+ dat->list.hideOffline = cfg::getByte("CLC", "HideOfflineRoot", 0);
+ dat->list.cl.count = 0;
+ dat->list.totalMembers = 0;
+ dat->selection = -1;
+ dat->SelectMode = cfg::getByte("CLC", "SelectMode", 0); {
+ int i;
+ wchar_t *szGroupName;
+ DWORD groupFlags;
+
+ for (i = 1; ; i++) {
+ szGroupName = pcli->pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL)
+ break;
+ pcli->pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
+ }
+ }
+
+ hContact = db_find_first();
+ while (hContact) {
+ if (style & CLS_SHOWHIDDEN || !CLVM_GetContactHiddenStatus(hContact, NULL, dat)) {
+ ZeroMemory((void *)&dbv, sizeof(dbv));
+ if (cfg::getTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = pcli->pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ mir_free(dbv.ptszVal);
+ }
+
+ if (group != NULL) {
+ group->totalMembers++;
+ if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ szProto = GetContactProto(hContact);
+ if (szProto == NULL) {
+ if (!pcli->pfnIsHiddenMode(dat, ID_STATUS_OFFLINE))
+ AddContactToGroup(dat, group, hContact);
+ } else if (!pcli->pfnIsHiddenMode(dat, (WORD) cfg::getWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ AddContactToGroup(dat, group, hContact);
+ } else
+ AddContactToGroup(dat, group, hContact);
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ if (style & CLS_HIDEEMPTYGROUPS) {
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (; ;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ } else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group->cl.count == 0) {
+ group = pcli->pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
+ } else {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ }
+ continue;
+ }
+ group->scanIndex++;
+ }
+ }
+ pcli->pfnSortCLC(hwnd, dat, 0);
+ pcli->pfnSetAllExtraIcons(NULL);
+ if(!dat->bisEmbedded)
+ FLT_SyncWithClist();
+}
+
+/*
+ * status msg in the database has changed.
+ * get it and store it properly formatted in the extra data cache
+ */
+
+BYTE GetCachedStatusMsg(int iExtraCacheEntry, char *szProto)
+{
+ DBVARIANT dbv = {0};
+ MCONTACT hContact;
+ TExtraCache *cEntry;
+ int result;
+
+ if(iExtraCacheEntry < 0 || iExtraCacheEntry > cfg::nextCacheEntry)
+ return 0;
+
+ cEntry = &cfg::eCache[iExtraCacheEntry];
+
+ cEntry->bStatusMsgValid = STATUSMSG_NOTFOUND;
+ hContact = cEntry->hContact;
+
+ result = cfg::getTString(hContact, "CList", "StatusMsg", &dbv);
+ if ( !result && lstrlen(dbv.ptszVal) > 1)
+ cEntry->bStatusMsgValid = STATUSMSG_CLIST;
+ else {
+ if (!szProto)
+ szProto = GetContactProto(hContact);
+ if(szProto) {
+ if ( !result )
+ db_free(&dbv);
+ if( !( result = cfg::getTString(hContact, szProto, "YMsg", &dbv)) && lstrlen(dbv.ptszVal) > 1)
+ cEntry->bStatusMsgValid = STATUSMSG_YIM;
+ else if ( !(result = cfg::getTString(hContact, szProto, "StatusDescr", &dbv)) && lstrlen(dbv.ptszVal) > 1)
+ cEntry->bStatusMsgValid = STATUSMSG_GG;
+ else if( !(result = cfg::getTString(hContact, szProto, "XStatusMsg", &dbv)) && lstrlen(dbv.ptszVal) > 1)
+ cEntry->bStatusMsgValid = STATUSMSG_XSTATUS;
+ } }
+
+ if(cEntry->bStatusMsgValid == STATUSMSG_NOTFOUND) { // no status msg, consider xstatus name (if available)
+ if ( !result )
+ db_free( &dbv );
+ result = cfg::getTString(hContact, szProto, "XStatusName", &dbv);
+ if ( !result && lstrlen(dbv.ptszVal) > 1) {
+ int iLen = lstrlen(dbv.ptszVal);
+ cEntry->bStatusMsgValid = STATUSMSG_XSTATUSNAME;
+ cEntry->statusMsg = (wchar_t *)realloc(cEntry->statusMsg, (iLen + 2) * sizeof(wchar_t));
+ _tcsncpy(cEntry->statusMsg, dbv.ptszVal, iLen + 1);
+ }
+ else {
+ int xStatus;
+ WPARAM xStatus2;
+ wchar_t xStatusName[128];
+
+ CUSTOM_STATUS cst = { sizeof(cst) };
+ cst.flags = CSSF_MASK_STATUS;
+ cst.status = &xStatus;
+ if (ProtoServiceExists(szProto, PS_GETCUSTOMSTATUSEX) && !CallProtoService(szProto, PS_GETCUSTOMSTATUSEX, hContact, (LPARAM)&cst) && xStatus > 0) {
+ cst.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR;
+ cst.wParam = &xStatus2;
+ cst.ptszName = xStatusName;
+ if (!CallProtoService(szProto, PS_GETCUSTOMSTATUSEX, hContact, (LPARAM)&cst)) {
+ wchar_t *szwXstatusName = TranslateTS(xStatusName);
+ cEntry->statusMsg = (wchar_t *)realloc(cEntry->statusMsg, (lstrlen(szwXstatusName) + 2) * sizeof(wchar_t));
+ _tcsncpy(cEntry->statusMsg, szwXstatusName, lstrlen(szwXstatusName) + 1);
+ cEntry->bStatusMsgValid = STATUSMSG_XSTATUSNAME;
+ }
+ }
+ }
+ }
+ if(cEntry->bStatusMsgValid > STATUSMSG_XSTATUSNAME) {
+ int j = 0, i;
+ cEntry->statusMsg = (wchar_t *)realloc(cEntry->statusMsg, (lstrlen(dbv.ptszVal) + 2) * sizeof(wchar_t));
+ for(i = 0; dbv.ptszVal[i]; i++) {
+ if(dbv.ptszVal[i] == (wchar_t)0x0d)
+ continue;
+ cEntry->statusMsg[j] = dbv.ptszVal[i] == (wchar_t)0x0a ? (wchar_t)' ' : dbv.ptszVal[i];
+ j++;
+ }
+ cEntry->statusMsg[j] = (wchar_t)0;
+ }
+ if ( !result )
+ db_free( &dbv );
+
+ if(cEntry->bStatusMsgValid != STATUSMSG_NOTFOUND) {
+ WORD infoTypeC2[12];
+ int iLen, i
+ ;
+ ZeroMemory(infoTypeC2, sizeof(WORD) * 12);
+ iLen = min(lstrlenW(cEntry->statusMsg), 10);
+ GetStringTypeW(CT_CTYPE2, cEntry->statusMsg, iLen, infoTypeC2);
+ cEntry->dwCFlags &= ~ECF_RTLSTATUSMSG;
+ for(i = 0; i < 10; i++) {
+ if(infoTypeC2[i] == C2_RIGHTTOLEFT) {
+ cEntry->dwCFlags |= ECF_RTLSTATUSMSG;
+ break;
+ }
+ }
+ }
+ if(cEntry->hTimeZone == 0)
+ TZ_LoadTimeZone(hContact, cEntry, szProto);
+ return cEntry->bStatusMsgValid;;
+}
+
+/*
+ * load time zone information for the contact
+ * if TzName is set, use it. It has to be a standard windows time zone name
+ * Currently, it can only be set by using UserInfoEx plugin
+ *
+ * Fallback: use ordinary GMT offsets (incorrect, in some cases due to DST
+ * differences.
+ */
+
+static void TZ_LoadTimeZone(MCONTACT hContact, TExtraCache *c, const char *szProto)
+{
+ DWORD flags = 0;
+ if (cfg::dat.bShowLocalTimeSelective) flags |= TZF_DIFONLY;
+ c->hTimeZone = TimeZone_CreateByContact(hContact, 0, flags);
+}
+
+void ReloadExtraInfo(MCONTACT hContact)
+{
+ if(hContact && pcli->hwndContactTree) {
+ int index = cfg::getCache(hContact, NULL);
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ char *szProto = GetContactProto(hContact);
+
+ TZ_LoadTimeZone(hContact, &cfg::eCache[index], szProto);
+ InvalidateRect(pcli->hwndContactTree, NULL, FALSE);
+ }
+ }
+}
+
+/*
+ * autodetect RTL property of the nickname, evaluates the first 10 characters of the nickname only
+ */
+
+void RTL_DetectAndSet(struct ClcContact *contact, MCONTACT hContact)
+{
+ WORD infoTypeC2[12];
+ int i, index;
+ wchar_t *szText = NULL;
+ DWORD iLen;
+
+ ZeroMemory(infoTypeC2, sizeof(WORD) * 12);
+
+ if(contact == NULL) {
+ szText = pcli->pfnGetContactDisplayName(hContact, 0);
+ index = cfg::getCache(hContact, NULL);
+ }
+ else {
+ szText = contact->szText;
+ index = contact->extraCacheEntry;
+ }
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ iLen = min(lstrlenW(szText), 10);
+ GetStringTypeW(CT_CTYPE2, szText, iLen, infoTypeC2);
+ cfg::eCache[index].dwCFlags &= ~ECF_RTLNICK;
+ for(i = 0; i < 10; i++) {
+ if(infoTypeC2[i] == C2_RIGHTTOLEFT) {
+ cfg::eCache[index].dwCFlags |= ECF_RTLNICK;
+ return;
+ }
+ }
+ }
+}
+
+void RTL_DetectGroupName(struct ClcContact *group)
+{
+ WORD infoTypeC2[12];
+ int i;
+ DWORD iLen;
+
+ group->isRtl = 0;
+
+ if(group->szText) {
+ iLen = min(lstrlenW(group->szText), 10);
+ GetStringTypeW(CT_CTYPE2, group->szText, iLen, infoTypeC2);
+ for(i = 0; i < 10; i++) {
+ if(infoTypeC2[i] == C2_RIGHTTOLEFT) {
+ group->isRtl = 1;
+ return;
+ }
+ }
+ }
+}
+/*
+ * check for exteneded user information - email, phone numbers, homepage
+ * set extra icons accordingly
+ */
+
+void GetExtendedInfo(struct ClcContact *contact, struct ClcData *dat)
+{
+ int index;
+
+ if(dat->bisEmbedded || contact == NULL)
+ return;
+
+ if(contact->proto == NULL || contact->hContact == 0)
+ return;
+
+ index = contact->extraCacheEntry;
+
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ if(cfg::eCache[index].valid)
+ return;
+ cfg::eCache[index].valid = TRUE;
+ }
+ else
+ return;
+ cfg::eCache[index].isChatRoom = cfg::getByte(contact->hContact, contact->proto, "ChatRoom", 0);
+ cfg::eCache[index].msgFrequency = cfg::getDword(contact->hContact, "CList", "mf_freq", 0x7fffffff);
+
+}
+
+DWORD CalcXMask(MCONTACT hContact)
+{
+ DWORD dwXMask = cfg::getDword(hContact, "CList", "CLN_xmask", 0);
+ int i;
+ DWORD dwResult = cfg::dat.dwExtraImageMask, bForced, bHidden;
+
+ for(i = 0; i <= 10; i++) {
+ bForced = (dwXMask & (1 << (2 * i)));
+ bHidden = (dwXMask & (1 << (2 * i + 1)));
+ if(bForced == 0 && bHidden == 0)
+ continue;
+ else if(bForced)
+ dwResult |= (1 << i);
+ else if(bHidden)
+ dwResult &= ~(1 << i);
+ }
+ return(dwResult);
+}
+
+/*
+ * checks the currently active view mode filter and returns true, if the contact should be hidden
+ * if no view mode is active, it returns the CList/Hidden setting
+ * also cares about sub contacts (if meta is active)
+ */
+
+int __fastcall CLVM_GetContactHiddenStatus(MCONTACT hContact, char *szProto, struct ClcData *dat)
+{
+ int dbHidden = cfg::getByte(hContact, "CList", "Hidden", 0); // default hidden state, always respect it.
+ int filterResult = 1;
+ DBVARIANT dbv = {0};
+ char szTemp[64];
+ wchar_t szGroupMask[256];
+ DWORD dwLocalMask;
+
+ // always hide subcontacts (but show them on embedded contact lists)
+
+ if(cfg::dat.bMetaAvail && dat != NULL && dat->bHideSubcontacts && cfg::dat.bMetaEnabled && cfg::getByte(hContact, cfg::dat.szMetaName, "IsSubcontact", 0))
+ return 1;
+
+ if(cfg::dat.bFilterEffective) {
+ if (szProto == NULL)
+ szProto = GetContactProto(hContact);
+ // check stickies first (priority), only if we really have stickies defined (CLVM_STICKY_CONTACTS is set).
+ if(cfg::dat.bFilterEffective & CLVM_STICKY_CONTACTS) {
+ if((dwLocalMask = cfg::getDword(hContact, "CLVM", cfg::dat.current_viewmode, 0)) != 0) {
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_STICKYSTATUS) {
+ WORD wStatus = cfg::getWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ return !((1 << (wStatus - ID_STATUS_OFFLINE)) & HIWORD(dwLocalMask));
+ }
+ return 0;
+ }
+ }
+ // check the proto, use it as a base filter result for all further checks
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_PROTOS) {
+ mir_snprintf(szTemp, sizeof(szTemp), "%s|", szProto);
+ filterResult = strstr(cfg::dat.protoFilter, szTemp) ? 1 : 0;
+ }
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_GROUPS) {
+ if(!cfg::getTString(hContact, "CList", "Group", &dbv)) {
+ _sntprintf(szGroupMask, safe_sizeof(szGroupMask), _T("%s|"), &dbv.ptszVal[1]);
+ filterResult = (cfg::dat.filterFlags & CLVM_PROTOGROUP_OP) ? (filterResult | (_tcsstr(cfg::dat.groupFilter, szGroupMask) ? 1 : 0)) : (filterResult & (_tcsstr(cfg::dat.groupFilter, szGroupMask) ? 1 : 0));
+ mir_free(dbv.ptszVal);
+ }
+ else if(cfg::dat.filterFlags & CLVM_INCLUDED_UNGROUPED)
+ filterResult = (cfg::dat.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 1;
+ else
+ filterResult = (cfg::dat.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 0;
+ }
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_STATUS) {
+ WORD wStatus = cfg::getWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ filterResult = (cfg::dat.filterFlags & CLVM_GROUPSTATUS_OP) ? ((filterResult | ((1 << (wStatus - ID_STATUS_OFFLINE)) & cfg::dat.statusMaskFilter ? 1 : 0))) : (filterResult & ((1 << (wStatus - ID_STATUS_OFFLINE)) & cfg::dat.statusMaskFilter ? 1 : 0));
+ }
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_LASTMSG) {
+ DWORD now;
+ int iEntry = cfg::getCache(hContact, szProto);
+ if(iEntry >= 0 && iEntry <= cfg::nextCacheEntry) {
+ now = cfg::dat.t_now;
+ now -= cfg::dat.lastMsgFilter;
+ if(cfg::dat.bFilterEffective & CLVM_FILTER_LASTMSG_OLDERTHAN)
+ filterResult = filterResult & (cfg::eCache[iEntry].dwLastMsgTime < now);
+ else if(cfg::dat.bFilterEffective & CLVM_FILTER_LASTMSG_NEWERTHAN)
+ filterResult = filterResult & (cfg::eCache[iEntry].dwLastMsgTime > now);
+ }
+ }
+ return (dbHidden | !filterResult);
+ }
+ else
+ return dbHidden;
+}
diff --git a/plugins/Clist_ng/SRC/clcmsgs.cpp b/plugins/Clist_ng/SRC/clcmsgs.cpp new file mode 100644 index 0000000000..f8b52b27f2 --- /dev/null +++ b/plugins/Clist_ng/SRC/clcmsgs.cpp @@ -0,0 +1,211 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_nicer plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clcmsgs.cpp 132 2010-09-29 07:49:20Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+//processing of all the CLM_ messages incoming
+
+LRESULT CLC::ProcessExternalMessages(HWND hwnd, ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case CLM_SETSTICKY:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+
+ if (wParam == 0 || !findItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ return 0;
+ if (lParam)
+ contact->flags |= CONTACTF_STICKY;
+ else
+ contact->flags &= ~CONTACTF_STICKY;
+ break;
+ }
+
+ case CLM_SETEXTRAIMAGEINT:
+ {
+ struct ClcContact *contact = NULL;
+ int index = -1;
+
+ if (LOWORD(lParam) >= MAXEXTRACOLUMNS || wParam == 0)
+ return 0;
+
+ if (!findItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+
+ index = contact->extraCacheEntry;
+
+ if(contact->type != CLCIT_CONTACT) // || contact->bIsMeta)
+ return 0;
+
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ cfg::eCache[index].iExtraImage[LOWORD(lParam)] = (BYTE)HIWORD(lParam);
+ cfg::eCache[index].iExtraValid = cfg::eCache[index].iExtraImage[LOWORD(lParam)] != (BYTE)0xff ? (cfg::eCache[index].iExtraValid | (1 << LOWORD(lParam))) : (cfg::eCache[index].iExtraValid & ~(1 << LOWORD(lParam)));
+ PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contact ? contact->hContact : 0));
+ }
+ }
+ return 0;
+ case CLM_SETEXTRAIMAGEINTMETA:
+ {
+ MCONTACT hMasterContact = 0;
+ int index = -1;
+
+ if (LOWORD(lParam) >= MAXEXTRACOLUMNS)
+ return 0;
+
+ index = cfg::getCache(wParam, NULL);
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ cfg::eCache[index].iExtraImage[LOWORD(lParam)] = (BYTE)HIWORD(lParam);
+ cfg::eCache[index].iExtraValid = cfg::eCache[index].iExtraImage[LOWORD(lParam)] != (BYTE)0xff ? (cfg::eCache[index].iExtraValid | (1 << LOWORD(lParam))) : (cfg::eCache[index].iExtraValid & ~(1 << LOWORD(lParam)));
+ }
+
+ hMasterContact = cfg::getDword(wParam, cfg::dat.szMetaName, "Handle", 0);
+
+ index = cfg::getCache(hMasterContact, NULL);
+ if(index >= 0 && index < cfg::nextCacheEntry) {
+ cfg::eCache[index].iExtraImage[LOWORD(lParam)] = (BYTE)HIWORD(lParam);
+ cfg::eCache[index].iExtraValid = cfg::eCache[index].iExtraImage[LOWORD(lParam)] != (BYTE)0xff ? (cfg::eCache[index].iExtraValid | (1 << LOWORD(lParam))) : (cfg::eCache[index].iExtraValid & ~(1 << LOWORD(lParam)));
+ PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
+ }
+ }
+ return 0;
+
+ case CLM_GETSTATUSMSG:
+ {
+ ClcContact *contact = NULL;
+
+ if (wParam == 0)
+ return 0;
+
+ if (!findItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
+ return 0;
+ if(contact->type != CLCIT_CONTACT)
+ return 0;
+ if(contact->extraCacheEntry >= 0 && contact->extraCacheEntry <= cfg::nextCacheEntry) {
+ if(cfg::eCache[contact->extraCacheEntry].bStatusMsgValid != STATUSMSG_NOTFOUND)
+ return((INT_PTR)cfg::eCache[contact->extraCacheEntry].statusMsg);
+ } }
+ return 0;
+
+ case CLM_SETHIDESUBCONTACTS:
+ dat->bHideSubcontacts = (BOOL)lParam;
+ return 0;
+
+ case CLM_TOGGLEPRIORITYCONTACT:
+ {
+ struct ClcContact *contact = NULL;
+
+ if (wParam == 0)
+ return 0;
+
+ if (!findItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
+ return 0;
+ if(contact->type != CLCIT_CONTACT)
+ return 0;
+ contact->flags ^= CONTACTF_PRIORITY;
+ cfg::writeByte(contact->hContact, "CList", "Priority", (BYTE)(contact->flags & CONTACTF_PRIORITY ? 1 : 0));
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ return 0;
+ }
+ case CLM_QUERYPRIORITYCONTACT:
+ {
+ struct ClcContact *contact = NULL;
+
+ if (wParam == 0)
+ return 0;
+
+ if (!findItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
+ return 0;
+ if(contact->type != CLCIT_CONTACT)
+ return 0;
+ return(contact->flags & CONTACTF_PRIORITY ? 1 : 0);
+ }
+ case CLM_TOGGLEFLOATINGCONTACT:
+ {
+ struct ClcContact *contact = NULL;
+ BYTE state;
+ int iEntry;
+
+ if (wParam == 0)
+ return 0;
+
+ if (!findItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
+ return 0;
+ if(contact->type != CLCIT_CONTACT)
+ return 0;
+
+ iEntry = contact->extraCacheEntry;
+
+ if(iEntry >= 0 && iEntry <= cfg::nextCacheEntry) {
+ state = !cfg::getByte(contact->hContact, "CList", "floating", 0);
+ if(state) {
+ if(cfg::eCache[iEntry].floater == NULL)
+ FLT_Create(iEntry);
+ ShowWindow(cfg::eCache[contact->extraCacheEntry].floater->hwnd, SW_SHOW);
+ }
+ else {
+ if(cfg::eCache[iEntry].floater && cfg::eCache[iEntry].floater->hwnd) {
+ DestroyWindow(cfg::eCache[iEntry].floater->hwnd);
+ cfg::eCache[iEntry].floater = 0;
+ }
+ }
+ cfg::writeByte(contact->hContact, "CList", "floating", state);
+ }
+ return 0;
+ }
+ case CLM_QUERYFLOATINGCONTACT:
+ {
+ return(cfg::getByte(wParam, "CList", "floating", 0));
+ }
+ case CLM_SETEXTRAIMAGELIST:
+ dat->himlExtraColumns = (HIMAGELIST) lParam;
+ InvalidateRect(hwnd, NULL, FALSE);
+ return 0;
+
+ case CLM_SETFONT:
+ if(HIWORD(lParam)<0 || HIWORD(lParam)>FONTID_LAST)
+ return 0;
+ dat->fontInfo[HIWORD(lParam)].hFont = (HFONT)wParam;
+ dat->fontInfo[HIWORD(lParam)].changed = 1;
+
+ RowHeight::getMaxRowHeight(dat, hwnd);
+
+ if(LOWORD(lParam))
+ InvalidateRect(hwnd,NULL,FALSE);
+ return 0;
+
+ case CLM_ISMULTISELECT:
+ return dat->isMultiSelect;
+ }
+
+ return coreCli.pfnProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+}
diff --git a/plugins/Clist_ng/SRC/clcopts.cpp b/plugins/Clist_ng/SRC/clcopts.cpp new file mode 100644 index 0000000000..2c4e81ae39 --- /dev/null +++ b/plugins/Clist_ng/SRC/clcopts.cpp @@ -0,0 +1,1408 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_n plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clcopts.cpp 136 2010-10-12 18:55:36Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include "../coolsb/coolscroll.h"
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+struct CheckBoxToStyleEx_t {
+ int id;
+ DWORD flag;
+ int not_t;
+} static const checkBoxToStyleEx[] = {
+ {IDC_DISABLEDRAGDROP, CLS_EX_DISABLEDRAGDROP, 0}, {IDC_NOTEDITLABELS, CLS_EX_EDITLABELS, 1},
+ {IDC_SHOWSELALWAYS, CLS_EX_SHOWSELALWAYS, 0}, {IDC_TRACKSELECT, CLS_EX_TRACKSELECT, 0},
+ {IDC_DIVIDERONOFF, CLS_EX_DIVIDERONOFF, 0}, {IDC_NOTNOTRANSLUCENTSEL, CLS_EX_NOTRANSLUCENTSEL, 1},
+ {IDC_NOTNOSMOOTHSCROLLING, CLS_EX_NOSMOOTHSCROLLING, 1}
+};
+
+struct CheckBoxToGroupStyleEx_t {
+ int id;
+ DWORD flag;
+ int not_t;
+} static const checkBoxToGroupStyleEx[] = {
+ {IDC_SHOWGROUPCOUNTS, CLS_EX_SHOWGROUPCOUNTS, 0}, {IDC_HIDECOUNTSWHENEMPTY, CLS_EX_HIDECOUNTSWHENEMPTY, 0},
+ {IDC_LINEWITHGROUPS, CLS_EX_LINEWITHGROUPS, 0}, {IDC_QUICKSEARCHVISONLY, CLS_EX_QUICKSEARCHVISONLY, 0},
+ {IDC_SORTGROUPSALPHA, CLS_EX_SORTGROUPSALPHA, 0}
+};
+
+struct CheckBoxValues_t {
+ DWORD style;
+ wchar_t *szDescr;
+};
+
+static const struct CheckBoxValues_t greyoutValues[] = {
+ { GREYF_UNFOCUS, LPGENT("Not focused")},
+ { MODEF_OFFLINE, LPGENT("Offline")},
+ { PF2_ONLINE, LPGENT("Online")},
+ { PF2_SHORTAWAY, LPGENT("Away")},
+ { PF2_LONGAWAY, LPGENT("NA")},
+ { PF2_LIGHTDND, LPGENT("Occupied")},
+ { PF2_HEAVYDND, LPGENT("DND")},
+ { PF2_FREECHAT, LPGENT("Free for chat")},
+ { PF2_INVISIBLE, LPGENT("Invisible")},
+ { PF2_OUTTOLUNCH, LPGENT("Out to lunch")},
+ { PF2_ONTHEPHONE, LPGENT("On the phone")}
+};
+
+static const struct CheckBoxValues_t offlineValues[] = {
+ { MODEF_OFFLINE, LPGENT("Offline")},
+ { PF2_ONLINE, LPGENT("Online")},
+ { PF2_SHORTAWAY, LPGENT("Away")},
+ { PF2_LONGAWAY, LPGENT("NA")},
+ { PF2_LIGHTDND, LPGENT("Occupied")},
+ { PF2_HEAVYDND, LPGENT("DND")},
+ { PF2_FREECHAT, LPGENT("Free for chat")},
+ { PF2_INVISIBLE, LPGENT("Invisible")},
+ { PF2_OUTTOLUNCH, LPGENT("Out to lunch")},
+ { PF2_ONTHEPHONE, LPGENT("On the phone")}
+};
+
+static HIMAGELIST himlCheckBoxes = 0;
+
+static HIMAGELIST CreateStateImageList()
+{
+ if(0 == himlCheckBoxes) {
+ HICON hIconNoTick = Skin_LoadIcon(SKINICON_OTHER_NOTICK);
+ HICON hIconTick = Skin_LoadIcon(SKINICON_OTHER_TICK);
+
+ himlCheckBoxes = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 2, 2);
+ ImageList_AddIcon(himlCheckBoxes, hIconNoTick);
+ ImageList_AddIcon(himlCheckBoxes, hIconTick);
+ ImageList_AddIcon(himlCheckBoxes, hIconNoTick);
+ }
+ return(himlCheckBoxes);
+}
+
+
+static UINT sortCtrlIDs[] = {IDC_SORTPRIMARY, IDC_SORTTHEN, IDC_SORTFINALLY, 0};
+
+static void FillCheckBoxTree(HWND hwndTree, const struct CheckBoxValues_t *values, int nValues, DWORD style)
+{
+ TVINSERTSTRUCT tvis;
+ int i;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
+ for(i = 0; i < nValues; i++) {
+ tvis.item.lParam = values[i].style;
+ tvis.item.pszText = TranslateTS(values[i].szDescr);
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK((style & tvis.item.lParam) != 0 ? 2 : 1);
+ TreeView_InsertItem(hwndTree, &tvis);
+ }
+}
+
+static DWORD MakeCheckBoxTreeFlags(HWND hwndTree)
+{
+ DWORD flags = 0;
+ TVITEM tvi;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while(tvi.hItem) {
+ TreeView_GetItem(hwndTree, &tvi);
+ if(((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2))
+ flags |= tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return(flags);
+}
+
+/*
+ * load current values into the given profile
+ */
+
+void DSP_LoadFromDefaults(TDisplayProfile *p)
+{
+ int i;
+ DBVARIANT dbv = {0};
+ char szKey[5];
+
+ if (0 == p)
+ return;
+
+ p->dwExtraImageMask = cfg::dat.dwExtraImageMask;
+ p->exIconScale = cfg::dat.exIconScale;
+ p->bCenterStatusIcons = cfg::dat.bCenterStatusIcons;
+ p->dwFlags = cfg::dat.dwFlags;
+ p->bDimIdle = cfg::getByte("CLC", "ShowIdle", CLCDEFAULT_SHOWIDLE);
+ p->avatarBorder = cfg::dat.avatarBorder;
+ p->avatarSize = cfg::dat.avatarSize;
+ p->dualRowMode = cfg::dat.dualRowMode;
+ p->bNoOfflineAvatars = cfg::dat.bNoOfflineAvatars;
+ p->bShowLocalTime = cfg::dat.bShowLocalTime;
+ p->bShowLocalTimeSelective = cfg::dat.bShowLocalTimeSelective;
+ p->clcExStyle = cfg::getDword("CLC", "ExStyle", pcli->pfnGetDefaultExStyle());
+ p->clcOfflineModes = cfg::getDword("CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES);
+ p->bDontSeparateOffline = cfg::dat.bDontSeparateOffline;
+ p->sortOrder[0] = cfg::dat.sortOrder[0];
+ p->sortOrder[1] = cfg::dat.sortOrder[1];
+ p->sortOrder[2] = cfg::dat.sortOrder[2];
+ p->bUseDCMirroring = cfg::dat.bUseDCMirroring;
+ p->bCenterGroupNames = cfg::getByte("CLCExt", "EXBK_CenterGroupnames", 0);
+ p->bGroupAlign = cfg::dat.bGroupAlign;
+ p->avatarPadding = cfg::dat.avatarPadding;
+
+ p->bLeftMargin = cfg::getByte("CLC", "LeftMargin", CLCDEFAULT_LEFTMARGIN);
+ p->bRightMargin = cfg::getByte("CLC", "RightMargin", CLCDEFAULT_LEFTMARGIN);
+ p->bRowSpacing = cfg::dat.bRowSpacing;
+ p->bGroupIndent = cfg::getByte("CLC", "GroupIndent", CLCDEFAULT_GROUPINDENT);
+ p->bRowHeight = cfg::getByte("CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT);
+ p->bGroupRowHeight = cfg::getByte("CLC", "GRowHeight", CLCDEFAULT_ROWHEIGHT);
+ CopyMemory(p->exIconOrder, cfg::dat.exIconOrder, EXICON_COUNT);
+
+ for(i = 0; i < NR_DSPOVERRIDES; i++) {
+ mir_snprintf(szKey, 3, "%d", i);
+ ZeroMemory(&p->dspOverride[i], sizeof(TDspOverride));
+ if(0 == db_get(0, DSP_PROFILES_MODULE, szKey, &dbv)) {
+ if(dbv.type == DBVT_BLOB && dbv.cpbVal > 0 && dbv.cpbVal <= sizeof(TDspOverride))
+ CopyMemory((void *)&p->dspOverride[i], (void *)dbv.pbVal, dbv.cpbVal);
+ db_free(&dbv);
+ }
+ }
+}
+
+/*
+ * apply a display profile
+ */
+
+void DSP_Apply(TDisplayProfile *p)
+{
+ int oldexIconScale = cfg::dat.exIconScale;
+ int i;
+ DWORD exStyle;
+ char temp[EXICON_COUNT + 1], szKey[5];
+ /*
+ * icons page
+ */
+ cfg::dat.dwFlags &= ~(CLUI_FRAME_STATUSICONS | CLUI_SHOWVISI | CLUI_FRAME_OVERLAYICONS | CLUI_FRAME_SELECTIVEICONS);
+ cfg::dat.dwExtraImageMask = p->dwExtraImageMask;
+ cfg::dat.exIconScale = p->exIconScale;
+ cfg::dat.bCenterStatusIcons = p->bCenterStatusIcons;
+
+ cfg::writeDword("CLUI", "ximgmask", cfg::dat.dwExtraImageMask);
+ cfg::writeByte("CLC", "ExIconScale", (BYTE)cfg::dat.exIconScale);
+ cfg::writeByte("CLC", "si_centered", (BYTE)cfg::dat.bCenterStatusIcons);
+ cfg::writeByte("CLC", "ShowIdle", (BYTE)p->bDimIdle);
+
+ CopyMemory(cfg::dat.exIconOrder, p->exIconOrder, EXICON_COUNT);
+ CopyMemory(temp, p->exIconOrder, EXICON_COUNT);
+ temp[EXICON_COUNT] = 0;
+ cfg::writeString(NULL, "CLUI", "exIconOrder", temp);
+
+ /*
+ * advanced (avatars & 2nd row)
+ */
+
+ cfg::dat.dwFlags &= ~(CLUI_FRAME_AVATARSLEFT | CLUI_FRAME_AVATARSRIGHT | CLUI_FRAME_AVATARSRIGHTWITHNICK |
+ CLUI_FRAME_AVATARS |
+ CLUI_FRAME_ALWAYSALIGNNICK | CLUI_FRAME_SHOWSTATUSMSG | CLUI_FRAME_AVATARBORDER);
+
+ cfg::dat.avatarSize = p->avatarSize;
+ cfg::dat.avatarBorder = p->avatarBorder;
+ cfg::dat.dualRowMode = p->dualRowMode;
+ cfg::dat.bNoOfflineAvatars = p->bNoOfflineAvatars;
+ cfg::dat.bShowLocalTime = p->bShowLocalTime;
+ cfg::dat.bShowLocalTimeSelective = p->bShowLocalTimeSelective;
+
+ if(cfg::dat.hBrushAvatarBorder)
+ DeleteObject(cfg::dat.hBrushAvatarBorder);
+ cfg::dat.hBrushAvatarBorder = CreateSolidBrush(cfg::dat.avatarBorder);
+
+ /*
+ * items page
+ */
+
+ cfg::dat.dwFlags &= ~CLUI_STICKYEVENTS;
+
+ cfg::dat.sortOrder[0] = p->sortOrder[0];
+ cfg::dat.sortOrder[1] = p->sortOrder[1];
+ cfg::dat.sortOrder[2] = p->sortOrder[2];
+ cfg::dat.bDontSeparateOffline = p->bDontSeparateOffline;
+ cfg::writeByte("CList", "DontSeparateOffline", (BYTE)cfg::dat.bDontSeparateOffline);
+ cfg::writeDword("CLC", "OfflineModes", p->clcOfflineModes);
+
+ cfg::writeDword("CList", "SortOrder",
+ MAKELONG(MAKEWORD(cfg::dat.sortOrder[0], cfg::dat.sortOrder[1]),
+ MAKEWORD(cfg::dat.sortOrder[2], 0)));
+
+ cfg::dat.bUseDCMirroring = p->bUseDCMirroring;
+ cfg::writeByte("CLC", "MirrorDC", cfg::dat.bUseDCMirroring);
+
+ /*
+ * groups page
+ */
+
+ cfg::dat.dwFlags &= ~CLUI_FRAME_NOGROUPICON;
+ cfg::dat.bGroupAlign = p->bGroupAlign;
+ cfg::writeByte("CLC", "GroupAlign", cfg::dat.bGroupAlign);
+ cfg::writeByte("CLCExt", "EXBK_CenterGroupnames", (BYTE)p->bCenterGroupNames);
+
+ exStyle = cfg::getDword("CLC", "ExStyle", pcli->pfnGetDefaultExStyle());
+ for(i = 0; i < sizeof(checkBoxToGroupStyleEx) / sizeof(checkBoxToGroupStyleEx[0]); i++)
+ exStyle &= ~(checkBoxToGroupStyleEx[i].flag);
+
+ exStyle |= p->clcExStyle;
+ cfg::writeDword("CLC", "ExStyle", exStyle);
+ cfg::dat.avatarPadding = p->avatarPadding;
+ cfg::writeByte("CList", "AvatarPadding", cfg::dat.avatarPadding);
+
+ cfg::dat.bRowSpacing = p->bRowSpacing;
+ cfg::writeByte("CLC", "RowGap", cfg::dat.bRowSpacing);
+
+ cfg::writeByte("CLC", "LeftMargin", (BYTE)p->bLeftMargin);
+ cfg::writeByte("CLC", "RightMargin", (BYTE)p->bRightMargin);
+ cfg::writeByte("CLC", "GroupIndent", (BYTE)p->bGroupIndent);
+ cfg::writeByte("CLC", "RowHeight", (BYTE)p->bRowHeight);
+ cfg::writeByte("CLC", "GRowHeight", (BYTE)p->bGroupRowHeight);
+
+ if(cfg::dat.sortOrder[0] == SORTBY_LASTMSG || cfg::dat.sortOrder[1] == SORTBY_LASTMSG || cfg::dat.sortOrder[2] == SORTBY_LASTMSG) {
+ int i;
+
+ for(i = 0; i < cfg::nextCacheEntry; i++)
+ cfg::eCache[i].dwLastMsgTime = INTSORT_GetLastMsgTime(cfg::eCache[i].hContact);
+ }
+
+ cfg::writeByte("CLC", "ShowLocalTime", (BYTE)cfg::dat.bShowLocalTime);
+ cfg::writeByte("CLC", "SelectiveLocalTime", (BYTE)cfg::dat.bShowLocalTimeSelective);
+ cfg::writeDword("CLC", "avatarborder", cfg::dat.avatarBorder);
+ cfg::writeWord(NULL, "CList", "AvatarSize", (WORD)cfg::dat.avatarSize);
+ cfg::writeByte("CLC", "DualRowMode", cfg::dat.dualRowMode);
+ cfg::writeByte("CList", "NoOfflineAV", (BYTE)cfg::dat.bNoOfflineAvatars);
+
+ KillTimer(pcli->hwndContactTree, TIMERID_REFRESH);
+ if(cfg::dat.bShowLocalTime)
+ SetTimer(pcli->hwndContactTree, TIMERID_REFRESH, 65000, NULL);
+
+ cfg::dat.dwFlags |= p->dwFlags;
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+
+ for(i = 0; i < cfg::nextCacheEntry; i++)
+ cfg::eCache[i].dwXMask = CalcXMask(cfg::eCache[i].hContact);
+
+ if(oldexIconScale != cfg::dat.exIconScale) {
+ ImageList_RemoveAll(CLUI::hExtraImages);
+ ImageList_SetIconSize(CLUI::hExtraImages, cfg::dat.exIconScale, cfg::dat.exIconScale);
+ IcoLibReloadIcons();
+ }
+ pcli->pfnClcOptionsChanged();
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+
+ for(i = 0; i < NR_DSPOVERRIDES; i++) {
+ mir_snprintf(szKey, 3, "%d", i);
+ db_set_blob(0, DSP_PROFILES_MODULE, szKey, (void *)&p->dspOverride[i], sizeof(TDspOverride));
+ }
+
+ CopyMemory(&CLC::dsp_default, p, sizeof(TDisplayProfile));
+}
+
+void GetDefaultFontSetting(int i, LOGFONTW *lf, COLORREF *colour)
+{
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), lf, FALSE);
+ *colour = GetSysColor(COLOR_WINDOWTEXT);
+ switch(i) {
+ case FONTID_GROUPS:
+ lf->lfWeight = FW_BOLD;
+ break;
+ case FONTID_GROUPCOUNTS:
+ lf->lfHeight = (int)(lf->lfHeight * .75);
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+ case FONTID_OFFINVIS:
+ case FONTID_INVIS:
+ lf->lfItalic = !lf->lfItalic;
+ break;
+ case FONTID_DIVIDERS:
+ lf->lfHeight = (int)(lf->lfHeight * .75);
+ break;
+ case FONTID_NOTONLIST:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+ }
+}
+
+INT_PTR CALLBACK cfg::DlgProcDspGroups(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_GROUPALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Always Left"));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Always Right"));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Automatic (RTL)"));
+ return(TRUE);
+ }
+ case WM_COMMAND:
+ if((LOWORD(wParam) == IDC_ROWHEIGHT || LOWORD(wParam) == IDC_AVATARPADDING || LOWORD(wParam) == IDC_ROWGAP || LOWORD(wParam) == IDC_RIGHTMARGIN || LOWORD(wParam) == IDC_LEFTMARGIN || LOWORD(wParam) == IDC_SMOOTHTIME || LOWORD(wParam) == IDC_GROUPINDENT || LOWORD(wParam) == IDC_GROUPROWHEIGHT)
+ && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return(0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_USER + 100: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ DWORD exStyle = p->clcExStyle;
+ int i;
+ for(i = 0; i < sizeof(checkBoxToGroupStyleEx) / sizeof(checkBoxToGroupStyleEx[0]); i++)
+ CheckDlgButton(hwndDlg, checkBoxToGroupStyleEx[i].id, (exStyle & checkBoxToGroupStyleEx[i].flag) ^(checkBoxToGroupStyleEx[i].flag * checkBoxToGroupStyleEx[i].not_t) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_NOGROUPICON, (p->dwFlags & CLUI_FRAME_NOGROUPICON) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CENTERGROUPNAMES, p->bCenterGroupNames);
+ SendDlgItemMessage(hwndDlg, IDC_GROUPALIGN, CB_SETCURSEL, p->bGroupAlign, 0);
+ SendDlgItemMessage(hwndDlg, IDC_AVATARPADDINGSPIN, UDM_SETRANGE, 0, MAKELONG(10, 0));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARPADDINGSPIN, UDM_SETPOS, 0, p->avatarPadding);
+
+ SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_SETRANGE, 0, MAKELONG(64, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, p->bLeftMargin);
+ SendDlgItemMessage(hwndDlg, IDC_RIGHTMARGINSPIN, UDM_SETRANGE, 0, MAKELONG(64, 0));
+ SendDlgItemMessage(hwndDlg, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, p->bRightMargin);
+ SendDlgItemMessage(hwndDlg, IDC_ROWGAPSPIN, UDM_SETRANGE, 0, MAKELONG(10, 0));
+ SendDlgItemMessage(hwndDlg, IDC_ROWGAPSPIN, UDM_SETPOS, 0, p->bRowSpacing);
+ SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_SETRANGE, 0, MAKELONG(50, 0));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_SETPOS, 0, p->bGroupIndent);
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETRANGE, 0, MAKELONG(255, 8));
+ SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_SETPOS, 0, p->bRowHeight);
+ SendDlgItemMessage(hwndDlg, IDC_GROUPROWHEIGHTSPIN, UDM_SETRANGE, 0, MAKELONG(255, 8));
+ SendDlgItemMessage(hwndDlg, IDC_GROUPROWHEIGHTSPIN, UDM_SETPOS, 0, p->bGroupRowHeight);
+ }
+ return(0);
+ }
+ case WM_USER + 200: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ int i;
+ DWORD exStyle = 0;
+ LRESULT curSel;
+ BOOL translated;
+
+ for(i = 0; i < sizeof(checkBoxToGroupStyleEx) / sizeof(checkBoxToGroupStyleEx[0]); i++) {
+ if((IsDlgButtonChecked(hwndDlg, checkBoxToGroupStyleEx[i].id) == 0) == checkBoxToGroupStyleEx[i].not_t)
+ exStyle |= checkBoxToGroupStyleEx[i].flag;
+ }
+ p->clcExStyle = exStyle;
+ p->dwFlags |= (IsDlgButtonChecked(hwndDlg, IDC_NOGROUPICON) ? CLUI_FRAME_NOGROUPICON : 0);
+ p->bCenterGroupNames = IsDlgButtonChecked(hwndDlg, IDC_CENTERGROUPNAMES) ? 1 : 0;
+ curSel = SendDlgItemMessage(hwndDlg, IDC_GROUPALIGN, CB_GETCURSEL, 0, 0);
+ if(curSel != CB_ERR)
+ p->bGroupAlign = (BYTE)curSel;
+
+ p->avatarPadding = (BYTE)GetDlgItemInt(hwndDlg, IDC_AVATARPADDING, &translated, FALSE);
+ p->bLeftMargin = (BYTE)SendDlgItemMessage(hwndDlg, IDC_LEFTMARGINSPIN, UDM_GETPOS, 0, 0);
+ p->bRightMargin = (BYTE)SendDlgItemMessage(hwndDlg, IDC_RIGHTMARGINSPIN, UDM_GETPOS, 0, 0);
+ p->bRowSpacing = (BYTE)SendDlgItemMessage(hwndDlg, IDC_ROWGAPSPIN, UDM_GETPOS, 0, 0);
+ p->bGroupIndent = (BYTE)SendDlgItemMessage(hwndDlg, IDC_GROUPINDENTSPIN, UDM_GETPOS, 0, 0);
+ p->bRowHeight = (BYTE)SendDlgItemMessage(hwndDlg, IDC_ROWHEIGHTSPIN, UDM_GETPOS, 0, 0);
+ p->bGroupRowHeight = (BYTE)SendDlgItemMessage(hwndDlg, IDC_GROUPROWHEIGHTSPIN, UDM_GETPOS, 0, 0);
+ }
+ return(0);
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ return(TRUE);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+INT_PTR CALLBACK cfg::DlgProcDspItems(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ int i = 0;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), GWL_STYLE,
+ GetWindowLong(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+
+ for(i = 0; sortCtrlIDs[i] != 0; i++) {
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Nothing"));
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Name"));
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Protocol"));
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Status"));
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Last Message"));
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_INSERTSTRING, -1, (LPARAM)TranslateT("Message Frequency"));
+ }
+ SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Never"));
+ SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Always"));
+ SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("For RTL only"));
+ SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_INSERTSTRING, -1, (LPARAM)TranslateT("RTL TEXT only"));
+ return(TRUE);
+ }
+ case WM_COMMAND:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_USER + 100: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ int i;
+ FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), offlineValues, sizeof(offlineValues) / sizeof(offlineValues[0]), p->clcOfflineModes);
+ CheckDlgButton(hwndDlg, IDC_EVENTSONTOP, (p->dwFlags & CLUI_STICKYEVENTS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DONTSEPARATE, p->bDontSeparateOffline);
+ for(i = 0; sortCtrlIDs[i] != 0; i++)
+ SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_SETCURSEL, p->sortOrder[i], 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_SETCURSEL, p->bUseDCMirroring, 0);
+ }
+ return(0);
+ }
+ case WM_USER + 200: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ int i;
+ LRESULT curSel;
+
+ for(i = 0; sortCtrlIDs[i] != 0; i++) {
+ curSel = SendDlgItemMessage(hwndDlg, sortCtrlIDs[i], CB_GETCURSEL, 0, 0);
+ if(curSel == 0 || curSel == CB_ERR)
+ p->sortOrder[i] = 0;
+ else
+ p->sortOrder[i] = (BYTE)curSel;
+ }
+ p->bDontSeparateOffline = IsDlgButtonChecked(hwndDlg, IDC_DONTSEPARATE) ? 1 : 0;
+ p->dwFlags |= IsDlgButtonChecked(hwndDlg, IDC_EVENTSONTOP) ? CLUI_STICKYEVENTS : 0;
+ p->clcOfflineModes = MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS));
+ p->bUseDCMirroring = (BYTE)SendDlgItemMessage(hwndDlg, IDC_CLISTALIGN, CB_GETCURSEL, 0, 0);
+ }
+ return(0);
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR) lParam)->idFrom) {
+ case IDC_HIDEOFFLINEOPTS:
+ if(((LPNMHDR) lParam)->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short) LOWORD(GetMessagePos());
+ hti.pt.y = (short) HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR) lParam)->hwndFrom, &hti.pt);
+ if(TreeView_HitTest(((LPNMHDR) lParam)->hwndFrom, &hti))
+ if(hti.flags & TVHT_ONITEMSTATEICON) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
+ TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case 0:
+ switch(((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ return(TRUE);
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY: {
+ ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_HIDEOFFLINEOPTS), TVSIL_STATE));
+ break;
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+static UINT avatar_controls[] = { IDC_ALIGNMENT, IDC_AVATARSBORDER, IDC_AVATARBORDERCLR, IDC_ALWAYSALIGNNICK, IDC_AVATARHEIGHT, IDC_AVATARSIZESPIN, 0};
+
+INT_PTR CALLBACK cfg::DlgProcDspClasses(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"Offline contacts"));
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"Online contacts"));
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"Selected contacts"));
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"Hovered contacts"));
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"Priority contacts"));
+ SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_SETCURSEL, 0, 0);
+ break;
+
+ /*
+ * sent from the tab parent to init settings
+ */
+ case WM_USER + 100: {
+ TDisplayProfile* p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, reinterpret_cast<INT_PTR>(p));
+ SendMessage(hwndDlg, WM_USER + 300, 0, 0);
+
+ CheckDlgButton(hwndDlg, IDC_DSPCLASS_ENABLE_SELECTED, p->dspOverride[DSP_OVR_SELECTED].fActive ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DSPCLASS_ENABLE_HOVERED, p->dspOverride[DSP_OVR_HOVERED].fActive ? BST_CHECKED : BST_UNCHECKED);
+ }
+ return(0);
+ }
+
+ /*
+ * sent from the tab parent to collect settings
+ */
+ case WM_USER + 200: {
+ TDisplayProfile* pNew = reinterpret_cast<TDisplayProfile *>(lParam);
+ TDisplayProfile* p = reinterpret_cast<TDisplayProfile *>(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
+ CopyMemory(&pNew->dspOverride[0], &p->dspOverride[0], sizeof(TDspOverride) * NR_DSPOVERRIDES);
+ return(0);
+ }
+
+ /*
+ * internal - init settings based on the selected override identifier
+ * (stored in IDC_DSPCLASS)
+ */
+ case WM_USER + 300: {
+ TDisplayProfile* p = reinterpret_cast<TDisplayProfile *>(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
+ if(p) {
+ LRESULT uIndex = SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_GETCURSEL, 0, 0);
+ if(uIndex >= 0 && uIndex < NR_DSPOVERRIDES) {
+ TDspOverride* o = &p->dspOverride[uIndex];
+ CheckDlgButton(hwndDlg, IDC_DSPCLASS_AVATAR, o->bAvatar == 0 ? BST_INDETERMINATE : (o->bAvatar == 1 ? BST_CHECKED : BST_UNCHECKED));
+ CheckDlgButton(hwndDlg, IDC_DSPCLASS_SECONDLINE, o->bSecondLine == 0 ? BST_INDETERMINATE : (o->bSecondLine == 1 ? BST_CHECKED : BST_UNCHECKED));
+ CheckDlgButton(hwndDlg, IDC_DSPCLASS_ICON, o->bIcon == 0 ? BST_INDETERMINATE : (o->bIcon == 1 ? BST_CHECKED : BST_UNCHECKED));
+ }
+ }
+ return(0);
+ }
+
+ case WM_COMMAND: {
+ if(IDC_DSPCLASS == LOWORD(wParam) && CBN_SELCHANGE == HIWORD(wParam)) {
+ SendMessage(hwndDlg, WM_USER + 300, 0, 0);
+ break;
+ }
+ switch(LOWORD(wParam)) {
+ case IDC_DSPCLASS_AVATAR:
+ case IDC_DSPCLASS_ICON:
+ case IDC_DSPCLASS_SECONDLINE:
+ case IDC_DSPCLASS_ENABLE_SELECTED:
+ case IDC_DSPCLASS_ENABLE_HOVERED: {
+ TDisplayProfile* p = reinterpret_cast<TDisplayProfile *>(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
+ if(p) {
+ LRESULT uIndex = SendDlgItemMessage(hwndDlg, IDC_DSPCLASS, CB_GETCURSEL, 0, 0);
+ if(uIndex >= 0 && uIndex < NR_DSPOVERRIDES) {
+ LRESULT r;
+ TDspOverride* o = &p->dspOverride[uIndex];
+ r = IsDlgButtonChecked(hwndDlg, IDC_DSPCLASS_AVATAR);
+ o->bAvatar = (r == BST_INDETERMINATE ? 0 : (r == BST_CHECKED ? 1 : -1));
+ r = IsDlgButtonChecked(hwndDlg, IDC_DSPCLASS_ICON);
+ o->bIcon = (r == BST_INDETERMINATE ? 0 : (r == BST_CHECKED ? 1 : -1));
+ r = IsDlgButtonChecked(hwndDlg, IDC_DSPCLASS_SECONDLINE);
+ o->bSecondLine = (r == BST_INDETERMINATE ? 0 : (r == BST_CHECKED ? 1 : -1));
+ }
+ p->dspOverride[DSP_OVR_HOVERED].fActive = (IsDlgButtonChecked(hwndDlg, IDC_DSPCLASS_ENABLE_HOVERED) ? true : false);
+ p->dspOverride[DSP_OVR_SELECTED].fActive = (IsDlgButtonChecked(hwndDlg, IDC_DSPCLASS_ENABLE_SELECTED) ? true : false);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+INT_PTR CALLBACK cfg::DlgProcDspAdvanced(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ int i = 0;
+
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_DUALROWMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Never"));
+ SendDlgItemMessage(hwndDlg, IDC_DUALROWMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Always"));
+ SendDlgItemMessage(hwndDlg, IDC_DUALROWMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("When needed"));
+
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("With Nickname - left"));
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Far left"));
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Far right"));
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("With Nickname - right"));
+
+ Utils::enableDlgControl(hwndDlg, IDC_CLISTAVATARS, TRUE);
+ while(avatar_controls[i] != 0)
+ Utils::enableDlgControl(hwndDlg, avatar_controls[i++], TRUE);
+ return(TRUE);
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_CLISTAVATARS:
+ if((HWND)lParam != GetFocus())
+ return(0);
+ break;
+ case IDC_SHOWLOCALTIME:
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWLOCALTIMEONLYWHENDIFFERENT, IsDlgButtonChecked(hwndDlg, IDC_SHOWLOCALTIME));
+ break;
+ case IDC_AVATARSBORDER:
+ Utils::enableDlgControl(hwndDlg, IDC_AVATARBORDERCLR, IsDlgButtonChecked(hwndDlg, IDC_AVATARSBORDER) ? TRUE : FALSE);
+ break;
+ }
+ if((LOWORD(wParam) == IDC_AVATARHEIGHT) && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return(0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_USER + 100: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ CheckDlgButton(hwndDlg, IDC_NOAVATARSOFFLINE, p->bNoOfflineAvatars);
+ SendDlgItemMessage(hwndDlg, IDC_DUALROWMODE, CB_SETCURSEL, (WPARAM)p->dualRowMode, 0);
+ CheckDlgButton(hwndDlg, IDC_CLISTAVATARS, (p->dwFlags & CLUI_FRAME_AVATARS) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_AVATARSBORDER, (p->dwFlags & CLUI_FRAME_AVATARBORDER) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSALIGNNICK, (p->dwFlags & CLUI_FRAME_ALWAYSALIGNNICK) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWSTATUSMSG, (p->dwFlags & CLUI_FRAME_SHOWSTATUSMSG) ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_AVATARBORDERCLR, CPM_SETCOLOUR, 0, p->avatarBorder);
+
+ SendDlgItemMessage(hwndDlg, IDC_AVATARSIZESPIN, UDM_SETRANGE, 0, MAKELONG(100, 16));
+ SendDlgItemMessage(hwndDlg, IDC_AVATARSIZESPIN, UDM_SETPOS, 0, p->avatarSize);
+
+ Utils::enableDlgControl(hwndDlg, IDC_AVATARBORDERCLR, IsDlgButtonChecked(hwndDlg, IDC_AVATARSBORDER) ? TRUE : FALSE);
+
+ CheckDlgButton(hwndDlg, IDC_SHOWLOCALTIME, p->bShowLocalTime ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_SHOWLOCALTIMEONLYWHENDIFFERENT, p->bShowLocalTimeSelective ? 1 : 0);
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWLOCALTIMEONLYWHENDIFFERENT, IsDlgButtonChecked(hwndDlg, IDC_SHOWLOCALTIME));
+
+ if(p->dwFlags & CLUI_FRAME_AVATARSLEFT)
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_SETCURSEL, 1, 0);
+ else if(p->dwFlags & CLUI_FRAME_AVATARSRIGHT)
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_SETCURSEL, 2, 0);
+ else if(p->dwFlags & CLUI_FRAME_AVATARSRIGHTWITHNICK)
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_SETCURSEL, 3, 0);
+ else
+ SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_SETCURSEL, 0, 0);
+ }
+ return(0);
+ }
+ case WM_USER + 200: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ LRESULT sel = SendDlgItemMessage(hwndDlg, IDC_ALIGNMENT, CB_GETCURSEL, 0, 0);
+ BOOL translated;
+
+ if(sel != CB_ERR) {
+ if(sel == 1)
+ p->dwFlags |= CLUI_FRAME_AVATARSLEFT;
+ else if(sel == 2)
+ p->dwFlags |= CLUI_FRAME_AVATARSRIGHT;
+ else if(sel == 3)
+ p->dwFlags |= CLUI_FRAME_AVATARSRIGHTWITHNICK;
+ }
+
+ p->dwFlags |= ((IsDlgButtonChecked(hwndDlg, IDC_CLISTAVATARS) ? CLUI_FRAME_AVATARS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_AVATARSBORDER) ? CLUI_FRAME_AVATARBORDER : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_ALWAYSALIGNNICK) ? CLUI_FRAME_ALWAYSALIGNNICK : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUSMSG) ? CLUI_FRAME_SHOWSTATUSMSG : 0));
+
+ p->avatarBorder = SendDlgItemMessage(hwndDlg, IDC_AVATARBORDERCLR, CPM_GETCOLOUR, 0, 0);
+ p->avatarSize = GetDlgItemInt(hwndDlg, IDC_AVATARHEIGHT, &translated, FALSE);
+ p->bNoOfflineAvatars = IsDlgButtonChecked(hwndDlg, IDC_NOAVATARSOFFLINE) ? TRUE : FALSE;
+ p->bShowLocalTime = IsDlgButtonChecked(hwndDlg, IDC_SHOWLOCALTIME) ? 1 : 0;
+ p->bShowLocalTimeSelective = IsDlgButtonChecked(hwndDlg, IDC_SHOWLOCALTIMEONLYWHENDIFFERENT) ? 1 : 0;
+
+ p->dualRowMode = (BYTE)SendDlgItemMessage(hwndDlg, IDC_DUALROWMODE, CB_GETCURSEL, 0, 0);
+ if(p->dualRowMode == CB_ERR)
+ p->dualRowMode = 0;
+ }
+ return(0);
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ return(TRUE);
+ }
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+ORDERTREEDATA OrderTreeData[] = {
+ {EXTRA_ICON_RES0, _T("Reserved, unused"), 9, TRUE, 0},
+ {EXTRA_ICON_EMAIL, _T("E-mail"), 0, TRUE, 0},
+ {EXTRA_ICON_RES1, _T("Reserved #1"), 7, TRUE, 0},
+ {EXTRA_ICON_SMS, _T("Telephone"), 2, TRUE, 0},
+ {EXTRA_ICON_ADV1, _T("Advanced #1 (X-Status)"), 3, TRUE, 0},
+ {EXTRA_ICON_ADV2, _T("Advanced #2"), 4, TRUE, 0},
+ {EXTRA_ICON_WEB, _T("Homepage"), 1, TRUE, 0},
+ {EXTRA_ICON_CLIENT, _T("Client (fingerprint required)"), 10, TRUE, 0},
+ {EXTRA_ICON_RES2, _T("Reserved #2"), 8, TRUE, 0},
+ {EXTRA_ICON_ADV3, _T("Advanced #3"), 5, TRUE, 0},
+ {EXTRA_ICON_ADV4, _T("Advanced #4"), 6, TRUE, 0},
+};
+
+static int dragging = 0;
+static HTREEITEM hDragItem = NULL;
+
+static int FillOrderTree(HWND hwndDlg, HWND hwndTree, TDisplayProfile *p)
+{
+ int i = 0;
+ TVINSERTSTRUCT tvis = {0};
+ TreeView_DeleteAllItems(hwndTree);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
+
+ for(i = 0; i < EXICON_COUNT; i++) {
+ int iIndex = (int)(p->exIconOrder[i] - 1);
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.lParam = (LPARAM)(&(OrderTreeData[iIndex]));
+ tvis.item.pszText = TranslateTS(OrderTreeData[iIndex].Name);
+ OrderTreeData[iIndex].Visible = (p->dwExtraImageMask & (1 << OrderTreeData[iIndex].ID)) ? TRUE : FALSE;
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(OrderTreeData[iIndex].Visible ? 1 : 2);
+ TreeView_InsertItem(hwndTree, &tvis);
+ }
+ return(0);
+}
+
+static int SaveOrderTree(HWND hwndDlg, HWND hwndTree, TDisplayProfile *p)
+{
+ HTREEITEM ht;
+ TVITEM tvi = {0};
+ int iIndex = 0;
+
+ tvi.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM;
+ ht = TreeView_GetRoot(hwndTree);
+
+ p->dwExtraImageMask = 0;
+
+ do {
+ ORDERTREEDATA *it = NULL;
+ tvi.hItem = ht;
+ TreeView_GetItem(hwndTree, &tvi);
+ it = (ORDERTREEDATA *)(tvi.lParam);
+
+ p->exIconOrder[iIndex] = it->ID + 1;
+ p->dwExtraImageMask |= (it->Visible ? (1 << it->ID) : 0);
+ ht = TreeView_GetNextSibling(hwndTree, ht);
+ iIndex++;
+ } while(ht);
+ return(0);
+}
+
+INT_PTR CALLBACK cfg::DlgProcXIcons(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EXTRAORDER), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EXTRAORDER), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+ HIMAGELIST himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_EXTRAORDER, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList());
+ ImageList_Destroy(himlOptions);
+ return(TRUE);
+ }
+ case WM_COMMAND:
+ if((LOWORD(wParam) == IDC_EXICONSCALE) && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return(0);
+
+ if(IDC_RESETXICONS == LOWORD(wParam)) {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
+ if(p) {
+ for(int i = 0; i < EXICON_COUNT; i++) {
+ OrderTreeData[i].Visible = TRUE;
+ p->exIconOrder[i] = i + 1;
+ }
+ p->dwExtraImageMask = 0xffffffff;
+ FillOrderTree(hwndDlg, GetDlgItem(hwndDlg, IDC_EXTRAORDER), p);
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_USER + 100: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (INT_PTR)p);
+ CheckDlgButton(hwndDlg, IDC_SHOWSTATUSICONS, (p->dwFlags & CLUI_FRAME_STATUSICONS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWVISIBILITY, (p->dwFlags & CLUI_SHOWVISI) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_OVERLAYICONS, (p->dwFlags & CLUI_FRAME_OVERLAYICONS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SELECTIVEICONS, (p->dwFlags & CLUI_FRAME_SELECTIVEICONS) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_STATUSICONSCENTERED, p->bCenterStatusIcons ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_IDLE, p->bDimIdle ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_EXICONSCALESPIN, UDM_SETRANGE, 0, MAKELONG(20, 8));
+ SendDlgItemMessage(hwndDlg, IDC_EXICONSCALESPIN, UDM_SETPOS, 0, (LPARAM)p->exIconScale);
+ FillOrderTree(hwndDlg, GetDlgItem(hwndDlg, IDC_EXTRAORDER), p);
+ }
+ return(0);
+ }
+ case WM_USER + 200: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ if(p) {
+ SaveOrderTree(hwndDlg, GetDlgItem(hwndDlg, IDC_EXTRAORDER), p);
+
+ p->exIconScale = SendDlgItemMessage(hwndDlg, IDC_EXICONSCALESPIN, UDM_GETPOS, 0, 0);
+ p->exIconScale = (p->exIconScale < 8 || p->exIconScale > 20) ? 16 : p->exIconScale;
+
+ p->dwFlags |= ((IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUSICONS) ? CLUI_FRAME_STATUSICONS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SHOWVISIBILITY) ? CLUI_SHOWVISI : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_OVERLAYICONS) ? CLUI_FRAME_OVERLAYICONS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_SELECTIVEICONS) ? CLUI_FRAME_SELECTIVEICONS : 0));
+
+ p->bDimIdle = IsDlgButtonChecked(hwndDlg, IDC_IDLE) ? 1 : 0;
+ p->bCenterStatusIcons = IsDlgButtonChecked(hwndDlg, IDC_STATUSICONSCENTERED) ? 1 : 0;
+ }
+ return(0);
+ }
+ case WM_NOTIFY:
+ if(((LPNMHDR) lParam)->idFrom == IDC_EXTRAORDER) {
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_BEGINDRAGA:
+ case TVN_BEGINDRAGW:
+ SetCapture(hwndDlg);
+ dragging = 1;
+ hDragItem = ((LPNMTREEVIEWA)lParam)->itemNew.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), hDragItem);
+ break;
+ case NM_CLICK: {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti))
+ if(hti.flags & TVHT_ONITEMSTATEICON) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
+ ((ORDERTREEDATA *)tvi.lParam)->Visible = (tvi.iImage == 2 ? FALSE : TRUE);
+ if(((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2))
+ ((ORDERTREEDATA *)tvi.lParam)->Visible = TRUE;
+ else
+ ((ORDERTREEDATA *)tvi.lParam)->Visible = FALSE;
+ TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ }
+ }
+ break;
+ }
+ switch(((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ return(TRUE);
+ }
+ }
+ break;
+
+ case WM_MOUSEMOVE: {
+ if(!dragging)
+ break;
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &hti.pt);
+ TreeView_HitTest(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &hti);
+ if(hti.flags&(TVHT_ONITEM | TVHT_ONITEMRIGHT)) {
+ HTREEITEM it = hti.hItem;
+ hti.pt.y -= TreeView_GetItemHeight(GetDlgItem(hwndDlg, IDC_EXTRAORDER)) / 2;
+ TreeView_HitTest(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &hti);
+ if(!(hti.flags & TVHT_ABOVE))
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_EXTRAORDER), hti.hItem, 1);
+ else
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_EXTRAORDER), it, 0);
+ } else {
+ if(hti.flags & TVHT_ABOVE) SendDlgItemMessage(hwndDlg, IDC_EXTRAORDER, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
+ if(hti.flags & TVHT_BELOW) SendDlgItemMessage(hwndDlg, IDC_EXTRAORDER, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_EXTRAORDER), NULL, 0);
+ }
+ }
+ }
+ break;
+ case WM_LBUTTONUP: {
+ if(!dragging) break;
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_EXTRAORDER), NULL, 0);
+ dragging = 0;
+ ReleaseCapture();
+ {
+ TVHITTESTINFO hti;
+ TVITEM tvi;
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &hti.pt);
+ hti.pt.y -= TreeView_GetItemHeight(GetDlgItem(hwndDlg, IDC_EXTRAORDER)) / 2;
+ TreeView_HitTest(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &hti);
+ if(hDragItem == hti.hItem) break;
+ if(hti.flags & TVHT_ABOVE) hti.hItem = TVI_FIRST;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hDragItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &tvi);
+ if(hti.flags&(TVHT_ONITEM | TVHT_ONITEMRIGHT) || (hti.hItem == TVI_FIRST)) {
+ TVINSERTSTRUCT tvis;
+ wchar_t name[128];
+ tvis.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvis.item.stateMask = 0xFFFFFFFF;
+ tvis.item.pszText = name;
+ tvis.item.cchTextMax = sizeof(name);
+ tvis.item.hItem = hDragItem;
+ tvis.item.iImage = tvis.item.iSelectedImage = ((ORDERTREEDATA *)tvi.lParam)->Visible;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &tvis.item);
+ TreeView_DeleteItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), hDragItem);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = hti.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_EXTRAORDER), &tvis));
+ SendMessage((GetParent(hwndDlg)), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ }
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+static TDisplayProfile dsp_current;
+
+INT_PTR CALLBACK cfg::DlgProcDspProfiles(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+ static HWND hwndTab;
+ static int iTabCount;
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TCITEM tci;
+ RECT rcClient;
+ int oPage = cfg::getByte("CLUI", "opage_d", 0);
+
+ TranslateDialogDefault(hwnd);
+
+ GetClientRect(hwnd, &rcClient);
+ hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB);
+ iInit = TRUE;
+ tci.mask = TCIF_PARAM | TCIF_TEXT;
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_DSPITEMS), hwnd, DlgProcDspItems);
+ tci.pszText = TranslateT("Contacts");
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 0 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_DSPGROUPS), hwnd, DlgProcDspGroups);
+ tci.pszText = TranslateT("Groups and layout");
+ TabCtrl_InsertItem(hwndTab, 1, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 1 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_XICONS), hwnd, DlgProcXIcons);
+ tci.pszText = TranslateT("Icons");
+ TabCtrl_InsertItem(hwndTab, 2, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 2 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_DSPADVANCED), hwnd, DlgProcDspAdvanced);
+ tci.pszText = TranslateT("Advanced");
+ TabCtrl_InsertItem(hwndTab, 3, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 3 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_DSPCLASSES), hwnd, DlgProcDspClasses);
+ tci.pszText = TranslateT("Display classes");
+ TabCtrl_InsertItem(hwndTab, 4, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 4 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ TabCtrl_SetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB), oPage);
+
+ DSP_LoadFromDefaults(&CLC::dsp_default);
+ CopyMemory(&dsp_current, &CLC::dsp_default, sizeof(TDisplayProfile));
+
+ iTabCount = TabCtrl_GetItemCount(hwndTab);
+
+ SendMessage(hwnd, WM_USER + 100, 0, (LPARAM)&CLC::dsp_default);
+
+ iInit = FALSE;
+ return(FALSE);
+ }
+
+ /*
+ * distribute a WM_USER message to all child windows so they can update their pages from the
+ * display profile structure
+ * LPARAM = DISPLAYPROFILE *
+ */
+
+ case WM_USER + 100: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+
+ if(p) {
+ int i;
+ TCITEM item = {0};
+ item.mask = TCIF_PARAM;
+
+ for(i = 0; i < iTabCount; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if(item.lParam && IsWindow((HWND)item.lParam))
+ SendMessage((HWND)item.lParam, WM_USER + 100, 0, (LPARAM)p);
+ }
+ }
+ return(0);
+ }
+
+ /*
+ * collect the settings from the pages into a DISPLAYPROFILE struct
+ */
+ case WM_USER + 200: {
+ TDisplayProfile *p = reinterpret_cast<TDisplayProfile *>(lParam);
+ int i;
+ TCITEM item = {0};
+ item.mask = TCIF_PARAM;
+
+ for(i = 0; i < iTabCount; i++) {
+ TabCtrl_GetItem(hwndTab, i, &item);
+ if(item.lParam && IsWindow((HWND)item.lParam))
+ SendMessage((HWND)item.lParam, WM_USER + 200, 0, (LPARAM)p);
+ }
+ return(0);
+ }
+
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ TDisplayProfile p;
+
+ ZeroMemory(&p, sizeof(p));
+ SendMessage(hwnd, WM_USER + 200, 0, (LPARAM)&p);
+ DSP_Apply(&p);
+ }
+ break;
+ }
+ break;
+ case IDC_OPTIONSTAB:
+ switch(((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ cfg::writeByte("CLUI", "opage_d", (BYTE)TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)));
+ }
+ break;
+ }
+ break;
+
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+INT_PTR CALLBACK cfg::TabOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ TCITEM tci;
+ RECT rcClient;
+ int oPage = cfg::getByte("CLUI", "opage_m", 0);
+
+ if(oPage > 3)
+ oPage = 0;
+
+ GetClientRect(hwnd, &rcClient);
+ iInit = TRUE;
+ tci.mask = TCIF_PARAM | TCIF_TEXT;
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_CLIST), hwnd, cfg::DlgProcGenOpts);
+ tci.pszText = TranslateT("General");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 0, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 0 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_CLC), hwnd, cfg::DlgProcClcMainOpts);
+ tci.pszText = TranslateT("List layout");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 1, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 1 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_CLUI), hwnd, cfg::DlgProcCluiOpts);
+ tci.pszText = TranslateT("Window");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 2, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 2 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_OPT_SBAR), hwnd, cfg::DlgProcSBarOpts);
+ tci.pszText = TranslateT("Status Bar");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 3, &tci);
+ MoveWindow((HWND)tci.lParam, 5, 25, rcClient.right - 9, rcClient.bottom - 30, 1);
+ ShowWindow((HWND)tci.lParam, oPage == 3 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ TabCtrl_SetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB), oPage);
+ iInit = FALSE;
+ return(FALSE);
+ }
+
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY: {
+ TCITEM tci;
+ int i, count;
+ tci.mask = TCIF_PARAM;
+ count = TabCtrl_GetItemCount(GetDlgItem(hwnd, IDC_OPTIONSTAB));
+ for(i = 0; i < count; i++) {
+ TabCtrl_GetItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), i, &tci);
+ SendMessage((HWND)tci.lParam, WM_NOTIFY, 0, lParam);
+ }
+ }
+ break;
+ }
+ break;
+ case IDC_OPTIONSTAB:
+ switch(((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE: {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ cfg::writeByte("CLUI", "opage_m", (BYTE)TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)));
+ }
+ break;
+ }
+ break;
+
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+int ClcOptInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof(odp));
+ //odp.cbSize = sizeof(odp);
+ odp.position = 0;
+ odp.hInstance = g_hInst;
+ odp.pszGroup = LPGEN("Contact List");
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_DSPPROFILES);
+ odp.pszTitle = LPGEN("Contact rows");
+ odp.pfnDlgProc = cfg::DlgProcDspProfiles;
+ odp.flags = ODPF_BOLDGROUPS;
+ Options_AddPage(wParam, &odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FLOATING);
+ odp.pszTitle = LPGEN("Floating contacts");
+ odp.pfnDlgProc = cfg::DlgProcFloatingContacts;
+ odp.flags = ODPF_BOLDGROUPS;
+ Options_AddPage(wParam, &odp);
+
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT);
+ odp.pszGroup = LPGEN("Skins");
+ odp.pszTitle = LPGEN("Contact list skin");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = cfg::SkinOptionsDlgProc;
+ Options_AddPage(wParam, &odp);
+
+ odp.position = -1000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONSDIALOG);
+ odp.pszGroup = NULL;
+ odp.pszTitle = LPGEN("Contact List");
+ odp.pfnDlgProc = cfg::TabOptionsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ Options_AddPage(wParam, &odp);
+ return(0);
+}
+
+static int opt_clc_main_changed = 0;
+
+INT_PTR CALLBACK cfg::DlgProcClcMainOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ opt_clc_main_changed = 0;
+ SetWindowLong(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+
+ {
+ int i;
+ DWORD exStyle = cfg::getDword("CLC", "ExStyle", pcli->pfnGetDefaultExStyle());
+ UDACCEL accel[2] = {
+ {0, 10}, {2, 50}
+ };
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETRANGE, 0, MAKELONG(999, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETACCEL, sizeof(accel) / sizeof(accel[0]), (LPARAM) &accel);
+ SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_SETPOS, 0, MAKELONG(cfg::getWord("CLC", "ScrollTime", CLCDEFAULT_SCROLLTIME), 0));
+
+ for(i = 0; i < sizeof(checkBoxToStyleEx) / sizeof(checkBoxToStyleEx[0]); i++)
+ CheckDlgButton(hwndDlg, checkBoxToStyleEx[i].id, (exStyle & checkBoxToStyleEx[i].flag) ^(checkBoxToStyleEx[i].flag * checkBoxToStyleEx[i].not_t) ? BST_CHECKED : BST_UNCHECKED);
+ }
+ CheckDlgButton(hwndDlg, IDC_FULLROWSELECT, (cfg::dat.dwFlags & CLUI_FULLROWSELECT) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hwndDlg, IDC_DBLCLKAVATARS, cfg::dat.bDblClkAvatars);
+ CheckDlgButton(hwndDlg, IDC_GREYOUT, cfg::getDword("CLC", "GreyoutFlags", CLCDEFAULT_GREYOUTFLAGS) ? BST_CHECKED : BST_UNCHECKED);
+ Utils::enableDlgControl(hwndDlg, IDC_SMOOTHTIME, IsDlgButtonChecked(hwndDlg, IDC_NOTNOSMOOTHSCROLLING));
+ Utils::enableDlgControl(hwndDlg, IDC_GREYOUTOPTS, IsDlgButtonChecked(hwndDlg, IDC_GREYOUT));
+ FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), greyoutValues, sizeof(greyoutValues) / sizeof(greyoutValues[0]), cfg::getDword("CLC", "FullGreyoutFlags", CLCDEFAULT_FULLGREYOUTFLAGS));
+ CheckDlgButton(hwndDlg, IDC_NOSCROLLBAR, cfg::getByte("CLC", "NoVScrollBar", 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ return(TRUE);
+ case WM_VSCROLL:
+ opt_clc_main_changed = 1;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDC_NOTNOSMOOTHSCROLLING)
+ Utils::enableDlgControl(hwndDlg, IDC_SMOOTHTIME, IsDlgButtonChecked(hwndDlg, IDC_NOTNOSMOOTHSCROLLING));
+ if(LOWORD(wParam) == IDC_GREYOUT)
+ Utils::enableDlgControl(hwndDlg, IDC_GREYOUTOPTS, IsDlgButtonChecked(hwndDlg, IDC_GREYOUT));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ opt_clc_main_changed = 1;
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR) lParam)->idFrom) {
+ case IDC_GREYOUTOPTS:
+ if(((LPNMHDR) lParam)->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short) LOWORD(GetMessagePos());
+ hti.pt.y = (short) HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR) lParam)->hwndFrom, &hti.pt);
+ if(TreeView_HitTest(((LPNMHDR) lParam)->hwndFrom, &hti))
+ if(hti.flags & TVHT_ONITEMSTATEICON) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
+ TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
+ opt_clc_main_changed = 1;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case 0:
+ switch(((LPNMHDR) lParam)->code) {
+ case PSN_APPLY: {
+ int i;
+ DWORD exStyle = cfg::getDword("CLC", "ExStyle", CLCDEFAULT_EXSTYLE);
+
+ if(!opt_clc_main_changed)
+ return(TRUE);
+
+ for(i = 0; i < sizeof(checkBoxToStyleEx) / sizeof(checkBoxToStyleEx[0]); i++)
+ exStyle &= ~(checkBoxToStyleEx[i].flag);
+
+ for(i = 0; i < sizeof(checkBoxToStyleEx) / sizeof(checkBoxToStyleEx[0]); i++) {
+ if((IsDlgButtonChecked(hwndDlg, checkBoxToStyleEx[i].id) == 0) == checkBoxToStyleEx[i].not_t)
+ exStyle |= checkBoxToStyleEx[i].flag;
+ }
+ cfg::writeDword("CLC", "ExStyle", exStyle);
+ } {
+ DWORD fullGreyoutFlags = MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS));
+ cfg::writeDword("CLC", "FullGreyoutFlags", fullGreyoutFlags);
+ if(IsDlgButtonChecked(hwndDlg, IDC_GREYOUT))
+ cfg::writeDword("CLC", "GreyoutFlags", fullGreyoutFlags);
+ else
+ cfg::writeDword("CLC", "GreyoutFlags", 0);
+ }
+ cfg::writeWord("CLC", "ScrollTime", (WORD) SendDlgItemMessage(hwndDlg, IDC_SMOOTHTIMESPIN, UDM_GETPOS, 0, 0));
+ cfg::writeByte("CLC", "NoVScrollBar", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_NOSCROLLBAR) ? 1 : 0));
+ cfg::dat.dwFlags = IsDlgButtonChecked(hwndDlg, IDC_FULLROWSELECT) ? cfg::dat.dwFlags | CLUI_FULLROWSELECT : cfg::dat.dwFlags & ~CLUI_FULLROWSELECT;
+ cfg::dat.bDblClkAvatars = IsDlgButtonChecked(hwndDlg, IDC_DBLCLKAVATARS) ? TRUE : FALSE;
+ cfg::writeByte("CLC", "dblclkav", (BYTE)cfg::dat.bDblClkAvatars);
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+
+ pcli->pfnClcOptionsChanged();
+ CoolSB_SetupScrollBar(pcli->hwndContactTree);
+ PostMessage(pcli->hwndContactList, CLUIINTM_REDRAW, 0, 0);
+ opt_clc_main_changed = 0;
+ return(TRUE);
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_GREYOUTOPTS), TVSIL_STATE));
+ break;
+ }
+ return(FALSE);
+}
+
diff --git a/plugins/Clist_ng/SRC/clcpaint.cpp b/plugins/Clist_ng/SRC/clcpaint.cpp new file mode 100644 index 0000000000..3b7afc0ee4 --- /dev/null +++ b/plugins/Clist_ng/SRC/clcpaint.cpp @@ -0,0 +1,1372 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda IM: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2010 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of clist_ng plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: clcpaint.cpp 134 2010-10-01 10:23:10Z silvercircle $ + * + */ + +#include <commonheaders.h> + +HANDLE CLC::hTheme = 0; + +extern ORDERTREEDATA OrderTreeData[]; +extern HICON overlayicons[]; +extern FRAMEWND* wndFrameCLC; +extern wchar_t* statusNames[]; + +int g_center, g_ignoreselforgroups, g_selectiveIcon, g_exIconSpacing; +HWND g_focusWnd; +BYTE selBlend; +int my_status; + +//static Gdiplus::Graphics* _g; + +static wchar_t wszTimeFormat[] = L"%H:%M"; +static LONG dxBufferDiff, dBufferDiff; + +HFONT CLCPaintHelper::changeToFont(const unsigned int id) +{ + HFONT hOldFont = 0; + + hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, dat->fontInfo[id].hFont)); + Gfx::setTextColor(dat->fontInfo[id].colour); + m_fontHeight = dat->fontInfo[id].fontHeight; + + dat->currentFontID = id; + return hOldFont; +} + +void CLCPaintHelper::setHotTrackColour() +{ + if (dat->gammaCorrection) { + COLORREF oldCol, newCol; + int oldLum, newLum; + + oldCol = GetTextColor(hdcMem); + oldLum = (GetRValue(oldCol) * 30 + GetGValue(oldCol) * 59 + GetBValue(oldCol) * 11) / 100; + newLum = (GetRValue(dat->hotTextColour) * 30 + GetGValue(dat->hotTextColour) * 59 + GetBValue(dat->hotTextColour) * 11) / 100; + if (newLum == 0) { + Gfx::setTextColor(dat->hotTextColour); + return; + } + if (newLum >= oldLum + 20) { + oldLum += 20; + newCol = RGB(GetRValue(dat->hotTextColour) * oldLum / newLum, GetGValue(dat->hotTextColour) * oldLum / newLum, GetBValue(dat->hotTextColour) * oldLum / newLum); + } else if (newLum <= oldLum) { + int r, g, b; + r = GetRValue(dat->hotTextColour) * oldLum / newLum; + g = GetGValue(dat->hotTextColour) * oldLum / newLum; + b = GetBValue(dat->hotTextColour) * oldLum / newLum; + if (r > 255) { + g +=(r-255)*3 / 7; + b +=(r-255)*3 / 7; + r = 255; + } + if (g > 255) { + r +=(g-255)*59 / 41; + if (r > 255) + r = 255; + b +=(g-255)*59 / 41; + g = 255; + } + if (b > 255) { + r +=(b-255)*11 / 89; + if (r > 255) + r = 255; + g +=(b-255)*11 / 89; + if (g > 255) + g = 255; + b = 255; + } + newCol = RGB(r, g, b); + } else + newCol = dat->hotTextColour; + Gfx::setTextColor(newCol); + } else + Gfx::setTextColor(dat->hotTextColour); +} + +/** + * return "relative" onlineness value based on the status mode + * + * @param status status mode + * @param ignoreConnectingState ignore the special "in + * connection progress" status + * + * @return int "onlineness" value for the + * given status mode + */ +static int __fastcall GetRealStatus(struct ClcContact *contact, int status) +{ + int i; + char *szProto = contact->proto; + if (!szProto) + return status; + for (i = 0; i < pcli->hClcProtoCount; i++) { + if (!lstrcmpA(pcli->clcProto[i].szProto, szProto)) { + return pcli->clcProto[i].dwStatus; + } + } + return status; +} + +int GetBasicFontID(struct ClcContact * contact) +{ + switch (contact->type) { + case CLCIT_CONTACT: + if (contact->flags & CONTACTF_NOTONLIST) + return FONTID_NOTONLIST; + else if ((contact->flags&CONTACTF_INVISTO && GetRealStatus(contact, ID_STATUS_OFFLINE) != ID_STATUS_INVISIBLE) + || (contact->flags&CONTACTF_VISTO && GetRealStatus(contact, ID_STATUS_OFFLINE) == ID_STATUS_INVISIBLE)) + return contact->flags & CONTACTF_ONLINE ? FONTID_INVIS : FONTID_OFFINVIS; + else + return contact->flags & CONTACTF_ONLINE ? FONTID_CONTACTS : FONTID_OFFLINE; + break; + case CLCIT_GROUP: + return FONTID_GROUPS; + case CLCIT_INFO: + if(contact->flags & CLCIIF_GROUPFONT) + return FONTID_GROUPS; + else + return FONTID_CONTACTS; + case CLCIT_DIVIDER: + return FONTID_DIVIDERS; + default: + return FONTID_CONTACTS; + } +} + +static BLENDFUNCTION bf = {0, 0, AC_SRC_OVER, 0}; +static BOOL avatar_done = FALSE; +HDC g_HDC; +static BOOL g_RTL; +HDC hdcTempAV; +HBITMAP hbmTempAV, hbmTempOldAV; + +LONG g_maxAV_X = 200, g_maxAV_Y = 200; + +int CLCPaintHelper::drawAvatar(RECT *rc, ClcContact *contact, int y, WORD cstatus, int rowHeight) +{ + float dScale = 0.; + float newHeight, newWidth, dAspect; + DWORD topoffset = 0, leftoffset = 0, dwFlags = contact->dwDFlags; + LONG bmWidth, bmHeight; + HBITMAP hbm; + HRGN rgn = 0; + int avatar_size = cfg::dat.avatarSize; + DWORD av_saved_left; + TStatusItem *item = contact->wStatus == ID_STATUS_OFFLINE ? &Skin::statusItems[ID_EXTBKAVATARFRAMEOFFLINE] : &Skin::statusItems[ID_EXTBKAVATARFRAME]; + int skinMarginX, skinMarginY; + BOOL fOverlay = (cfg::dat.dwFlags & CLUI_FRAME_OVERLAYICONS); + + contact->avatarLeft = -1; + if(dat->bisEmbedded) + return 0; + + if(contact->ace) { + if(contact->ace->dwFlags & AVS_HIDEONCLIST) { + if (cfg::dat.dwFlags & CLUI_FRAME_ALWAYSALIGNNICK) + return avatar_size + 2; + else + return 0; + } + bmHeight = contact->ace->bmHeight; + bmWidth = contact->ace->bmWidth; + if(bmWidth != 0) + dAspect = (float)bmHeight / (float)bmWidth; + else + dAspect = 1.0; + hbm = contact->ace->hbmPic; + contact->ace->t_lastAccess = cfg::dat.t_now; + } + else if (cfg::dat.dwFlags & CLUI_FRAME_ALWAYSALIGNNICK) + return avatar_size + 2; + else + return 0; + + if(bmHeight == 0 || bmWidth == 0 || hbm == 0) + return 0; + + g_maxAV_X = max(bmWidth, g_maxAV_X); + g_maxAV_Y = max(bmHeight, g_maxAV_Y); + + if(dAspect >= 1.0) { // height > width + skinMarginY = item->IGNORED ? 0 : (item->MARGIN_TOP + item->MARGIN_BOTTOM); + skinMarginX = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT); + + dScale = (float)(avatar_size - 2) / (float)bmHeight; + newHeight = (float)(avatar_size - skinMarginY - 2); + newWidth = (float)(bmWidth * dScale) - skinMarginX; + } + else { + skinMarginY = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT); + skinMarginX = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT); + + newWidth = (float)(avatar_size - 2) - skinMarginX; + dScale = (float)(avatar_size - 2) / (float)bmWidth; + newHeight = (float)(bmHeight * dScale) - skinMarginY; + } + topoffset = rowHeight > (int)newHeight ? (rowHeight - (int)newHeight) / 2 : 0; + if(!item->IGNORED) { + //topoffset += item->MARGIN_TOP; + leftoffset = item->MARGIN_LEFT; + } + // create the region for the avatar border - use the same region for clipping, if needed. + + av_saved_left = rc->left; + if(cfg::dat.bCenterStatusIcons && newWidth < newHeight) + rc->left += (((avatar_size - 2) - ((int)newWidth + skinMarginX)) / 2); + + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = contact->ace->dwFlags & AVS_PREMULTIPLIED ? AC_SRC_ALPHA : 0; + + + FIBITMAP *fib = cfg::fif->FI_CreateDIBFromHBITMAP(contact->ace->hbmPic); + FIBITMAP *fibnew = cfg::fif->FI_Rescale(fib, newWidth, newHeight, FILTER_LANCZOS3); + HBITMAP hbmNew = cfg::fif->FI_CreateHBITMAPFromDIB(fibnew); + HBITMAP hbmTempOld = (HBITMAP)SelectObject(hdcTempAV, hbmNew); + + Api::pfnAlphaBlend(hdcMem, leftoffset + rc->left - (g_RTL ? 1 : 0), y + topoffset, (int)newWidth, (int)newHeight, hdcTempAV, 0, 0, newWidth, newHeight, bf); + + SelectObject(hdcTempAV, hbmTempOld); + if(hbmNew != contact->ace->hbmPic) + DeleteObject(hbmNew); + cfg::fif->FI_Unload(fib); + cfg::fif->FI_Unload(fibnew); + + if(cfg::dat.dwFlags & CLUI_FRAME_AVATARBORDER) { + rgn = CreateRectRgn(leftoffset + rc->left, y + topoffset, leftoffset + rc->left + (int)newWidth, y + topoffset + (int)newHeight); + if(g_RTL) + OffsetRgn(rgn, -1 , 0); + FrameRgn(hdcMem, rgn, cfg::dat.hBrushAvatarBorder, 1, 1); + DeleteObject(rgn); + } + + if(fOverlay) + fOverlay = (dwFlags & ECF_HIDEOVERLAY) ? 0 : 1; + else + fOverlay = (dwFlags & ECF_FORCEOVERLAY) ? 1 : 0; + + if(fOverlay && cstatus && (int)newHeight >= CYSMICON) + DrawIconEx(hdcMem, rc->left + (int)newWidth - 15, y + topoffset + (int)newHeight - 15, overlayicons[cstatus - ID_STATUS_OFFLINE], CYSMICON, CXSMICON, 0, 0, DI_NORMAL | DI_COMPAT); + + if(!item->IGNORED) { + RECT rcFrame; + bool inClCPaint_save = CLC::fInPaint; + HDC hdcTemp = 0; + HBITMAP hbmOld, hbmTemp; + + CLC::fInPaint = false; + rcFrame.left = rc->left; + rcFrame.top = y + topoffset - item->MARGIN_TOP; + rcFrame.right = rcFrame.left + (int)newWidth + item->MARGIN_RIGHT + item->MARGIN_LEFT; + rcFrame.bottom = rcFrame.top + (int)newHeight + item->MARGIN_BOTTOM + item->MARGIN_TOP; + if(g_RTL) { + RECT rcTemp; + + OffsetRect(&rcFrame, 1, 0); + rcTemp.left = rcTemp.top = 0; + rcTemp.right = rcFrame.right - rcFrame.left; + rcTemp.bottom = rcFrame.bottom - rcFrame.top; + hdcTemp = CreateCompatibleDC(g_HDC); + hbmTemp = CreateCompatibleBitmap(g_HDC, rcTemp.right, rcTemp.bottom); + hbmOld = reinterpret_cast<HBITMAP>(SelectObject(hdcTemp, hbmTemp)); + SetLayout(hdcTemp, LAYOUT_RTL); + BitBlt(hdcTemp, 0, 0, rcTemp.right, rcTemp.bottom, + hdcMem, rcFrame.left, rcFrame.top, SRCCOPY); + SetLayout(hdcTemp, 0); + Gfx::renderSkinItem(hdcTemp, &rcTemp, item->imageItem); + BitBlt(hdcMem, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, + hdcTemp, 0, 0, SRCCOPY); + SelectObject(hdcTemp, hbmOld); + DeleteObject(hbmTemp); + DeleteDC(hdcTemp); + } else + Gfx::renderSkinItem(hdcMem, &rcFrame, item->imageItem); + CLC::fInPaint = inClCPaint_save; + } + contact->avatarLeft = rc->left; + avatar_done = TRUE; + rc->left = av_saved_left; + return avatar_size + 2; + +} + +static BOOL pi_avatar = FALSE; +static RECT rcContent; +static BOOL pi_selectiveIcon; + +static BOOL av_left, av_right, av_rightwithnick; +static BOOL mirror_rtl, mirror_always, mirror_rtltext; + +BYTE savedCORNER = -1; +int g_padding_y = 0; + +void CLCPaintHelper::Paint(ClcGroup *group, ClcContact *contact, int rowHeight) +{ + RECT rc; + int iImage = -1; + SIZE textSize = { 0 }, countsSize = { 0 }, spaceSize = { 0 }; + int width, checkboxWidth; + TCHAR* szCounts = 0; + wchar_t* wszCounts = 0; + BOOL twoRows = FALSE; + WORD cstatus; + DWORD leftOffset = 0, rightOffset = 0; + int iconXSpace = dat->iconXSpace; + HFONT hPreviousFont = 0; + BYTE type; + BYTE flags; + COLORREF oldGroupColor = -1; + DWORD qLeft = 0; + int leftX = dat->leftMargin + indent * dat->groupIndent; + int bg_indent_r = 0; + int bg_indent_l = 0; + int rightIcons = 0; + DWORD dt_nickflags = 0, dt_2ndrowflags = 0; + TExtraCache* cEntry = NULL; + DWORD dwFlags = cfg::dat.dwFlags; + int scanIndex; + BOOL av_local_wanted, fLocalTime; + + if(!isContactFloater) + current_shape = 0; + + rowHeight -= cfg::dat.bRowSpacing; + + if(group == NULL || contact == NULL) + return; + + g_RTL = FALSE; + scanIndex = group->scanIndex; + av_local_wanted = (CLC::uNrAvatars > 0); + + type = contact->type; + flags = contact->flags; + avatar_done = FALSE; + if(contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry) + cEntry = &cfg::eCache[contact->extraCacheEntry]; + else + cEntry = cfg::eCache; + + if(dat->bisEmbedded) + goto set_bg_l; + + if(type == CLCIT_CONTACT && (cEntry->dwCFlags & ECF_RTLNICK || mirror_always)) { + if(mirror_rtl || mirror_always) { + g_RTL = TRUE; + bg_indent_r = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + } + else if(mirror_rtltext) { + bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + dt_nickflags = DT_RTLREADING | DT_RIGHT; + } + else + bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + } + else if(type == CLCIT_GROUP) { + if((contact->isRtl && cfg::dat.bGroupAlign == CLC_GROUPALIGN_AUTO) || cfg::dat.bGroupAlign == CLC_GROUPALIGN_RIGHT) { + g_RTL = TRUE; + bg_indent_r = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + } + else + bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + } + else + bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0; + +set_bg_l: + //setup + if (type == CLCIT_GROUP) { + changeToFont(FONTID_GROUPS); + GetTextExtentPoint32(hdcMem, contact->szText, lstrlen(contact->szText), &textSize); + width = textSize.cx; + szCounts = pcli->pfnGetGroupCountsText(dat, contact); + if (szCounts[0]) { + GetTextExtentPoint32W(hdcMem, L" ", 1, &spaceSize); + changeToFont(FONTID_GROUPCOUNTS); + GetTextExtentPoint32W(hdcMem, szCounts, lstrlenW(szCounts), &countsSize); + width += spaceSize.cx + countsSize.cx; + wszCounts = szCounts; + } + } else if (type == CLCIT_INFO) { + if (flags & CLCIIF_GROUPFONT) + changeToFont(FONTID_GROUPS); + else + changeToFont(FONTID_CONTACTS); + } else if (type == CLCIT_DIVIDER) { + changeToFont(FONTID_DIVIDERS); + GetTextExtentPoint32(hdcMem, contact->szText, lstrlen(contact->szText), &textSize); + } + else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST) + changeToFont(FONTID_NOTONLIST); + else if (type == CLCIT_CONTACT && ((flags & CONTACTF_INVISTO && GetRealStatus(contact, my_status) != ID_STATUS_INVISIBLE) || (flags & CONTACTF_VISTO && GetRealStatus(contact, my_status) == ID_STATUS_INVISIBLE))) { + changeToFont(flags & CONTACTF_ONLINE ? FONTID_INVIS : FONTID_OFFINVIS); + } else if (type == CLCIT_CONTACT && !(flags & CONTACTF_ONLINE)) + changeToFont(FONTID_OFFLINE); + else + changeToFont(FONTID_CONTACTS); + + if ((style & CLS_CHECKBOXES && type == CLCIT_CONTACT) || (style & CLS_GROUPCHECKBOXES && type == CLCIT_GROUP) || (type == CLCIT_INFO && flags & CLCIIF_CHECKBOX)) + checkboxWidth = dat->checkboxSize + 2; + else + checkboxWidth = 0; + + rc.left = 0; + cstatus = contact->wStatus; + + /***** BACKGROUND DRAWING *****/ + // contacts + + CLC::fHottrackDone = false; + + if(dat->bisEmbedded) { + rc.left = bg_indent_l; + rc.top = y; + rc.right = clRect->right - bg_indent_r; + rc.bottom = y + rowHeight; + if (fSelected) { + FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_HIGHLIGHT)); + Gfx::setTextColor(dat->selTextColour); + } + else { + FillRect(hdcMem, &rc, type == CLCIT_GROUP ? cfg::dat.hBrushCLCGroupsBk : cfg::dat.hBrushCLCBk); + if(CLC::iHottrackItem) + setHotTrackColour(); + } + goto bgskipped; + } + if (type == CLCIT_CONTACT || type == CLCIT_DIVIDER) { + TStatusItem *sitem, *pp_item; + + if (cstatus >= ID_STATUS_OFFLINE && cstatus <= ID_STATUS_OUTTOLUNCH) { + BYTE perstatus_ignored; + + if((flags & CONTACTF_IDLE) && !Skin::statusItems[ID_EXTBKIDLE].IGNORED) + sitem = &Skin::statusItems[ID_EXTBKIDLE]; + else + sitem = &Skin::statusItems[cstatus - ID_STATUS_OFFLINE]; + + if(!dat->bisEmbedded) { + pp_item = cEntry->status_item ? cEntry->status_item : cEntry->proto_status_item; + + if (!(perstatus_ignored = sitem->IGNORED) && !(flags & CONTACTF_NOTONLIST)) + Gfx::setTextColor(sitem->TEXTCOLOR); + + if(cfg::dat.bUsePerProto && pp_item && !pp_item->IGNORED) { + sitem = pp_item; + if((perstatus_ignored || cfg::dat.bOverridePerStatusColors) && sitem->TEXTCOLOR != -1) + Gfx::setTextColor(sitem->TEXTCOLOR); + } + } + else if(!sitem->IGNORED) + Gfx::setTextColor(sitem->TEXTCOLOR); + + rc.left = sitem->MARGIN_LEFT + bg_indent_l; + rc.top = y + sitem->MARGIN_TOP; + rc.right = clRect->right - sitem->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - sitem->MARGIN_BOTTOM; + + // single item in a group + if (!ssingleitem->IGNORED && scanIndex == 0 && group->cl.count == 1 && group->parent != NULL) { + rc.left = ssingleitem->MARGIN_LEFT + bg_indent_l; + rc.top = y + ssingleitem->MARGIN_TOP; + rc.right = clRect->right - ssingleitem->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - ssingleitem->MARGIN_BOTTOM; + + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, ssingleitem, &rc); + + // first item in a group + } else if (scanIndex == 0 && group->cl.count > 1 && !sfirstitem->IGNORED && group->parent != NULL) { + rc.left = sfirstitem->MARGIN_LEFT + bg_indent_l; + rc.top = y + sfirstitem->MARGIN_TOP; + rc.right = clRect->right - sfirstitem->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - sfirstitem->MARGIN_BOTTOM; + + current_shape = sfirstitem->rect; + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, sfirstitem, &rc); + + // last item in a group + } else if (scanIndex == group->cl.count - 1 && !slastitem->IGNORED && group->parent != NULL) { + rc.left = slastitem->MARGIN_LEFT + bg_indent_l; + rc.top = y + slastitem->MARGIN_TOP; + rc.right = clRect->right - slastitem->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - slastitem->MARGIN_BOTTOM; + rc.bottom = y + rowHeight - slastitem->MARGIN_BOTTOM; + + current_shape = slastitem->rect; + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, slastitem, &rc); + } else { + // - - - Non-grouped items - - - + if (type != CLCIT_GROUP && group->parent == NULL && !sfirstitem_NG->IGNORED && scanIndex != group->cl.count - 1 && !(bFirstNGdrawn)) { + // first NON-grouped + bFirstNGdrawn = TRUE; + rc.left = sfirstitem_NG->MARGIN_LEFT + bg_indent_l; + rc.top = y + sfirstitem_NG->MARGIN_TOP; + rc.right = clRect->right - sfirstitem_NG->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - sfirstitem_NG->MARGIN_BOTTOM; + + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, sfirstitem, &rc); + + } else if (type != CLCIT_GROUP && group->parent == NULL && !slastitem_NG->IGNORED && scanIndex == group->cl.count - 1 && (bFirstNGdrawn)) { + // last item of list (NON-group) + // last NON-grouped + rc.left = slastitem_NG->MARGIN_LEFT + bg_indent_l; + rc.top = y + slastitem_NG->MARGIN_TOP; + rc.right = clRect->right - slastitem_NG->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - slastitem_NG->MARGIN_BOTTOM; + + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, slastitem, &rc); + } else if (type != CLCIT_GROUP && group->parent == NULL && !slastitem_NG->IGNORED && !(bFirstNGdrawn)) { + // single item of NON-group + // single NON-grouped + rc.left = ssingleitem_NG->MARGIN_LEFT + bg_indent_l; + rc.top = y + ssingleitem_NG->MARGIN_TOP; + rc.right = clRect->right - ssingleitem_NG->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - ssingleitem_NG->MARGIN_BOTTOM; + + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if (!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + Gfx::renderSkinItem(this, ssingleitem, &rc); + } else { + // draw default grouped + // draw odd/even contact underlay + if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED) + Gfx::renderSkinItem(this, sevencontact_pos, &rc); + else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED) + Gfx::renderSkinItem(this, soddcontact_pos, &rc); + + if(!sitem->IGNORED) + Gfx::renderSkinItem(this, sitem, &rc); + } + } + } + } + if (type == CLCIT_GROUP) { + TStatusItem *sempty = &Skin::statusItems[ID_EXTBKEMPTYGROUPS]; + TStatusItem *sexpanded = &Skin::statusItems[ID_EXTBKEXPANDEDGROUP]; + TStatusItem *scollapsed = &Skin::statusItems[ID_EXTBKCOLLAPSEDDGROUP]; + + changeToFont(FONTID_GROUPS); + if (contact->group->cl.count == 0) { + if (!sempty->IGNORED) { + rc.left = sempty->MARGIN_LEFT + bg_indent_l; + rc.top = y + sempty->MARGIN_TOP; + rc.right = clRect->right - sempty->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - sempty->MARGIN_BOTTOM; + Gfx::renderSkinItem(this, sempty, &rc); + oldGroupColor = GetTextColor(hdcMem); + Gfx::setTextColor(sempty->TEXTCOLOR); + } + } else if (contact->group->expanded) { + if (!sexpanded->IGNORED) { + rc.left = sexpanded->MARGIN_LEFT + bg_indent_l; + rc.top = y + sexpanded->MARGIN_TOP; + rc.right = clRect->right - sexpanded->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - (char) sexpanded->MARGIN_BOTTOM; + Gfx::renderSkinItem(this, sexpanded, &rc); + oldGroupColor =GetTextColor(hdcMem); + Gfx::setTextColor(sexpanded->TEXTCOLOR); + } + } else { + if (!scollapsed->IGNORED) { + // collapsed but not empty + rc.left = scollapsed->MARGIN_LEFT + bg_indent_l; + rc.top = y + scollapsed->MARGIN_TOP; + rc.right = clRect->right - scollapsed->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - scollapsed->MARGIN_BOTTOM; + Gfx::renderSkinItem(this, scollapsed, &rc); + oldGroupColor = GetTextColor(hdcMem); + Gfx::setTextColor(scollapsed->TEXTCOLOR); + } + } + } + if (fSelected) { + TStatusItem *sselected = &Skin::statusItems[ID_EXTBKSELECTION]; + + if (!g_ignoreselforgroups || type != CLCIT_GROUP) { + rc.left = sselected->MARGIN_LEFT + bg_indent_l; + rc.top = y + sselected->MARGIN_TOP; + rc.right = clRect->right - sselected->MARGIN_RIGHT - bg_indent_r; + rc.bottom = y + rowHeight - sselected->MARGIN_BOTTOM; + Gfx::renderSkinItem(this, sselected, &rc); + Gfx::setTextColor(sselected->TEXTCOLOR); + } + } + else if (CLC::iHottrackItem) { + TStatusItem *ht = &Skin::statusItems[ID_EXTBKHOTTRACK]; + + if(ht->IGNORED == 0) + Gfx::setTextColor(ht->TEXTCOLOR); + if(!CLC::fHottrackDone) { + if (ht->IGNORED == 0) { + Gfx::renderSkinItem(this, ht, &rc); + } + } + } + + if(g_RTL) { + SetLayout(hdcMem, LAYOUT_RTL | LAYOUT_BITMAPORIENTATIONPRESERVED); + dxBufferDiff = dBufferDiff; + } + else + dxBufferDiff = 0; // adjust discrepancy between the width of the buffered paint dc and the actual window width (bug in buffered paint?) +bgskipped: + + rcContent.top = y + g_padding_y; + rcContent.bottom = y + rowHeight - (2 * g_padding_y); + rcContent.left = leftX + dxBufferDiff; + rcContent.right = clRect->right - dat->rightMargin + dxBufferDiff; + twoRows = ((dat->fontInfo[FONTID_STATUS].fontHeight + m_fontHeight <= rowHeight + 1) && (fSecondLine)) && !dat->bisEmbedded; + + pi_avatar = (!dat->bisEmbedded && fAvatar); + + //checkboxes + if (checkboxWidth) { + RECT rc; + + rc.left = leftX; + rc.right = rc.left + dat->checkboxSize; + rc.top = y + ((rowHeight - dat->checkboxSize) >> 1); + rc.bottom = rc.top + dat->checkboxSize; + if (hTheme) { + Api::pfnDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, flags & CONTACTF_CHECKED ? (CLC::iHottrackItem ? CBS_CHECKEDHOT : CBS_CHECKEDNORMAL) : + (CLC::iHottrackItem ? CBS_UNCHECKEDHOT : CBS_UNCHECKEDNORMAL), &rc, &rc); + } + else + DrawFrameControl(hdcMem, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | (flags & CONTACTF_CHECKED ? DFCS_CHECKED : 0) | (CLC::iHottrackItem ? DFCS_HOT : 0)); + rcContent.left += checkboxWidth; + leftX += checkboxWidth; + } + + if (type == CLCIT_GROUP) + iImage = (contact->group->expanded) ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT; + else if (type == CLCIT_CONTACT) + iImage = contact->iImage; + + + if(pi_avatar && (av_left || av_right)) { + RECT rc; + + rc.left = rcContent.left; + rc.right = clRect->right; + rc.top = y; + rc.bottom = rc.top + rowHeight; + + if(av_left) { + leftOffset += drawAvatar(&rc, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight); + rcContent.left += leftOffset; + leftX += leftOffset; + } + else { + rc.left = (rcContent.right - cfg::dat.avatarSize) + 1; + rightOffset += drawAvatar(&rc, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight); + rcContent.right -= (rightOffset); + } + } + else if(type == CLCIT_CONTACT && !dat->bisEmbedded && !g_selectiveIcon && (dwFlags & CLUI_FRAME_ALWAYSALIGNNICK) && av_local_wanted && (av_left || av_right)) { + if(av_right) + rcContent.right -= (cfg::dat.avatarSize + 2); + if(av_left) + rcContent.left += (cfg::dat.avatarSize + 2); + } + //icon + + // skip icon for groups if the option is enabled... + + if(type == CLCIT_GROUP && dwFlags & CLUI_FRAME_NOGROUPICON) { + iconXSpace = 0; + goto text; + } + if (iImage != -1) { + // this doesnt use CLS_CONTACTLIST since the colour prolly wont match anyway + COLORREF colourFg = dat->selBkColour; + //int clientId = contact->clientId; + int mode = ILD_NORMAL; + pi_selectiveIcon = g_selectiveIcon && (type == CLCIT_CONTACT); + + if((dwFlags & CLUI_FRAME_STATUSICONS && !pi_selectiveIcon) || type != CLCIT_CONTACT || (pi_selectiveIcon && !avatar_done)) { + HIMAGELIST hImgList = CLC::hClistImages; + + if (CLC::iHottrackItem) { + colourFg = dat->hotTextColour; + } else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST) { + colourFg = dat->fontInfo[FONTID_NOTONLIST].colour; + mode = ILD_BLEND50; + } + if (type == CLCIT_CONTACT && dat->showIdle && (flags & CONTACTF_IDLE) && contact->wStatus != ID_STATUS_OFFLINE) + mode = ILD_SELECTED; + + if(pi_selectiveIcon && av_right) { + ImageList_DrawEx(hImgList, iImage, hdcMem, rcContent.right - 18, (twoRows && type == CLCIT_CONTACT && !cfg::dat.bCenterStatusIcons) ? y + 2 : y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode); + rcContent.right -= 18; + } + else { + LONG offset = 0; + BOOL centered = FALSE; + offset += (type != CLCIT_CONTACT || avatar_done || !(av_local_wanted) ? 20 : dwFlags & CLUI_FRAME_ALWAYSALIGNNICK && av_left && g_selectiveIcon ? cfg::dat.avatarSize + 2 : 20); + centered = (cfg::dat.bCenterStatusIcons && offset == cfg::dat.avatarSize + 2); + ImageList_DrawEx(hImgList, iImage, hdcMem, centered ? rcContent.left + offset / 2 - 10 : rcContent.left, (twoRows && type == CLCIT_CONTACT && !cfg::dat.bCenterStatusIcons) ? y + 2 : y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode); + rcContent.left += offset; + } + } + else + iconXSpace = 0; + if (type == CLCIT_CONTACT && !dat->bisEmbedded) { + BYTE bApparentModeDontCare = !((flags & CONTACTF_VISTO) ^ (flags & CONTACTF_INVISTO)); + contact->extraIconRightBegin = 0; + if(cEntry && (contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry && cEntry->iExtraValid)) { + int i, iIndex, id; + DWORD dwOldMask = cEntry->dwXMask; + + for(i = EXICON_COUNT - 1; i >= 0; i--) { + iIndex = cfg::dat.exIconOrder[i] - 1; + if(iIndex >= 0 && iIndex < EXICON_COUNT) { + id = OrderTreeData[iIndex].ID; + if(cEntry->iExtraImage[id] != 0xff && ((1 << id) & cEntry->dwXMask)) { + if(contact->extraIconRightBegin == 0 && i != (EXICON_COUNT - 1)) + contact->extraIconRightBegin = rcContent.right; + ImageList_DrawEx(dat->himlExtraColumns, cEntry->iExtraImage[id], hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1), + 0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL); + rcContent.right -= g_exIconSpacing; + rightIcons++; + } + } + } + cEntry->dwXMask = dwOldMask; + } + if (!bApparentModeDontCare && (dwFlags & CLUI_SHOWVISI) && contact->proto) { + BOOL fVisi; + + if(dwFlags & CLUI_SHOWVISI) + fVisi = contact->dwDFlags & ECF_HIDEVISIBILITY ? 0 : 1; + else + fVisi = contact->dwDFlags & ECF_FORCEVISIBILITY ? 1 : 0; + + if(fVisi) { + if(cEntry->isChatRoom) + DrawIconEx(hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1), + cfg::dat.hIconChatactive, cfg::dat.exIconScale, cfg::dat.exIconScale, 0, 0, DI_NORMAL | DI_COMPAT); + else + DrawIconEx(hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1), + flags & CONTACTF_VISTO ? cfg::dat.hIconVisible : cfg::dat.hIconInvisible, cfg::dat.exIconScale, cfg::dat.exIconScale, 0, 0, DI_NORMAL | DI_COMPAT); + rcContent.right -= g_exIconSpacing; + rightIcons++; + } + } + } + } + //text +text: + if (type == CLCIT_DIVIDER) { + RECT rc, rcText; + rc.top = y + ((rowHeight) >> 1) - 1; rc.bottom = rc.top + 2; + rc.left = clRect->left + dat->leftMargin; + rc.right = rc.left - dat->rightMargin + ((clRect->right - rc.left - textSize.cx) >> 1) - 3; + DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT); + Api::pfnBufferedPaintSetAlpha(hbp, &rc, 255); + rcText.left = rc.right + 3; + rcText.top = y; + rcText.bottom = y + rowHeight; + rcText.right = rcText.left + textSize.cx; + Gfx::renderText(hdcMem, hTheme, contact->szText, &rcText, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + rc.left = rc.right + 6 + textSize.cx; + rc.right = clRect->right - dat->rightMargin; + DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT); + Api::pfnBufferedPaintSetAlpha(hbp, &rc, 255); + } else if (type == CLCIT_GROUP) { + RECT rc; + m_fontHeight = dat->fontInfo[FONTID_GROUPS].fontHeight; + rc.top = y + ((rowHeight - m_fontHeight) >> 1) + cfg::dat.group_padding; + rc.bottom = rc.top + textSize.cy; + if (szCounts[0]) { + int required, labelWidth, offset = 0; + COLORREF clr = GetTextColor(hdcMem); + + changeToFont(FONTID_GROUPCOUNTS); + if(oldGroupColor != -1) + Gfx::setTextColor(clr); + + rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + iconXSpace; + rc.right = clRect->right - dat->rightMargin; + + if(indent == 0 && iconXSpace == 0) + rc.left += 2; + + required = textSize.cx + countsSize.cx + spaceSize.cx; + + if(required > rc.right - rc.left) + textSize.cx = (rc.right - rc.left) - countsSize.cx - spaceSize.cx; + + labelWidth = textSize.cx + countsSize.cx + spaceSize.cx; + if(g_center) + offset = ((rc.right - rc.left) - labelWidth) / 2; + + RECT rcCounts = rc; + rcCounts.left += (offset + textSize.cx + spaceSize.cx + dxBufferDiff); + rcCounts.right += dxBufferDiff; + rcCounts.top += groupCountsFontTopShift; + Gfx::renderText(hdcMem, hTheme, wszCounts, &rcCounts, DT_SINGLELINE); + mir_free(wszCounts); + + if (fSelected && !g_ignoreselforgroups) + clr = dat->selTextColour; + else + Gfx::setTextColor(clr); + changeToFont(FONTID_GROUPS); + rc.left += (offset + dxBufferDiff); + rc.right = rc.left + textSize.cx; + qLeft = rc.left; + + Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS); + } else if (g_center && !szCounts[0]) { + int offset; + + rc.left = rcContent.left; + rc.right = clRect->right - dat->rightMargin; + if(textSize.cx >= rc.right - rc.left) + textSize.cx = rc.right - rc.left; + + offset = ((rc.right - rc.left) - textSize.cx) / 2; + rc.left += (offset + dxBufferDiff); + rc.right = rc.left + textSize.cx + dxBufferDiff; + Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE); + qLeft = rc.left; + } else { + qLeft = rcContent.left + (indent == 0 && iconXSpace == 0 ? 2 : 0); + rc.left = qLeft; + rc.right = min(rc.left + textSize.cx, clRect->right - dat->rightMargin) + dxBufferDiff; + Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS); + } + } else { + wchar_t *szText = contact->szText; + + rcContent.top = y + ((rowHeight - m_fontHeight) >> 1); + + // avatar + + if(!dat->bisEmbedded) { + if(av_local_wanted && !avatar_done && pi_avatar) { + if(av_rightwithnick) { + RECT rcAvatar = rcContent; + + rcAvatar.left = rcContent.right - (cfg::dat.avatarSize - 1); + drawAvatar(&rcAvatar, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight); + rcContent.right -= (cfg::dat.avatarSize + 2); + } + else + rcContent.left += drawAvatar(&rcContent, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight); + } + else if(dwFlags & CLUI_FRAME_ALWAYSALIGNNICK && !avatar_done && av_local_wanted) + rcContent.left += (dwFlags & (CLUI_FRAME_AVATARSLEFT | CLUI_FRAME_AVATARSRIGHT | CLUI_FRAME_AVATARSRIGHTWITHNICK) ? 0 : cfg::dat.avatarSize + 2); + } + + // nickname + if(!twoRows) + Gfx::renderText(hdcMem, hTheme, szText, &rcContent, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE | dt_nickflags); + else { + DWORD dtFlags = DT_WORD_ELLIPSIS | DT_NOPREFIX | DT_NOCLIP | DT_SINGLELINE; + DWORD saved_right = rcContent.right; + BOOL verticalfit = FALSE; + + rcContent.top = y + cfg::dat.avatarPadding / 2; + + if(cfg::dat.bShowLocalTime) + fLocalTime = contact->dwDFlags & ECF_HIDELOCALTIME ? 0 : 1; + else + fLocalTime = contact->dwDFlags & ECF_FORCELOCALTIME ? 1 : 0; + + if(cEntry->hTimeZone != 0 && fLocalTime) { + wchar_t szResult[80]; + int idOldFont; + SIZE szTime; + RECT rc = rcContent; + COLORREF oldColor = 0; + + if (TimeZone_PrintDateTime(cEntry->hTimeZone, _T("t"), szResult, _countof(szResult), 0))
+ goto nodisplay;
+ + oldColor = Gfx::getTextColor(); + idOldFont = dat->currentFontID; + changeToFont(FONTID_TIMESTAMP); + GetTextExtentPoint32(hdcMem, szResult, lstrlenW(szResult), &szTime); + verticalfit = ((rowHeight - szTime.cy) >= (cfg::dat.exIconScale + 1)); + + if(av_right) { + if(verticalfit) + rc.left = rcContent.right + (rightIcons * g_exIconSpacing) - szTime.cx - 2; + else + rc.left = rcContent.right - szTime.cx - 2; + } + else if(av_rightwithnick) { + if(verticalfit && rightIcons * g_exIconSpacing >= szTime.cx) + rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff; + else if(verticalfit && !avatar_done) + rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff; + else { + rc.left = rcContent.right - szTime.cx - 2; + rcContent.right = rc.left - 2; + } + } + else { + if(verticalfit) + rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff; + else + rc.left = rcContent.right - szTime.cx - 2; + } + rc.right = clRect->right + dxBufferDiff; + Gfx::renderText(hdcMem, hTheme, szResult, &rc, DT_NOPREFIX | DT_NOCLIP | DT_SINGLELINE); + changeToFont(idOldFont); + Gfx::setTextColor(oldColor); + + verticalfit = (rowHeight - m_fontHeight >= cfg::dat.exIconScale + 1); + if(verticalfit && av_right) + rcContent.right = min((clRect->right - cfg::dat.avatarSize - 2) + dxBufferDiff, rc.left - 2); + else if(verticalfit && !av_rightwithnick) + rcContent.right = min((clRect->right - dat->rightMargin) + dxBufferDiff, rc.left - 3); + + } + else { +nodisplay: + verticalfit = (rowHeight - m_fontHeight >= cfg::dat.exIconScale + 1); + if(avatar_done) { + if(verticalfit && av_right) + rcContent.right = (clRect->right - cfg::dat.avatarSize - 2) + dxBufferDiff; + else if(verticalfit && !av_rightwithnick) + rcContent.right = (clRect->right - dat->rightMargin) + dxBufferDiff; + } + } + Gfx::renderText(hdcMem, hTheme, szText, &rcContent, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE | dt_nickflags); + + rcContent.right = saved_right; + rcContent.top += (m_fontHeight - 1); + hPreviousFont = changeToFont(FONTID_STATUS); + rcContent.bottom = y + rowHeight; + + if(cstatus >= ID_STATUS_OFFLINE && cstatus <= ID_STATUS_OUTTOLUNCH) { + wchar_t *szText = NULL; + BYTE smsgValid = cEntry->bStatusMsgValid; + + if((dwFlags & CLUI_FRAME_SHOWSTATUSMSG && smsgValid > STATUSMSG_XSTATUSID) || smsgValid == STATUSMSG_XSTATUSNAME) + szText = cEntry->statusMsg; + else + szText = &statusNames[cstatus - ID_STATUS_OFFLINE][0]; + if(cEntry->dwCFlags & ECF_RTLSTATUSMSG && cfg::dat.bUseDCMirroring == 3) + dt_2ndrowflags |= (DT_RTLREADING | DT_RIGHT); + + if(rightIcons == 0) { + if((rcContent.bottom - rcContent.top) >= (2 * m_fontHeight)) { + dtFlags &= ~(DT_SINGLELINE | DT_BOTTOM | DT_NOCLIP); + dtFlags |= DT_WORDBREAK; + rcContent.bottom -= ((rcContent.bottom - rcContent.top) % m_fontHeight); + } + Gfx::renderText(hdcMem, hTheme, szText, &rcContent, dtFlags | dt_2ndrowflags); + } + else { + if((rcContent.bottom - rcContent.top) < (2 * m_fontHeight) - 2) + Gfx::renderText(hdcMem, hTheme, szText, &rcContent, dtFlags | dt_2ndrowflags); + else { + DRAWTEXTPARAMS dtp = {0}; + LONG rightIconsTop = rcContent.bottom - g_exIconSpacing; + LONG old_right = rcContent.right; + ULONG textCounter = 0; + ULONG ulLen = lstrlen(szText); + LONG old_bottom = rcContent.bottom; + DWORD i_dtFlags = DT_WORDBREAK | DT_NOPREFIX | dt_2ndrowflags; + dtp.cbSize = sizeof(dtp); + rcContent.right = clRect->right - dat->rightMargin - rightOffset; + do { + if(rcContent.top + (m_fontHeight - 1) > rightIconsTop + 1) + rcContent.right = old_right; + dtp.uiLengthDrawn = 0; + rcContent.bottom = rcContent.top + m_fontHeight - 1; + if(rcContent.bottom + m_fontHeight >= old_bottom) + i_dtFlags |= DT_END_ELLIPSIS; + DrawTextEx(hdcMem, &szText[textCounter], -1, &rcContent, i_dtFlags | DT_CALCRECT, &dtp); + if(dtp.uiLengthDrawn) + Gfx::renderText(hdcMem, hTheme, &szText[textCounter], &rcContent, i_dtFlags, 0, dtp.uiLengthDrawn); + rcContent.top += m_fontHeight; + textCounter += dtp.uiLengthDrawn; + } while (textCounter <= ulLen && dtp.uiLengthDrawn && rcContent.top + m_fontHeight <= old_bottom); + } + } + } + } + } + if (fSelected) { + if (type != CLCIT_DIVIDER) { + wchar_t *szText = contact->szText; + RECT rc; + int qlen = lstrlen(dat->szQuickSearch); + if(hPreviousFont) + SelectObject(hdcMem, hPreviousFont); + Gfx::setTextColor(dat->quickSearchColour); + if(type == CLCIT_CONTACT) { + rc.left = rcContent.left; + rc.top = y + ((rowHeight - m_fontHeight) >> 1); + rc.right = clRect->right - rightOffset; + rc.right = rcContent.right; + rc.bottom = rc.top; + if(twoRows) + rc.top = y; + } + else { + rc.left = qLeft; + rc.top = y + ((rowHeight - m_fontHeight) >> 1); + rc.right = clRect->right - rightOffset; + rc.bottom = rc.top; + } + if (qlen) + Gfx::renderText(hdcMem, hTheme, szText, &rc, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE); + } + } + //extra icons + DWORD spacing = 1; + for (int i = dat->extraColumnsCount - 1; i >= 0; i--) { + COLORREF colourFg = dat->selBkColour; + int mode = ILD_NORMAL; + if (contact->iExtraImage[i] == 0xffff) + continue; + if (fSelected) + mode = ILD_SELECTED; + else if (CLC::iHottrackItem) { + mode = ILD_FOCUS; colourFg = dat->hotTextColour; + } else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST) { + colourFg = dat->fontInfo[FONTID_NOTONLIST].colour; mode = ILD_BLEND50; + } + ImageList_DrawEx(dat->himlExtraColumns, contact->iExtraImage[i], hdcMem, clRect->right - rightOffset - dat->extraColumnSpacing * (spacing++), y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode); + } + if(g_RTL) + SetLayout(hdcMem, 0); +} + +void CLC::Paint(HWND hwnd, ClcData *dat, HDC hdc, RECT *rcPaint) +{ + RGBQUAD* rgq = 0; + ClcContact* contact; + int ipxWidth = 0; + HDC hdcMem; + RECT clRect; + ClcGroup* group; + HANDLE hbp = 0; + HFONT hOldFont = 0; + DWORD style = GetWindowLong(hwnd, GWL_STYLE); + int grey = 0, groupCountsFontTopShift; + int line_num = -1; + COLORREF tmpbkcolour = style & CLS_CONTACTLIST ? (dat->useWindowsColours ? GetSysColor(COLOR_3DFACE) : dat->bkColour) : dat->bkColour; + BOOL isFloating = (wndFrameCLC && wndFrameCLC->floating) ? TRUE : FALSE; + bool fFocusCheck; + + fInPaint = true; + g_focusWnd = GetFocus(); + my_status = getGeneralisedStatus(); + g_HDC = hdc; + + /* + * temporary DC for avatar drawing + */ + + g_padding_y = 0; + + hdcTempAV = CreateCompatibleDC(g_HDC); + hbmTempAV = CreateCompatibleBitmap(g_HDC, g_maxAV_X, g_maxAV_Y); + hbmTempOldAV = reinterpret_cast<HBITMAP>(SelectObject(hdcTempAV, hbmTempAV)); + + cfg::dat.t_now = time(NULL); + + /* + * setup static globals used by PaintItem(); + */ + av_left = (cfg::dat.dwFlags & CLUI_FRAME_AVATARSLEFT); + av_right = (cfg::dat.dwFlags & CLUI_FRAME_AVATARSRIGHT); + av_rightwithnick = (cfg::dat.dwFlags & CLUI_FRAME_AVATARSRIGHTWITHNICK); + + mirror_rtl = (cfg::dat.bUseDCMirroring == 2); + mirror_always = (cfg::dat.bUseDCMirroring == 1); + mirror_rtltext = (cfg::dat.bUseDCMirroring == 3); + + g_center = cfg::getByte("CLCExt", "EXBK_CenterGroupnames", 0) && !dat->bisEmbedded; + g_ignoreselforgroups = cfg::getByte("CLC", "IgnoreSelforGroups", 0); + g_exIconSpacing = cfg::dat.exIconScale + 2; + + /* + * check if list should be greyed out based on focus or current status + */ + if (GetForegroundWindow()!= pcli->hwndContactList && dat->greyoutFlags & GREYF_UNFOCUS) + grey = 1; + else if((dat->greyoutFlags & pcli->pfnClcStatusToPf2(my_status)) || style & WS_DISABLED) + grey = 1; + + GetClientRect(hwnd, &clRect); + if (rcPaint == NULL) + rcPaint = &clRect; + +#ifndef _USE_D2D + if (IsRectEmpty(rcPaint)) { + SelectObject(hdcTempAV, hbmTempOldAV); + DeleteObject(hbmTempAV); + DeleteDC(hdcTempAV); + return; + } +#endif + +#ifdef _USE_D2D + HBITMAP hbmMem, hbmMemOld; + if(hwnd == pcli->hwndContactTree) { + rcPaint = &clRect; + hdcMem = CreateCompatibleDC(cfg::dat.hdcBg); + hbmMem = Gfx::createRGBABitmap(clRect.right - clRect.left, clRect.bottom - clRect.top, hdcMem); + hbmMemOld = (HBITMAP)SelectObject(hdcMem, hbmMem); + } + else + hbp = Gfx::initiateBufferedPaint(hdc, clRect, hdcMem); +#else + /* explanation for this weird code.. (dBufferDiff etc..) + * a bufferend paint dc is normally not the same size as the client rectangle of a + * child window (CLC in this case). It's usually much wider. This isn't a problem + * for LTR rendering where everything starts at (0,0) but when using SetLayout() + * to mirror the DC (for RTL support) it becomes a HUGE problem, because right + * becomes left and content will vanish outside the client area. + * + * dBufferDiff is the difference between the width of the buffered DC and the width + * of the actual client rectangle. PaintItem() will add that offset to rcContent.left + * when rendering RTL rows to compensate for the difference in width. + * + */ + dBufferDiff = 0; + INIT_PAINT(hdc, clRect, hdcMem); + Api::pfnGetBufferedPaintBits(hbp, &rgq, &ipxWidth); + dBufferDiff = ipxWidth - clRect.right; +#endif + + { + TEXTMETRIC tm; + hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPS].hFont)); + GetTextMetrics(hdcMem, &tm); + groupCountsFontTopShift = tm.tmAscent; + SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPCOUNTS].hFont); + GetTextMetrics(hdcMem, &tm); + groupCountsFontTopShift -= tm.tmAscent; + } + + SetBkMode(hdcMem, TRANSPARENT); + if(!cfg::isAero || dat->bisEmbedded || isFloating) { + HBRUSH hBrush, hoBrush; + hBrush = CreateSolidBrush(tmpbkcolour); + hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush); + FillRect(hdcMem, rcPaint, hBrush); + SelectObject(hdcMem, hoBrush); + DeleteObject(hBrush); + } + + if(!dat->bisEmbedded && rcPaint && !isFloating) + Gfx::drawBGFromSurface(hwnd, *rcPaint, hdcMem); + + g_selectiveIcon = (CLC::uNrAvatars > 0) && (cfg::dat.dwFlags & CLUI_FRAME_SELECTIVEICONS) && !dat->bisEmbedded; + + group = &dat->list; + group->scanIndex = 0; + + CLCPaintHelper* ph = dat->ph; + + fFocusCheck = dat->showSelAlways || dat->exStyle &CLS_EX_SHOWSELALWAYS || g_focusWnd == hwnd; + + // set up the paint helper + ph->setHDC(hdcMem); + ph->aggctx->attach(rgq, ipxWidth, clRect.bottom); + ph->hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON"); + ph->style = style; + ph->clRect = &clRect; + ph->y = -dat->yScroll; + ph->indent = 0; + ph->bFirstNGdrawn = false; + ph->groupCountsFontTopShift = groupCountsFontTopShift; + ph->hbp = hbp; + + ph->sevencontact_pos = &Skin::statusItems[ID_EXTBKEVEN_CNTCTPOS]; + ph->soddcontact_pos = &Skin::statusItems[ID_EXTBKODD_CNTCTPOS]; + ph->sfirstitem = &Skin::statusItems[ID_EXTBKFIRSTITEM]; + ph->ssingleitem = &Skin::statusItems[ID_EXTBKSINGLEITEM]; + ph->slastitem = &Skin::statusItems[ID_EXTBKLASTITEM]; + + ph->sfirstitem_NG = &Skin::statusItems[ID_EXTBKFIRSTITEM_NG]; + ph->ssingleitem_NG = &Skin::statusItems[ID_EXTBKSINGLEITEM_NG]; + ph->slastitem_NG = &Skin::statusItems[ID_EXTBKLASTITEM_NG]; + + + hOldFont = ph->changeToFont(FONTID_CONTACTS); + + if ( dat->row_heights == NULL ) + RowHeight::calcRowHeights(dat, hwnd, ph); + + for (ph->index = 0; ph->y < rcPaint->bottom;) { + if (group->scanIndex == group->cl.count) { + group = group->parent; + ph->indent--; + if (group == NULL) { + break; + } + group->scanIndex++; + continue; + } + + line_num++; + contact = group->cl.items[group->scanIndex]; + if(cfg::dat.bForceRefetchOnPaint) + contact->ace = (struct avatarCacheEntry*)-1; + + if (ph->y > rcPaint->top - dat->row_heights[line_num] && ph->y <= rcPaint->bottom) { + if (contact->ace == (struct avatarCacheEntry*)-1 ) + contact->ace = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)group->cl.items[group->scanIndex]->hContact, 0); + + ph->fSelected = (ph->index == dat->selection && contact->type != CLCIT_DIVIDER && fFocusCheck); + iHottrackItem = dat->exStyle & CLS_EX_TRACKSELECT && contact->type == CLCIT_CONTACT && dat->iHotTrack == ph->index; + if (iHottrackItem == ph->fSelected) + iHottrackItem = 0; + if(ph->fSelected && dsp_default.dspOverride[DSP_OVR_SELECTED].fActive) + ph->dsp = &dsp_default.dspOverride[DSP_OVR_SELECTED]; + else if(iHottrackItem && dsp_default.dspOverride[DSP_OVR_HOVERED].fActive) + ph->dsp = &dsp_default.dspOverride[DSP_OVR_HOVERED]; + else if(ID_STATUS_OFFLINE == contact->wStatus) + ph->dsp = &dsp_default.dspOverride[DSP_OVR_OFFLINE]; + else if(ID_STATUS_OFFLINE != contact->wStatus) + ph->dsp = &dsp_default.dspOverride[DSP_OVR_ONLINE]; + else + ph->dsp = 0; // calc dsp profile + RowHeight::getRowHeight(dat, contact, line_num, style, ph); + ph->Paint(group, contact, dat->row_heights[line_num]); + } + ph->index++; + ph->y += dat->row_heights[line_num]; + if (contact->type == CLCIT_GROUP && (contact->group->expanded)) { + group = contact->group; + ph->indent++; + group->scanIndex = 0; + continue; + } + group->scanIndex++; + } + + SelectObject(hdcTempAV, hbmTempOldAV); + DeleteObject(hbmTempAV); + DeleteDC(hdcTempAV); + Api::pfnCloseThemeData(ph->hTheme); + + if (dat->iInsertionMark != -1) { + //insertion mark + HBRUSH hBrush, hoBrush; + POINT pts[8]; + HRGN hRgn; + + pts[0].x=dat->leftMargin; pts[0].y = RowHeight::getItemTopY(dat, dat->iInsertionMark) - dat->yScroll - 4; + //pts[0]. x = dat->leftMargin; pts[0]. y = dat->iInsertionMark * rowHeight - dat->yScroll - 4; + pts[1]. x = pts[0].x + 2; pts[1]. y = pts[0].y + 3; + pts[2]. x = clRect.right - 4; pts[2]. y = pts[1].y; + pts[3]. x = clRect.right - 1; pts[3]. y = pts[0].y - 1; + pts[4]. x = pts[3].x; pts[4]. y = pts[0].y + 7; + pts[5]. x = pts[2].x + 1; pts[5]. y = pts[1].y + 2; + pts[6]. x = pts[1].x; pts[6]. y = pts[5].y; + pts[7]. x = pts[0].x; pts[7]. y = pts[4].y; + hRgn = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE); + hBrush = CreateSolidBrush(dat->fontInfo[FONTID_CONTACTS].colour); + hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush); + FillRgn(hdcMem, hRgn, hBrush); + SelectObject(hdcMem, hoBrush); + DeleteObject(hBrush); + } + if(hOldFont) + SelectObject(hdcMem, hOldFont); + + fInPaint = false; + if (grey) + Skin::renderNamedImageItem("@GreyOut", &clRect, hdcMem); + +#if defined _USE_D2D + if(hwnd == pcli->hwndContactTree) { + MapWindowPoints(pcli->hwndContactTree, pcli->hwndContactList, (POINT*)&clRect, 2); + Gfx::setBitmapAlpha(hbmMem, 0); + Api::pfnAlphaBlend(cfg::dat.hdcBg, clRect.left, clRect.top, clRect.right - clRect.left, clRect.bottom - clRect.top, + hdcMem, 0, 0, clRect.right - clRect.left, clRect.bottom - clRect.top, CLUI::bf); + SelectObject(hdcMem, hbmMemOld); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + CLUI::updateLayers(); + } + else + FINALIZE_PAINT(hbp, &clRect); +#else + //delete _g; + FINALIZE_PAINT(hbp, &clRect, isFloating ? 255 : 0); +#endif +} diff --git a/plugins/Clist_ng/SRC/clcutils.cpp b/plugins/Clist_ng/SRC/clcutils.cpp new file mode 100644 index 0000000000..440832a7e1 --- /dev/null +++ b/plugins/Clist_ng/SRC/clcutils.cpp @@ -0,0 +1,591 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clcutils.cpp 134 2010-10-01 10:23:10Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <richedit.h>
+#include "../coolsb/coolscroll.h"
+
+static int MY_pathIsAbsolute(const wchar_t *path)
+{
+ if (!path || !(lstrlen(path) > 2))
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+/**
+ * performs hit-testing for reversed (mirrored) contact rows when using RTL
+ * shares all the init stuff with HitTest(), but needs to reverse the
+ * x-coordinate.
+ */
+
+int CLC::RTL_HitTest(HWND hwnd, ClcData *dat, int testx, int testy, ClcContact *hitcontact, DWORD *flags, int indent, int hit)
+{
+ RECT clRect;
+ int right, checkboxWidth, cxSmIcon, i, width;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ SIZE textSize;
+ HDC hdc;
+ HFONT hFont;
+
+ GetClientRect(hwnd, &clRect);
+ right = clRect.right;
+
+ // avatar check
+ if(hitcontact->type == CLCIT_CONTACT && cfg::dat.dwFlags & CLUI_FRAME_AVATARS && hitcontact->ace != NULL && hitcontact->avatarLeft != -1) {
+ if(testx < right - hitcontact->avatarLeft && testx > right - hitcontact->avatarLeft - cfg::dat.avatarSize) {
+ if(flags)
+ *flags |= CLCHT_ONAVATAR;
+ }
+ }
+ if (testx > right - (dat->leftMargin + indent * dat->groupIndent)) {
+ if (flags)
+ *flags |= CLCHT_ONITEMINDENT;
+ return hit;
+ }
+ checkboxWidth = 0;
+ if (style & CLS_CHECKBOXES && hitcontact->type == CLCIT_CONTACT)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (style & CLS_GROUPCHECKBOXES && hitcontact->type == CLCIT_GROUP)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (hitcontact->type == CLCIT_INFO && hitcontact->flags & CLCIIF_CHECKBOX)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (testx > right - (dat->leftMargin + indent * dat->groupIndent + checkboxWidth)) {
+ if (flags)
+ *flags |= CLCHT_ONITEMCHECK;
+ return hit;
+ }
+ if (testx > right - (dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace)) {
+ if (flags)
+ *flags |= CLCHT_ONITEMICON;
+ return hit;
+ }
+ cxSmIcon = GetSystemMetrics(SM_CXSMICON);
+ for (i = 0; i < dat->extraColumnsCount; i++) {
+ if (hitcontact->iExtraImage[i] == 0xFF)
+ continue;
+ if (testx >= dat->extraColumnSpacing * (dat->extraColumnsCount - i) && testx < dat->extraColumnSpacing * (dat->extraColumnsCount - i) + cxSmIcon) {
+ if (flags)
+ *flags |= CLCHT_ONITEMEXTRA | (i << 24);
+ return hit;
+ }
+ }
+ if(hitcontact->extraCacheEntry >= 0 && hitcontact->extraCacheEntry < cfg::nextCacheEntry && cfg::eCache[hitcontact->extraCacheEntry].iExtraValid) {
+ int rightOffset = hitcontact->extraIconRightBegin;
+ int images_present = 0;
+
+ for (i = 5; i >= 0; i--) {
+ if (cfg::eCache[hitcontact->extraCacheEntry].iExtraImage[i] == 0xFF)
+ continue;
+ if(!((1 << i) & cfg::eCache[hitcontact->extraCacheEntry].dwXMask))
+ continue;
+ images_present++;
+ if (testx < right - (rightOffset - (cfg::dat.exIconScale + 2) * images_present) && testx > right - (rightOffset - (cfg::dat.exIconScale + 2) * images_present + (cfg::dat.exIconScale))) {
+ if (flags)
+ *flags |= (CLCHT_ONITEMEXTRAEX | ((i + 1) << 24));
+ return hit;
+ }
+ }
+ }
+
+ hdc = GetDC(hwnd);
+ if (hitcontact->type == CLCIT_GROUP)
+ hFont = reinterpret_cast<HFONT>(SelectObject(hdc, dat->fontInfo[FONTID_GROUPS].hFont));
+ else
+ hFont = reinterpret_cast<HFONT>(SelectObject(hdc, dat->fontInfo[FONTID_CONTACTS].hFont));
+ GetTextExtentPoint32(hdc, hitcontact->szText, lstrlen(hitcontact->szText), &textSize);
+ width = textSize.cx;
+ if (hitcontact->type == CLCIT_GROUP) {
+ wchar_t *szCounts = pcli->pfnGetGroupCountsText(dat, hitcontact);
+ if (szCounts[0]) {
+ GetTextExtentPoint32W(hdc, L" ", 1, &textSize);
+ width += textSize.cx;
+ SelectObject(hdc, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextExtentPoint32W(hdc, szCounts, lstrlenW(szCounts), &textSize);
+ width += textSize.cx;
+ }
+ }
+ SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+ if (testx > right - (dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4 + (cfg::dat.dwFlags & CLUI_FRAME_AVATARS ? cfg::dat.avatarSize : 0))) {
+ if (flags)
+ *flags |= CLCHT_ONITEMLABEL;
+ return hit;
+ }
+ if (cfg::dat.dwFlags & CLUI_FULLROWSELECT && !(GetKeyState(VK_SHIFT) & 0x8000) && testx < right - (dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4 + (cfg::dat.dwFlags & CLUI_FRAME_AVATARS ? cfg::dat.avatarSize : 0))) {
+ if (flags)
+ *flags |= CLCHT_ONITEMSPACE;
+ return hit;
+ }
+ if (flags)
+ *flags |= CLCHT_NOWHERE;
+ return -1;
+}
+
+/**
+ * peform a hit testing and figure out on which item of a contact row the user clicked.
+ *
+ * @param hwnd clc control window handle
+ * @param dat clc data struct
+ * @param testx x coordinate (mouse)
+ * @param testy y coordinate (mouse)
+ * @param contact affected contact row
+ * @param group contact list group the contact is in
+ * @param flags internal flags
+ * @return DWORD value with flags describing the hit event
+ */
+int CLC::HitTest(HWND hwnd, ClcData *dat, int testx, int testy, ClcContact **contact, ClcGroup **group, DWORD *flags)
+{
+ struct ClcContact *hitcontact = 0;
+ struct ClcGroup *hitgroup = 0;
+ int hit, indent, width, i;
+ int checkboxWidth;
+ SIZE textSize;
+ HDC hdc;
+ RECT clRect;
+ HFONT hFont;
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ BYTE mirror_mode = cfg::dat.bUseDCMirroring;
+
+ if (flags)
+ *flags = 0;
+ GetClientRect(hwnd, &clRect);
+ if (testx < 0 || testy < 0 || testy >= clRect.bottom || testx >= clRect.right) {
+ if (flags) {
+ if (testx < 0)
+ *flags |= CLCHT_TOLEFT;
+ else if (testx >= clRect.right)
+ *flags |= CLCHT_TORIGHT;
+ if (testy < 0)
+ *flags |= CLCHT_ABOVE;
+ else if (testy >= clRect.bottom)
+ *flags |= CLCHT_BELOW;
+ }
+ return -1;
+ }
+ if (testx < dat->leftMargin) {
+ if (flags)
+ *flags |= CLCHT_INLEFTMARGIN | CLCHT_NOWHERE;
+ return -1;
+ }
+ hit = RowHeight::hitTest(dat, dat->yScroll + testy);
+ if (hit != -1)
+ hit = pcli->pfnGetRowByIndex(dat, hit, &hitcontact, &hitgroup);
+
+ if (hit == -1) {
+ if (flags)
+ *flags |= CLCHT_NOWHERE | CLCHT_BELOWITEMS;
+ return -1;
+ }
+ if (contact)
+ *contact = hitcontact;
+ if (group)
+ *group = hitgroup;
+
+ for (indent = 0; hitgroup->parent; indent++, hitgroup = hitgroup->parent) {
+ ;
+ }
+
+ if(!dat->bisEmbedded) {
+ if(hitcontact->type == CLCIT_CONTACT) {
+ if(mirror_mode == 1 || (mirror_mode == 2 && cfg::eCache[hitcontact->extraCacheEntry].dwCFlags & ECF_RTLNICK))
+ return RTL_HitTest(hwnd, dat, testx, testy, hitcontact, flags, indent, hit);
+ } else if(hitcontact->type == CLCIT_GROUP) {
+ if(cfg::dat.bGroupAlign == CLC_GROUPALIGN_RIGHT || (hitcontact->isRtl && cfg::dat.bGroupAlign == CLC_GROUPALIGN_AUTO))
+ return RTL_HitTest(hwnd, dat, testx, testy, hitcontact, flags, indent, hit);
+ }
+ }
+
+ // avatar check
+ if(hitcontact->type == CLCIT_CONTACT && cfg::dat.dwFlags & CLUI_FRAME_AVATARS && hitcontact->ace != NULL && hitcontact->avatarLeft != -1) {
+ if(testx > hitcontact->avatarLeft && testx < hitcontact->avatarLeft + cfg::dat.avatarSize) {
+ if(flags)
+ *flags |= CLCHT_ONAVATAR;
+ }
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent) {
+ if (flags)
+ *flags |= CLCHT_ONITEMINDENT;
+ return hit;
+ }
+ checkboxWidth = 0;
+ if (style & CLS_CHECKBOXES && hitcontact->type == CLCIT_CONTACT)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (style & CLS_GROUPCHECKBOXES && hitcontact->type == CLCIT_GROUP)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (hitcontact->type == CLCIT_INFO && hitcontact->flags & CLCIIF_CHECKBOX)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth) {
+ if (flags)
+ *flags |= CLCHT_ONITEMCHECK;
+ return hit;
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace) {
+ if (flags)
+ *flags |= CLCHT_ONITEMICON;
+ return hit;
+ }
+
+ int rightOffset = hitcontact->extraIconRightBegin;
+ if (rightOffset) {
+ for (i = dat->extraColumnsCount - 1; i >= 0; i--) {
+ if (hitcontact->iExtraImage[i] == EMPTY_EXTRA_ICON)
+ continue;
+
+ rightOffset -= dat->extraColumnSpacing;
+ if (testx > rightOffset && testx < rightOffset + dat->extraColumnSpacing) {
+ if (flags)
+ *flags |= (CLCHT_ONITEMEXTRA | (i << 24));
+ return hit;
+ }
+ }
+ }
+
+ if (hitcontact->extraCacheEntry >= 0 && hitcontact->extraCacheEntry < cfg::nextCacheEntry && cfg::eCache[hitcontact->extraCacheEntry].iExtraValid) {
+ //int rightOffset = clRect.right;
+ int rightOffset = hitcontact->extraIconRightBegin;
+ int images_present = 0;
+
+ for (i = 5; i >= 0; i--) {
+ if (cfg::eCache[hitcontact->extraCacheEntry].iExtraImage[i] == 0xFF)
+ continue;
+ if(!((1 << i) & cfg::eCache[hitcontact->extraCacheEntry].dwXMask))
+ continue;
+ images_present++;
+ if (testx > (rightOffset - (cfg::dat.exIconScale + 2) * images_present) && testx < (rightOffset - (cfg::dat.exIconScale + 2) * images_present + (cfg::dat.exIconScale))) {
+ if (flags)
+ *flags |= (CLCHT_ONITEMEXTRAEX | ((i + 1) << 24));
+ return hit;
+ }
+ }
+ }
+ hdc = GetDC(hwnd);
+ if (hitcontact->type == CLCIT_GROUP)
+ hFont = reinterpret_cast<HFONT>(SelectObject(hdc, dat->fontInfo[FONTID_GROUPS].hFont));
+ else
+ hFont = reinterpret_cast<HFONT>(SelectObject(hdc, dat->fontInfo[FONTID_CONTACTS].hFont));
+ GetTextExtentPoint32(hdc, hitcontact->szText, lstrlen(hitcontact->szText), &textSize);
+ width = textSize.cx;
+ if (hitcontact->type == CLCIT_GROUP) {
+ wchar_t *szCounts = pcli->pfnGetGroupCountsText(dat, hitcontact);
+ if (szCounts[0]) {
+ GetTextExtentPoint32W(hdc, L" ", 1, &textSize);
+ width += textSize.cx;
+ SelectObject(hdc, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextExtentPoint32W(hdc, szCounts, lstrlenW(szCounts), &textSize);
+ width += textSize.cx;
+ }
+ }
+ SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+ if (cfg::dat.dwFlags & CLUI_FULLROWSELECT && !(GetKeyState(VK_SHIFT) & 0x8000) && testx > dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4 + (cfg::dat.dwFlags & CLUI_FRAME_AVATARS ? cfg::dat.avatarSize : 0)) {
+ if (flags)
+ *flags |= CLCHT_ONITEMSPACE;
+ return hit;
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4 + (cfg::dat.dwFlags & CLUI_FRAME_AVATARS ? cfg::dat.avatarSize : 0)) {
+ if (flags)
+ *flags |= CLCHT_ONITEMLABEL;
+ return hit;
+ }
+ if (flags)
+ *flags |= CLCHT_NOWHERE;
+ return -1;
+}
+
+void CLC::ScrollTo(HWND hwnd, ClcData *dat, int desty, int noSmooth)
+{
+ DWORD startTick, nowTick;
+ int oldy = dat->yScroll;
+ RECT clRect, rcInvalidate;
+ int maxy, previousy;
+
+ if (dat->iHotTrack != -1 && dat->yScroll != desty) {
+ pcli->pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ dat->iHotTrack = -1;
+ ReleaseCapture();
+ }
+ GetClientRect(hwnd, &clRect);
+ rcInvalidate = clRect;
+
+ maxy = RowHeight::getTotalHeight(dat) - clRect.bottom;
+ if (desty > maxy)
+ desty = maxy;
+ if (desty < 0)
+ desty = 0;
+ if (abs(desty - dat->yScroll) < 4)
+ noSmooth = 1;
+ if (!noSmooth && dat->exStyle & CLS_EX_NOSMOOTHSCROLLING)
+ noSmooth = 1;
+ previousy = dat->yScroll;
+ if (!noSmooth) {
+ startTick = GetTickCount();
+ for (; ;) {
+ nowTick = GetTickCount();
+ if (nowTick >= startTick + dat->scrollTime)
+ break;
+ dat->yScroll = oldy + (desty - oldy) * (int) (nowTick - startTick) / dat->scrollTime;
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ previousy = dat->yScroll;
+ CoolSB_SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+ UpdateWindow(hwnd);
+ }
+ }
+ dat->yScroll = desty;
+ if(!noSmooth)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ InvalidateRect(hwnd, NULL, FALSE);
+
+ CoolSB_SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+ dat->forceScroll = 0;
+}
+
+void CLC::RecalcScrollBar(HWND hwnd, ClcData *dat)
+{
+ SCROLLINFO si = { 0 };
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ RowHeight::calcRowHeights(dat, hwnd, dat->ph);
+
+ GetClientRect(hwnd, &clRect);
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = pcli->pfnGetRowTotalHeight(dat) - 1;
+ si.nPage = clRect.bottom;
+ si.nPos = dat->yScroll;
+
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar == 0) {
+ if (cfg::dat.bSkinnedScrollbar && !dat->bisEmbedded)
+ CoolSB_SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ else
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ }
+ else {
+ if (cfg::dat.bSkinnedScrollbar && !dat->bisEmbedded)
+ CoolSB_SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ else
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ ScrollTo(hwnd, dat, dat->yScroll, 1);
+ nm.hdr.code = CLN_LISTSIZECHANGE;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.pt.y = si.nMax;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm);
+}
+
+void SetGroupExpand(HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState)
+{
+ int contentCount;
+ int groupy;
+ int newy;
+ int posy;
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ if (newState == -1)
+ group->expanded ^= 1;
+ else {
+ if (group->expanded == (newState != 0))
+ return;
+ group->expanded = newState != 0;
+ }
+ InvalidateRect(hwnd, NULL, FALSE);
+ contentCount = pcli->pfnGetGroupContentsCount(group, 1);
+
+ groupy = pcli->pfnGetRowsPriorTo(&dat->list, group, -1);
+ if(dat->selection > groupy && dat->selection < groupy + contentCount) dat->selection = groupy;
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+
+ GetClientRect(hwnd, &clRect);
+ newy = dat->yScroll;
+ posy = RowHeight::getItemBottomY(dat, groupy + contentCount);
+ if(posy >= newy + clRect.bottom)
+ newy = posy - clRect.bottom;
+ posy = RowHeight::getItemTopY(dat, groupy);
+ if(newy > posy) newy = posy;
+ CLC::ScrollTo(hwnd, dat, newy, 0);
+
+ nm.hdr.code = CLN_EXPANDED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.hItem = (HANDLE)group->groupId;
+ nm.action = (group->expanded);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
+}
+
+static WNDPROC OldRenameEditWndProc;
+static LRESULT CALLBACK RenameEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ pcli->pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 1);
+ return 0;
+ case VK_ESCAPE:
+ pcli->pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 0);
+ return 0;
+ }
+ break;
+
+ /*
+ * same as with embedded frames... let the richedit paint itself and
+ * capture it to the buffered paint DC.
+ */
+ case WM_PAINT: {
+ HDC hdc = GetDC(hwnd);
+ HDC hdcMem;
+ RECT rc;
+ HANDLE hbp = 0;
+
+ GetClientRect(hwnd, &rc);
+ INIT_PAINT(hdc, rc, hdcMem);
+ CallWindowProc(OldRenameEditWndProc, hwnd, msg, wParam, lParam);
+ Gfx::drawBGFromSurface(hwnd, rc, hdcMem);
+ BitBlt(hdcMem, 0, 0, rc.right, rc.bottom, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
+ FINALIZE_PAINT(hbp, &rc, 255);
+ ReleaseDC(hwnd, hdc);
+ return(0);
+ }
+
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN && msg->wParam == VK_TAB)
+ return 0;
+ if (msg->message == WM_CHAR && msg->wParam == '\t')
+ return 0;
+ }
+ return DLGC_WANTMESSAGE;
+ case WM_KILLFOCUS:
+ pcli->pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 1);
+ return 0;
+ }
+ return CallWindowProc(OldRenameEditWndProc, hwnd, msg, wParam, lParam);
+}
+
+void CLC::BeginRenameSelection(HWND hwnd, ClcData *dat)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int indent, x, y, h;
+ RECT clRect;
+
+ KillTimer(hwnd, TIMERID_RENAME);
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ dat->selection = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (dat->selection == -1)
+ return;
+ if (contact->type != CLCIT_CONTACT && contact->type != CLCIT_GROUP)
+ return;
+ for (indent = 0; group->parent; indent++, group = group->parent) {
+ ;
+ }
+ GetClientRect(hwnd, &clRect);
+ x = indent * dat->groupIndent + dat->iconXSpace - 2;
+ //y = dat->selection * dat->rowHeight - dat->yScroll;
+ y = RowHeight::getItemTopY(dat, dat->selection) - dat->yScroll;
+
+ h = dat->row_heights[dat->selection];
+ {
+ int i;
+ for (i = 0; i <= FONTID_LAST; i++)
+ if (h < dat->fontInfo[i].fontHeight + 2) h = dat->fontInfo[i].fontHeight + 2;
+ }
+ dat->hwndRenameEdit = CreateWindowEx(0, _T("RichEdit20W"), contact->szText, WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOHSCROLL, x, y, clRect.right - x, h, hwnd, NULL, g_hInst, NULL);
+ {
+ if((contact->type == CLCIT_CONTACT && cfg::eCache[contact->extraCacheEntry].dwCFlags & ECF_RTLNICK) || (contact->type == CLCIT_GROUP && contact->isRtl)) {
+ PARAFORMAT2 pf2;
+ ZeroMemory((void *)&pf2, sizeof(pf2));
+ pf2.cbSize = sizeof(pf2);
+ pf2.dwMask = PFM_RTLPARA;
+ pf2.wEffects = PFE_RTLPARA;
+ SetWindowText(dat->hwndRenameEdit, _T(""));
+ SendMessage(dat->hwndRenameEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ SetWindowText(dat->hwndRenameEdit, contact->szText);
+ }
+ }
+ //dat->hwndRenameEdit = CreateWindow(_T("EDIT"), contact->szText, WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, x, y, clRect.right - x, dat->rowHeight, hwnd, NULL, g_hInst, NULL);
+ OldRenameEditWndProc = (WNDPROC) SetWindowLongPtr(dat->hwndRenameEdit, GWLP_WNDPROC, (LONG_PTR) RenameEditSubclassProc);
+ SendMessage(dat->hwndRenameEdit, WM_SETFONT, (WPARAM) (contact->type == CLCIT_GROUP ? dat->fontInfo[FONTID_GROUPS].hFont : dat->fontInfo[FONTID_CONTACTS].hFont), 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN | EC_USEFONTINFO, 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETSEL, 0, (LPARAM) (-1));
+ ShowWindow(dat->hwndRenameEdit, SW_SHOW);
+ SetFocus(dat->hwndRenameEdit);
+}
+
+void CLC::LoadClcOptions(HWND hwnd, ClcData *dat, BOOL first)
+{
+ HDC hdc = GetDC(hwnd);
+ for (int i = 0; i <= FONTID_MAX; i++) {
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+
+ LOGFONT lf;
+ pcli->pfnGetFontSetting(i, &lf, &dat->fontInfo[i].colour);
+ lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+
+ dat->fontInfo[i].hFont = CreateFontIndirect(&lf);
+ dat->fontInfo[i].changed = 0;
+
+ HFONT holdfont = (HFONT)SelectObject(hdc, dat->fontInfo[i].hFont);
+ SIZE fontSize;
+ GetTextExtentPoint32(hdc, _T("x"), 1, &fontSize);
+ SelectObject(hdc, holdfont);
+
+ dat->fontInfo[i].fontHeight = fontSize.cy;
+ }
+ ReleaseDC(hwnd, hdc);
+ dat->min_row_heigh = (int)cfg::getByte("CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT);
+ dat->group_row_height = (int)cfg::getByte("CLC", "GRowHeight", CLCDEFAULT_ROWHEIGHT);
+ dat->row_border = 0;
+ dat->rightMargin = cfg::getByte("CLC", "RightMargin", CLCDEFAULT_LEFTMARGIN);
+ dat->bkColour = cfg::getDword("CLC", "BkColour", GetSysColor(COLOR_WINDOW));
+ if(cfg::dat.hBrushCLCBk)
+ DeleteObject(cfg::dat.hBrushCLCBk);
+ cfg::dat.hBrushCLCBk = CreateSolidBrush(dat->bkColour);
+
+ coreCli.pfnLoadClcOptions(hwnd, dat, first);
+
+ if(cfg::dat.hBrushCLCGroupsBk)
+ DeleteObject(cfg::dat.hBrushCLCGroupsBk);
+ cfg::dat.hBrushCLCGroupsBk = CreateSolidBrush(cfg::getDword("CLC", "BkColourGroups", GetSysColor(COLOR_3DFACE)));
+ DSP_LoadFromDefaults(&dsp_default);
+}
diff --git a/plugins/Clist_ng/SRC/clistevents.cpp b/plugins/Clist_ng/SRC/clistevents.cpp new file mode 100644 index 0000000000..e477a34bdf --- /dev/null +++ b/plugins/Clist_ng/SRC/clistevents.cpp @@ -0,0 +1,455 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clistevents.cpp 134 2010-10-01 10:23:10Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+static HWND hwndEventFrame = 0;
+
+extern FRAMEWND *wndFrameEventArea;
+
+extern HPEN g_hPenCLUIFrames;
+
+HWND g_hwndEventArea = 0;
+
+struct CListEvent {
+ int imlIconIndex;
+ int flashesDone;
+ CLISTEVENT cle;
+
+ int menuId;
+ int imlIconOverlayIndex;
+};
+
+struct CListImlIcon {
+ int index;
+ HICON hIcon;
+};
+
+static int iconsOn;
+
+HANDLE hNotifyFrame = (HANDLE) - 1;
+
+CListEvent* CLC::fnCreateEvent()
+{
+ CListEvent *p = reinterpret_cast<CListEvent *>(mir_alloc(sizeof(struct CListEvent)));
+ if(p)
+ ZeroMemory(p, sizeof(struct CListEvent));
+
+ return p;
+}
+
+void CLUI::hideShowNotifyFrame()
+{
+ int dwVisible = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, hNotifyFrame), 0) & F_VISIBLE;
+ int desired;
+
+ if(cfg::dat.dwFlags & CLUI_FRAME_AUTOHIDENOTIFY)
+ desired = cfg::dat.notifyActive ? TRUE : FALSE;
+ else
+ desired = dwVisible;
+
+ if(desired) {
+ if(!dwVisible)
+ CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)hNotifyFrame, 0);
+ } else {
+ if(dwVisible)
+ CallService(MS_CLIST_FRAMES_SHFRAME, (WPARAM)hNotifyFrame, 0);
+ }
+}
+
+static CLISTEVENT* MyGetEvent(int iSelection)
+{
+ int i;
+
+ for(i = 0; i < pcli->events.count; i++) {
+ struct CListEvent* p = pcli->events.items[i];
+ if(p->menuId == iSelection)
+ return &p->cle;
+ }
+ return NULL;
+}
+
+/**
+ * paint content of the event area frame
+ * @param hDC device context to use
+ * @param rc target rectangle (client coordinates)
+ * @param hTheme UxTheme handle to use for drawing text
+ */
+void PaintNotifyArea(HDC hDC, RECT *rc, HANDLE hTheme)
+{
+ int iCount;
+ static int ev_lastIcon = 0;
+
+ rc->left += 26; // button
+ iCount = GetMenuItemCount(cfg::dat.hMenuNotify);
+ if(cfg::dat.hUpdateContact != 0) {
+ wchar_t *szName = pcli->pfnGetContactDisplayName(cfg::dat.hUpdateContact, 0);
+ int iIcon = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) cfg::dat.hUpdateContact, 0);
+
+ ImageList_DrawEx(CLC::hClistImages, iIcon, hDC, rc->left, (rc->bottom + rc->top - CYSMICON) / 2, CXSMICON, CYSMICON, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ rc->left += 18;
+ Gfx::renderText(hDC, hTheme, szName, rc, DT_VCENTER | DT_SINGLELINE, 0);
+ ImageList_DrawEx(CLC::hClistImages, (int)cfg::dat.hIconNotify, hDC, 4, (rc->bottom + rc->top - 16) / 2, 16, 16, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ ev_lastIcon = cfg::dat.hIconNotify;
+ } else if(iCount > 0) {
+ MENUITEMINFO mii = {0};
+ struct NotifyMenuItemExData *nmi;
+ wchar_t *szName;
+ int iIcon;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+ GetMenuItemInfo(cfg::dat.hMenuNotify, iCount - 1, TRUE, &mii);
+ nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
+ szName = pcli->pfnGetContactDisplayName(nmi->hContact, 0);
+ iIcon = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) nmi->hContact, 0);
+ ImageList_DrawEx(CLC::hClistImages, iIcon, hDC, rc->left, (rc->bottom + rc->top - CYSMICON) / 2, CXSMICON, CYSMICON, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ rc->left += 18;
+ ImageList_DrawEx(CLC::hClistImages, nmi->iIcon, hDC, 4, (rc->bottom + rc->top) / 2 - 8, 16, 16, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ Gfx::renderText(hDC, hTheme, szName, rc, DT_VCENTER | DT_SINGLELINE, 0);
+ ev_lastIcon = (int)nmi->hIcon;
+ } else
+ Gfx::renderText(hDC, hTheme, cfg::dat.szNoEvents, rc, DT_VCENTER | DT_SINGLELINE, 0);
+}
+
+/**
+ * this handles the subclassing for the event area frame.
+ */
+LRESULT CALLBACK CLUI::eventAreaWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CREATE: {
+ hwndEventFrame = hwnd;
+ return FALSE;
+ }
+ case WM_MEASUREITEM: {
+ MEASUREITEMSTRUCT *lpi = (LPMEASUREITEMSTRUCT) lParam;
+ MENUITEMINFOA mii = {0};
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_ID;
+ if(GetMenuItemInfoA(cfg::dat.hMenuNotify, lpi->itemID, FALSE, &mii) != 0) {
+ if(mii.dwItemData == lpi->itemData) {
+ lpi->itemWidth = 8 + 16;
+ lpi->itemHeight = 0;
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case WM_NCCALCSIZE:
+ return FrameNCCalcSize(hwnd, DefWindowProc, wParam, lParam,
+ wndFrameEventArea ? wndFrameEventArea->TitleBar.ShowTitleBar : 0);
+ case WM_NCPAINT:
+ return FrameNCPaint(hwnd, DefWindowProc, wParam, lParam,
+ wndFrameEventArea ? wndFrameEventArea->TitleBar.ShowTitleBar : 0);
+ case WM_DRAWITEM: {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+
+ if(dis->hwndItem == (HWND) cfg::dat.hMenuNotify) {
+ MENUITEMINFOA mii = {0};
+
+ struct NotifyMenuItemExData *nmi = 0;
+ int iIcon;
+ HICON hIcon;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+ if(GetMenuItemInfoA(cfg::dat.hMenuNotify, (UINT) dis->itemID, FALSE, &mii) != 0) {
+ nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
+ if(nmi) {
+ iIcon = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) nmi->hContact, 0);
+ hIcon = ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL);
+ pcli->pfnDrawMenuItem(dis, hIcon, nmi->hIcon);
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ case WM_LBUTTONUP:
+ if(cfg::dat.bEventAreaEnabled)
+ SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_NOTIFYBUTTON, 0), 0);
+ break;
+ case WM_COMMAND:
+ if(LOWORD(wParam) == IDC_NOTIFYBUTTON) {
+ int iSelection;
+ MENUITEMINFO mii = {0};
+ POINT pt;
+ struct NotifyMenuItemExData *nmi = 0;
+ int iCount = GetMenuItemCount(cfg::dat.hMenuNotify);
+ BOOL result;
+
+ GetCursorPos(&pt);
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+ if(iCount > 1)
+ iSelection = TrackPopupMenu(cfg::dat.hMenuNotify, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
+ else
+ iSelection = GetMenuItemID(cfg::dat.hMenuNotify, 0);
+ result = GetMenuItemInfo(cfg::dat.hMenuNotify, (UINT) iSelection, FALSE, &mii);
+ if(result != 0) {
+ nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
+ if(nmi) {
+ CLISTEVENT *cle = MyGetEvent(iSelection);
+ if(cle) {
+ CLISTEVENT *cle1 = NULL;
+ CallService(cle->pszService, (WPARAM) NULL, (LPARAM) cle);
+ // re-obtain the pointer, it may already be invalid/point to another event if the
+ // event we're interested in was removed by the service (nasty one...)
+ cle1 = MyGetEvent(iSelection);
+ if(cle1 != NULL)
+ CallService(MS_CLIST_REMOVEEVENT, (WPARAM) cle->hContact, (LPARAM) cle->hDbEvent);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_ERASEBKGND:
+ return TRUE;
+
+ case WM_LBUTTONDOWN: {
+ POINT ptMouse, pt;
+ RECT rcClient;
+
+ if((GetKeyState(VK_CONTROL) & 0x8000) && wndFrameEventArea->floating) {
+ GetCursorPos(&ptMouse);
+ pt = ptMouse;
+ ScreenToClient(hwnd, &ptMouse);
+ GetClientRect(hwnd, &rcClient);
+ return SendMessage(GetParent(hwnd), WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ }
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ RECT rc, rcClient;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ LONG dwLeft;
+ HDC hdcMem;
+ HANDLE hbp = 0;
+ TStatusItem* item;
+ HFONT hFontOld = 0;
+ HANDLE hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON");
+
+ GetClientRect(hwnd, &rc);
+ rcClient = rc;
+ if(wndFrameEventArea->floating) {
+ hdcMem = hdc;
+ FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE));
+ } else
+ INIT_PAINT(hdc, rcClient, hdcMem);
+
+ SetBkMode(hdcMem, TRANSPARENT);
+
+ if(cfg::clcdat)
+ hFontOld = reinterpret_cast<HFONT>(SelectObject(hdcMem, cfg::clcdat->fontInfo[FONTID_EVENTAREA].hFont));
+
+ Gfx::drawBGFromSurface(hwnd, rc, hdcMem);
+ item = &Skin::statusItems[ID_EXTBKEVTAREA];
+ if(!item->IGNORED) {
+ rc.top += item->MARGIN_TOP;
+ rc.bottom -= item->MARGIN_BOTTOM;
+ rc.left += item->MARGIN_LEFT;
+ rc.right -= item->MARGIN_RIGHT;
+
+ Gfx::renderSkinItem(hdcMem, &rc, item->imageItem);
+ Gfx::setTextColor(item->TEXTCOLOR);
+ }
+
+ dwLeft = rc.left;
+
+ PaintNotifyArea(hdcMem, &rc, hTheme);
+ if(hFontOld)
+ SelectObject(hdcMem, hFontOld);
+
+ if(hbp)
+ FINALIZE_PAINT(hbp, &rcClient, 0);
+
+ ps.fErase = FALSE;
+ EndPaint(hwnd, &ps);
+ if(hTheme)
+ Api::pfnCloseThemeData(hTheme);
+ return 0;
+ }
+ default:
+ break;
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+CListEvent* CLC::AddEvent(CLISTEVENT *cle)
+{
+ CListEvent* p = coreCli.pfnAddEvent(cle);
+ if(p == NULL)
+ return NULL;
+
+ if(p->cle.hContact != 0 && p->cle.hDbEvent != (MEVENT) 1 && !(p->cle.flags & CLEF_ONLYAFEW)) {
+ int j;
+ struct NotifyMenuItemExData *nmi = 0;
+ char *szProto;
+ wchar_t *szName;
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA | MIIM_BITMAP | MIIM_ID;
+ if(p->cle.pszService && !strncmp("SRMsg/ReadMessage", p->cle.pszService, 17)) {
+ // dup check only for msg events
+ for(j = 0; j < GetMenuItemCount(cfg::dat.hMenuNotify); j++) {
+ if(GetMenuItemInfo(cfg::dat.hMenuNotify, j, TRUE, &mii) != 0) {
+ nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
+ if(nmi != 0 && (HANDLE) nmi->hContact == (HANDLE) p->cle.hContact && nmi->iIcon == p->imlIconIndex)
+ return p;
+ }
+ }
+ }
+
+ szProto = GetContactProto(p->cle.hContact);
+ szName = pcli->pfnGetContactDisplayName(p->cle.hContact, 0);
+ if(szProto && szName) {
+ nmi = (struct NotifyMenuItemExData *) malloc(sizeof(struct NotifyMenuItemExData));
+ if(nmi) {
+ wchar_t szBuffer[128];
+ wchar_t* szStatus = pcli->pfnGetStatusModeDescription(cfg::getWord(p->cle.hContact, szProto, "Status", ID_STATUS_OFFLINE), 0);
+ wchar_t szwProto[64];
+ MultiByteToWideChar(CP_ACP, 0, szProto, -1, szwProto, 64);
+ szwProto[63] = 0;
+ _snwprintf(szBuffer, _countof(szBuffer), L"%s: %s (%s)", szwProto, szName, szStatus);
+ szBuffer[127] = 0;
+ AppendMenu(cfg::dat.hMenuNotify, MF_BYCOMMAND | MF_STRING, cfg::dat.wNextMenuID, szBuffer);
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ nmi->hContact = p->cle.hContact;
+ nmi->iIcon = p->imlIconIndex;
+ nmi->hIcon = p->cle.hIcon;
+ nmi->hDbEvent = p->cle.hDbEvent;
+ mii.dwItemData = (ULONG_PTR) nmi;
+ mii.wID = cfg::dat.wNextMenuID;
+ SetMenuItemInfo(cfg::dat.hMenuNotify, cfg::dat.wNextMenuID, FALSE, &mii);
+ p-> menuId = cfg::dat.wNextMenuID;
+ cfg::dat.wNextMenuID++;
+ if(cfg::dat.wNextMenuID > 0x7fff)
+ cfg::dat.wNextMenuID = 1;
+ cfg::dat.hIconNotify = p->imlIconIndex;
+ }
+ }
+ } else if(p->cle.hContact != 0 && (p->cle.flags & CLEF_ONLYAFEW)) {
+ cfg::dat.hIconNotify = p->imlIconIndex;
+ cfg::dat.hUpdateContact = p->cle.hContact;
+ }
+ if(cfg::dat.dwFlags & CLUI_STICKYEVENTS) {
+ HANDLE hItem = (HANDLE) SendMessage(pcli->hwndContactTree, CLM_FINDCONTACT, (WPARAM) p->cle.hContact, 0);
+ if(hItem) {
+ SendMessage(pcli->hwndContactTree, CLM_SETSTICKY, (WPARAM) hItem, 1);
+ pcli->pfnClcBroadcast(INTM_PROTOCHANGED, (WPARAM) p->cle.hContact, 0);
+ }
+ }
+ if(pcli->events.count > 0) {
+ cfg::dat.bEventAreaEnabled = TRUE;
+ if(cfg::dat.notifyActive == 0) {
+ cfg::dat.notifyActive = 1;
+ CLUI::hideShowNotifyFrame();
+ }
+ }
+ InvalidateRect(hwndEventFrame, NULL, FALSE);
+ if(cfg::dat.bUseFloater & CLUI_USE_FLOATER && cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS)
+ SFL_Update(0, 0, 0, NULL, FALSE);
+
+ return p;
+}
+
+// Removes an event from the contact list's queue
+// wParam=(WPARAM)(HANDLE)hContact
+// lParam=(LPARAM)(HANDLE)hDbEvent
+// Returns 0 if the event was successfully removed, or nonzero if the event was not found
+int CLC::RemoveEvent(MCONTACT hContact, MEVENT hDbEvent)
+{
+ HANDLE hItem;
+ int i;
+ BOOL bUnstick = TRUE;
+
+ // Find the event that should be removed
+ for(i = 0; i < pcli->events.count; i++) {
+ if((pcli->events.items[i]->cle.hContact == hContact) && (pcli->events.items[i]->cle.hDbEvent == hDbEvent)) {
+ break;
+ }
+ }
+
+ // Event was not found
+ if(i == pcli->events.count)
+ return 1;
+
+ // remove event from the notify menu
+ if(pcli->events.items[i]->menuId > 0) {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_DATA;
+ if(GetMenuItemInfo(cfg::dat.hMenuNotify, pcli->events.items[i]->menuId, FALSE, &mii) != 0) {
+ struct NotifyMenuItemExData *nmi = (struct NotifyMenuItemExData *) mii.dwItemData;
+ if(nmi && nmi->hContact == hContact && nmi->hDbEvent == hDbEvent) {
+ free(nmi);
+ DeleteMenu(cfg::dat.hMenuNotify, pcli->events.items[i]->menuId, MF_BYCOMMAND);
+ }
+ }
+ }
+
+ coreCli.pfnRemoveEvent(hContact, hDbEvent);
+
+ if(pcli->events.count == 0) {
+ cfg::dat.bEventAreaEnabled = FALSE;
+ if(cfg::dat.dwFlags & CLUI_FRAME_AUTOHIDENOTIFY) {
+ cfg::dat.notifyActive = 0;
+ CLUI::hideShowNotifyFrame();
+ }
+ }
+
+ if(bUnstick) {
+ // clear "sticky" (sort) status
+
+ hItem = (HANDLE) SendMessage(pcli->hwndContactTree, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if(hItem) {
+ SendMessage(pcli->hwndContactTree, CLM_SETSTICKY, (WPARAM) hItem, 0);
+ pcli->pfnClcBroadcast(INTM_PROTOCHANGED, (WPARAM)hContact, 0);
+ }
+ }
+
+ if(hContact == cfg::dat.hUpdateContact || (INT_PTR)hDbEvent == 1)
+ cfg::dat.hUpdateContact = 0;
+
+ if(cfg::dat.notifyActive) {
+ InvalidateRect(hwndEventFrame, NULL, FALSE);
+ if(cfg::dat.bUseFloater & CLUI_USE_FLOATER && cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS)
+ SFL_Update(0, 0, 0, NULL, FALSE);
+ }
+
+ return 0;
+}
diff --git a/plugins/Clist_ng/SRC/clistmenus.cpp b/plugins/Clist_ng/SRC/clistmenus.cpp new file mode 100644 index 0000000000..6b3f0ea92e --- /dev/null +++ b/plugins/Clist_ng/SRC/clistmenus.cpp @@ -0,0 +1,469 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <commonheaders.h>
+
+#pragma hdrstop
+
+static HMENU hMainMenu, hMainStatusMenu;
+static MWindowList hWindowListIGN = 0;
+
+void DestroyTrayMenu(HMENU hMenu)
+{
+ int i, cnt;
+
+ cnt = GetMenuItemCount(hMenu);
+ for (i=0; i<cnt; ++i)
+ {
+ HMENU hSubMenu = GetSubMenu(hMenu, i);
+ if (hSubMenu == hMainStatusMenu || hSubMenu == hMainMenu)
+ RemoveMenu(hMenu, i--, MF_BYPOSITION);
+ }
+ DestroyMenu(hMenu);
+}
+
+INT_PTR CloseAction(WPARAM wParam,LPARAM lParam)
+{
+ int k;
+ cfg::shutDown = 1;
+ k=CallService(MS_SYSTEM_OKTOEXIT,(WPARAM)0,(LPARAM)0);
+ if (k) {
+ DestroyWindow(pcli->hwndContactList);
+ PostQuitMessage(0);
+ Sleep(0);
+ }
+
+ return(0);
+}
+
+static const UINT xImgCtrlIds[] = {
+ IDC_EXTRA_ICON_RES0,
+ IDC_EXTRA_ICON_EMAIL,
+ IDC_EXTRA_ICON_RES1,
+ IDC_EXTRA_ICON_SMS,
+ IDC_EXTRA_ICON_ADV1,
+ IDC_EXTRA_ICON_ADV2,
+ IDC_EXTRA_ICON_WEB,
+ IDC_EXTRA_ICON_CLIENT,
+ IDC_EXTRA_ICON_RES2,
+ IDC_EXTRA_ICON_ADV3,
+ IDC_EXTRA_ICON_ADV4
+};
+
+static const UINT xImgCtrlBits[] = {
+ EXTRA_ICON_RES0,
+ EXTRA_ICON_EMAIL,
+ EXTRA_ICON_RES1,
+ EXTRA_ICON_SMS,
+ EXTRA_ICON_ADV1,
+ EXTRA_ICON_ADV2,
+ EXTRA_ICON_WEB,
+ EXTRA_ICON_CLIENT,
+ EXTRA_ICON_RES2,
+ EXTRA_ICON_ADV3,
+ EXTRA_ICON_ADV4
+};
+
+
+static INT_PTR CALLBACK IgnoreDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ DWORD dwMask;
+ struct ClcContact *contact = NULL;
+ int pCaps;
+ HWND hwndAdd;
+
+ hContact = lParam;
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)hContact);
+ dwMask = cfg::getDword(hContact, "Ignore", "Mask1", 0);
+ SendMessage(hWnd, WM_USER + 100, (WPARAM)hContact, dwMask);
+ SendMessage(hWnd, WM_USER + 120, 0, 0);
+ TranslateDialogDefault(hWnd);
+ hwndAdd = GetDlgItem(hWnd, IDC_IGN_ADDPERMANENTLY); // CreateWindowEx(0, _T("CLCButtonClass"), _T("FOO"), WS_VISIBLE | BS_PUSHBUTTON | WS_CHILD | WS_TABSTOP, 200, 276, 106, 24, hWnd, (HMENU)IDC_IGN_ADDPERMANENTLY, g_hInst, NULL);
+ SendMessage(hwndAdd, BUTTONSETASFLATBTN, 0, 1);
+ SendMessage(hwndAdd, BUTTONSETASFLATBTN + 10, 0, 1);
+
+ SendMessage(hwndAdd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)Skin_LoadIcon(SKINICON_OTHER_ADDCONTACT));
+ SetWindowText(hwndAdd, TranslateT("Add permanently"));
+ EnableWindow(hwndAdd, cfg::getByte(hContact, "CList", "NotOnList", 0));
+
+ hwndAdd = GetDlgItem(hWnd, IDC_DSP_LOADDEFAULT); // CreateWindowEx(0, _T("CLCButtonClass"), _T("FOO"), WS_VISIBLE | BS_PUSHBUTTON | WS_CHILD | WS_TABSTOP, 200, 276, 106, 24, hWnd, (HMENU)IDC_IGN_ADDPERMANENTLY, g_hInst, NULL);
+ SendMessage(hwndAdd, BUTTONSETASFLATBTN, 0, 1);
+ SendMessage(hwndAdd, BUTTONSETASFLATBTN + 10, 0, 1);
+
+ SendMessage(hwndAdd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)Skin_LoadIcon(SKINICON_OTHER_DELETE));
+ SetWindowText(hwndAdd, TranslateT("Revert to default"));
+ EnableWindow(hwndAdd, TRUE);
+
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Default (global setting)"));
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Show always when available"));
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Hide always"));
+
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Default (global setting)"));
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Never"));
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Always"));
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("When space is available"));
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_INSERTSTRING, -1, (LPARAM)TranslateT("When needed by status message"));
+
+ if(cfg::clcdat) {
+ CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)hContact, &contact, NULL, NULL);
+ if(contact && contact->type != CLCIT_CONTACT) {
+ DestroyWindow(hWnd);
+ return FALSE;
+ } else {
+ wchar_t szTitle[512];
+ DWORD dwFlags = cfg::getDword(hContact, "CList", "CLN_Flags", 0);
+ BYTE bSecondLine = cfg::getByte(hContact, "CList", "CLN_2ndline", -1);
+ DWORD dwXMask = cfg::getDword(hContact, "CList", "CLN_xmask", 0);
+ int i = 0;
+
+ mir_sntprintf(szTitle, 512, TranslateT("Contact list display and ignore options for %s"), contact ? contact->szText : pcli->pfnGetContactDisplayName(hContact, 0));
+
+ SetWindowText(hWnd, szTitle);
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)Skin_LoadIcon(SKINICON_OTHER_MIRANDA));
+ pCaps = CallProtoService(contact ? contact->proto : GetContactProto(hContact), PS_GETCAPS, PFLAGNUM_1, 0);
+ Utils::enableDlgControl(hWnd, IDC_IGN_ALWAYSONLINE, pCaps & PF1_INVISLIST ? TRUE : FALSE);
+ Utils::enableDlgControl(hWnd, IDC_IGN_ALWAYSOFFLINE, pCaps & PF1_VISLIST ? TRUE : FALSE);
+ CheckDlgButton(hWnd, IDC_IGN_PRIORITY, cfg::getByte(hContact, "CList", "Priority", 0) ? 1 : 0);
+ Utils::enableDlgControl(hWnd, IDC_IGN_PRIORITY, TRUE);
+ Utils::enableDlgControl(hWnd, IDC_AVATARDISPMODE, TRUE);
+ Utils::enableDlgControl(hWnd, IDC_SECONDLINEMODE, TRUE);
+ if(dwFlags & ECF_FORCEAVATAR)
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_SETCURSEL, 1, 0);
+ else if(dwFlags & ECF_HIDEAVATAR)
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_SETCURSEL, 2, 0);
+ else
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_SETCURSEL, 0, 0);
+
+ if(dwFlags & ECF_FORCEOVERLAY)
+ SendDlgItemMessage(hWnd, IDC_OVERLAYICON, BM_SETCHECK, BST_CHECKED, 0);
+ else if(dwFlags & ECF_HIDEOVERLAY)
+ SendDlgItemMessage(hWnd, IDC_OVERLAYICON, BM_SETCHECK, BST_UNCHECKED, 0);
+ else
+ SendDlgItemMessage(hWnd, IDC_OVERLAYICON, BM_SETCHECK, BST_INDETERMINATE, 0);
+
+ if(dwFlags & ECF_FORCELOCALTIME)
+ SendDlgItemMessage(hWnd, IDC_SHOWLOCALTIME1, BM_SETCHECK, BST_CHECKED, 0);
+ else if(dwFlags & ECF_HIDELOCALTIME)
+ SendDlgItemMessage(hWnd, IDC_SHOWLOCALTIME1, BM_SETCHECK, BST_UNCHECKED, 0);
+ else
+ SendDlgItemMessage(hWnd, IDC_SHOWLOCALTIME1, BM_SETCHECK, BST_INDETERMINATE, 0);
+
+ if(dwFlags & ECF_FORCEVISIBILITY)
+ SendDlgItemMessage(hWnd, IDC_SHOWVISIBILITY, BM_SETCHECK, BST_CHECKED, 0);
+ else if(dwFlags & ECF_HIDEVISIBILITY)
+ SendDlgItemMessage(hWnd, IDC_SHOWVISIBILITY, BM_SETCHECK, BST_UNCHECKED, 0);
+ else
+ SendDlgItemMessage(hWnd, IDC_SHOWVISIBILITY, BM_SETCHECK, BST_INDETERMINATE, 0);
+
+ while(xImgCtrlIds[i] != 0) {
+ if(dwXMask & (1 << (2 * xImgCtrlBits[i])))
+ SendDlgItemMessage(hWnd, xImgCtrlIds[i], BM_SETCHECK, BST_CHECKED, 0);
+ else if(dwXMask & (1 << (2 * xImgCtrlBits[i] + 1)))
+ SendDlgItemMessage(hWnd, xImgCtrlIds[i], BM_SETCHECK, BST_UNCHECKED, 0);
+ else
+ SendDlgItemMessage(hWnd, xImgCtrlIds[i], BM_SETCHECK, BST_INDETERMINATE, 0);
+ i++;
+ }
+
+ if(bSecondLine == 0xff)
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_SETCURSEL, 0, 0);
+ else
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_SETCURSEL, (WPARAM)(bSecondLine + 1), 0);
+ }
+ }
+ WindowList_Add(hWindowListIGN, hWnd, hContact);
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_IGN_PRIORITY:
+ SendMessage(pcli->hwndContactTree, CLM_TOGGLEPRIORITYCONTACT, (WPARAM)hContact, 0);
+ return 0;
+ case IDC_IGN_ALL:
+ SendMessage(hWnd, WM_USER + 100, (WPARAM)hContact, (LPARAM)0xffffffff);
+ return 0;
+ case IDC_IGN_NONE:
+ SendMessage(hWnd, WM_USER + 100, (WPARAM)hContact, (LPARAM)0);
+ return 0;
+ case IDC_IGN_ALWAYSONLINE:
+ if(IsDlgButtonChecked(hWnd, IDC_IGN_ALWAYSONLINE))
+ CheckDlgButton(hWnd, IDC_IGN_ALWAYSOFFLINE, FALSE);
+ break;
+ case IDC_IGN_ALWAYSOFFLINE:
+ if(IsDlgButtonChecked(hWnd, IDC_IGN_ALWAYSOFFLINE))
+ CheckDlgButton(hWnd, IDC_IGN_ALWAYSONLINE, FALSE);
+ break;
+ case IDC_HIDECONTACT:
+ cfg::writeByte(hContact, "CList", "Hidden", (BYTE)(IsDlgButtonChecked(hWnd, IDC_HIDECONTACT) ? 1 : 0));
+ break;
+ case IDC_IGN_ADDPERMANENTLY:
+ {
+ ADDCONTACTSTRUCT acs = {0};
+
+ acs.hContact = hContact;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = 0;
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM)hWnd, (LPARAM)&acs);
+ Utils::enableDlgControl(hWnd, IDC_IGN_ADDPERMANENTLY, cfg::getByte(hContact, "CList", "NotOnList", 0));
+ break;
+ }
+ case IDC_DSP_LOADDEFAULT:
+ {
+ int i = 0;
+
+ SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_SETCURSEL, 0, 0);
+ while(xImgCtrlIds[i] != 0)
+ SendDlgItemMessage(hWnd, xImgCtrlIds[i++], BM_SETCHECK, BST_INDETERMINATE, 0);
+
+ SendDlgItemMessage(hWnd, IDC_OVERLAYICON, BM_SETCHECK, BST_INDETERMINATE, 0);
+ SendDlgItemMessage(hWnd, IDC_LOCALTIME, BM_SETCHECK, BST_INDETERMINATE, 0);
+ SendDlgItemMessage(hWnd, IDC_SHOWVISIBILITY, BM_SETCHECK, BST_INDETERMINATE, 0);
+ break;
+ }
+ case IDOK:
+ {
+ DWORD newMask = 0;
+ struct ClcContact *contact = NULL;
+
+ SendMessage(hWnd, WM_USER + 110, 0, (LPARAM)&newMask);
+ cfg::writeDword(hContact, "Ignore", "Mask1", newMask);
+ SendMessage(hWnd, WM_USER + 130, 0, 0);
+
+ if(cfg::clcdat) {
+ LRESULT iSel = SendDlgItemMessage(hWnd, IDC_AVATARDISPMODE, CB_GETCURSEL, 0, 0);
+ DWORD dwFlags = cfg::getDword(hContact, "CList", "CLN_Flags", 0), dwXMask = 0;
+ LRESULT checked = 0;
+ int i = 0;
+
+ CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)hContact, &contact, NULL, NULL);
+ if(iSel != CB_ERR) {
+ dwFlags &= ~(ECF_FORCEAVATAR | ECF_HIDEAVATAR);
+
+ if(iSel == 1)
+ dwFlags |= ECF_FORCEAVATAR;
+ else if(iSel == 2)
+ dwFlags |= ECF_HIDEAVATAR;
+ if(contact)
+ LoadAvatarForContact(contact);
+ }
+
+ dwFlags &= ~(ECF_FORCEOVERLAY | ECF_HIDEOVERLAY | ECF_FORCELOCALTIME | ECF_HIDELOCALTIME |
+ ECF_FORCEVISIBILITY | ECF_HIDEVISIBILITY);
+
+ checked = SendDlgItemMessage(hWnd, IDC_OVERLAYICON, BM_GETCHECK, 0, 0);
+ if(checked == BST_CHECKED)
+ dwFlags |= ECF_FORCEOVERLAY;
+ else if(checked == BST_UNCHECKED)
+ dwFlags |= ECF_HIDEOVERLAY;
+
+ checked = SendDlgItemMessage(hWnd, IDC_SHOWLOCALTIME1, BM_GETCHECK, 0, 0);
+ if(checked == BST_CHECKED)
+ dwFlags |= ECF_FORCELOCALTIME;
+ else if(checked == BST_UNCHECKED)
+ dwFlags |= ECF_HIDELOCALTIME;
+
+ checked = SendDlgItemMessage(hWnd, IDC_SHOWVISIBILITY, BM_GETCHECK, 0, 0);
+ if(checked == BST_CHECKED)
+ dwFlags |= ECF_FORCEVISIBILITY;
+ else if(checked == BST_UNCHECKED)
+ dwFlags |= ECF_HIDEVISIBILITY;
+
+ cfg::writeDword(hContact, "CList", "CLN_Flags", dwFlags);
+
+ if((iSel = SendDlgItemMessage(hWnd, IDC_SECONDLINEMODE, CB_GETCURSEL, 0, 0)) != CB_ERR) {
+ if(iSel == 0) {
+ db_unset(hContact, "CList", "CLN_2ndline");
+ if(contact)
+ contact->bSecondLineLocal = -1;
+ }
+ else {
+ cfg::writeByte(hContact, "CList", "CLN_2ndline", (BYTE)(iSel - 1));
+ if(contact)
+ contact->bSecondLineLocal = (BYTE)(iSel - 1);
+ }
+ }
+ while(xImgCtrlIds[i] != 0) {
+ checked = SendDlgItemMessage(hWnd, xImgCtrlIds[i], BM_GETCHECK, 0, 0);
+ if(checked == BST_CHECKED)
+ dwXMask |= (1 << (2 * xImgCtrlBits[i]));
+ else if(checked == BST_UNCHECKED)
+ dwXMask |= (1 << (2 * xImgCtrlBits[i] + 1));
+ i++;
+ }
+ cfg::writeDword(hContact, "CList", "CLN_xmask", dwXMask);
+ if(contact) {
+ if(contact->extraCacheEntry >= 0 && contact->extraCacheEntry <= cfg::nextCacheEntry) {
+ contact->dwDFlags = dwFlags;
+ cfg::eCache[contact->extraCacheEntry].dwXMask = CalcXMask(hContact);
+ }
+ }
+ else {
+ int iIndex = cfg::getCache(hContact, NULL);
+ if(iIndex >= 0 && iIndex <= cfg::nextCacheEntry)
+ cfg::eCache[iIndex].dwXMask = CalcXMask(hContact);
+ }
+ cfg::writeByte(hContact, "CList", "Priority", (BYTE)(IsDlgButtonChecked(hWnd, IDC_IGN_PRIORITY) ? 1 : 0));
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ }
+ }
+ case IDCANCEL:
+ DestroyWindow(hWnd);
+ break;
+ }
+ break;
+ case WM_USER + 100: // fill dialog (wParam = hContact, lParam = mask)
+ {
+ CheckDlgButton(hWnd, IDC_IGN_MSGEVENTS, lParam & (1 << (IGNOREEVENT_MESSAGE - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_IGN_FILEEVENTS, lParam & (1 << (IGNOREEVENT_FILE - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_IGN_URLEVENTS, lParam & (1 << (IGNOREEVENT_URL - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_IGN_AUTH, lParam & (1 << (IGNOREEVENT_AUTHORIZATION - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_IGN_ADD, lParam & (1 << (IGNOREEVENT_YOUWEREADDED - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hWnd, IDC_IGN_ONLINE, lParam & (1 << (IGNOREEVENT_USERONLINE - 1)) ? BST_CHECKED : BST_UNCHECKED);
+ return 0;
+ }
+ case WM_USER + 110: // retrieve value
+ {
+ DWORD *dwNewMask = (DWORD *)lParam, dwMask = 0;
+
+ dwMask = (IsDlgButtonChecked(hWnd, IDC_IGN_MSGEVENTS) ? (1 << (IGNOREEVENT_MESSAGE - 1)) : 0) |
+ (IsDlgButtonChecked(hWnd, IDC_IGN_FILEEVENTS) ? (1 << (IGNOREEVENT_FILE - 1)) : 0) |
+ (IsDlgButtonChecked(hWnd, IDC_IGN_URLEVENTS) ? (1 << (IGNOREEVENT_URL - 1)) : 0) |
+ (IsDlgButtonChecked(hWnd, IDC_IGN_AUTH) ? (1 << (IGNOREEVENT_AUTHORIZATION - 1)) : 0) |
+ (IsDlgButtonChecked(hWnd, IDC_IGN_ADD) ? (1 << (IGNOREEVENT_YOUWEREADDED - 1)) : 0) |
+ (IsDlgButtonChecked(hWnd, IDC_IGN_ONLINE) ? (1 << (IGNOREEVENT_USERONLINE - 1)) : 0);
+
+ if(dwNewMask)
+ *dwNewMask = dwMask;
+ return 0;
+ }
+ case WM_USER + 120: // set visibility status
+ {
+ struct ClcContact *contact = NULL;
+
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)hContact, &contact, NULL, NULL)) {
+ if(contact) {
+ WORD wApparentMode = cfg::getWord(contact->hContact, contact->proto, "ApparentMode", 0);
+
+ CheckDlgButton(hWnd, IDC_IGN_ALWAYSOFFLINE, wApparentMode == ID_STATUS_OFFLINE ? TRUE : FALSE);
+ CheckDlgButton(hWnd, IDC_IGN_ALWAYSONLINE, wApparentMode == ID_STATUS_ONLINE ? TRUE : FALSE);
+ }
+ }
+ return 0;
+ }
+ case WM_USER + 130: // update apparent mode
+ {
+ struct ClcContact *contact = NULL;
+
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)hContact, &contact, NULL, NULL)) {
+ if(contact) {
+ WORD wApparentMode = 0;
+
+ if(IsDlgButtonChecked(hWnd, IDC_IGN_ALWAYSONLINE))
+ wApparentMode = ID_STATUS_ONLINE;
+ else if(IsDlgButtonChecked(hWnd, IDC_IGN_ALWAYSOFFLINE))
+ wApparentMode = ID_STATUS_OFFLINE;
+
+ CallContactService(hContact, PSS_SETAPPARENTMODE, (WPARAM)wApparentMode, 0);
+ SendMessage(hWnd, WM_USER + 120, 0, 0);
+ }
+ }
+ return 0;
+ }
+ case WM_DESTROY:
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
+ WindowList_Remove(hWindowListIGN, hWnd);
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * service function: Open ignore settings dialog for the contact handle in wParam
+ * (clist_nicer+ specific service)
+ *
+ * Servicename = CList/SetContactIgnore
+ *
+ * ensure that dialog is only opened once (the dialog proc saves the window handle of an open dialog
+ * of this type to the contacts database record).
+ *
+ * if dialog is already open, focus it.
+*/
+
+static INT_PTR SetContactIgnore(WPARAM wParam, LPARAM)
+{
+ HWND hWnd = 0;
+
+ if (hWindowListIGN == 0)
+ hWindowListIGN = WindowList_Create();
+
+ hWnd = WindowList_Find(hWindowListIGN, wParam);
+ if (wParam) {
+ if (hWnd == 0)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_QUICKIGNORE), 0, IgnoreDialogProc, (LPARAM)wParam);
+ else if (IsWindow(hWnd))
+ SetFocus(hWnd);
+ }
+ return 0;
+}
+
+/*
+ * service function: Set a contacts floating status.
+ * (clist_nicer+ specific service)
+ *
+ * Servicename = CList/SetContactFloating
+ *
+ * a floating contact appears as a small independent top level window anywhere on
+ * the desktop.
+*/
+
+static INT_PTR SetContactFloating(WPARAM wParam, LPARAM lParam)
+{
+ SendMessage(pcli->hwndContactTree, CLM_TOGGLEFLOATINGCONTACT, wParam, lParam);
+ return 0;
+}
+
+int InitCustomMenus(void)
+{
+ CreateServiceFunction("CloseAction", CloseAction);
+ CreateServiceFunction("CList/SetContactIgnore", SetContactIgnore);
+
+ CMenuItem mi;
+ mi.position = 200000;
+ mi.pszService = "CList/SetContactIgnore";
+ mi.hIcolibItem = iconItem[0].hIcolib;
+ mi.name.a = LPGEN("&Contact list settings...");
+ Menu_AddContactMenuItem(&mi);
+ return 0;
+}
+
+void UninitCustomMenus(void)
+{
+ WindowList_Destroy(hWindowListIGN);
+}
diff --git a/plugins/Clist_ng/SRC/clistmod.cpp b/plugins/Clist_ng/SRC/clistmod.cpp new file mode 100644 index 0000000000..a36eae8c00 --- /dev/null +++ b/plugins/Clist_ng/SRC/clistmod.cpp @@ -0,0 +1,225 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2015 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ */
+
+#include <commonheaders.h>
+
+void TrayIconUpdateBase(const char *szChangedProto);
+int EventsProcessContactDoubleClick(HANDLE hContact);
+
+extern HANDLE hSvc_GetContactStatusMsg;
+
+static INT_PTR GetContactStatusMessage(WPARAM wParam, LPARAM lParam)
+{
+ if (!cfg::shutDown)
+ return SendMessage(pcli->hwndContactTree, CLM_GETSTATUSMSG, wParam, lParam);
+ return 0;
+}
+
+static INT_PTR GetStatusMode(WPARAM wParam, LPARAM lParam)
+{
+ return(cfg::maxStatus == ID_STATUS_OFFLINE ? pcli->currentDesiredStatusMode : cfg::maxStatus);
+}
+
+int CLC::IconFromStatusMode(const char *szProto, int status, MCONTACT hContact, HICON *phIcon)
+{
+ char *szFinalProto;
+ int finalStatus;
+
+ if (szProto != NULL && !strcmp(szProto, cfg::dat.szMetaName) && cfg::dat.bMetaAvail && hContact != 0) {
+ MCONTACT hSubContact = db_mc_getMostOnline(hContact);
+ szFinalProto = GetContactProto(hSubContact);
+ finalStatus = (status == 0) ? (WORD) cfg::getWord(hSubContact, szFinalProto, "Status", ID_STATUS_OFFLINE) : status;
+ } else {
+ szFinalProto = (char*) szProto;
+ finalStatus = status;
+ }
+
+ if(status >= ID_STATUS_CONNECTING && status < ID_STATUS_OFFLINE && phIcon != NULL) {
+ if(szProto) {
+ char szBuf[128];
+ mir_snprintf(szBuf, 128, "%s_conn", szProto);
+ *phIcon = IcoLib_GetIcon(szBuf);
+ }
+ }
+ return coreCli.pfnIconFromStatusMode(szFinalProto, finalStatus, hContact);
+}
+
+static int MenuItem_LockAvatar(WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+static int ContactListShutdownProc(WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+int LoadContactListModule(void)
+{
+ HookEvent(ME_SYSTEM_SHUTDOWN, ContactListShutdownProc);
+ CreateServiceFunction(MS_CLIST_GETSTATUSMODE, GetStatusMode);
+
+ hSvc_GetContactStatusMsg = CreateServiceFunction("CList/GetContactStatusMsg", GetContactStatusMessage);
+ InitCustomMenus();
+ return 0;
+}
+
+#define GWVS_HIDDEN 1
+#define GWVS_VISIBLE 2
+#define GWVS_COVERED 3
+#define GWVS_PARTIALLY_COVERED 4
+
+int GetWindowVisibleState(HWND hWnd, int iStepX, int iStepY)
+{
+ RECT rc = { 0 };
+ POINT pt = {0};
+ register int i = 0, j = 0, width = 0, height = 0, iCountedDots = 0, iNotCoveredDots = 0;
+ BOOL bPartiallyCovered = FALSE;
+ HWND hAux = 0;
+
+ if (hWnd == NULL) {
+ SetLastError(0x00000006); //Wrong handle
+ return -1;
+ }
+ //Some defaults now. The routine is designed for thin and tall windows.
+
+ if (IsIconic(hWnd) || !IsWindowVisible(hWnd))
+ return GWVS_HIDDEN;
+ else {
+ HRGN rgn = 0;
+ POINT ptOrig;
+ RECT rcClient;
+
+ GetClientRect(hWnd, &rcClient);
+ ptOrig.x = ptOrig.y = 0;
+ ClientToScreen(hWnd, &ptOrig);
+ rc.left = ptOrig.x;
+ rc.top = ptOrig.y;
+ rc.right = rc.left + rcClient.right;
+ rc.bottom = rc.top + rcClient.bottom;
+
+ width = rc.right - rc.left;
+ height = rc.bottom - rc.top;
+
+ if (iStepX <= 0)
+ iStepX = 4;
+ if (iStepY <= 0)
+ iStepY = 16;
+
+ /*
+ * use a rounded clip region to determine which pixels are covered
+ * this will avoid problems with certain XP themes which are using transparency for rounded
+ * window frames (reluna being one popular example).
+
+ * the radius of 8 should be sufficient for most themes as they usually don't use bigger
+ * radii.
+ * also, clip at least 2 pixels from the border (same reason)
+ */
+
+ int clip = max(3, db_get_b(0, "CLUI", "ignoreframepixels", 2));
+ for (i = rc.top + clip; i < rc.bottom - clip; i += (height / iStepY)) {
+ pt.y = i;
+ for (j = rc.left + clip; j < rc.right - clip; j += (width / iStepX)) {
+ pt.x = j;
+ hAux = WindowFromPoint(pt);
+ while (GetParent(hAux) != NULL)
+ hAux = GetParent(hAux);
+ if (hAux != hWnd && hAux) //There's another window!
+ bPartiallyCovered = TRUE;
+ else
+ iNotCoveredDots++; //Let's count the not covered dots.
+ iCountedDots++; //Let's keep track of how many dots we checked.
+ }
+ }
+ if(rgn)
+ DeleteObject(rgn);
+
+ if (iNotCoveredDots == iCountedDots) //Every dot was not covered: the window is visible.
+ return GWVS_VISIBLE;
+ else if (iNotCoveredDots == 0) //They're all covered!
+ return GWVS_COVERED;
+ else //There are dots which are visible, but they are not as many as the ones we counted: it's partially covered.
+ return GWVS_PARTIALLY_COVERED;
+ }
+}
+
+int ShowHide(WPARAM wParam, LPARAM lParam)
+{
+ BOOL bShow = FALSE;
+
+ int iVisibleState = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0);
+
+ if(IsIconic(pcli->hwndContactList)) {
+ SendMessage(pcli->hwndContactList, WM_SYSCOMMAND, SC_RESTORE, 0);
+ bShow = TRUE;
+ }
+ else {
+ switch (iVisibleState) {
+ case GWVS_PARTIALLY_COVERED:
+ //If we don't want to bring it to top, we can use a simple break. This goes against readability ;-) but the comment explains it.
+ if (!cfg::getByte("CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT))
+ break;
+ case GWVS_COVERED: //Fall through (and we're already falling)
+ case GWVS_HIDDEN:
+ bShow = TRUE;
+ break;
+ case GWVS_VISIBLE: //This is not needed, but goes for readability.
+ bShow = FALSE;
+ break;
+ case -1: //We can't get here, both cli.hwndContactList and iStepX and iStepY are right.
+ return 0;
+ }
+ }
+
+ if (bShow == TRUE) {
+ RECT rcWindow;
+
+ SetWindowPos(pcli->hwndContactList, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOCOPYBITS);
+ if (!cfg::getByte("CList", "OnTop", SETTING_ONTOP_DEFAULT))
+ SetWindowPos(pcli->hwndContactList, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOCOPYBITS);
+ SetForegroundWindow(pcli->hwndContactList);
+ ShowWindow(pcli->hwndContactList, SW_SHOW);
+ cfg::writeByte("CList", "State", SETTING_STATE_NORMAL);
+
+ GetWindowRect(pcli->hwndContactList, &rcWindow);
+ if (Utils_AssertInsideScreen(&rcWindow) == 1)
+ {
+ MoveWindow(pcli->hwndContactList, rcWindow.left, rcWindow.top,
+ rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
+ }
+ }
+ else { //It needs to be hidden
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ cfg::writeByte("CList", "State", SETTING_STATE_HIDDEN);
+ if (cfg::getByte("CList", "DisableWorkingSet", 1))
+ SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ return 0;
+}
diff --git a/plugins/Clist_ng/SRC/clistopts.cpp b/plugins/Clist_ng/SRC/clistopts.cpp new file mode 100644 index 0000000000..44b810d90c --- /dev/null +++ b/plugins/Clist_ng/SRC/clistopts.cpp @@ -0,0 +1,216 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+#include "commonheaders.h"
+
+void LoadContactTree(void);
+void SortContacts(void);
+
+static int opt_gen_opts_changed = 0;
+
+static void __setFlag(DWORD dwFlag, int iMode)
+{
+ cfg::dat.dwFlags = iMode ? cfg::dat.dwFlags | dwFlag : cfg::dat.dwFlags & ~dwFlag;
+}
+
+INT_PTR CALLBACK cfg::DlgProcGenOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_USER+1:
+ {
+ HANDLE hContact = (HANDLE) wParam;
+ DBCONTACTWRITESETTING *ws = (DBCONTACTWRITESETTING *) lParam;
+ if (hContact == NULL && ws != NULL && ws->szModule != NULL && ws->szSetting != NULL && lstrcmpiA(ws->szModule, "CList") == 0 && lstrcmpiA(ws->szSetting, "UseGroups") == 0 && IsWindowVisible(hwndDlg)) {
+ CheckDlgButton(hwndDlg, IDC_DISABLEGROUPS, ws->value.bVal == 0);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ UnhookEvent((HANDLE) GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
+ break;
+
+ case WM_INITDIALOG:
+ opt_gen_opts_changed = 0;
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) HookEventMessage(ME_DB_CONTACT_SETTINGCHANGED, hwndDlg, WM_USER + 1));
+ CheckDlgButton(hwndDlg, IDC_ONTOP, cfg::getByte("CList", "OnTop", SETTING_ONTOP_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_HIDEOFFLINE, cfg::getByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_HIDEEMPTYGROUPS, cfg::getByte("CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISABLEGROUPS, cfg::getByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_CONFIRMDELETE, cfg::getByte("CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ {
+ DWORD caps = CallService(MS_CLUI_GETCAPS, CLUICAPS_FLAGS1, 0);
+ if (!(caps & CLUIF_HIDEEMPTYGROUPS))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HIDEEMPTYGROUPS), SW_HIDE);
+ if (!(caps & CLUIF_DISABLEGROUPS))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DISABLEGROUPS), SW_HIDE);
+ if (caps & CLUIF_HASONTOPOPTION)
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ONTOP), SW_HIDE);
+ if (caps & CLUIF_HASAUTOHIDEOPTION) {
+ }
+ }
+
+ CheckDlgButton(hwndDlg, IDC_SHOWBOTTOMBUTTONS, cfg::dat.dwFlags & CLUI_FRAME_SHOWBOTTOMBUTTONS);
+ CheckDlgButton(hwndDlg, IDC_CLISTSUNKEN, cfg::dat.dwFlags & CLUI_FRAME_CLISTSUNKEN);
+ CheckDlgButton(hwndDlg, IDC_EVENTAREAAUTOHIDE, cfg::dat.dwFlags & CLUI_FRAME_AUTOHIDENOTIFY);
+
+ CheckDlgButton(hwndDlg, IDC_ONECLK, cfg::getByte("CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSSTATUS, cfg::getByte("CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSMULTI, !cfg::getByte("CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DONTCYCLE, cfg::getByte("CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_SINGLE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CYCLE, cfg::getByte("CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_CYCLE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_MULTITRAY, cfg::getByte("CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISABLEBLINK, cfg::getByte("CList", "DisableTrayFlash", 0) == 1 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ICONBLINK, cfg::getByte("CList", "NoIconBlink", 0) == 1 ? BST_CHECKED : BST_UNCHECKED);
+ if (IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE)) {
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIMESPIN, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIME, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_ALWAYSMULTI, FALSE);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_CYCLE)) {
+ Utils::enableDlgControl(hwndDlg, IDC_PRIMARYSTATUS, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_ALWAYSMULTI, FALSE);
+ }
+ if (IsDlgButtonChecked(hwndDlg, IDC_MULTITRAY)) {
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIMESPIN, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIME, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_PRIMARYSTATUS, FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_SETRANGE, 0, MAKELONG(120, 1));
+ SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_SETPOS, 0, MAKELONG(cfg::getWord("CList", "CycleTime", SETTING_CYCLETIME_DEFAULT), 0)); {
+ int i, count, item;
+ PROTOACCOUNT **accs;
+ DBVARIANT dbv = {
+ DBVT_DELETED
+ };
+ db_get(NULL, "CList", "PrimaryStatus", &dbv);
+ Proto_EnumAccounts( &count, &accs );
+ item = SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_ADDSTRING, 0, (LPARAM) TranslateT("Global"));
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETITEMDATA, item, (LPARAM) 0);
+ for (i = 0; i < count; i++) {
+ if ( !Proto_IsAccountEnabled(accs[i]) || CallProtoService(accs[i]->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+
+ item = SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_ADDSTRING, 0, (LPARAM) accs[i]->tszAccountName);
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETITEMDATA, item, (LPARAM)accs[i] );
+ if (dbv.type == DBVT_ASCIIZ && !lstrcmpA(dbv.pszVal, accs[i]->szModuleName ))
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETCURSEL, item, 0);
+ }
+ }
+ if (-1 == (int) SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETCURSEL, 0, 0))
+ SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETBUDDY, (WPARAM) GetDlgItem(hwndDlg, IDC_BLINKTIME), 0); // set buddy
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETRANGE, 0, MAKELONG(0x3FFF, 250));
+ SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETPOS, 0, MAKELONG(cfg::getWord("CList", "IconFlashTime", 550), 0));
+ CheckDlgButton(hwndDlg, IDC_NOTRAYINFOTIPS, cfg::dat.bNoTrayTips ? 1 : 0);
+ CheckDlgButton(hwndDlg, IDC_APPLYLASTVIEWMODE, cfg::getByte("CList", "AutoApplyLastViewMode", 0) ? 1 : 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_DONTCYCLE || LOWORD(wParam) == IDC_CYCLE || LOWORD(wParam) == IDC_MULTITRAY) {
+ Utils::enableDlgControl(hwndDlg, IDC_PRIMARYSTATUS, IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE));
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIME, IsDlgButtonChecked(hwndDlg, IDC_CYCLE));
+ Utils::enableDlgControl(hwndDlg, IDC_CYCLETIMESPIN, IsDlgButtonChecked(hwndDlg, IDC_CYCLE));
+ Utils::enableDlgControl(hwndDlg, IDC_ALWAYSMULTI, IsDlgButtonChecked(hwndDlg, IDC_MULTITRAY));
+ }
+ if ((LOWORD(wParam) == IDC_CYCLETIME) && HIWORD(wParam) != EN_CHANGE)
+ break;
+ if (LOWORD(wParam) == IDC_PRIMARYSTATUS && HIWORD(wParam) != CBN_SELCHANGE)
+ break;
+ if ((LOWORD(wParam) == IDC_CYCLETIME) && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ if (LOWORD(wParam) == IDC_BLINKTIME && HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0; // dont make apply enabled during buddy set crap
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ opt_gen_opts_changed = TRUE;
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ if(!opt_gen_opts_changed)
+ return TRUE;
+
+ cfg::writeByte("CList", "HideOffline", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_HIDEOFFLINE));
+ {
+ DWORD caps = CallService(MS_CLUI_GETCAPS, CLUICAPS_FLAGS1, 0);
+ if (caps & CLUIF_HIDEEMPTYGROUPS)
+ cfg::writeByte("CList", "HideEmptyGroups", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_HIDEEMPTYGROUPS));
+ if (caps & CLUIF_DISABLEGROUPS)
+ cfg::writeByte("CList", "UseGroups", (BYTE) ! IsDlgButtonChecked(hwndDlg, IDC_DISABLEGROUPS));
+ if (!(caps & CLUIF_HASONTOPOPTION)) {
+ cfg::writeByte("CList", "OnTop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONTOP));
+ SetWindowPos(pcli->hwndContactList, IsDlgButtonChecked(hwndDlg, IDC_ONTOP) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ if (!(caps & CLUIF_HASAUTOHIDEOPTION)) {
+ }
+ }
+ cfg::writeByte("CList", "ConfirmDelete", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CONFIRMDELETE));
+ cfg::writeByte("CList", "Tray1Click", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONECLK));
+ cfg::writeByte("CList", "AlwaysStatus", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ALWAYSSTATUS));
+ cfg::writeByte("CList", "AlwaysMulti", (BYTE) ! IsDlgButtonChecked(hwndDlg, IDC_ALWAYSMULTI));
+ cfg::writeByte("CList", "TrayIcon", (BYTE) (IsDlgButtonChecked(hwndDlg, IDC_DONTCYCLE) ? SETTING_TRAYICON_SINGLE : (IsDlgButtonChecked(hwndDlg, IDC_CYCLE) ? SETTING_TRAYICON_CYCLE : SETTING_TRAYICON_MULTI)));
+ cfg::writeWord("CList", "CycleTime", (WORD) SendDlgItemMessage(hwndDlg, IDC_CYCLETIMESPIN, UDM_GETPOS, 0, 0));
+ cfg::writeWord("CList", "IconFlashTime", (WORD) SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_GETPOS, 0, 0));
+ cfg::writeByte("CList", "DisableTrayFlash", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_DISABLEBLINK));
+ cfg::writeByte("CList", "NoIconBlink", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ICONBLINK));
+ cfg::writeByte("CList", "AutoApplyLastViewMode", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_APPLYLASTVIEWMODE));
+
+ __setFlag(CLUI_FRAME_AUTOHIDENOTIFY, IsDlgButtonChecked(hwndDlg, IDC_EVENTAREAAUTOHIDE));
+
+ __setFlag(CLUI_FRAME_SHOWBOTTOMBUTTONS, IsDlgButtonChecked(hwndDlg, IDC_SHOWBOTTOMBUTTONS));
+ __setFlag(CLUI_FRAME_CLISTSUNKEN, IsDlgButtonChecked(hwndDlg, IDC_CLISTSUNKEN));
+
+ cfg::dat.bNoTrayTips = IsDlgButtonChecked(hwndDlg, IDC_NOTRAYINFOTIPS) ? 1 : 0;
+ cfg::writeByte("CList", "NoTrayTips", (BYTE)cfg::dat.bNoTrayTips);
+ {
+ int cursel = SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETCURSEL, 0, 0);
+ PROTOACCOUNT* pa = (PROTOACCOUNT*)SendDlgItemMessage(hwndDlg, IDC_PRIMARYSTATUS, CB_GETITEMDATA, cursel, 0);
+ if ( !pa )
+ db_unset(NULL, "CList", "PrimaryStatus");
+ else
+ cfg::writeString(NULL, "CList", "PrimaryStatus", pa->szModuleName );
+ }
+ pcli->pfnTrayIconIconsChanged();
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+ CLUI::configureWindowLayout();
+ CLUI::configureGeometry(1);
+ CLUI::configureEventArea(pcli->hwndContactList);
+ CLUI::hideShowNotifyFrame();
+ SendMessage(pcli->hwndContactTree, WM_SIZE, 0, 0);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ CLC::LoadContactTree(); /* this won't do job properly since it only really works when changes happen */
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ PostMessage(pcli->hwndContactList, CLUIINTM_REDRAW, 0, 0);
+
+ opt_gen_opts_changed = 0;
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/plugins/Clist_ng/SRC/clisttray.cpp b/plugins/Clist_ng/SRC/clisttray.cpp new file mode 100644 index 0000000000..1eec622829 --- /dev/null +++ b/plugins/Clist_ng/SRC/clisttray.cpp @@ -0,0 +1,166 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+UNICODE done
+
+*/
+#include "commonheaders.h"
+
+#define TRAYICON_ID_BASE 100
+#define TIM_CALLBACK (WM_USER+1857)
+#define TIM_CREATE (WM_USER+1858)
+
+#define NIF_STATE 0x00000008
+#define NIF_INFO 0x00000010
+
+void TrayIconUpdateBase(const char *szChangedProto)
+{
+ int i,count,netProtoCount,changed = -1;
+ PROTOACCOUNT **accs;
+ int averageMode = 0;
+ HWND hwnd = pcli->hwndContactList;
+
+ if (pcli->cycleTimerId)
+ KillTimer(NULL, pcli->cycleTimerId); pcli->cycleTimerId = 0;
+
+ Proto_EnumAccounts( &count, &accs );
+ for (i = 0,netProtoCount = 0; i < count; i++) {
+ if ( !pcli->pfnGetProtocolVisibility( accs[i]->szModuleName ))
+ continue;
+ netProtoCount++;
+ if (!lstrcmpA(szChangedProto, accs[i]->szModuleName ))
+ pcli->cycleStep = i;
+ if (averageMode == 0)
+ averageMode = CallProtoService( accs[i]->szModuleName, PS_GETSTATUS, 0, 0);
+ else if (averageMode != CallProtoService( accs[i]->szModuleName, PS_GETSTATUS, 0, 0)) {
+ averageMode = -1; break;
+ }
+ }
+ if (netProtoCount > 1) {
+ if (averageMode > 0) {
+ if (cfg::getByte("CList", "TrayIcon", SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI) {
+ if (cfg::getByte("CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT)) {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(szChangedProto, averageMode, 0, &hIcon);
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), szChangedProto);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), szChangedProto);
+ }
+ else if (pcli->trayIcon && pcli->trayIcon[0].szProto != NULL) {
+ pcli->pfnTrayIconDestroy(hwnd);
+ pcli->pfnTrayIconInit(hwnd);
+ }
+ else {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(NULL, averageMode, 0, &hIcon);
+
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), NULL);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), NULL);
+ }
+ } else {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(NULL, averageMode, 0, &hIcon);
+
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), NULL);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), NULL);
+ }
+ } else {
+ switch (cfg::getByte("CList", "TrayIcon", SETTING_TRAYICON_DEFAULT)) {
+ case SETTING_TRAYICON_SINGLE:
+ {
+ DBVARIANT dbv = {DBVT_DELETED};
+ int iIcon = 0;
+ HICON hIcon = 0;
+ char *szProto;
+ if (cfg::getString(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ iIcon = CLC::IconFromStatusMode(szProto, szProto ? CallProtoService(szProto, PS_GETSTATUS, 0, 0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0), 0, &hIcon);
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), NULL);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), NULL);
+ db_free(&dbv);
+ break;
+ }
+ case SETTING_TRAYICON_CYCLE:
+ {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), 0, &hIcon);
+
+ pcli->cycleTimerId = SetTimer(NULL, 0, cfg::getWord("CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, pcli->pfnTrayCycleTimerProc);
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), NULL);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), NULL);
+ break;
+ }
+ case SETTING_TRAYICON_MULTI:
+ if ( !pcli->trayIcon )
+ pcli->pfnTrayIconRemove(NULL, NULL);
+ else if (cfg::getByte("CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT)) {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), 0, &hIcon);
+
+ if(hIcon)
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), szChangedProto);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), szChangedProto);
+ }
+ else {
+ pcli->pfnTrayIconDestroy(hwnd);
+ pcli->pfnTrayIconInit(hwnd);
+ }
+ break;
+ }
+ }
+ } else {
+ HICON hIcon = 0;
+ int iIcon = CLC::IconFromStatusMode(NULL, averageMode, 0, &hIcon);
+ if ( hIcon )
+ changed = pcli->pfnTrayIconSetBaseInfo(CopyIcon(hIcon), NULL);
+ else
+ changed = pcli->pfnTrayIconSetBaseInfo(ImageList_GetIcon(CLC::hClistImages, iIcon, ILD_NORMAL), NULL);
+ }
+ if (changed != -1 && pcli->trayIcon[changed].isBase)
+ pcli->pfnTrayIconUpdate( pcli->trayIcon[changed].hBaseIcon, NULL, pcli->trayIcon[changed].szProto, 1);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CLC::TrayIconProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG* msg = ( MSG* )wParam;
+ if ( msg->message == TIM_CALLBACK && msg->lParam == WM_MOUSEMOVE ) {
+ if ( cfg::dat.bNoTrayTips ) {
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ } }
+
+ return coreCli.pfnTrayIconProcessMessage(wParam, lParam);
+}
diff --git a/plugins/Clist_ng/SRC/clui.cpp b/plugins/Clist_ng/SRC/clui.cpp new file mode 100644 index 0000000000..81545a7894 --- /dev/null +++ b/plugins/Clist_ng/SRC/clui.cpp @@ -0,0 +1,2062 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: clui.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <shobjidl.h>
+#include <m_findadd.h>
+#include <m_icq.h>
+#include "../coolsb/coolscroll.h"
+
+LRESULT (CALLBACK* CLUI::saveContactListWndProc )(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
+
+int CLUI::fading_active = 0;
+HPEN CLUI::hPenFrames = 0;
+WNDPROC CLUI::OldStatusBarProc = 0;
+bool CLUI::fInSizing = false;
+RECT CLUI::newRect = {0};
+RECT CLUI::rcWPC = {0};
+RECT CLUI::cluiPos = {0};
+HIMAGELIST CLUI::hExtraImages = 0;
+TImageItem* CLUI::bgImageItem = 0, *CLUI::bgImageItem_nonAero = 0, *CLUI::bgClientItem = 0;
+TButtonItem* CLUI::buttonItems = 0;
+
+#ifdef _USE_D2D
+ ID2D1HwndRenderTarget* CLUI::renderTarget = 0;
+#endif
+UPDATELAYEREDWINDOWINFO CLUI::ulwInfo = {0};
+BLENDFUNCTION CLUI::bf = {0};
+
+static RECT g_PreSizeRect;
+static LONG g_CLUI_x_off, g_CLUI_y_off, g_CLUI_y1_off, g_CLUI_x1_off;
+
+static int transparentFocus = 1;
+static byte oldhideoffline;
+static int disableautoupd = 1;
+HANDLE hFrameContactTree;
+extern PLUGININFOEX pluginInfo;
+
+extern BOOL g_trayTooltipActive;
+extern POINT tray_hover_pos;
+extern HWND g_hwndViewModeFrame, g_hwndEventArea;
+
+extern HBRUSH g_CLUISkinnedBkColor;
+extern HWND g_hwndSFL;
+extern COLORREF g_CLUISkinnedBkColorRGB;
+extern FRAMEWND *wndFrameCLC;
+
+static BYTE old_cliststate;
+
+wchar_t *statusNames[12];
+
+extern HANDLE hNotifyFrame;
+
+void FLT_ShowHideAll(int showCmd);
+void FLT_SnapToEdges(HWND hwnd);
+void DestroyTrayMenu(HMENU hMenu);
+
+extern HANDLE hSoundHook;
+extern HANDLE hIcoLibChanged;
+extern HANDLE hExtraImageListRebuilding, hExtraImageApplying;
+
+SIZE g_oldSize = {0};
+POINT g_oldPos = {0};
+extern int dock_prevent_moving;
+
+static HDC hdcLockedPoint = 0;
+static HBITMAP hbmLockedPoint = 0, hbmOldLockedPoint = 0;
+
+HICON overlayicons[10];
+
+struct CluiTopButton top_buttons[] = {
+ 0, 0, 0, IDC_TBTOPMENU, IDI_TBTOPMENU, 0, "CLN_topmenu", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 1, LPGENT("Show menu"),
+ 0, 0, 0, IDC_TBHIDEOFFLINE, IDI_HIDEOFFLINE, 0, "CLN_online", NULL, 0, 2, LPGENT("Show / hide offline contacts"),
+ 0, 0, 0, IDC_TBHIDEGROUPS, IDI_HIDEGROUPS, 0, "CLN_groups", NULL, 0, 4, LPGENT("Toggle group mode"),
+ 0, 0, 0, IDC_TBFINDANDADD, IDI_FINDANDADD, 0, "CLN_findadd", NULL, TOPBUTTON_PUSH, 8, LPGENT("Find and add contacts"),
+ 0, 0, 0, IDC_TBACCOUNTS, IDI_TBACCOUNTS, 0, "CLN_accounts", NULL, TOPBUTTON_PUSH, 8192, LPGENT("Accounts"),
+ 0, 0, 0, IDC_TBOPTIONS, IDI_TBOPTIONS, 0, "CLN_options", NULL, TOPBUTTON_PUSH, 16, LPGENT("Open preferences"),
+ 0, 0, 0, IDC_TBSOUND, IDI_SOUNDSON, IDI_SOUNDSOFF, "CLN_sound", "CLN_soundsoff", 0, 32, LPGENT("Toggle sounds"),
+ 0, 0, 0, IDC_TBMINIMIZE, IDI_MINIMIZE, 0, "CLN_minimize", NULL, TOPBUTTON_PUSH, 64, LPGENT("Minimize contact list"),
+ 0, 0, 0, IDC_TBTOPSTATUS, 0, 0, "CLN_topstatus", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 128, LPGENT("Status menu"),
+ 0, 0, 0, IDC_TABSRMMSLIST, IDI_TABSRMMSESSIONLIST, 0, "CLN_slist", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 256, LPGENT("tabSRMM session list"),
+ 0, 0, 0, IDC_TABSRMMMENU, IDI_TABSRMMMENU, 0, "CLN_menu", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 512, LPGENT("tabSRMM Menu"),
+
+ 0, 0, 0, IDC_TBSELECTVIEWMODE, 0, 0, "CLN_CLVM_select", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 1024, LPGENT("Select view mode"),
+ 0, 0, 0, IDC_TBCONFIGUREVIEWMODE, 0, 0, "CLN_CLVM_options", NULL, TOPBUTTON_PUSH, 2048, LPGENT("Setup view modes"),
+ 0, 0, 0, IDC_TBCLEARVIEWMODE, 0, 0, "CLN_CLVM_reset", NULL, TOPBUTTON_PUSH, 4096, LPGENT("Clear view mode"),
+
+ 0, 0, 0, IDC_TBGLOBALSTATUS, 0, 0, "", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 0, LPGENT("Set status modes"),
+ 0, 0, 0, IDC_TBMENU, IDI_MINIMIZE, 0, "", NULL, TOPBUTTON_PUSH | TOPBUTTON_SENDONDOWN, 0, LPGENT("Open main menu"),
+ (HWND) - 1, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+IconItemT iconItem[] = {
+ { LPGENT("Toggle show online/offline"), "CLN_online", IDI_HIDEOFFLINE },
+ { LPGENT("Toggle groups"), "CLN_groups", IDI_HIDEGROUPS },
+ { LPGENT("Find contacts"), "CLN_findadd", IDI_FINDANDADD },
+ { LPGENT("Open preferences"), "CLN_options", IDI_TBOPTIONS },
+ { LPGENT("Toggle sounds"), "CLN_sound", IDI_SOUNDSON },
+ { LPGENT("Minimize contact list"), "CLN_minimize", IDI_MINIMIZE },
+ { LPGENT("Show TabSRMM session list"), "CLN_slist", IDI_TABSRMMSESSIONLIST },
+ { LPGENT("Show TabSRMM menu"), "CLN_menu", IDI_TABSRMMMENU },
+ { LPGENT("Sounds are off"), "CLN_soundsoff", IDI_SOUNDSOFF },
+ { LPGENT("Select view mode"), "CLN_CLVM_select", IDI_CLVM_SELECT },
+ { LPGENT("Reset view mode"), "CLN_CLVM_reset", IDI_DELETE },
+ { LPGENT("Configure view modes"), "CLN_CLVM_options", IDI_CLVM_OPTIONS },
+ { LPGENT("Show menu"), "CLN_topmenu", IDI_TBTOPMENU },
+ { LPGENT("Setup accounts"), "CLN_accounts", IDI_TBACCOUNTS }
+};
+
+void CLUI::Tweak_It(const COLORREF clr)
+{
+#ifndef _USE_D2D
+ if(!cfg::isAero)
+ SetLayeredWindowAttributes(pcli->hwndContactList, clr, 0, LWA_COLORKEY);
+#endif
+ cfg::dat.colorkey = clr;
+}
+
+void CLUI::layoutButtons(HWND hwnd, RECT *rc)
+{
+ RECT rect;
+ BYTE left_offset = Skin::metrics.cLeft - (cfg::dat.dwFlags & CLUI_FRAME_CLISTSUNKEN ? 3 : 0);
+ BYTE right_offset = Skin::metrics.cRight - (cfg::dat.dwFlags & CLUI_FRAME_CLISTSUNKEN ? 3 : 0);
+ BYTE delta = left_offset + right_offset;
+ TButtonItem *btnItems = buttonItems;
+ HDWP dwp = 0;
+ bool fFrame = Skin::metrics.fHaveFrame;
+
+ if (rc == NULL)
+ GetClientRect(hwnd, &rect);
+ else
+ rect = *rc;
+
+ rect.bottom -= Skin::metrics.cBottom;
+
+ if (buttonItems || cfg::dat.dwFlags && CLUI_FRAME_SHOWBOTTOMBUTTONS) {
+ LONG x, y;
+ dwp = BeginDeferWindowPos(10);
+
+ while (btnItems) {
+ if(btnItems->dwFlags & BUTTON_FRAMELESS_ONLY) {
+ if(Skin::metrics.fHaveFrame && IsWindowVisible(btnItems->hWnd))
+ ShowWindow(btnItems->hWnd, SW_HIDE);
+ else if(!Skin::metrics.fHaveFrame && !IsWindowVisible(btnItems->hWnd))
+ ShowWindow(btnItems->hWnd, SW_SHOW);
+ }
+ fFrame = Skin::metrics.fHaveFrame || btnItems->dwFlags & BUTTON_FRAMELESS_ONLY;
+
+ x = (btnItems->xOff >= 0) ? rect.left + btnItems->xOff + (!fFrame ? Skin::metrics.cFakeLeftBorder : 0) :
+ rect.right - abs(btnItems->xOff) - (!fFrame ? Skin::metrics.cFakeRightBorder : 0);
+ if(btnItems->dwFlags & BUTTON_VALIGN_B)
+ y = rect.bottom - Skin::metrics.bSBarHeight - abs(btnItems->yOff) - (!fFrame ? Skin::metrics.cFakeBtmBorder : 0);
+ else
+ y = rect.top + btnItems->yOff + (!fFrame ? Skin::metrics.cFakeCaption : 0);
+
+ DeferWindowPos(dwp, btnItems->hWnd, 0, x, y, btnItems->width, btnItems->height,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOREDRAW);
+ btnItems = btnItems->nextItem;
+ }
+ DeferWindowPos(dwp, top_buttons[15].hwnd, 0, 2 + left_offset, rect.bottom - Skin::metrics.bSBarHeight - Skin::metrics.cButtonHeight - 1,
+ BUTTON_WIDTH_D * 3, Skin::metrics.cButtonHeight + 1, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOREDRAW);
+ DeferWindowPos(dwp, top_buttons[14].hwnd, 0, left_offset + (3 * BUTTON_WIDTH_D) + 3, rect.bottom - Skin::metrics.bSBarHeight - Skin::metrics.cButtonHeight - 1,
+ rect.right - delta - (3 * BUTTON_WIDTH_D + 5), Skin::metrics.cButtonHeight + 1, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOREDRAW);
+
+ EndDeferWindowPos(dwp);
+ return;
+ }
+}
+
+static int FS_FontsChanged(WPARAM wParam, LPARAM lParam)
+{
+ pcli->pfnClcOptionsChanged();
+ CLUI::Redraw();
+ return 0;
+}
+
+/*
+* create the CLC control, but not yet the frame. The frame containing the CLC should be created as the
+* last frame of all.
+*/
+
+HWND CLUI::preCreateCLC(HWND parent)
+{
+ pcli->hwndContactTree = CreateWindow(_T(CLISTCONTROL_CLASS), L"",
+ WS_CHILD | CLS_CONTACTLIST
+ | (cfg::getByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? CLS_USEGROUPS : 0)
+ | CLS_HIDEOFFLINE
+ //|(DBGetContactSettingByte(NULL,"CList","HideOffline",SETTING_HIDEOFFLINE_DEFAULT)?CLS_HIDEOFFLINE:0)
+ | (cfg::getByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ? CLS_HIDEEMPTYGROUPS : 0)
+ | CLS_MULTICOLUMN
+ , 0, 0, 0, 0, parent, NULL, g_hInst, (LPVOID)0xff00ff00);
+
+ cfg::clcdat = (struct ClcData *)GetWindowLongPtr(pcli->hwndContactTree, 0);
+
+ return pcli->hwndContactTree;
+}
+
+/*
+* create internal frames, including the last frame (actual CLC control)
+*/
+
+int CLUI::createCLC(HWND parent)
+{
+ reloadExtraIcons();
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM)oldhideoffline, 0);
+ disableautoupd = 0;
+ {
+ CLISTFrame frame = {0};
+ frame.cbSize = sizeof(frame);
+ frame.tname = _T("EventArea");
+ frame.TBtname = TranslateT("Event Area");
+ frame.hIcon = 0;
+ frame.height = 20;
+ frame.Flags = F_VISIBLE | F_SHOWTBTIP | F_NOBORDER | F_TCHAR;
+ frame.align = alBottom;
+ frame.hWnd = CreateWindowExW(0, L"EventAreaClass", L"evt", WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 20, 20, pcli->hwndContactList, (HMENU) 0, g_hInst, NULL);
+ g_hwndEventArea = frame.hWnd;
+ hNotifyFrame = (HWND)CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM) & frame, (LPARAM)0);
+ CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)hNotifyFrame, FU_FMPOS);
+ hideShowNotifyFrame();
+ CreateViewModeFrame();
+ }
+
+ SetButtonToSkinned();
+
+ {
+ DWORD flags;
+ CLISTFrame Frame;
+ memset(&Frame, 0, sizeof(Frame));
+ Frame.cbSize = sizeof(CLISTFrame);
+ Frame.hWnd = pcli->hwndContactTree;
+ Frame.align = alClient;
+ Frame.hIcon = Skin_LoadIcon(SKINICON_OTHER_MIRANDA);
+ Frame.Flags = F_VISIBLE | F_SHOWTB | F_SHOWTBTIP | F_NOBORDER | F_TCHAR;
+ Frame.tname = _T("My Contacts");
+ Frame.TBtname = TranslateT("My Contacts");
+ Frame.height = 200;
+ hFrameContactTree = (HWND)CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM) & Frame, (LPARAM)0);
+ //free(Frame.name);
+ CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_TBTIPNAME, hFrameContactTree), (LPARAM)Translate("My Contacts"));
+
+ /*
+ * ugly, but working hack. Prevent that annoying little scroll bar from appearing in the "My Contacts" title bar
+ */
+
+ flags = (DWORD)CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, hFrameContactTree), 0);
+ flags |= F_VISIBLE;
+ CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, hFrameContactTree), flags);
+ }
+ return(0);
+}
+
+int CLUI::modulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ MTG_OnmodulesLoad(wParam, lParam);
+ HookEvent(ME_FONT_RELOAD, FS_FontsChanged);
+ return 0;
+}
+
+static HICON hIconSaved = 0;
+
+void ClearIcons(int mode)
+{
+ int i;
+
+ for (i = IDI_OVL_OFFLINE; i <= IDI_OVL_OUTTOLUNCH; i++) {
+ if (overlayicons[i - IDI_OVL_OFFLINE] != 0) {
+ if (mode)
+ DestroyIcon(overlayicons[i - IDI_OVL_OFFLINE]);
+ overlayicons[i - IDI_OVL_OFFLINE] = 0;
+ }
+ }
+ hIconSaved = ImageList_GetIcon(CLUI::hExtraImages, 3, ILD_NORMAL);
+ ImageList_RemoveAll(CLUI::hExtraImages);
+}
+
+static void CacheClientIcons()
+{
+ int i = 0;
+ char szBuffer[128];
+
+ ClearIcons(0);
+
+ for (i = IDI_OVL_OFFLINE; i <= IDI_OVL_OUTTOLUNCH; i++) {
+ mir_snprintf(szBuffer, sizeof(szBuffer), "cln_ovl_%d", ID_STATUS_OFFLINE + (i - IDI_OVL_OFFLINE));
+ overlayicons[i - IDI_OVL_OFFLINE] = IcoLib_GetIcon(szBuffer);
+ }
+ ImageList_AddIcon(CLUI::hExtraImages, IcoLib_GetIcon("core_main_14"));
+ ImageList_AddIcon(CLUI::hExtraImages, Skin_LoadIcon(SKINICON_EVENT_URL));
+ ImageList_AddIcon(CLUI::hExtraImages, IcoLib_GetIcon("core_main_17"));
+ if (hIconSaved != 0) {
+ ImageList_AddIcon(CLUI::hExtraImages, hIconSaved);
+ DestroyIcon(hIconSaved);
+ hIconSaved = 0;
+ } else
+ ImageList_AddIcon(CLUI::hExtraImages, IcoLib_GetIcon("core_main_17"));
+}
+
+static void InitIcoLib()
+{
+ Icon_RegisterT(g_hInst, LPGENT("Contact list")_T("/")LPGENT("Default"),iconItem, _countof(iconItem));
+
+ for (int i = IDI_OVL_OFFLINE; i <= IDI_OVL_OUTTOLUNCH; i++) {
+ char szBuffer[128];
+ mir_snprintf(szBuffer, _countof(szBuffer), "cln_ovl_%d", ID_STATUS_OFFLINE + (i - IDI_OVL_OFFLINE));
+ IconItemT icon = { pcli->pfnGetStatusModeDescription(ID_STATUS_OFFLINE + (i - IDI_OVL_OFFLINE), 0), szBuffer, i };
+ Icon_RegisterT(g_hInst, LPGENT("Contact list")_T("/")LPGENT("Overlay icons"), &icon, 1);
+ }
+
+ PROTOACCOUNT **accs = NULL;
+ int p_count = 0;
+ Proto_EnumAccounts(&p_count, &accs);
+ for (int k = 0; k < p_count; k++) {
+ if (!Proto_IsAccountEnabled(accs[k]) || CallProtoService(accs[k]->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0) == 0)
+ continue;
+
+ TCHAR szDescr[128];
+ mir_sntprintf(szDescr, _countof(szDescr), TranslateT("%s connecting"), accs[k]->tszAccountName);
+ IconItemT icon = { szDescr, "conn", IDI_PROTOCONNECTING };
+ Icon_RegisterT(g_hInst, LPGENT("Contact list")_T("/")LPGENT("Connecting icons"), &icon, 1, accs[k]->szModuleName);
+ }
+}
+
+static int IcoLibChanged(WPARAM wParam, LPARAM lParam)
+{
+ IcoLibReloadIcons();
+ return 0;
+}
+
+/*
+* if mode != 0 we do first time init, otherwise only reload the extra icon stuff
+*/
+
+void CLN_LoadAllIcons(BOOL mode)
+{
+ if (mode) {
+ InitIcoLib();
+ HookEvent(ME_SKIN2_ICONSCHANGED, IcoLibChanged);
+ }
+ CacheClientIcons();
+ /*
+ if (mode) {
+ InitIcoLib();
+ hIcoLibChanged = HookEvent(ME_SKIN2_ICONSCHANGED, IcoLibChanged);
+ cfg::dat.hIconVisible = (HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM) "CLN_visible");
+ cfg::dat.hIconInvisible = (HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM) "CLN_invisible");
+ cfg::dat.hIconChatactive = (HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM) "CLN_chatactive");
+ }
+ CacheClientIcons();
+ */
+}
+
+void CLUI::configureEventArea(HWND hwnd)
+{
+ int iCount = GetMenuItemCount(cfg::dat.hMenuNotify);
+ DWORD dwFlags = cfg::dat.dwFlags;
+ int oldstate = cfg::dat.notifyActive;
+ int dwVisible = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, hNotifyFrame), 0) & F_VISIBLE;
+
+ if (dwVisible) {
+ if (dwFlags & CLUI_FRAME_AUTOHIDENOTIFY)
+ cfg::dat.notifyActive = iCount > 0 ? 1 : 0;
+ else
+ cfg::dat.notifyActive = 1;
+ } else
+ cfg::dat.notifyActive = 0;
+
+ if (oldstate != cfg::dat.notifyActive)
+ hideShowNotifyFrame();
+}
+
+void CLUI::configureWindowLayout()
+{
+ int i;
+
+ for (i = 0; ; i++) {
+ if (top_buttons[i].szTooltip == NULL)
+ break;
+ if (top_buttons[i].hwnd == 0)
+ continue;
+ switch (top_buttons[i].id) {
+ case IDC_TBMENU:
+ case IDC_TBGLOBALSTATUS:
+ ShowWindow(top_buttons[i].hwnd, cfg::dat.dwFlags & CLUI_FRAME_SHOWBOTTOMBUTTONS ? SW_SHOW : SW_HIDE);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void IcoLibReloadIcons()
+{
+ int i;
+ HICON hIcon;
+
+ for (i = 0; ; i++) {
+ if (top_buttons[i].szTooltip == NULL)
+ break;
+
+ if (top_buttons[i].id == IDC_TBMENU || top_buttons[i].id == IDC_TBGLOBALSTATUS || top_buttons[i].id == IDC_TBTOPSTATUS)
+ continue;
+
+ hIcon = IcoLib_GetIcon(top_buttons[i].szIcoLibIcon);
+ if (top_buttons[i].hwnd && IsWindow(top_buttons[i].hwnd)) {
+ SendMessage(top_buttons[i].hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
+ InvalidateRect(top_buttons[i].hwnd, NULL, TRUE);
+ }
+ }
+ cfg::dat.hIconVisible = IcoLib_GetIcon("CLN_visible");
+ cfg::dat.hIconInvisible = IcoLib_GetIcon("CLN_invisible");
+ cfg::dat.hIconChatactive = IcoLib_GetIcon("CLN_chatactive");
+ CacheClientIcons();
+ CLUI::reloadExtraIcons();
+
+ // force client icons reload
+ {
+ int i;
+
+ for (i = 0; i < cfg::nextCacheEntry; i++) {
+ if (cfg::eCache[i].hContact)
+ NotifyEventHooks(hExtraImageApplying, (WPARAM)cfg::eCache[i].hContact, 0);
+ }
+ }
+ //
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ SendMessage(g_hwndViewModeFrame, WM_USER + 100, 0, 0);
+}
+
+void CreateButtonBar(HWND hWnd)
+{
+ int i;
+ HICON hIcon;
+
+ for (i = 0; ; i++) {
+ if (top_buttons[i].szTooltip == NULL)
+ break;
+ if (top_buttons[i].hwnd)
+ continue;
+
+ if (top_buttons[i].id != IDC_TBGLOBALSTATUS && top_buttons[i].id != IDC_TBMENU)
+ continue;
+
+ top_buttons[i].hwnd = CreateWindowEx(0, _T("CLCButtonClass"), _T(""), BS_PUSHBUTTON | WS_CHILD | WS_TABSTOP, 0, 0, 20, 20, hWnd, (HMENU) top_buttons[i].id, g_hInst, NULL);
+
+ hIcon = top_buttons[i].hIcon = IcoLib_GetIcon(top_buttons[i].szIcoLibIcon);
+ if (top_buttons[i].szIcoLibAltIcon)
+ top_buttons[i].hAltIcon = IcoLib_GetIcon(top_buttons[i].szIcoLibAltIcon);
+
+ if (top_buttons[i].id == IDC_TBMENU) {
+ SetWindowText(top_buttons[i].hwnd, TranslateT("Menu"));
+ SendMessage(top_buttons[i].hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM) Skin_LoadIcon(SKINICON_OTHER_MIRANDA));
+ }
+ if (top_buttons[i].id == IDC_TBGLOBALSTATUS) {
+ SetWindowText(top_buttons[i].hwnd, TranslateT("Offline"));
+ SendMessage(top_buttons[i].hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM) Skin_LoadIcon(SKINICON_STATUS_OFFLINE));
+ }
+ SendMessage(top_buttons[i].hwnd, BUTTONADDTOOLTIP, (WPARAM) TranslateTS(top_buttons[i].szTooltip), 0);
+ }
+}
+
+/*
+ * to properly configure the CLUI window
+ *
+ * 1) applyBorderStyle()
+ * 2) configureGeometry()
+ */
+void CLUI::configureGeometry(int mode)
+{
+ RECT rcStatus;
+
+ Skin::metrics.cLeft = Skin::metrics.fHaveFrame ? (Skin::metrics.cLeftFramed + Skin::metrics.cLeftButtonset) :
+ (Skin::metrics.cLeftSkinned + Skin::metrics.cFakeLeftBorder + Skin::metrics.cLeftButtonset);
+
+ Skin::metrics.cRight = Skin::metrics.fHaveFrame ? (Skin::metrics.cRightFramed + Skin::metrics.cRightButtonset) :
+ (Skin::metrics.cRightSkinned + Skin::metrics.cFakeRightBorder + Skin::metrics.cRightButtonset);
+
+ Skin::metrics.cTop = Skin::metrics.fHaveFrame ? (Skin::metrics.cTopFramed + Skin::metrics.cTopButtonset) :
+ (Skin::metrics.cTopSkinned + Skin::metrics.cFakeCaption + Skin::metrics.cTopButtonset);
+
+ Skin::metrics.cBottom = Skin::metrics.fHaveFrame ? (Skin::metrics.cBottomFramed + Skin::metrics.cBottomButtonset) :
+ (Skin::metrics.cBottomSkinned + Skin::metrics.cFakeBtmBorder + Skin::metrics.cBottomButtonset);
+
+ if (mode) {
+ if (cfg::dat.dwFlags & CLUI_FRAME_SBARSHOW) {
+ SendMessage(pcli->hwndStatus, WM_SIZE, 0, 0);
+ GetWindowRect(pcli->hwndStatus, &rcStatus);
+ Skin::metrics.bSBarHeight = (rcStatus.bottom - rcStatus.top);
+ } else
+ Skin::metrics.bSBarHeight = 0;
+ }
+
+ Skin::metrics.dwTopOffset = Skin::metrics.cTop;
+ Skin::metrics.dwBottomOffset = (cfg::dat.dwFlags & CLUI_FRAME_SHOWBOTTOMBUTTONS ? 2 + Skin::metrics.cButtonHeight : 0) + Skin::metrics.cBottom;
+
+ if (cfg::dat.dwFlags & CLUI_FRAME_CLISTSUNKEN) {
+ Skin::metrics.dwTopOffset += 2;
+ Skin::metrics.dwBottomOffset += 2;
+ Skin::metrics.cLeft += 3;
+ Skin::metrics.cRight += 3;
+ }
+}
+
+/*
+ * set the states of defined database action buttons (only if button is a toggle)
+*/
+
+void CLUI::setFrameButtonStates(MCONTACT hPassedContact)
+{
+ TButtonItem *buttonItem = buttonItems;
+ MCONTACT hContact = 0, hFinalContact = 0;
+ char *szModule, *szSetting;
+ int sel = cfg::clcdat ? cfg::clcdat->selection : -1;
+ struct ClcContact *contact = 0;
+
+ if (sel != -1 && hPassedContact == 0) {
+ sel = pcli->pfnGetRowByIndex(cfg::clcdat, cfg::clcdat->selection, &contact, NULL);
+ if (contact && contact->type == CLCIT_CONTACT) {
+ hContact = contact->hContact;
+ }
+ }
+
+ while (buttonItem) {
+ BOOL result = FALSE;
+
+ if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) {
+ buttonItem = buttonItem->nextItem;
+ continue;
+ }
+ szModule = buttonItem->szModule;
+ szSetting = buttonItem->szSetting;
+ if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) {
+ if (hContact == 0) {
+ SendMessage(buttonItem->hWnd, BM_SETCHECK, BST_UNCHECKED, 0);
+ buttonItem = buttonItem->nextItem;
+ continue;
+ }
+ if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION)
+ szModule = GetContactProto(hContact);
+ hFinalContact = hContact;
+ } else
+ hFinalContact = 0;
+
+ if (buttonItem->type == DBVT_ASCIIZ) {
+ DBVARIANT dbv = {0};
+
+ if (!cfg::getString(hFinalContact, szModule, szSetting, &dbv)) {
+ result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal);
+ db_free(&dbv);
+ }
+ } else {
+ switch (buttonItem->type) {
+ case DBVT_BYTE: {
+ BYTE val = cfg::getByte(hFinalContact, szModule, szSetting, 0);
+ result = (val == buttonItem->bValuePush[0]);
+ break;
+ }
+ case DBVT_WORD: {
+ WORD val = cfg::getWord(hFinalContact, szModule, szSetting, 0);
+ result = (val == *((WORD *) & buttonItem->bValuePush));
+ break;
+ }
+ case DBVT_DWORD: {
+ DWORD val = cfg::getDword(hFinalContact, szModule, szSetting, 0);
+ result = (val == *((DWORD *) & buttonItem->bValuePush));
+ break;
+ }
+ }
+ }
+ SendMessage(buttonItem->hWnd, BM_SETCHECK, (WPARAM)result, 0);
+ buttonItem = buttonItem->nextItem;
+ }
+}
+
+/*
+ * set states of standard buttons (pressed/unpressed
+ */
+void CLUI::setButtonStates(HWND hwnd)
+{
+ BYTE iMode;
+ TButtonItem *buttonItem = buttonItems;
+
+ iMode = cfg::getByte("CList", "HideOffline", 0);
+ while (buttonItem) {
+ if (buttonItem->dwFlags & BUTTON_ISINTERNAL) {
+ switch (buttonItem->uId) {
+ case IDC_TBSOUND:
+ SendMessage(buttonItem->hWnd, BM_SETCHECK, cfg::dat.soundsOff ? BST_UNCHECKED : BST_CHECKED, 0);
+ break;
+ case IDC_TBHIDEOFFLINE:
+ SendMessage(buttonItem->hWnd, BM_SETCHECK, iMode ? BST_CHECKED : BST_UNCHECKED, 0);
+ break;
+ case IDC_TBHIDEGROUPS:
+ SendMessage(buttonItem->hWnd, BM_SETCHECK, cfg::getByte("CList", "UseGroups", 0) ? BST_CHECKED : BST_UNCHECKED, 0);
+ break;
+ }
+ }
+ buttonItem = buttonItem->nextItem;
+ }
+}
+
+
+void ReloadThemedOptions()
+{
+ cfg::dat.bUsePerProto = cfg::getByte("CLCExt", "useperproto", 0);
+ cfg::dat.bOverridePerStatusColors = cfg::getByte("CLCExt", "override_status", 0);
+ cfg::dat.bRowSpacing = cfg::getByte("CLC", "RowGap", 0);
+ cfg::dat.exIconScale = cfg::getByte("CLC", "ExIconScale", 16);
+ cfg::dat.bApplyIndentToBg = cfg::getByte("CLCExt", "applyindentbg", 0);
+ cfg::dat.gapBetweenFrames = (BYTE)cfg::getDword("CLUIFrames", "GapBetweenFrames", 1);
+ cfg::dat.bUseDCMirroring = cfg::getByte("CLC", "MirrorDC", 0);
+ cfg::dat.bGroupAlign = cfg::getByte("CLC", "GroupAlign", 0);
+ cfg::dat.bUseFloater = cfg::getByte("CLUI", "FloaterMode", 0);
+ cfg::dat.titleBarHeight = cfg::getByte("CLCExt", "frame_height", DEFAULT_TITLEBAR_HEIGHT);
+ cfg::dat.group_padding = cfg::getDword("CLCExt", "grp_padding", 0);
+}
+
+static RECT rcWindow = {0};
+
+static void sttProcessResize(HWND hwnd, NMCLISTCONTROL *nmc)
+{
+ RECT rcTree, rcWorkArea, rcOld;
+ int maxHeight, newHeight;
+ int winstyle, skinHeight = 0;
+
+ if (disableautoupd)
+ return;
+
+ if (!cfg::getByte("CLUI", "AutoSize", 0))
+ return;
+
+ if (Docking_IsDocked(0, 0))
+ return;
+ if (hFrameContactTree == 0)
+ return;
+
+ maxHeight = cfg::getByte("CLUI", "MaxSizeHeight", 75);
+ rcOld = rcWindow;
+
+ GetWindowRect(hwnd, &rcWindow);
+ GetWindowRect(pcli->hwndContactTree, &rcTree);
+ winstyle = GetWindowLong(pcli->hwndContactTree, GWL_STYLE);
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, FALSE);
+ if (nmc->pt.y > (rcWorkArea.bottom - rcWorkArea.top)) {
+ nmc->pt.y = (rcWorkArea.bottom - rcWorkArea.top);
+ }
+
+ if (winstyle & CLS_SKINNEDFRAME) {
+ BOOL hasTitleBar = wndFrameCLC ? wndFrameCLC->TitleBar.ShowTitleBar : 0;
+ TStatusItem *item = &Skin::statusItems[(hasTitleBar ? ID_EXTBKOWNEDFRAMEBORDERTB : ID_EXTBKOWNEDFRAMEBORDER)];
+ skinHeight = item->IGNORED ? 0 : item->MARGIN_BOTTOM + item->MARGIN_TOP;
+ }
+
+ newHeight = max(nmc->pt.y, 3) + 1 + ((winstyle & WS_BORDER) ? 2 : 0) + skinHeight + (rcWindow.bottom - rcWindow.top) - (rcTree.bottom - rcTree.top);
+ if (newHeight == (rcWindow.bottom - rcWindow.top))
+ return;
+
+ if (newHeight > (rcWorkArea.bottom - rcWorkArea.top)*maxHeight / 100)
+ newHeight = (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100;
+ if (cfg::getByte("CLUI", "AutoSizeUpward", 0)) {
+ rcWindow.top = rcWindow.bottom - newHeight;
+ if (rcWindow.top < rcWorkArea.top) rcWindow.top = rcWorkArea.top;
+ } else {
+ rcWindow.bottom = rcWindow.top + newHeight;
+ if (rcWindow.bottom > rcWorkArea.bottom) rcWindow.bottom = rcWorkArea.bottom;
+ }
+ if (cfg::dat.szOldCTreeSize.cx != rcTree.right - rcTree.left) {
+ cfg::dat.szOldCTreeSize.cx = rcTree.right - rcTree.left;
+ return;
+ }
+ KillTimer(hwnd, TIMERID_AUTOSIZE);
+ SetTimer(hwnd, TIMERID_AUTOSIZE, 50, 0);
+}
+
+BP_PAINTPARAMS bppp = {0, 0, 0, 0};
+
+static char* _sbItemNames[] = {
+ "@ScrollBackUpper",
+ "@ScrollBackLower",
+ "@ScrollThumb",
+ "@ScrollButton",
+ "@ScrollArrowUp",
+ "@ScrollArrowDn"
+};
+
+#define ID_SBARSKIN_BACK_UPR 0
+#define ID_SBARSKIN_BACK_LWR 1
+#define ID_SBARSKIN_THUMB 2
+#define ID_SBARSKIN_BUTTON 3
+#define ID_SBARSKIN_ARROWUP 4
+#define ID_SBARSKIN_ARROWDN 5
+
+/**
+ * draw the custom scroll bar
+ * TODO Scrollbar: improve this to allow selective skinning of hovered/selected/pressed
+ * elements.
+ * @param nmcsbcd custom control drawing structure
+ * @return
+ */
+int CustomDrawScrollBars(NMCSBCUSTOMDRAW *nmcsbcd)
+{
+ switch (nmcsbcd->hdr.code) {
+ case NM_COOLSB_CUSTOMDRAW: {
+ static HDC hdcScroll = 0;
+ //static HBITMAP hbmScroll, hbmScrollOld;
+ static LONG scrollLeft, scrollRight, scrollHeight, scrollYmin, scrollYmax;
+
+ switch (nmcsbcd->dwDrawStage) {
+ case CDDS_PREPAINT:
+ if (cfg::dat.bSkinnedScrollbar)
+ return CDRF_SKIPDEFAULT;
+ else
+ return CDRF_DODEFAULT;
+ case CDDS_POSTPAINT:
+ return 0;
+ case CDDS_ITEMPREPAINT: {
+ HDC hdc = nmcsbcd->hdc;
+ UINT uItemID = ID_SBARSKIN_BACK_UPR;
+ RECT rcWindow;
+ POINT pt;
+ DWORD dfcFlags;
+ GetWindowRect(pcli->hwndContactTree, &rcWindow);
+ pt.x = rcWindow.left;
+ pt.y = rcWindow.top;
+ ScreenToClient(pcli->hwndContactList, &pt);
+
+ bppp.cbSize = sizeof(BP_PAINTPARAMS);
+ HANDLE hbp = Api::pfnBeginBufferedPaint(hdc, &nmcsbcd->rect, BPBF_TOPDOWNDIB, &bppp, &hdcScroll);
+
+ //hdcScroll = hdc;
+ BitBlt(hdcScroll, nmcsbcd->rect.left, nmcsbcd->rect.top, nmcsbcd->rect.right - nmcsbcd->rect.left,
+ nmcsbcd->rect.bottom - nmcsbcd->rect.top, cfg::dat.hdcBg, pt.x + nmcsbcd->rect.left, pt.y + nmcsbcd->rect.top, SRCCOPY);
+
+ switch (nmcsbcd->uItem) {
+ case HTSCROLL_UP:
+ case HTSCROLL_DOWN:
+ uItemID = (nmcsbcd->uState == CDIS_DEFAULT || nmcsbcd->uState == CDIS_DISABLED) ? ID_SBARSKIN_BUTTON :
+ (nmcsbcd->uState == CDIS_HOT ? ID_SBARSKIN_BUTTON : ID_SBARSKIN_BUTTON);
+ break;
+ case HTSCROLL_PAGEGDOWN:
+ case HTSCROLL_PAGEGUP:
+ uItemID = nmcsbcd->uItem == HTSCROLL_PAGEGUP ? ID_SBARSKIN_BACK_UPR : ID_SBARSKIN_BACK_LWR;
+ break;
+ case HTSCROLL_THUMB:
+ uItemID = nmcsbcd->uState == CDIS_HOT ? ID_SBARSKIN_THUMB : ID_SBARSKIN_THUMB;
+ uItemID = nmcsbcd->uState == CDIS_SELECTED ? ID_SBARSKIN_THUMB : ID_SBARSKIN_THUMB;
+ break;
+ default:
+ break;
+ }
+
+ Skin::renderNamedImageItem(_sbItemNames[uItemID], &nmcsbcd->rect, hdcScroll);
+ dfcFlags = DFCS_FLAT | (nmcsbcd->uState == CDIS_DISABLED ? DFCS_INACTIVE :
+ (nmcsbcd->uState == CDIS_HOT ? DFCS_HOT :
+ (nmcsbcd->uState == CDIS_SELECTED ? DFCS_PUSHED : 0)));
+
+ if (nmcsbcd->uItem == HTSCROLL_UP)
+ uItemID = ID_SBARSKIN_ARROWUP;
+ if (nmcsbcd->uItem == HTSCROLL_DOWN)
+ uItemID = ID_SBARSKIN_ARROWDN;
+ Skin::renderNamedImageItem(_sbItemNames[uItemID], &nmcsbcd->rect, hdcScroll);
+ Api::pfnEndBufferedPaint(hbp, TRUE);
+ }
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static int ServiceParamsOK(TButtonItem *item, WPARAM *wParam, LPARAM *lParam, MCONTACT hContact)
+{
+ if (item->dwFlags & BUTTON_PASSHCONTACTW || item->dwFlags & BUTTON_PASSHCONTACTL || item->dwFlags & BUTTON_ISCONTACTDBACTION) {
+ if (hContact == 0)
+ return 0;
+ if (item->dwFlags & BUTTON_PASSHCONTACTW)
+ *wParam = (WPARAM)hContact;
+ else if (item->dwFlags & BUTTON_PASSHCONTACTL)
+ *lParam = (LPARAM)hContact;
+ return 1;
+ }
+ return 1; // doesn't need a paramter
+}
+void CLUI::Show(HWND hwnd)
+{
+ int state = old_cliststate;
+ int onTop = cfg::getByte("CList", "OnTop", SETTING_ONTOP_DEFAULT);
+
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, FALSE);
+ if (state == SETTING_STATE_NORMAL) {
+ ShowWindow(pcli->hwndContactList, SW_SHOWNORMAL);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ Redraw();
+ } else if (state == SETTING_STATE_MINIMIZED) {
+ cfg::dat.forceResize = TRUE;
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ } else if (state == SETTING_STATE_HIDDEN) {
+ cfg::dat.forceResize = TRUE;
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ }
+ SetWindowPos(pcli->hwndContactList, onTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
+ if (cfg::dat.autosize) {
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ SendMessage(pcli->hwndContactTree, WM_SIZE, 0, 0);
+ }
+ SFL_Create();
+ SFL_SetState(cfg::dat.bUseFloater & CLUI_FLOATER_AUTOHIDE ? (old_cliststate == SETTING_STATE_NORMAL ? 0 : 1) : 1);
+}
+
+#define M_CREATECLC (WM_USER+1)
+LRESULT CALLBACK CLUI::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_CREATE: {
+ int i;
+ wchar_t szSkinFile[MAX_PATH];
+ wchar_t* pszSkinToLoad = 0;
+ DBVARIANT dbv = {0};
+
+ SetMenu(hwnd, 0);
+ Skin::Unload();
+ if(0 == cfg::getTString(0, SKIN_DB_MODULE, "gCurrentSkin", &dbv)) {
+ mir_sntprintf(szSkinFile, MAX_PATH, L"%s%s", cfg::szProfileDir, dbv.ptszVal);
+ if(PathFileExistsW(szSkinFile))
+ pszSkinToLoad = szSkinFile;
+ db_free(&dbv);
+ }
+ SkinLoader *sLoader = new SkinLoader(pszSkinToLoad);
+
+ if(sLoader->isValid())
+ sLoader->Load();
+ else
+ WarningDlg::show(WarningDlg::WARN_SKIN_LOADER_ERROR, WarningDlg::CWF_UNTRANSLATED|MB_OK|MB_ICONERROR);
+ delete sLoader;
+
+ Skin::updateAeroState();
+ int flags = WS_CHILD | CCS_BOTTOM;
+ flags |= cfg::getByte("CLUI", "ShowSBar", 1) ? WS_VISIBLE : 0;
+ pcli->hwndStatus = CreateWindowExW(0, STATUSCLASSNAME, NULL, flags, 0, 0, 0, 0, hwnd, NULL, g_hInst, NULL);
+ //SendMessage(pcli->hwndStatus, SB_SETMINHEIGHT, 12, 0);
+ if (flags & WS_VISIBLE) {
+ ShowWindow(pcli->hwndStatus, SW_SHOW);
+ SendMessage(pcli->hwndStatus, WM_SIZE, 0, 0);
+ }
+ OldStatusBarProc = (WNDPROC)SetWindowLongPtr(pcli->hwndStatus, GWLP_WNDPROC, (LONG_PTR)NewStatusBarWndProc);
+ SetClassLong(pcli->hwndStatus, GCL_STYLE, GetClassLong(pcli->hwndStatus, GCL_STYLE) & ~(CS_VREDRAW | CS_HREDRAW));
+
+ g_oldSize.cx = g_oldSize.cy = 0;
+ old_cliststate = cfg::getByte("CList", "State", SETTING_STATE_NORMAL);
+ cfg::writeByte("CList", "State", SETTING_STATE_HIDDEN);
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_CLIPCHILDREN);
+ if (!cfg::dat.bFirstRun)
+ configureEventArea(hwnd);
+ CluiProtocolStatusChanged(0, 0);
+
+ for (i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ statusNames[i - ID_STATUS_OFFLINE] = pcli->pfnGetStatusModeDescription(i, 0);
+
+ SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | (WS_EX_LAYERED));
+
+#ifndef _USE_D2D
+ SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA);
+#endif
+ transparentFocus = 1;
+
+ TranslateMenu(GetMenu(hwnd));
+ PostMessage(hwnd, M_CREATECLC, 0, 0);
+ bf.BlendOp = AC_SRC_OVER;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+ bf.SourceConstantAlpha = 255;
+
+ ulwInfo.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
+ ulwInfo.pblend = &bf;
+ Skin::setAeroMargins();
+ return FALSE;
+ }
+ case WM_NCCREATE: {
+ LPCREATESTRUCT p = (LPCREATESTRUCT)lParam;
+ p->style &= ~(CS_HREDRAW | CS_VREDRAW);
+ pcli->hwndContactList = hwnd;
+ }
+ break;
+ case M_CREATECLC: {
+ CreateButtonBar(hwnd);
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, FALSE);
+ {
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ applyBorderStyle();
+ configureGeometry(0);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ SetWindowPos(pcli->hwndContactList, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOACTIVATE);
+ }
+
+ if (cfg::dat.soundsOff)
+ hSoundHook = HookEvent(ME_SKIN_PLAYINGSOUND, ClcSoundHook);
+ configureWindowLayout();
+ setButtonStates(hwnd);
+
+ createCLC(hwnd);
+ cfg::clcdat = (struct ClcData *)GetWindowLongPtr(pcli->hwndContactTree, 0);
+
+ cfg::writeByte("CList", "State", old_cliststate);
+
+ if (cfg::getByte("CList", "AutoApplyLastViewMode", 0)) {
+ DBVARIANT dbv = {0};
+ if (!db_get(NULL, "CList", "LastViewMode", &dbv)) {
+ if (lstrlenA(dbv.pszVal) > 2) {
+ if (cfg::getDword(NULL, CLVM_MODULE, dbv.pszVal, -1) != 0xffffffff)
+ ApplyViewMode((char *)dbv.pszVal);
+ }
+ db_free(&dbv);
+ }
+ }
+ Show(hwnd);
+ return 0;
+ }
+ case WM_ERASEBKGND:
+ return TRUE;
+
+ case WM_PAINT: {
+ PAINTSTRUCT ps;
+ RECT rc, rcFrame, rcClient;
+ HDC hdc;
+ HDC hdcReal = BeginPaint(hwnd, &ps);
+ TImageItem* activeItem = cfg::isAero ? bgImageItem : bgImageItem_nonAero;
+
+ GetClientRect(hwnd, &rcClient);
+ CopyRect(&rc, &rcClient);
+
+ if (!cfg::dat.hdcBg || rc.right != cfg::dat.dcSize.cx || rc.bottom + Skin::metrics.bSBarHeight != cfg::dat.dcSize.cy) {
+ cfg::dat.dcSize.cy = rc.bottom + Skin::metrics.bSBarHeight;
+ cfg::dat.dcSize.cx = rc.right;
+ if (cfg::dat.hdcBg) {
+ SelectObject(cfg::dat.hdcBg, cfg::dat.hbmBgOld);
+ DeleteObject(cfg::dat.hbmBg);
+ DeleteDC(cfg::dat.hdcBg);
+ }
+ cfg::dat.hdcBg = CreateCompatibleDC(hdcReal);
+ cfg::dat.hbmBg = Gfx::createRGBABitmap(cfg::dat.dcSize.cx, cfg::dat.dcSize.cy);
+ cfg::dat.hbmBgOld = reinterpret_cast<HBITMAP>(SelectObject(cfg::dat.hdcBg, cfg::dat.hbmBg));
+ }
+
+ if (cfg::shutDown) {
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ hdc = cfg::dat.hdcBg;
+
+ CopyRect(&rcFrame, &rcClient);
+
+ cfg::dat.ptW.x = cfg::dat.ptW.y = 0;
+ ClientToScreen(hwnd, &cfg::dat.ptW);
+
+ if(cfg::isAero)
+ FillRect(hdc, &rcClient, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
+ else if (g_CLUISkinnedBkColor)
+ FillRect(hdc, &rcClient, g_CLUISkinnedBkColor);
+ if(!Skin::metrics.fHaveFrame) {
+ if (activeItem) {
+ Gfx::renderImageItem(hdc, activeItem, &rcFrame);
+ goto skipbg;
+ }
+ }
+ else {
+ if(bgClientItem) {
+ Gfx::renderImageItem(hdc, bgClientItem, &rcFrame);
+ goto skipbg;
+ }
+ }
+
+ rcFrame.left += (Skin::metrics.cLeft - 1);
+ rcFrame.right -= (Skin::metrics.cRight - 1);
+ rcFrame.bottom++;
+ rcFrame.bottom -= Skin::metrics.bSBarHeight;
+ rcFrame.top += (Skin::metrics.dwTopOffset - 1);
+
+ if (cfg::dat.dwFlags & CLUI_FRAME_CLISTSUNKEN) {
+ InflateRect(&rcFrame, 1, 1);
+ if (cfg::dat.bSkinnedButtonMode)
+ rcFrame.bottom -= (Skin::metrics.dwBottomOffset);
+ DrawEdge(hdc, &rcFrame, BDR_SUNKENOUTER, BF_RECT);
+ }
+skipbg:
+#ifndef _USE_D2D
+ BitBlt(hdcReal, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdc, 0, 0, SRCCOPY);
+#endif
+ EndPaint(hwnd, &ps);
+ /*
+ if(renderTarget) {
+ renderTarget->BeginDraw();
+ ID2D1SolidColorBrush* brush;
+ D2D1_COLOR_F clr;
+ clr.b = clr.r = clr.g = 0.0;
+ clr.r = 25.0;
+ clr.a = 0.0;
+
+ D2D1_BRUSH_PROPERTIES bp;
+ bp.transform = D2D1::Matrix3x2F();
+ bp.opacity = 0.0;
+ D2D1_RECT_F rect;
+ rect.left = rect.top = 0;
+ rect.right = rcClient.right;
+ rect.bottom = rcClient.bottom;
+ renderTarget->CreateSolidColorBrush(clr, bp, &brush);
+ renderTarget->FillRectangle(&rect, brush);
+ renderTarget->EndDraw();
+ brush->Release();
+ }
+ */
+#ifdef _USE_D2D
+ //updateLayers();
+#endif
+ return 0;
+ }
+
+ case WM_NCPAINT:
+ if(Skin::metrics.fHaveFrame)
+ break;
+ return(0);
+
+ case WM_ENTERSIZEMOVE: {
+ RECT rc;
+ POINT pt = {0};
+
+ GetWindowRect(hwnd, &g_PreSizeRect);
+ GetClientRect(hwnd, &rc);
+ ClientToScreen(hwnd, &pt);
+ g_CLUI_x_off = pt.x - g_PreSizeRect.left;
+ g_CLUI_y_off = pt.y - g_PreSizeRect.top;
+ pt.x = rc.right;
+ ClientToScreen(hwnd, &pt);
+ g_CLUI_x1_off = g_PreSizeRect.right - pt.x;
+ pt.x = 0;
+ pt.y = rc.bottom;
+ ClientToScreen(hwnd, &pt);
+ g_CLUI_y1_off = g_PreSizeRect.bottom - pt.y;
+ break;
+ }
+ case WM_EXITSIZEMOVE:
+ PostMessage(hwnd, CLUIINTM_REDRAW, 0, 0);
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ return(0);
+
+ case WM_WINDOWPOSCHANGING: {
+ WINDOWPOS *wp = (WINDOWPOS *)lParam;
+
+ if (wp && wp->flags & SWP_NOSIZE)
+ return FALSE;
+
+ if (Docking_IsDocked(0, 0))
+ break;
+
+ if (pcli->hwndContactList != NULL) {
+
+ //dsize.width = rcOld.right - rcOld.left;
+ //dsize.height = rcOld.bottom - rcOld.top;
+
+ /*
+ if(0 == renderTarget) {
+ D2D1_RENDER_TARGET_PROPERTIES rp = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
+ D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), 0, 0, D2D1_RENDER_TARGET_USAGE_NONE,
+ D2D1_FEATURE_LEVEL_DEFAULT);
+
+ D2D1_HWND_RENDER_TARGET_PROPERTIES hp = D2D1::HwndRenderTargetProperties(hwnd, dsize, D2D1_PRESENT_OPTIONS_NONE);
+ Gfx::pD2DFactory->CreateHwndRenderTarget(&rp, &hp, &renderTarget);
+ if(0 == renderTarget)
+ MessageBox(0, L"Creating render target failed", L"foo", MB_OK);
+
+ }
+ else
+ renderTarget->Resize(&dsize);
+ */
+ fInSizing = true;
+
+ newRect.left = 0;
+ newRect.right = wp->cx - (g_CLUI_x_off + g_CLUI_x1_off);
+ newRect.top = 0;
+ newRect.bottom = wp->cy - g_CLUI_y_off - g_CLUI_y1_off;
+
+ if(!cfg::isAero)
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+ if (cfg::dat.dwFlags & CLUI_FRAME_SBARSHOW) {
+ RECT rcStatus;
+ SetWindowPos(pcli->hwndStatus, 0, 0, newRect.bottom - 20 - (Skin::metrics.fHaveFrame ? 0 : Skin::metrics.cFakeBtmBorder), newRect.right, 20, SWP_NOZORDER);
+ GetWindowRect(pcli->hwndStatus, &rcStatus);
+ Skin::metrics.bSBarHeight = (rcStatus.bottom - rcStatus.top);
+ } else
+ Skin::metrics.bSBarHeight = 0;
+
+ SizeFramesByWindowRect(&newRect);
+ dock_prevent_moving = 0;
+ layoutButtons(hwnd, &newRect);
+ if (wp->cx != g_oldSize.cx)
+ SendMessage(hwnd, CLUIINTM_STATUSBARUPDATE, 0, 0);
+ dock_prevent_moving = 1;
+ g_oldPos.x = wp->x;
+ g_oldPos.y = wp->y;
+ g_oldSize.cx = wp->cx;
+ g_oldSize.cy = wp->cy;
+ rcWPC = newRect;
+
+ fInSizing = false;
+ }
+ fInSizing = false;
+ return(0);
+ }
+
+ case WM_SIZE: {
+ RECT rc;
+
+ if ((wParam == 0 && lParam == 0) || Docking_IsDocked(0, 0)) {
+
+ if (IsZoomed(hwnd))
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+
+ if (pcli->hwndContactList != 0) {
+ SendMessage(hwnd, WM_ENTERSIZEMOVE, 0, 0);
+ GetWindowRect(hwnd, &rc);
+ WINDOWPOS wp = {0};
+ wp.cx = rc.right - rc.left;
+ wp.cy = rc.bottom - rc.top;
+ wp.x = rc.left;
+ wp.y = rc.top;
+ wp.flags = 0;
+ SendMessage(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&wp);
+ SendMessage(hwnd, WM_EXITSIZEMOVE, 0, 0);
+ }
+ }
+ }
+ case WM_MOVE:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!Docking_IsDocked(0, 0)) {
+ cluiPos.bottom = (DWORD)(rc.bottom - rc.top);
+ cluiPos.left = rc.left;
+ cluiPos.top = rc.top;
+ }
+ cluiPos.right = rc.right - rc.left;
+ if (cfg::dat.realTimeSaving) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ cfg::writeDword("CList", "Height", (DWORD)(rc.bottom - rc.top));
+ cfg::writeDword("CList", "x", (DWORD) rc.left);
+ cfg::writeDword("CList", "y", (DWORD) rc.top);
+ }
+ cfg::writeDword("CList", "Width", (DWORD)(rc.right - rc.left));
+ }
+ }
+ return TRUE;
+
+ case WM_SETFOCUS:
+ SetFocus(pcli->hwndContactTree);
+ return 0;
+
+ case CLUIINTM_REMOVEFROMTASKBAR: {
+ if (Skin::metrics.bWindowStyle == SETTING_WINDOWSTYLE_DEFAULT && cfg::getByte("CList", "AlwaysHideOnTB", 0))
+ removeFromTaskBar(hwnd);
+ return 0;
+ }
+ case WM_ACTIVATE:
+ if (fading_active) {
+ if (wParam != WA_INACTIVE && cfg::dat.isTransparent)
+ transparentFocus = 1;
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ if (wParam == WA_INACTIVE) {
+ if ((HWND) wParam != hwnd)
+ if (cfg::dat.isTransparent)
+ if (transparentFocus)
+ SetTimer(hwnd, TM_AUTOALPHA, 250, NULL);
+ } else {
+ if (cfg::dat.isTransparent) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), cfg::dat.alpha, LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ transparentFocus = 1;
+ }
+ SetWindowPos(pcli->hwndContactList, cfg::getByte("CList", "OnTop", SETTING_ONTOP_DEFAULT) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
+ }
+ PostMessage(hwnd, CLUIINTM_REMOVEFROMTASKBAR, 0, 0);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_SETCURSOR:
+ if (cfg::dat.isTransparent) {
+ if (!transparentFocus && GetForegroundWindow() != hwnd) {
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), cfg::dat.alpha, LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ transparentFocus = 1;
+ SetTimer(hwnd, TM_AUTOALPHA, 250, NULL);
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ case WM_NCHITTEST: {
+ LRESULT result;
+ RECT r;
+ POINT pt;
+
+ GetWindowRect(hwnd, &r);
+ GetCursorPos(&pt);
+ if (pt.y <= r.bottom && pt.y >= r.bottom - 6 && !cfg::getByte("CLUI", "AutoSize", 0)) {
+ if (pt.x > r.left + 10 && pt.x < r.right - 10)
+ return HTBOTTOM;
+ if (pt.x < r.left + 10)
+ return HTBOTTOMLEFT;
+ if (pt.x > r.right - 10)
+ return HTBOTTOMRIGHT;
+
+ } else if (pt.y >= r.top && pt.y <= r.top + 3 && !cfg::getByte("CLUI", "AutoSize", 0)) {
+ if (pt.x > r.left + 10 && pt.x < r.right - 10)
+ return HTTOP;
+ if (pt.x < r.left + 10)
+ return HTTOPLEFT;
+ if (pt.x > r.right - 10)
+ return HTTOPRIGHT;
+ } else if (pt.x >= r.left && pt.x <= r.left + 6)
+ return HTLEFT;
+ else if (pt.x >= r.right - 6 && pt.x <= r.right)
+ return HTRIGHT;
+
+ result = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT || result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT)
+ if (cfg::dat.autosize)
+ return HTCLIENT;
+ return result;
+ }
+
+ case WM_TIMER:
+ if ((int) wParam == TM_AUTOALPHA) {
+ int inwnd;
+
+ if (GetForegroundWindow() == hwnd) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ inwnd = 1;
+ } else {
+ POINT pt;
+ HWND hwndPt;
+ pt.x = (short) LOWORD(GetMessagePos());
+ pt.y = (short) HIWORD(GetMessagePos());
+ hwndPt = WindowFromPoint(pt);
+ inwnd = (hwndPt == hwnd || GetParent(hwndPt) == hwnd);
+ }
+ if (inwnd != transparentFocus) {
+ //change
+ transparentFocus = inwnd;
+ if (transparentFocus)
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), cfg::dat.alpha, LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ else
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), cfg::dat.autoalpha, LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ }
+ if (!transparentFocus)
+ KillTimer(hwnd, TM_AUTOALPHA);
+ } else if (wParam == TIMERID_AUTOSIZE) {
+ KillTimer(hwnd, wParam);
+ SetWindowPos(hwnd, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ if(cfg::isAero)
+ RedrawWindow(hwnd, 0, 0, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ else
+ PostMessage(hwnd, CLUIINTM_REDRAW, 0, 0);
+ }
+ return TRUE;
+ case WM_SHOWWINDOW: {
+ static int noRecurse = 0;
+ DWORD thisTick, startTick;
+ int sourceAlpha, destAlpha;
+
+ if (cfg::dat.forceResize && wParam != SW_HIDE) {
+ cfg::dat.forceResize = FALSE;
+ PostMessage(hwnd, WM_SIZE, 0, 0);
+ PostMessage(hwnd, CLUIINTM_REDRAW, 0, 0);
+ }
+ PostMessage(hwnd, CLUIINTM_REMOVEFROMTASKBAR, 0, 0);
+
+ if (g_floatoptions.enabled) {
+ if (wParam)
+ FLT_ShowHideAll(SW_HIDE);
+ else
+ FLT_ShowHideAll(SW_SHOWNOACTIVATE);
+ }
+
+ if (!cfg::dat.fadeinout)
+ SFL_SetState(-1);
+ if (lParam)
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ if (noRecurse)
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ if (!cfg::dat.fadeinout)
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ fading_active = 1;
+
+ if (wParam) {
+ sourceAlpha = 0;
+ destAlpha = cfg::dat.isTransparent ? cfg::dat.alpha : 255;
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? (COLORREF)cfg::dat.colorkey : RGB(0, 0, 0), (BYTE)sourceAlpha, LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ noRecurse = 1;
+ ShowWindow(hwnd, SW_SHOW);
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ noRecurse = 0;
+ } else {
+ sourceAlpha = cfg::dat.isTransparent ? (transparentFocus ? cfg::dat.alpha : cfg::dat.autoalpha) : 255;
+ destAlpha = 0;
+ }
+ for (startTick = GetTickCount(); ;) {
+ thisTick = GetTickCount();
+ if (thisTick >= startTick + 200) {
+ SFL_SetState(-1);
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), (BYTE)(destAlpha), LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ fading_active = 0;
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), (BYTE)(sourceAlpha + (destAlpha - sourceAlpha) * (int)(thisTick - startTick) / 200), LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ }
+ //setLayeredAttributes(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : RGB(0, 0, 0), (BYTE)(destAlpha), LWA_ALPHA | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0));
+ //return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ case WM_SYSCOMMAND:
+ if(SETTING_WINDOWSTYLE_DEFAULT == Skin::metrics.bWindowStyle && SC_RESTORE == wParam) {
+ CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ Redraw();
+ cfg::writeByte("CList", "State", SETTING_STATE_NORMAL);
+ break;
+ }
+
+ if (wParam == SC_MAXIMIZE)
+ return 0;
+ else if (wParam == SC_MINIMIZE) {
+ if(SETTING_WINDOWSTYLE_DEFAULT == Skin::metrics.bWindowStyle) {
+ cfg::writeByte("CList", "State", SETTING_STATE_MINIMIZED);
+ break;
+ }
+ pcli->pfnShowHide(0, 0);
+ return 0;
+ }
+ else if (wParam == SC_RESTORE) {
+ pcli->pfnShowHide(0, 0);
+ return(0);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_COMMAND: {
+ DWORD dwOldFlags = cfg::dat.dwFlags;
+ if (HIWORD(wParam) == BN_CLICKED && lParam != 0) {
+ if (LOWORD(wParam) == IDC_TBFIRSTUID - 1)
+ break;
+ else if (LOWORD(wParam) >= IDC_TBFIRSTUID) { // skinnable buttons handling
+ TButtonItem *item = buttonItems;
+ WPARAM wwParam = 0;
+ LPARAM llParam = 0;
+ MCONTACT hContact = 0;
+ ClcContact *contact = 0;
+ int sel = cfg::clcdat ? cfg::clcdat->selection : -1;
+ int serviceFailure = FALSE;
+
+ if (sel != -1) {
+ sel = pcli->pfnGetRowByIndex(cfg::clcdat, cfg::clcdat->selection, &contact, NULL);
+ if (contact && contact->type == CLCIT_CONTACT) {
+ hContact = contact->hContact;
+ }
+ }
+ while (item) {
+ if (item->uId == (DWORD)LOWORD(wParam)) {
+ int contactOK = ServiceParamsOK(item, &wwParam, &llParam, hContact);
+
+ if (item->dwFlags & BUTTON_ISSERVICE) {
+ if (ServiceExists(item->szService) && contactOK)
+ CallService(item->szService, wwParam, llParam);
+ else if (contactOK)
+ serviceFailure = TRUE;
+ } else if (item->dwFlags & BUTTON_ISPROTOSERVICE && cfg::clcdat) {
+ if (contactOK) {
+ char szFinalService[512];
+
+ mir_snprintf(szFinalService, 512, "%s/%s", GetContactProto(hContact), item->szService);
+ if (ServiceExists(szFinalService))
+ CallService(szFinalService, wwParam, llParam);
+ else
+ serviceFailure = TRUE;
+ }
+ } else if (item->dwFlags & BUTTON_ISDBACTION) {
+ BYTE *pValue;
+ char *szModule = item->szModule;
+ char *szSetting = item->szSetting;
+ MCONTACT finalhContact = 0;
+
+ if (item->dwFlags & BUTTON_ISCONTACTDBACTION || item->dwFlags & BUTTON_DBACTIONONCONTACT) {
+ contactOK = ServiceParamsOK(item, &wwParam, &llParam, hContact);
+ if (contactOK && item->dwFlags & BUTTON_ISCONTACTDBACTION)
+ szModule = GetContactProto(hContact);
+ finalhContact = hContact;
+ } else
+ contactOK = 1;
+
+ if (contactOK) {
+ BOOL fDelete = FALSE;
+
+ if (item->dwFlags & BUTTON_ISTOGGLE) {
+ BOOL fChecked = (SendMessage(item->hWnd, BM_GETCHECK, 0, 0) == BST_UNCHECKED);
+
+ pValue = fChecked ? item->bValueRelease : item->bValuePush;
+ if (fChecked && pValue[0] == 0)
+ fDelete = TRUE;
+ } else
+ pValue = item->bValuePush;
+
+ if (fDelete) {
+ //_DebugTraceA("delete value: %s, %s ON %d", szModule, szSetting, finalhContact);
+ db_unset(finalhContact, szModule, szSetting);
+ } else {
+ switch (item->type) {
+ case DBVT_BYTE:
+ cfg::writeByte(finalhContact, szModule, szSetting, pValue[0]);
+ break;
+ case DBVT_WORD:
+ cfg::writeWord(finalhContact, szModule, szSetting, *((WORD *)&pValue[0]));
+ //_DebugTraceA("set WORD value: %s, %s, %d ON %d", szModule, item->szSetting, *((WORD *)&pValue[0]), finalhContact);
+ break;
+ case DBVT_DWORD:
+ cfg::writeDword(finalhContact, szModule, szSetting, *((DWORD *)&pValue[0]));
+ break;
+ case DBVT_ASCIIZ:
+ cfg::writeString(finalhContact, szModule, szSetting, (char *)pValue);
+ break;
+ }
+ }
+ } else if (item->dwFlags & BUTTON_ISTOGGLE)
+ SendMessage(item->hWnd, BM_SETCHECK, 0, 0);
+ }
+ if (!contactOK)
+ MessageBox(0, _T("The requested action requires a valid contact selection. Please select a contact from the contact list and repeat"), _T("Parameter mismatch"), MB_OK);
+ if (serviceFailure) {
+ char szError[512];
+
+ mir_snprintf(szError, 512, "The service %s specified by the %s button definition was not found. You may need to install additional plugins", item->szService, item->szName);
+ MessageBoxA(0, szError, "Service failure", MB_OK);
+ }
+ break;
+ }
+ item = item->nextItem;
+ }
+ goto buttons_done;
+ }
+ switch (LOWORD(wParam)) {
+ case IDC_TBMENU:
+ case IDC_TBTOPMENU: {
+ RECT rc;
+ HMENU hMenu = Menu_GetMainMenu();
+
+ GetWindowRect(GetDlgItem(hwnd, LOWORD(wParam)), &rc);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, rc.left, LOWORD(wParam) == IDC_TBMENU ? rc.top : rc.bottom, 0, hwnd, NULL);
+ return 0;
+ }
+ case IDC_TBGLOBALSTATUS:
+ case IDC_TBTOPSTATUS: {
+ RECT rc;
+ HMENU hmenu = Menu_GetStatusMenu();
+ GetWindowRect(GetDlgItem(hwnd, LOWORD(wParam)), &rc);
+ TrackPopupMenu(hmenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, rc.left, rc.top, 0, hwnd, NULL);
+ return 0;
+ }
+ case IDC_TBSOUND: {
+ cfg::dat.soundsOff = !cfg::dat.soundsOff;
+ cfg::writeByte("CLUI", "NoSounds", (BYTE)cfg::dat.soundsOff);
+ cfg::writeByte("Skin", "UseSound", (BYTE)(cfg::dat.soundsOff ? 0 : 1));
+ return 0;
+ }
+ case IDC_TBSELECTVIEWMODE:
+ SendMessage(g_hwndViewModeFrame, WM_COMMAND, IDC_SELECTMODE, lParam);
+ break;
+ case IDC_TBCLEARVIEWMODE:
+ SendMessage(g_hwndViewModeFrame, WM_COMMAND, IDC_RESETMODES, lParam);
+ break;
+ case IDC_TBCONFIGUREVIEWMODE:
+ SendMessage(g_hwndViewModeFrame, WM_COMMAND, IDC_CONFIGUREMODES, lParam);
+ break;
+ case IDC_TBFINDANDADD:
+ CallService(MS_FINDADD_FINDADD, 0, 0);
+ return 0;
+ case IDC_TBACCOUNTS:
+ CallService(MS_PROTO_SHOWACCMGR, 0, 0);
+ break;
+ case IDC_TBOPTIONS:
+ CallService("Options/OptionsCommand", 0, 0);
+ return 0;
+ }
+ } else if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), (LPARAM)(HANDLE) NULL))
+ return 0;
+
+buttons_done:
+ switch (LOWORD(wParam)) {
+ case ID_TRAY_EXIT:
+ case ID_ICQ_EXIT:
+ cfg::shutDown = 1;
+ if (CallService(MS_SYSTEM_OKTOEXIT, 0, 0))
+ DestroyWindow(hwnd);
+ break;
+ case IDC_TBMINIMIZE:
+ case ID_TRAY_HIDE:
+ pcli->pfnShowHide(0, 0);
+ break;
+ case POPUP_NEWGROUP:
+ SendMessage(pcli->hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0);
+ CallService(MS_CLIST_GROUPCREATE, 0, 0);
+ break;
+ case POPUP_HIDEOFFLINE:
+ case IDC_TBHIDEOFFLINE:
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM)(-1), 0);
+ break;
+ case POPUP_HIDEOFFLINEROOT:
+ SendMessage(pcli->hwndContactTree, CLM_SETHIDEOFFLINEROOT, !SendMessage(pcli->hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), 0);
+ break;
+ case POPUP_HIDEEMPTYGROUPS: {
+ int newVal = !(GetWindowLong(pcli->hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS);
+ cfg::writeByte("CList", "HideEmptyGroups", (BYTE) newVal);
+ SendMessage(pcli->hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_DISABLEGROUPS:
+ case IDC_TBHIDEGROUPS: {
+ int newVal = !(GetWindowLong(pcli->hwndContactTree, GWL_STYLE) & CLS_USEGROUPS);
+ cfg::writeByte("CList", "UseGroups", (BYTE) newVal);
+ SendMessage(pcli->hwndContactTree, CLM_SETUSEGROUPS, newVal, 0);
+ CheckDlgButton(hwnd, IDC_TBHIDEGROUPS, newVal ? BST_CHECKED : BST_UNCHECKED);
+ break;
+ }
+ case POPUP_HIDEMIRANDA:
+ pcli->pfnShowHide(0, 0);
+ break;
+ case POPUP_VISIBILITY:
+ cfg::dat.dwFlags ^= CLUI_SHOWVISI;
+ break;
+ case POPUP_FRAME:
+ cfg::dat.dwFlags ^= CLUI_FRAME_CLISTSUNKEN;
+ break;
+ case POPUP_BUTTONS:
+ cfg::dat.dwFlags ^= CLUI_FRAME_SHOWBOTTOMBUTTONS;
+ break;
+ case POPUP_SHOWSTATUSICONS:
+ cfg::dat.dwFlags ^= CLUI_FRAME_STATUSICONS;
+ break;
+ case POPUP_FLOATER:
+ cfg::dat.bUseFloater ^= CLUI_USE_FLOATER;
+ if (cfg::dat.bUseFloater & CLUI_USE_FLOATER) {
+ SFL_Create();
+ SFL_SetState(-1);
+ } else
+ SFL_Destroy();
+ cfg::writeByte("CLUI", "FloaterMode", cfg::dat.bUseFloater);
+ break;
+ case POPUP_FLOATER_AUTOHIDE:
+ cfg::dat.bUseFloater ^= CLUI_FLOATER_AUTOHIDE;
+ SFL_SetState(cfg::dat.bUseFloater & CLUI_FLOATER_AUTOHIDE ? (cfg::getByte("CList", "State", SETTING_STATE_NORMAL) == SETTING_STATE_NORMAL ? 0 : 1) : 1);
+ cfg::writeByte("CLUI", "FloaterMode", cfg::dat.bUseFloater);
+ break;
+ case POPUP_FLOATER_EVENTS:
+ cfg::dat.bUseFloater ^= CLUI_FLOATER_EVENTS;
+ SFL_SetSize();
+ SFL_Update(0, 0, 0, NULL, FALSE);
+ cfg::writeByte("CLUI", "FloaterMode", cfg::dat.bUseFloater);
+ break;
+ }
+ if (dwOldFlags != cfg::dat.dwFlags) {
+ InvalidateRect(pcli->hwndContactTree, NULL, FALSE);
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+ if ((dwOldFlags & (CLUI_FRAME_SHOWBOTTOMBUTTONS | CLUI_FRAME_CLISTSUNKEN)) != (cfg::dat.dwFlags & (CLUI_FRAME_SHOWBOTTOMBUTTONS | CLUI_FRAME_CLISTSUNKEN))) {
+ configureWindowLayout();
+ configureGeometry(1);
+ }
+ configureEventArea(pcli->hwndContactList);
+ PostMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ PostMessage(pcli->hwndContactList, CLUIINTM_REDRAW, 0, 0);
+ }
+ return FALSE;
+ }
+ case WM_LBUTTONDOWN: {
+ if (buttonItems) {
+ POINT ptMouse, pt;
+ RECT rcClient;
+
+ GetCursorPos(&ptMouse);
+ pt = ptMouse;
+ if (buttonItems)
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ ScreenToClient(hwnd, &ptMouse);
+ GetClientRect(hwnd, &rcClient);
+ rcClient.bottom = Skin::metrics.dwTopOffset;
+ if (PtInRect(&rcClient, ptMouse))
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ }
+ case WM_DISPLAYCHANGE:
+ SendMessage(pcli->hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ break;
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->hwndFrom == pcli->hwndContactTree) {
+ switch (((LPNMHDR) lParam)->code) {
+ case CLN_LISTSIZECHANGE:
+ sttProcessResize(hwnd, (NMCLISTCONTROL*)lParam);
+ return FALSE;
+
+ case NM_CLICK: {
+ NMCLISTCONTROL *nm = (NMCLISTCONTROL *) lParam;
+ DWORD hitFlags;
+ HANDLE hItem;
+
+ hItem = (HANDLE)SendMessage(pcli->hwndContactTree, CLM_HITTEST, (WPARAM) & hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y));
+
+ if ((hitFlags & (CLCHT_NOWHERE | CLCHT_INLEFTMARGIN | CLCHT_BELOWITEMS)) == 0)
+ break;
+ if (cfg::getByte("CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT)) {
+ POINT pt;
+ pt = nm->pt;
+ ClientToScreen(pcli->hwndContactTree, &pt);
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ }
+ return FALSE;
+ }
+ }
+ break;
+ case WM_CONTEXTMENU: {
+ RECT rc;
+ POINT pt;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ // x/y might be -1 if it was generated by a kb click
+ GetWindowRect(pcli->hwndContactTree, &rc);
+ if (pt.x == -1 && pt.y == -1) {
+ // all this is done in screen-coords!
+ GetCursorPos(&pt);
+ // the mouse isnt near the window, so put it in the middle of the window
+ if (!PtInRect(&rc, pt)) {
+ pt.x = rc.left + (rc.right - rc.left) / 2;
+ pt.y = rc.top + (rc.bottom - rc.top) / 2;
+ }
+ }
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ hMenu = Menu_BuildGroupMenu();
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyTrayMenu(hMenu);
+ return 0;
+ }
+ GetWindowRect(pcli->hwndStatus, &rc);
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ if (cfg::getByte("CLUI", "SBarRightClk", 0))
+ hMenu = Menu_GetMainMenu();
+ else
+ hMenu = Menu_GetStatusMenu();
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ }
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ if (((LPMEASUREITEMSTRUCT) lParam)->itemData == MENU_MIRANDAMENU) {
+ ((LPMEASUREITEMSTRUCT) lParam)->itemWidth = CXSMICON * 4 / 3;
+ ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = 0;
+ return TRUE;
+ }
+ return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam);
+ case WM_DRAWITEM: {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+
+ if (hbmLockedPoint == 0) {
+ hdcLockedPoint = CreateCompatibleDC(dis->hDC);
+ hbmLockedPoint = CreateCompatibleBitmap(dis->hDC, 5, 5);
+ hbmOldLockedPoint = reinterpret_cast<HBITMAP>(SelectObject(hdcLockedPoint, hbmLockedPoint));
+ }
+ if (dis->hwndItem == pcli->hwndStatus) {
+ ProtocolData *pd = (ProtocolData *)dis->itemData;
+ int nParts = SendMessage(pcli->hwndStatus, SB_GETPARTS, 0, 0);
+ char *szProto;
+ int status, x;
+ SIZE textSize;
+ BYTE showOpts = cfg::getByte("CLUI", "SBarShow", 1);
+ if (IsBadCodePtr((FARPROC)pd))
+ return TRUE;
+ if (cfg::shutDown)
+ return TRUE;
+ szProto = pd->RealName;
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ x = dis->rcItem.left;
+
+ if (showOpts & 1) {
+ HICON hIcon;
+
+ if (status >= ID_STATUS_CONNECTING && status < ID_STATUS_OFFLINE) {
+ char szBuffer[128];
+ mir_snprintf(szBuffer, 128, "%s_conn", pd->RealName);
+ hIcon = IcoLib_GetIcon(szBuffer);
+ } else
+ hIcon = Skin_LoadProtoIcon(szProto, status);
+
+ if (!(showOpts & 6) && cfg::dat.bEqualSections)
+ x = (dis->rcItem.left + dis->rcItem.right - 16) >> 1;
+ if (pd->protopos == 0)
+ x += (cfg::dat.bEqualSections ? (Skin::metrics.cLeft / 2) : Skin::metrics.cLeft);
+ else if (pd->protopos == nParts - 1)
+ x -= (Skin::metrics.cRight / 2);
+ DrawIconEx(dis->hDC, x, 2, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+ IcoLib_ReleaseIcon(hIcon);
+
+ if (cfg::getByte("CLUI", "sbar_showlocked", 1)) {
+ if (cfg::getByte(szProto, "LockMainStatus", 0)) {
+ hIcon = Skin_LoadIcon(SKINICON_OTHER_STATUS_LOCKED);
+ if (hIcon != NULL) {
+ DrawIconEx(dis->hDC, x, 2, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+ IcoLib_ReleaseIcon(hIcon);
+ }
+ }
+ }
+ x += 18;
+ } else {
+ x += 2;
+ if (pd->protopos == 0)
+ x += (cfg::dat.bEqualSections ? (Skin::metrics.cLeft / 2) : Skin::metrics.cLeft);
+ else if (pd->protopos == nParts - 1)
+ x -= (Skin::metrics.cRight / 2);
+ }
+ dis->rcItem.bottom += (dis->rcItem.top + 16);
+ if (showOpts & 2) {
+ wchar_t szName[64];
+ PROTOACCOUNT* pa = Proto_GetAccount( szProto );
+ if ( pa ) {
+ lstrcpyn(szName, pa->tszAccountName, _countof(szName));
+ szName[_countof(szName) - 1] = 0;
+ }
+ else szName[0] = 0;
+
+ if (lstrlen(szName) < sizeof(szName) - 1)
+ lstrcat(szName, _T(" "));
+ GetTextExtentPoint32(dis->hDC, szName, lstrlen(szName), &textSize);
+ dis->rcItem.left += x;
+ Gfx::renderText(dis->hDC, (HANDLE)dis->CtlID, szName, &dis->rcItem, DT_VCENTER | DT_SINGLELINE, 0);
+ x += textSize.cx;
+ }
+ if (showOpts & 4) {
+ wchar_t *szStatus = pcli->pfnGetStatusModeDescription( status, 0 );
+ dis->rcItem.left += x;
+ Gfx::renderText(dis->hDC, (HANDLE)dis->CtlID, szStatus, &dis->rcItem, DT_VCENTER | DT_SINGLELINE, 0);
+ }
+ } else if (dis->CtlType == ODT_MENU) {
+ if (dis->itemData == MENU_MIRANDAMENU)
+ break;
+ return Menu_DrawItem(dis);
+ }
+ return 0;
+ }
+
+ case WM_CLOSE:
+ if(SETTING_WINDOWSTYLE_DEFAULT == Skin::metrics.bWindowStyle && !cfg::getByte("CList", "AlwaysHideOnTB", 0)) {
+ PostMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ return(0);
+ }
+ pcli->pfnShowHide(0, 0);
+ return(0);
+
+ case CLUIINTM_REDRAW:
+ Redraw();
+ return 0;
+ case CLUIINTM_STATUSBARUPDATE:
+ CluiProtocolStatusChanged(0, 0);
+ return 0;
+
+ case WM_THEMECHANGED:
+ Api::updateState();
+ break;
+
+ case WM_NCDESTROY:
+#if _USE_D2D
+ if(renderTarget) {
+ renderTarget->Release();
+ renderTarget = 0;
+ }
+#endif
+ break;
+
+ case WM_DESTROY:
+ if (cfg::dat.hdcBg) {
+ SelectObject(cfg::dat.hdcBg, cfg::dat.hbmBgOld);
+ DeleteObject(cfg::dat.hbmBg);
+ DeleteDC(cfg::dat.hdcBg);
+ cfg::dat.hdcBg = NULL;
+ }
+ FreeProtocolData();
+ if (hdcLockedPoint) {
+ SelectObject(hdcLockedPoint, hbmOldLockedPoint);
+ DeleteObject(hbmLockedPoint);
+ DeleteDC(hdcLockedPoint);
+ }
+ /*
+ * if this has not yet been set, do it now.
+ * indicates that clist is shutting down and prevents various things
+ * from happening at shutdown.
+ */
+ if (!cfg::shutDown)
+ cfg::shutDown = 1;
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME, (WPARAM)hFrameContactTree, (LPARAM)0);
+ break;
+ }
+ return saveContactListWndProc(hwnd, msg, wParam, lParam);
+}
+
+static int MetaChanged(WPARAM wParam, LPARAM lParam)
+{
+ pcli->pfnClcBroadcast(INTM_METACHANGEDEVENT, wParam, lParam);
+ return 0;
+}
+
+static BOOL g_AboutDlgActive = 0;
+
+INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HICON hIcon;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ int h;
+ HFONT hFont;
+ LOGFONT lf;
+
+ g_AboutDlgActive = TRUE;
+ hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_CLNICER, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ h = lf.lfHeight;
+ lf.lfHeight = (int)(lf.lfHeight * 1.5);
+ lf.lfWeight = FW_BOLD;
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_CLNICER, WM_SETFONT, (WPARAM)hFont, 0);
+ lf.lfHeight = h;
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_VERSION, WM_SETFONT, (WPARAM)hFont, 0);
+ }
+ {
+ char str[64];
+ DWORD v = pluginInfo.version;
+ mir_snprintf(str, sizeof(str), "%s %d.%d.%d.%d (Unicode)", Translate("Version"), HIBYTE(HIWORD(v)), LOBYTE(HIWORD(v)), HIBYTE(LOWORD(v)), LOBYTE(LOWORD(v)));
+ SetDlgItemTextA(hwndDlg, IDC_VERSION, str);
+ mir_snprintf(str, sizeof(str), Translate("Built %s %s"), __DATE__, __TIME__);
+ SetDlgItemTextA(hwndDlg, IDC_BUILDTIME, str);
+ }
+ hIcon = LoadIcon(GetModuleHandleA("miranda32.exe"), MAKEINTRESOURCE(102));
+ SendDlgItemMessage(hwndDlg, IDC_LOGO, STM_SETICON, (WPARAM)hIcon, 0);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
+ DestroyIcon(hIcon);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_SUPPORT:
+ //CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda-im.org/download/details.php?action=viewfile&id=2365");
+ break;
+ }
+ break;
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_WHITERECT)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_CLNICER)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_VERSION)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_BUILDTIME)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_COPYRIGHT)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_SUPPORT)
+ || (HWND)lParam == GetDlgItem(hwndDlg, IDC_LOGO)) {
+ if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_CLNICER))
+ SetTextColor((HDC)wParam, RGB(180, 10, 10));
+ else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_VERSION))
+ SetTextColor((HDC)wParam, RGB(70, 70, 70));
+ else
+ SetTextColor((HDC)wParam, RGB(0, 0, 0));
+ SetBkColor((HDC)wParam, RGB(255, 255, 255));
+ return (INT_PTR)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ case WM_DESTROY: {
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_CLNICER, WM_GETFONT, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CLNICER, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0), 0);
+ DeleteObject(hFont);
+ hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_VERSION, WM_GETFONT, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_VERSION, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0), 0);
+ DeleteObject(hFont);
+ g_AboutDlgActive = FALSE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CLN_ShowAbout(WPARAM wParam, LPARAM lParam)
+{
+ if (!g_AboutDlgActive)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CLNABOUT), 0, DlgProcAbout, 0);
+ return 0;
+}
+
+static INT_PTR CLN_ShowMainMenu(WPARAM wParam, LPARAM lParam)
+{
+ HMENU hMenu;
+ POINT pt;
+
+ hMenu = Menu_GetMainMenu();
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, pcli->hwndContactList, NULL);
+ return 0;
+}
+
+static INT_PTR CLN_ShowStatusMenu(WPARAM wParam, LPARAM lParam)
+{
+ HMENU hMenu;
+ POINT pt;
+
+ hMenu = Menu_GetStatusMenu();
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, pcli->hwndContactList, NULL);
+ return 0;
+}
+
+#define MS_CLUI_SHOWMAINMENU "CList/ShowMainMenu"
+#define MS_CLUI_SHOWSTATUSMENU "CList/ShowStatusMenu"
+
+void CLUI::loadModule(void)
+{
+ WNDCLASSW wndclass;
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, CLUI::modulesLoaded);
+ HookEvent(ME_MC_DEFAULTTCHANGED, MetaChanged);
+ HookEvent(ME_MC_SUBCONTACTSCHANGED, MetaChanged);
+
+// InitGroupMenus();
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = eventAreaWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = g_hInst;
+ wndclass.hIcon = 0;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE);
+ wndclass.lpszMenuName = 0;
+ wndclass.lpszClassName = L"EventAreaClass";
+ RegisterClassW(&wndclass);
+
+ oldhideoffline = cfg::getByte("CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ cluiPos.left = cfg::getDword("CList", "x", 600);
+ cluiPos.top = cfg::getDword("CList", "y", 200);
+ cluiPos.right = cfg::getDword("CList", "Width", 150);
+ cluiPos.bottom = cfg::getDword("CList", "Height", 350);
+
+ loadExtraIconModule();
+ SFL_RegisterWindowClass();
+
+ preCreateCLC(pcli->hwndContactList);
+ //cfg::FrameMgr = new CLUIFrames();
+ CreateServiceFunction("CLN/About", CLN_ShowAbout);
+ CreateServiceFunction(MS_CLUI_SHOWMAINMENU, CLN_ShowMainMenu);
+ CreateServiceFunction(MS_CLUI_SHOWSTATUSMENU, CLN_ShowStatusMenu);
+}
+
+
+
+void CLUI::removeFromTaskBar(HWND hWnd)
+{
+ ITaskbarList *pTaskbarList = NULL;
+
+ if (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER, IID_ITaskbarList,
+ (void **)(&pTaskbarList))) && pTaskbarList != NULL) {
+ if (SUCCEEDED(pTaskbarList->HrInit())) {
+ pTaskbarList->DeleteTab(hWnd);
+ }
+ pTaskbarList->Release();
+ }
+}
+
+void CLUI::addToTaskBar(HWND hWnd)
+{
+ ITaskbarList *pTaskbarList = NULL;
+
+ if (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER, IID_ITaskbarList,
+ (void **)(&pTaskbarList))) && pTaskbarList != NULL) {
+ if (SUCCEEDED(pTaskbarList->HrInit())) {
+ pTaskbarList->AddTab(hWnd);
+ }
+ pTaskbarList->Release();
+ }
+}
+
+void CLUI::updateLayers()
+{
+ SIZE sz;
+ RECT rcWin;
+ POINT ptSrc = {0}, ptDest;
+ GetWindowRect(pcli->hwndContactList, &rcWin);
+ sz.cx = rcWin.right - rcWin.left;
+ sz.cy = rcWin.bottom - rcWin.top;
+ ptDest.x = rcWin.left;
+ ptDest.y = rcWin.top;
+ ulwInfo.dwFlags = ULW_ALPHA;
+ ulwInfo.prcDirty = 0;
+ ulwInfo.hdcSrc = cfg::dat.hdcBg;
+ ulwInfo.pptDst = &ptDest;
+ ulwInfo.pptSrc = &ptSrc;
+ ulwInfo.psize = &sz;
+ Gfx::setBitmapAlpha(cfg::dat.hbmBg, 255);
+ UpdateLayeredWindowIndirect(pcli->hwndContactList, &ulwInfo);
+}
+
+void CLUI::setLayeredAttributes(COLORREF clr, BYTE alpha, DWORD flags)
+{
+ if(cfg::isAero)
+ flags &= LWA_ALPHA;
+
+ SetLayeredWindowAttributes(pcli->hwndContactList, clr, alpha, flags);
+}
diff --git a/plugins/Clist_ng/SRC/cluiopts.cpp b/plugins/Clist_ng/SRC/cluiopts.cpp new file mode 100644 index 0000000000..72d0a78ab3 --- /dev/null +++ b/plugins/Clist_ng/SRC/cluiopts.cpp @@ -0,0 +1,370 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: cluiopts.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+extern WNDPROC OldStatusBarProc;
+extern HANDLE hExtraImageApplying;
+extern SIZE g_oldSize;
+extern POINT g_oldPos;
+extern COLORREF g_CLUISkinnedBkColorRGB;
+
+static int opt_clui_changed = 0;
+
+INT_PTR CALLBACK cfg::DlgProcCluiOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ opt_clui_changed = 0;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_BRINGTOFRONT, cfg::getByte("CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYSHIDEONTASKBAR, cfg::getByte("CList", "AlwaysHideOnTB", 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ONTOP, cfg::getByte("CList", "OnTop", SETTING_ONTOP_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CLIENTDRAG, cfg::getByte("CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FADEINOUT, cfg::dat.fadeinout ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOSIZE, cfg::dat.autosize);
+ CheckDlgButton(hwndDlg, IDC_ONDESKTOP, cfg::getByte("CList", "OnDesktop", 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_MAXSIZESPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
+ SendDlgItemMessage(hwndDlg, IDC_MAXSIZESPIN, UDM_SETPOS, 0, cfg::getByte("CLUI", "MaxSizeHeight", 75));
+
+ SendDlgItemMessage(hwndDlg, IDC_CLUIFRAMESBDR, CPM_SETCOLOUR, 0, cfg::getDword("CLUI", "clr_frameborder", RGB(40, 40, 40)));
+
+ CheckDlgButton(hwndDlg, IDC_AUTOSIZEUPWARD, cfg::getByte("CLUI", "AutoSizeUpward", 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOHIDE, cfg::getByte("CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETRANGE, 0, MAKELONG(900, 1));
+ SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_SETPOS, 0, MAKELONG(cfg::getWord("CList", "HideTime", SETTING_HIDETIME_DEFAULT), 0));
+ Utils::enableDlgControl(hwndDlg, IDC_HIDETIME, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ Utils::enableDlgControl(hwndDlg, IDC_HIDETIMESPIN, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC01, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE)) {
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC21, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC22, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_MAXSIZEHEIGHT, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_MAXSIZESPIN, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_AUTOSIZEUPWARD, FALSE);
+ }
+ CheckDlgButton(hwndDlg, IDC_TRANSPARENT, cfg::dat.isTransparent ? BST_CHECKED : BST_UNCHECKED);
+ if (!IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT)) {
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC11, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC12, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSACTIVE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSINACTIVE, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_ACTIVEPERC, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_INACTIVEPERC, FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_SETPOS, TRUE, cfg::dat.alpha);
+ SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_SETPOS, TRUE, cfg::dat.autoalpha);
+ SendMessage(hwndDlg, WM_HSCROLL, 0x12345678, 0);
+
+ CheckDlgButton(hwndDlg, IDC_USEAERO, Skin::settings.fUseAero ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_FRAMEGAPSPIN, UDM_SETRANGE, 0, MAKELONG(10, 0));
+ SendDlgItemMessage(hwndDlg, IDC_FRAMEGAPSPIN, UDM_SETPOS, 0, (LPARAM)cfg::dat.gapBetweenFrames);
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_AUTOHIDE) {
+ Utils::enableDlgControl(hwndDlg, IDC_HIDETIME, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ Utils::enableDlgControl(hwndDlg, IDC_HIDETIMESPIN, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC01, IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ } else if (LOWORD(wParam) == IDC_TRANSPARENT) {
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC11, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC12, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSACTIVE, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ Utils::enableDlgControl(hwndDlg, IDC_TRANSINACTIVE, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ Utils::enableDlgControl(hwndDlg, IDC_ACTIVEPERC, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ Utils::enableDlgControl(hwndDlg, IDC_INACTIVEPERC, IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ } else if (LOWORD(wParam) == IDC_AUTOSIZE) {
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC21, IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ Utils::enableDlgControl(hwndDlg, IDC_STATIC22, IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ Utils::enableDlgControl(hwndDlg, IDC_MAXSIZEHEIGHT, IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ Utils::enableDlgControl(hwndDlg, IDC_MAXSIZESPIN, IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ Utils::enableDlgControl(hwndDlg, IDC_AUTOSIZEUPWARD, IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+ }
+ if ((LOWORD(wParam) == IDC_FRAMEGAP || LOWORD(wParam) == IDC_HIDETIME || LOWORD(wParam) == IDC_ROWGAP ||
+ LOWORD(wParam) == IDC_MAXSIZEHEIGHT) && (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()))
+ return 0;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ opt_clui_changed = 1;
+ break;
+
+ case WM_HSCROLL:
+ {
+ char str[10];
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_INACTIVEPERC, str);
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_ACTIVEPERC, str);
+ }
+ if (wParam != 0x12345678) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ opt_clui_changed = 1;
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ BOOL translated;
+ BYTE oldFading;
+ COLORREF clr_cluiframes;
+
+ if(!opt_clui_changed)
+ return TRUE;
+
+ cfg::writeByte("CLUI", "FadeInOut", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_FADEINOUT));
+ cfg::dat.fadeinout = IsDlgButtonChecked(hwndDlg, IDC_FADEINOUT) ? 1 : 0;
+ oldFading = cfg::dat.fadeinout;
+ cfg::dat.fadeinout = FALSE;
+
+ cfg::dat.gapBetweenFrames = GetDlgItemInt(hwndDlg, IDC_FRAMEGAP, &translated, FALSE);
+
+ cfg::writeDword("CLUIFrames", "GapBetweenFrames", cfg::dat.gapBetweenFrames);
+ cfg::writeByte("CList", "OnTop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONTOP));
+ SetWindowPos(pcli->hwndContactList, IsDlgButtonChecked(hwndDlg, IDC_ONTOP) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+
+ cfg::writeByte("CList", "BringToFront", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_BRINGTOFRONT));
+ cfg::writeByte("CList", "AlwaysHideOnTB", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ALWAYSHIDEONTASKBAR));
+
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+
+ cfg::writeByte("CLUI", "ClientAreaDrag", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_CLIENTDRAG));
+
+ clr_cluiframes = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_CLUIFRAMESBDR, CPM_GETCOLOUR, 0, 0);
+
+ if(CLUI::hPenFrames)
+ DeleteObject(CLUI::hPenFrames);
+ CLUI::hPenFrames = CreatePen(PS_SOLID, 1, clr_cluiframes);
+ cfg::writeDword("CLUI", "clr_frameborder", clr_cluiframes);
+
+ CLUI::applyBorderStyle();
+
+ cfg::writeByte("CLUI", "AutoSize", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE));
+
+ if((cfg::dat.autosize = IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZE) ? 1 : 0)) {
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ SendMessage(pcli->hwndContactTree, WM_SIZE, 0, 0);
+ }
+
+ cfg::writeByte("CLUI", "MaxSizeHeight", (BYTE) GetDlgItemInt(hwndDlg, IDC_MAXSIZEHEIGHT, NULL, FALSE));
+ cfg::writeByte("CLUI", "AutoSizeUpward", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOSIZEUPWARD));
+ cfg::writeByte("CList", "AutoHide", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_AUTOHIDE));
+ cfg::writeWord("CList", "HideTime", (WORD) SendDlgItemMessage(hwndDlg, IDC_HIDETIMESPIN, UDM_GETPOS, 0, 0));
+
+ cfg::writeByte("CList", "Transparent", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT));
+ cfg::dat.isTransparent = IsDlgButtonChecked(hwndDlg, IDC_TRANSPARENT) ? 1 : 0;
+ cfg::writeByte("CList", "Alpha", (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_GETPOS, 0, 0));
+ cfg::dat.alpha = (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSACTIVE, TBM_GETPOS, 0, 0);
+ cfg::writeByte("CList", "AutoAlpha", (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_GETPOS, 0, 0));
+ cfg::dat.autoalpha = (BYTE) SendDlgItemMessage(hwndDlg, IDC_TRANSINACTIVE, TBM_GETPOS, 0, 0);
+ cfg::writeByte("CList", "OnDesktop", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ONDESKTOP));
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+
+ cfg::writeByte(SKIN_DB_MODULE, "sfUseAero", IsDlgButtonChecked(hwndDlg, IDC_USEAERO));
+ if(g_CLUISkinnedBkColorRGB)
+ cfg::dat.colorkey = g_CLUISkinnedBkColorRGB;
+ else {
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ cfg::dat.colorkey = RGB(255, 0, 255);
+ }
+
+ Api::updateState();
+ if(!cfg::isAero) {
+ if (cfg::dat.isTransparent || Skin::metrics.fHaveColorkey) {
+ SetLayeredWindowAttributes(pcli->hwndContactList, 0, 255, LWA_ALPHA | LWA_COLORKEY);
+ SetLayeredWindowAttributes(pcli->hwndContactList,
+ (COLORREF)(Skin::metrics.fHaveColorkey ? cfg::dat.colorkey : 0),
+ (BYTE)(cfg::dat.isTransparent ? cfg::dat.autoalpha : 255),
+ (DWORD)((cfg::dat.isTransparent ? LWA_ALPHA : 0L) | (Skin::metrics.fHaveColorkey ? LWA_COLORKEY : 0L)));
+ } else
+ SetLayeredWindowAttributes(pcli->hwndContactList, RGB(0, 0, 0), (BYTE)255, LWA_ALPHA);
+ }
+ CLUI::configureGeometry(1);
+ ShowWindow(pcli->hwndContactList, SW_SHOW);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ SetWindowPos(pcli->hwndContactList, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ RedrawWindow(pcli->hwndContactList, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
+ cfg::dat.fadeinout = oldFading;
+ SFL_SetState(cfg::dat.bUseFloater & CLUI_FLOATER_AUTOHIDE ? (cfg::getByte("CList", "State", SETTING_STATE_NORMAL) == SETTING_STATE_NORMAL ? 0 : 1) : 1);
+ opt_clui_changed = 0;
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int opt_sbar_changed = 0;
+
+INT_PTR CALLBACK cfg::DlgProcSBarOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ opt_sbar_changed = 0;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_SHOWSBAR, cfg::getByte("CLUI", "ShowSBar", 1) ? BST_CHECKED : BST_UNCHECKED); {
+ BYTE showOpts = cfg::getByte("CLUI", "SBarShow", 1);
+ CheckDlgButton(hwndDlg, IDC_SHOWICON, showOpts & 1 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWPROTO, showOpts & 2 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWSTATUS, showOpts & 4 ? BST_CHECKED : BST_UNCHECKED);
+ }
+ CheckDlgButton(hwndDlg, IDC_RIGHTSTATUS, cfg::getByte("CLUI", "SBarRightClk", 0) ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_RIGHTMIRANDA, !IsDlgButtonChecked(hwndDlg, IDC_RIGHTSTATUS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_EQUALSECTIONS, cfg::dat.bEqualSections ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_MARKLOCKED, cfg::getByte("CLUI", "sbar_showlocked", 1));
+
+ if (!IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR)) {
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWICON, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWPROTO, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWSTATUS, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_RIGHTSTATUS, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_RIGHTMIRANDA, FALSE);
+ Utils::enableDlgControl(hwndDlg, IDC_EQUALSECTIONS, FALSE);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_SHOWSBAR) {
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWICON, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWPROTO, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ Utils::enableDlgControl(hwndDlg, IDC_SHOWSTATUS, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ Utils::enableDlgControl(hwndDlg, IDC_RIGHTSTATUS, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ Utils::enableDlgControl(hwndDlg, IDC_RIGHTMIRANDA, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ Utils::enableDlgControl(hwndDlg, IDC_EQUALSECTIONS, IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ opt_sbar_changed = 1;
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ if(!opt_sbar_changed)
+ return TRUE;
+
+ cfg::writeByte("CLUI", "ShowSBar", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR));
+ cfg::writeByte("CLUI", "SBarShow", (BYTE) ((IsDlgButtonChecked(hwndDlg, IDC_SHOWICON) ? 1 : 0) | (IsDlgButtonChecked(hwndDlg, IDC_SHOWPROTO) ? 2 : 0) | (IsDlgButtonChecked(hwndDlg, IDC_SHOWSTATUS) ? 4 : 0)));
+ cfg::writeByte("CLUI", "SBarRightClk", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_RIGHTMIRANDA));
+ cfg::writeByte("CLUI", "EqualSections", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_EQUALSECTIONS));
+ cfg::writeByte("CLUI", "sbar_showlocked", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_MARKLOCKED));
+
+ cfg::dat.bEqualSections = IsDlgButtonChecked(hwndDlg, IDC_EQUALSECTIONS) ? 1 : 0;
+ if (IsDlgButtonChecked(hwndDlg, IDC_SHOWSBAR)) {
+ ShowWindow(pcli->hwndStatus, SW_SHOW);
+ SendMessage(pcli->hwndStatus, WM_SIZE, 0, 0);
+ cfg::dat.dwFlags |= CLUI_FRAME_SBARSHOW;
+ } else {
+ ShowWindow(pcli->hwndStatus, SW_HIDE);
+ cfg::dat.dwFlags &= ~CLUI_FRAME_SBARSHOW;
+ }
+ cfg::writeDword("CLUI", "Frameflags", cfg::dat.dwFlags);
+ CLUI::configureGeometry(1);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ CluiProtocolStatusChanged(0, 0);
+ PostMessage(pcli->hwndContactList, CLUIINTM_REDRAW, 0, 0);
+ opt_sbar_changed = 0;
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+DWORD CLUI::getWindowStyle(BYTE style)
+{
+ DWORD dwBasic = WS_CLIPCHILDREN;
+
+ if(style == SETTING_WINDOWSTYLE_THINBORDER)
+ return dwBasic | WS_BORDER;
+ else if(style == SETTING_WINDOWSTYLE_TOOLWINDOW || style == 0)
+ return dwBasic | (WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_THICKFRAME);
+ else if(style == SETTING_WINDOWSTYLE_NOBORDER)
+ return dwBasic;
+
+ return dwBasic;
+}
+
+void CLUI::applyBorderStyle()
+{
+ BYTE windowStyle = Skin::metrics.bWindowStyle;
+ WINDOWPLACEMENT p = {0};
+ DWORD style;
+ bool minToTray = TRUE;
+
+ p.length = sizeof(p);
+ GetWindowPlacement(pcli->hwndContactList, &p);
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+
+ Skin::metrics.fHaveFrame = true;
+
+ if (windowStyle == SETTING_WINDOWSTYLE_DEFAULT || windowStyle == SETTING_WINDOWSTYLE_TOOLWINDOW) {
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_THICKFRAME);
+ if(SETTING_WINDOWSTYLE_DEFAULT == windowStyle) {
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) & ~(WS_MAXIMIZEBOX/* | WS_MINIMIZEBOX*/));
+ minToTray = FALSE;
+ }
+ } else if(windowStyle == SETTING_WINDOWSTYLE_THINBORDER) {
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_THICKFRAME));
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) | WS_BORDER | WS_CLIPCHILDREN);
+ }
+ else {
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_THICKFRAME));
+ SetWindowLong(pcli->hwndContactList, GWL_STYLE, GetWindowLong(pcli->hwndContactList, GWL_STYLE) | WS_CLIPCHILDREN);
+ Skin::metrics.fHaveFrame = false;
+ }
+
+ style = GetWindowLong(pcli->hwndContactList, GWL_EXSTYLE);
+ if (windowStyle != SETTING_WINDOWSTYLE_DEFAULT)
+ {
+ style |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+ style &= ~WS_EX_APPWINDOW;
+ }
+ else
+ {
+ style &= ~(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE);
+ if (cfg::getByte("CList", "AlwaysHideOnTB", 1))
+ style &= ~WS_EX_APPWINDOW;
+ else
+ style |= WS_EX_APPWINDOW;
+ }
+
+ SetWindowLong(pcli->hwndContactList, GWL_EXSTYLE, style);
+ p.showCmd = SW_HIDE;
+ SetWindowPlacement(pcli->hwndContactList, &p);
+
+ cfg::writeByte(0, "CList", "Min2Tray", minToTray);
+}
diff --git a/plugins/Clist_ng/SRC/cluiservices.cpp b/plugins/Clist_ng/SRC/cluiservices.cpp new file mode 100644 index 0000000000..088b0db00e --- /dev/null +++ b/plugins/Clist_ng/SRC/cluiservices.cpp @@ -0,0 +1,264 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: cluiservices.cpp 133 2010-09-30 06:27:18Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <m_icq.h>
+
+extern PLUGININFOEX pluginInfo;
+
+static INT_PTR GetClistVersion(WPARAM wParam, LPARAM lParam)
+{
+ static char g_szVersionString[256];
+
+ mir_snprintf(g_szVersionString, 256, "%s, %d.%d.%d.%d", pluginInfo.shortName, HIBYTE(HIWORD(pluginInfo.version)), LOBYTE(HIWORD(pluginInfo.version)), HIBYTE(LOWORD(pluginInfo.version)), LOBYTE(LOBYTE(pluginInfo.version)));
+ if(!IsBadWritePtr((LPVOID)lParam, 4))
+ *((DWORD *)lParam) = pluginInfo.version;
+
+ return (INT_PTR)g_szVersionString;
+}
+
+
+void FreeProtocolData( void )
+{
+ //free protocol data
+ int nPanel;
+ int nParts=SendMessage(pcli->hwndStatus,SB_GETPARTS,0,0);
+ for (nPanel=0;nPanel<nParts;nPanel++) {
+ ProtocolData *PD;
+ PD=(ProtocolData *)SendMessage(pcli->hwndStatus,SB_GETTEXT,(WPARAM)nPanel,(LPARAM)0);
+ if (PD!=NULL&&!IsBadCodePtr((FARPROC)PD)) {
+ SendMessage(pcli->hwndStatus,SB_SETTEXT,(WPARAM)nPanel|SBT_OWNERDRAW,(LPARAM)0);
+ if (PD->RealName) mir_free(PD->RealName);
+ if (PD) mir_free(PD);
+ }
+ }
+}
+
+char g_maxProto[100] = "";
+
+void CluiProtocolStatusChanged( int parStatus, const char* szProto )
+{
+ int protoCount,i;
+ PROTOACCOUNT **accs;
+ int *partWidths,partCount;
+ int borders[3];
+ int status;
+ int toshow;
+ wchar_t *szStatus = NULL;
+ char *szMaxProto = NULL;
+ int maxOnline = 0, onlineness = 0;
+ WORD maxStatus = ID_STATUS_OFFLINE, wStatus = ID_STATUS_OFFLINE;
+ DBVARIANT dbv = {0};
+ int iIcon = 0;
+ HICON hIcon = 0;
+ int rdelta = Skin::metrics.cLeft + Skin::metrics.cRight;
+ BYTE windowStyle;
+
+ if (pcli->hwndStatus == 0 || cfg::shutDown)
+ return;
+
+ Proto_EnumAccounts( &protoCount, &accs );
+ if (protoCount == 0)
+ return;
+
+ FreeProtocolData();
+ cfg::maxStatus = ID_STATUS_OFFLINE;
+ g_maxProto[0] = 0;
+
+ SendMessage(pcli->hwndStatus,SB_GETBORDERS,0,(LPARAM)&borders);
+
+ partWidths=(int*)_alloca(( protoCount+1)*sizeof(int));
+
+ if (cfg::dat.bEqualSections) {
+ RECT rc;
+ int part;
+ GetClientRect(pcli->hwndStatus,&rc);
+ rc.right-=borders[0]*2;
+ toshow=0;
+ for ( i=0; i < protoCount; i++ )
+ if ( pcli->pfnGetProtocolVisibility( accs[i]->szModuleName ))
+ toshow++;
+
+ if ( toshow > 0 ) {
+ for ( part=0, i=0; i < protoCount; i++ ) {
+ if ( !pcli->pfnGetProtocolVisibility( accs[i]->szModuleName ))
+ continue;
+
+ partWidths[ part ] = ((rc.right-rc.left-rdelta)/toshow)*(part+1) + Skin::metrics.cLeft;
+ if ( part == toshow-1 )
+ partWidths[ part ] += Skin::metrics.cRight;
+ part++;
+ }
+ }
+ partCount=toshow;
+ }
+ else {
+ HDC hdc;
+ SIZE textSize;
+ BYTE showOpts = cfg::getByte("CLUI","SBarShow",1);
+ int x;
+ HFONT hofont;
+ wchar_t szName[32];
+ PROTOACCOUNT* pa;
+
+ hdc=GetDC(NULL);
+ hofont = reinterpret_cast<HFONT>(SelectObject(hdc,(HFONT)SendMessage(pcli->hwndStatus,WM_GETFONT,0,0)));
+
+ for ( partCount=0,i=0; i < protoCount; i++ ) { //count down since built in ones tend to go at the end
+ int idx = pcli->pfnGetAccountIndexByPos( i );
+ if ( idx == -1 )
+ continue;
+
+ pa = accs[idx];
+ if ( !pcli->pfnGetProtocolVisibility( pa->szModuleName ))
+ continue;
+
+ x=2;
+ if (showOpts & 1)
+ x += 16;
+ if (showOpts & 2) {
+ lstrcpyn( szName, pa->tszAccountName, _countof(szName));
+ szName[ _countof(szName)-1 ] = 0;
+ if (( showOpts & 4 ) && lstrlen(szName) < sizeof(szName)-1 )
+ lstrcat( szName, _T(" "));
+ GetTextExtentPoint32( hdc, szName, lstrlen(szName), &textSize );
+ x += textSize.cx + GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ if (showOpts & 4) {
+ wchar_t* modeDescr = pcli->pfnGetStatusModeDescription( CallProtoService(accs[i]->szModuleName,PS_GETSTATUS,0,0 ), 0 );
+ GetTextExtentPoint32(hdc, modeDescr, lstrlen(modeDescr), &textSize );
+ x += textSize.cx + GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ partWidths[partCount]=(partCount?partWidths[partCount-1]:Skin::metrics.cLeft)+ x + 2;
+ partCount++;
+ }
+ SelectObject(hdc,hofont);
+ ReleaseDC(NULL,hdc);
+ }
+ if (partCount==0) {
+ SendMessage(pcli->hwndStatus,SB_SIMPLE,TRUE,0);
+ return;
+ }
+ SendMessage(pcli->hwndStatus,SB_SIMPLE,FALSE,0);
+
+ partWidths[partCount-1]=-1;
+ windowStyle = Skin::metrics.bWindowStyle;
+ //SendMessage(pcli->hwndStatus,SB_SETMINHEIGHT, 12 + ((windowStyle == SETTING_WINDOWSTYLE_THINBORDER || windowStyle == SETTING_WINDOWSTYLE_NOBORDER) ? 3 : 0), 0);
+ SendMessage(pcli->hwndStatus, SB_SETPARTS, partCount, (LPARAM)partWidths);
+
+ for ( partCount=0, i=0; i < protoCount; i++ ) { //count down since built in ones tend to go at the end
+ ProtocolData *PD;
+ PROTOACCOUNT *pa;
+ int caps1, caps2;
+
+ int idx = pcli->pfnGetAccountIndexByPos( i );
+ if ( idx == -1 )
+ continue;
+
+ pa = accs[idx];
+ if ( !pcli->pfnGetProtocolVisibility( pa->szModuleName ))
+ continue;
+
+ status = CallProtoService( pa->szModuleName,PS_GETSTATUS,0,0);
+ PD = ( ProtocolData* )mir_alloc(sizeof(ProtocolData));
+ PD->RealName = mir_strdup( pa->szModuleName );
+ PD->protopos = partCount;
+ {
+ int flags;
+ flags = SBT_OWNERDRAW;
+ if ( cfg::getByte("CLUI","SBarBevel", 1)==0 )
+ flags |= SBT_NOBORDERS;
+ SendMessageA( pcli->hwndStatus, SB_SETTEXTA, partCount|flags,(LPARAM)PD );
+ }
+ caps2 = CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0);
+ caps1 = CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0);
+ if((caps1 & PF1_IM) && (caps2 & (PF2_LONGAWAY | PF2_SHORTAWAY))) {
+ onlineness = CLC::getStatusOnlineness(status, false);
+ if(onlineness > maxOnline) {
+ maxStatus = status;
+ maxOnline = onlineness;
+ szMaxProto = pa->szModuleName;
+ }
+ }
+ partCount++;
+ }
+ // update the clui button
+
+ if (!db_get(NULL, "CList", "PrimaryStatus", &dbv)) {
+ if (dbv.type == DBVT_ASCIIZ && lstrlenA(dbv.pszVal) > 1) {
+ wStatus = (WORD) CallProtoService(dbv.pszVal, PS_GETSTATUS, 0, 0);
+ iIcon = CLC::IconFromStatusMode(dbv.pszVal, (int) wStatus, 0, &hIcon);
+ }
+ mir_free(dbv.pszVal);
+ } else {
+ wStatus = maxStatus;
+ iIcon = CLC::IconFromStatusMode((wStatus >= ID_STATUS_CONNECTING && wStatus < ID_STATUS_OFFLINE) ? szMaxProto : NULL, (int) wStatus, 0, &hIcon);
+ cfg::maxStatus = (int)wStatus;
+ if(szMaxProto) {
+ lstrcpynA(g_maxProto, szMaxProto, 100);
+ g_maxProto[99] = 0;
+ }
+ }
+ /*
+ * this is used globally (actually, by the clist control only) to determine if
+ * any protocol is "in connection" state. If true, then the clist discards redraws
+ * and uses timer based sort and redraw handling. This can improve performance
+ * when connecting multiple protocols significantly.
+ */
+ //g_isConnecting = (wStatus >= ID_STATUS_CONNECTING && wStatus < ID_STATUS_OFFLINE);
+
+ szStatus = pcli->pfnGetStatusModeDescription(wStatus, 0);
+
+ /*
+ * set the global status icon and display the global (most online) status mode on the
+ * status mode button
+ */
+
+ if (szStatus) {
+ if(pcli->hwndContactList && IsWindow(GetDlgItem(pcli->hwndContactList, IDC_TBGLOBALSTATUS)) && IsWindow(GetDlgItem(pcli->hwndContactList, IDC_TBTOPSTATUS))) {
+ SendMessage(GetDlgItem(pcli->hwndContactList, IDC_TBGLOBALSTATUS), WM_SETTEXT, 0, (LPARAM) szStatus);
+ if(!hIcon) {
+ SendMessage(GetDlgItem(pcli->hwndContactList, IDC_TBGLOBALSTATUS), BM_SETIMLICON, (WPARAM) CLC::hClistImages, (LPARAM) iIcon);
+ if(CLUI::buttonItems == NULL)
+ SendMessage(GetDlgItem(pcli->hwndContactList, IDC_TBTOPSTATUS), BM_SETIMLICON, (WPARAM) CLC::hClistImages, (LPARAM) iIcon);
+ }
+ else {
+ SendMessage(GetDlgItem(pcli->hwndContactList, IDC_TBGLOBALSTATUS), BM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
+ if(CLUI::buttonItems == NULL)
+ SendMessage(GetDlgItem(pcli->hwndContactList, IDC_TBTOPSTATUS), BM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
+ }
+ InvalidateRect(GetDlgItem(pcli->hwndContactList, IDC_TBGLOBALSTATUS), NULL, TRUE);
+ InvalidateRect(GetDlgItem(pcli->hwndContactList, IDC_TBTOPSTATUS), NULL, TRUE);
+ SFL_Update(hIcon, iIcon, CLC::hClistImages, szStatus, TRUE);
+ } }
+ return;
+}
diff --git a/plugins/Clist_ng/SRC/config.cpp b/plugins/Clist_ng/SRC/config.cpp new file mode 100644 index 0000000000..4674f398c5 --- /dev/null +++ b/plugins/Clist_ng/SRC/config.cpp @@ -0,0 +1,626 @@ +
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: config.cpp 137 2010-10-16 21:03:23Z silvercircle $
+ *
+ * plugin configuration and low level API handling
+ *
+ */
+
+#include <commonheaders.h>
+
+TCluiData cfg::dat = {0};
+ClcData* cfg::clcdat = 0;
+TExtraCache* cfg::eCache = 0;
+int cfg::nextCacheEntry = 0, cfg::maxCacheEntry = 0;
+bool cfg::isAero = true;
+bool cfg::fBaseSkinValid = true;
+FI_INTERFACE* cfg::fif = 0;
+CRITICAL_SECTION cfg::cachecs = {0};
+
+bool cfg::shutDown = false;
+wchar_t cfg::szProfileDir[MAX_PATH] = L"\0";
+int cfg::maxStatus = ID_STATUS_OFFLINE;
+CLUIFrames *cfg::FrameMgr = nullptr;
+
+
+pfnAlphaBlend_t Api::pfnAlphaBlend = 0;
+PGF Api::pfnGradientFill = 0;
+pfnGetTickCount64_t Api::pfnGetTickCount64 = 0;
+
+TSysConfig Api::sysConfig = {0};
+TSysState Api::sysState = {0};
+
+pfnIsThemeActive_t Api::pfnIsThemeActive = 0;
+pfnOpenThemeData_t Api::pfnOpenThemeData = 0;
+pfnDrawThemeBackground_t Api::pfnDrawThemeBackground = 0;
+pfnCloseThemeData_t Api::pfnCloseThemeData = 0;
+pfnDrawThemeText_t Api::pfnDrawThemeText = 0;
+pfnDrawThemeTextEx_t Api::pfnDrawThemeTextEx = 0;
+pfnIsThemeBackgroundPartiallyTransparent_t Api::pfnIsThemeBackgroundPartiallyTransparent = 0;
+pfnDrawThemeParentBackground_t Api::pfnDrawThemeParentBackground = 0;
+pfnGetThemeBackgroundContentRect_t Api::pfnGetThemeBackgroundContentRect = 0;
+pfnEnableThemeDialogTexture_t Api::pfnEnableThemeDialogTexture = 0;
+
+pfnDwmExtendFrameIntoClientArea_t Api::pfnDwmExtendFrameIntoClientArea = 0;
+pfnDwmIsCompositionEnabled_t Api::pfnDwmIsCompositionEnabled = 0;
+
+pfnBufferedPaintInit_t Api::pfnBufferedPaintInit = 0;
+pfnBufferedPaintUninit_t Api::pfnBufferedPaintUninit = 0;
+
+pfnBeginBufferedPaint_t Api::pfnBeginBufferedPaint = 0;
+pfnEndBufferedPaint_t Api::pfnEndBufferedPaint = 0;
+pfnBufferedPaintSetAlpha_t Api::pfnBufferedPaintSetAlpha = 0;
+pfnBufferedPaintClear_t Api::pfnBufferedPaintClear = 0;
+pfnGetBufferedPaintBits_t Api::pfnGetBufferedPaintBits = 0;
+
+pfnDwmGetColorizationColor_t Api::pfnDwmGetColorizationColor = 0;
+pfnDwmBlurBehindWindow_t Api::pfnDwmBlurBehindWindow = 0;
+
+EXCEPTION_RECORD Api::exRecord = {0};
+CONTEXT Api::exCtx = {0};
+LRESULT Api::exLastResult = 0;
+char Api::exSzFile[MAX_PATH] = "\0";
+wchar_t Api::exReason[256] = L"\0";
+int Api::exLine = 0;
+bool Api::exAllowContinue = false;
+HMODULE Api::hUxTheme = 0, Api::hDwm = 0;
+
+void cfg::initCache()
+{
+ InitializeCriticalSection(&cachecs);
+}
+
+DWORD cfg::getDword(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, DWORD uDefault = 0)
+{
+ return(db_get_dw(hContact, szModule, szSetting, uDefault));
+}
+
+/*
+ * read a setting from our default module (Tab_SRMSG)
+ */
+
+DWORD cfg::getDword(const char *szSetting = 0, DWORD uDefault = 0)
+{
+ return(db_get_dw(0, DEFAULT_MODULE, szSetting, uDefault));
+}
+
+/*
+ * read a setting from module only
+ */
+
+DWORD cfg::getDword(const char *szModule, const char *szSetting, DWORD uDefault)
+{
+ return(db_get_dw(0, szModule, szSetting, uDefault));
+}
+
+
+WORD cfg::getWord(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, WORD uDefault = 0)
+{
+ return(db_get_w(hContact, szModule, szSetting, uDefault));
+}
+
+/*
+ * read a setting from our default module (Tab_SRMSG)
+ */
+
+WORD cfg::getWord(const char *szSetting = 0, WORD uDefault = 0)
+{
+ return(db_get_w(0, DEFAULT_MODULE, szSetting, uDefault));
+}
+
+/*
+ * read a setting from module only
+ */
+
+WORD cfg::getWord(const char *szModule, const char *szSetting, WORD uDefault)
+{
+ return(db_get_w(0, szModule, szSetting, uDefault));
+}
+
+/*
+ * same for bytes now
+ */
+int cfg::getByte(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, int uDefault = 0)
+{
+ return(db_get_b(hContact, szModule, szSetting, uDefault));
+}
+
+int cfg::getByte(const char *szSetting = 0, int uDefault = 0)
+{
+ return(db_get_b(0, DEFAULT_MODULE, szSetting, uDefault));
+}
+
+int cfg::getByte(const char *szModule, const char *szSetting, int uDefault)
+{
+ return(db_get_b(0, szModule, szSetting, uDefault));
+}
+
+INT_PTR cfg::getTString(const MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv)
+{
+ return(db_get_ws(hContact, szModule, szSetting, dbv));
+}
+
+INT_PTR cfg::getString(const MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv)
+{
+ return(db_get_s(hContact, szModule, szSetting, dbv));
+}
+
+/*
+ * writer functions
+ */
+
+INT_PTR cfg::writeDword(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, DWORD value = 0)
+{
+ return(db_set_dw(hContact, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeDword(const char *szModule = 0, const char *szSetting = 0, DWORD value = 0)
+{
+ return(db_set_dw(0, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeWord(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, WORD value = 0)
+{
+ return(db_set_w(hContact, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeWord(const char *szModule = 0, const char *szSetting = 0, WORD value = 0)
+{
+ return(db_set_w(0, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeByte(const MCONTACT hContact = 0, const char *szModule = 0, const char *szSetting = 0, BYTE value = 0)
+{
+ return(db_set_b(hContact, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeByte(const char *szModule = 0, const char *szSetting = 0, BYTE value = 0)
+{
+ return(db_set_b(0, szModule, szSetting, value));
+}
+
+INT_PTR cfg::writeTString(const MCONTACT hContact, const char *szModule = 0, const char *szSetting = 0, const wchar_t *str = 0)
+{
+ return(db_set_ws(hContact, szModule, szSetting, str));
+}
+
+INT_PTR cfg::writeString(const MCONTACT hContact, const char *szModule = 0, const char *szSetting = 0, const char *str = 0)
+{
+ return(db_set_s(hContact, szModule, szSetting, str));
+}
+
+int cfg::getCache(const MCONTACT hContact, const char *szProto)
+{
+ int i, iFound = -1;
+
+ for(i = 0; i < nextCacheEntry; i++) {
+ if(eCache[i].hContact == hContact) {
+ iFound = i;
+ break;
+ }
+ }
+ if(iFound == -1) {
+ EnterCriticalSection(&cachecs);
+ if(nextCacheEntry == maxCacheEntry) {
+ maxCacheEntry += 100;
+ cfg::eCache = (TExtraCache *)realloc(cfg::eCache, maxCacheEntry * sizeof(TExtraCache));
+ }
+ memset(&cfg::eCache[nextCacheEntry], 0, sizeof(TExtraCache));
+ cfg::eCache[nextCacheEntry].hContact = hContact;
+ memset(cfg::eCache[nextCacheEntry].iExtraImage, 0xff, MAXEXTRACOLUMNS);
+ cfg::eCache[nextCacheEntry].iExtraValid = 0;
+ cfg::eCache[nextCacheEntry].valid = FALSE;
+ cfg::eCache[nextCacheEntry].bStatusMsgValid = 0;
+ cfg::eCache[nextCacheEntry].statusMsg = NULL;
+ cfg::eCache[nextCacheEntry].status_item = NULL;
+ cfg::eCache[nextCacheEntry].dwCFlags = 0;
+ cfg::eCache[nextCacheEntry].dwXMask = CalcXMask(hContact);
+ GetCachedStatusMsg(nextCacheEntry, const_cast<char *>(szProto));
+ cfg::eCache[nextCacheEntry].dwLastMsgTime = INTSORT_GetLastMsgTime(hContact);
+ iFound = nextCacheEntry++;
+ LeaveCriticalSection(&cachecs);
+ }
+ return iFound;
+}
+
+static struct {
+ UINT id;
+ TCHAR* name;
+} _tagFSINFO[] = {
+ FONTID_CONTACTS, LPGENT("Standard contacts"),
+ FONTID_INVIS, LPGENT("Online contacts to whom you have a different visibility"),
+ FONTID_OFFLINE, LPGENT("Offline contacts"),
+ FONTID_OFFINVIS, LPGENT("Offline contacts to whom you have a different visibility"),
+ FONTID_NOTONLIST, LPGENT("Contacts which are 'not on list'"),
+ FONTID_GROUPS, LPGENT("Groups"),
+ FONTID_GROUPCOUNTS, LPGENT("Group member counts"),
+ FONTID_DIVIDERS, LPGENT("Dividers"),
+ FONTID_STATUS, LPGENT("Status mode"),
+ FONTID_FRAMETITLE, LPGENT("Frame titles"),
+ FONTID_EVENTAREA, LPGENT("Event area"),
+ FONTID_TIMESTAMP, LPGENT("Contact list local time"),
+ 0, NULL
+};
+
+struct ColorOptionsList {
+ int order;
+ TCHAR* tszName;
+ char* szSetting;
+ COLORREF def;
+};
+
+/*
+ * note: bits 24-31 in default color indicates that color is a system color index
+ * (GetSysColor(default_color & 0x00ffffff)), not a rgb value.
+ */
+static ColorOptionsList _clrs[] = {
+ 0, L"List background", "BkColour", COLOR_WINDOW | 0xff000000,
+ 1, L"Group header background", "BkColourGroups", COLOR_3DFACE | 0xff000000,
+ 2, L"Selected text", "SelTextColour", COLOR_HIGHLIGHTTEXT | 0xff000000,
+ 3, L"Hottrack text", "HotTextColour", COLOR_HOTLIGHT | 0xff000000,
+ 4, L"Quicksearch text", "QuickSearchColour", CLCDEFAULT_QUICKSEARCHCOLOUR,
+ 5, L"Frame title background", "BkFrameTitles", COLOR_3DFACE | 0xff000000,
+ 6, L"Event area background", "BkEventAera", COLOR_WINDOW | 0xff000000
+};
+
+void cfg::FS_RegisterFonts()
+{
+ ColourIDT colourid;
+ FontIDT fid = {0};
+ char szTemp[50];
+ DBVARIANT dbv;
+ int j = 0;
+
+ fid.cbSize = sizeof(fid);
+ wcsncpy(fid.group, L"Contact List", _countof(fid.group));
+ strncpy(fid.dbSettingsGroup, "CLC", 5);
+ fid.flags = FIDF_DEFAULTVALID | FIDF_ALLOWEFFECTS | FIDF_APPENDNAME | FIDF_SAVEPOINTSIZE;
+ wcsncpy(fid.backgroundGroup, L"Contact List", _countof(fid.backgroundGroup));
+ while(_tagFSINFO[j].name != 0) {
+ if(FONTID_EVENTAREA == _tagFSINFO[j].id)
+ wcsncpy(fid.backgroundName, L"Event area background", _countof(fid.backgroundName));
+ else if(FONTID_FRAMETITLE == _tagFSINFO[j].id)
+ wcsncpy(fid.backgroundName, L"Frame title background", _countof(fid.backgroundName));
+ else if(FONTID_GROUPCOUNTS == _tagFSINFO[j].id || FONTID_GROUPS == _tagFSINFO[j].id)
+ _tcsncpy(fid.backgroundName, L"Group header background", _countof(fid.backgroundName));
+ else
+ wcsncpy(fid.backgroundName, L"List background", _countof(fid.backgroundName));
+
+ mir_snprintf(szTemp, sizeof(szTemp), "Font%d", _tagFSINFO[j].id);
+ strncpy(fid.prefix, szTemp, sizeof(fid.prefix));
+ fid.order = _tagFSINFO[j].id;
+ wcsncpy(fid.name, _tagFSINFO[j].name, 60);
+ _snprintf(szTemp, sizeof(szTemp), "Font%dCol", _tagFSINFO[j].id);
+ fid.deffontsettings.colour = (COLORREF)cfg::getDword("CLC", szTemp, GetSysColor(COLOR_WINDOWTEXT));
+
+ _snprintf(szTemp, sizeof(szTemp), "Font%dSize", _tagFSINFO[j].id);
+ fid.deffontsettings.size = (BYTE)cfg::getByte("CLC", szTemp, 8);
+
+ _snprintf(szTemp, sizeof(szTemp), "Font%dSty", _tagFSINFO[j].id);
+ fid.deffontsettings.style = cfg::getByte("CLC", szTemp, 0);
+ _snprintf(szTemp, sizeof(szTemp), "Font%dSet", _tagFSINFO[j].id);
+ fid.deffontsettings.charset = cfg::getByte("CLC", szTemp, DEFAULT_CHARSET);
+ _snprintf(szTemp, sizeof(szTemp), "Font%dName", _tagFSINFO[j].id);
+ if(cfg::getString(NULL, "CLC", szTemp, &dbv))
+ lstrcpyn(fid.deffontsettings.szFace, L"Tahoma", LF_FACESIZE);
+ else {
+ lstrcpyn(fid.deffontsettings.szFace, dbv.ptszVal, LF_FACESIZE);
+ mir_free(dbv.ptszVal);
+ }
+ FontRegisterT(&fid);
+ j++;
+ }
+
+ colourid.order = 0;
+ strncpy(colourid.dbSettingsGroup, "CLC", sizeof(colourid.dbSettingsGroup));
+ colourid.cbSize = sizeof(ColourIDT);
+ mir_sntprintf(colourid.group, _countof(colourid.group), L"%s", L"Contact List");
+ for (int i = 0; i < _countof(_clrs); i++) {
+ colourid.order = _clrs[i].order;
+ mir_snprintf(colourid.setting, sizeof(colourid.setting), "%s", _clrs[i].szSetting);
+ mir_sntprintf(colourid.name, _countof(colourid.name), L"%s", _clrs[i].tszName);
+ colourid.defcolour = (_clrs[i].def & 0xff000000 ? GetSysColor(_clrs[i].def & 0x00ffffff) : _clrs[i].def);
+ ColourRegisterT(&colourid);
+ }
+}
+
+TSkinDescription cfg::my_default_skin[] = {
+ IDR_SKIN_BASE, _T("base.cng"),
+ IDR_SKIN_BACK, _T("back.png"),
+ IDR_SKIN_BACKAERO, _T("AeroBack.png"),
+ IDR_SKIN_GLYPHS, _T("glyphs.png"),
+};
+
+/**
+ * first stage config init. Just read profile base path and try to
+ * extract the skin from the DLL
+ */
+int cfg::onInit()
+{
+ wchar_t* userdata = ::Utils_ReplaceVarsT(L"%miranda_profilesdir%");
+ wchar_t szBaseSkin[MAX_PATH];
+
+ LRESULT fi_version = CallService(MS_IMG_GETIFVERSION, 0, 0);
+ CallService(MS_IMG_GETINTERFACE, fi_version, (LPARAM)&fif);
+
+ if(0 == fif)
+ return(-S_FALSE);
+
+ mir_sntprintf(szProfileDir, MAX_PATH, L"%s", userdata);
+ mir_free(userdata);
+
+ Utils::ensureTralingBackslash(szProfileDir);
+ mir_sntprintf(szBaseSkin, MAX_PATH, L"%s%s", szProfileDir, L"skin\\clng\\base");
+ CreateDirectoryTreeW(szBaseSkin);
+ extractBaseSkin(false);
+
+ return(fBaseSkinValid ? S_OK : -S_FALSE);
+}
+/**
+ * extract the aero skin images from the DLL and store them in
+ * the private data folder.
+ * runs at every startup
+ *
+ * only overwrites the files when version number does not match or
+ * one of the files is missing.
+ */
+void cfg::extractBaseSkin(bool fForceOverwrite)
+{
+ wchar_t wszBasePath[MAX_PATH], wszTest[MAX_PATH];
+ bool fChecksPassed = true;
+ HANDLE hFile;
+
+ mir_sntprintf(wszBasePath, MAX_PATH, L"%s%s", szProfileDir, L"skin\\clng\\base\\");
+ mir_sntprintf(wszTest, MAX_PATH, L"%s%s", wszBasePath, L"base.cng");
+
+ /*
+ * version check, also fails when the file is simply missing
+ */
+ int uVersion = GetPrivateProfileInt(L"SkinInfo", L"Version", 0, wszTest);
+ if(uVersion < SKIN_REQUIRED_VERSION)
+ fChecksPassed = false;
+
+ /*
+ * version check passed, verify files are present
+ */
+ if(fChecksPassed) {
+ for(int i = 0; i < safe_sizeof(my_default_skin); i++) {
+ mir_sntprintf(wszTest, MAX_PATH, L"%s%s", wszBasePath, my_default_skin[i].tszName);
+ if((hFile = CreateFile(wszTest, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) {
+ fChecksPassed = false;
+ break;
+ }
+ CloseHandle(hFile);
+ }
+ }
+
+ // files are not present in skin dir, extract the default skin
+ if(!fChecksPassed) {
+ try {
+ for(int i = 0; i < safe_sizeof(my_default_skin); i++)
+ Utils::extractResource(g_hInst, my_default_skin[i].ulID, L"SKIN_GLYPH", wszBasePath, my_default_skin[i].tszName, true);
+
+ fBaseSkinValid = true;
+ } catch(CRTException& ex) {
+ ex.display();
+ fBaseSkinValid = false;
+ }
+ }
+}
+
+int Api::onInit()
+{
+ HMODULE hUserDll = 0;
+
+ hUserDll = GetModuleHandleA("user32.dll");
+
+ pfnGradientFill = (PGF) GetProcAddress(GetModuleHandleA("gdi32"), "GdiGradientFill");
+ if(0 == pfnGradientFill)
+ pfnGradientFill = (PGF) GetProcAddress(GetModuleHandleA("msimg32"), "GradientFill");
+
+ pfnAlphaBlend = (pfnAlphaBlend_t) GetProcAddress(GetModuleHandleA("gdi32"), "GdiAlphaBlend");
+ if(0 == pfnAlphaBlend)
+ pfnAlphaBlend = (pfnAlphaBlend_t)GetProcAddress(GetModuleHandleA("msimg32"), "AlphaBlend");
+
+ pfnGetTickCount64 = (pfnGetTickCount64_t)GetProcAddress(GetModuleHandleA("kernel32"), "GetTickCount64");
+
+ sysConfig.isVistaPlus = (IsWinVerVistaPlus() ? true : false);
+ sysConfig.isSevenPlus = (IsWinVer7Plus() ? true : false);
+
+ if(!sysConfig.isVistaPlus)
+ return(-S_FALSE);
+
+ if(sysConfig.isVistaPlus) {
+ if((hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll"), true) != 0) {
+ pfnIsThemeActive = (pfnIsThemeActive_t)GetProcAddress(hUxTheme, "IsThemeActive");
+ pfnOpenThemeData = (pfnOpenThemeData_t)GetProcAddress(hUxTheme, "OpenThemeData");
+ pfnDrawThemeBackground = (pfnDrawThemeBackground_t)GetProcAddress(hUxTheme, "DrawThemeBackground");
+ pfnCloseThemeData = (pfnCloseThemeData_t)GetProcAddress(hUxTheme, "CloseThemeData");
+ pfnDrawThemeText = (pfnDrawThemeText_t)GetProcAddress(hUxTheme, "DrawThemeText");
+ pfnIsThemeBackgroundPartiallyTransparent = (pfnIsThemeBackgroundPartiallyTransparent_t)GetProcAddress(hUxTheme, "IsThemeBackgroundPartiallyTransparent");
+ pfnDrawThemeParentBackground = (pfnDrawThemeParentBackground_t)GetProcAddress(hUxTheme, "DrawThemeParentBackground");
+ pfnGetThemeBackgroundContentRect = (pfnGetThemeBackgroundContentRect_t)GetProcAddress(hUxTheme, "GetThemeBackgroundContentRect");
+ pfnEnableThemeDialogTexture = (pfnEnableThemeDialogTexture_t)GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+
+ if(pfnIsThemeActive != 0 && pfnOpenThemeData != 0 && pfnDrawThemeBackground != 0 && pfnCloseThemeData != 0
+ && pfnDrawThemeText != 0 && pfnIsThemeBackgroundPartiallyTransparent != 0 && pfnDrawThemeParentBackground != 0
+ && pfnGetThemeBackgroundContentRect != 0) {
+ }
+ pfnBeginBufferedPaint = (pfnBeginBufferedPaint_t)GetProcAddress(hUxTheme, "BeginBufferedPaint");
+ pfnEndBufferedPaint = (pfnEndBufferedPaint_t)GetProcAddress(hUxTheme, "EndBufferedPaint");
+ pfnBufferedPaintInit = (pfnBufferedPaintInit_t)GetProcAddress(hUxTheme, "BufferedPaintInit");
+ pfnBufferedPaintUninit = (pfnBufferedPaintUninit_t)GetProcAddress(hUxTheme, "BufferedPaintUnInit");
+ pfnBufferedPaintSetAlpha = (pfnBufferedPaintSetAlpha_t)GetProcAddress(hUxTheme, "BufferedPaintSetAlpha");
+ pfnBufferedPaintClear = (pfnBufferedPaintClear_t)GetProcAddress(hUxTheme, "BufferedPaintClear");
+ pfnGetBufferedPaintBits = (pfnGetBufferedPaintBits_t)GetProcAddress(hUxTheme, "GetBufferedPaintBits");
+ pfnDrawThemeTextEx = (pfnDrawThemeTextEx_t)GetProcAddress(hUxTheme, "DrawThemeTextEx");
+
+ if((hDwm = Utils::loadSystemLibrary(L"\\dwmapi.dll"), true) != 0) {
+ pfnDwmIsCompositionEnabled = (pfnDwmIsCompositionEnabled_t)GetProcAddress(hDwm, "DwmIsCompositionEnabled");
+ pfnDwmExtendFrameIntoClientArea = (pfnDwmExtendFrameIntoClientArea_t)GetProcAddress(hDwm, "DwmExtendFrameIntoClientArea");
+
+ pfnDwmBlurBehindWindow = (pfnDwmBlurBehindWindow_t)GetProcAddress(hDwm, "DwmEnableBlurBehindWindow");
+ pfnDwmGetColorizationColor = (pfnDwmGetColorizationColor_t)GetProcAddress(hDwm, "DwmGetColorizationColor");
+ }
+ }
+ }
+ pfnBufferedPaintInit();
+ updateState();
+ return(S_OK);
+}
+
+void Api::onUnload()
+{
+ if(hUxTheme)
+ FreeLibrary(hUxTheme);
+
+ pfnBufferedPaintUninit();
+}
+
+/**
+ * update system's state (theme status, aero status, DWM check...
+ *
+ * called when windows broadcasts things like WM_THEMECHANGED or
+ * WM_DWMCOMPOSITIONCHANGED
+ */
+void Api::updateState()
+{
+ BOOL result = FALSE;
+
+ ::ZeroMemory(&sysState, sizeof(TSysState));
+
+ sysState.isThemed = pfnIsThemeActive() ? true : false;
+
+ if(sysConfig.isVistaPlus) {
+ sysState.isDwmActive = (pfnDwmIsCompositionEnabled && (pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false;
+ sysState.isAero = cfg::getByte(SKIN_DB_MODULE, "fUseAero", 1) && sysState.isDwmActive;
+ }
+ else
+ sysState.isAero = sysState.isDwmActive = false;
+}
+
+/**
+ * exception handling for SEH exceptions
+ */
+
+/**
+ * exception handling - copy error message to clip board
+ * @param hWnd: window handle of the edit control containing the error message
+ */
+void Api::Ex_CopyEditToClipboard(HWND hWnd)
+{
+ SendMessage(hWnd, EM_SETSEL, 0, 65535L);
+ SendMessage(hWnd, WM_COPY, 0 , 0);
+ SendMessage(hWnd, EM_SETSEL, 0, 0);
+}
+
+INT_PTR CALLBACK Api::Ex_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WORD wNotifyCode, wID;
+
+ switch(uMsg) {
+ case WM_INITDIALOG: {
+ char szBuffer[2048];
+#ifdef _WIN64
+ sprintf(szBuffer,
+ "Exception %16.16X at address %16.16X occured in %s at line %d.\r\n\r\nEAX=%16.16X EBX=%16.16X ECX=%16.16X\r\nEDX=%16.16X ESI=%16.16X EDI=%16.16X\r\nEBP=%16.16X ESP=%16.16X EIP=%16.16X",
+ exRecord.ExceptionCode, exRecord.ExceptionAddress, exSzFile, exLine,
+ exCtx.Rax, exCtx.Rbx, exCtx.Rcx, exCtx.Rdx,
+ exCtx.Rsi, exCtx.Rdi, exCtx.Rbp, exCtx.Rsp, exCtx.Rip);
+#else
+ sprintf(szBuffer,
+ "Exception %8.8X at address %8.8X occured in %s at line %d.\r\n\r\nEAX=%8.8X EBX=%8.8X ECX=%8.8X\r\nEDX=%8.8X ESI=%8.8X EDI=%8.8X\r\nEBP=%8.8X ESP=%8.8X EIP=%8.8X",
+ exRecord.ExceptionCode, exRecord.ExceptionAddress, exSzFile, exLine,
+ exCtx.Eax, exCtx.Ebx, exCtx.Ecx, exCtx.Edx,
+ exCtx.Esi, exCtx.Edi, exCtx.Ebp, exCtx.Esp, exCtx.Eip);
+#endif
+ SetDlgItemTextA(hwndDlg, IDC_EXCEPTION_DETAILS, szBuffer);
+ SetFocus(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ SendDlgItemMessage(hwndDlg, IDC_EXCEPTION_DETAILS, WM_SETFONT, (WPARAM)GetStockObject(OEM_FIXED_FONT), 0);
+ SetDlgItemTextW(hwndDlg, IDC_EX_REASON, exReason);
+ Utils::enableDlgControl(hwndDlg, IDOK, exAllowContinue ? TRUE : FALSE);
+ }
+ break;
+
+ case WM_COMMAND:
+ wNotifyCode = HIWORD(wParam);
+ wID = LOWORD(wParam);
+ if(wNotifyCode == BN_CLICKED) {
+ if(wID == IDOK || wID == IDCANCEL)
+ EndDialog(hwndDlg, wID);
+
+ if(wID == IDC_COPY_EXCEPTION)
+ Ex_CopyEditToClipboard(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ }
+
+ break;
+ }
+ return FALSE;
+}
+
+void Api::Ex_Handler()
+{
+ if(exLastResult == IDCANCEL)
+ ExitProcess(1);
+}
+
+int Api::Ex_ShowDialog(EXCEPTION_POINTERS *ep, const char *szFile, int line, wchar_t* szReason, bool fAllowContinue)
+{
+ char szDrive[MAX_PATH], szDir[MAX_PATH], szName[MAX_PATH], szExt[MAX_PATH];
+
+ _splitpath(szFile, szDrive, szDir, szName, szExt);
+ memcpy(&exRecord, ep->ExceptionRecord, sizeof(EXCEPTION_RECORD));
+ memcpy(&exCtx, ep->ContextRecord, sizeof(CONTEXT));
+
+ _snprintf(exSzFile, MAX_PATH, "%s%s", szName, szExt);
+ mir_sntprintf(exReason, 256, L"An application error has occured: %s", szReason);
+ exLine = line;
+ exLastResult = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXCEPTION), 0, Ex_DlgProc, 0);
+ exAllowContinue = fAllowContinue;
+ if(IDCANCEL == exLastResult)
+ ExitProcess(1);
+ return 1;
+}
+
+CRTException::CRTException(const char *szMsg, const wchar_t *szParam) : std::runtime_error(std::string(szMsg))
+{
+ mir_sntprintf(m_szParam, MAX_PATH, szParam);
+}
+
+void CRTException::display() const
+{
+ wchar_t* tszMsg = mir_a2t(what());
+ wchar_t tszBoxMsg[500];
+
+ mir_sntprintf(tszBoxMsg, 500, _T("%s\n\n(%s)"), tszMsg, m_szParam);
+ ::MessageBox(0, tszBoxMsg, _T("ClistNG runtime error"), MB_OK | MB_ICONERROR);
+ mir_free(tszMsg);
+}
+
diff --git a/plugins/Clist_ng/SRC/contact.cpp b/plugins/Clist_ng/SRC/contact.cpp new file mode 100644 index 0000000000..919b49938c --- /dev/null +++ b/plugins/Clist_ng/SRC/contact.cpp @@ -0,0 +1,329 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: contact.cpp 116 2010-09-11 10:40:18Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+struct {
+ int status,order;
+} statusModeOrder[]={
+ {ID_STATUS_OFFLINE,500},
+ {ID_STATUS_ONLINE,10},
+ {ID_STATUS_AWAY,200},
+ {ID_STATUS_DND,110},
+ {ID_STATUS_NA,450},
+ {ID_STATUS_OCCUPIED,100},
+ {ID_STATUS_FREECHAT,0},
+ {ID_STATUS_INVISIBLE,20},
+ {ID_STATUS_ONTHEPHONE,150},
+ {ID_STATUS_OUTTOLUNCH,425}
+};
+
+static int GetContactStatus(MCONTACT hContact)
+{
+ char *szProto;
+
+ szProto = GetContactProto(hContact);
+ if (szProto == NULL)
+ return ID_STATUS_OFFLINE;
+ return cfg::getWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+}
+
+int __forceinline GetStatusModeOrdering(int statusMode)
+{
+ int i;
+ for (i = 0; i < sizeof(statusModeOrder) / sizeof(statusModeOrder[0]); i++) {
+ if (statusModeOrder[i].status == statusMode)
+ return statusModeOrder[i].order;
+ }
+ return 1000;
+}
+
+int mf_updatethread_running = TRUE;
+HANDLE hThreadMFUpdate = 0;
+
+/**
+ * calculate message frequency for a single contact
+ */
+static void MF_CalcFrequency(MCONTACT hContact, DWORD dwCutoffDays, int doSleep)
+{
+ DWORD curTime = time(NULL);
+ DWORD frequency, eventCount;
+ DBEVENTINFO dbei = {0};
+ MEVENT hEvent = db_event_last(hContact);
+
+ eventCount = 0;
+ dbei.cbSize = sizeof(dbei);
+ dbei.timestamp = 0;
+
+ while(hEvent) {
+ dbei.cbBlob = 0;
+ dbei.pBlob = NULL;
+ db_event_get(hEvent, &dbei);
+
+ if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { // record time of last event
+ eventCount++;
+ }
+ /*
+ * consider the most recent 100 messages and ignore messages that are older than the cutoff days.
+ * this will prevent contacts with a high message rate in the past to keep occupying the
+ * top positions forever.
+ */
+ if(eventCount >= 100 || dbei.timestamp < curTime - (dwCutoffDays * 86400))
+ break;
+ hEvent = db_event_prev(hContact, hEvent);
+ // check for main update thread still running (if not, application is shutting down, so terminate our work)
+ if(doSleep && mf_updatethread_running == FALSE)
+ return;
+ if(doSleep)
+ Sleep(100);
+ }
+
+ if(eventCount == 0) {
+ frequency = 0x7fffffff;
+ cfg::writeDword(hContact, "CList", "mf_firstEvent", curTime - (dwCutoffDays * 86400));
+ }
+ else {
+ frequency = (curTime - dbei.timestamp) / eventCount;
+ cfg::writeDword(hContact, "CList", "mf_firstEvent", dbei.timestamp);
+ }
+
+ cfg::writeDword(hContact, "CList", "mf_freq", frequency);
+ cfg::writeDword(hContact, "CList", "mf_count", eventCount);
+}
+
+extern wchar_t g_ptszEventName[];
+
+/**
+ * This background thread iterates over database contacts and calculates the message frequency
+ * which can be used to sort conctacts based on how frequent they are used as chat partners.
+ * it runs at low priority and scans one contact every 5 seconds. Once it's finished, it will
+ * wait another 1000 seconds and then repeat the process.
+*/
+void MF_UpdateThread(LPVOID)
+{
+ HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, g_ptszEventName);
+
+ WaitForSingleObject(hEvent, 20000);
+ ResetEvent(hEvent);
+
+ while (mf_updatethread_running) {
+ for (MCONTACT hContact = db_find_first(); hContact && mf_updatethread_running; hContact = db_find_next(hContact)) {
+ MF_CalcFrequency(hContact, 50, 1);
+ if (mf_updatethread_running)
+ WaitForSingleObject(hEvent, 5000);
+ ResetEvent(hEvent);
+ }
+ if (mf_updatethread_running)
+ WaitForSingleObject(hEvent, 1000000);
+ ResetEvent(hEvent);
+ }
+ CloseHandle(hEvent);
+}
+
+static BOOL mc_hgh_removed = FALSE;
+
+void CLC::LoadContactTree()
+{
+ MCONTACT hContact;
+ int i, status, hideOffline;
+ BYTE bMsgFrequency = cfg::getByte("CList", "fhistdata", 0);
+
+ CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0);
+ for (i = 1; ; i++) {
+ if (pcli->pfnGetGroupName(i, NULL) == NULL)
+ break;
+ CallService(MS_CLUI_GROUPADDED, i, 0);
+ }
+
+ hideOffline = cfg::getByte("CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ hContact = db_find_first();
+ while (hContact != NULL) {
+ status = GetContactStatus(hContact);
+ if ((!hideOffline || status != ID_STATUS_OFFLINE) && !CLVM_GetContactHiddenStatus(hContact, NULL, NULL))
+ pcli->pfnChangeContactIcon(hContact, IconFromStatusMode(GetContactProto(hContact), status, hContact, NULL), 1);
+
+ // build initial data for message frequency
+ if(!bMsgFrequency)
+ MF_CalcFrequency(hContact, 100, 0);
+
+ hContact = db_find_next(hContact);
+ }
+ cfg::writeByte("CList", "fhistdata", 1);
+ mc_hgh_removed = TRUE;
+ //CallService(MS_CLUI_SORTLIST, 0, 0);
+ CallService(MS_CLUI_LISTENDREBUILD, 0, 0);
+}
+
+DWORD INTSORT_GetLastMsgTime(MCONTACT hContact)
+{
+ for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get(hDbEvent, &dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT))
+ return dbei.timestamp;
+ }
+ return 0;
+}
+
+int __forceinline GetProtoIndex(char * szName)
+{
+ if ( !szName )
+ return -1;
+ else {
+ PROTOACCOUNT* pa = Proto_GetAccount( szName );
+ return ( pa == NULL ) ? -1 : pa->iOrder;
+ }
+}
+
+static int __forceinline INTSORT_CompareContacts(const struct ClcContact* c1, const struct ClcContact* c2, UINT bywhat)
+{
+ wchar_t *namea, *nameb;
+ int statusa, statusb;
+ char *szProto1, *szProto2;
+ int rc;
+
+ if (c1 == 0 || c2 == 0)
+ return 0;
+
+ szProto1 = c1->proto;
+ szProto2 = c2->proto;
+ statusa = c1->wStatus;
+ statusb = c2->wStatus;
+ // make sure, sticky contacts are always at the beginning of the group/list
+
+ if ((c1->flags & CONTACTF_STICKY) != (c2->flags & CONTACTF_STICKY))
+ return 2 * (c2->flags & CONTACTF_STICKY) - 1;
+
+ if(bywhat == SORTBY_PRIOCONTACTS) {
+ if((cfg::clcdat->exStyle & CLS_EX_DIVIDERONOFF) && ((c1->flags & CONTACTF_ONLINE) != (c2->flags & CONTACTF_ONLINE)))
+ return 0;
+ if ((c1->flags & CONTACTF_PRIORITY) != (c2->flags & CONTACTF_PRIORITY))
+ return 2 * (c2->flags & CONTACTF_PRIORITY) - 1;
+ else
+ return 0;
+ }
+
+ if (bywhat == SORTBY_STATUS) {
+ int ordera, orderb;
+
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ else
+ return 0;
+ }
+
+ // separate contacts treated as "offline"
+ if ( !cfg::dat.bDontSeparateOffline && ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE )))
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+
+ switch( bywhat ) {
+ case SORTBY_NAME:
+ namea = (wchar_t *)c1->szText;
+ nameb = (wchar_t *)c2->szText;
+ return CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, namea, -1, nameb, -1) - 2;
+
+ case SORTBY_LASTMSG:
+ if(c1->extraCacheEntry >= 0 && c1->extraCacheEntry < cfg::nextCacheEntry &&
+ c2->extraCacheEntry >= 0 && c2->extraCacheEntry < cfg::nextCacheEntry)
+ return(cfg::eCache[c2->extraCacheEntry].dwLastMsgTime - cfg::eCache[c1->extraCacheEntry].dwLastMsgTime);
+ else {
+ DWORD timestamp1 = INTSORT_GetLastMsgTime(c1->hContact);
+ DWORD timestamp2 = INTSORT_GetLastMsgTime(c2->hContact);
+ return timestamp2 - timestamp1;
+ }
+
+ case SORTBY_FREQUENCY:
+ if ( c1->extraCacheEntry >= 0 && c1->extraCacheEntry < cfg::nextCacheEntry &&
+ c2->extraCacheEntry >= 0 && c2->extraCacheEntry < cfg::nextCacheEntry )
+ return(cfg::eCache[c1->extraCacheEntry].msgFrequency - cfg::eCache[c2->extraCacheEntry].msgFrequency);
+ break;
+
+ case SORTBY_PROTO:
+ if(c1->bIsMeta)
+ szProto1 = c1->metaProto ? c1->metaProto : c1->proto;
+ if(c2->bIsMeta)
+ szProto2 = c2->metaProto ? c2->metaProto : c2->proto;
+
+ rc = GetProtoIndex(szProto1) - GetProtoIndex(szProto2);
+
+ if (rc != 0 && (szProto1 != NULL && szProto2 != NULL))
+ return rc;
+ }
+ return 0;
+}
+
+int CLC::CompareContacts(const ClcContact* c1, const ClcContact* c2)
+{
+ int i, result;
+
+ result = INTSORT_CompareContacts(c1, c2, SORTBY_PRIOCONTACTS);
+ if(result)
+ return result;
+
+ for(i = 0; i <= 2; i++) {
+ if(cfg::dat.sortOrder[i]) {
+ result = INTSORT_CompareContacts(c1, c2, cfg::dat.sortOrder[i]);
+ if(result != 0)
+ return result;
+ }
+ }
+ return 0;
+}
+
+#undef SAFESTRING
+
+static int resortTimerId = 0;
+static VOID CALLBACK SortContactsTimer(HWND hwnd, UINT message, UINT idEvent, DWORD dwTime)
+{
+ KillTimer(NULL, resortTimerId);
+ resortTimerId = 0;
+ //CallService(MS_CLUI_SORTLIST, 0, 0);
+}
+
+int CLC::SetHideOffline(WPARAM wParam, LPARAM lParam)
+{
+ switch ((int) wParam) {
+ case 0:
+ cfg::writeByte("CList", "HideOffline", 0);
+ break;
+ case 1:
+ cfg::writeByte("CList", "HideOffline", 1);
+ break;
+ case -1:
+ cfg::writeByte("CList", "HideOffline", (BYTE) ! cfg::getByte("CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)); break;
+ }
+ CLUI::setButtonStates(pcli->hwndContactList);
+ CLC::LoadContactTree();
+ return 0;
+}
diff --git a/plugins/Clist_ng/SRC/extBackg.cpp b/plugins/Clist_ng/SRC/extBackg.cpp new file mode 100644 index 0000000000..cdfdc00ebd --- /dev/null +++ b/plugins/Clist_ng/SRC/extBackg.cpp @@ -0,0 +1,714 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * parts (C) by pixel, written many years ago for the original
+ * clist_nicer plugin.
+ * $Id: extBackg.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include "../coolsb/coolscroll.h"
+
+extern HWND g_hwndViewModeFrame;
+extern struct CluiTopButton top_buttons[];
+
+void ReloadThemedOptions();
+
+
+TStatusItem DefaultStatusItems[ID_EXTBK_LAST_D + 1] = {
+ {"Offline", ID_EXTBKOFFLINE,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Online", ID_EXTBKONLINE,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Away", ID_EXTBKAWAY,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"DND", ID_EXTBKDND,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"NA", ID_EXTBKNA,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Occupied", ID_EXTBKOCCUPIED,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Free for chat", ID_EXTBKFREECHAT,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Invisible", ID_EXTBKINVISIBLE,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"On the phone", ID_EXTBKONTHEPHONE,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Out to lunch", ID_EXTBKOUTTOLUNCH,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Idle", ID_EXTBKIDLE,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"{-}Expanded Group", ID_EXTBKEXPANDEDGROUP,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Collapsed Group", ID_EXTBKCOLLAPSEDDGROUP,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Empty Group", ID_EXTBKEMPTYGROUPS,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"{-}First contact of a group", ID_EXTBKFIRSTITEM,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Single item in group", ID_EXTBKSINGLEITEM,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Last contact of a group", ID_EXTBKLASTITEM,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"{-}First contact of NON-group", ID_EXTBKFIRSTITEM_NG,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Single item in NON-group", ID_EXTBKSINGLEITEM_NG,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Last contact of NON-group", ID_EXTBKLASTITEM_NG,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, 0, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"{-}Even rows", ID_EXTBKEVEN_CNTCTPOS,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"Odd rows", ID_EXTBKODD_CNTCTPOS,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"{-}Selection", ID_EXTBKSELECTION,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"Hottracked", ID_EXTBKHOTTRACK,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"{-}Frame titlebars", ID_EXTBKFRAMETITLE,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 0
+ }, {"Event area", ID_EXTBKEVTAREA,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 0
+ }, {"Status Bar", ID_EXTBKSTATUSBAR,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1
+ }, {"{-}UI Button pressed", ID_EXTBKBUTTONSPRESSED,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"UI Button normal", ID_EXTBKBUTTONSNPRESSED,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"UI Button hover", ID_EXTBKBUTTONSMOUSEOVER,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"{-}Status floater", ID_EXTBKSTATUSFLOATER,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+ }, {"{-}Frame border no titlebar", ID_EXTBKOWNEDFRAMEBORDER,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, 1,
+ 1, 1, 1, CLCDEFAULT_IGNORE, S_ITEM_IMAGE_ONLY
+ }, {"Frame border with titlebar", ID_EXTBKOWNEDFRAMEBORDERTB,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, 1,
+ CLCDEFAULT_MRGN_TOP, 1, 1, CLCDEFAULT_IGNORE, S_ITEM_IMAGE_ONLY
+ }, {"{-}Avatarframe", ID_EXTBKAVATARFRAME,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1, S_ITEM_IMAGE_ONLY
+ }, {"Avatarframe offline", ID_EXTBKAVATARFRAMEOFFLINE,
+ CLCDEFAULT_GRADIENT,CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT,
+ CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, 1, S_ITEM_IMAGE_ONLY
+ }
+};
+
+void SetButtonToSkinned()
+{
+ int bSkinned = cfg::dat.bSkinnedButtonMode = cfg::getByte("CLCExt", "bskinned", 0);
+
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBMENU, BM_SETSKINNED, 0, bSkinned);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBGLOBALSTATUS, BM_SETSKINNED, 0, bSkinned);
+ if(bSkinned) {
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBMENU, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBGLOBALSTATUS, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBGLOBALSTATUS, BUTTONSETASFLATBTN + 10, 0, 0);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBMENU, BUTTONSETASFLATBTN + 10, 0, 0);
+ }
+ else {
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBMENU, BUTTONSETASFLATBTN, 0, 1);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBGLOBALSTATUS, BUTTONSETASFLATBTN, 0, 1);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBGLOBALSTATUS, BUTTONSETASFLATBTN + 10, 0, 1);
+ SendDlgItemMessage(pcli->hwndContactList, IDC_TBMENU, BUTTONSETASFLATBTN + 10, 0, 1);
+ }
+ SendMessage(g_hwndViewModeFrame, WM_USER + 100, 0, 0);
+}
+
+TStatusItem *GetProtocolStatusItem(const char *szProto)
+{
+ int i;
+
+ if(szProto == NULL)
+ return NULL;
+
+ for(i = ID_EXTBK_LAST_D + 1; i <= Skin::ID_EXTBK_LAST; i++) {
+ if(!strcmp(Skin::statusItems[i].szName[0] == '{' ? &Skin::statusItems[i].szName[3] : Skin::statusItems[i].szName, szProto))
+ return &Skin::statusItems[i];
+ }
+ return NULL;
+}
+
+// Save Non-StatusItems Settings
+void SaveNonStatusItemsSettings(HWND hwndDlg)
+{
+ BOOL translated;
+
+ cfg::dat.bApplyIndentToBg = IsDlgButtonChecked(hwndDlg, IDC_APPLYINDENTBG) ? 1 : 0;
+ cfg::dat.bUsePerProto = IsDlgButtonChecked(hwndDlg, IDC_USEPERPROTO) ? 1 : 0;
+ cfg::dat.bOverridePerStatusColors = IsDlgButtonChecked(hwndDlg, IDC_OVERRIDEPERSTATUSCOLOR) ? 1 : 0;
+ cfg::dat.titleBarHeight = (BYTE)GetDlgItemInt(hwndDlg, IDC_LASTITEMPADDING, &translated, FALSE);
+ cfg::dat.group_padding = GetDlgItemInt(hwndDlg, IDC_GRPTOPPADDING, &translated, FALSE);
+
+ cfg::writeByte("CLCExt", "applyindentbg", (BYTE)cfg::dat.bApplyIndentToBg);
+ cfg::writeByte("CLCExt", "useperproto", (BYTE)cfg::dat.bUsePerProto);
+ cfg::writeByte("CLCExt", "override_status", (BYTE)cfg::dat.bOverridePerStatusColors);
+ cfg::writeByte("CLCExt", "bskinned", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SETALLBUTTONSKINNED) ? 1 : 0));
+ cfg::writeByte("CLC", "IgnoreSelforGroups", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_IGNORESELFORGROUPS));
+
+ cfg::writeDword("CLCExt", "grp_padding", cfg::dat.group_padding);
+ cfg::writeByte("CLCExt", "frame_height", cfg::dat.titleBarHeight);
+
+ SetButtonToSkinned();
+}
+
+
+void extbk_import(char *file, HWND hwndDlg)
+{
+ int n, i;
+ char buffer[255];
+ char szKey[255], szSection[255];
+ DWORD data, version = 0;
+ int oldexIconScale = cfg::dat.exIconScale;
+
+ data = 0;
+ GetPrivateProfileStructA("Global", "Version", &version, 4, file);
+ if(version >= 2) {
+ for(n = 0; n <= FONTID_LAST; n++) {
+ mir_snprintf(szSection, 255, "Font%d", n);
+
+ mir_snprintf(szKey, 255, "Font%dName", n);
+ GetPrivateProfileStringA(szSection, "Name", "Arial", buffer, sizeof(buffer), file);
+ cfg::writeString(NULL, "CLC", szKey, buffer);
+
+ mir_snprintf(szKey, 255, "Font%dSize", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "Size", &data, 1, file);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dSty", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "Style", &data, 1, file);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dSet", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "Set", &data, 1, file);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dCol", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "Color", &data, 4, file);
+ cfg::writeDword("CLC", szKey, data);
+
+ mir_snprintf(szKey, 255, "Font%dFlags", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "Flags", &data, 4, file);
+ cfg::writeDword("CLC", szKey, (WORD)data);
+
+ mir_snprintf(szKey, 255, "Font%dAs", n);
+ data = 0;
+ GetPrivateProfileStructA(szSection, "SameAs", &data, 2, file);
+ cfg::writeDword("CLC", szKey, (WORD)data);
+ }
+ }
+ i = 0;
+
+ ReloadThemedOptions();
+ // refresh
+ if(hwndDlg && ServiceExists(MS_CLNSE_FILLBYCURRENTSEL))
+ CallService(MS_CLNSE_FILLBYCURRENTSEL, (WPARAM)hwndDlg, 0);
+ pcli->pfnClcOptionsChanged();
+ CLUI::configureGeometry(1);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ CLUI::Redraw();
+ if(oldexIconScale != cfg::dat.exIconScale) {
+ ImageList_SetIconSize(CLUI::hExtraImages, cfg::dat.exIconScale, cfg::dat.exIconScale);
+ IcoLibReloadIcons();
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ }
+}
+
+static void ApplyCLUISkin()
+{
+ DBVARIANT dbv = {0};
+ wchar_t tszFinalName[MAX_PATH];
+ char szFinalName[MAX_PATH];
+ if(!cfg::getTString(NULL, "CLC", "AdvancedSkin", &dbv)) {
+ Utils::pathToAbsolute(dbv.ptszVal, tszFinalName);
+ WideCharToMultiByte(CP_ACP, 0, tszFinalName, MAX_PATH, szFinalName, MAX_PATH, 0, 0);
+ if(cfg::getByte("CLUI", "skin_changed", 0)) {
+ extbk_import(szFinalName, 0);
+ //SaveCompleteStructToDB();
+ cfg::writeByte("CLUI", "skin_changed", 0);
+ }
+ //IMG_LoadItems();
+ ShowWindow(pcli->hwndContactList, SW_SHOWNORMAL);
+ SetWindowPos(pcli->hwndContactList, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ SendMessage(pcli->hwndContactList, WM_SIZE, 0, 0);
+ RedrawWindow(pcli->hwndContactList, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE);
+ db_free(&dbv);
+ }
+}
+
+/**
+ * scan a single skin directory and find the .TSK file. Fill the combobox and set the
+ * relative path name as item extra data.
+ *
+ * If available, read the Name property from the [Global] section and use it in the
+ * combo box. If such property is not found, the base filename (without .tsk extension)
+ * will be used as the name of the skin.
+ *
+ */
+static int ScanSkinDir(const wchar_t* tszFolder, HWND hwndCombobox)
+{
+ WIN32_FIND_DATA fd = {0};
+ bool fValid = false;
+ wchar_t tszMask[MAX_PATH];
+
+ mir_sntprintf(tszMask, MAX_PATH, L"%s*.*", tszFolder);
+
+ HANDLE h = FindFirstFile(tszMask, &fd);
+
+ while(h != INVALID_HANDLE_VALUE) {
+ if(lstrlenW(fd.cFileName) >= 5 && !wcsncmp(fd.cFileName + lstrlenW(fd.cFileName) - 4, L".cng", 4)) {
+ fValid = true;
+ break;
+ }
+ if(FindNextFileW(h, &fd) == 0)
+ break;
+ }
+ if(h != INVALID_HANDLE_VALUE)
+ FindClose(h);
+
+ if(fValid) {
+ TCHAR tszFinalName[MAX_PATH], tszRel[MAX_PATH];
+ LRESULT lr;
+ TCHAR szBuf[255];
+
+ mir_sntprintf(tszFinalName, MAX_PATH, _T("%s%s"), tszFolder, fd.cFileName);
+
+ GetPrivateProfileStringW(L"SkinInfo", L"Name", L"None", szBuf, 500, tszFinalName);
+ if(!wcscmp(szBuf, L"None")) {
+ fd.cFileName[lstrlenW(fd.cFileName) - 4] = 0;
+ mir_sntprintf(szBuf, 255, L"%s", fd.cFileName);
+ }
+
+ Utils::pathToRelative(tszFinalName, tszRel, cfg::szProfileDir);
+ if((lr = SendMessageW(hwndCombobox, CB_INSERTSTRING, -1, (LPARAM)szBuf)) != CB_ERR) {
+ wchar_t* idata = (wchar_t *)malloc((lstrlenW(tszRel) + 1) * sizeof(wchar_t));
+
+ wcscpy(idata, tszRel);
+ SendMessageW(hwndCombobox, CB_SETITEMDATA, lr, (LPARAM)idata);
+ }
+ }
+ return(0);
+}
+
+/**
+ * scan the skin root folder for subfolder(s). Each folder is supposed to contain a single
+ * skin. This function won't dive deeper into the folder structure, so the folder
+ * structure for any VALID skin should be:
+ * $SKINS_ROOT/skin_folder/skin_name.tsk
+ *
+ * By default, $SKINS_ROOT is set to %miranda_userdata% or custom folder
+ * selected by the folders plugin.
+ */
+static int RescanSkins(HWND hwndCombobox)
+{
+ WIN32_FIND_DATA fd = {0};
+ wchar_t tszSkinRoot[MAX_PATH], tszFindMask[MAX_PATH];
+ DBVARIANT dbv = {0};
+
+
+ mir_sntprintf(tszSkinRoot, MAX_PATH, L"%sskin\\clng\\", cfg::szProfileDir);
+
+ SetDlgItemTextW(GetParent(hwndCombobox), IDC_SKINROOTFOLDER, tszSkinRoot);
+ mir_sntprintf(tszFindMask, MAX_PATH, L"%s*.*", tszSkinRoot);
+
+ SendMessageW(hwndCombobox, CB_RESETCONTENT, 0, 0);
+ SendMessageW(hwndCombobox, CB_INSERTSTRING, -1, (LPARAM)TranslateW(L"<none>"));
+
+ HANDLE h = FindFirstFileW(tszFindMask, &fd);
+ while (h != INVALID_HANDLE_VALUE) {
+ if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && fd.cFileName[0] != '.') {
+ TCHAR tszSubDir[MAX_PATH];
+ mir_sntprintf(tszSubDir, MAX_PATH, _T("%s%s\\"), tszSkinRoot, fd.cFileName);
+ ScanSkinDir(tszSubDir, hwndCombobox);
+ }
+ if(FindNextFile(h, &fd) == 0)
+ break;
+ }
+ if(h != INVALID_HANDLE_VALUE)
+ FindClose(h);
+
+
+ SendMessage(hwndCombobox, CB_SETCURSEL, 0, 0);
+ if(0 == cfg::getTString(0, SKIN_DB_MODULE, "gCurrentSkin", &dbv)) {
+ LRESULT lr = SendMessage(hwndCombobox, CB_GETCOUNT, 0, 0);
+ for(int i = 1; i < lr; i++) {
+
+ wchar_t* idata = (wchar_t *)SendMessage(hwndCombobox, CB_GETITEMDATA, i, 0);
+ if(idata && idata != (wchar_t *)CB_ERR) {
+ if(!wcsicmp(dbv.ptszVal, idata)) {
+ SendMessage(hwndCombobox, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ }
+ db_free(&dbv);
+ }
+ return(0);
+}
+
+/**
+ * free the item extra data (used to store the skin filenames for
+ * each entry).
+ */
+static void TSAPI FreeComboData(HWND hwndCombobox)
+{
+ LRESULT lr = SendMessage(hwndCombobox, CB_GETCOUNT, 0, 0);
+
+ for(int i = 1; i < lr; i++) {
+ void *idata = (void *)SendMessage(hwndCombobox, CB_GETITEMDATA, i, 0);
+
+ if(idata && idata != (void *)CB_ERR)
+ free(idata);
+ }
+}
+
+
+INT_PTR CALLBACK cfg::DlgProcSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ RescanSkins(GetDlgItem(hwndDlg, IDC_SKINNAME));
+
+ CheckDlgButton(hwndDlg, IDC_SETALLBUTTONSKINNED, cfg::getByte("CLCExt", "bskinned", 0));
+
+ SendDlgItemMessage(hwndDlg, IDC_GRPPADDINGSPIN, UDM_SETRANGE, 0, MAKELONG(20, 0));
+ SendDlgItemMessage(hwndDlg, IDC_GRPPADDINGSPIN, UDM_SETPOS, 0, cfg::dat.group_padding);
+
+ SendDlgItemMessage(hwndDlg, IDC_LASTITEMPADDINGSPIN, UDM_SETRANGE, 0, MAKELONG(40, 0));
+ SendDlgItemMessage(hwndDlg, IDC_LASTITEMPADDINGSPIN, UDM_SETPOS, 0, cfg::dat.titleBarHeight);
+
+ CheckDlgButton(hwndDlg, IDC_APPLYINDENTBG, cfg::dat.bApplyIndentToBg);
+ CheckDlgButton(hwndDlg, IDC_USEPERPROTO, cfg::dat.bUsePerProto);
+ CheckDlgButton(hwndDlg, IDC_OVERRIDEPERSTATUSCOLOR, cfg::dat.bOverridePerStatusColors);
+ CheckDlgButton(hwndDlg, IDC_IGNORESELFORGROUPS, cfg::getByte("CLC", "IgnoreSelforGroups", 0) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_UNLOAD:
+ break;
+ case IDC_RELOADSKIN: {
+ DBVARIANT dbv = {0};
+ wchar_t wszSkinName[MAX_PATH];
+
+ if(0 == cfg::getTString(0, SKIN_DB_MODULE, "gCurrentSkin", &dbv)) {
+ Utils::pathToAbsolute(dbv.ptszVal, wszSkinName, cfg::szProfileDir);
+ if(PathFileExistsW(wszSkinName)) {
+ ShowWindow(pcli->hwndContactList, SW_HIDE);
+ Skin::Unload();
+ SkinLoader *s = new SkinLoader(wszSkinName);
+ if(s->isValid())
+ s->Load();
+
+ delete s;
+ Skin::Activate();
+ ShowWindow(pcli->hwndContactList, SW_SHOW);
+ }
+ db_free(&dbv);
+ }
+ break;
+ }
+
+ case IDC_HELP_GENERAL:
+ //CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://blog.miranda.or.at/tabsrmm/skin-selection-changes/");
+ break;
+
+ case IDC_RESCANSKIN:
+ FreeComboData(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ RescanSkins(GetDlgItem(hwndDlg, IDC_SKINNAME));
+ break;
+
+ case IDC_SKINNAME: {
+ if(HIWORD(wParam) == CBN_SELCHANGE) {
+ LRESULT lr = SendDlgItemMessageW(hwndDlg, IDC_SKINNAME, CB_GETCURSEL, 0 ,0);
+ if(lr != CB_ERR && lr > 0) {
+ wchar_t *tszRelPath = (TCHAR *)SendDlgItemMessageW(hwndDlg, IDC_SKINNAME, CB_GETITEMDATA, lr, 0);
+ if(tszRelPath && tszRelPath != (wchar_t *)CB_ERR)
+ cfg::writeTString(0, SKIN_DB_MODULE, "gCurrentSkin", tszRelPath);
+ SendMessageW(hwndDlg, WM_COMMAND, IDC_RELOADSKIN, 0);
+ }
+ else if(lr == 0) // selected the <no skin> entry
+ db_unset(0, SKIN_DB_MODULE, "gCurrentSkin");
+ return(0);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ SaveNonStatusItemsSettings(hwndDlg);
+ pcli->pfnClcOptionsChanged();
+ PostMessage(pcli->hwndContactList, CLUIINTM_REDRAW, 0, 0);
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK cfg::SkinOptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+ static HWND hwndSkinEdit = 0;
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCITEM tci;
+ RECT rcClient;
+ int oPage = cfg::getByte("CLUI", "s_opage", 0);
+ SKINDESCRIPTION sd;
+
+ TranslateDialogDefault(hwnd);
+ GetClientRect(hwnd, &rcClient);
+ iInit = TRUE;
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)CreateDialog(g_hInst,MAKEINTRESOURCE(IDD_OPT_SKIN), hwnd, cfg::DlgProcSkinOpts);
+ tci.pszText = TranslateT("Load and apply");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 0, &tci);
+ MoveWindow((HWND)tci.lParam,5,25,rcClient.right-9,rcClient.bottom-65,1);
+ ShowWindow((HWND)tci.lParam, oPage == 0 ? SW_SHOW : SW_HIDE);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+
+ ZeroMemory(&sd, sizeof(sd));
+ sd.cbSize = sizeof(sd);
+ sd.StatusItems = Skin::statusItems;
+ sd.hWndParent = hwnd;
+ sd.hWndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB);
+ sd.pfnSaveCompleteStruct = 0; //SaveCompleteStructToDB;
+ sd.lastItem = Skin::ID_EXTBK_LAST;
+ sd.firstItem = ID_EXTBKOFFLINE;
+ sd.pfnClcOptionsChanged = pcli->pfnClcOptionsChanged;
+ sd.hwndCLUI = pcli->hwndContactList;
+ hwndSkinEdit = SkinEdit_Invoke(0, (LPARAM)&sd);
+
+ if(hwndSkinEdit) {
+ ShowWindow(hwndSkinEdit, oPage == 1 ? SW_SHOW : SW_HIDE);
+ ShowWindow(sd.hwndImageEdit, oPage == 2 ? SW_SHOW : SW_HIDE);
+ TabCtrl_SetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB), oPage);
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture(hwndSkinEdit, ETDT_ENABLETAB);
+ }
+ Utils::enableDlgControl(hwnd, IDC_EXPORT, TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)) != 0);
+ Utils::enableDlgControl(hwnd, IDC_SAVEASMOD, TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)) != 0);
+ iInit = FALSE;
+ return FALSE;
+ }
+
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_EXPORT:
+ {
+ char str[MAX_PATH] = "*.cng";
+ char szBaseFolder[MAX_PATH];
+ OPENFILENAMEA ofn = {0};
+
+ if(WarningDlg::show(WarningDlg::WARN_SKIN_OVERWRITE, MB_YESNOCANCEL | MB_ICONWARNING | WarningDlg::CWF_NOALLOWHIDE, 0) != IDYES)
+ break;
+
+ WideCharToMultiByte(CP_ACP, 0, Skin::settings.wszSkinBaseFolder, -1, szBaseFolder, MAX_PATH, 0, 0);
+
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwnd;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = "*.cng";
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.nMaxFile = sizeof(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "cng";
+
+ ofn.lpstrInitialDir = szBaseFolder;
+ if (!GetSaveFileNameA(&ofn))
+ break;
+ Skin::exportToFile(str);
+ Skin::exportSettingsToFile(str);
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count;
+ tci.mask = TCIF_PARAM;
+ count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ for (i=0;i<count;i++)
+ {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ }
+ }
+ break;
+ }
+ break;
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ cfg::writeByte("CLUI", "s_opage", (BYTE)TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)));
+ Utils::enableDlgControl(hwnd, IDC_EXPORT, TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)) != 0);
+ Utils::enableDlgControl(hwnd, IDC_SAVEASMOD, TabCtrl_GetCurSel(GetDlgItem(hwnd, IDC_OPTIONSTAB)) != 0);
+ }
+ break;
+ }
+ break;
+
+ }
+ break;
+ case WM_DESTROY:
+ hwndSkinEdit = 0;
+ break;
+ }
+ return FALSE;
+}
+
+int CoolSB_SetupScrollBar(HWND hwnd)
+{
+ cfg::dat.bSkinnedScrollbar = TRUE;
+
+ if(cfg::getByte("CLC", "NoVScrollBar", 0)) {
+ UninitializeCoolSB(hwnd);
+ return 0;
+ }
+ if(cfg::dat.bSkinnedScrollbar) {
+ InitializeCoolSB(hwnd);
+ CoolSB_SetStyle(hwnd, SB_VERT, CSBS_HOTTRACKED);
+ }
+ else
+ UninitializeCoolSB(hwnd);
+ return 0;
+}
diff --git a/plugins/Clist_ng/SRC/gfx.cpp b/plugins/Clist_ng/SRC/gfx.cpp new file mode 100644 index 0000000000..3055ff8ef7 --- /dev/null +++ b/plugins/Clist_ng/SRC/gfx.cpp @@ -0,0 +1,441 @@ +/*
+* astyle --force-indent=tab=4 --brackets=linux --indent-switches
+* --pad=oper --one-line=keep-blocks --unpad=paren
+*
+* Miranda IM: the free IM client for Microsoft* Windows*
+*
+* Copyright 2000-2010 Miranda ICQ/IM project,
+* all portions of this codebase are copyrighted to the people
+* listed in contributors.txt.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* you should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* part of clist_ng plugin for Miranda.
+*
+* (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+*
+* $Id: gfx.cpp 134 2010-10-01 10:23:10Z silvercircle $
+*
+* clist_ng low level graphics code
+*/
+
+#include <commonheaders.h>
+#include <math.h>
+
+#ifdef _USE_D2D
+ ID2D1Factory* Gfx::pD2DFactory = 0;
+#endif
+COLORREF Gfx::txtColor = 0;
+//Gdiplus::GdiplusStartupInput Gfx::gdiPlusStartupInput;
+//ULONG_PTR Gfx::gdiPlusToken;
+
+/**
+ * Create a 32bit RGBA bitmap, compatible for rendering with alpha channel.
+ * Required by anything which would render on a transparent aero surface.
+ * the image is a "bottom up" bitmap, as it has a negative
+ * height. This is a requirement for some UxTheme APIs (e.g.
+ * DrawThemeTextEx).
+ *
+ * @param rc RECT &: the rectangle describing the target area.
+ * @param dc The device context for which the bitmap should be created.
+ *
+ * @return HBITMAP: handle to the bitmap created.
+ */
+
+BYTE* Gfx::m_p = nullptr;
+size_t Gfx::m_sAllocated = 0;
+
+HBITMAP Gfx::createRGBABitmap(const LONG cx, const LONG cy)
+{
+ BITMAPINFO dib = {0};
+
+ dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib.bmiHeader.biWidth = cx;
+ dib.bmiHeader.biHeight = -cy; // use a "topdown" bitmap (0,0 = left, top corner)
+ dib.bmiHeader.biPlanes = 1;
+ dib.bmiHeader.biBitCount = 32;
+ dib.bmiHeader.biCompression = BI_RGB;
+ return(CreateDIBSection(0, &dib, DIB_RGB_COLORS, NULL, NULL, 0 ));
+}
+
+/**
+ * initialize Direct2D, create the factory
+ */
+void Gfx::D2D_Init()
+{
+#ifdef _USE_D2D
+ HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
+#endif
+}
+
+void Gfx::D2D_Release()
+{
+#ifdef _USE_D2D
+ pD2DFactory->Release();
+#endif
+}
+
+void Gfx::deSaturate(HBITMAP hBitmap, bool fReduceContrast)
+{
+ BITMAP bmp;
+ DWORD dwLen;
+ BYTE bMin = 255, bMax = 0, bRamp = 0, bMaxAdjust, bMinAdjust;
+
+ int x, y;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ if(fReduceContrast) {
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ BYTE avg = (px[0] + px[1] + px[2]) / 3;
+ bMin = min(avg, bMin);
+ bMax = max(avg, bMax);
+ px += 4;
+ }
+ }
+ bRamp = (bMax + bMin) / 2;
+ bMaxAdjust = (bMax - bRamp) / 2;
+ bMinAdjust = (bRamp - bMin) / 2;
+ }
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ BYTE avg = (px[0] + px[1] + px[2]) / 3;
+ //if(fReduceContrast)
+ // avg = (avg < bRamp ? avg + bMinAdjust : avg - bMaxAdjust);
+ px[0] = px[1] = px[2] = avg;
+ px += 4;
+ }
+ }
+ SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, m_p);
+}
+
+void Gfx::setBitmapAlpha(HBITMAP hBitmap, BYTE bAlpha)
+{
+ BITMAP bmp;
+ DWORD dwLen;
+ int x, y;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ px[3] = bAlpha;
+ px += 4;
+ }
+ }
+ SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, m_p);
+}
+
+/**
+ * render text using UxTheme (vista+) DrawTextEx() API
+ * @param hdc device context
+ * @param hTheme a valid theme handle
+ * @param szText text to draw
+ * @param rc rectangle where to draw
+ * @param dtFlags flags (same as DrawText())
+ * @param iGlowSize glow size if we want glow, if 0 use solid color
+ * @param clr color to use
+ * @param fForceAero force using composited text with glow
+ * @return return value of DrawText()
+ */
+int Gfx::renderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize, int length, bool fForceAero)
+{
+ if(hTheme || fForceAero) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ if(iGlowSize && (cfg::isAero || fForceAero)) {
+ dto.iGlowSize = iGlowSize;
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ }
+ else {
+ dto.dwFlags = DTT_TEXTCOLOR|DTT_COMPOSITED;//|DTT_SHADOWTYPE|DTT_SHADOWOFFSET|DTT_SHADOWCOLOR|DTT_BORDERSIZE|DTT_BORDERCOLOR;
+ dto.crText = txtColor;
+ }
+ dto.iBorderSize = 10;
+ return(Api::pfnDrawThemeTextEx(hTheme, hdc, BP_PUSHBUTTON, PBS_NORMAL, szText, length, dtFlags, rc, &dto));
+ }
+ else {
+ ::SetTextColor(hdc, txtColor);
+ return(::DrawText(hdc, szText, -1, rc, dtFlags));
+ }
+}
+
+void Gfx::preMultiply(HBITMAP hBitmap, int mode)
+{
+ DWORD dwLen;
+ int width, height, x, y;
+ BITMAP bmp;
+ BYTE alpha;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+ width = bmp.bmWidth;
+ height = bmp.bmHeight;
+ dwLen = width * height * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ if(m_p) {
+ GetBitmapBits(hBitmap, dwLen, m_p);
+ for (y = 0; y < height; ++y) {
+ BYTE *px = m_p + width * 4 * y;
+
+ for (x = 0; x < width; ++x) {
+ if(mode) {
+ alpha = px[3];
+ px[0] = px[0] * alpha/255;
+ px[1] = px[1] * alpha/255;
+ px[2] = px[2] * alpha/255;
+ }
+ else
+ px[3] = 255;
+ px += 4;
+ }
+ }
+ dwLen = SetBitmapBits(hBitmap, dwLen, m_p);
+ }
+}
+
+/**
+ * render a image item on the given target surface.
+ *
+ * @param hdc target HDC
+ * @param item image item
+ * @param rc target rectangle (client coordinates)
+ */
+void __fastcall Gfx::renderImageItem(HDC hdc, TImageItem *item, RECT *rc)
+{
+ BYTE l = item->bLeft, r = item->bRight, t = item->bTop, b = item->bBottom;
+ LONG width = rc->right - rc->left;
+ LONG height = rc->bottom - rc->top;
+ BOOL isGlyph = (item->dwFlags & IMAGE_GLYPH) && Skin::glyphItem;
+ HDC hdcSrc = isGlyph ? Skin::glyphItem->hdc : item->hdc;
+ LONG srcOrigX = isGlyph ? item->glyphMetrics[0] : 0;
+ LONG srcOrigY = isGlyph ? item->glyphMetrics[1] : 0;
+
+ if(item->dwFlags & IMAGE_FLAG_DIVIDED) {
+ // top 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top, l, t, hdcSrc, srcOrigX, srcOrigY, l, t, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->top, width - l - r, t, hdcSrc, srcOrigX + l, srcOrigY, item->inner_width, t, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->top, r, t, hdcSrc, srcOrigX + (item->width - r), srcOrigY, r, t, item->bf);
+ // middle 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top + t, l, height - t - b, hdcSrc, srcOrigX, srcOrigY + t, l, item->inner_height, item->bf);
+
+ if(item->dwFlags & IMAGE_FILLSOLID && item->fillBrush) {
+ RECT rcFill;
+ rcFill.left = rc->left + l; rcFill.top = rc->top +t;
+ rcFill.right = rc->right - r; rcFill.bottom = rc->bottom - b;
+ FillRect(hdc, &rcFill, item->fillBrush);
+ }
+ else
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->top + t, width - l - r, height - t - b, hdcSrc, srcOrigX + l, srcOrigY + t, item->inner_width, item->inner_height, item->bf);
+
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->top + t, r, height - t - b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + t, r, item->inner_height, item->bf);
+
+ // bottom 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->bottom - b, l, b, hdcSrc, srcOrigX, srcOrigY + (item->height - b), l, b, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->bottom - b, width - l - r, b, hdcSrc, srcOrigX + l, srcOrigY + (item->height - b), item->inner_width, b, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->bottom - b, r, b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + (item->height - b), r, b, item->bf);
+ }
+ else {
+ switch(item->bStretch) {
+ case IMAGE_STRETCH_H:
+ // tile image vertically, stretch to width
+ {
+ LONG top = rc->top;
+
+ do {
+ if(top + item->height <= rc->bottom) {
+ Api::pfnAlphaBlend(hdc, rc->left, top, width, item->height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ top += item->height;
+ }
+ else {
+ Api::pfnAlphaBlend(hdc, rc->left, top, width, rc->bottom - top, hdcSrc, srcOrigX, srcOrigY, item->width, rc->bottom - top, item->bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_V:
+ // tile horizontally, stretch to height
+ {
+ LONG left = rc->left;
+
+ do {
+ if(left + item->width <= rc->right) {
+ Api::pfnAlphaBlend(hdc, left, rc->top, item->width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ left += item->width;
+ }
+ else {
+ Api::pfnAlphaBlend(hdc, left, rc->top, rc->right - left, height, hdcSrc, srcOrigX, srcOrigY, rc->right - left, item->height, item->bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_B:
+ // stretch the image in both directions...
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top, width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * colorize an image item (both standalone items with their own bitmap and glyph items).
+ *
+ * @param item image item to colorize
+ * @param clr color to use (note: BGRA format required, although, alpha is ignored)
+ * @param hue hue adjustment (in degrees, -180 .. +180
+ * @param saturation scalar value (0.0 ... 1.0)
+ * @param value scalar value (0.0 ... 1.0)
+ *
+ * note: this isn't performance critical as it only runs at skin loading time or when
+ * the user changes colorization options, never during rendering.
+ *
+ * if clr == 0, hsv transformation will be applied, otherwise it's rgb colorization.
+ */
+void Gfx::colorizeGlyph(TImageItem *item, const COLORREF clr, float hue, float saturation, float value)
+{
+ LONG stride = 0, line, pixel;
+ HBITMAP hBitmap = 0;
+ LONG x, y, x1, y1;
+ BITMAP bmp = {0};
+ DWORD dwLen;
+ BYTE* pOrig, *pLine, alpha;
+ float v_s_u = 0, v_s_w = 0, r = 0, g = 0, b = 0;
+
+ if(0 == clr) { // do hsv transformation
+ v_s_u = value * saturation * cos(hue * M_PI/180);
+ v_s_w = value * saturation * sin(hue * M_PI/180);
+ }
+ else { // rgb colorization
+ BYTE rValue = GetRValue(clr);
+ BYTE gValue = GetGValue(clr);
+ BYTE bValue = GetBValue(clr);
+
+ r = (float)rValue / 2.55;
+ g = (float)gValue / 2.55;
+ b = (float)bValue / 2.55;
+ }
+ if(item) {
+ /*
+ * colorize a rectangular glyph
+ */
+ if(item->dwFlags & IMAGE_GLYPH) {
+ hBitmap = Skin::glyphItem->hbm;
+ x = item->glyphMetrics[0];
+ y = item->glyphMetrics[1];
+ x1 = x + item->glyphMetrics[2] - 1;
+ y1 = y + item->glyphMetrics[3] - 1;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ dwLen = (DWORD)m_sAllocated;
+ }
+ memset(m_p, 0, dwLen);
+ pOrig = m_p;
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ stride = bmp.bmWidthBytes;
+
+ m_p += ((y * stride) + (4 * x));
+
+ for(line = y; line <= y1; line++) {
+ pLine = m_p;
+ for(pixel = x; pixel <= x1; pixel++) {
+ alpha = m_p[3];
+ if(alpha > 0) {
+ if(0 == clr)
+ hsvTransformPixel(m_p, value, v_s_u, v_s_w, alpha);
+ else
+ rgbTransformPixel(m_p, r, g, b, alpha);
+ }
+ m_p += 4;
+ }
+ m_p = pLine + stride;
+ }
+ SetBitmapBits(hBitmap, dwLen, pOrig);
+ }
+ else if (item->hbm) {
+ GetObject(item->hbm, sizeof(bmp), &bmp);
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+ pOrig = m_p;
+ GetBitmapBits(item->hbm, dwLen, m_p);
+
+ for(pixel = 0; pixel < (bmp.bmWidth * bmp.bmHeight); pixel++) {
+ alpha = m_p[3];
+ if(alpha > 0) {
+ if(0 == clr)
+ hsvTransformPixel(m_p, value, v_s_u, v_s_w, alpha);
+ else
+ rgbTransformPixel(m_p, r, g, b, alpha);
+ }
+ m_p += 4;
+ }
+ SetBitmapBits(item->hbm, dwLen, pOrig);
+ }
+ }
+}
diff --git a/plugins/Clist_ng/SRC/gfx.sublime-workspace b/plugins/Clist_ng/SRC/gfx.sublime-workspace new file mode 100644 index 0000000000..0e99932ba2 --- /dev/null +++ b/plugins/Clist_ng/SRC/gfx.sublime-workspace @@ -0,0 +1,181 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "con", + "context" + ] + ] + }, + "buffers": + [ + ], + "build_system": "", + "command_palette": + { + "height": 375.0, + "selected_items": + [ + [ + "pack", + "Package Control: Install Package" + ], + [ + "pa", + "Package Control: Remove Package" + ], + [ + "packa", + "Preferences: Browse Packages" + ] + ], + "width": 418.0 + }, + "console": + { + "height": 0.0, + "history": + [ + ] + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/D/idea12/bin/idea64.exe.vmoptions", + "/C/Users/alex/Dropbox/smf/Sources/EosSmarty.php", + "/C/Users/alex/Dropbox/smf/Sources/Calendar.php", + "/C/Users/alex/Dropbox/smf/Sources/DbPackages-mysql.php", + "/C/Users/alex/Dropbox/smf/Sources/Load.php", + "/C/Users/alex/Dropbox/smf/Sources/BoardIndex.php", + "/C/Users/alex/Dropbox/smf/Sources/Display.php", + "/C/Users/alex/Dropbox/smf/Sources/Class-Graphics.php", + "/D/NET_DATA/Dropbox/sublime/Data/Packages/BufferScroll/BufferScroll.py", + "/C/Users/Alex/Dropbox/sublime/Data/Packages/User/BufferScroll.sublime-settings", + "/C/Users/Alex/Dropbox/sublime/Data/Packages/Default/Preferences.sublime-settings", + "/C/Users/Alex/Dropbox/sublime/Data/Packages/BufferScroll/BufferScroll.sublime-settings", + "/C/Users/Alex/Dropbox/sublime/Data/Packages/User/Package Control.sublime-settings", + "/D/net_data/dropbox/sublime/Data/Packages/User/Package Control.sublime-settings" + ], + "find": + { + "height": 34.0 + }, + "find_in_files": + { + "height": 0.0, + "where_history": + [ + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + "fold" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "sheets": + [ + ] + } + ], + "incremental_find": + { + "height": 24.0 + }, + "input": + { + "height": 34.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ] + ], + "cols": + [ + 0.0, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "project": "gfx.sublime-project", + "replace": + { + "height": 44.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "select_project": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "select_symbol": + { + "height": 0.0, + "selected_items": + [ + ], + "width": 0.0 + }, + "settings": + { + }, + "show_minimap": true, + "show_open_files": true, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 284.0, + "status_bar_visible": true, + "template_settings": + { + } +} diff --git a/plugins/Clist_ng/SRC/init.cpp b/plugins/Clist_ng/SRC/init.cpp new file mode 100644 index 0000000000..eacf362b0d --- /dev/null +++ b/plugins/Clist_ng/SRC/init.cpp @@ -0,0 +1,386 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: init.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+
+HINSTANCE g_hInst = 0;
+CLIST_INTERFACE *pcli, coreCli;
+int hLangpack;
+
+#define DEFAULT_TB_VISIBILITY (1 | 2 | 4 | 8 | 16 | 32 | 64 | 8192)
+
+wchar_t* szNoevents = L"No events...";
+extern HICON overlayicons[10];
+
+extern int Docking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam);
+extern void RegisterCLUIFrameClasses();
+
+HMENU BuildGroupPopupMenu(struct ClcGroup* group);
+void ReloadThemedOptions();
+void TrayIconUpdateBase(const char *szChangedProto);
+
+void GetDefaultFontSetting(int i, LOGFONT *lf, COLORREF *colour);
+int GetWindowVisibleState(HWND hWnd, int iStepX, int iStepY);
+int ShowHide(WPARAM wParam, LPARAM lParam);
+
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 9
+#define __RELEASE_NUM 2
+#define __BUILD_NUM 4
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Clist NG"
+#define __FILENAME "Clist_NG.dll"
+#define __DESCRIPTION "Displays contacts, event notifications, protocol status."
+#define __AUTHOR "Pixel, egoDust, cyreve, Nightwish"
+#define __AUTHOREMAIL ""
+#define __AUTHORWEB "http://miranda-ng.org/p/Clist_nicer/"
+#define __COPYRIGHT "Copyright 2000-2015 Miranda-IM project"
+
+PLUGININFOEX pluginInfo =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __AUTHOREMAIL,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {8F79B4EE-EB48-4A03-873E-27BE6B7E9A25}
+ { 0xe3a15605, 0x62be, 0x4a1b, { 0xa1, 0x10, 0xf8, 0x89, 0xfa, 0x4b, 0x2f, 0x0 } }
+};
+
+int _DebugTraceW(const wchar_t *fmt, ...)
+{
+ wchar_t debug[2048];
+ int ibsize = 2047;
+ SYSTEMTIME st;
+ va_list va;
+ char tszTime[50];
+ va_start(va, fmt);
+
+ GetLocalTime(&st);
+
+ mir_snprintf(tszTime, 50, "%02d.%02d.%04d - %02d:%02d:%02d.%04d: ", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+
+
+ _vsnwprintf(debug, ibsize - 10, fmt, va);
+//#ifdef _DEBUG
+ OutputDebugStringW(debug);
+//#else
+ {
+ char szLogFileName[MAX_PATH], szDataPath[MAX_PATH];
+ FILE *f;
+
+ CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (LPARAM)szDataPath);
+ mir_snprintf(szLogFileName, MAX_PATH, "%s\\%s", szDataPath, "clg_debug.log");
+ f = fopen(szLogFileName, "a+");
+ if(f) {
+ char *szDebug = Utf8EncodeW(debug);
+ fputs(tszTime, f);
+ fputs(szDebug, f);
+ fputs("\n", f);
+ fclose(f);
+ if(szDebug)
+ mir_free(szDebug);
+ }
+ }
+//#endif
+ return 0;
+}
+
+int _DebugTraceA(const char *fmt, ...)
+{
+ char debug[2048];
+ int ibsize = 2047;
+ va_list va;
+ va_start(va, fmt);
+
+ lstrcpyA(debug, "CLIST_NG: ");
+ _vsnprintf(&debug[9], ibsize - 10, fmt, va);
+#ifdef _DEBUG
+ OutputDebugStringA(debug);
+#else
+ {
+ char szLogFileName[MAX_PATH], szDataPath[MAX_PATH];
+ FILE *f;
+
+ CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (LPARAM)szDataPath);
+ mir_snprintf(szLogFileName, MAX_PATH, "%s\\%s", szDataPath, "clg_debugA.log");
+ f = fopen(szLogFileName, "a+");
+ if(f) {
+ fputs(debug, f);
+ fputs("\n", f);
+ fclose(f);
+ }
+ }
+#endif
+ return 0;
+}
+
+
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID reserved)
+{
+ g_hInst = hInstDLL;
+ DisableThreadLibraryCalls(g_hInst);
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_CLIST, MIID_LAST };
+
+int LoadContactListModule(void);
+int LoadCLCModule(void);
+
+static int systemModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ GetSystemTime(&cfg::dat.st);
+ SystemTimeToFileTime(&cfg::dat.st, &cfg::dat.ft);
+
+ cfg::dat.bMetaEnabled = db_mc_isEnabled();
+
+ cfg::dat.bAvatarServiceAvail = ServiceExists(MS_AV_GETAVATARBITMAP) ? TRUE : FALSE;
+ if (cfg::dat.bAvatarServiceAvail)
+ HookEvent(ME_AV_AVATARCHANGED, AvatarChanged);
+ cfg::dat.tabSRMM_Avail = ServiceExists("SRMsg_MOD/GetWindowFlags") ? TRUE : FALSE;
+
+ ZeroMemory((void *)overlayicons, sizeof(HICON) * 10);
+
+ CLN_LoadAllIcons(1);
+ return 0;
+}
+
+int CLC::fnIconFromStatusMode(const char* szProto, int status, MCONTACT hContact)
+{
+ return IconFromStatusMode(szProto, status, hContact, NULL);
+}
+
+extern "C" int __declspec(dllexport) CListInitialise()
+{
+ int rc = 0;
+ DBVARIANT dbv = {0};
+ int i;
+#ifdef _DEBUG
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ mir_getLP( &pluginInfo );
+ mir_getCLI();
+ coreCli = *pcli;
+
+ if(!SUCCEEDED(Api::onInit())) {
+ MessageBoxW(0, L"Unsupported operating system", L"Clist NG fatal", MB_OK);
+ return(1);
+ }
+ if(!SUCCEEDED(cfg::onInit())) {
+ MessageBoxW(0, L"cfg::OnInit() failed", L"Clist NG fatal", MB_OK);
+ return(1);
+ }
+ Gfx::D2D_Init();
+ LoadCLCButtonModule();
+ RegisterCLUIFrameClasses();
+ ZeroMemory((void*) &cfg::dat, sizeof(cfg::dat));
+
+ int iCount = CallService(MS_DB_CONTACT_GETCOUNT, 0, 0);
+
+ iCount += 20;
+ if(iCount < 300)
+ iCount = 300;
+
+ cfg::eCache = reinterpret_cast<TExtraCache *>(malloc(sizeof(TExtraCache) * iCount));
+ ZeroMemory(cfg::eCache, sizeof(struct TExtraCache) * iCount);
+ cfg::nextCacheEntry = 0;
+ cfg::maxCacheEntry = iCount;
+ cfg::initCache();
+
+ cfg::dat.hMenuNotify = CreatePopupMenu();
+ cfg::dat.wNextMenuID = 1;
+ cfg::dat.szNoEvents = TranslateTS(szNoevents);
+ cfg::dat.avatarBorder = (COLORREF)cfg::getDword("CLC", "avatarborder", 0);
+ cfg::dat.hBrushAvatarBorder = CreateSolidBrush(cfg::dat.avatarBorder);
+ cfg::dat.avatarSize = cfg::getWord("CList", "AvatarSize", 24);
+ cfg::dat.dualRowMode = cfg::getByte("CLC", "DualRowMode", 0);
+ cfg::dat.avatarPadding = cfg::getByte("CList", "AvatarPadding", 0);
+ cfg::dat.isTransparent = cfg::getByte("CList", "Transparent", 0);
+ cfg::dat.alpha = cfg::getByte("CList", "Alpha", SETTING_ALPHA_DEFAULT);
+ cfg::dat.autoalpha = cfg::getByte("CList", "AutoAlpha", SETTING_ALPHA_DEFAULT);
+ cfg::dat.fadeinout = cfg::getByte("CLUI", "FadeInOut", 0);
+ cfg::dat.autosize = cfg::getByte("CLUI", "AutoSize", 0);
+ cfg::dat.dwExtraImageMask = cfg::getDword("CLUI", "ximgmask", 0);
+ cfg::dat.bNoOfflineAvatars = cfg::getByte("CList", "NoOfflineAV", 1);
+ cfg::dat.bDblClkAvatars = cfg::getByte("CLC", "dblclkav", 0);
+ cfg::dat.bEqualSections = cfg::getByte("CLUI", "EqualSections", 0);
+ cfg::dat.bCenterStatusIcons = cfg::getByte("CLC", "si_centered", 1);
+ cfg::dat.boldHideOffline = -1;
+ cfg::dat.bNoTrayTips = cfg::getByte("CList", "NoTrayTips", 0);
+ cfg::dat.bShowLocalTime = cfg::getByte("CLC", "ShowLocalTime", 1);
+ cfg::dat.bShowLocalTimeSelective = cfg::getByte("CLC", "SelectiveLocalTime", 1);
+ cfg::dat.bDontSeparateOffline = cfg::getByte("CList", "DontSeparateOffline", 0);
+ cfg::dat.bFirstRun = cfg::getByte("CLUI", "firstrun", 1);
+ cfg::dat.langPackCP = Langpack_GetDefaultCodePage();
+ cfg::dat.realTimeSaving = cfg::getByte("CLUI", "save_pos_always", 0);
+
+ DWORD sortOrder = cfg::getDword("CList", "SortOrder", SORTBY_NAME);
+ cfg::dat.sortOrder[0] = LOBYTE(LOWORD(sortOrder));
+ cfg::dat.sortOrder[1] = HIBYTE(LOWORD(sortOrder));
+ cfg::dat.sortOrder[2] = LOBYTE(HIWORD(sortOrder));
+
+ if(cfg::dat.bFirstRun)
+ cfg::writeByte("CLUI", "firstrun", 0);
+
+ _tzset();
+
+ if(!cfg::getString(NULL, "CLUI", "exIconOrder", &dbv)) {
+ if(lstrlenA(dbv.pszVal) < EXICON_COUNT) {
+ for(i = 1; i <= EXICON_COUNT; i++)
+ cfg::dat.exIconOrder[i - 1] = i;
+ } else {
+ for(i = 0; i < EXICON_COUNT; i++)
+ if(dbv.pszVal[i] < EXICON_COUNT + 1 && dbv.pszVal[i] > 0)
+ cfg::dat.exIconOrder[i] = dbv.pszVal[i];
+ else
+ cfg::dat.exIconOrder[i] = i + 1;
+ }
+ db_free(&dbv);
+ } else {
+ for(i = 1; i <= EXICON_COUNT; i++)
+ cfg::dat.exIconOrder[i - 1] = i;
+ }
+ ReloadThemedOptions();
+ FLT_ReadOptions();
+
+ CLUI::hExtraImages = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 30, 2);
+ ImageList_SetIconSize(CLUI::hExtraImages, cfg::dat.exIconScale, cfg::dat.exIconScale);
+
+ cfg::dat.dwFlags = cfg::getDword("CLUI", "Frameflags", CLUI_FRAME_STATUSICONS |
+ CLUI_FRAME_SHOWBOTTOMBUTTONS | CLUI_FRAME_BUTTONSFLAT | CLUI_FRAME_CLISTSUNKEN);
+ cfg::dat.dwFlags |= (cfg::getByte("CLUI", "ShowSBar", 1) ? CLUI_FRAME_SBARSHOW : 0);
+ cfg::dat.soundsOff = cfg::getByte("CLUI", "NoSounds", 0);
+
+ if(cfg::getByte("Skin", "UseSound", 0) != cfg::dat.soundsOff)
+ cfg::writeByte("Skin", "UseSound", (BYTE)(cfg::dat.soundsOff ? 0 : 1));
+
+ // get the clist interface
+ pcli = (CLIST_INTERFACE*)CallService(MS_CLIST_RETRIEVE_INTERFACE, 0, (LPARAM)g_hInst);
+
+ pcli->pfnBuildGroupPopupMenu = BuildGroupPopupMenu;
+ pcli->pfnCluiProtocolStatusChanged = CluiProtocolStatusChanged;
+ pcli->pfnCompareContacts = CLC::CompareContacts;
+ pcli->pfnCreateClcContact = CLC::CreateClcContact;
+ pcli->pfnCreateEvent = CLC::fnCreateEvent;
+ pcli->pfnDocking_ProcessWindowMessage = Docking_ProcessWindowMessage;
+ pcli->pfnGetDefaultFontSetting = GetDefaultFontSetting;
+ pcli->pfnGetRowBottomY = RowHeight::getItemBottomY;
+ pcli->pfnGetRowHeight = RowHeight::getHeight;
+ pcli->pfnGetRowTopY = RowHeight::getItemTopY;
+ pcli->pfnGetRowTotalHeight = RowHeight::getTotalHeight;
+ pcli->pfnGetWindowVisibleState = GetWindowVisibleState;
+ pcli->pfnHitTest = CLC::HitTest;
+ pcli->pfnLoadContactTree = CLC::LoadContactTree;
+ pcli->pfnOnCreateClc = CLUI::loadModule;
+ pcli->pfnPaintClc = CLC::Paint;
+ pcli->pfnRebuildEntireList = CLC::RebuildEntireList;
+ pcli->pfnRowHitTest = RowHeight::hitTest;
+ pcli->pfnScrollTo = CLC::ScrollTo;
+ pcli->pfnTrayIconUpdateBase = TrayIconUpdateBase;
+ pcli->pfnSetHideOffline = CLC::SetHideOffline;
+ pcli->pfnShowHide = ShowHide;
+ pcli->pfnBeginRenameSelection = CLC::BeginRenameSelection;
+ pcli->pfnAddContactToGroup = CLC::AddContactToGroup;
+
+ pcli->pfnRemoveItemFromGroup = CLC::RemoveItemFromGroup;
+
+ pcli->pfnAddEvent = CLC::AddEvent;
+
+ pcli->pfnRemoveEvent = CLC::RemoveEvent;
+
+ pcli->pfnAddGroup = CLC::AddGroup;
+
+ pcli->pfnAddInfoItemToGroup = CLC::AddInfoItemToGroup;
+
+ CLC::saveContactListControlWndProc = pcli->pfnContactListControlWndProc;
+ pcli->pfnContactListControlWndProc = CLC::wndProc;
+
+ CLUI::saveContactListWndProc = pcli->pfnContactListWndProc;
+ pcli->pfnContactListWndProc = CLUI::wndProc;
+
+ pcli->pfnIconFromStatusMode = CLC::fnIconFromStatusMode;
+
+ pcli->pfnLoadClcOptions = CLC::LoadClcOptions;
+
+ pcli->pfnProcessExternalMessages = CLC::ProcessExternalMessages;
+
+ pcli->pfnRecalcScrollBar = CLC::RecalcScrollBar;
+
+ pcli->pfnTrayIconProcessMessage = CLC::TrayIconProcessMessage;
+
+ rc = LoadContactListModule();
+ if(rc == 0)
+ rc = CLC::loadModule();
+
+ LoadCLUIFramesModule();
+ HookEvent(ME_SYSTEM_MODULESLOADED, systemModulesLoaded);
+ return rc;
+}
+
+// a plugin loader aware of CList exports will never call this.
+extern "C" int __declspec(dllexport) Load()
+{
+ return 1;
+}
+
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ if(IsWindow(pcli->hwndContactList))
+ DestroyWindow(pcli->hwndContactList);
+
+ ImageList_Destroy(CLUI::hExtraImages);
+ CLC::shutDown(0, 0);
+ UnLoadCLUIFramesModule();
+ Skin::Unload();
+ Api::onUnload();
+ WarningDlg::destroyAll();
+ DeleteCriticalSection(&cfg::cachecs);
+ UnregisterClassW(L"CLCButtonClass", g_hInst);
+ free(cfg::eCache);
+ Gfx::shutDown();
+ Gfx::D2D_Release();
+ return 0;
+}
+
diff --git a/plugins/Clist_ng/SRC/rowheight_funcs.cpp b/plugins/Clist_ng/SRC/rowheight_funcs.cpp new file mode 100644 index 0000000000..23e0434360 --- /dev/null +++ b/plugins/Clist_ng/SRC/rowheight_funcs.cpp @@ -0,0 +1,302 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: rowheight_funcs.cpp 133 2010-09-30 06:27:18Z silvercircle $
+ *
+ */
+
+#include <commonheaders.h>
+#include <rowheight_funcs.h>
+
+BOOL RowHeight::Init(ClcData *dat)
+{
+ dat->rowHeight = 0;
+ dat->row_heights_size = 0;
+ dat->row_heights_allocated = 0;
+ dat->row_heights = NULL;
+
+ return TRUE;
+}
+
+void RowHeight::Free(ClcData *dat)
+{
+ if (dat->row_heights != NULL) {
+ free(dat->row_heights);
+ dat->row_heights = NULL;
+ }
+ dat->row_heights_allocated = 0;
+ dat->row_heights_size = 0;
+}
+
+void RowHeight::Clear(ClcData *dat)
+{
+ dat->row_heights_size = 0;
+}
+
+BOOL RowHeight::Alloc(ClcData *dat, int size)
+{
+ if (size > dat->row_heights_size)
+ {
+ if (size > dat->row_heights_allocated) {
+ int size_grow = size;
+
+ size_grow += 100 - (size_grow % 100);
+
+ if (dat->row_heights != NULL) {
+ int *tmp = (int *)realloc((void *)dat->row_heights, sizeof(int) * size_grow);
+
+ if (tmp == NULL) {
+ Free(dat);
+ return FALSE;
+ }
+
+ dat->row_heights = tmp;
+ }
+ else {
+ dat->row_heights = (int *)malloc(sizeof(int) * size_grow);
+
+ if (dat->row_heights == NULL) {
+ Free(dat);
+ return FALSE;
+ }
+ }
+ dat->row_heights_allocated = size_grow;
+ }
+ dat->row_heights_size = size;
+ }
+ return TRUE;
+}
+
+// Calc and store max row height
+int RowHeight::getMaxRowHeight(ClcData *dat, const HWND hwnd)
+{
+ int max_height = 0, i;
+ DWORD style=GetWindowLong(hwnd,GWL_STYLE);
+
+ int contact_fonts[] = {FONTID_CONTACTS, FONTID_INVIS, FONTID_OFFLINE, FONTID_NOTONLIST, FONTID_OFFINVIS};
+ int other_fonts[] = {FONTID_GROUPS, FONTID_GROUPCOUNTS, FONTID_DIVIDERS};
+
+ // Get contact font size
+ for (i = 0 ; i < MAX_REGS(contact_fonts) ; i++) {
+ if (max_height < dat->fontInfo[contact_fonts[i]].fontHeight)
+ max_height = dat->fontInfo[contact_fonts[i]].fontHeight;
+ }
+
+ if (cfg::dat.dualRowMode == 1 && !dat->bisEmbedded)
+ max_height += dat->fontInfo[FONTID_STATUS].fontHeight;
+
+ // Get other font sizes
+ for (i = 0 ; i < MAX_REGS(other_fonts) ; i++) {
+ if (max_height < dat->fontInfo[other_fonts[i]].fontHeight)
+ max_height = dat->fontInfo[other_fonts[i]].fontHeight;
+ }
+
+ // Avatar size
+ if (cfg::dat.dwFlags & CLUI_FRAME_AVATARS && !dat->bisEmbedded)
+ max_height = max(max_height, cfg::dat.avatarSize + cfg::dat.avatarPadding);
+
+ // Checkbox size
+ if (style&CLS_CHECKBOXES || style&CLS_GROUPCHECKBOXES)
+ max_height = max(max_height, dat->checkboxSize);
+
+ //max_height += 2 * dat->row_border;
+ // Min size
+ max_height = max(max_height, dat->min_row_heigh);
+ max_height += cfg::dat.bRowSpacing;
+
+ dat->rowHeight = max_height;
+
+ return max_height;
+}
+
+// Calc and store row height for all itens in the list
+void RowHeight::calcRowHeights(ClcData *dat, HWND hwnd, CLCPaintHelper* ph)
+{
+ int indent, subindex, line_num;
+ struct ClcContact *Drawing;
+ struct ClcGroup *group;
+ DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ // Draw lines
+ group=&dat->list;
+ group->scanIndex=0;
+ indent=0;
+ //subindex=-1;
+ line_num = -1;
+
+ Clear(dat);
+
+ while(TRUE)
+ {
+ if (group->scanIndex==group->cl.count)
+ {
+ group=group->parent;
+ indent--;
+ if(group==NULL) break; // Finished list
+ group->scanIndex++;
+ continue;
+ }
+
+ // Get item to draw
+ Drawing = group->cl.items[group->scanIndex];
+ line_num++;
+
+ if(!dat->bisEmbedded) {
+ ph->fSelected = (ph->index == dat->selection && Drawing->type != CLCIT_DIVIDER);
+ CLC::iHottrackItem = dat->exStyle & CLS_EX_TRACKSELECT && Drawing->type == CLCIT_CONTACT && dat->iHotTrack == ph->index;
+ if (CLC::iHottrackItem == ph->fSelected)
+ CLC::iHottrackItem = 0;
+ if(ph->fSelected && CLC::dsp_default.dspOverride[DSP_OVR_SELECTED].fActive)
+ ph->dsp = &CLC::dsp_default.dspOverride[DSP_OVR_SELECTED];
+ else if(CLC::iHottrackItem && CLC::dsp_default.dspOverride[DSP_OVR_HOVERED].fActive)
+ ph->dsp = &CLC::dsp_default.dspOverride[DSP_OVR_HOVERED];
+ else if(ID_STATUS_OFFLINE == Drawing->wStatus)
+ ph->dsp = &CLC::dsp_default.dspOverride[DSP_OVR_OFFLINE];
+ else if(ID_STATUS_OFFLINE != Drawing->wStatus)
+ ph->dsp = &CLC::dsp_default.dspOverride[DSP_OVR_ONLINE];
+ else
+ ph->dsp = 0; // calc dsp profile
+ }
+ else
+ ph->dsp = 0;
+
+ // Calc row height
+ getRowHeight(dat, Drawing, line_num, dwStyle, ph);
+
+ if(group->cl.items[group->scanIndex]->type==CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded & 0x0000ffff)) {
+ group=group->cl.items[group->scanIndex]->group;
+ indent++;
+ group->scanIndex=0;
+ subindex=-1;
+ continue;
+ }
+ group->scanIndex++;
+ }
+}
+
+
+// Calc item top Y (using stored data)
+int RowHeight::getItemTopY(ClcData *dat, int item)
+{
+ int i;
+ int y = 0;
+
+ if (item >= dat->row_heights_size)
+ return -1;
+
+ for (i = 0 ; i < item ; i++)
+ {
+ y += dat->row_heights[i];
+ }
+
+ return y;
+}
+
+
+// Calc item bottom Y (using stored data)
+int RowHeight::getItemBottomY(ClcData *dat, int item)
+{
+ int i;
+ int y = 0;
+
+ if (item >= dat->row_heights_size)
+ return -1;
+
+ for (i = 0 ; i <= item ; i++)
+ {
+ y += dat->row_heights[i];
+ }
+
+ return y;
+}
+
+
+// Calc total height of rows (using stored data)
+int RowHeight::getTotalHeight(ClcData *dat)
+{
+ int i;
+ int y = 0;
+
+ for (i = 0 ; i < dat->row_heights_size ; i++)
+ {
+ y += dat->row_heights[i];
+ }
+
+ return y;
+}
+
+// Return the line that pos_y is at or -1 (using stored data)
+int RowHeight::hitTest(ClcData *dat, int pos_y)
+{
+ int i;
+ int y = 0;
+
+ if (pos_y < 0)
+ return -1;
+
+ for (i = 0 ; i < dat->row_heights_size ; i++)
+ {
+ y += dat->row_heights[i];
+
+ if (pos_y < y)
+ return i;
+ }
+
+ return -1;
+}
+
+int RowHeight::getHeight(ClcData *dat, int item)
+{
+ if ( dat->row_heights == 0 )
+ return 0;
+
+ return dat->row_heights[ item ];
+}
+
+int RowHeight::getFloatingRowHeight(const ClcData *dat, HWND hwnd, ClcContact *contact, DWORD dwFlags)
+{
+ int height = 0;
+
+ height = dat->fontInfo[GetBasicFontID(contact)].fontHeight;
+
+ if(!dat->bisEmbedded) {
+ if(!(dwFlags & FLT_SIMPLE)){
+ if(dwFlags & FLT_DUALROW) {
+ height += (dat->fontInfo[FONTID_STATUS].fontHeight + cfg::dat.avatarPadding);
+ }
+ // Avatar size
+ if (dwFlags & FLT_AVATARS && contact->cFlags & ECF_AVATAR && contact->type == CLCIT_CONTACT && contact->ace != NULL && !(contact->ace->dwFlags & AVS_HIDEONCLIST))
+ height = max(height, cfg::dat.avatarSize + cfg::dat.avatarPadding);
+ }
+ }
+
+ height = max(height, dat->min_row_heigh);
+ height += cfg::dat.bRowSpacing;
+
+ return height;
+}
diff --git a/plugins/Clist_ng/SRC/skin.cpp b/plugins/Clist_ng/SRC/skin.cpp new file mode 100644 index 0000000000..4137b30c87 --- /dev/null +++ b/plugins/Clist_ng/SRC/skin.cpp @@ -0,0 +1,1119 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: skin.cpp 138 2010-11-01 10:51:15Z silvercircle $
+ *
+ * implement skin management, loading, applying etc.
+ *
+ * about database values:
+ *
+ * various skin-related settings may be written to the databse. the module
+ * name is CLNgSkin and the value names are the same as variable names in the
+ * TSkinSettings and TSkinMetrics data structures with the following
+ * prefixes:
+ *
+ * s - a value belonging to TSkinSettings
+ * m - a value belonging to TSkinMetrics
+ * g - a global value belonging to the Skin class - e.gl gCurrentSkin
+ * holds the name of the currently active skin.
+ *
+ */
+
+
+#include <commonheaders.h>
+
+TStatusItem* Skin::statusItems = 0;
+TImageItem* Skin::imageItems = 0;
+TImageItem* Skin::glyphItem = 0;
+TSkinMetrics Skin::metrics = {0};
+TSkinSettings Skin::settings = {0};
+
+int Skin::ID_EXTBK_LAST = ID_EXTBK_LAST_D;
+
+UINT SkinLoader::nextButtonID = IDC_TBFIRSTUID;
+
+
+
+/*
+ * TODO Refactor
+ */
+extern struct CluiTopButton top_buttons[];
+extern TStatusItem DefaultStatusItems[ID_EXTBK_LAST_D + 1];
+
+HBRUSH g_CLUISkinnedBkColor = 0;
+COLORREF g_CLUISkinnedBkColorRGB = 0;
+
+
+void Skin::setAeroMargins()
+{
+ if(cfg::isAero) {
+ MARGINS m = {-1};
+ Api::pfnDwmExtendFrameIntoClientArea(pcli->hwndContactList, &m);
+ }
+ else {
+ MARGINS m = {0};
+ Api::pfnDwmExtendFrameIntoClientArea(pcli->hwndContactList, &m);
+ }
+}
+
+void Skin::updateAeroState()
+{
+ cfg::isAero = (settings.fHaveAeroBG && settings.fUseAero && Api::sysState.isAero) ? true : false;
+}
+
+void Skin::Activate()
+{
+ CLUI::applyBorderStyle();
+ CLUI::configureGeometry(1);
+
+ ShowWindow(pcli->hwndContactList, SW_SHOWNORMAL);
+ SetWindowPos(pcli->hwndContactList, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ SendMessageW(pcli->hwndContactList, WM_SIZE, 0, 0);
+ updateAeroState();
+ setAeroMargins();
+ CLUI::Redraw();
+}
+
+/**
+ * free a single image item, release DC, delete bitmap
+ * @param item TImageItem* the item to free
+ */
+void Skin::freeImageItem(TImageItem *item)
+{
+ if(item) {
+ if(!(item->dwFlags & IMAGE_GLYPH)) {
+ SelectObject(item->hdc, item->hbmOld);
+ DeleteObject(item->hbm);
+ DeleteDC(item->hdc);
+ }
+ if(item->fillBrush)
+ DeleteObject(item->fillBrush);
+ }
+}
+
+void Skin::colorizeGlyphByName(const char* szGlyphName, const COLORREF clr, float h, float s, float v)
+{
+ if(szGlyphName) {
+ TImageItem *_t = imageItems;
+ while(_t) {
+ if(!strcmp(_t->szName, szGlyphName)) {
+ Gfx::colorizeGlyph(_t, clr, h, s, v);
+ break;
+ }
+ _t = _t->nextItem;
+ }
+ }
+}
+
+/**
+ * render a image item with the given name to the target rectangle in the target
+ * device context.
+ *
+ * @param szItemname image item name (must include the preceeding $ or @)
+ * @param rc target rectangle
+ * @param hdc target dc
+ */
+void Skin::renderNamedImageItem(const char *szItemname, RECT* rc, const HDC hdc)
+{
+ if(szItemname) {
+ TImageItem *_t = imageItems;
+ while(_t) {
+ if(_t->szName && !strcmp(_t->szName, szItemname)) {
+ Gfx::renderImageItem(hdc, _t, rc);
+ break;
+ }
+ _t = _t->nextItem;
+ }
+ }
+}
+/**
+ * free all skin items
+ * a) image items
+ * b) global image items (glyph, CLUI background)
+ * c) button items
+ */
+void Skin::Unload()
+{
+ TImageItem *pItem = imageItems, *pNextItem;
+ TButtonItem *pbItem = CLUI::buttonItems, *pbNextItem;
+
+ while(pItem) {
+ freeImageItem(pItem);
+ pNextItem = pItem->nextItem;
+ free(pItem);
+ pItem = pNextItem;
+ }
+ imageItems = NULL;
+ while(pbItem) {
+ DestroyWindow(pbItem->hWnd);
+ pbNextItem = pbItem->nextItem;
+ free(pbItem);
+ pbItem = pbNextItem;
+ }
+ CLUI::buttonItems = 0;
+
+ if(CLUI::bgImageItem) {
+ freeImageItem(CLUI::bgImageItem);
+ free(CLUI::bgImageItem);
+ }
+ CLUI::bgImageItem = 0;
+
+ if(CLUI::bgImageItem_nonAero) {
+ freeImageItem(CLUI::bgImageItem_nonAero);
+ free(CLUI::bgImageItem_nonAero);
+ }
+ CLUI::bgImageItem_nonAero = 0;
+
+ if(CLUI::bgClientItem) {
+ freeImageItem(CLUI::bgClientItem);
+ free(CLUI::bgClientItem);
+ }
+ CLUI::bgClientItem = 0;
+
+ if(glyphItem) {
+ freeImageItem(glyphItem);
+ free(glyphItem);
+ }
+ glyphItem = NULL;
+
+ if(statusItems) {
+ TStatusItem* item;
+ for(int i = 0; i <= ID_EXTBK_LAST; i++) {
+ item = &statusItems[i];
+
+ if(item->span_allocator) {
+ delete item->gradient_renderer_x;
+ delete item->gradient_renderer_y;
+ delete item->solid_renderer;
+ delete item->span_gradient_x;
+ delete item->span_gradient_y;
+ delete item->gradient_trans;
+ delete item->gradient_func_x;
+ delete item->gradient_func_y;
+ delete item->color_array;
+ delete item->span_interpolator;
+ delete item->span_allocator;
+ delete item->pixfmt;
+ delete item->rbase;
+ delete item->rect;
+ }
+ }
+ free(statusItems);
+ statusItems = 0;
+ ID_EXTBK_LAST = ID_EXTBK_LAST_D;
+ }
+}
+
+/**
+ * setup the items AGG rendering pipeline - set color values for the gradient
+ * and the rectangle shape (corners)
+ *
+ * @param item TStatusItem* - a skin item
+ */
+void Skin::setupAGGItemContext(TStatusItem* item)
+{
+ BYTE r = GetRValue(item->COLOR);
+ BYTE g = GetGValue(item->COLOR);
+ BYTE b = GetBValue(item->COLOR);
+
+ BYTE r2 = GetRValue(item->COLOR2);
+ BYTE g2 = GetGValue(item->COLOR2);
+ BYTE b2 = GetBValue(item->COLOR2);
+
+ if(0 == item->span_allocator) // do not setup for image items only (these do not have AGG objects).
+ return;
+
+ item->dwFlags &= ~(AGG_USE_GRADIENT_X_RENDERER | AGG_USE_GRADIENT_Y_RENDERER | AGG_USE_SOLID_RENDERER);
+
+ /*
+ * alpha values as read from the skin definition are in PERCENT (0-100)
+ */
+ if(item->GRADIENT & GRADIENT_ACTIVE) {
+ //agg::rgba8 r1 = agg::rgba8(r, g, b, percent_to_byte(item->ALPHA));
+ //agg::rgba8 r2 = agg::rgba8(r2, g2, b2, percent_to_byte(item->ALPHA2));
+
+ agg::rgba8 r1(r, g, b, percent_to_byte(item->ALPHA));
+ agg::rgba8 r2(r2, g2, b2, percent_to_byte(item->ALPHA2));
+
+ if(item->GRADIENT & GRADIENT_LR || item->GRADIENT & GRADIENT_TB) {
+ AGGContext::fill_color_array(*(item->color_array), r1, r2);
+ item->dwFlags |= (item->GRADIENT & GRADIENT_LR ? AGG_USE_GRADIENT_X_RENDERER : AGG_USE_GRADIENT_Y_RENDERER);
+ }
+ else {
+ item->dwFlags |= (item->GRADIENT & GRADIENT_RL ? AGG_USE_GRADIENT_X_RENDERER : AGG_USE_GRADIENT_Y_RENDERER);
+ AGGContext::fill_color_array(*(item->color_array), r2, r1);
+ }
+ }
+ else {
+ /*
+ * if no gradient is defined for this item, use a solid renderer
+ * it's faster.
+ */
+ item->solid_renderer->color(agg::rgba8(r, g, b, percent_to_byte(item->ALPHA)));
+ item->dwFlags |= AGG_USE_SOLID_RENDERER;
+ }
+
+ /*
+ * we can setup the corner radius values for our shape here. When rendering, we use
+ * item->rect->rect() to set the dimensions of the rectangle only.
+ *
+ * TODO make radius customizable
+ */
+
+ item->rect->radius(0, 0, 0, 0, 0, 0, 0, 0);
+ if(item->CORNER & CORNER_ACTIVE) {
+ double x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0;
+
+ if(item->CORNER & CORNER_TL)
+ x1 = y1 = Skin::metrics.cCornerRadius;
+ if(item->CORNER & CORNER_TR)
+ x2 = y2 = Skin::metrics.cCornerRadius;
+ if(item->CORNER & CORNER_BL)
+ x4 = y4 = Skin::metrics.cCornerRadius;
+ if(item->CORNER & CORNER_BR)
+ x3 = y3 = Skin::metrics.cCornerRadius;
+
+ item->rect->radius(x1, y1, x2, y2, x3, y3, x4, y4);
+ }
+}
+
+/**
+ * export skin-relevant database settings to the corresponding skin settings file
+ * @param file
+ */
+void Skin::exportSettingsToFile(const char *file)
+{
+ // TODO needs work
+
+ /*
+ int i = 0;
+ DWORD data;
+ char cPrefix, szBuf[30];
+ */
+}
+/**
+ * exports all skin-relevant customization to a file
+ * @param file file name (INI format)
+ */
+void Skin::exportToFile(const char *file)
+{
+ int n;
+ char szSection[255];
+ char szKey[255];
+ DBVARIANT dbv = {0};
+ DWORD data;
+ char* szSectionName = 0, *p = 0;
+
+ for (n = 0; n <= ID_EXTBK_LAST; n++) {
+ if (statusItems[n].statusID != ID_EXTBKSEPARATOR) {
+ szSectionName = p = statusItems[n].szName;
+ if('{' == szSectionName[0])
+ p += 3;
+
+ Utils::writeProfile(p, "ColorHigh", statusItems[n].COLOR, file);
+ Utils::writeProfile(p, "ColorLow", statusItems[n].COLOR2, file);
+ Utils::writeProfile(p, "Textcolor", statusItems[n].TEXTCOLOR, file);
+ Utils::writeProfile(p, "Ignored", statusItems[n].IGNORED, file);
+ Utils::writeProfile(p, "Left", statusItems[n].MARGIN_LEFT, file);
+ Utils::writeProfile(p, "Top", statusItems[n].MARGIN_TOP, file);
+ Utils::writeProfile(p, "Right", statusItems[n].MARGIN_RIGHT, file);
+ Utils::writeProfile(p, "Bottom", statusItems[n].MARGIN_BOTTOM, file);
+ Utils::writeProfile(p, "Alpha", statusItems[n].ALPHA, file);
+ Utils::writeProfile(p, "Alpha2", statusItems[n].ALPHA2, file);
+ Utils::writeProfile(p, "Corner", statusItems[n].CORNER, file);
+ Utils::writeProfile(p, "Gradient", statusItems[n].GRADIENT, file);
+ Utils::writeProfile(p, "Flags", statusItems[n].dwFlags, file);
+ }
+ }
+ for(n = 0; n <= FONTID_LAST; n++) {
+ mir_snprintf(szSection, 255, "Font%d", n);
+
+ mir_snprintf(szKey, 255, "Font%dName", n);
+ if(!cfg::getString(NULL, "CLC", szKey, &dbv)) {
+ Utils::writeProfile(szSection, "Name", dbv.pszVal, file);
+ mir_free(dbv.pszVal);
+ }
+ mir_snprintf(szKey, 255, "Font%dSize", n);
+ data = (DWORD)cfg::getByte("CLC", szKey, 8);
+ Utils::writeProfile(szSection, "Size", data, file);
+
+ mir_snprintf(szKey, 255, "Font%dSty", n);
+ data = (DWORD)cfg::getByte("CLC", szKey, 8);
+ Utils::writeProfile(szSection, "Style", data, file);
+
+ mir_snprintf(szKey, 255, "Font%dSet", n);
+ data = (DWORD)cfg::getByte("CLC", szKey, 8);
+ Utils::writeProfile(szSection, "Set", data, file);
+
+ mir_snprintf(szKey, 255, "Font%dCol", n);
+ data = cfg::getDword("CLC", szKey, 8);
+ Utils::writeProfile(szSection, "Color", data, file);
+
+ mir_snprintf(szKey, 255, "Font%dFlags", n);
+ data = (DWORD)cfg::getDword("CLC", szKey, 8);
+ Utils::writeProfile(szSection, "Flags", data, file);
+
+ }
+}
+
+static TStatusItem default_item = {
+ "{--Contact--}", 0,
+ CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER,
+ CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, -1,
+ CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT,
+ CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE
+};
+
+void SkinLoader::readItem(TStatusItem *this_item, const char *szItem)
+{
+ TStatusItem *defaults = &default_item;
+ DWORD tmpflags;
+
+ this_item->ALPHA = (int)GetPrivateProfileIntA(szItem, "Alpha", defaults->ALPHA, m_szFilename);
+ this_item->ALPHA = min(this_item->ALPHA, 100);
+ this_item->ALPHA2 = (int)GetPrivateProfileIntA(szItem, "Alpha2", defaults->ALPHA, m_szFilename);
+ this_item->ALPHA2 = min(this_item->ALPHA2, 100);
+ this_item->COLOR = GetPrivateProfileIntA(szItem, "ColorHigh", 0, m_szFilename);
+ this_item->COLOR2 = GetPrivateProfileIntA(szItem, "ColorLow", 0, m_szFilename);
+
+ this_item->CORNER = GetPrivateProfileIntA(szItem, "Corner", 0, m_szFilename);
+
+ this_item->GRADIENT = GetPrivateProfileIntA(szItem, "Gradient", 0, m_szFilename);
+
+ this_item->MARGIN_LEFT = GetPrivateProfileIntA(szItem, "Left", defaults->MARGIN_LEFT, m_szFilename);
+ this_item->MARGIN_RIGHT = GetPrivateProfileIntA(szItem, "Right", defaults->MARGIN_RIGHT, m_szFilename);
+ this_item->MARGIN_TOP = GetPrivateProfileIntA(szItem, "Top", defaults->MARGIN_TOP, m_szFilename);
+ this_item->MARGIN_BOTTOM = GetPrivateProfileIntA(szItem, "Bottom", defaults->MARGIN_BOTTOM, m_szFilename);
+
+ this_item->TEXTCOLOR = GetPrivateProfileIntA(szItem, "Textcolor", 0, m_szFilename);
+ this_item->IGNORED = GetPrivateProfileIntA(szItem, "Ignored", 0, m_szFilename);
+ tmpflags = GetPrivateProfileIntA(szItem, "Flags", 0, m_szFilename);
+ this_item->dwFlags |= tmpflags;
+}
+
+void SkinLoader::loadBaseItems()
+{
+ int protoCount = 0, i, n;
+ PROTOACCOUNT** accs = 0;
+ char* p = 0;
+
+ Proto_EnumAccounts(&protoCount, &accs);
+
+ if(Skin::statusItems) {
+ free(Skin::statusItems);
+ Skin::statusItems = 0;
+ Skin::ID_EXTBK_LAST = ID_EXTBK_LAST_D;
+ }
+ Skin::statusItems = (TStatusItem *)malloc(sizeof(TStatusItem) * ((Skin::ID_EXTBK_LAST) + protoCount + 2));
+ CopyMemory(Skin::statusItems, DefaultStatusItems, sizeof(DefaultStatusItems));
+
+ for(i = 0; i < protoCount; i++) {
+ Skin::ID_EXTBK_LAST++;
+ CopyMemory(&Skin::statusItems[Skin::ID_EXTBK_LAST], &Skin::statusItems[0], sizeof(TStatusItem));
+ if(i == 0) {
+ lstrcpynA(Skin::statusItems[Skin::ID_EXTBK_LAST].szName, "{-}", 30);
+ strncat(Skin::statusItems[Skin::ID_EXTBK_LAST].szName, accs[i]->szModuleName, 30);
+ }
+ else
+ lstrcpynA(Skin::statusItems[Skin::ID_EXTBK_LAST].szName, accs[i]->szModuleName, 30);
+ Skin::statusItems[Skin::ID_EXTBK_LAST].statusID = Skin::ID_EXTBK_LAST;
+ }
+ for (n = 0; n <= Skin::ID_EXTBK_LAST; n++) {
+ if (Skin::statusItems[n].statusID != ID_EXTBKSEPARATOR) {
+ Skin::statusItems[n].imageItem = 0;
+ p = Skin::statusItems[n].szName;
+ if(*p == '{')
+ p += 3;
+
+ TStatusItem* item = &Skin::statusItems[n];
+
+ readItem(item, p);
+
+ if(!(item->dwFlags & S_ITEM_IMAGE_ONLY)) {
+ item->span_allocator = new span_allocator_t;
+ item->color_array = new agg::pod_auto_array<agg::rgba8, 256>();
+ item->gradient_func_x = new agg::gradient_x();
+ item->gradient_func_y = new agg::gradient_y();
+ item->gradient_trans = new agg::trans_affine();
+ item->span_interpolator = new agg::span_interpolator_linear<>(*(item->gradient_trans));
+ item->span_gradient_x = new span_gradient_x_t(*(item->span_interpolator),
+ *(item->gradient_func_x), *(item->color_array), 0, 200);
+
+ item->span_gradient_y = new span_gradient_y_t(*(item->span_interpolator),
+ *(item->gradient_func_y), *(item->color_array), 0, 200);
+
+ item->pixfmt = new agg::pixfmt_bgra32(); //*(item->rbuf));
+ item->rbase = new agg::renderer_base<agg::pixfmt_bgra32>(); //*(item->pixfmt));
+ item->gradient_renderer_x = new agg::renderer_scanline_aa<agg::renderer_base<agg::pixfmt_bgra32>, span_allocator_t, span_gradient_x_t>(*(item->rbase),
+ *(item->span_allocator), *(item->span_gradient_x));
+
+ item->gradient_renderer_y = new agg::renderer_scanline_aa<agg::renderer_base<agg::pixfmt_bgra32>, span_allocator_t, span_gradient_y_t>(*(item->rbase),
+ *(item->span_allocator), *(item->span_gradient_y));
+
+ item->solid_renderer = new agg::renderer_scanline_aa_solid<agg::renderer_base<agg::pixfmt_bgra32> >(*(item->rbase));
+
+ item->rect = new agg::rounded_rect(0, 0, 0, 0, 0);
+
+ Skin::setupAGGItemContext(item);
+ }
+ else
+ item->span_allocator = 0;
+ }
+ }
+}
+
+/**
+ * read font definitions from INI style file and write them to the
+ * database.
+ *
+ * uses m_szFilename to read from...
+ */
+void SkinLoader::loadFonts()
+{
+ int n;
+ char buffer[255];
+ char szKey[255], szSection[255];
+ DWORD data;
+
+ for(n = 0; n <= FONTID_LAST; n++) {
+ mir_snprintf(szSection, 255, "Font%d", n);
+
+ mir_snprintf(szKey, 255, "Font%dName", n);
+ GetPrivateProfileStringA(szSection, "Name", "Arial", buffer, sizeof(buffer), m_szFilename);
+ cfg::writeString(NULL, "CLC", szKey, buffer);
+
+ mir_snprintf(szKey, 255, "Font%dSize", n);
+ data = readInt(szSection, "Size", 10);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dSty", n);
+ data = readInt(szSection, "Style", 0);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dSet", n);
+ data = readInt(szSection, "Set", 1);
+ cfg::writeByte("CLC", szKey, (BYTE)data);
+
+ mir_snprintf(szKey, 255, "Font%dCol", n);
+ data = readInt(szSection, "Color", 0x00);
+ cfg::writeDword("CLC", szKey, data);
+
+ mir_snprintf(szKey, 255, "Font%dFlags", n);
+ data = readInt(szSection, "Flags", 0);
+ cfg::writeDword("CLC", szKey, (WORD)data);
+ }
+}
+
+/**
+ * load a skin with the given name.
+ * @param wszFilename: full path and file name of the skin
+ * definition file (.cng format)
+ *
+ * after constructing, check ::isValid() before using the Load()
+ * method.
+ */
+SkinLoader::SkinLoader(const wchar_t* wszFilename)
+{
+ wchar_t wszBase[MAX_PATH], wszRelPath[MAX_PATH];
+ m_isValid = false;
+ wchar_t wszDrive[_MAX_DRIVE], wszDir[_MAX_DIR], wszFile[_MAX_FNAME];
+
+ Skin::settings.wszSkinBaseFolder[0] = Skin::settings.wszSkinName[0] = 0;
+
+ mir_sntprintf(wszBase, MAX_PATH, L"%s%s", cfg::szProfileDir, L"skin\\clng\\base\\base.cng");
+ if(0 == wszFilename) {
+ if(PathFileExists(wszBase)) {
+ wcsncpy(m_wszFilename, wszBase, MAX_PATH);
+ m_wszFilename[MAX_PATH - 1] = 0;
+ WideCharToMultiByte(CP_ACP, 0, wszBase, MAX_PATH, m_szFilename, MAX_PATH, 0, 0);
+ m_isValid = true;
+ }
+ }
+ else {
+ if(PathFileExists(wszFilename)) {
+ WideCharToMultiByte(CP_ACP, 0, wszFilename, MAX_PATH, m_szFilename, MAX_PATH, 0, 0);
+ wcsncpy(m_wszFilename, wszFilename, MAX_PATH);
+ m_wszFilename[MAX_PATH - 1] = 0;
+ }
+ else {
+ WideCharToMultiByte(CP_ACP, 0, wszBase, MAX_PATH, m_szFilename, MAX_PATH, 0, 0);
+ wcsncpy(m_wszFilename, wszBase, MAX_PATH);
+ m_wszFilename[MAX_PATH - 1] = 0;
+ }
+ m_isValid = true;
+ }
+ Utils::pathToRelative(m_wszFilename, wszRelPath, cfg::szProfileDir);
+ cfg::writeTString(0, SKIN_DB_MODULE, "gCurrentSkin", wszRelPath);
+ _wsplitpath(m_wszFilename, wszDrive, wszDir, wszFile, 0);
+ mir_sntprintf(Skin::settings.wszSkinBaseFolder, MAX_PATH, L"%s%s", wszDrive, wszDir);
+ mir_sntprintf(Skin::settings.wszSkinName, MAX_PATH, L"%s", wszFile);
+}
+
+/**
+ * read a setting from the skin definition file
+ * the filename is in m_szFilename and was set in the ctor
+ *
+ * @param szSection INI section
+ * @param szValue key name
+ * @param dwDefault default when the entry is not found
+ * @return DWORD containing the read value (or the default)
+ */
+DWORD SkinLoader::readInt(const char* szSection, const char* szValue, DWORD dwDefault)
+{
+ if(m_isValid)
+ return(GetPrivateProfileIntA(szSection, szValue, dwDefault, m_szFilename));
+ else
+ return(0);
+}
+
+HRESULT SkinLoader::Load()
+{
+ /*
+ * load metrics and other skin data
+ */
+
+ Skin::metrics.cLeftSkinned = readInt("FramelessMetrics", "CLeft", 0);
+ Skin::metrics.cRightSkinned = readInt("FramelessMetrics", "CRight", 0);
+ Skin::metrics.cTopSkinned = readInt("FramelessMetrics", "CTop", 0);
+ Skin::metrics.cBottomSkinned = readInt("FramelessMetrics", "CBottom", 0);
+
+ Skin::metrics.cLeftFramed = readInt("Metrics", "CLeft", 0);
+ Skin::metrics.cRightFramed = readInt("Metrics", "CRight", 0);
+ Skin::metrics.cTopFramed = readInt("Metrics", "CTop", 0);
+ Skin::metrics.cBottomFramed = readInt("Metrics", "CBottom", 0);
+
+ Skin::metrics.bWindowStyle = readInt("Settings", "DefaultWindowStyle", SETTING_WINDOWSTYLE_NOBORDER);
+ Skin::metrics.cButtonHeight = readInt("Settings", "ButtonHeight", BUTTON_HEIGHT_D);
+ Skin::metrics.cFakeCaption = readInt("FramelessMetrics", "CaptionHeight", 0);
+ Skin::metrics.cFakeLeftBorder = readInt("FramelessMetrics", "LeftBorderWidth", 0);
+ Skin::metrics.cFakeRightBorder = readInt("FramelessMetrics", "RightBorderWidth", 0);
+ Skin::metrics.cFakeBtmBorder = readInt("FramelessMetrics", "BottomBorderWidth", 0);
+
+ Skin::metrics.cTopButtonset = readInt("Buttonset", "Top", 0);
+ Skin::metrics.cLeftButtonset = readInt("Buttonset", "Left", 0);
+ Skin::metrics.cRightButtonset = readInt("Buttonset", "Right", 0);
+ Skin::metrics.cBottomButtonset = readInt("Buttonset", "Bottom", 0);
+
+ Skin::metrics.cCornerRadius = readInt("Settings", "CornerRadius", 5);
+ Skin::settings.fUseAero = cfg::getByte(SKIN_DB_MODULE, "sfUseAero", 1) ? true : false;
+
+ /*
+ * read the base items and fill the structure
+ */
+ loadBaseItems();
+
+ /*
+ * load all other skin elements (images, buttons, icons)
+ */
+ if(!SUCCEEDED(loadItems()))
+ return(-S_FALSE);
+
+ /*
+ * TODO read font settings only when necessary (when skin has changed)
+ */
+
+ loadFonts();
+ cfg::FS_RegisterFonts();
+
+ /*
+ * validations (check image items, border styles and make sure everything makes
+ * sense). Protect against skin definition errors
+ */
+ Skin::settings.fHaveAeroBG = CLUI::bgImageItem ? true : false;
+ if(Skin::metrics.bWindowStyle == SETTING_WINDOWSTYLE_NOBORDER && (0 == CLUI::bgImageItem || 0 == CLUI::bgImageItem_nonAero))
+ Skin::metrics.bWindowStyle = SETTING_WINDOWSTYLE_DEFAULT;
+
+ return(S_OK);
+}
+
+HRESULT SkinLoader::loadItems()
+{
+ char* szSections = 0, *szFileName;
+ char* p;
+
+ /*
+ * TODO rewrite the skin loading in wchar_t manner
+ */
+
+ if(!PathFileExistsA(m_szFilename) || !m_isValid)
+ return(-S_FALSE);
+
+ szFileName = m_szFilename;
+
+ szSections = reinterpret_cast<char *>(malloc(3002));
+ ZeroMemory(szSections, 3002);
+ p = szSections;
+ GetPrivateProfileSectionNamesA(szSections, 3000, szFileName);
+
+ szSections[3001] = szSections[3000] = 0;
+ p = szSections;
+ while(lstrlenA(p) > 1) {
+ if(p[0] == '$' || p[0] == '@')
+ readImageItem(p, szFileName);
+ p += (lstrlenA(p) + 1);
+ }
+ nextButtonID = IDC_TBFIRSTUID;
+ p = szSections;
+ while(lstrlenA(p) > 1) {
+ if(p[0] == '!')
+ readButtonItem(p, szFileName);
+ p += (lstrlenA(p) + 1);
+ }
+ if(pcli && pcli->hwndContactList)
+ CLUI::setButtonStates(pcli->hwndContactList);
+ free(szSections);
+
+ if(CLUI::bgImageItem)
+ cfg::dat.dwFlags &= ~CLUI_FRAME_CLISTSUNKEN;
+
+ return(S_OK);
+}
+
+void SkinLoader::readImageItem(const char *itemname, const char *szFileName)
+{
+ TImageItem tmpItem, *newItem = NULL;
+ char buffer[512], szItemNr[30];
+ char szFinalName[MAX_PATH];
+ HDC hdc = GetDC(pcli->hwndContactList);
+ int i, n;
+ BOOL alloced = FALSE;
+ char szDrive[MAX_PATH], szPath[MAX_PATH];
+
+ ZeroMemory(&tmpItem, sizeof(TImageItem));
+ GetPrivateProfileStringA(itemname, "Glyph", "None", buffer, 500, szFileName);
+ if(strcmp(buffer, "None")) {
+ sscanf(buffer, "%d,%d,%d,%d", &tmpItem.glyphMetrics[0], &tmpItem.glyphMetrics[1],
+ &tmpItem.glyphMetrics[2], &tmpItem.glyphMetrics[3]);
+ if(tmpItem.glyphMetrics[2] > tmpItem.glyphMetrics[0] && tmpItem.glyphMetrics[3] > tmpItem.glyphMetrics[1]) {
+ tmpItem.dwFlags |= IMAGE_GLYPH;
+ tmpItem.glyphMetrics[2] = (tmpItem.glyphMetrics[2] - tmpItem.glyphMetrics[0]) + 1;
+ tmpItem.glyphMetrics[3] = (tmpItem.glyphMetrics[3] - tmpItem.glyphMetrics[1]) + 1;
+ goto done_with_glyph;
+ }
+ }
+ GetPrivateProfileStringA(itemname, "Image", "None", buffer, 500, szFileName);
+ if(strcmp(buffer, "None")) {
+
+done_with_glyph:
+
+ strncpy(tmpItem.szName, &itemname[0], sizeof(tmpItem.szName));
+ tmpItem.szName[sizeof(tmpItem.szName) - 1] = 0;
+ _splitpath(szFileName, szDrive, szPath, NULL, NULL);
+ mir_snprintf(szFinalName, MAX_PATH, "%s\\%s\\%s", szDrive, szPath, buffer);
+ tmpItem.alpha = GetPrivateProfileIntA(itemname, "Alpha", 100, szFileName);
+ tmpItem.alpha = min(tmpItem.alpha, 100);
+ tmpItem.alpha = (BYTE)((FLOAT)(((FLOAT) tmpItem.alpha) / 100) * 255);
+ tmpItem.bf.SourceConstantAlpha = tmpItem.alpha;
+ tmpItem.bLeft = GetPrivateProfileIntA(itemname, "Left", 0, szFileName);
+ tmpItem.bRight = GetPrivateProfileIntA(itemname, "Right", 0, szFileName);
+ tmpItem.bTop = GetPrivateProfileIntA(itemname, "Top", 0, szFileName);
+ tmpItem.bBottom = GetPrivateProfileIntA(itemname, "Bottom", 0, szFileName);
+ if(tmpItem.dwFlags & IMAGE_GLYPH) {
+ tmpItem.width = tmpItem.glyphMetrics[2];
+ tmpItem.height = tmpItem.glyphMetrics[3];
+ tmpItem.inner_height = tmpItem.glyphMetrics[3] - tmpItem.bTop - tmpItem.bBottom;
+ tmpItem.inner_width = tmpItem.glyphMetrics[2] - tmpItem.bRight - tmpItem.bLeft;
+
+ if(tmpItem.bTop && tmpItem.bBottom && tmpItem.bLeft && tmpItem.bRight)
+ tmpItem.dwFlags |= IMAGE_FLAG_DIVIDED;
+ tmpItem.bf.BlendFlags = 0;
+ tmpItem.bf.BlendOp = AC_SRC_OVER;
+ tmpItem.bf.AlphaFormat = 0;
+ tmpItem.dwFlags |= IMAGE_PERPIXEL_ALPHA;
+ tmpItem.bf.AlphaFormat = AC_SRC_ALPHA;
+ if(tmpItem.inner_height <= 0 || tmpItem.inner_width <= 0) {
+ ReleaseDC(pcli->hwndContactList, hdc);
+ return;
+ }
+ }
+ GetPrivateProfileStringA(itemname, "Fillcolor", "None", buffer, 500, szFileName);
+ if(strcmp(buffer, "None")) {
+ COLORREF fillColor = Utils::hexStringToLong(buffer);
+ tmpItem.fillBrush = CreateSolidBrush(fillColor);
+ tmpItem.dwFlags |= IMAGE_FILLSOLID;
+ }
+ else
+ tmpItem.fillBrush = 0;
+
+ GetPrivateProfileStringA(itemname, "Stretch", "None", buffer, 500, szFileName);
+ if(buffer[0] == 'B' || buffer[0] == 'b')
+ tmpItem.bStretch = IMAGE_STRETCH_B;
+ else if(buffer[0] == 'h' || buffer[0] == 'H')
+ tmpItem.bStretch = IMAGE_STRETCH_V;
+ else if(buffer[0] == 'w' || buffer[0] == 'W')
+ tmpItem.bStretch = IMAGE_STRETCH_H;
+ tmpItem.hbm = 0;
+
+ if(!_stricmp(itemname, "$glyphs")) {
+ createImageItem(&tmpItem, szFinalName, hdc);
+ if(tmpItem.hbm) {
+ newItem = reinterpret_cast<TImageItem *>(malloc(sizeof(TImageItem)));
+ ZeroMemory(newItem, sizeof(TImageItem));
+ *newItem = tmpItem;
+ Skin::glyphItem = newItem;
+ }
+ goto imgread_done;
+ }
+ if(itemname[0] == '@') {
+ if(!(tmpItem.dwFlags & IMAGE_GLYPH))
+ createImageItem(&tmpItem, szFinalName, hdc);
+ if(tmpItem.hbm || tmpItem.dwFlags & IMAGE_GLYPH) {
+
+ newItem = reinterpret_cast<TImageItem *>(malloc(sizeof(TImageItem)));
+ ZeroMemory(newItem, sizeof(TImageItem));
+ *newItem = tmpItem;
+
+ if(Skin::imageItems == NULL)
+ Skin::imageItems = newItem;
+ else {
+ TImageItem *pItem = Skin::imageItems;
+
+ while(pItem->nextItem != 0)
+ pItem = pItem->nextItem;
+ pItem->nextItem = newItem;
+ }
+ }
+ goto imgread_done;
+ }
+ for(n = 0;;n++) {
+ mir_snprintf(szItemNr, 30, "Item%d", n);
+ GetPrivateProfileStringA(itemname, szItemNr, "None", buffer, 500, szFileName);
+ if(!strcmp(buffer, "None"))
+ break;
+ if(!stricmp(buffer, "CLUI") || !stricmp(buffer, "CLUIAero") || !stricmp(buffer, "CLUIClient")) {
+ if(!(tmpItem.dwFlags & IMAGE_GLYPH))
+ createImageItem(&tmpItem, szFinalName, hdc);
+ if(tmpItem.hbm || tmpItem.dwFlags & IMAGE_GLYPH) {
+ COLORREF clr;
+
+ newItem = reinterpret_cast<TImageItem *>(malloc(sizeof(TImageItem)));
+ ZeroMemory(newItem, sizeof(TImageItem));
+ *newItem = tmpItem;
+
+ if(!stricmp(buffer, "CLUIAero"))
+ CLUI::bgImageItem = newItem;
+ else if(!stricmp(buffer, "CLUIClient"))
+ CLUI::bgClientItem = newItem;
+ else {
+ GetPrivateProfileStringA(itemname, "Colorkey", "e5e5e5", buffer, 500, szFileName);
+ clr = Utils::hexStringToLong(buffer);
+ cfg::dat.colorkey = clr;
+ cfg::writeDword("CLUI", "ColorKey", clr);
+ if(g_CLUISkinnedBkColor)
+ DeleteObject(g_CLUISkinnedBkColor);
+ g_CLUISkinnedBkColor = CreateSolidBrush(clr);
+ g_CLUISkinnedBkColorRGB = clr;
+ CLUI::bgImageItem_nonAero = newItem;
+ }
+ }
+ continue;
+ }
+ for(i = 0; i <= Skin::ID_EXTBK_LAST; i++) {
+ if(!_stricmp(Skin::statusItems[i].szName[0] == '{' ? &Skin::statusItems[i].szName[3] : Skin::statusItems[i].szName, buffer)) {
+ if(!alloced) {
+ if(!(tmpItem.dwFlags & IMAGE_GLYPH))
+ createImageItem(&tmpItem, szFinalName, hdc);
+ if(tmpItem.hbm || tmpItem.dwFlags & IMAGE_GLYPH) {
+ newItem = reinterpret_cast<TImageItem *>(malloc(sizeof(TImageItem)));
+ ZeroMemory(newItem, sizeof(TImageItem));
+ *newItem = tmpItem;
+ Skin::statusItems[i].imageItem = newItem;
+ if(Skin::imageItems == NULL)
+ Skin::imageItems = newItem;
+ else {
+ TImageItem *pItem = Skin::imageItems;
+
+ while(pItem->nextItem != 0)
+ pItem = pItem->nextItem;
+ pItem->nextItem = newItem;
+ }
+ alloced = TRUE;
+ }
+ }
+ else if(newItem != NULL)
+ Skin::statusItems[i].imageItem = newItem;
+ }
+ }
+ }
+ }
+imgread_done:
+ ReleaseDC(pcli->hwndContactList, hdc);
+
+}
+
+void SkinLoader::readButtonItem(const char *itemName, const char *file)
+{
+ TButtonItem tmpItem, *newItem;
+ char szBuffer[1024];
+ TImageItem *imgItem = Skin::imageItems;
+
+ ZeroMemory(&tmpItem, sizeof(tmpItem));
+ mir_snprintf(tmpItem.szName, sizeof(tmpItem.szName), "%s", &itemName[1]);
+ tmpItem.width = GetPrivateProfileIntA(itemName, "Width", 16, file);
+ tmpItem.height = GetPrivateProfileIntA(itemName, "Height", 16, file);
+ tmpItem.xOff = GetPrivateProfileIntA(itemName, "xoff", 0, file);
+ tmpItem.yOff = GetPrivateProfileIntA(itemName, "yoff", 0, file);
+
+ tmpItem.dwFlags |= GetPrivateProfileIntA(itemName, "toggle", 0, file) ? BUTTON_ISTOGGLE : 0;
+ tmpItem.dwFlags |= (GetPrivateProfileIntA(itemName, "FakeTitleButton", 0, file) ? (BUTTON_FRAMELESS_ONLY | BUTTON_FAKE_CAPTIONBUTTON) : 0);
+
+ GetPrivateProfileStringA(itemName, "Pressed", "None", szBuffer, 1000, file);
+ if(!_stricmp(szBuffer, "default"))
+ tmpItem.imgPressed = Skin::statusItems[ID_EXTBKBUTTONSPRESSED].imageItem;
+ else {
+ while(imgItem) {
+ if(!_stricmp(&imgItem->szName[1], szBuffer)) {
+ tmpItem.imgPressed = imgItem;
+ break;
+ }
+ imgItem = imgItem->nextItem;
+ }
+ }
+
+ imgItem = Skin::imageItems;
+ GetPrivateProfileStringA(itemName, "Normal", "None", szBuffer, 1000, file);
+ if(!_stricmp(szBuffer, "default"))
+ tmpItem.imgNormal = Skin::statusItems[ID_EXTBKBUTTONSNPRESSED].imageItem;
+ else {
+ while(imgItem) {
+ if(!_stricmp(&imgItem->szName[1], szBuffer)) {
+ tmpItem.imgNormal = imgItem;
+ break;
+ }
+ imgItem = imgItem->nextItem;
+ }
+ }
+
+ imgItem = Skin::imageItems;
+ GetPrivateProfileStringA(itemName, "Hover", "None", szBuffer, 1000, file);
+ if(!_stricmp(szBuffer, "default"))
+ tmpItem.imgHover = Skin::statusItems[ID_EXTBKBUTTONSMOUSEOVER].imageItem;
+ else {
+ while(imgItem) {
+ if(!_stricmp(&imgItem->szName[1], szBuffer)) {
+ tmpItem.imgHover = imgItem;
+ break;
+ }
+ imgItem = imgItem->nextItem;
+ }
+ }
+ GetPrivateProfileStringA(itemName, "Align", "lt", szBuffer, 1000, file);
+ if(lstrlenA(szBuffer) == 2) {
+ if(szBuffer[0] =='r' || szBuffer[0] == 'R')
+ tmpItem.dwFlags |= BUTTON_HALIGN_R;
+ if(szBuffer[1] == 'B' || szBuffer[1] == 'B')
+ tmpItem.dwFlags |= BUTTON_VALIGN_B;
+ }
+ GetPrivateProfileStringA(itemName, "NormalGlyph", "0, 0, 0, 0", szBuffer, 1000, file);
+ sscanf(szBuffer, "%d,%d,%d,%d", &tmpItem.normalGlyphMetrics[0], &tmpItem.normalGlyphMetrics[1],
+ &tmpItem.normalGlyphMetrics[2], &tmpItem.normalGlyphMetrics[3]);
+ tmpItem.normalGlyphMetrics[2] = (tmpItem.normalGlyphMetrics[2] - tmpItem.normalGlyphMetrics[0]) + 1;
+ tmpItem.normalGlyphMetrics[3] = (tmpItem.normalGlyphMetrics[3] - tmpItem.normalGlyphMetrics[1]) + 1;
+
+ GetPrivateProfileStringA(itemName, "PressedGlyph", "0, 0, 0, 0", szBuffer, 1000, file);
+ sscanf(szBuffer, "%d,%d,%d,%d", &tmpItem.pressedGlyphMetrics[0], &tmpItem.pressedGlyphMetrics[1],
+ &tmpItem.pressedGlyphMetrics[2], &tmpItem.pressedGlyphMetrics[3]);
+ tmpItem.pressedGlyphMetrics[2] = (tmpItem.pressedGlyphMetrics[2] - tmpItem.pressedGlyphMetrics[0]) + 1;
+ tmpItem.pressedGlyphMetrics[3] = (tmpItem.pressedGlyphMetrics[3] - tmpItem.pressedGlyphMetrics[1]) + 1;
+
+
+ GetPrivateProfileStringA(itemName, "HoverGlyph", "0, 0, 0, 0", szBuffer, 1000, file);
+ sscanf(szBuffer, "%d,%d,%d,%d", &tmpItem.hoverGlyphMetrics[0], &tmpItem.hoverGlyphMetrics[1],
+ &tmpItem.hoverGlyphMetrics[2], &tmpItem.hoverGlyphMetrics[3]);
+ tmpItem.hoverGlyphMetrics[2] = (tmpItem.hoverGlyphMetrics[2] - tmpItem.hoverGlyphMetrics[0]) + 1;
+ tmpItem.hoverGlyphMetrics[3] = (tmpItem.hoverGlyphMetrics[3] - tmpItem.hoverGlyphMetrics[1]) + 1;
+
+ tmpItem.uId = IDC_TBFIRSTUID - 1;
+
+ GetPrivateProfileStringA(itemName, "Action", "Custom", szBuffer, 1000, file);
+ if(!_stricmp(szBuffer, "service")) {
+ tmpItem.szService[0] = 0;
+ GetPrivateProfileStringA(itemName, "Service", "None", szBuffer, 1000, file);
+ if(_stricmp(szBuffer, "None")) {
+ mir_snprintf(tmpItem.szService, 256, "%s", szBuffer);
+ tmpItem.dwFlags |= BUTTON_ISSERVICE;
+ tmpItem.uId = nextButtonID++;
+ }
+ }
+ else if(!_stricmp(szBuffer, "protoservice")) {
+ tmpItem.szService[0] = 0;
+ GetPrivateProfileStringA(itemName, "Service", "None", szBuffer, 1000, file);
+ if(_stricmp(szBuffer, "None")) {
+ mir_snprintf(tmpItem.szService, 256, "%s", szBuffer);
+ tmpItem.dwFlags |= BUTTON_ISPROTOSERVICE;
+ tmpItem.uId = nextButtonID++;
+ }
+ }
+ else if(!_stricmp(szBuffer, "database")) {
+ int n;
+
+ GetPrivateProfileStringA(itemName, "Module", "None", szBuffer, 1000, file);
+ if(_stricmp(szBuffer, "None"))
+ mir_snprintf(tmpItem.szModule, 256, "%s", szBuffer);
+ GetPrivateProfileStringA(itemName, "Setting", "None", szBuffer, 1000, file);
+ if(_stricmp(szBuffer, "None"))
+ mir_snprintf(tmpItem.szSetting, 256, "%s", szBuffer);
+ if(GetPrivateProfileIntA(itemName, "contact", 0, file) != 0)
+ tmpItem.dwFlags |= BUTTON_DBACTIONONCONTACT;
+
+ for(n = 0; n <= 1; n++) {
+ char szKey[20];
+ BYTE *pValue;
+
+ strcpy(szKey, n == 0 ? "dbonpush" : "dbonrelease");
+ pValue = (n == 0 ? tmpItem.bValuePush : tmpItem.bValueRelease);
+
+ GetPrivateProfileStringA(itemName, szKey, "None", szBuffer, 1000, file);
+ switch(szBuffer[0]) {
+ case 'b':
+ {
+ BYTE value = (BYTE)atol(&szBuffer[1]);
+ pValue[0] = value;
+ tmpItem.type = DBVT_BYTE;
+ break;
+ }
+ case 'w':
+ {
+ WORD value = (WORD)atol(&szBuffer[1]);
+ *((WORD *)&pValue[0]) = value;
+ tmpItem.type = DBVT_WORD;
+ break;
+ }
+ case 'd':
+ {
+ DWORD value = (DWORD)atol(&szBuffer[1]);
+ *((DWORD *)&pValue[0]) = value;
+ tmpItem.type = DBVT_DWORD;
+ break;
+ }
+ case 's':
+ {
+ mir_snprintf((char *)pValue, 256, &szBuffer[1]);
+ tmpItem.type = DBVT_ASCIIZ;
+ break;
+ }
+ }
+ }
+ if(tmpItem.szModule[0] && tmpItem.szSetting[0]) {
+ tmpItem.dwFlags |= BUTTON_ISDBACTION;
+ if(tmpItem.szModule[0] == '$' && (tmpItem.szModule[1] == 'c' || tmpItem.szModule[1] == 'C'))
+ tmpItem.dwFlags |= BUTTON_ISCONTACTDBACTION;
+ tmpItem.uId = nextButtonID++;
+ }
+ }
+ else if(_stricmp(szBuffer, "Custom")) {
+ int i = 0;
+
+ while(top_buttons[i].id) {
+ if(!_stricmp(top_buttons[i].szIcoLibIcon, szBuffer)) {
+ tmpItem.uId = top_buttons[i].id;
+ tmpItem.dwFlags |= BUTTON_ISINTERNAL;
+ break;
+ }
+ i++;
+ }
+ }
+ GetPrivateProfileStringA(itemName, "PassContact", "None", szBuffer, 1000, file);
+ if(_stricmp(szBuffer, "None")) {
+ if(szBuffer[0] == 'w' || szBuffer[0] == 'W')
+ tmpItem.dwFlags |= BUTTON_PASSHCONTACTW;
+ else if(szBuffer[0] == 'l' || szBuffer[0] == 'L')
+ tmpItem.dwFlags |= BUTTON_PASSHCONTACTL;
+ }
+
+ GetPrivateProfileStringA(itemName, "Tip", "None", szBuffer, 1000, file);
+ if(strcmp(szBuffer, "None")) {
+ MultiByteToWideChar(cfg::dat.langPackCP, 0, szBuffer, -1, tmpItem.szTip, 256);
+ tmpItem.szTip[255] = 0;
+ }
+ else
+ tmpItem.szTip[0] = 0;
+
+ // create it
+
+ newItem = (TButtonItem *)malloc(sizeof(TButtonItem));
+ ZeroMemory(newItem, sizeof(TButtonItem));
+ if(CLUI::buttonItems == NULL) {
+ CLUI::buttonItems = newItem;
+ *newItem = tmpItem;
+ newItem->nextItem = 0;
+ }
+ else {
+ TButtonItem *curItem = CLUI::buttonItems;
+ while(curItem->nextItem)
+ curItem = curItem->nextItem;
+ *newItem = tmpItem;
+ newItem->nextItem = 0;
+ curItem->nextItem = newItem;
+ }
+ newItem->hWnd = CreateWindowEx(0, _T("CLCButtonClass"), _T(""), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 5, 5, pcli->hwndContactList, (HMENU)newItem->uId, g_hInst, NULL);
+
+ SendMessage(newItem->hWnd, BM_SETBTNITEM, 0, (LPARAM)newItem);
+ SendMessage(newItem->hWnd, BUTTONSETASFLATBTN, 0, 0);
+ SendMessage(newItem->hWnd, BUTTONSETASFLATBTN + 10, 0, 0);
+ if(newItem->dwFlags & BUTTON_ISTOGGLE)
+ SendMessage(newItem->hWnd, BUTTONSETASPUSHBTN, 0, 0);
+
+ if(newItem->szTip[0])
+ SendMessage(newItem->hWnd, BUTTONADDTOOLTIP, (WPARAM)newItem->szTip, 0);
+ return;
+}
+
+void SkinLoader::createImageItem(TImageItem *item, const char *fileName, HDC hdc)
+{
+ HBITMAP hbm = Gfx::loadPNG(fileName);
+ BITMAP bm;
+
+ if(hbm) {
+ item->hbm = hbm;
+ item->bf.BlendFlags = 0;
+ item->bf.BlendOp = AC_SRC_OVER;
+ item->bf.AlphaFormat = 0;
+
+ GetObject(hbm, sizeof(bm), &bm);
+ if(bm.bmBitsPixel == 32) {
+ Gfx::preMultiply(hbm, 1);
+ item->dwFlags |= IMAGE_PERPIXEL_ALPHA;
+ item->bf.AlphaFormat = AC_SRC_ALPHA;
+ }
+ item->width = bm.bmWidth;
+ item->height = bm.bmHeight;
+ item->inner_height = item->height - item->bTop - item->bBottom;
+ item->inner_width = item->width - item->bLeft - item->bRight;
+ if(item->bTop && item->bBottom && item->bLeft && item->bRight) {
+ item->dwFlags |= IMAGE_FLAG_DIVIDED;
+ if(item->inner_height <= 0 || item->inner_width <= 0) {
+ DeleteObject(hbm);
+ item->hbm = 0;
+ return;
+ }
+ }
+ item->hdc = CreateCompatibleDC(hdc);
+ item->hbmOld = reinterpret_cast<HBITMAP>(SelectObject(item->hdc, item->hbm));
+ }
+}
diff --git a/plugins/Clist_ng/SRC/statusbar.cpp b/plugins/Clist_ng/SRC/statusbar.cpp new file mode 100644 index 0000000000..c0bcbf61f6 --- /dev/null +++ b/plugins/Clist_ng/SRC/statusbar.cpp @@ -0,0 +1,202 @@ +/*
+* astyle --force-indent=tab=4 --brackets=linux --indent-switches
+* --pad=oper --one-line=keep-blocks --unpad=paren
+*
+* Miranda IM: the free IM client for Microsoft* Windows*
+*
+* Copyright 2000-2010 Miranda ICQ/IM project,
+* all portions of this codebase are copyrighted to the people
+* listed in contributors.txt.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* you should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* part of clist_ng plugin for Miranda.
+*
+* (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+*
+* $Id: statusbar.cpp 134 2010-10-01 10:23:10Z silvercircle $
+*
+* clist_ng status bar subclassing
+*/
+
+#include <commonheaders.h>
+
+static POINT ptMouse = {0};
+static RECT rcMouse = {0};
+static int timer_set = 0, tooltip_active = 0;
+extern HANDLE hStatusBarShowToolTipEvent, hStatusBarHideToolTipEvent;
+
+#define TIMERID_HOVER 1000
+
+LRESULT CALLBACK NewStatusBarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_SETCURSOR:
+ {
+ POINT pt;
+
+ GetCursorPos(&pt);
+ SendMessage(GetParent(hwnd),msg,wParam,lParam);
+ if (pt.x == ptMouse.x && pt.y == ptMouse.y)
+ return 1;//return(TestCursorOnBorders());
+
+ ptMouse = pt;
+ if (tooltip_active){
+ KillTimer(hwnd, TIMERID_HOVER);
+ if(!NotifyEventHooks(hStatusBarHideToolTipEvent, 0, 0))
+ CallService("mToolTip/HideTip", 0, 0);
+ tooltip_active = FALSE;
+ }
+ KillTimer(hwnd, TIMERID_HOVER);
+ SetTimer(hwnd, TIMERID_HOVER, 750, 0);
+ break;
+ }
+ case WM_NCHITTEST:
+ {
+ LRESULT lr = SendMessage(GetParent(hwnd), WM_NCHITTEST, wParam, lParam);
+ if(lr == HTLEFT || lr == HTRIGHT || lr == HTBOTTOM || lr == HTTOP || lr == HTTOPLEFT || lr == HTTOPRIGHT
+ || lr == HTBOTTOMLEFT || lr == HTBOTTOMRIGHT)
+ return HTTRANSPARENT;
+ break;
+ }
+ case WM_ERASEBKGND:
+ return(1);
+
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ KillTimer(hwnd, TIMERID_HOVER);
+ if(!NotifyEventHooks(hStatusBarHideToolTipEvent, 0, 0))
+ CallService("mToolTip/HideTip", 0, 0);
+ tooltip_active = FALSE;
+ break;
+
+ case WM_PAINT: {
+ if(cfg::shutDown)
+ return 0;
+
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ HDC hdcMem;
+ HANDLE hbp = 0;
+ RECT rcClient;
+ TStatusItem* item = NULL;
+ DRAWITEMSTRUCT dis = {0};
+ int nParts = 0;
+ int i;
+ HFONT hOldFont = 0;
+ HANDLE hTheme;
+ BYTE windowStyle = cfg::getByte("CLUI", "WindowStyle", SETTING_WINDOWSTYLE_DEFAULT);
+ LONG b_offset = (windowStyle == SETTING_WINDOWSTYLE_NOBORDER ? 2 : (windowStyle == SETTING_WINDOWSTYLE_THINBORDER ? 1 : 0));
+
+ GetClientRect(hwnd, &rcClient);
+ INIT_PAINT(hdc, rcClient, hdcMem);
+ SetBkMode(hdcMem, TRANSPARENT);
+ hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, GetStockObject(DEFAULT_GUI_FONT)));
+ Gfx::drawBGFromSurface(hwnd, rcClient, hdcMem);
+ item = &Skin::statusItems[ID_EXTBKSTATUSBAR];
+ if(!item->IGNORED) {
+ RECT rc = rcClient;
+ RGBQUAD* rgb = 0;
+ int iWidth;
+
+ Api::pfnGetBufferedPaintBits(hbp, &rgb, &iWidth);
+ AGGPaintHelper* ph = new AGGPaintHelper(hdcMem);
+ ph->aggctx->attach(rgb, iWidth, rc.bottom);
+ ph->current_shape = 0;
+
+ rc.left += item->MARGIN_LEFT;
+ rc.right -= item->MARGIN_RIGHT;
+ if(!Skin::metrics.fHaveFrame) {
+ rc.left += Skin::metrics.cFakeLeftBorder;
+ rc.right -= Skin::metrics.cFakeRightBorder;
+ }
+ rc.top += item->MARGIN_TOP;
+ rc.bottom -= item->MARGIN_BOTTOM;
+ Gfx::renderSkinItem(ph, item, &rc);
+ Gfx::setTextColor(item->TEXTCOLOR);
+ delete ph;
+ }else{
+ Gfx::setTextColor(GetSysColor(COLOR_BTNTEXT));
+ }
+ dis.hwndItem = hwnd;
+ dis.hDC = hdcMem;
+ dis.CtlType = 0;
+ nParts = SendMessage(hwnd, SB_GETPARTS, 0, 0);
+
+ hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON");
+ for(i = 0; i < nParts; i++) {
+ SendMessage(hwnd, SB_GETRECT, i, (LPARAM)&dis.rcItem);
+ OffsetRect(&dis.rcItem, 0, -b_offset);
+ dis.itemData = SendMessage(hwnd, SB_GETTEXTA, i, 0);
+ dis.CtlID = (UINT)hTheme;
+ SendMessage(pcli->hwndContactList, WM_DRAWITEM, 0, (LPARAM)&dis);
+ }
+ Api::pfnCloseThemeData(hTheme);
+ if(hOldFont)
+ SelectObject(hdcMem, hOldFont);
+ FINALIZE_PAINT(hbp, &rcClient, 0);
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ case WM_SIZE:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+
+ case WM_TIMER:
+ if(wParam == TIMERID_HOVER) {
+ POINT pt;
+ KillTimer(hwnd, TIMERID_HOVER);
+
+ GetCursorPos(&pt);
+ if (pt.x == ptMouse.x && pt.y == ptMouse.y) {
+ int i,nParts;
+ RECT rc;
+
+ ScreenToClient(hwnd, &pt);
+ nParts = SendMessage(hwnd, SB_GETPARTS, 0, 0);
+ for(i = 0; i < nParts; i++) {
+ SendMessage(hwnd, SB_GETRECT, i, (LPARAM)&rc);
+ if(PtInRect(&rc,pt)) {
+ ProtocolData *PD;
+ PD = (ProtocolData *)SendMessageA(hwnd, SB_GETTEXTA, i, 0);
+
+ if(PD) {
+ if(NotifyEventHooks(hStatusBarShowToolTipEvent, (WPARAM)PD->RealName, 0) > 0) // a plugin handled this event
+ tooltip_active = TRUE;
+ else if(cfg::getDword("mToolTip", "ShowStatusTip", 0)) {
+ CLCINFOTIP ti = {0};
+ BYTE isLocked = 0;
+ wchar_t szTipText[256], *szStatus = NULL;
+ WORD wStatus;
+
+ ti.cbSize = sizeof(ti);
+ ti.isTreeFocused = GetFocus() == pcli->hwndContactList ? 1 : 0;
+ wStatus = (WORD)CallProtoService(PD->RealName, PS_GETSTATUS, 0, 0);
+ isLocked = cfg::getByte(PD->RealName, "LockMainStatus", 0);
+ szStatus = pcli->pfnGetStatusModeDescription(wStatus, 0);
+ mir_snwprintf(szTipText, 256, L"<b>%s</b>: %s%s", PD->RealName, szStatus, isLocked ? L" (LOCKED)" : L"");
+ CallService("mToolTip/ShowTip", (WPARAM)szTipText, (LPARAM)&ti);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ return CallWindowProc(CLUI::OldStatusBarProc, hwnd, msg, wParam, lParam);
+}
diff --git a/plugins/Clist_ng/SRC/statusfloater.cpp b/plugins/Clist_ng/SRC/statusfloater.cpp new file mode 100644 index 0000000000..0d2353710a --- /dev/null +++ b/plugins/Clist_ng/SRC/statusfloater.cpp @@ -0,0 +1,1170 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+------------------------
+
+implements a simple status floater as a layered (and skinnable) window with
+a minimalistic UI (change status, access main menu). It also may hold a copy
+of the event area.
+
+Also implementes floating contacts (FLT_*() functions)
+
+*/
+
+#include <commonheaders.h>
+
+#define SNAP_SCREEN_TOLERANCE 10
+#define SNAP_FLT_TOLERANCE 10
+#define TOOLTIP_TIMER 1
+
+#define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip"
+#define MS_TOOLTIP_HIDETIP "mToolTip/HideTip"
+
+void FLT_Update(struct ClcData *dat, struct ClcContact *contact);
+void FLT_ShowHideAll(int showCmd);
+void FLT_SnapToEdges(HWND hwnd);
+void FLT_SnapToFloater(HWND hwnd);
+void PaintNotifyArea(HDC hDC, RECT *rc, HANDLE hTheme);
+
+HWND g_hwndSFL = 0;
+HDC g_SFLCachedDC = 0;
+HBITMAP g_SFLhbmOld = 0, g_SFLhbm = 0;
+struct ContactFloater *pFirstFloater = 0;
+BOOL hover = FALSE;
+BOOL tooltip = FALSE;
+int hTooltipTimer = 0;
+POINT start_pos;
+
+extern int g_padding_y;
+
+extern HWND g_hwndEventArea;
+extern HDC g_HDC;
+
+FLOATINGOPTIONS g_floatoptions;
+
+static UINT padctrlIDs[] = { IDC_FLT_PADLEFTSPIN, IDC_FLT_PADRIGHTSPIN, IDC_FLT_PADTOPSPIN,
+ IDC_FLT_PADBOTTOMSPIN, 0 };
+
+/*
+ * floating contacts support functions
+ * simple linked list of allocated ContactFloater* structs
+ */
+
+static struct ContactFloater *FLT_AddToList(struct ContactFloater *pFloater) {
+ struct ContactFloater *pCurrent = pFirstFloater;
+
+ if (!pFirstFloater) {
+ pFirstFloater = pFloater;
+ pFirstFloater->pNextFloater = NULL;
+ return pFirstFloater;
+ } else {
+ while (pCurrent->pNextFloater != 0)
+ pCurrent = pCurrent->pNextFloater;
+ pCurrent->pNextFloater = pFloater;
+ pFloater->pNextFloater = NULL;
+ return pCurrent;
+ }
+}
+
+static struct ContactFloater *FLT_RemoveFromList(struct ContactFloater *pFloater) {
+ struct ContactFloater *pCurrent = pFirstFloater;
+
+ if (pFloater == pFirstFloater) {
+ if(pFloater->pNextFloater != NULL)
+ pFirstFloater = pFloater->pNextFloater;
+ else
+ pFirstFloater = NULL;
+ return pFirstFloater;
+ }
+
+ do {
+ if (pCurrent->pNextFloater == pFloater) {
+ pCurrent->pNextFloater = pCurrent->pNextFloater->pNextFloater;
+ return 0;
+ }
+ } while (pCurrent = pCurrent->pNextFloater);
+
+ return NULL;
+}
+
+void FLT_SnapToEdges(HWND hwnd)
+{
+ RECT dr;
+ MONITORINFO monInfo;
+ RECT rcWindow;
+ HMONITOR curMonitor;
+
+ HWND onTop = g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST;
+
+ curMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+
+ monInfo.cbSize = sizeof(monInfo);
+ GetMonitorInfo(curMonitor, &monInfo);
+
+ dr = monInfo.rcWork;
+ GetWindowRect(hwnd, &rcWindow);
+
+ if (rcWindow.left < dr.left + SNAP_SCREEN_TOLERANCE){
+ SetWindowPos(hwnd, onTop, 0, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetWindowRect(hwnd, &rcWindow);
+ }
+
+ if (rcWindow.top < dr.top + SNAP_SCREEN_TOLERANCE){
+ SetWindowPos(hwnd, onTop, rcWindow.left, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetWindowRect(hwnd, &rcWindow);
+ }
+
+ if (rcWindow.right > dr.right - SNAP_SCREEN_TOLERANCE)
+ SetWindowPos(hwnd, onTop, dr.right - (rcWindow.right - rcWindow.left), rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ if (rcWindow.bottom > dr.bottom - SNAP_SCREEN_TOLERANCE)
+ SetWindowPos(hwnd, onTop, rcWindow.left, dr.bottom - (rcWindow.bottom - rcWindow.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+}
+
+void FLT_SnapToFloater(HWND hwnd)
+{
+ struct ContactFloater *pCurrent = pFirstFloater;
+ RECT rcWindow, rcBase;
+ int minTop = 0xFFFFFF, minBottom = 0xFFFFFF, minRight = 0xFFFFFF, minLeft = 0xFFFFFF;
+ int posTop = 0, posBottom = 0, posRight = 0, posLeft = 0;
+ HWND onTop = g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST;
+
+ GetWindowRect(hwnd, &rcBase);
+
+ //find the closest floater
+ while(pCurrent) {
+ GetWindowRect(pCurrent->hwnd, &rcWindow);
+ //top
+ if((rcWindow.top - rcBase.bottom > -SNAP_FLT_TOLERANCE) && (rcWindow.top - rcBase.bottom < minTop)){
+ posTop = rcWindow.top;
+ minTop = rcWindow.top - rcBase.bottom;
+ }
+ //bottom
+ if((rcBase.top - rcWindow.bottom > -SNAP_FLT_TOLERANCE) && (rcBase.top - rcWindow.bottom < minBottom)){
+ posBottom = rcWindow.bottom;
+ minBottom = rcBase.top - rcWindow.bottom;
+ }
+ //left
+ if((rcWindow.left - rcBase.right > -SNAP_FLT_TOLERANCE) && (rcWindow.left - rcBase.right < minLeft)){
+ posLeft= rcWindow.left;
+ minLeft = rcWindow.left - rcBase.right;
+ }
+ //right
+ if((rcBase.left - rcWindow.right > -SNAP_FLT_TOLERANCE) && (rcBase.left - rcWindow.right < minRight)){
+ posRight= rcWindow.right;
+ minRight = rcBase.left - rcWindow.right;
+ }
+ pCurrent = pCurrent->pNextFloater;
+ }
+
+ //snap to the closest floater if spacing is under SNAP_FLT_TOLERANCE
+ if (posTop && (rcBase.bottom > posTop - SNAP_FLT_TOLERANCE))
+ SetWindowPos(hwnd, onTop, rcBase.left, posTop - (rcBase.bottom - rcBase.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ if (posBottom && (rcBase.top < posBottom + SNAP_FLT_TOLERANCE))
+ SetWindowPos(hwnd, onTop, rcBase.left, posBottom, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ if (posLeft && (rcBase.right > posLeft - SNAP_FLT_TOLERANCE))
+ SetWindowPos(hwnd, onTop, posLeft - (rcBase.right - rcBase.left), rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+
+ if (posRight && (rcBase.left < posRight + SNAP_FLT_TOLERANCE))
+ SetWindowPos(hwnd, onTop, posRight, rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+}
+
+/*
+ * dialog procedure for the floating contacts option page
+ */
+
+INT_PTR CALLBACK cfg::DlgProcFloatingContacts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ DWORD dwFlags = g_floatoptions.dwFlags;
+ int i = 0;
+
+ TranslateDialogDefault(hwndDlg);
+
+ CheckDlgButton(hwndDlg, IDC_FLT_ENABLED, g_floatoptions.enabled);
+ SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_ENABLED, 0);
+ CheckDlgButton(hwndDlg, IDC_FLT_SIMPLELAYOUT, dwFlags & FLT_SIMPLE);
+ SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_SIMPLELAYOUT, 0);
+ CheckDlgButton(hwndDlg, IDC_FLT_AVATARS, dwFlags & FLT_AVATARS);
+ CheckDlgButton(hwndDlg, IDC_FLT_DUALROWS, dwFlags & FLT_DUALROW);
+ CheckDlgButton(hwndDlg, IDC_FLT_EXTRAICONS, dwFlags & FLT_EXTRAICONS);
+ CheckDlgButton(hwndDlg, IDC_FLT_SYNCED, dwFlags & FLT_SYNCWITHCLIST);
+ CheckDlgButton(hwndDlg, IDC_FLT_AUTOHIDE, dwFlags & FLT_AUTOHIDE);
+ CheckDlgButton(hwndDlg, IDC_FLT_SNAP, dwFlags & FLT_SNAP);
+ CheckDlgButton(hwndDlg, IDC_FLT_BORDER, dwFlags & FLT_BORDER);
+ CheckDlgButton(hwndDlg, IDC_FLT_ONTOP, dwFlags & FLT_ONTOP);
+ SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_BORDER, 0);
+ CheckDlgButton(hwndDlg, IDC_FLT_FILLSTD, dwFlags & FLT_FILLSTDCOLOR);
+
+ if (ServiceExists(MS_TOOLTIP_SHOWTIP))
+ {
+ CheckDlgButton(hwndDlg, IDC_FLT_SHOWTOOLTIPS, dwFlags & FLT_SHOWTOOLTIPS);
+ SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_SHOWTOOLTIPS, 0);
+ CheckDlgButton(hwndDlg, IDC_FLT_DEFHOVERTIME, g_floatoptions.def_hover_time);
+ SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_DEFHOVERTIME, 0);
+ }
+ else
+ {
+ CheckDlgButton(hwndDlg, IDC_FLT_SHOWTOOLTIPS, 0);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_SHOWTOOLTIPS, 0);
+ }
+
+ for(i = 0; padctrlIDs[i] != 0; i++)
+ SendDlgItemMessage(hwndDlg, padctrlIDs[i], UDM_SETRANGE, 0, MAKELONG(20, 0));
+ SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_SETRANGE, 0, MAKELONG(200, 50));
+ SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_SETRANGE, 0, MAKELONG(5000, 1));
+
+
+ SendDlgItemMessage(hwndDlg, IDC_FLT_PADLEFTSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_left);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_PADRIGHTSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_right);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_top);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_top);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.width);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.hover_time);
+
+ SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_SETPOS, TRUE, g_floatoptions.act_trans);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_SETRANGE, FALSE, MAKELONG(1, 255));
+ SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_SETPOS, TRUE, g_floatoptions.trans);
+ SendMessage(hwndDlg, WM_HSCROLL, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_SETDEFAULTCOLOUR, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_SETCOLOUR, 0, g_floatoptions.border_colour);
+
+ FLT_ShowHideAll(SW_SHOWNOACTIVATE);
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_FLT_ENABLED:
+ {
+ int isEnabled = IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED);
+ int isSimple = IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT);
+ int isBorder = IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER);
+ int isTooltip = IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS);
+ int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME);
+
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_SIMPLELAYOUT, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_SYNCED, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_AUTOHIDE, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_SNAP, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_ACTIVEOPACITY, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_OPACITY, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADLEFTSPIN, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADRIGHTSPIN, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADTOPSPIN, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADLEFT, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADRIGHT, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADTOP, isEnabled);
+ //EnableWindow(GetDlgItem(hwndDlg, IDC_FLT_PADBOTTOMSPIN), isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_PADBOTTOM, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_WIDTHSPIN, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_WIDTH, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDER, isEnabled);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDERCOLOUR, isEnabled & isBorder);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_SHOWTOOLTIPS, isEnabled & ServiceExists(MS_TOOLTIP_SHOWTIP));
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_DEFHOVERTIME, isEnabled & isTooltip);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, isEnabled & isTooltip & !isDefHoverTime);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, isEnabled & isTooltip & !isDefHoverTime);
+
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_AVATARS, isEnabled & !isSimple);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_EXTRAICONS, isEnabled & !isSimple);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_DUALROWS, isEnabled & !isSimple);
+ }
+ break;
+ case IDC_FLT_SIMPLELAYOUT:
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)){
+ int isSimple = IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_AVATARS, !isSimple);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_EXTRAICONS, !isSimple);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_DUALROWS, !isSimple);
+ }
+ }
+ break;
+ case IDC_FLT_BORDER:
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)){
+ int isBorder = IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDERCOLOUR, isBorder);
+ }
+ }
+ break;
+ case IDC_FLT_SHOWTOOLTIPS:
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)){
+ int isTooltip = IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS);
+ int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_DEFHOVERTIME, isTooltip);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, isTooltip & !isDefHoverTime);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, isTooltip & !isDefHoverTime);
+ }
+ }
+ break;
+ case IDC_FLT_DEFHOVERTIME:
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED) && IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS)){
+ int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, !isDefHoverTime);
+ Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, !isDefHoverTime);
+ }
+ }
+ break;
+
+ case IDC_FLT_PADTOP:
+ {
+ if(HIWORD(wParam) == EN_CHANGE){
+ int value = SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_GETPOS, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_SETPOS, 0, (LPARAM)value);
+ }
+ }
+ break;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_HSCROLL:
+ {
+ char str[10];
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_FLT_ACTIVEOPACITYVALUE, str);
+ wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_GETPOS, 0, 0) / 255);
+ SetDlgItemTextA(hwndDlg, IDC_FLT_OPACITYVALUE, str);
+
+ if (lParam)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR) lParam)->code) {
+ case PSN_APPLY:
+ {
+ g_floatoptions.enabled = IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED) ? 1 : 0;
+ g_floatoptions.dwFlags = 0;
+
+ if(IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT))
+ g_floatoptions.dwFlags = FLT_SIMPLE;
+
+ g_floatoptions.dwFlags |= (IsDlgButtonChecked(hwndDlg, IDC_FLT_AVATARS) ? FLT_AVATARS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_DUALROWS) ? FLT_DUALROW : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_EXTRAICONS) ? FLT_EXTRAICONS : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_SYNCED) ? FLT_SYNCWITHCLIST : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_AUTOHIDE) ? FLT_AUTOHIDE : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_SNAP) ? FLT_SNAP : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER) ? FLT_BORDER : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_FILLSTD) ? FLT_FILLSTDCOLOR : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_ONTOP) ? FLT_ONTOP : 0) |
+ (IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS) ? FLT_SHOWTOOLTIPS : 0);
+
+ g_floatoptions.act_trans = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_GETPOS, 0, 0);
+ g_floatoptions.trans = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_GETPOS, 0, 0);
+ g_floatoptions.pad_left = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADLEFTSPIN, UDM_GETPOS, 0, 0);
+ g_floatoptions.pad_right = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADRIGHTSPIN, UDM_GETPOS, 0, 0);
+ g_floatoptions.pad_top = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_GETPOS, 0, 0);
+ g_floatoptions.pad_bottom = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_GETPOS, 0, 0);
+ g_floatoptions.width = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_GETPOS, 0, 0);
+ g_floatoptions.border_colour = SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_GETCOLOUR, 0, 0);
+
+ g_floatoptions.def_hover_time= IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME) ? 1 : 0;
+ if (g_floatoptions.def_hover_time)
+ g_floatoptions.hover_time = cfg::getWord("CLC", "InfoTipHoverTime", 200);
+ else
+ g_floatoptions.hover_time = (WORD)SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_GETPOS, 0, 0);
+
+ FLT_WriteOptions();
+ FLT_RefreshAll();
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+void FLT_ReadOptions()
+{
+ DWORD dwPad;
+
+ ZeroMemory(&g_floatoptions, sizeof(FLOATINGOPTIONS));
+
+ g_floatoptions.enabled = cfg::getByte("CList", "flt_enabled", 0);
+ g_floatoptions.dwFlags = cfg::getDword("CList", "flt_flags", FLT_SIMPLE);
+ dwPad = cfg::getDword("CList", "flt_padding", 0);
+
+ g_floatoptions.pad_top = LOBYTE(LOWORD(dwPad));
+ g_floatoptions.pad_right = HIBYTE(LOWORD(dwPad));
+ g_floatoptions.pad_bottom = LOBYTE(HIWORD(dwPad));
+ g_floatoptions.pad_left = HIBYTE(HIWORD(dwPad));
+
+ g_floatoptions.width = cfg::getDword("CList", "flt_width", 100);
+ g_floatoptions.act_trans = cfg::getByte("CList", "flt_acttrans", 255);
+ g_floatoptions.trans = cfg::getByte("CList", "flt_trans", 255);
+ g_floatoptions.border_colour = cfg::getDword("CList", "flt_bordercolour", 0);
+ g_floatoptions.def_hover_time = cfg::getByte("CList", "flt_defhovertime", 1);
+
+ if (g_floatoptions.def_hover_time)
+ g_floatoptions.hover_time = cfg::getWord("CLC", "InfoTipHoverTime", 200);
+ else
+ g_floatoptions.hover_time = cfg::getWord("CList", "flt_hovertime", 200);
+
+}
+
+void FLT_WriteOptions()
+{
+ DWORD dwPad;
+
+ cfg::writeByte("CList", "flt_enabled", g_floatoptions.enabled);
+ cfg::writeDword("CList", "flt_flags", g_floatoptions.dwFlags);
+ dwPad = MAKELONG(MAKEWORD(g_floatoptions.pad_top, g_floatoptions.pad_right),
+ MAKEWORD(g_floatoptions.pad_bottom, g_floatoptions.pad_left));
+ cfg::writeDword("CList", "flt_padding", dwPad);
+ cfg::writeDword("CList", "flt_width", g_floatoptions.width);
+ cfg::writeByte("CList", "flt_acttrans", g_floatoptions.act_trans);
+ cfg::writeByte("CList", "flt_trans", g_floatoptions.trans);
+ cfg::writeDword("CList", "flt_bordercolour", g_floatoptions.border_colour);
+ cfg::writeByte("CList", "flt_defhovertime", g_floatoptions.def_hover_time);
+ if (!g_floatoptions.def_hover_time)
+ cfg::writeWord("CList", "flt_hovertime", g_floatoptions.hover_time);
+
+}
+
+LRESULT CALLBACK StatusFloaterClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_DESTROY:
+ Utils_SaveWindowPosition(hwnd, 0, "CLUI", "sfl");
+ if(g_SFLCachedDC) {
+ SelectObject(g_SFLCachedDC, g_SFLhbmOld);
+ DeleteObject(g_SFLhbm);
+ DeleteDC(g_SFLCachedDC);
+ g_SFLCachedDC = 0;
+ }
+ break;
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+
+ hdc = BeginPaint(hwnd, &ps);
+ ps.fErase = FALSE;
+ EndPaint(hwnd, &ps);
+ return TRUE;
+ }
+ case WM_LBUTTONDOWN:
+ {
+ POINT ptMouse;
+ RECT rcWindow;
+
+ GetCursorPos(&ptMouse);
+ GetWindowRect(hwnd, &rcWindow);
+ rcWindow.right = rcWindow.left + 25;
+ if(!PtInRect(&rcWindow, ptMouse))
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(ptMouse.x, ptMouse.y));
+ break;
+ }
+ case WM_LBUTTONUP:
+ {
+ HMENU hmenu = Menu_GetStatusMenu();
+ RECT rcWindow;
+ POINT pt;
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwnd, &rcWindow);
+ if(cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS) {
+ if(pt.y > rcWindow.top + ((rcWindow.bottom - rcWindow.top) / 2))
+ SendMessage(g_hwndEventArea, WM_COMMAND, MAKEWPARAM(IDC_NOTIFYBUTTON, 0), 0);
+ else
+ TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL);
+ }
+ else
+ TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL);
+ return 0;
+ }
+ case WM_CONTEXTMENU:
+ {
+ HMENU hmenu = Menu_GetMainMenu();
+ RECT rcWindow;
+
+ GetWindowRect(hwnd, &rcWindow);
+ TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL);
+ return 0;
+ }
+
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void CALLBACK ShowTooltip(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
+ struct ContactFloater *pCurrent = pFirstFloater;
+ POINT pt;
+ CLCINFOTIP ti = {0};
+
+ KillTimer(hwnd, TOOLTIP_TIMER);
+ hTooltipTimer = 0;
+
+ GetCursorPos(&pt);
+ if ((abs(pt.x - start_pos.x) > 3) && (abs(pt.y - start_pos.y) > 3)) return;
+
+ while(pCurrent->hwnd != hwnd)
+ pCurrent = pCurrent->pNextFloater;
+
+ ti.cbSize = sizeof(ti);
+ ti.isGroup = 0;
+ ti.isTreeFocused = 0;
+ ti.hItem = (HANDLE)pCurrent->hContact;
+ ti.ptCursor = pt;
+ CallService(MS_TOOLTIP_SHOWTIP, 0, (LPARAM)&ti);
+ tooltip = TRUE;
+}
+
+LRESULT CALLBACK ContactFloaterClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR iEntry = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ struct TExtraCache *centry = NULL;
+
+ if(iEntry >= 0 && iEntry < cfg::nextCacheEntry)
+ centry = &cfg::eCache[iEntry];
+
+ switch(msg) {
+ case WM_NCCREATE:
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
+ iEntry = (int)cs->lpCreateParams;
+ if(iEntry >= 0 && iEntry < cfg::nextCacheEntry)
+ centry = &cfg::eCache[iEntry];
+ return TRUE;
+ }
+ case WM_DESTROY:
+ if(centry) {
+ SelectObject(centry->floater->hdc, centry->floater->hbmOld);
+ DeleteObject(centry->floater->hbm);
+ DeleteDC(centry->floater->hdc);
+ FLT_RemoveFromList(centry->floater);
+ free(centry->floater);
+ centry->floater = 0;
+ Utils_SaveWindowPosition(hwnd, centry->hContact, "CList", "flt");
+ break;
+ }
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+
+ hdc = BeginPaint(hwnd, &ps);
+ ps.fErase = FALSE;
+ EndPaint(hwnd, &ps);
+ return TRUE;
+ }
+ case WM_LBUTTONDBLCLK:
+ if(centry)
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)centry->hContact, 0);
+ return 0;
+ case WM_LBUTTONDOWN:
+ {
+ POINT ptMouse;
+ RECT rcWindow;
+
+ GetCursorPos(&ptMouse);
+ GetWindowRect(hwnd, &rcWindow);
+ rcWindow.right = rcWindow.left + 25;
+ if(!PtInRect(&rcWindow, ptMouse))
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(ptMouse.x, ptMouse.y));
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if(!hover) {
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_HOVER | TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = 5;
+ TrackMouseEvent(&tme);
+ hover = TRUE;
+ }
+ if ( ServiceExists( MS_TOOLTIP_SHOWTIP )) {
+ if ((g_floatoptions.dwFlags & FLT_SHOWTOOLTIPS) && !tooltip) {
+ GetCursorPos(&start_pos);
+ if (hTooltipTimer) KillTimer(hwnd, TOOLTIP_TIMER);
+ hTooltipTimer = SetTimer(hwnd, TOOLTIP_TIMER, g_floatoptions.hover_time, ShowTooltip);
+ }
+ }
+
+ return FALSE;
+
+ case WM_MOUSEHOVER:
+ {
+ struct ClcContact *contact = NULL;
+ struct ContactFloater *pCurrent = pFirstFloater;
+ int oldTrans = g_floatoptions.trans;
+
+ while(pCurrent->hwnd != hwnd)
+ pCurrent = pCurrent->pNextFloater;
+
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0)){
+ g_floatoptions.trans = g_floatoptions.act_trans;
+ FLT_Update(cfg::clcdat, contact);
+ g_floatoptions.trans = oldTrans;
+ }
+
+ break;
+ }
+ case WM_MOUSELEAVE:
+ {
+ struct ClcContact *contact = NULL;
+ struct ContactFloater *pCurrent = pFirstFloater;
+
+ while(pCurrent->hwnd != hwnd)
+ pCurrent = pCurrent->pNextFloater;
+
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0))
+ FLT_Update(cfg::clcdat, contact);
+
+ if (hTooltipTimer)
+ {
+ KillTimer(hwnd, TOOLTIP_TIMER);
+ hTooltipTimer = 0;
+ }
+
+ if (tooltip) CallService(MS_TOOLTIP_HIDETIP, 0, 0);
+
+ hover = FALSE;
+ tooltip = FALSE;
+
+
+ break;
+ }
+
+ case WM_MOVE:
+ {
+ if (g_floatoptions.dwFlags & FLT_SNAP)
+ FLT_SnapToEdges(hwnd);
+
+ if(GetKeyState(VK_CONTROL) < 0)
+ FLT_SnapToFloater(hwnd);
+
+ break;
+ }
+ case WM_MEASUREITEM:
+ return(Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam));
+ case WM_DRAWITEM:
+ return(Menu_DrawItem((LPDRAWITEMSTRUCT)lParam));
+ case WM_COMMAND:
+ return(CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKELONG(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)centry->hContact));
+ case WM_CONTEXTMENU:
+ {
+ if(centry) {
+ HMENU hContactMenu = Menu_BuildContactMenu(centry->hContact);
+ RECT rcWindow;
+
+ GetWindowRect(hwnd, &rcWindow);
+ TrackPopupMenu(hContactMenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, hwnd, NULL);
+ DestroyMenu(hContactMenu);
+ return 0;
+ }
+ break;
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void SFL_RegisterWindowClass()
+{
+ WNDCLASS wndclass;
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = StatusFloaterClassProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = g_hInst;
+ wndclass.hIcon = 0;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE);
+ wndclass.lpszMenuName = 0;
+ wndclass.lpszClassName = _T("StatusFloaterClass");
+ RegisterClass(&wndclass);
+
+ wndclass.style = CS_DBLCLKS;
+ wndclass.lpszClassName = _T("ContactFloaterClass");
+ wndclass.lpfnWndProc = ContactFloaterClassProc;
+ RegisterClass(&wndclass);
+}
+
+void SFL_UnregisterWindowClass()
+{
+ UnregisterClass(_T("StatusFloaterClass"), g_hInst);
+ UnregisterClass(_T("ContactFloaterClass"), g_hInst);
+}
+
+void SFL_Destroy()
+{
+ if(g_hwndSFL)
+ DestroyWindow(g_hwndSFL);
+ g_hwndSFL = 0;
+}
+
+static HICON sfl_hIcon = (HICON)-1;
+static int sfl_iIcon = -1;
+static wchar_t sfl_statustext[100] = _T("");
+
+void SFL_Update(HICON hIcon, int iIcon, HIMAGELIST hIml, const wchar_t *szText, BOOL refresh)
+{
+ RECT rcClient, rcWindow;
+ POINT ptDest, ptSrc = {0};
+ SIZE szDest, szT;
+ BLENDFUNCTION bf = {0};
+ HFONT hOldFont;
+ TStatusItem *item = &Skin::statusItems[ID_EXTBKSTATUSFLOATER];
+ RECT rcStatusArea;
+ LONG cy;
+
+ if(g_hwndSFL == 0)
+ return;
+
+ GetClientRect(g_hwndSFL, &rcClient);
+ GetWindowRect(g_hwndSFL, &rcWindow);
+
+ ptDest.x = rcWindow.left;
+ ptDest.y = rcWindow.top;
+ szDest.cx = rcWindow.right - rcWindow.left;
+ szDest.cy = rcWindow.bottom - rcWindow.top;
+
+ if(item->IGNORED)
+ Gfx::setTextColor(GetSysColor(COLOR_BTNTEXT));
+ else {
+ FillRect(g_SFLCachedDC, &rcClient, GetSysColorBrush(COLOR_3DFACE));
+ Gfx::renderSkinItem(g_SFLCachedDC, &rcClient, item->imageItem);
+ Gfx::setTextColor(item->TEXTCOLOR);
+ }
+ bf.BlendOp = AC_SRC_OVER;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+ bf.SourceConstantAlpha = item->IGNORED ? 255 : percent_to_byte(item->ALPHA);
+
+ rcStatusArea = rcClient;
+
+ if(cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS)
+ rcStatusArea.bottom = 20;
+
+ cy = rcStatusArea.bottom - rcStatusArea.top;
+
+ if(szText != NULL && refresh) {
+ _tcsncpy(sfl_statustext, szText, 100);
+ sfl_statustext[99] = 0;
+ }
+
+ if(!hIcon) {
+ HICON p_hIcon;
+
+ if(refresh)
+ sfl_iIcon = iIcon;
+ if(sfl_iIcon != -1) {
+ p_hIcon = ImageList_ExtractIcon(0, CLC::hClistImages, sfl_iIcon);
+ DrawIconEx(g_SFLCachedDC, 5, (cy - 16) / 2, p_hIcon, 16, 16, 0, 0, DI_NORMAL);
+ DestroyIcon(p_hIcon);
+ }
+ }
+ else {
+ if(refresh)
+ sfl_hIcon = hIcon;
+ if(sfl_hIcon != (HICON)-1)
+ DrawIconEx(g_SFLCachedDC, 5, (cy - 16) / 2, sfl_hIcon, 16, 16, 0, 0, DI_NORMAL);
+ }
+
+ hOldFont = reinterpret_cast<HFONT>(SelectObject(g_SFLCachedDC, GetStockObject(DEFAULT_GUI_FONT)));
+ SetBkMode(g_SFLCachedDC, TRANSPARENT);
+ GetTextExtentPoint32(g_SFLCachedDC, sfl_statustext, lstrlen(sfl_statustext), &szT);
+ TextOut(g_SFLCachedDC, 24, (cy - szT.cy) / 2, sfl_statustext, lstrlen(sfl_statustext));
+
+ if(cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS) {
+ RECT rcNA = rcClient;
+
+ rcNA.top = 18;
+ PaintNotifyArea(g_SFLCachedDC, &rcNA, 0);
+ }
+
+ SelectObject(g_SFLCachedDC, hOldFont);
+ UpdateLayeredWindow(g_hwndSFL, 0, &ptDest, &szDest, g_SFLCachedDC, &ptSrc, 0, &bf, ULW_ALPHA);
+}
+
+/*
+ * set the floater
+ * mode = 0/1 forced hide/show
+ * OR -1 to set it depending on the clist state (visible/hidden) (this is actually reversed, because the function
+ * is called *before* the clist is shown or hidden)
+ */
+
+void SFL_SetState(int uMode)
+{
+ BYTE bClistState;
+
+ if(g_hwndSFL == 0 || !(cfg::dat.bUseFloater & CLUI_USE_FLOATER))
+ return;
+
+ if(uMode == -1) {
+ if(cfg::dat.bUseFloater & CLUI_FLOATER_AUTOHIDE) {
+ bClistState = cfg::getByte("CList", "State", SETTING_STATE_NORMAL);
+ ShowWindow(g_hwndSFL, bClistState == SETTING_STATE_NORMAL ? SW_SHOW : SW_HIDE);
+ }
+ else
+ ShowWindow(g_hwndSFL, SW_SHOW);
+ }
+ else
+ ShowWindow(g_hwndSFL, uMode ? SW_SHOW : SW_HIDE);
+}
+
+// XXX improve size calculations for the floater window.
+
+void SFL_SetSize()
+{
+ HDC hdc;
+ LONG lWidth;
+ RECT rcWindow;
+ SIZE sz = {0};
+ wchar_t *szStatusMode;
+ HFONT oldFont;
+ int i;
+
+ GetWindowRect(g_hwndSFL, &rcWindow);
+ lWidth = rcWindow.right - rcWindow.left;
+
+ hdc = GetDC(g_hwndSFL);
+ oldFont = reinterpret_cast<HFONT>(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)));
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ szStatusMode = TranslateTS(pcli->pfnGetStatusModeDescription(i, 0));
+ GetTextExtentPoint32W(hdc, szStatusMode, lstrlenW(szStatusMode), &sz);
+ lWidth = max(lWidth, sz.cx + 16 + 8);
+ }
+ SetWindowPos(g_hwndSFL, g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST, rcWindow.left, rcWindow.top, lWidth, max(cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS ? 36 : 20, sz.cy + 4), SWP_SHOWWINDOW);
+ GetWindowRect(g_hwndSFL, &rcWindow);
+
+ if(g_SFLCachedDC) {
+ SelectObject(g_SFLCachedDC, g_SFLhbmOld);
+ DeleteObject(g_SFLhbm);
+ DeleteDC(g_SFLCachedDC);
+ g_SFLCachedDC = 0;
+ }
+
+ g_SFLCachedDC = CreateCompatibleDC(hdc);
+ g_SFLhbm = Gfx::createRGBABitmap(lWidth, rcWindow.bottom - rcWindow.top);
+ g_SFLhbmOld = reinterpret_cast<HBITMAP>(SelectObject(g_SFLCachedDC, g_SFLhbm));
+
+ ReleaseDC(g_hwndSFL, hdc);
+ CluiProtocolStatusChanged(0, 0);
+}
+
+void SFL_Create()
+{
+ if(g_hwndSFL == 0 && cfg::dat.bUseFloater & CLUI_USE_FLOATER)
+ g_hwndSFL = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, _T("StatusFloaterClass"), _T("sfl"), WS_VISIBLE, 0, 0, 0, 0, 0, 0, g_hInst, 0);
+ else
+ return;
+
+ SetWindowLong(g_hwndSFL, GWL_STYLE, GetWindowLong(g_hwndSFL, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW));
+
+ Utils_RestoreWindowPosition(g_hwndSFL, 0, "CLUI", "sfl");
+ SFL_SetSize();
+}
+
+void FLT_SetSize(struct TExtraCache *centry, LONG width, LONG height)
+{
+ HDC hdc;
+ RECT rcWindow;
+ HFONT oldFont;
+ int flags = SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOACTIVATE;
+
+ int iVis = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0);
+ if((g_floatoptions.dwFlags & FLT_AUTOHIDE) && (iVis == 2 || iVis == 4)) //2 = GWVS_VISIBLE, 4 = GWVS_PARTIALLY_COVERED
+ flags = SWP_NOMOVE | SWP_NOACTIVATE;
+
+ if(centry->floater) {
+ hdc = GetDC(centry->floater->hwnd);
+ oldFont = reinterpret_cast<HFONT>(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)));
+
+ SetWindowPos(centry->floater->hwnd, g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, width, height, flags);
+ GetWindowRect(centry->floater->hwnd, &rcWindow);
+
+ if(centry->floater->hdc) {
+ SelectObject(centry->floater->hdc, centry->floater->hbmOld);
+ DeleteObject(centry->floater->hbm);
+ DeleteDC(centry->floater->hdc);
+ centry->floater->hdc = 0;
+ }
+
+ centry->floater->hdc = CreateCompatibleDC(hdc);
+ centry->floater->hbm = Gfx::createRGBABitmap(width, rcWindow.bottom - rcWindow.top);
+ centry->floater->hbmOld= reinterpret_cast<HBITMAP>(SelectObject(centry->floater->hdc, centry->floater->hbm));
+
+ ReleaseDC(centry->floater->hwnd, hdc);
+ }
+}
+
+void FLT_Create(int iEntry)
+{
+ struct TExtraCache *centry = NULL;
+
+ if(iEntry >= 0 && iEntry < cfg::nextCacheEntry) {
+ struct ClcContact *contact = NULL;
+ struct ClcGroup *group = NULL;
+ centry = &cfg::eCache[iEntry];
+ if(centry->floater == 0) {
+ centry->floater = (struct ContactFloater *)malloc(sizeof(struct ContactFloater));
+ if(centry->floater == NULL)
+ return;
+ FLT_AddToList(centry->floater);
+ centry->floater->hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, _T("ContactFloaterClass"), _T("sfl"), WS_VISIBLE, 0, 0, 0, 0, 0, 0, g_hInst, (LPVOID)iEntry);
+ centry->floater->hContact = centry->hContact;
+ }
+ else if(centry->floater != NULL) {
+ ShowWindow(centry->floater->hwnd, SW_SHOWNOACTIVATE);
+ return;
+ }
+
+ SetWindowLong(centry->floater->hwnd, GWL_STYLE, GetWindowLong(centry->floater->hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW));
+
+ if(Utils_RestoreWindowPosition(centry->floater->hwnd, centry->hContact, "CList", "flt"))
+ if(Utils_RestoreWindowPositionNoMove(centry->floater->hwnd, centry->hContact, "CList", "flt"))
+ SetWindowPos(centry->floater->hwnd, 0, 50, 50, 150, 30, SWP_NOZORDER | SWP_NOACTIVATE);
+
+ //FLT_SetSize(centry, 100, 20);
+ ShowWindow(centry->floater->hwnd, SW_SHOWNOACTIVATE);
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)centry->hContact, &contact, &group, 0)) {
+ if(contact)
+ FLT_Update(cfg::clcdat, contact);
+ }
+ }
+}
+
+extern HDC hdcTempAV;
+extern HBITMAP hbmTempAV, hbmTempOldAV;
+extern LONG g_maxAV_X, g_maxAV_Y;
+
+void FLT_Update(struct ClcData *dat, struct ClcContact *contact)
+{
+ RECT rcClient, rcWindow;
+ POINT ptDest, ptSrc = {0};
+ SIZE szDest;
+ BLENDFUNCTION bf = {0};
+ HWND hwnd;
+ HDC hdc;
+ ClcGroup *group = NULL;
+ ClcContact *newContact = NULL;
+ HBRUSH hbrBorder;
+ float greyLevel;
+
+ if(contact == NULL || dat == NULL)
+ return;
+
+ if(contact->extraCacheEntry < 0 || contact->extraCacheEntry >= cfg::nextCacheEntry)
+ return;
+
+ if(cfg::eCache[contact->extraCacheEntry].floater == NULL)
+ return;
+
+ FLT_SetSize(&cfg::eCache[contact->extraCacheEntry], g_floatoptions.width, RowHeight::getFloatingRowHeight(dat, pcli->hwndContactTree, contact, g_floatoptions.dwFlags) + (2*g_floatoptions.pad_top));
+
+ hwnd = cfg::eCache[contact->extraCacheEntry].floater->hwnd;
+ hdc = cfg::eCache[contact->extraCacheEntry].floater->hdc;
+
+ if(hwnd == 0)
+ return;
+
+ GetClientRect(hwnd, &rcClient);
+ GetWindowRect(hwnd, &rcWindow);
+
+ ptDest.x = rcWindow.left;
+ ptDest.y = rcWindow.top;
+ szDest.cx = rcWindow.right - rcWindow.left;
+ szDest.cy = rcWindow.bottom - rcWindow.top;
+
+ /*
+ * fill with a DESATURATED representation of the clist bg color and use this later as a color key
+ */
+
+ greyLevel = (float)(GetRValue(cfg::clcdat->bkColour) * 0.299 + GetGValue(cfg::clcdat->bkColour) * 0.587 + GetBValue(cfg::clcdat->bkColour) * 0.144);
+ if (greyLevel > 255)
+ greyLevel = 255;
+
+ SetBkMode(hdc, TRANSPARENT);
+
+ if(CLC::findItem(pcli->hwndContactTree, dat, (HANDLE)contact->hContact, &newContact, &group, 0)) {
+ DWORD oldFlags = cfg::dat.dwFlags;
+ BYTE oldPadding = cfg::dat.avatarPadding;
+ DWORD oldExtraImageMask = cfg::eCache[contact->extraCacheEntry].dwXMask;
+
+ int oldLeftMargin = dat->leftMargin;
+ int oldRightMargin = dat->rightMargin;
+
+ dat->leftMargin = g_floatoptions.pad_left;
+ dat->rightMargin = g_floatoptions.pad_right;
+
+ g_HDC = hdc;
+
+ hdcTempAV = CreateCompatibleDC(g_HDC);
+ hbmTempAV = CreateCompatibleBitmap(g_HDC, g_maxAV_X, g_maxAV_Y);
+ hbmTempOldAV = reinterpret_cast<HBITMAP>(SelectObject(hdcTempAV, hbmTempAV));
+
+ g_padding_y = g_floatoptions.pad_top;
+
+ CLCPaintHelper ph(pcli->hwndContactTree, dat, 0, &rcClient, 0, 0, -4);
+ ph.setHDC(hdc);
+
+ if(g_floatoptions.dwFlags & FLT_SIMPLE) {
+ ph.fAvatar = ph.fSecondLine = false;
+ cfg::dat.dwFlags &= ~(CLUI_SHOWCLIENTICONS | CLUI_SHOWVISI);
+ cfg::eCache[contact->extraCacheEntry].dwXMask = 0;
+ }
+ else{
+ ph.fAvatar = g_floatoptions.dwFlags & FLT_AVATARS ? true : false;
+ ph.fSecondLine = g_floatoptions.dwFlags & FLT_DUALROW ? true : false;
+ if(!(g_floatoptions.dwFlags & FLT_EXTRAICONS)) {
+ cfg::dat.dwFlags &= ~(CLUI_SHOWCLIENTICONS | CLUI_SHOWVISI);
+ cfg::eCache[contact->extraCacheEntry].dwXMask = 0;
+ }
+ }
+
+ ph.aggctx->attach(cfg::eCache[contact->extraCacheEntry].floater->hbm);
+ ph.current_shape = 0;
+ Gfx::renderSkinItem(&ph, &Skin::statusItems[ID_EXTBKSTATUSFLOATER], &rcClient);
+
+ ph.setFloater();
+ ph.hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON");
+
+ ph.Paint(group, contact, rcClient.bottom - rcClient.top);
+
+ Api::pfnCloseThemeData(ph.hTheme);
+
+ g_padding_y = 0;
+
+ SelectObject(hdcTempAV, hbmTempOldAV);
+ DeleteObject(hbmTempAV);
+ DeleteDC(hdcTempAV);
+
+ cfg::dat.dwFlags = oldFlags;
+ cfg::dat.avatarPadding = oldPadding;
+ cfg::eCache[contact->extraCacheEntry].dwXMask = oldExtraImageMask;
+
+ dat->leftMargin = oldLeftMargin;
+ dat->rightMargin = oldRightMargin;
+ }
+
+ if(g_floatoptions.dwFlags & FLT_BORDER){
+ hbrBorder = CreateSolidBrush(g_floatoptions.border_colour);
+ FrameRect(hdc, &rcClient, hbrBorder);
+ DeleteObject(hbrBorder);
+ }
+
+ bf.BlendOp = AC_SRC_OVER;
+ bf.AlphaFormat = AC_SRC_ALPHA;
+ bf.SourceConstantAlpha = g_floatoptions.trans;
+
+ UpdateLayeredWindow(hwnd, 0, &ptDest, &szDest, hdc, &ptSrc, 0, &bf, ULW_ALPHA);
+}
+
+/*
+ * syncs the floating contacts with clist contact visibility.
+ * will hide all floating contacts which are not visible on the list
+ * needed after a list rebuild
+ */
+
+void FLT_SyncWithClist()
+{
+ struct ClcContact *contact;
+ struct ContactFloater *pCurrent = pFirstFloater;
+ HWND hwnd;
+ int iVis = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0);
+
+ if(g_floatoptions.dwFlags & FLT_SYNCWITHCLIST){
+ while(pCurrent) {
+ hwnd = pCurrent->hwnd;
+ if(hwnd && IsWindow(hwnd)){
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0)) {
+ FLT_Update(cfg::clcdat, contact);
+ if(((g_floatoptions.dwFlags & FLT_AUTOHIDE) && (iVis == 2 || iVis == 4)) || !(g_floatoptions.dwFlags & FLT_AUTOHIDE))
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ else
+ ShowWindow(hwnd, SW_HIDE);
+ }
+ else
+ ShowWindow(hwnd, SW_HIDE);
+ }
+ pCurrent = pCurrent->pNextFloater;
+ }
+ }
+}
+
+/*
+ * quickly show or hide all floating contacts
+ * used by autohide/show feature
+ */
+
+void FLT_ShowHideAll(int showCmd)
+{
+ struct ClcContact *contact;
+ struct ContactFloater *pCurrent = pFirstFloater;
+ HWND hwnd;
+
+ if(g_floatoptions.dwFlags & FLT_AUTOHIDE){
+ while(pCurrent) {
+ hwnd = pCurrent->hwnd;
+ if(hwnd && IsWindow(hwnd)){
+ if(showCmd == SW_SHOWNOACTIVATE && CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0))
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ else if(showCmd != SW_SHOWNOACTIVATE)
+ ShowWindow(hwnd, showCmd);
+ }
+ pCurrent = pCurrent->pNextFloater;
+ }
+ }
+}
+
+/*
+ * update/repaint all contact floaters
+ */
+
+void FLT_RefreshAll()
+{
+ struct ClcContact *contact = NULL;
+ struct ContactFloater *pCurrent = pFirstFloater;
+
+ while(pCurrent) {
+ if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0)) {
+ HWND hwnd = pCurrent->hwnd;
+ if(hwnd && IsWindow(hwnd))
+ FLT_Update(cfg::clcdat, contact);
+ }
+ pCurrent = pCurrent->pNextFloater;
+ }
+}
+
diff --git a/plugins/Clist_ng/SRC/utils.cpp b/plugins/Clist_ng/SRC/utils.cpp new file mode 100644 index 0000000000..99c33d9bcc --- /dev/null +++ b/plugins/Clist_ng/SRC/utils.cpp @@ -0,0 +1,615 @@ +/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2010 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of clist_ng plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: utils.cpp 137 2010-10-16 21:03:23Z silvercircle $
+ *
+ * utility functions for clist_ng.
+ */
+
+#include <commonheaders.h>
+
+#define RTF_DEFAULT_HEADER _T("{\\rtf1\\ansi\\deff0\\pard\\li%u\\fi-%u\\ri%u\\tx%u")
+
+wchar_t* WarningDlg::m_warnings[WarningDlg::WARN_LAST] = {
+ LPGENT("Notes|release notes"),
+ LPGENT("Skin loading error|The skin cannot be loaded"),
+ LPGENT("Overwrite skin file|You are about to save your customized settings to the \\b1 original skin file.\\b0 This could cause problems and may require to reinstall the skin.\nYou should use \\b1 Save as user modification\\b0 to keep the original skin untouched.\n\nContinue?")
+};
+
+MWindowList WarningDlg::hWindowList = 0;
+
+/**
+ * ensure that a path name ends on a trailing backslash
+ * @param szPathname - pathname to check
+ */
+void Utils::ensureTralingBackslash(wchar_t *szPathname)
+{
+ if(szPathname[lstrlenW(szPathname) - 1] != '\\')
+ wcscat(szPathname, L"\\");
+}
+
+void Utils::extractResource(const HMODULE h, const UINT uID, const wchar_t* tszName, const wchar_t* tszPath,
+ const wchar_t* tszFilename, bool fForceOverwrite)
+{
+ HRSRC hRes;
+ HGLOBAL hResource;
+ wchar_t szFilename[MAX_PATH];
+
+ hRes = FindResourceW(h, MAKEINTRESOURCE(uID), tszName);
+
+ if(hRes) {
+ hResource = LoadResource(h, hRes);
+ if(hResource) {
+ HANDLE hFile;
+ char *pData = (char *)LockResource(hResource);
+ DWORD dwSize = SizeofResource(g_hInst, hRes), written = 0;
+ mir_sntprintf(szFilename, MAX_PATH, _T("%s%s"), tszPath, tszFilename);
+ if(!fForceOverwrite) {
+ if(PathFileExistsW(szFilename))
+ return;
+ }
+ if((hFile = CreateFileW(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) {
+ WriteFile(hFile, (void *)pData, dwSize, &written, NULL);
+ CloseHandle(hFile);
+ }
+ else {
+ wchar_t wszTemp[512];
+ mir_sntprintf(wszTemp, 512, L"%s - (WIN32 Error: %d)", szFilename, GetLastError());
+ throw(CRTException("Error while extracting base skin.", wszTemp));
+ }
+ }
+ }
+}
+
+/**
+ * enable or disable a dialog control
+ */
+void TSAPI Utils::enableDlgControl(const HWND hwnd, UINT id, BOOL fEnable)
+{
+ ::EnableWindow(::GetDlgItem(hwnd, id), fEnable);
+}
+
+/**
+ * show or hide a dialog control
+ */
+void TSAPI Utils::showDlgControl(const HWND hwnd, UINT id, int showCmd)
+{
+ ::ShowWindow(::GetDlgItem(hwnd, id), showCmd);
+}
+
+/**
+ * load a system library from the Windows system path and return its module
+ * handle.
+ *
+ * return 0 and throw an exception if something goes wrong.
+ */
+HMODULE Utils::loadSystemLibrary(const wchar_t* szFilename, bool useGetHandle)
+{
+ wchar_t sysPathName[MAX_PATH + 2];
+ HMODULE _h = 0;
+
+ try {
+ if(0 == ::GetSystemDirectoryW(sysPathName, MAX_PATH))
+ throw(CRTException("Error while loading system library", szFilename));
+
+ sysPathName[MAX_PATH - 1] = 0;
+ if(wcslen(sysPathName) + wcslen(szFilename) >= MAX_PATH)
+ throw(CRTException("Error while loading system library", szFilename));
+
+ lstrcatW(sysPathName, szFilename);
+ if(useGetHandle)
+ _h = ::GetModuleHandle(sysPathName);
+ else
+ _h = LoadLibraryW(sysPathName);
+ if(0 == _h)
+ throw(CRTException("Error while loading system library", szFilename));
+ }
+ catch(CRTException& ex) {
+ ex.display();
+ return(0);
+ }
+ return(_h);
+}
+
+DWORD __fastcall Utils::hexStringToLong(const char *szSource)
+{
+ char *stopped;
+ COLORREF clr = strtol(szSource, &stopped, 16);
+ if(clr == -1)
+ return clr;
+ return(RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)));
+}
+
+/**
+ * Case insensitive _tcsstr
+ *
+ * @param szString TCHAR *: String to be searched
+ * @param szSearchFor
+ * TCHAR *: String that should be found in szString
+ *
+ * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found
+ */
+const wchar_t* Utils::striStr(const wchar_t* szString, const wchar_t* szSearchFor)
+{
+ if(szString && *szString) {
+ if (0 == szSearchFor || 0 == *szSearchFor)
+ return(szString);
+
+ for(; *szString; ++szString) {
+ if(towupper(*szString) == towupper(*szSearchFor)) {
+ const wchar_t* h, *n;
+ for(h = szString, n = szSearchFor; *h && *n; ++h, ++n) {
+ if(towupper(*h) != towupper(*n))
+ break;
+ }
+ if(!*n)
+ return(szString);
+ }
+ }
+ return(0);
+ }
+ else
+ return(0);
+}
+
+int Utils::pathIsAbsolute(const wchar_t* path)
+{
+ if (!path || !(lstrlenW(path) > 2))
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+size_t Utils::pathToRelative(const wchar_t* pSrc, wchar_t* pOut, const wchar_t* szBase)
+{
+ const wchar_t* tszBase = szBase ? szBase : cfg::szProfileDir;
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlenW(pSrc) || lstrlenW(pSrc) > MAX_PATH)
+ return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_sntprintf(pOut, MAX_PATH, L"%s", pSrc);
+ return lstrlenW(pOut);
+ } else {
+ wchar_t szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, _countof(szTmp), L"%s", pSrc);
+ if (striStr(szTmp, tszBase)) {
+ if(tszBase[lstrlenW(tszBase) - 1] == '\\')
+ mir_sntprintf(pOut, MAX_PATH, L"%s", pSrc + lstrlenW(tszBase));
+ else {
+ mir_sntprintf(pOut, MAX_PATH, L"%s", pSrc + lstrlenW(tszBase) + 1 );
+ //pOut[0]='.';
+ }
+ return(lstrlenW(pOut));
+ } else {
+ mir_sntprintf(pOut, MAX_PATH, L"%s", pSrc);
+ return(lstrlenW(pOut));
+ }
+ }
+}
+
+/**
+ * Translate a relativ path to an absolute, using the current profile
+ * data directory.
+ *
+ * @param pSrc TCHAR *: input path + filename (relative)
+ * @param pOut TCHAR *: the result
+ * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case
+ * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata%
+ *
+ * @return
+ */
+size_t Utils::pathToAbsolute(const wchar_t* pSrc, wchar_t* pOut, const wchar_t* szBase)
+{
+ const wchar_t* tszBase = szBase ? szBase : cfg::szProfileDir;
+ const wchar_t* wszFmt = (tszBase[lstrlenW(tszBase) - 1] == '\\' ? L"%s%s" : L"%s\\%s");
+
+ pOut[0] = 0;
+ if (!pSrc || !lstrlenW(pSrc) || lstrlenW(pSrc) > MAX_PATH)
+ return 0;
+ if (pathIsAbsolute(pSrc) && pSrc[0]!='.')
+ mir_sntprintf(pOut, MAX_PATH, L"%s", pSrc);
+ else if (pSrc[0]=='.')
+ mir_sntprintf(pOut, MAX_PATH, wszFmt, tszBase, pSrc + 1);
+ else
+ mir_sntprintf(pOut, MAX_PATH, wszFmt, tszBase, pSrc);
+
+ return lstrlenW(pOut);
+}
+
+/**
+ * extract the clicked URL from a rich edit control. Return the URL as TCHAR*
+ * caller MUST mir_free() the returned string
+ * @param hwndRich - rich edit window handle
+ * @return wchar_t* extracted URL
+ */
+const wchar_t* Utils::extractURLFromRichEdit(const ENLINK* _e, const HWND hwndRich)
+{
+ TEXTRANGEW tr = {0};
+ CHARRANGE sel = {0};
+
+ ::SendMessageW(hwndRich, EM_EXGETSEL, 0, (LPARAM) & sel);
+ if (sel.cpMin != sel.cpMax)
+ return(0);
+
+ tr.chrg = _e->chrg;
+ tr.lpstrText = (wchar_t *)mir_alloc(2 * (tr.chrg.cpMax - tr.chrg.cpMin + 8));
+ ::SendMessageW(hwndRich, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
+ if (wcschr(tr.lpstrText, '@') != NULL && wcschr(tr.lpstrText, ':') == NULL && wcschr(tr.lpstrText, '/') == NULL) {
+ ::MoveMemory(tr.lpstrText + 7, tr.lpstrText, sizeof(TCHAR) * (tr.chrg.cpMax - tr.chrg.cpMin + 1));
+ ::CopyMemory(tr.lpstrText, L"mailto:", 7);
+ }
+ return(tr.lpstrText);
+}
+
+/**
+ * implementation of the CWarning class
+ */
+WarningDlg::WarningDlg(const wchar_t *tszTitle, const wchar_t *tszText, const UINT uId, const DWORD dwFlags)
+{
+ m_pszTitle = pSmartWstring(new std::basic_string<wchar_t>(tszTitle));
+ m_pszText = pSmartWstring(new std::basic_string<wchar_t>(tszText));
+
+ m_uId = uId;
+ m_hFontCaption = 0;
+ m_dwFlags = dwFlags;
+
+ m_fIsModal = ((m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL) ? true : false);
+}
+
+WarningDlg::~WarningDlg()
+{
+ if(m_hFontCaption)
+ ::DeleteObject(m_hFontCaption);
+
+#if defined(__LOGDEBUG_)
+ _DebugTraceW(L"destroy object");
+#endif
+}
+
+LRESULT WarningDlg::ShowDialog() const
+{
+ if(!m_fIsModal) {
+ ::CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_WARNING), 0, stubDlgProc, reinterpret_cast<LPARAM>(this));
+ return(0);
+ }
+ else {
+ LRESULT res = ::DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_WARNING), 0, stubDlgProc, reinterpret_cast<LPARAM>(this));
+ return(res);
+ }
+}
+
+__int64 WarningDlg::getMask()
+{
+ __int64 mask = 0;
+
+ DWORD dwLow = cfg::getDword("CList", "cWarningsL", 0);
+ DWORD dwHigh = cfg::getDword("CList", "cWarningsH", 0);
+
+ mask = ((((__int64)dwHigh) << 32) & 0xffffffff00000000) | dwLow;
+
+ return(mask);
+}
+
+/**
+ * send cancel message to all open warning dialogs so they are destroyed
+ * before plugin is unloaded.
+ *
+ * called by the OkToExit handler in globals.cpp
+ */
+void WarningDlg::destroyAll()
+{
+ if(hWindowList)
+ WindowList_Broadcast(hWindowList, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0), 0);
+}
+/**
+ * show a CWarning dialog using the id value. Check whether the user has chosen to
+ * not show this message again. This has room for 64 different warning dialogs, which
+ * should be enough in the first place. Extending it should not be too hard though.
+ */
+LRESULT WarningDlg::show(const int uId, DWORD dwFlags, const wchar_t* tszTxt)
+{
+ wchar_t* separator_pos = 0;
+ __int64 mask = 0, val = 0;
+ LRESULT result = 0;
+ wchar_t* _s = 0;
+
+ if (0 == hWindowList)
+ hWindowList = WindowList_Create();
+
+ /*
+ * don't open new warnings when shutdown was initiated (modal ones will otherwise
+ * block the shutdown)
+ */
+ if(cfg::shutDown)
+ return(-1);
+
+ if(uId >= 0) {
+ mask = getMask();
+ val = ((__int64)1L) << uId;
+ }
+ else
+ mask = val = 0;
+
+ if(!(0 == (mask & val) || dwFlags & CWF_NOALLOWHIDE))
+ return(-1);
+
+ if(tszTxt)
+ _s = const_cast<wchar_t *>(tszTxt);
+ else {
+ if(uId != -1) {
+ if(dwFlags & CWF_UNTRANSLATED)
+ _s = const_cast<wchar_t *>(m_warnings[uId]);
+ else {
+ /*
+ * revert to untranslated warning when the translated message
+ * is not well-formatted.
+ */
+ _s = const_cast<wchar_t *>(TranslateW(m_warnings[uId]));
+
+ if(wcslen(_s) < 3 || 0 == wcschr(_s, '|'))
+ _s = const_cast<wchar_t *>(m_warnings[uId]);
+ }
+ }
+ else if(-1 == uId && tszTxt) {
+ dwFlags |= CWF_NOALLOWHIDE;
+ _s = (dwFlags & CWF_UNTRANSLATED ? const_cast<wchar_t *>(tszTxt) : TranslateW(tszTxt));
+ }
+ else
+ return(-1);
+ }
+
+ if((wcslen(_s) > 3) && ((separator_pos = wcschr(_s, '|')) != 0)) {
+
+ wchar_t *s = reinterpret_cast<wchar_t *>(mir_alloc((wcslen(_s) + 1) * 2));
+ wcscpy(s, _s);
+ separator_pos = wcschr(s, '|');
+
+ if(separator_pos) {
+ separator_pos[0] = 0;
+
+ WarningDlg *w = new WarningDlg(s, &separator_pos[1], uId, dwFlags);
+ if(!(dwFlags & MB_YESNO || dwFlags & MB_YESNOCANCEL)) {
+ w->ShowDialog();
+ mir_free(s);
+ }
+ else {
+ result = w->ShowDialog();
+ mir_free(s);
+ return(result);
+ }
+ }
+ else
+ mir_free(s);
+ }
+ return(-1);
+}
+
+/**
+ * stub dlg procedure. Just register the object pointer in WM_INITDIALOG
+ */
+INT_PTR CALLBACK WarningDlg::stubDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WarningDlg *w = reinterpret_cast<WarningDlg *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
+ if(w)
+ return(w->dlgProc(hwnd, msg, wParam, lParam));
+
+ switch(msg) {
+ case WM_INITDIALOG: {
+ w = reinterpret_cast<WarningDlg *>(lParam);
+ if(w) {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ return(w->dlgProc(hwnd, msg, wParam, lParam));
+ }
+ break;
+ }
+
+#if defined(__LOGDEBUG_)
+ case WM_NCDESTROY:
+ _DebugTraceW(L"window destroyed");
+ break;
+#endif
+
+ default:
+ break;
+ }
+ return(FALSE);
+}
+
+/**
+ * dialog procedure for the warning dialog box
+ */
+INT_PTR CALLBACK WarningDlg::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG: {
+ HICON hIcon = 0;
+ UINT uResId = 0;
+ TCHAR temp[1024];
+ SETTEXTEX stx = {ST_SELECTION, CP_UTF8};
+ size_t pos = 0;
+
+ m_hwnd = hwnd;
+
+ ::SetWindowTextW(hwnd, L"Clist NG warning");
+ ::SendMessage(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(Skin_LoadIcon(SKINICON_OTHER_MIRANDA, true)));
+ ::SendMessage(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(Skin_LoadIcon(SKINICON_OTHER_MIRANDA)));
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_SETEVENTMASK, 0, ENM_LINK);
+
+ mir_sntprintf(temp, 1024, RTF_DEFAULT_HEADER, 0, 0, 0, 30*15);
+ std::basic_string<wchar_t> *str = new std::basic_string<wchar_t>(temp);
+
+ str->append((*m_pszText).c_str());
+ str->append(L"}");
+
+ TranslateDialogDefault(hwnd);
+
+ /*
+ * convert normal line breaks to rtf
+ */
+ while((pos = str->find(L"\n")) != str->npos) {
+ str->erase(pos, 1);
+ str->insert(pos, L"\\line ");
+ }
+
+ char *utf8 = Utf8EncodeW(str->c_str());
+ ::SendDlgItemMessage(hwnd, IDC_WARNTEXT, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)utf8);
+ mir_free(utf8);
+ delete str;
+
+ ::SetDlgItemTextW(hwnd, IDC_CAPTION, (*m_pszTitle).c_str());
+
+ if(m_dwFlags & CWF_NOALLOWHIDE)
+ Utils::showDlgControl(hwnd, IDC_DONTSHOWAGAIN, SW_HIDE);
+ if(m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL) {
+ Utils::showDlgControl(hwnd, IDOK, SW_HIDE);
+ ::SetFocus(::GetDlgItem(hwnd, IDCANCEL));
+ }
+ else {
+ Utils::showDlgControl(hwnd, IDCANCEL, SW_HIDE);
+ Utils::showDlgControl(hwnd, IDYES, SW_HIDE);
+ Utils::showDlgControl(hwnd, IDNO, SW_HIDE);
+ ::SetFocus(::GetDlgItem(hwnd, IDOK));
+ }
+ if(m_dwFlags & MB_ICONERROR || m_dwFlags & MB_ICONHAND)
+ uResId = 32513;
+ else if(m_dwFlags & MB_ICONEXCLAMATION || m_dwFlags & MB_ICONWARNING)
+ uResId = 32515;
+ else if(m_dwFlags & MB_ICONASTERISK || m_dwFlags & MB_ICONINFORMATION)
+ uResId = 32516;
+ else if(m_dwFlags & MB_ICONQUESTION)
+ uResId = 32514;
+
+ if(uResId)
+ hIcon = reinterpret_cast<HICON>(::LoadImage(0, MAKEINTRESOURCE(uResId), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
+ else
+ hIcon = Skin_LoadIcon(SKINICON_EVENT_MESSAGE, true);
+
+ ::SendDlgItemMessageW(hwnd, IDC_WARNICON, STM_SETICON, reinterpret_cast<WPARAM>(hIcon), 0);
+ if(!(m_dwFlags & MB_YESNO || m_dwFlags & MB_YESNOCANCEL))
+ ::ShowWindow(hwnd, SW_SHOWNORMAL);
+
+ WindowList_Add(hWindowList, hwnd, (MCONTACT)hwnd);
+ return(TRUE);
+ }
+
+ case WM_CTLCOLORSTATIC: {
+ HWND hwndChild = reinterpret_cast<HWND>(lParam);
+ UINT id = ::GetDlgCtrlID(hwndChild);
+ if(0 == m_hFontCaption) {
+ HFONT hFont = reinterpret_cast<HFONT>(::SendDlgItemMessage(hwnd, IDC_CAPTION, WM_GETFONT, 0, 0));
+ LOGFONT lf = {0};
+
+ ::GetObject(hFont, sizeof(lf), &lf);
+ lf.lfHeight = (int)((double)lf.lfHeight * 1.7f);
+ m_hFontCaption = ::CreateFontIndirect(&lf);
+ ::SendDlgItemMessage(hwnd, IDC_CAPTION, WM_SETFONT, (WPARAM)m_hFontCaption, FALSE);
+ }
+
+ if(IDC_CAPTION == id) {
+ ::SetTextColor(reinterpret_cast<HDC>(wParam), ::GetSysColor(COLOR_HIGHLIGHT));
+ ::SendMessage(hwndChild, WM_SETFONT, (WPARAM)m_hFontCaption, FALSE);
+ }
+
+ if(IDC_WARNGROUP != id && IDC_DONTSHOWAGAIN != id) {
+ ::SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW));
+ return reinterpret_cast<INT_PTR>(::GetSysColorBrush(COLOR_WINDOW));
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ case IDYES:
+ case IDNO:
+ if(!m_fIsModal && (IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam))) { // modeless dialogs can receive a IDCANCEL from destroyAll()
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ delete this;
+ WindowList_Remove(hWindowList, hwnd);
+ ::DestroyWindow(hwnd);
+ }
+ else {
+ ::SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ delete this;
+ WindowList_Remove(hWindowList, hwnd);
+ ::EndDialog(hwnd, LOWORD(wParam));
+ }
+ break;
+
+ case IDC_DONTSHOWAGAIN: {
+ __int64 mask = getMask(), val64 = ((__int64)1L << m_uId), newVal = 0;
+
+ newVal = mask | val64;
+
+ if(::IsDlgButtonChecked(hwnd, IDC_DONTSHOWAGAIN)) {
+ DWORD val = (DWORD)(newVal & 0x00000000ffffffff);
+ cfg::writeDword("CList", "cWarningsL", val);
+ val = (DWORD)((newVal >> 32) & 0x00000000ffffffff);
+ cfg::writeDword("CList", "cWarningsH", val);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: {
+ switch (((NMHDR *) lParam)->code) {
+ case EN_LINK:
+ switch (((ENLINK *) lParam)->msg) {
+ case WM_LBUTTONUP: {
+ ENLINK* e = reinterpret_cast<ENLINK *>(lParam);
+
+ const wchar_t* wszUrl = Utils::extractURLFromRichEdit(e, ::GetDlgItem(hwnd, IDC_WARNTEXT));
+ if(wszUrl) {
+ char* szUrl = mir_t2a(wszUrl);
+
+ Utils_OpenUrl(szUrl);
+ mir_free(szUrl);
+ mir_free(const_cast<TCHAR *>(wszUrl));
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return(FALSE);
+}
diff --git a/plugins/Clist_ng/SRC/viewmodes.cpp b/plugins/Clist_ng/SRC/viewmodes.cpp new file mode 100644 index 0000000000..34142bb736 --- /dev/null +++ b/plugins/Clist_ng/SRC/viewmodes.cpp @@ -0,0 +1,1249 @@ +/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+contact list view modes (CLVM)
+
+$Id: viewmodes.cpp 131 2010-09-29 04:50:58Z silvercircle $
+
+*/
+
+#include <commonheaders.h>
+
+#define TIMERID_VIEWMODEEXPIRE 100
+
+extern HPEN g_hPenCLUIFrames;
+extern FRAMEWND *wndFrameViewMode;
+
+typedef int (__cdecl *pfnEnumCallback)(char *szName);
+static HWND clvmHwnd = 0;
+static int clvm_curItem = 0;
+HMENU hViewModeMenu = 0;
+
+static HWND hwndSelector = 0;
+static HIMAGELIST himlViewModes = 0;
+static HANDLE hInfoItem = 0;
+static int nullImage;
+static DWORD stickyStatusMask = 0;
+static char g_szModename[2048];
+
+static int g_ViewModeOptDlg = FALSE;
+
+static UINT _page1Controls[] = {IDC_STATIC1, IDC_STATIC2, IDC_STATIC3, IDC_STATIC5, IDC_STATIC4,
+ IDC_STATIC8, IDC_ADDVIEWMODE, IDC_DELETEVIEWMODE, IDC_NEWVIEMODE, IDC_GROUPS, IDC_PROTOCOLS,
+ IDC_VIEWMODES, IDC_STATUSMODES, IDC_STATIC12, IDC_STATIC13, IDC_STATIC14, IDC_PROTOGROUPOP, IDC_GROUPSTATUSOP,
+ IDC_AUTOCLEAR, IDC_AUTOCLEARVAL, IDC_AUTOCLEARSPIN, IDC_STATIC15, IDC_STATIC16,
+ IDC_LASTMESSAGEOP, IDC_LASTMESSAGEUNIT, IDC_LASTMSG, IDC_LASTMSGVALUE, 0};
+
+static UINT _page2Controls[] = {IDC_CLIST, IDC_STATIC9, IDC_STATIC8, IDC_CLEARALL, IDC_CURVIEWMODE2, 0};
+
+
+/*
+ * enumerate all view modes, call the callback function with the mode name
+ * useful for filling lists, menus and so on..
+ */
+
+int CLVM_EnumProc(const char *szSetting, LPARAM lParam)
+{
+ pfnEnumCallback EnumCallback = (pfnEnumCallback)lParam;
+ if (szSetting != NULL)
+ EnumCallback((char *)szSetting);
+ return(0);
+}
+
+void CLVM_EnumModes(pfnEnumCallback EnumCallback)
+{
+ DBCONTACTENUMSETTINGS dbces;
+
+ dbces.pfnEnumProc = CLVM_EnumProc;
+ dbces.szModule = CLVM_MODULE;
+ dbces.ofsSettings=0;
+ dbces.lParam = (LPARAM)EnumCallback;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS,0,(LPARAM)&dbces);
+}
+
+int FillModes(char *szsetting)
+{
+ if(szsetting[0] == 'ö')
+ return 1;
+ SendDlgItemMessageA(clvmHwnd, IDC_VIEWMODES, LB_INSERTSTRING, -1, (LPARAM)szsetting);
+ return 1;
+}
+
+static void ShowPage(HWND hwnd, int page)
+{
+ int i = 0;
+ int pageChange = 0;
+
+ if(page == 0 && IsWindowVisible(GetDlgItem(hwnd, _page2Controls[0])))
+ pageChange = 1;
+
+ if(page == 1 && IsWindowVisible(GetDlgItem(hwnd, _page1Controls[0])))
+ pageChange = 1;
+
+ if(pageChange)
+ SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+
+ switch(page) {
+ case 0:
+ while(_page1Controls[i] != 0)
+ ShowWindow(GetDlgItem(hwnd, _page1Controls[i++]), SW_SHOW);
+ i = 0;
+ while(_page2Controls[i] != 0)
+ ShowWindow(GetDlgItem(hwnd, _page2Controls[i++]), SW_HIDE);
+ break;
+ case 1:
+ while(_page1Controls[i] != 0)
+ ShowWindow(GetDlgItem(hwnd, _page1Controls[i++]), SW_HIDE);
+ i = 0;
+ while(_page2Controls[i] != 0)
+ ShowWindow(GetDlgItem(hwnd, _page2Controls[i++]), SW_SHOW);
+ break;
+ }
+ if(pageChange) {
+ SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
+ }
+}
+
+static int UpdateClistItem(HANDLE hContact, DWORD mask)
+{
+ int i;
+
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_SETEXTRAIMAGE, (WPARAM)hContact, MAKELONG(i - ID_STATUS_OFFLINE,
+ (1 << (i - ID_STATUS_OFFLINE)) & mask ? i - ID_STATUS_OFFLINE : nullImage));
+
+ return 0;
+}
+
+static DWORD GetMaskForItem(HANDLE hItem)
+{
+ int i;
+ DWORD dwMask = 0;
+
+ for(i = 0; i <= ID_STATUS_OUTTOLUNCH - ID_STATUS_OFFLINE; i++)
+ dwMask |= (SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, i) == nullImage ? 0 : 1 << i);
+
+ return dwMask;
+}
+
+static void UpdateStickies()
+{
+ MCONTACT hContact = db_find_first();
+ HANDLE hItem;
+ DWORD localMask;
+ int i;
+
+ while(hContact) {
+ hItem = (HANDLE)SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if(hItem)
+ SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM)hItem, cfg::getByte(hContact, "CLVM", g_szModename, 0) ? 1 : 0);
+ localMask = HIWORD(cfg::getDword(hContact, "CLVM", g_szModename, 0));
+ UpdateClistItem(hItem, (localMask == 0 || localMask == stickyStatusMask) ? stickyStatusMask : localMask);
+ hContact = db_find_next(hContact);
+ }
+
+ {
+ HANDLE hItem;
+
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_SETEXTRAIMAGE, (WPARAM)hInfoItem, MAKELONG(i - ID_STATUS_OFFLINE, (1 << (i - ID_STATUS_OFFLINE)) & stickyStatusMask ? i - ID_STATUS_OFFLINE : ID_STATUS_OUTTOLUNCH - ID_STATUS_OFFLINE + 1));
+
+ hItem=(HANDLE)SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_GETNEXTITEM,CLGN_ROOT,0);
+ hItem=(HANDLE)SendDlgItemMessage(clvmHwnd, IDC_CLIST,CLM_GETNEXTITEM,CLGN_NEXTGROUP, (LPARAM)hItem);
+ while(hItem) {
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELONG(i - ID_STATUS_OFFLINE, nullImage));
+ hItem=(HANDLE)SendDlgItemMessage(clvmHwnd, IDC_CLIST,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ ShowPage(clvmHwnd, 0);
+ }
+}
+
+static int FillDialog(HWND hwnd)
+{
+ LVCOLUMN lvc = {0};
+ HWND hwndList = GetDlgItem(hwnd, IDC_PROTOCOLS);
+ LVITEMA item = {0};
+ int protoCount = 0, i, newItem;
+ PROTOACCOUNT **accs = 0;
+
+ CLVM_EnumModes(FillModes);
+ ListView_SetExtendedListViewStyle(GetDlgItem(hwnd, IDC_PROTOCOLS), LVS_EX_CHECKBOXES);
+ lvc.mask = LVCF_FMT;
+ lvc.fmt = LVCFMT_IMAGE | LVCFMT_LEFT;
+ ListView_InsertColumn(GetDlgItem(hwnd, IDC_PROTOCOLS), 0, &lvc);
+
+ // fill protocols...
+
+ Proto_EnumAccounts( &protoCount, &accs );
+ item.mask = LVIF_TEXT;
+ item.iItem = 1000;
+ for (i = 0; i < protoCount; i++) {
+ item.pszText = accs[i]->szModuleName;
+ newItem = SendMessageA(hwndList, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ }
+
+ ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE);
+ ListView_Arrange(hwndList, LVA_ALIGNLEFT | LVA_ALIGNTOP);
+
+ // fill groups
+ {
+ LVITEM item = {0};
+ char buf[20];
+ DBVARIANT dbv = {0};
+
+ hwndList = GetDlgItem(hwnd, IDC_GROUPS);
+
+ ListView_SetExtendedListViewStyle(hwndList, LVS_EX_CHECKBOXES);
+ lvc.mask = LVCF_FMT;
+ lvc.fmt = LVCFMT_IMAGE | LVCFMT_LEFT;
+ ListView_InsertColumn(hwndList, 0, &lvc);
+
+ item.mask = LVIF_TEXT;
+ item.iItem = 1000;
+
+ item.pszText = TranslateT("Ungrouped contacts");
+ newItem = SendMessage(hwndList, LVM_INSERTITEM, 0, (LPARAM)&item);
+
+ for(i = 0;;i++) {
+ mir_snprintf(buf, 20, "%d", i);
+ if(cfg::getTString(NULL, "CListGroups", buf, &dbv))
+ break;
+
+ item.pszText = &dbv.ptszVal[1];
+ newItem = SendMessage(hwndList, LVM_INSERTITEM, 0, (LPARAM)&item);
+ db_free(&dbv);
+ }
+ ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE);
+ ListView_Arrange(hwndList, LVA_ALIGNLEFT | LVA_ALIGNTOP);
+ }
+ hwndList = GetDlgItem(hwnd, IDC_STATUSMODES);
+ ListView_SetExtendedListViewStyle(hwndList, LVS_EX_CHECKBOXES);
+ lvc.mask = LVCF_FMT;
+ lvc.fmt = LVCFMT_IMAGE | LVCFMT_LEFT;
+ ListView_InsertColumn(hwndList, 0, &lvc);
+ {
+ LVITEMW item = { 0 };
+ item.mask = LVIF_TEXT;
+ item.iItem = 1000;
+ for (i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ item.pszText = TranslateTS(pcli->pfnGetStatusModeDescription(i, 0));
+ item.iItem = i - ID_STATUS_OFFLINE;
+ newItem = SendMessageA(hwndList, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ }
+ }
+ ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE);
+ ListView_Arrange(hwndList, LVA_ALIGNLEFT | LVA_ALIGNTOP);
+
+ SendDlgItemMessage(hwnd, IDC_PROTOGROUPOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("And"));
+ SendDlgItemMessage(hwnd, IDC_PROTOGROUPOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Or"));
+ SendDlgItemMessage(hwnd, IDC_GROUPSTATUSOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("And"));
+ SendDlgItemMessage(hwnd, IDC_GROUPSTATUSOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Or"));
+
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Older than"));
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEOP, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Newer than"));
+
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEUNIT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Minutes"));
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEUNIT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Hours"));
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEUNIT, CB_INSERTSTRING, -1, (LPARAM)TranslateT("Days"));
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEOP, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(hwnd, IDC_LASTMESSAGEUNIT, CB_SETCURSEL, 0, 0);
+ SetDlgItemInt(hwnd, IDC_LASTMSGVALUE, 0, 0);
+ return 0;
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem)
+ SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+static void SetIconsForColumn(HWND hwndList,HANDLE hItem,HANDLE hItemAll,int iColumn,int iImage)
+{
+ int itemType;
+
+ itemType=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hItem,0);
+ if(itemType==CLCIT_CONTACT) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ }
+ else if(itemType==CLCIT_INFO) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ if(hItem == hItemAll)
+ SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ else
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage)); //hItemUnknown
+ }
+ else if(itemType==CLCIT_GROUP) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hItem)
+ SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ }
+}
+
+void SaveViewMode(const char *name, const wchar_t *szGroupFilter, const char *szProtoFilter, DWORD statusMask, DWORD stickyStatusMask, unsigned int options,
+ unsigned int stickies, unsigned int operators, unsigned int lmdat)
+{
+ char szSetting[512];
+
+ mir_snprintf(szSetting, 512, "%c%s_PF", 246, name);
+ cfg::writeString(NULL, CLVM_MODULE, szSetting, szProtoFilter);
+ mir_snprintf(szSetting, 512, "%c%s_GF", 246, name);
+ cfg::writeTString(NULL, CLVM_MODULE, szSetting, szGroupFilter);
+ mir_snprintf(szSetting, 512, "%c%s_SM", 246, name);
+ cfg::writeDword(CLVM_MODULE, szSetting, statusMask);
+ mir_snprintf(szSetting, 512, "%c%s_SSM", 246, name);
+ cfg::writeDword(CLVM_MODULE, szSetting, stickyStatusMask);
+ mir_snprintf(szSetting, 512, "%c%s_OPT", 246, name);
+ cfg::writeDword(CLVM_MODULE, szSetting, options);
+ mir_snprintf(szSetting, 512, "%c%s_LM", 246, name);
+ cfg::writeDword(CLVM_MODULE, szSetting, lmdat);
+
+ cfg::writeDword(CLVM_MODULE, name, MAKELONG((unsigned short)operators, (unsigned short)stickies));
+}
+
+/*
+ * saves the state of the filter definitions for the current item
+ */
+
+void SaveState()
+{
+ wchar_t newGroupFilter[2048] = _T("|");
+ char newProtoFilter[2048] = "|";
+ int i, iLen;
+ HWND hwndList;
+ char *szModeName = NULL;
+ DWORD statusMask = 0;
+ MCONTACT hContact;
+ HANDLE hItem;
+ DWORD operators = 0;
+
+ if(clvm_curItem == -1)
+ return;
+
+ {
+ LVITEMA item = {0};
+ char szTemp[256];
+
+ hwndList = GetDlgItem(clvmHwnd, IDC_PROTOCOLS);
+ for(i = 0; i < ListView_GetItemCount(hwndList); i++) {
+ if(ListView_GetCheckState(hwndList, i)) {
+ item.mask = LVIF_TEXT;
+ item.pszText = szTemp;
+ item.cchTextMax = 255;
+ item.iItem = i;
+ SendMessageA(hwndList, LVM_GETITEMA, 0, (LPARAM)&item);
+ strncat(newProtoFilter, szTemp, 2048);
+ strncat(newProtoFilter, "|", 2048);
+ newProtoFilter[2047] = 0;
+ }
+ }
+ }
+
+ {
+ LVITEM item = {0};
+ wchar_t szTemp[256];
+
+ hwndList = GetDlgItem(clvmHwnd, IDC_GROUPS);
+
+ operators |= ListView_GetCheckState(hwndList, 0) ? CLVM_INCLUDED_UNGROUPED : 0;
+
+ for(i = 0; i < ListView_GetItemCount(hwndList); i++) {
+ if(ListView_GetCheckState(hwndList, i)) {
+ item.mask = LVIF_TEXT;
+ item.pszText = szTemp;
+ item.cchTextMax = 255;
+ item.iItem = i;
+ SendMessage(hwndList, LVM_GETITEM, 0, (LPARAM)&item);
+ _tcsncat(newGroupFilter, szTemp, 2048);
+ _tcsncat(newGroupFilter, _T("|"), 2048);
+ newGroupFilter[2047] = 0;
+ }
+ }
+ }
+ hwndList = GetDlgItem(clvmHwnd, IDC_STATUSMODES);
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ if(ListView_GetCheckState(hwndList, i - ID_STATUS_OFFLINE))
+ statusMask |= (1 << (i - ID_STATUS_OFFLINE));
+ }
+ iLen = SendMessageA(GetDlgItem(clvmHwnd, IDC_VIEWMODES), LB_GETTEXTLEN, clvm_curItem, 0);
+ if(iLen) {
+ unsigned int stickies = 0;
+ DWORD dwGlobalMask, dwLocalMask;
+ BOOL translated;
+
+ szModeName = ( char* )malloc(iLen + 1);
+ if(szModeName) {
+ DWORD options, lmdat;
+ //char *vastring = NULL;
+ //int len = GetWindowTextLengthA(GetDlgItem(clvmHwnd, IDC_VARIABLES)) + 1;
+
+ //vastring = (char *)malloc(len);
+ //if(vastring)
+ // GetDlgItemTextA(clvmHwnd, IDC_VARIABLES, vastring, len);
+ SendDlgItemMessageA(clvmHwnd, IDC_VIEWMODES, LB_GETTEXT, clvm_curItem, (LPARAM)szModeName);
+ dwGlobalMask = GetMaskForItem(hInfoItem);
+ hContact = db_find_first();
+ while(hContact) {
+ hItem = (HANDLE)SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if(hItem) {
+ if(SendDlgItemMessage(clvmHwnd, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) {
+ dwLocalMask = GetMaskForItem(hItem);
+ cfg::writeDword(hContact, "CLVM", szModeName, MAKELONG(1, (unsigned short)dwLocalMask));
+ stickies++;
+ }
+ else {
+ if(cfg::getDword(hContact, "CLVM", szModeName, 0))
+ cfg::writeDword(hContact, "CLVM", szModeName, 0);
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+ operators |= ((SendDlgItemMessage(clvmHwnd, IDC_PROTOGROUPOP, CB_GETCURSEL, 0, 0) == 1 ? CLVM_PROTOGROUP_OP : 0) |
+ (SendDlgItemMessage(clvmHwnd, IDC_GROUPSTATUSOP, CB_GETCURSEL, 0, 0) == 1 ? CLVM_GROUPSTATUS_OP : 0) |
+ (IsDlgButtonChecked(clvmHwnd, IDC_AUTOCLEAR) ? CLVM_AUTOCLEAR : 0) |
+ (IsDlgButtonChecked(clvmHwnd, IDC_LASTMSG) ? CLVM_USELASTMSG : 0));
+
+ options = SendDlgItemMessage(clvmHwnd, IDC_AUTOCLEARSPIN, UDM_GETPOS, 0, 0);
+
+ lmdat = MAKELONG(GetDlgItemInt(clvmHwnd, IDC_LASTMSGVALUE, &translated, FALSE),
+ MAKEWORD(SendDlgItemMessage(clvmHwnd, IDC_LASTMESSAGEOP, CB_GETCURSEL, 0, 0),
+ SendDlgItemMessage(clvmHwnd, IDC_LASTMESSAGEUNIT, CB_GETCURSEL, 0, 0)));
+
+ SaveViewMode(szModeName, newGroupFilter, newProtoFilter, statusMask, dwGlobalMask, options,
+ stickies, operators, lmdat);
+ //free(vastring);
+ free(szModeName);
+ }
+ }
+ Utils::enableDlgControl(clvmHwnd, IDC_APPLY, FALSE);
+}
+
+
+/*
+ * updates the filter list boxes with the data taken from the filtering string
+ */
+
+void UpdateFilters()
+{
+ DBVARIANT dbv_pf = {0};
+ DBVARIANT dbv_gf = {0};
+ char szSetting[128];
+ char *szBuf = NULL;
+ int iLen;
+ DWORD statusMask = 0;
+ DWORD dwFlags;
+ DWORD opt;
+ char szTemp[100];
+
+ if(clvm_curItem == LB_ERR)
+ return;
+
+ iLen = SendDlgItemMessageA(clvmHwnd, IDC_VIEWMODES, LB_GETTEXTLEN, clvm_curItem, 0);
+
+ if(iLen == 0)
+ return;
+
+ szBuf = (char *)malloc(iLen + 1);
+ SendDlgItemMessageA(clvmHwnd, IDC_VIEWMODES, LB_GETTEXT, clvm_curItem, (LPARAM)szBuf);
+ strncpy(g_szModename, szBuf, sizeof(g_szModename));
+ g_szModename[sizeof(g_szModename) - 1] = 0;
+ mir_snprintf(szTemp, 100, Translate("Current view mode: %s"), g_szModename);
+ SetDlgItemTextA(clvmHwnd, IDC_CURVIEWMODE2, szTemp);
+ mir_snprintf(szSetting, 128, "%c%s_PF", 246, szBuf);
+ if(db_get(NULL, CLVM_MODULE, szSetting, &dbv_pf))
+ goto cleanup;
+ mir_snprintf(szSetting, 128, "%c%s_GF", 246, szBuf);
+ if(cfg::getTString(NULL, CLVM_MODULE, szSetting, &dbv_gf))
+ goto cleanup;
+ mir_snprintf(szSetting, 128, "%c%s_OPT", 246, szBuf);
+ if((opt = cfg::getDword(NULL, CLVM_MODULE, szSetting, -1)) != -1) {
+ SendDlgItemMessage(clvmHwnd, IDC_AUTOCLEARSPIN, UDM_SETPOS, 0, MAKELONG(LOWORD(opt), 0));
+ }
+ mir_snprintf(szSetting, 128, "%c%s_SM", 246, szBuf);
+ statusMask = cfg::getDword(CLVM_MODULE, szSetting, -1);
+ mir_snprintf(szSetting, 128, "%c%s_SSM", 246, szBuf);
+ stickyStatusMask = cfg::getDword(CLVM_MODULE, szSetting, -1);
+ dwFlags = cfg::getDword(CLVM_MODULE, szBuf, 0);
+ {
+ LVITEMA item = {0};
+ char szTemp[256];
+ char szMask[256];
+ int i;
+ HWND hwndList = GetDlgItem(clvmHwnd, IDC_PROTOCOLS);
+
+ item.mask = LVIF_TEXT;
+ item.pszText = szTemp;
+ item.cchTextMax = 255;
+
+ for(i = 0; i < ListView_GetItemCount(hwndList); i++) {
+ item.iItem = i;
+ SendMessageA(hwndList, LVM_GETITEMA, 0, (LPARAM)&item);
+ mir_snprintf(szMask, 256, "%s|", szTemp);
+ if(dbv_pf.pszVal && strstr(dbv_pf.pszVal, szMask))
+ ListView_SetCheckState(hwndList, i, TRUE)
+ else
+ ListView_SetCheckState(hwndList, i, FALSE);
+ }
+ }
+ {
+ LVITEM item = {0};
+ wchar_t szTemp[256];
+ wchar_t szMask[256];
+ int i;
+ HWND hwndList = GetDlgItem(clvmHwnd, IDC_GROUPS);
+
+ item.mask = LVIF_TEXT;
+ item.pszText = szTemp;
+ item.cchTextMax = 255;
+
+ ListView_SetCheckState(hwndList, 0, dwFlags & CLVM_INCLUDED_UNGROUPED ? TRUE : FALSE);
+
+ for(i = 1; i < ListView_GetItemCount(hwndList); i++) {
+ item.iItem = i;
+ SendMessage(hwndList, LVM_GETITEM, 0, (LPARAM)&item);
+ _sntprintf(szMask, 256, _T("%s|"), szTemp);
+ if(dbv_gf.ptszVal && _tcsstr(dbv_gf.ptszVal, szMask))
+ ListView_SetCheckState(hwndList, i, TRUE)
+ else
+ ListView_SetCheckState(hwndList, i, FALSE);
+ }
+ }
+ {
+ HWND hwndList = GetDlgItem(clvmHwnd, IDC_STATUSMODES);
+ int i;
+
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ if((1 << (i - ID_STATUS_OFFLINE)) & statusMask)
+ ListView_SetCheckState(hwndList, i - ID_STATUS_OFFLINE, TRUE)
+ else
+ ListView_SetCheckState(hwndList, i - ID_STATUS_OFFLINE, FALSE);
+ }
+ }
+ SendDlgItemMessage(clvmHwnd, IDC_PROTOGROUPOP, CB_SETCURSEL, dwFlags & CLVM_PROTOGROUP_OP ? 1 : 0, 0);
+ SendDlgItemMessage(clvmHwnd, IDC_GROUPSTATUSOP, CB_SETCURSEL, dwFlags & CLVM_GROUPSTATUS_OP ? 1 : 0, 0);
+ CheckDlgButton(clvmHwnd, IDC_AUTOCLEAR, dwFlags & CLVM_AUTOCLEAR ? 1 : 0);
+ UpdateStickies();
+
+ {
+ int useLastMsg = dwFlags & CLVM_USELASTMSG;
+ DWORD lmdat;
+ BYTE bTmp;
+
+ CheckDlgButton(clvmHwnd, IDC_LASTMSG, useLastMsg);
+ Utils::enableDlgControl(clvmHwnd, IDC_LASTMESSAGEOP, useLastMsg);
+ Utils::enableDlgControl(clvmHwnd, IDC_LASTMSGVALUE, useLastMsg);
+ Utils::enableDlgControl(clvmHwnd, IDC_LASTMESSAGEUNIT, useLastMsg);
+
+ mir_snprintf(szSetting, 128, "%c%s_LM", 246, szBuf);
+ lmdat = cfg::getDword(CLVM_MODULE, szSetting, 0);
+
+ SetDlgItemInt(clvmHwnd, IDC_LASTMSGVALUE, LOWORD(lmdat), FALSE);
+ bTmp = LOBYTE(HIWORD(lmdat));
+ SendDlgItemMessage(clvmHwnd, IDC_LASTMESSAGEOP, CB_SETCURSEL, bTmp, 0);
+ bTmp = HIBYTE(HIWORD(lmdat));
+ SendDlgItemMessage(clvmHwnd, IDC_LASTMESSAGEUNIT, CB_SETCURSEL, bTmp, 0);
+ }
+
+ ShowPage(clvmHwnd, 0);
+cleanup:
+ db_free(&dbv_pf);
+ db_free(&dbv_gf);
+ free(szBuf);
+}
+
+INT_PTR CALLBACK DlgProcViewModesSetup(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ clvmHwnd = hwndDlg;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ int i = 0;
+ TCITEMA tci;
+ RECT rcClient;
+ CLCINFOITEM cii = {0};
+ HICON hIcon;
+
+ if(IS_THEMED)
+ Api::pfnEnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
+
+ himlViewModes = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 12, 0);
+ for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ ImageList_AddIcon(himlViewModes, Skin_LoadProtoIcon(NULL, i));
+
+ hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_MINIMIZE), IMAGE_ICON, 16, 16, 0);
+ nullImage = ImageList_AddIcon(himlViewModes, hIcon);
+ DestroyIcon(hIcon);
+ GetClientRect(hwndDlg, &rcClient);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = 0;
+ tci.pszText = Translate("Sticky contacts");
+ SendMessageA(GetDlgItem(hwndDlg, IDC_TAB), TCM_INSERTITEMA, (WPARAM)0, (LPARAM)&tci);
+
+ tci.pszText = Translate("Filtering");
+ SendMessageA(GetDlgItem(hwndDlg, IDC_TAB), TCM_INSERTITEMA, (WPARAM)0, (LPARAM)&tci);
+
+ TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), 0);
+
+ TranslateDialogDefault(hwndDlg);
+ FillDialog(hwndDlg);
+ Utils::enableDlgControl(hwndDlg, IDC_ADDVIEWMODE, FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)himlViewModes);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETEXTRACOLUMNS, ID_STATUS_OUTTOLUNCH - ID_STATUS_OFFLINE, 0);
+ cii.cbSize = sizeof(cii);
+ cii.hParentGroup = 0;
+ cii.pszText = _T("*** All contacts ***");
+ hInfoItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0);
+ if(SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_SETCURSEL, 0, 0) != LB_ERR) {
+ clvm_curItem = 0;
+ UpdateFilters();
+ }
+ else
+ clvm_curItem = -1;
+ g_ViewModeOptDlg = TRUE;
+ i = 0;
+ while(_page2Controls[i] != 0)
+ ShowWindow(GetDlgItem(hwndDlg, _page2Controls[i++]), SW_HIDE);
+ ShowWindow(hwndDlg, SW_SHOWNORMAL);
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_AUTOCLEARSPIN, UDM_SETRANGE, 0, MAKELONG(1000, 0));
+ SetWindowText(hwndDlg, TranslateT("Configure view modes"));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_PROTOGROUPOP:
+ case IDC_GROUPSTATUSOP:
+ case IDC_LASTMESSAGEUNIT:
+ case IDC_LASTMESSAGEOP:
+ if (HIWORD(wParam) == CBN_SELCHANGE)
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ break;
+ case IDC_AUTOCLEAR:
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ break;
+ case IDC_LASTMSG:
+ {
+ int bUseLastMsg = IsDlgButtonChecked(hwndDlg, IDC_LASTMSG);
+ Utils::enableDlgControl(hwndDlg, IDC_LASTMESSAGEOP, bUseLastMsg);
+ Utils::enableDlgControl(hwndDlg, IDC_LASTMESSAGEUNIT, bUseLastMsg);
+ Utils::enableDlgControl(hwndDlg, IDC_LASTMSGVALUE, bUseLastMsg);
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ break;
+ }
+ case IDC_AUTOCLEARVAL:
+ case IDC_LASTMSGVALUE:
+ if(HIWORD(wParam) == EN_CHANGE && GetFocus() == (HWND)lParam)
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ break;
+ case IDC_DELETEVIEWMODE:
+ {
+ if(MessageBoxA(0, Translate("Really delete this view mode? This cannot be undone"), Translate("Delete a view mode"), MB_YESNO | MB_ICONQUESTION) == IDYES) {
+ char szSetting[256];
+ int iLen = SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_GETTEXTLEN, SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_GETCURSEL, 0, 0), 0);
+ if(iLen) {
+ char *szBuf = ( char* )malloc(iLen + 1);
+ if(szBuf) {
+ MCONTACT hContact;
+
+ SendDlgItemMessageA(hwndDlg, IDC_VIEWMODES, LB_GETTEXT, SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_GETCURSEL, 0, 0), (LPARAM)szBuf);
+ mir_snprintf(szSetting, 256, "%c%s_PF", 246, szBuf);
+ db_unset(NULL, CLVM_MODULE, szSetting);
+ mir_snprintf(szSetting, 256, "%c%s_GF", 246, szBuf);
+ db_unset(NULL, CLVM_MODULE, szSetting);
+ mir_snprintf(szSetting, 256, "%c%s_SM", 246, szBuf);
+ db_unset(NULL, CLVM_MODULE, szSetting);
+ mir_snprintf(szSetting, 256, "%c%s_VA", 246, szBuf);
+ db_unset(NULL, CLVM_MODULE, szSetting);
+ mir_snprintf(szSetting, 256, "%c%s_SSM", 246, szBuf);
+ db_unset(NULL, CLVM_MODULE, szSetting);
+ db_unset(NULL, CLVM_MODULE, szBuf);
+ if(!strcmp(cfg::dat.current_viewmode, szBuf) && lstrlenA(szBuf) == lstrlenA(cfg::dat.current_viewmode)) {
+ cfg::dat.bFilterEffective = 0;
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ SetWindowTextA(hwndSelector, Translate("No view mode"));
+ }
+ hContact = db_find_first();
+ while(hContact) {
+ if(cfg::getDword(hContact, "CLVM", szBuf, -1) != -1)
+ cfg::writeDword(hContact, "CLVM", szBuf, 0);
+ hContact = db_find_next(hContact);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_DELETESTRING, SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_GETCURSEL, 0, 0), 0);
+ if(SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_SETCURSEL, 0, 0) != LB_ERR) {
+ clvm_curItem = 0;
+ UpdateFilters();
+ }
+ else
+ clvm_curItem = -1;
+ free(szBuf);
+ }
+ }
+ }
+ break;
+ }
+ case IDC_ADDVIEWMODE:
+ {
+ char szBuf[256];
+
+ szBuf[0] = 0;
+ GetDlgItemTextA(hwndDlg, IDC_NEWVIEMODE, szBuf, 256);
+ szBuf[255] = 0;
+
+ if(lstrlenA(szBuf) > 2) {
+ if(cfg::getDword(CLVM_MODULE, szBuf, -1) != -1)
+ MessageBox(0, TranslateT("A view mode with this name does alredy exist"), TranslateT("Duplicate name"), MB_OK);
+ else {
+ int iNewItem = SendDlgItemMessageA(hwndDlg, IDC_VIEWMODES, LB_INSERTSTRING, -1, (LPARAM)szBuf);
+ if(iNewItem != LB_ERR) {
+ SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_SETCURSEL, (WPARAM)iNewItem, 0);
+ SaveViewMode(szBuf, _T(""), "", -1, -1, 0, 0, 0, 0);
+ clvm_curItem = iNewItem;
+ UpdateStickies();
+ SendDlgItemMessage(hwndDlg, IDC_PROTOGROUPOP, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_GROUPSTATUSOP, CB_SETCURSEL, 0, 0);
+ }
+ }
+ SetDlgItemTextA(hwndDlg, IDC_NEWVIEMODE, "");
+ }
+ Utils::enableDlgControl(hwndDlg, IDC_ADDVIEWMODE, FALSE);
+ break;
+ }
+ case IDC_CLEARALL:
+ {
+ HANDLE hItem;
+ MCONTACT hContact = db_find_first();
+
+ while(hContact) {
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if(hItem)
+ SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM)hItem, 0);
+ hContact = db_find_next(hContact);
+ }
+ }
+ case IDOK:
+ case IDC_APPLY:
+ SaveState();
+ if(cfg::dat.bFilterEffective)
+ ApplyViewMode(cfg::dat.current_viewmode);
+ if(LOWORD(wParam) == IDOK)
+ DestroyWindow(hwndDlg);
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ if(LOWORD(wParam) == IDC_NEWVIEMODE && HIWORD(wParam) == EN_CHANGE)
+ Utils::enableDlgControl(hwndDlg, IDC_ADDVIEWMODE, TRUE);
+ if(LOWORD(wParam) == IDC_VIEWMODES && HIWORD(wParam) == LBN_SELCHANGE) {
+ SaveState();
+ clvm_curItem = SendDlgItemMessage(hwndDlg, IDC_VIEWMODES, LB_GETCURSEL, 0, 0);
+ UpdateFilters();
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR) lParam)->idFrom) {
+ case IDC_GROUPS:
+ case IDC_STATUSMODES:
+ case IDC_PROTOCOLS:
+ case IDC_CLIST:
+ if (((LPNMHDR) lParam)->code == NM_CLICK || ((LPNMHDR) lParam)->code == CLN_CHECKCHANGED)
+ Utils::enableDlgControl(hwndDlg, IDC_APPLY, TRUE);
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ //SetAllContactIcons(GetDlgItem(hwndDlg,IDC_CLIST));
+ //fall through
+ /*
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case CLN_CHECKCHANGED:
+ {
+ HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ int typeOfItem = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE,(WPARAM)nm->hItem, 0);
+ break;
+ }*/
+ case NM_CLICK:
+ {
+ HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+
+ if(nm->iColumn==-1)
+ break;
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_CLIST,CLM_HITTEST,(WPARAM)&hitFlags,MAKELPARAM(nm->pt.x,nm->pt.y));
+ if(hItem==NULL) break;
+ if(!(hitFlags&CLCHT_ONITEMEXTRA))
+ break;
+ iImage = SendDlgItemMessage(hwndDlg,IDC_CLIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,0));
+ if(iImage == nullImage)
+ iImage = nm->iColumn;
+ else if(iImage!=0xFF)
+ iImage = nullImage;
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_CLIST),hItem,hInfoItem,nm->iColumn,iImage);
+ //SetListGroupIcons(GetDlgItem(hwndDlg,IDC_CLIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hInfoItem,NULL);
+ break;
+ }
+ }
+ break;
+ case IDC_TAB:
+ if (((LPNMHDR) lParam)->code == TCN_SELCHANGE) {
+ int id = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+ if(id == 0)
+ ShowPage(hwndDlg, 0);
+ else
+ ShowPage(hwndDlg, 1);
+ break;
+ }
+
+ }
+ break;
+ }
+ case WM_DESTROY:
+ ImageList_RemoveAll(himlViewModes);
+ ImageList_Destroy(himlViewModes);
+ g_ViewModeOptDlg = FALSE;
+ break;
+ }
+ return FALSE;
+}
+
+static int menuCounter = 0;
+
+static int FillMenuCallback(char *szSetting)
+{
+ if(szSetting[0] == 246)
+ return 1;
+
+ AppendMenuA(hViewModeMenu, MF_STRING, menuCounter++, szSetting);
+ return 1;
+}
+
+void BuildViewModeMenu()
+{
+ if(hViewModeMenu)
+ DestroyMenu(hViewModeMenu);
+
+ menuCounter = 100;
+ hViewModeMenu = CreatePopupMenu();
+ CLVM_EnumModes(FillMenuCallback);
+
+ if(GetMenuItemCount(hViewModeMenu) > 0)
+ AppendMenuA(hViewModeMenu, MF_SEPARATOR, 0, NULL);
+
+ AppendMenuA(hViewModeMenu, MF_STRING, 10001, Translate("Setup View Modes..."));
+ AppendMenuA(hViewModeMenu, MF_STRING, 10002, Translate("Clear current View Mode"));
+
+}
+
+static UINT _buttons[] = {IDC_RESETMODES, IDC_SELECTMODE, IDC_CONFIGUREMODES, 0};
+
+LRESULT CALLBACK ViewModeFrameWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CREATE:
+ {
+ HWND hwndButton;
+
+ hwndSelector = CreateWindowEx(0, _T("CLCButtonClass"), _T(""), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 20, 20,
+ hwnd, (HMENU) IDC_SELECTMODE, g_hInst, NULL);
+ SendMessage(hwndSelector, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Select a view mode"), 0);
+ SendMessage(hwndSelector, BM_SETASMENUACTION, 1, 0);
+ hwndButton = CreateWindowEx(0, _T("CLCButtonClass"), _T(""), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 20, 20,
+ hwnd, (HMENU) IDC_CONFIGUREMODES, g_hInst, NULL);
+ SendMessage(hwndButton, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Setup view modes"), 0);
+ hwndButton = CreateWindowEx(0, _T("CLCButtonClass"), _T(""), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 20, 20,
+ hwnd, (HMENU) IDC_RESETMODES, g_hInst, NULL);
+ SendMessage(hwndButton, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Clear view mode and return to default display"), 0);
+ SendMessage(hwnd, WM_USER + 100, 0, 0);
+ return FALSE;
+ }
+ case WM_NCCALCSIZE:
+ {
+ BOOL hasTitleBar = wndFrameViewMode ? wndFrameViewMode->TitleBar.ShowTitleBar : 0;
+ return FrameNCCalcSize(hwnd, DefWindowProc, wParam, lParam, hasTitleBar);
+ }
+ case WM_NCPAINT:
+ {
+ BOOL hasTitleBar = wndFrameViewMode ? wndFrameViewMode->TitleBar.ShowTitleBar : 0;
+ return FrameNCPaint(hwnd, DefWindowProc, wParam, lParam, hasTitleBar);
+ }
+ case WM_SIZE:
+ {
+ RECT rcCLVMFrame;
+ HDWP PosBatch = BeginDeferWindowPos(3);
+ GetClientRect(hwnd, &rcCLVMFrame);
+ PosBatch = DeferWindowPos(PosBatch, GetDlgItem(hwnd, IDC_RESETMODES), 0,
+ rcCLVMFrame.right - 23, 1, 22, 22, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
+ PosBatch = DeferWindowPos(PosBatch, GetDlgItem(hwnd, IDC_CONFIGUREMODES), 0,
+ rcCLVMFrame.right - 46, 1, 22, 22, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
+ PosBatch = DeferWindowPos(PosBatch, GetDlgItem(hwnd, IDC_SELECTMODE), 0,
+ 1, 1, rcCLVMFrame.right - 48, 22, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
+ EndDeferWindowPos(PosBatch);
+ break;
+ }
+ case WM_USER + 100:
+ SendMessage(GetDlgItem(hwnd, IDC_RESETMODES), BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon("core_main_15"));
+ SendMessage(GetDlgItem(hwnd, IDC_CONFIGUREMODES), BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon("core_main_32"));
+ SendMessage(GetDlgItem(hwnd, IDC_SELECTMODE), BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon("core_main_11"));
+ {
+ int bSkinned = cfg::getByte("CLCExt", "bskinned", 0);
+ int i = 0;
+
+ while(_buttons[i] != 0) {
+ SendMessage(GetDlgItem(hwnd, _buttons[i]), BM_SETSKINNED, 0, bSkinned);
+ if(bSkinned) {
+ SendDlgItemMessage(hwnd, _buttons[i], BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwnd, _buttons[i], BUTTONSETASFLATBTN + 10, 0, 0);
+ }
+ else {
+ SendDlgItemMessage(hwnd, _buttons[i], BUTTONSETASFLATBTN, 0, 1);
+ SendDlgItemMessage(hwnd, _buttons[i], BUTTONSETASFLATBTN + 10, 0, 1);
+ }
+ i++;
+ }
+ }
+ if(cfg::dat.bFilterEffective)
+ SetWindowTextA(GetDlgItem(hwnd, IDC_SELECTMODE), cfg::dat.current_viewmode);
+ else
+ SetWindowText(GetDlgItem(hwnd, IDC_SELECTMODE), TranslateT("No view mode"));
+ break;
+
+ case WM_ERASEBKGND:
+ return(1);
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ RECT rc;
+ HDC hdcMem;
+ HANDLE hbp = 0;
+
+ GetClientRect(hwnd, &rc);
+ INIT_PAINT(hdc, rc, hdcMem);
+
+ Gfx::drawBGFromSurface(hwnd, rc, hdcMem);
+ FINALIZE_PAINT(hbp, &rc, 0);
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+ case WM_TIMER:
+ {
+ switch(wParam) {
+ case TIMERID_VIEWMODEEXPIRE:
+ {
+ POINT pt;
+ RECT rcCLUI;
+
+ GetWindowRect(pcli->hwndContactList, &rcCLUI);
+ GetCursorPos(&pt);
+ if(PtInRect(&rcCLUI, pt))
+ break;
+
+ KillTimer(hwnd, wParam);
+ if(!cfg::dat.old_viewmode[0])
+ SendMessage(hwnd, WM_COMMAND, IDC_RESETMODES, 0);
+ else
+ ApplyViewMode((const char *)cfg::dat.old_viewmode);
+ break;
+ } }
+ break;
+ }
+ case WM_COMMAND:
+ {
+ switch(LOWORD(wParam)) {
+ case IDC_SELECTMODE:
+ {
+ RECT rc;
+ POINT pt;
+ int selection;
+ MENUITEMINFOA mii = {0};
+ char szTemp[256];
+
+ BuildViewModeMenu();
+ //GetWindowRect(GetDlgItem(hwnd, IDC_SELECTMODE), &rc);
+ GetWindowRect((HWND)lParam, &rc);
+ pt.x = rc.left;
+ pt.y = rc.bottom;
+ selection = TrackPopupMenu(hViewModeMenu,TPM_RETURNCMD|TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ if(selection) {
+
+ if(selection == 10001)
+ goto clvm_config_command;
+ else if(selection == 10002)
+ goto clvm_reset_command;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STRING;
+ mii.dwTypeData = szTemp;
+ mii.cch = 256;
+ GetMenuItemInfoA(hViewModeMenu, selection, FALSE, &mii);
+ ApplyViewMode(szTemp);
+ }
+ break;
+ }
+ case IDC_RESETMODES:
+clvm_reset_command:
+ cfg::dat.bFilterEffective = 0;
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ SetWindowTextA(GetDlgItem(hwnd, IDC_SELECTMODE), Translate("No view mode"));
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM)cfg::dat.boldHideOffline, 0);
+ cfg::dat.boldHideOffline = (BYTE)-1;
+ CLUI::setButtonStates(pcli->hwndContactList);
+ cfg::dat.current_viewmode[0] = 0;
+ cfg::dat.old_viewmode[0] = 0;
+ cfg::writeString(NULL, "CList", "LastViewMode", "");
+ break;
+ case IDC_CONFIGUREMODES:
+clvm_config_command:
+ if(!g_ViewModeOptDlg)
+ CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_OPT_VIEWMODES), 0, DlgProcViewModesSetup, 0);
+ break;
+ }
+ break;
+ }
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return TRUE;
+}
+
+static HWND hCLVMFrame;
+HWND g_hwndViewModeFrame;
+
+void CreateViewModeFrame()
+{
+ CLISTFrame frame = {0};
+ WNDCLASS wndclass = {0};
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = ViewModeFrameWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = g_hInst;
+ wndclass.hIcon = 0;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE);
+ wndclass.lpszMenuName = 0;
+ wndclass.lpszClassName = _T("CLVMFrameWindow");
+
+ RegisterClass(&wndclass);
+
+ ZeroMemory(&frame, sizeof(frame));
+ frame.cbSize = sizeof(frame);
+ frame.tname = _T("View modes");
+ frame.TBtname = TranslateT("View Modes");
+ frame.hIcon = 0;
+ frame.height = 22;
+ frame.Flags=F_VISIBLE|F_SHOWTBTIP|F_NOBORDER|F_TCHAR;
+ frame.align = alBottom;
+ frame.hWnd = CreateWindowEx(0, _T("CLVMFrameWindow"), _T("CLVM"), WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN, 0, 0, 20, 20, pcli->hwndContactList, (HMENU) 0, g_hInst, NULL);
+ g_hwndViewModeFrame = frame.hWnd;
+ hCLVMFrame = (HWND)CallService(MS_CLIST_FRAMES_ADDFRAME,(WPARAM)&frame,(LPARAM)0);
+ CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)hCLVMFrame, FU_FMPOS);
+}
+
+const char *MakeVariablesString(const char *src, const char *UIN);
+
+void ApplyViewMode(const char *name)
+{
+ char szSetting[256];
+ DBVARIANT dbv = {0};
+
+ cfg::dat.bFilterEffective = 0;
+
+ mir_snprintf(szSetting, 256, "%c%s_PF", 246, name);
+ if(!cfg::getString(NULL, CLVM_MODULE, szSetting, &dbv)) {
+ if(lstrlenA(dbv.pszVal) >= 2) {
+ strncpy(cfg::dat.protoFilter, dbv.pszVal, sizeof(cfg::dat.protoFilter));
+ cfg::dat.protoFilter[sizeof(cfg::dat.protoFilter) - 1] = 0;
+ cfg::dat.bFilterEffective |= CLVM_FILTER_PROTOS;
+ }
+ mir_free(dbv.pszVal);
+ }
+ mir_snprintf(szSetting, 256, "%c%s_GF", 246, name);
+ if(!cfg::getTString(NULL, CLVM_MODULE, szSetting, &dbv)) {
+ if(lstrlen(dbv.ptszVal) >= 2) {
+ _tcsncpy(cfg::dat.groupFilter, dbv.ptszVal, safe_sizeof(cfg::dat.groupFilter));
+ cfg::dat.groupFilter[safe_sizeof(cfg::dat.groupFilter) - 1] = 0;
+ cfg::dat.bFilterEffective |= CLVM_FILTER_GROUPS;
+ }
+ mir_free(dbv.ptszVal);
+ }
+ mir_snprintf(szSetting, 256, "%c%s_SM", 246, name);
+ cfg::dat.statusMaskFilter = cfg::getDword(CLVM_MODULE, szSetting, -1);
+ if(cfg::dat.statusMaskFilter >= 1)
+ cfg::dat.bFilterEffective |= CLVM_FILTER_STATUS;
+
+ mir_snprintf(szSetting, 256, "%c%s_SSM", 246, name);
+ cfg::dat.stickyMaskFilter = cfg::getDword(CLVM_MODULE, szSetting, -1);
+ if(cfg::dat.stickyMaskFilter != -1)
+ cfg::dat.bFilterEffective |= CLVM_FILTER_STICKYSTATUS;
+
+ /*
+ mir_snprintf(szSetting, 256, "%c%s_VA", 246, name);
+ if(!DBGetContactSettingString(NULL, CLVM_MODULE, szSetting, &dbv)) {
+ strncpy(g_CluiData.varFilter, dbv.pszVal, sizeof(g_CluiData.varFilter));
+ g_CluiData.varFilter[sizeof(g_CluiData.varFilter) - 1] = 0;
+ if(lstrlenA(g_CluiData.varFilter) > 10 && ServiceExists(MS_VARS_FORMATSTRING))
+ g_CluiData.bFilterEffective |= CLVM_FILTER_VARIABLES;
+ mir_free(dbv.ptszVal);
+ if(g_CluiData.bFilterEffective & CLVM_FILTER_VARIABLES) {
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ char UIN[256];
+ char *id, *szProto;
+ const char *varstring;
+ char *temp;
+ FORMATINFO fi;
+
+ while(hContact) {
+ szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(szProto) {
+ id = (char*) CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
+ if(id) {
+ if(!DBGetContactSetting(hContact, szProto, id, &dbv)) {
+ if(dbv.type == DBVT_ASCIIZ) {
+ mir_snprintf(UIN, 256, "<%s:%s>", szProto, dbv.pszVal);
+ }
+ else {
+ mir_snprintf(UIN, 256, "<%s:%d>", szProto, dbv.dVal);
+ }
+ varstring = MakeVariablesString(g_CluiData.varFilter, UIN);
+ ZeroMemory(&fi, sizeof(fi));
+ fi.cbSize = sizeof(fi);
+ fi.szFormat = varstring;
+ fi.szSource = "";
+ fi.hContact = 0;
+ temp = (char *)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0);
+ if(temp && atol(temp) > 0)
+ _DebugPopup(hContact, "%s, %d, %d, %d", temp, temp, fi.pCount, fi.eCount);
+ variables_free(temp);
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+ }
+ }*/
+
+ cfg::dat.filterFlags = cfg::getDword(CLVM_MODULE, name, 0);
+
+ KillTimer(g_hwndViewModeFrame, TIMERID_VIEWMODEEXPIRE);
+
+ if(cfg::dat.filterFlags & CLVM_AUTOCLEAR) {
+ DWORD timerexpire;
+ mir_snprintf(szSetting, 256, "%c%s_OPT", 246, name);
+ timerexpire = LOWORD(cfg::getDword(CLVM_MODULE, szSetting, 0));
+ strncpy(cfg::dat.old_viewmode, cfg::dat.current_viewmode, 256);
+ cfg::dat.old_viewmode[255] = 0;
+ SetTimer(g_hwndViewModeFrame, TIMERID_VIEWMODEEXPIRE, timerexpire * 1000, NULL);
+ }
+ strncpy(cfg::dat.current_viewmode, name, 256);
+ cfg::dat.current_viewmode[255] = 0;
+
+ if(cfg::dat.filterFlags & CLVM_USELASTMSG) {
+ DWORD unit;
+ int i;
+ BYTE bSaved = cfg::dat.sortOrder[0];
+
+ cfg::dat.sortOrder[0] = SORTBY_LASTMSG;
+ for(i = 0; i < cfg::nextCacheEntry; i++)
+ cfg::eCache[i].dwLastMsgTime = INTSORT_GetLastMsgTime(cfg::eCache[i].hContact);
+
+ cfg::dat.sortOrder[0] = bSaved;
+
+ cfg::dat.bFilterEffective |= CLVM_FILTER_LASTMSG;
+ mir_snprintf(szSetting, 256, "%c%s_LM", 246, name);
+ cfg::dat.lastMsgFilter = cfg::getDword(CLVM_MODULE, szSetting, 0);
+ if(LOBYTE(HIWORD(cfg::dat.lastMsgFilter)))
+ cfg::dat.bFilterEffective |= CLVM_FILTER_LASTMSG_NEWERTHAN;
+ else
+ cfg::dat.bFilterEffective |= CLVM_FILTER_LASTMSG_OLDERTHAN;
+ unit = LOWORD(cfg::dat.lastMsgFilter);
+ switch(HIBYTE(HIWORD(cfg::dat.lastMsgFilter))) {
+ case 0:
+ unit *= 60;
+ break;
+ case 1:
+ unit *= 3600;
+ break;
+ case 2:
+ unit *= 86400;
+ break;
+ }
+ cfg::dat.lastMsgFilter = unit;
+ }
+
+ if(HIWORD(cfg::dat.filterFlags) > 0)
+ cfg::dat.bFilterEffective |= CLVM_STICKY_CONTACTS;
+
+ if(cfg::dat.boldHideOffline == (BYTE)-1)
+ cfg::dat.boldHideOffline = cfg::getByte("CList", "HideOffline", 0);
+
+ CallService(MS_CLIST_SETHIDEOFFLINE, 0, 0);
+ SetWindowTextA(hwndSelector, name);
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ CLUI::setButtonStates(pcli->hwndContactList);
+
+ cfg::writeString(NULL, "CList", "LastViewMode", cfg::dat.current_viewmode);
+}
+
+
|