summaryrefslogtreecommitdiff
path: root/src/modules/options
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
commit48540940b6c28bb4378abfeb500ec45a625b37b6 (patch)
tree2ef294c0763e802f91d868bdef4229b6868527de /src/modules/options
parent5c350913f011e119127baeb32a6aedeb4f0d33bc (diff)
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules/options')
-rw-r--r--src/modules/options/descbutton.cpp332
-rw-r--r--src/modules/options/filter.cpp217
-rw-r--r--src/modules/options/filter.h108
-rw-r--r--src/modules/options/headerbar.cpp372
-rw-r--r--src/modules/options/iconheader.cpp545
-rw-r--r--src/modules/options/options.cpp1521
6 files changed, 3095 insertions, 0 deletions
diff --git a/src/modules/options/descbutton.cpp b/src/modules/options/descbutton.cpp
new file mode 100644
index 0000000000..2e5d55c7a4
--- /dev/null
+++ b/src/modules/options/descbutton.cpp
@@ -0,0 +1,332 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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"
+#include "m_descbutton.h"
+
+extern HINSTANCE hMirandaInst;
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+#define DBC_BORDER_SIZE 7
+#define DBC_VSPACING 15
+#define DBC_HSPACING 10
+
+static LRESULT CALLBACK MDescButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+typedef struct {
+ HWND hwnd;
+ BOOL bSharedIcon;
+ HICON hIcon;
+ TCHAR *lpzTitle;
+ TCHAR *lpzDescription;
+
+ // UI info
+ BOOL bMouseInside;
+ RECT rc;
+ int width, height;
+ HFONT hfntTitle;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ RGBQUAD rgbSelTop, rgbSelBottom;
+ RGBQUAD rgbHotTop, rgbHotBottom;
+ COLORREF clText, clBackground;
+ COLORREF clSelText, clSelBorder;
+ COLORREF clHotText, clHotBorder;
+
+ // fonts
+ HFONT hFont;
+} MDescButtonCtrl;
+
+int LoadDescButtonModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDADESCBUTTONCLASS;
+ wc.lpfnWndProc = MDescButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_HAND);
+ wc.cbWndExtra = sizeof(MDescButtonCtrl *);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS|CS_SAVEBITS;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MDescButton_SetupColors(MDescButtonCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ cl = GetSysColor(COLOR_HIGHLIGHT);
+ dat->rgbSelTop.rgbRed = (dat->rgbSelBottom.rgbRed = GetRValue(cl)) * .75;
+ dat->rgbSelTop.rgbGreen = (dat->rgbSelBottom.rgbGreen = GetGValue(cl)) * .75;
+ dat->rgbSelTop.rgbBlue = (dat->rgbSelBottom.rgbBlue = GetBValue(cl)) * .75;
+
+ dat->rgbHotTop.rgbRed = (dat->rgbSelTop.rgbRed + 255) / 2;
+ dat->rgbHotTop.rgbGreen = (dat->rgbSelTop.rgbGreen + 255) / 2;
+ dat->rgbHotTop.rgbBlue = (dat->rgbSelTop.rgbBlue + 255) / 2;
+
+ dat->rgbHotBottom.rgbRed = (dat->rgbSelBottom.rgbRed + 255) / 2;
+ dat->rgbHotBottom.rgbGreen = (dat->rgbSelBottom.rgbGreen + 255) / 2;
+ dat->rgbHotBottom.rgbBlue = (dat->rgbSelBottom.rgbBlue + 255) / 2;
+
+ dat->clBackground = GetSysColor(COLOR_3DFACE);
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+ dat->clSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ dat->clSelBorder = RGB(dat->rgbSelTop.rgbRed, dat->rgbSelTop.rgbGreen, dat->rgbSelTop.rgbBlue);
+ dat->clHotBorder = RGB(dat->rgbHotTop.rgbRed, dat->rgbHotTop.rgbGreen, dat->rgbHotTop.rgbBlue);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MDescButton_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MDescButton_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for (int i=y+height; --i >= y; ) {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static LRESULT MDescButton_OnPaint(HWND hwndDlg, MDescButtonCtrl *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+ RECT temprc;
+ HFONT hfntSave;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ SIZE titleSize = {0};
+
+ hBmp=CreateCompatibleBitmap(hdc,dat->width, dat->height);
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ temprc.left=0;
+ temprc.right=dat->width;
+ temprc.top=0;
+
+ //Draw background
+ if (dat->bMouseInside || (GetFocus() == hwndDlg)) {
+ MDescButton_FillRect(tempDC, 0, 0, dat->width, dat->height, dat->clSelBorder);
+ MDescButton_DrawGradient(tempDC, 1, 1, dat->width-2, dat->height-2, &dat->rgbSelTop, &dat->rgbSelBottom);
+ SetTextColor(tempDC, dat->clSelText);
+ }
+ else {
+ MDescButton_FillRect(tempDC, 0, 0, dat->width, dat->height, dat->clBackground);
+ SetTextColor(tempDC, dat->clText);
+ }
+
+ if (dat->hIcon)
+ DrawIcon(tempDC, DBC_BORDER_SIZE, DBC_BORDER_SIZE, dat->hIcon);
+
+ hfntSave = (HFONT)SelectObject(tempDC, dat->hFont);
+ SetBkMode(tempDC, TRANSPARENT);
+
+ if (dat->lpzTitle) {
+ LOGFONT lf;
+ RECT textRect;
+ HFONT hfntSave;
+
+ GetObject(dat->hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ lf.lfHeight *= 1.5;
+ hfntSave = (HFONT)SelectObject(tempDC, CreateFontIndirect(&lf));
+
+ textRect.left = DBC_BORDER_SIZE + dat->hIcon ? 32 + DBC_VSPACING : 0;
+ textRect.right = dat->width - DBC_BORDER_SIZE;
+ textRect.top = DBC_BORDER_SIZE;
+ textRect.bottom = dat->height - DBC_BORDER_SIZE;
+ DrawText(tempDC, dat->lpzTitle, -1, &textRect, DT_TOP|DT_LEFT|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(tempDC, dat->lpzTitle, lstrlen(dat->lpzTitle), &titleSize);
+
+ DeleteObject(SelectObject(tempDC, hfntSave));
+ }
+
+ if (dat->lpzDescription) {
+ RECT textRect;
+ textRect.left = DBC_BORDER_SIZE + dat->hIcon ? 32 + DBC_VSPACING : 0;
+ textRect.right = dat->width - DBC_BORDER_SIZE;
+ textRect.top = DBC_BORDER_SIZE + titleSize.cy ? titleSize.cy + DBC_HSPACING : 0;
+ textRect.bottom = dat->height - DBC_BORDER_SIZE;
+ DrawText(tempDC, dat->lpzDescription, -1, &textRect, DT_TOP|DT_LEFT|DT_WORDBREAK|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(tempDC, dat->lpzTitle, lstrlen(dat->lpzTitle), &titleSize);
+ }
+
+ SelectObject(tempDC, hfntSave);
+
+ //Copy to output
+ BitBlt(hdc,dat->rc.left,dat->rc.top,dat->width,dat->height,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MDescButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MDescButtonCtrl *dat = (MDescButtonCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ dat = (MDescButtonCtrl*)mir_alloc(sizeof(MDescButtonCtrl));
+ if (dat==NULL)
+ return FALSE;
+
+ memset(dat, 0, sizeof(MDescButtonCtrl));
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)dat);
+ MDescButton_SetupColors(dat);
+ return TRUE;
+
+ case WM_SETFONT:
+ dat->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&dat->rc);
+ dat->width=dat->rc.right-dat->rc.left;
+ dat->height=dat->rc.bottom-dat->rc.top;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MDescButton_SetupColors(dat);
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (!dat->bMouseInside) {
+ TRACKMOUSEEVENT tme = {0};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwndDlg;
+ _TrackMouseEvent(&tme);
+ dat->bMouseInside = TRUE;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ }
+ return 0;
+
+ case WM_MOUSELEAVE:
+ dat->bMouseInside = FALSE;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_LBUTTONUP:
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), 0), 0);
+ return 0;
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MDescButton_OnPaint(hwndDlg, dat, msg, wParam, lParam);
+ break;
+
+ case DBCM_SETTITLE:
+ if (dat->lpzTitle)
+ mir_free(dat->lpzTitle);
+ if (wParam & MDBCF_UNICODE)
+ dat->lpzTitle = mir_u2t((WCHAR *)lParam);
+ else
+ dat->lpzTitle = mir_a2t((char *)lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case DBCM_SETDESCRIPTION:
+ if (dat->lpzDescription)
+ mir_free(dat->lpzDescription);
+ if (wParam & MDBCF_UNICODE)
+ dat->lpzDescription = mir_u2t((WCHAR *)lParam);
+ else
+ dat->lpzDescription = mir_a2t((char *)lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case DBCM_SETICON:
+ if (dat->hIcon && !dat->bSharedIcon)
+ DestroyIcon(dat->hIcon);
+
+ if (wParam & MDBCF_SHAREDICON) {
+ dat->bSharedIcon = TRUE;
+ dat->hIcon = (HICON)lParam;
+ }
+ else {
+ dat->bSharedIcon = FALSE;
+ dat->hIcon = CopyIcon((HICON)lParam);
+ }
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case WM_DESTROY:
+ if (dat->lpzTitle)
+ mir_free(dat->lpzTitle);
+ if (dat->lpzDescription)
+ mir_free(dat->lpzDescription);
+ if (dat->hIcon && !dat->bSharedIcon)
+ DestroyIcon(dat->hIcon);
+ mir_free(dat);
+ return TRUE;
+ }
+
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/filter.cpp b/src/modules/options/filter.cpp
new file mode 100644
index 0000000000..116899d44e
--- /dev/null
+++ b/src/modules/options/filter.cpp
@@ -0,0 +1,217 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 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"
+#include "filter.h"
+
+HANDLE hOptionsInitialize;
+
+int HookFilterEvents()
+{
+ hOptionsInitialize = HookEvent(ME_OPT_INITIALISE, OnOptionsInitialise);
+ return 0;
+}
+
+int UnhookFilterEvents()
+{
+ UnhookEvent(hOptionsInitialize);
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcOptSearch(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWnd);
+
+ CheckDlgButton(hWnd, IDC_ENABLE_KEYWORDFILTERING, DBGetContactSettingWord(NULL, "Options", "EnableKeywordFiltering", TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ENABLE_KEYWORDFILTERING:
+ SendMessage(GetParent(hWnd), PSM_CHANGED,0,0);
+ break;
+ }
+ break;
+
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hWnd, IDC_ENABLE_KEYWORDFILTERING));
+ break;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ DBWriteContactSettingWord(NULL, "Options", "EnableKeywordFiltering", IsDlgButtonChecked(hWnd, IDC_ENABLE_KEYWORDFILTERING));
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int OnOptionsInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ odp.cbSize = sizeof(odp);
+ odp.position = -190000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_KEYWORDFILTER);
+ odp.ptszTitle = TranslateT("Options search");
+ odp.ptszGroup = TranslateT("Customize");
+ odp.groupPosition = 810000000;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.pfnDlgProc = DlgProcOptSearch;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ return 0;
+}
+
+CPageList filterStrings(1);
+
+void AddFilterString(const PageHash key, TCHAR *data)
+{
+ if (ContainsFilterString(key, data)) return;
+
+ CPageKeywords * values = filterStrings[key];
+ if ( values == NULL ) {
+ values = new CPageKeywords( key );
+ filterStrings.insert( values );
+ }
+ values->AddKeyWord( data );
+}
+
+void ClearFilterStrings()
+{
+ filterStrings.destroy();
+}
+
+BOOL ContainsFilterString(const PageHash key, TCHAR *data)
+{
+ CPageKeywords* values = filterStrings[key];
+ return (values) ? values->ContainsString( data ) : FALSE;
+}
+
+void AddTreeViewNodes(HWND hWndDlg, PageHash key, HTREEITEM root)
+{
+ if (root) {
+ TCHAR title[2048] = {0};
+
+ TVITEM item = {0};
+ item.mask = TVIF_TEXT;
+ item.hItem = root;
+ item.pszText = title;
+ item.cchTextMax = SIZEOF(title);
+
+ if (TreeView_GetItem(hWndDlg, &item))
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+
+ HTREEITEM child = root;
+ while (child) {
+ child = TreeView_GetNextItem(hWndDlg, child, TVGN_CHILD);
+ AddTreeViewNodes(hWndDlg, key, child);
+ }
+
+ AddTreeViewNodes(hWndDlg, key, TreeView_GetNextSibling(hWndDlg, root));
+ }
+}
+
+void AddDialogString(HWND hWndDlg, const PageHash key)
+{
+ TCHAR title[2048];
+ GetWindowText(hWndDlg, title, SIZEOF( title ));
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+
+ TCHAR szClass[64];
+ GetClassName(hWndDlg,szClass, SIZEOF(szClass));
+
+ if (lstrcmpi(szClass, _T("SysTreeView32")) == 0) {
+ HTREEITEM hItem = TreeView_GetRoot(hWndDlg);
+ AddTreeViewNodes(hWndDlg, key, hItem);
+ }
+ else {
+ if (lstrcmpi(szClass, _T("listbox")) == 0) {
+ if (GetWindowStyle(hWndDlg) & LBS_HASSTRINGS) {
+ int count = ListBox_GetCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ int res = ListBox_GetText(hWndDlg, i, title);
+ if (res != LB_ERR) {
+ title[SIZEOF(title) - 1] = 0;
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+ } } }
+ }
+ else {
+ if (lstrcmpi(szClass, _T("SysListView32")) == 0) {
+ int count = ListView_GetItemCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ ListView_GetItemText(hWndDlg, i, 0, title, SIZEOF(title));
+
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+ } }
+
+ if (lstrcmpi(szClass, _T("combobox")) == 0) {
+ if (GetWindowStyle(hWndDlg) & CBS_HASSTRINGS) {
+ int count = ComboBox_GetCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ int res = ComboBox_GetLBText(hWndDlg, i, title);
+ if (res != CB_ERR) {
+ title[SIZEOF(title) - 1] = 0;
+
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+} } } } } } }
+
+static BOOL CALLBACK GetDialogStringsCallback(HWND hWnd,LPARAM lParam)
+{
+ AddDialogString(hWnd, lParam);
+
+ return TRUE;
+}
+
+void GetDialogStrings(int enableKeywordFiltering, const PageHash key, TCHAR *pluginName, HWND hWnd, TCHAR * group, TCHAR * title, TCHAR * tab, TCHAR * name )
+{
+ AddFilterString(key, pluginName); //add the plugin name as keyword
+ if ( group ) AddFilterString(key, group);
+ if ( title ) AddFilterString(key, title);
+ if ( tab ) AddFilterString(key, tab);
+ if ( name ) AddFilterString(key, name);
+
+ if ((enableKeywordFiltering) && (hWnd != 0)) {
+ AddDialogString(hWnd, key);
+
+ EnumChildWindows(hWnd, GetDialogStringsCallback, (LPARAM) key);
+ }
+}
diff --git a/src/modules/options/filter.h b/src/modules/options/filter.h
new file mode 100644
index 0000000000..3db823fcdf
--- /dev/null
+++ b/src/modules/options/filter.h
@@ -0,0 +1,108 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 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.
+*/
+
+#ifndef M_OPTIONS_FILTERING_H
+#define M_OPTIONS_FILTERING_H
+
+extern HANDLE hOptionsInitialize;
+
+int HookFilterEvents();
+int UnhookFilterEvents();
+int OnOptionsInitialise(WPARAM wParam, LPARAM lParam);
+
+typedef DWORD PageHash;
+
+void AddFilterString(const PageHash key, const TCHAR *data);
+BOOL ContainsFilterString(const PageHash key, TCHAR *data);
+void ClearFilterStrings();
+void GetDialogStrings(int enableKeywordFiltering, const PageHash key, TCHAR *pluginName, HWND hWnd, TCHAR * group, TCHAR * title, TCHAR * tab, TCHAR * name );
+
+_inline TCHAR * _tcslwr_locale( TCHAR * buf )
+{
+ LCMapString( LangPackGetDefaultLocale() , LCMAP_LOWERCASE, buf, (int)_tcslen( buf ), buf, (int)_tcslen( buf ) );
+ return buf;
+}
+
+typedef LIST<TCHAR> KeywordList;
+class CPageKeywords
+{
+ PageHash _pageHashKey;
+ KeywordList _pageKeyWords;
+ static int _KeyWordsSortFunc( const TCHAR* p1, const TCHAR* p2 ) { return _tcscmp( p1, p2 ); };
+
+public:
+ CPageKeywords( PageHash pageHashKey ) : _pageHashKey( pageHashKey ), _pageKeyWords( 1, _KeyWordsSortFunc ) {};
+ ~CPageKeywords()
+ {
+ for ( int j = 0; j < _pageKeyWords.getCount(); j++ )
+ {
+ TCHAR * data = _pageKeyWords[j];
+ mir_free( data );
+ }
+ _pageKeyWords.destroy();
+ };
+
+ void AddKeyWord( TCHAR * ptKeyWord )
+ {
+ TCHAR * plwrWord = _tcslwr_locale( mir_tstrdup( ptKeyWord ) );
+ if ( _pageKeyWords.getIndex( plwrWord ) == -1 )
+ _pageKeyWords.insert( plwrWord ) ;
+ else
+ mir_free( plwrWord );
+ };
+
+ BOOL ContainsString( TCHAR * data )
+ {
+ for ( int i = 0; i < _pageKeyWords.getCount(); i++)
+ if (_tcsstr(_pageKeyWords[i], data))
+ return TRUE;
+ return FALSE;
+ }
+ static int PageSortFunc( const CPageKeywords* p1, const CPageKeywords* p2 )
+ {
+ if (p1->_pageHashKey < p2->_pageHashKey) { return -1; }
+ else if (p1->_pageHashKey > p2->_pageHashKey) { return 1; }
+ return 0;
+ }
+};
+
+class CPageList : public OBJLIST<CPageKeywords>
+{
+ CPageList();
+public:
+ CPageList( int aincr, FTSortFunc afunc = CPageKeywords::PageSortFunc ) : OBJLIST<CPageKeywords>( aincr, afunc ) {};
+ CPageKeywords * operator[]( PageHash key )
+ {
+ CPageKeywords keyToSearch( key );
+ return this->find( &keyToSearch );
+ }
+ ~CPageList() {};
+};
+
+
+
+int LangPackGetDefaultLocale();
+
+
+#endif //M_OPTIONS_FILTERING_H
+
diff --git a/src/modules/options/headerbar.cpp b/src/modules/options/headerbar.cpp
new file mode 100644
index 0000000000..a2407d2aab
--- /dev/null
+++ b/src/modules/options/headerbar.cpp
@@ -0,0 +1,372 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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"
+#include "m_iconheader.h"
+
+extern HINSTANCE hMirandaInst;
+
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static BOOL IsVSMode()
+{
+ return isThemeActive && IsWinVerVistaPlus() && isThemeActive();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+static LRESULT CALLBACK MHeaderbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+struct MHeaderbarCtrl
+{
+ __inline void* operator new( size_t size )
+ { return mir_calloc( size );
+ }
+ __inline void operator delete( void* p )
+ { mir_free( p );
+ }
+
+ MHeaderbarCtrl() {}
+ ~MHeaderbarCtrl() { mir_free( controlsToRedraw ); }
+
+ HWND hwnd;
+
+ // UI info
+ RECT rc;
+ int width, height;
+ HICON hIcon;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ COLORREF clText;
+
+ int nControlsToRedraw;
+ HWND *controlsToRedraw;
+
+ // fonts
+ HFONT hFont;
+};
+
+int LoadHeaderbarModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _T("MHeaderbarCtrl"); //MIRANDAHEADERBARCLASS;
+ wc.lpfnWndProc = MHeaderbarWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MHeaderbarCtrl*);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS|CS_SAVEBITS;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MHeaderbar_SetupColors(MHeaderbarCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MHeaderbar_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MHeaderbar_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int i;
+
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for (i=y+height; --i >= y; )
+ {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static LRESULT MHeaderbar_OnPaint(HWND hwndDlg, MHeaderbarCtrl *mit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int iTopSpace = IsAeroMode() ? 0 : 3;
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+
+ int titleLength = GetWindowTextLength(hwndDlg) + 1;
+ TCHAR *szTitle = (TCHAR *)mir_alloc(sizeof(TCHAR) * titleLength);
+ GetWindowText(hwndDlg, szTitle, titleLength);
+
+ TCHAR *szSubTitle = _tcschr(szTitle, _T('\n'));
+ if (szSubTitle) *szSubTitle++ = 0;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = mit->width;
+ bmi.bmiHeader.biHeight = -mit->height; // we need this for DrawThemeTextEx
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ if (IsAeroMode()) {
+ RECT temprc;
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ FillRect(tempDC, &temprc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+
+ MARGINS margins = {0,0,mit->height,0};
+ dwmExtendFrameIntoClientArea(GetParent(hwndDlg), &margins);
+
+ WTA_OPTIONS opts;
+ opts.dwFlags = opts.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
+ setWindowThemeAttribute(GetParent(hwndDlg), WTA_NONCLIENT, &opts, sizeof(opts));
+ }
+ else {
+ if (IsVSMode())
+ MHeaderbar_FillRect(tempDC, 0, 0, mit->width, mit->height, GetSysColor(COLOR_WINDOW));
+ else
+ MHeaderbar_DrawGradient(tempDC, 0, 0, mit->width, mit->height, &mit->rgbBkgTop, &mit->rgbBkgBottom);
+
+ MHeaderbar_FillRect(tempDC, 0, mit->height-2, mit->width, 1, GetSysColor(COLOR_BTNSHADOW));
+ MHeaderbar_FillRect(tempDC, 0, mit->height-1, mit->width, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
+ }
+
+ HFONT hFont = mit->hFont;
+ SetBkMode(tempDC, TRANSPARENT);
+ SetTextColor(tempDC, mit->clText);
+
+ LOGFONT lf;
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ HFONT hFntBold = CreateFontIndirect(&lf);
+
+ if (mit->hIcon)
+ DrawIcon(tempDC, 10, iTopSpace, mit->hIcon);
+ else {
+ HICON hIcon = (HICON)SendMessage(GetParent(hwndDlg), WM_GETICON, ICON_BIG, 0);
+ if (hIcon == NULL)
+ hIcon = (HICON)SendMessage(GetParent(hwndDlg), WM_GETICON, ICON_SMALL, 0);
+ DrawIcon(tempDC, 10, iTopSpace, hIcon);
+ }
+
+ RECT textRect;
+ textRect.left=50;
+ textRect.right=mit->width;
+ textRect.top=2 + iTopSpace;
+ textRect.bottom=GetSystemMetrics(SM_CYICON)-2 + iTopSpace;
+
+ if (IsAeroMode()) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ dto.iGlowSize = 10;
+
+ HANDLE hTheme = openThemeData(hwndDlg, L"Window");
+ textRect.left=50;
+ SelectObject(tempDC, hFntBold);
+
+ wchar_t *szTitleW = mir_t2u(szTitle);
+ drawThemeTextEx(hTheme, tempDC, WP_CAPTION, CS_ACTIVE, szTitleW, -1, DT_TOP|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(szTitleW);
+
+ if (szSubTitle) {
+ textRect.left=66;
+ SelectObject(tempDC, hFont);
+
+ wchar_t *szSubTitleW = mir_t2u(szSubTitle);
+ drawThemeTextEx(hTheme, tempDC, WP_CAPTION, CS_ACTIVE, szSubTitleW, -1, DT_BOTTOM|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(szSubTitleW);
+ }
+ closeThemeData(hTheme);
+ }
+ else {
+ textRect.left=50;
+ SelectObject(tempDC, hFntBold);
+ DrawText(tempDC, szTitle, -1, &textRect, DT_TOP|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS);
+
+ if (szSubTitle) {
+ textRect.left=66;
+ SelectObject(tempDC, hFont);
+ DrawText(tempDC, szSubTitle, -1, &textRect, DT_BOTTOM|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS);
+ } }
+
+ DeleteObject(hFntBold);
+
+ mir_free(szTitle);
+
+ //Copy to output
+ if (mit->nControlsToRedraw)
+ {
+ RECT temprc;
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ HRGN hRgn = CreateRectRgnIndirect(&temprc);
+
+ for (int i = 0; i < mit->nControlsToRedraw; ++i)
+ {
+ GetWindowRect(mit->controlsToRedraw[i], &temprc);
+ MapWindowPoints(NULL, hwndDlg, (LPPOINT)&temprc, 2);
+ HRGN hRgnTmp = CreateRectRgnIndirect(&temprc);
+ CombineRgn(hRgn, hRgn, hRgnTmp, RGN_DIFF);
+ DeleteObject(hRgnTmp);
+ }
+ SelectClipRgn(hdc,hRgn);
+ DeleteObject(hRgn);
+ }
+
+ BitBlt(hdc,mit->rc.left,mit->rc.top,mit->width,mit->height,tempDC,0,0,SRCCOPY);
+
+ SelectClipRgn(hdc,NULL);
+
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MHeaderbarWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MHeaderbarCtrl* itc = (MHeaderbarCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ itc = new MHeaderbarCtrl; //(MHeaderbarCtrl*)mir_alloc(sizeof(MHeaderbarCtrl));
+ if (itc==NULL)
+ return FALSE;
+
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)itc);
+ MHeaderbar_SetupColors(itc);
+
+ { HWND hParent = GetParent(hwndDlg);
+ RECT rcWnd; GetWindowRect(hwndDlg, &rcWnd);
+ itc->controlsToRedraw = 0;
+ itc->nControlsToRedraw = 0;
+ for (HWND hChild = FindWindowEx(hParent, NULL, NULL, NULL); hChild; hChild = FindWindowEx(hParent, hChild, NULL, NULL))
+ {
+ if (hChild != hwndDlg)
+ {
+ RECT rcChild; GetWindowRect(hChild, &rcChild);
+ RECT rc;
+ IntersectRect(&rc, &rcChild, &rcWnd);
+ if (!IsRectEmpty(&rc))
+ {
+ ++itc->nControlsToRedraw;
+ itc->controlsToRedraw = (HWND *)mir_realloc(itc->controlsToRedraw, sizeof(HWND) * itc->nControlsToRedraw);
+ itc->controlsToRedraw[itc->nControlsToRedraw - 1] = hChild;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case WM_SETFONT:
+ itc->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&itc->rc);
+ itc->width=itc->rc.right-itc->rc.left;
+ itc->height=itc->rc.bottom-itc->rc.top;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MHeaderbar_SetupColors(itc);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ SendMessage(GetParent(hwndDlg), WM_SYSCOMMAND, 0xF012, 0);
+ return 0;
+
+ case WM_SETICON:
+ if (wParam < 3) {
+ itc->hIcon = (HICON)lParam;
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MHeaderbar_OnPaint(hwndDlg, itc, msg, wParam, lParam);
+ break;
+
+ case WM_DESTROY:
+ delete itc;
+ break;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/iconheader.cpp b/src/modules/options/iconheader.cpp
new file mode 100644
index 0000000000..9ab44b0852
--- /dev/null
+++ b/src/modules/options/iconheader.cpp
@@ -0,0 +1,545 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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"
+#include "m_iconheader.h"
+
+
+extern HINSTANCE hMirandaInst;
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static BOOL IsVSMode()
+{
+ return isThemeActive && IsWinVerVistaPlus() && isThemeActive();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+#define ITC_BORDER_SIZE 3
+
+static LRESULT CALLBACK MIcoTabWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+struct MIcoTabCtrl
+{
+ __inline void* operator new( size_t size )
+ { return mir_calloc( size );
+ }
+ __inline void operator delete( void* p )
+ { mir_free( p );
+ }
+
+ MIcoTabCtrl(): pList(1) {}
+
+ HWND hwnd;
+ int nSelectedIdx, nHotIdx;
+ LIST<MIcoTab> pList;
+
+ // UI info
+ BOOL bMouseInside;
+ RECT rc;
+ int width, height;
+ int itemWidth, itemHeight;
+
+ //background bitmap
+ HBITMAP hBkgBmp;
+ HBITMAP hBkgOldBmp;
+ HDC hBkgDC;
+ SIZE BkgSize;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ RGBQUAD rgbSelTop, rgbSelBottom;
+ RGBQUAD rgbHotTop, rgbHotBottom;
+ COLORREF clText;
+ COLORREF clSelText, clSelBorder;
+ COLORREF clHotText, clHotBorder;
+
+ // fonts
+ HFONT hFont;
+};
+
+typedef void (*ItemDestuctor)(void*);
+
+static void MITListDestructor(void * adr)
+{
+ MIcoTab * mit=(MIcoTab *)adr;
+ mir_free(mit->tcsName);
+ if (mit->hIcon && !(mit->flag&MITCF_SHAREDICON))
+ DestroyIcon(mit->hIcon);
+ mir_free(adr);
+}
+
+void li_ListDestruct(LIST<MIcoTab> &pList, ItemDestuctor pItemDestructor)
+{
+ for (int i=0; i<pList.getCount(); i++) pItemDestructor(pList[i]);
+ pList.destroy();
+}
+
+int LoadIcoTabsModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDAICOTABCLASS;
+ wc.lpfnWndProc = MIcoTabWndProc;
+// wc.hCursor = LoadCursor(NULL, IDC_HAND);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MIcoTabCtrl*);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS/*|CS_SAVEBITS*/;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MIcoTab_SetupColors(MIcoTabCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ cl = GetSysColor(COLOR_HIGHLIGHT);
+ dat->rgbSelTop.rgbRed = (dat->rgbSelBottom.rgbRed = GetRValue(cl)) * .75;
+ dat->rgbSelTop.rgbGreen = (dat->rgbSelBottom.rgbGreen = GetGValue(cl)) * .75;
+ dat->rgbSelTop.rgbBlue = (dat->rgbSelBottom.rgbBlue = GetBValue(cl)) * .75;
+
+ dat->rgbHotTop.rgbRed = (dat->rgbSelTop.rgbRed + 255) / 2;
+ dat->rgbHotTop.rgbGreen = (dat->rgbSelTop.rgbGreen + 255) / 2;
+ dat->rgbHotTop.rgbBlue = (dat->rgbSelTop.rgbBlue + 255) / 2;
+
+ dat->rgbHotBottom.rgbRed = (dat->rgbSelBottom.rgbRed + 255) / 2;
+ dat->rgbHotBottom.rgbGreen = (dat->rgbSelBottom.rgbGreen + 255) / 2;
+ dat->rgbHotBottom.rgbBlue = (dat->rgbSelBottom.rgbBlue + 255) / 2;
+
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+ dat->clSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ dat->clSelBorder = RGB(dat->rgbSelTop.rgbRed, dat->rgbSelTop.rgbGreen, dat->rgbSelTop.rgbBlue);
+ dat->clHotBorder = RGB(dat->rgbHotTop.rgbRed, dat->rgbHotTop.rgbGreen, dat->rgbHotTop.rgbBlue);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MIcoTab_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MIcoTab_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for ( int i=y+height; --i >= y; ) {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MIcoTab_DrawItem(HWND hwnd, HDC hdc, MIcoTabCtrl *dat, MIcoTab *tab, int i)
+{
+ int iTopSpace = IsAeroMode() ? 0 : ITC_BORDER_SIZE;
+ int itemX = ITC_BORDER_SIZE + dat->itemWidth * i;
+ int iconTop = iTopSpace + 5;
+ int textTop = iconTop + 32 + 3;
+
+ HFONT hFntSave = NULL;
+
+ if (dat->nSelectedIdx == i) {
+ LOGFONT lf;
+ GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ hFntSave = (HFONT)SelectObject(hdc, CreateFontIndirect(&lf));
+
+ if (IsVSMode()) {
+ RECT rc;
+ rc.left = itemX;
+ rc.top = iTopSpace;
+ rc.right = itemX + dat->itemWidth;
+ rc.bottom = iTopSpace + dat->itemHeight;
+ HANDLE hTheme = openThemeData(hwnd, L"ListView");
+ if (dat->nHotIdx == i || GetFocus() == hwnd)
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_HOTSELECTED, &rc, NULL);
+ else
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_SELECTED, &rc, NULL);
+
+ closeThemeData(hTheme);
+ }
+ else {
+ MIcoTab_FillRect(hdc, itemX, ITC_BORDER_SIZE, dat->itemWidth, dat->itemHeight, dat->clSelBorder);
+ MIcoTab_DrawGradient(hdc, itemX+1, ITC_BORDER_SIZE+1, dat->itemWidth-2, dat->itemHeight-2, &dat->rgbSelTop, &dat->rgbSelBottom);
+ }
+ SetTextColor(hdc, dat->clSelText);
+ }
+ else if (dat->nHotIdx == i) {
+ if (IsVSMode()) {
+ RECT rc;
+ rc.left = itemX;
+ rc.top = iTopSpace;
+ rc.right = itemX + dat->itemWidth;
+ rc.bottom = iTopSpace + dat->itemHeight;
+ setWindowTheme(hwnd, L"explorer", NULL);
+ HANDLE hTheme = openThemeData(hwnd, L"ListView");
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_HOT, &rc, NULL);
+ closeThemeData(hTheme);
+ }
+ else {
+ MIcoTab_FillRect(hdc, itemX, ITC_BORDER_SIZE, dat->itemWidth, dat->itemHeight, dat->clHotBorder);
+ MIcoTab_DrawGradient(hdc, itemX+1, ITC_BORDER_SIZE+1, dat->itemWidth-2, dat->itemHeight-2, &dat->rgbHotTop, &dat->rgbHotBottom);
+ }
+ SetTextColor(hdc, dat->clHotText);
+ }
+ else SetTextColor(hdc, dat->clText);
+
+ RECT textRect;
+ textRect.left=itemX;
+ textRect.right=itemX+dat->itemWidth;
+ textRect.top=textTop;
+ textRect.bottom=iconTop+dat->itemHeight;
+ DrawIcon(hdc,itemX+dat->itemWidth/2-16, iconTop, tab->hIcon);
+
+ if (IsVSMode()) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ dto.iGlowSize = 10;
+ HANDLE hTheme = openThemeData(hwnd, L"Window");
+ wchar_t *tcsNameW = mir_t2u(tab->tcsName);
+ drawThemeTextEx(hTheme, hdc, WP_CAPTION, CS_ACTIVE, tcsNameW, -1, DT_VCENTER|DT_CENTER|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(tcsNameW);
+ closeThemeData(hTheme);
+ }
+ else DrawText(hdc,tab->tcsName,-1,&textRect, DT_VCENTER|DT_CENTER|DT_END_ELLIPSIS);
+
+ if (hFntSave)
+ DeleteObject(SelectObject(hdc, hFntSave));
+}
+
+static LRESULT MIcoTab_OnPaint(HWND hwndDlg, MIcoTabCtrl *mit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+ RECT temprc;
+ int i;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ HFONT hFont = 0;
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = mit->width;
+ bmi.bmiHeader.biHeight = -mit->height; // we need this for DrawThemeTextEx
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ if (IsAeroMode()) {
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ FillRect(tempDC, &temprc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+ else {
+ if (mit->hBkgBmp)
+ StretchBlt(tempDC,0,0,mit->width,mit->height,mit->hBkgDC,0,0,mit->BkgSize.cx,mit->BkgSize.cy,SRCCOPY);
+ else {
+ if (IsVSMode())
+ MIcoTab_FillRect(tempDC, 0, 0, mit->width, mit->height, GetSysColor(COLOR_WINDOW));
+ else
+ MIcoTab_DrawGradient(tempDC, 0, 0, mit->width, mit->height, &mit->rgbBkgTop, &mit->rgbBkgBottom);
+
+ MIcoTab_FillRect(tempDC, 0, mit->height-2, mit->width, 1, GetSysColor(COLOR_BTNSHADOW));
+ MIcoTab_FillRect(tempDC, 0, mit->height-1, mit->width, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
+ } }
+
+ //Draw Items
+ hFont = mit->hFont;
+ SelectObject(tempDC,hFont);
+ SetBkMode(tempDC,TRANSPARENT);
+
+ for (i=0; i<mit->pList.getCount(); i++) {
+ MIcoTab *tab = (MIcoTab *)mit->pList[i];
+ MIcoTab_DrawItem(hwndDlg, tempDC, mit, tab, i);
+ }
+
+ //Copy to output
+ BitBlt(hdc,mit->rc.left,mit->rc.top,mit->width,mit->height,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MIcoTabWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MIcoTabCtrl* itc = (MIcoTabCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ itc = new MIcoTabCtrl; //(MIcoTabCtrl*)mir_alloc(sizeof(MIcoTabCtrl));
+ if (itc==NULL) return FALSE;
+ itc->nSelectedIdx=-1;
+ itc->nHotIdx=-1;
+ itc->bMouseInside = FALSE;
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)itc);
+ MIcoTab_SetupColors(itc);
+
+ if (IsAeroMode()) {
+ RECT rc; GetWindowRect(hwndDlg, &rc);
+ MARGINS margins = {0,0,rc.bottom-rc.top,0};
+ dwmExtendFrameIntoClientArea(GetParent(hwndDlg), &margins);
+ }
+
+ return TRUE;
+
+ case WM_SETFONT:
+ itc->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&itc->rc);
+ itc->width=itc->rc.right-itc->rc.left;
+ itc->height=itc->rc.bottom-itc->rc.top;
+
+ if (itc->pList.getCount()) {
+ itc->itemWidth=(itc->width-2*ITC_BORDER_SIZE)/itc->pList.getCount();
+ itc->itemHeight=itc->height-2*ITC_BORDER_SIZE-2;
+ }
+ else itc->itemWidth = itc->itemHeight = 0;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MIcoTab_SetupColors(itc);
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (!itc->bMouseInside) {
+ TRACKMOUSEEVENT tme = {0};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwndDlg;
+ _TrackMouseEvent(&tme);
+ itc->bMouseInside = TRUE;
+ }
+
+ itc->nHotIdx = (LOWORD(lParam) - ITC_BORDER_SIZE) / itc->itemWidth;
+ if (itc->nHotIdx >= itc->pList.getCount())
+ itc->nHotIdx = -1;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_MOUSELEAVE:
+ itc->bMouseInside = FALSE;
+ itc->nHotIdx = -1;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_LBUTTONUP:
+ if ((itc->nHotIdx >= 0) && (itc->nHotIdx != itc->nSelectedIdx))
+ {
+ itc->nSelectedIdx = itc->nHotIdx;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGED),
+ itc->nSelectedIdx);
+ }
+ return 0;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ break;
+
+ case WM_MOUSEACTIVATE:
+ SetFocus(hwndDlg);
+ return MA_ACTIVATE;
+
+ case WM_GETDLGCODE:
+ {
+ if (lParam)
+ {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN)
+ {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE)
+ return 0;
+ } else
+ if (msg->message == WM_CHAR)
+ {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+ }
+
+ case WM_KEYDOWN:
+ {
+ int newIdx = itc->nSelectedIdx;
+ switch (wParam)
+ {
+ case VK_NEXT:
+ case VK_RIGHT:
+ newIdx++;
+ break;
+ case VK_PRIOR:
+ case VK_LEFT:
+ newIdx--;
+ break;
+ }
+ if ((newIdx >= 0) && (newIdx < itc->pList.getCount()) && (newIdx != itc->nSelectedIdx))
+ {
+ itc->nSelectedIdx = newIdx;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGEDKBD),
+ itc->nSelectedIdx);
+ }
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MIcoTab_OnPaint(hwndDlg, itc, msg, wParam, lParam);
+ break;
+
+ case ITCM_SETBACKGROUND:
+ itc->hBkgBmp=(HBITMAP)lParam;
+ if (!itc->hBkgDC)
+ itc->hBkgDC = CreateCompatibleDC(NULL);
+ itc->hBkgOldBmp = (HBITMAP)SelectObject(itc->hBkgDC, itc->hBkgBmp);
+ {
+ BITMAPINFO bmp;
+ GetObject(itc->hBkgBmp, sizeof(bmp), &bmp);
+ itc->BkgSize.cx=bmp.bmiHeader.biWidth;
+ itc->BkgSize.cy=bmp.bmiHeader.biHeight;
+ }
+ return TRUE;
+
+ case ITCM_ADDITEM:
+ {
+ MIcoTab* pMit=(MIcoTab *)wParam;
+ if (!pMit)
+ return FALSE;
+
+ MIcoTab* pListMit=(MIcoTab *)mir_calloc(sizeof(MIcoTab));
+ pListMit->flag=pMit->flag;
+ pListMit->data=pMit->data;
+ if (pMit->flag & MITCF_UNICODE)
+ pListMit->tcsName=mir_u2t(pMit->lpwzName);
+ else
+ pListMit->tcsName=mir_a2t(pMit->lpzName);
+ if (pMit->hIcon) {
+ if (pListMit->flag&MITCF_SHAREDICON)
+ pListMit->hIcon=pMit->hIcon;
+ else
+ pListMit->hIcon=CopyIcon(pMit->hIcon);
+ }
+ itc->pList.insert(pListMit);
+
+ itc->itemWidth=(itc->width-2*ITC_BORDER_SIZE)/itc->pList.getCount();
+ itc->itemHeight=itc->height-2*ITC_BORDER_SIZE-2;
+
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+ }
+
+ case ITCM_SETSEL:
+ if ( wParam >= 0 && (int)wParam < itc->pList.getCount()) {
+ itc->nSelectedIdx = wParam;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGED),
+ itc->nSelectedIdx);
+ }
+ return TRUE;
+
+ case ITCM_GETSEL:
+ return itc->nSelectedIdx;
+
+ case ITCM_GETITEMDATA:
+ if ( wParam >= 0 && (int)wParam < itc->pList.getCount())
+ return ((MIcoTab *)itc->pList[wParam])->data;
+ return 0;
+
+ case WM_DESTROY:
+ if (itc->hBkgDC) {
+ SelectObject(itc->hBkgDC, itc->hBkgOldBmp);
+ DeleteDC(itc->hBkgDC);
+ }
+ li_ListDestruct(itc->pList,MITListDestructor);
+ delete itc;
+ return TRUE;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/options.cpp b/src/modules/options/options.cpp
new file mode 100644
index 0000000000..0366d99062
--- /dev/null
+++ b/src/modules/options/options.cpp
@@ -0,0 +1,1521 @@
+/*
+
+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.
+*/
+#include "commonheaders.h"
+#include "filter.h"
+
+#define OPENOPTIONSDIALOG_OLD_SIZE 12
+
+#define FILTER_TIMEOUT_TIMER 10012
+
+#define ALL_MODULES_FILTER _T("<all modules>")
+#define CORE_MODULES_FILTER _T("<core modules>")
+
+static HANDLE hOptionsInitEvent;
+static HWND hwndOptions=NULL;
+static HWND hFilterSearchWnd = NULL;
+
+// Thread for search keywords in dialogs
+static BYTE bSearchState = 0; // 0 - not executed; 1 - in progress; 2 - completed;
+static int FilterPage = 0;
+static int FilterLoadProgress = 100;
+static int FilterTimerId = 0;
+
+char * GetPluginNameByInstance( HINSTANCE hInstance );
+
+struct OptionsPageInit
+{
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DlgTemplateExBegin
+{
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+};
+
+struct OptionsPageData
+{
+ DLGTEMPLATE *pTemplate;
+ DLGPROC dlgProc;
+ HINSTANCE hInst;
+ HTREEITEM hTreeItem;
+ HWND hwnd;
+ int changed;
+ int simpleHeight,expertHeight;
+ int simpleWidth,expertWidth;
+ int simpleBottomControlId,simpleRightControlId;
+ int nExpertOnlyControls;
+ UINT *expertOnlyControls;
+ DWORD flags;
+ TCHAR *pszTitle, *pszGroup, *pszTab;
+ BOOL insideTab;
+ LPARAM dwInitParam;
+
+ int offsetX;
+ int offsetY;
+};
+
+struct OptionsDlgData
+{
+ int pageCount;
+ int currentPage;
+ HTREEITEM hCurrentPage;
+ struct OptionsPageData *opd;
+ RECT rcDisplay;
+ RECT rcTab;
+ HFONT hBoldFont;
+ TCHAR szFilterString[1024];
+};
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetRoot( hwndTree );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static HTREEITEM FindNamedTreeItemAtChildren(HWND hwndTree, HTREEITEM hItem, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetChild( hwndTree, hItem );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static BOOL CALLBACK BoldGroupTitlesEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ TCHAR szClass[64];
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmp(szClass,_T("Button")) && (GetWindowLongPtr(hwnd,GWL_STYLE)&0x0F)==BS_GROUPBOX)
+ SendMessage(hwnd,WM_SETFONT,lParam,0);
+ return TRUE;
+}
+
+struct MoveChildParam
+{
+ HWND hDlg;
+ POINT offset;
+};
+static BOOL CALLBACK MoveEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ struct MoveChildParam * param = ( struct MoveChildParam *) lParam;
+
+ RECT rcWnd;
+ GetWindowRect( hwnd, &rcWnd);
+
+ HWND hwndParent = GetParent( hwnd );
+ if ( hwndParent != param->hDlg )
+ return TRUE; // Do not move subchilds
+
+ POINT pt; pt.x = 0; pt.y = 0;
+
+ ClientToScreen( hwndParent, &pt );
+ OffsetRect( &rcWnd, -pt.x, -pt.y );
+
+ SetWindowPos( hwnd, NULL, rcWnd.left + param->offset.x, rcWnd.top + param->offset.y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
+
+ return TRUE;
+}
+
+#define OPTSTATE_PREFIX "s_"
+
+static void SaveOptionsTreeState(HWND hdlg)
+{
+ TVITEMA tvi;
+ char buf[130],str[128];
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot( GetDlgItem( hdlg, IDC_PAGETREE ));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ mir_snprintf(buf, SIZEOF(buf), "%s%s",OPTSTATE_PREFIX,str);
+ DBWriteContactSettingByte(NULL,"Options",buf,(BYTE)((tvi.state&TVIS_EXPANDED)?1:0));
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+} }
+
+#define DM_FOCUSPAGE (WM_USER+10)
+#define DM_REBUILDPAGETREE (WM_USER+11)
+
+static void ThemeDialogBackground(HWND hwnd, BOOL tabbed)
+{
+ if (enableThemeDialogTexture)
+ enableThemeDialogTexture(hwnd, (tabbed ? ETDT_ENABLE : ETDT_DISABLE) | ETDT_USETABTEXTURE);
+}
+
+static int lstrcmpnull(TCHAR *str1, TCHAR *str2)
+{
+ if ( str1 == NULL && str2 == NULL )
+ return 0;
+ if ( str1 != NULL && str2 == NULL )
+ return 1;
+ if ( str1 == NULL && str2 != NULL )
+ return -1;
+
+ return lstrcmp(str1, str2);
+}
+
+static TCHAR *GetPluginName(HINSTANCE hInstance, TCHAR *buffer, int size)
+{
+ TCHAR tszModuleName[MAX_PATH];
+ GetModuleFileName(hInstance, tszModuleName, SIZEOF(tszModuleName));
+ TCHAR *dllName = _tcsrchr(tszModuleName,'\\');
+ if (!dllName)
+ {
+ dllName = tszModuleName;
+ }
+ else {
+ dllName++;
+ }
+
+ _tcsncpy(buffer, dllName, size);
+
+ return buffer;
+}
+
+PageHash GetPluginPageHash(const OptionsPageData *page)
+{
+ return hashstr(page->pszGroup) + hashstr(page->pszTitle) + hashstr(page->pszTab);
+}
+
+static void FindFilterStrings(int enableKeywordFiltering, int current, HWND hWndParent, const OptionsPageData *page)
+{
+ TCHAR pluginName[MAX_PATH];
+ HWND hWnd = 0;
+ if (enableKeywordFiltering) {
+ if (current)
+ hWnd = page->hwnd;
+ else
+ {
+ hWnd = CreateDialogIndirectParamA(page->hInst, page->pTemplate, hWndParent, page->dlgProc, page->dwInitParam); //create the options dialog page so we can parse it
+ ShowWindow(hWnd, SW_HIDE); //make sure it's hidden
+ } }
+
+ DWORD key = GetPluginPageHash(page); //get the plugin page hash
+
+ TCHAR * PluginFullName = NULL;
+ char * temp = GetPluginNameByInstance( page->hInst );
+ if ( temp ) PluginFullName = mir_a2t( temp );
+ GetDialogStrings(enableKeywordFiltering, key, GetPluginName(page->hInst, pluginName, SIZEOF(pluginName)), hWnd, page->pszGroup, page->pszTitle, page->pszTab, PluginFullName );
+ if ( PluginFullName ) mir_free( PluginFullName ) ;
+
+ if (enableKeywordFiltering && !current)
+ DestroyWindow(hWnd); //destroy the page, we're done with it
+}
+
+static int MatchesFilter(const OptionsPageData *page, TCHAR *szFilterString)
+{
+ DWORD key = GetPluginPageHash(page);
+
+ return ContainsFilterString(key, szFilterString);
+}
+
+static WNDPROC OptionsFilterDefaultProc = NULL;
+
+static LRESULT CALLBACK OptionsFilterSubclassProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message != WM_PAINT && message != WM_PRINT)
+ return CallWindowProc(OptionsFilterDefaultProc, hWnd, message, wParam, lParam );
+
+ if ( GetFocus() == hWnd || GetWindowTextLength( hWnd ) )
+ return CallWindowProc(OptionsFilterDefaultProc, hWnd, message, wParam, lParam );
+
+ RECT rc;
+ GetClientRect( hWnd, &rc);
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ if (message == WM_PAINT)
+ hdc = BeginPaint( hWnd, &paint);
+ else
+ hdc = (HDC)wParam;
+
+ TCHAR buf[255];
+ if ( bSearchState==1 && FilterLoadProgress < 100 && FilterLoadProgress > 0 )
+ mir_sntprintf( buf, SIZEOF(buf), TranslateT("Loading... %d%%"), FilterLoadProgress );
+ else
+ mir_sntprintf( buf, SIZEOF(buf), TranslateT( "Search" ) );
+
+ BOOL bDrawnByTheme = FALSE;
+
+ int oldMode = SetBkMode( hdc, TRANSPARENT );
+
+ if ( openThemeData ) {
+ HTHEME hTheme = openThemeData( hWnd, L"EDIT");
+ if ( hTheme ) {
+ if ( isThemeBackgroundPartiallyTransparent( hTheme, EP_EDITTEXT, ETS_NORMAL ))
+ drawThemeParentBackground( hWnd, hdc, &rc );
+
+ RECT rc2;
+ getThemeBackgroundContentRect( hTheme, hdc, EP_EDITTEXT, ETS_NORMAL, &rc, &rc2 );
+ rc2.top = 2 * rc.top - rc2.top;
+ rc2.left = 2 * rc.left - rc2.left;
+ rc2.bottom = 2 * rc.bottom - rc2.bottom;
+ rc2.right = 2 * rc.right - rc2.right;
+
+ drawThemeBackground( hTheme, hdc, EP_EDITTEXT, ETS_NORMAL, &rc2, &rc );
+ HFONT hFont = (HFONT) SendMessage(hWnd, WM_GETFONT, 0, 0);
+ HFONT oldFont = (HFONT) SelectObject( hdc, hFont );
+
+ wchar_t *bufW = mir_t2u(buf);
+ drawThemeText( hTheme, hdc, EP_EDITTEXT, ETS_DISABLED, bufW, -1, 0, 0, &rc );
+ mir_free(bufW);
+
+ SelectObject( hdc, oldFont );
+ closeThemeData( hTheme );
+ bDrawnByTheme = TRUE;
+ }
+ }
+
+ SetBkMode( hdc, oldMode );
+
+ if ( !bDrawnByTheme ) {
+ HFONT hFont = (HFONT) SendMessage(hWnd, WM_GETFONT, 0, 0);
+ HFONT oldFont = (HFONT) SelectObject( hdc, hFont );
+ SetTextColor( hdc, GetSysColor(COLOR_GRAYTEXT) );
+ FillRect( hdc, &rc, GetSysColorBrush( COLOR_WINDOW ) );
+ int oldMode = SetBkMode( hdc, TRANSPARENT );
+ DrawText( hdc, buf, -1, &rc, 0 );
+ SetBkMode( hdc, oldMode );
+ SelectObject( hdc, oldFont );
+ }
+
+ if (message == WM_PAINT)
+ EndPaint( hWnd, &paint);
+
+ return 0;
+}
+
+static BOOL CheckPageShow( HWND hdlg, OptionsDlgData * dat, int i )
+{
+ if (dat->szFilterString && dat->szFilterString[0] && !MatchesFilter(&dat->opd[i], dat->szFilterString)) return FALSE;
+ if ((dat->opd[i].flags & ODPF_SIMPLEONLY) && IsDlgButtonChecked( hdlg, IDC_EXPERT)) return FALSE;
+ if ((dat->opd[i].flags & ODPF_EXPERTONLY) && !IsDlgButtonChecked( hdlg, IDC_EXPERT)) return FALSE;
+ return TRUE;
+}
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static void AeroPaintControl(HWND hwnd, HDC hdc, WNDPROC OldWndProc, UINT msg = WM_PRINT, LPARAM lpFlags = PRF_CLIENT|PRF_NONCLIENT)
+{
+ HBITMAP hBmp, hOldBmp;
+ RECT rc; GetClientRect(hwnd, &rc);
+ BYTE *pBits;
+
+ HDC tempDC = CreateCompatibleDC(hdc);
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = rc.right;
+ bmi.bmiHeader.biHeight = -rc.bottom;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+
+ hOldBmp = (HBITMAP)SelectObject(tempDC,hBmp);
+
+ //paint
+ SetPropA(hwnd, "Miranda.AeroRender.Active", (HANDLE)TRUE);
+ CallWindowProc(OldWndProc, hwnd, msg, (WPARAM)tempDC, lpFlags);
+ SetPropA(hwnd, "Miranda.AeroRender.Active", (HANDLE)FALSE);
+
+ // Fix alpha channel
+ GdiFlush();
+ for (int i = 0; i < rc.right*rc.bottom; ++i, pBits += 4)
+ if (!pBits[3]) pBits[3] = 255;
+
+ //Copy to output
+ BitBlt(hdc,0,0,rc.right,rc.bottom,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+}
+
+static LRESULT CALLBACK AeroPaintSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC OldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_CTLCOLOREDIT:
+ if (!GetPropA((HWND)lParam, "Miranda.AeroRender.Active"))
+ RedrawWindow((HWND)lParam, NULL, NULL, RDW_INVALIDATE);
+ break;
+
+ case WM_ERASEBKGND:
+ return TRUE;
+
+ case WM_PRINT:
+ case WM_PRINTCLIENT:
+ AeroPaintControl(hwnd, (HDC)wParam, OldWndProc, msg, lParam);
+ return TRUE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ AeroPaintControl(hwnd, hdc, OldWndProc);
+ EndPaint(hwnd, &ps);
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ RemovePropA(hwnd, "Miranda.AeroRender.Active");
+ break;
+ }
+ return CallWindowProc(OldWndProc, hwnd, msg, wParam, lParam);
+}
+
+static void CALLBACK FilterSearchTimerFunc( HWND hwnd, UINT, UINT_PTR, DWORD )
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLongPtr( hwnd, GWLP_USERDATA );
+ if ( !dat )
+ return;
+
+ if ( hFilterSearchWnd == NULL)
+ hFilterSearchWnd = CreateWindowA( "STATIC", "Test", WS_OVERLAPPED|WS_DISABLED, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), 0 ); // Fake window to keep option page focused
+
+ if ( FilterPage < dat->pageCount )
+ FindFilterStrings( TRUE, dat->currentPage == FilterPage, hFilterSearchWnd, &( dat->opd[FilterPage]) );
+
+ FilterPage++;
+ FilterLoadProgress = FilterPage*100/( (dat->pageCount) ? dat->pageCount : FilterPage );
+ if ( FilterPage >= dat->pageCount )
+ {
+ KillTimer( hwnd, FilterTimerId );
+ FilterTimerId = 0;
+ bSearchState = 2;
+ FilterLoadProgress = 100;
+ DestroyWindow( hFilterSearchWnd );
+ hFilterSearchWnd = NULL;
+ }
+ RedrawWindow( GetDlgItem(hwnd, IDC_KEYWORD_FILTER ), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
+}
+
+static void ExecuteFindFilterStringsTimer( HWND hdlg )
+{
+ bSearchState = 1;
+ FilterPage = 0;
+ if (FilterTimerId) KillTimer( hdlg, FilterTimerId );
+ FilterTimerId = SetTimer( hdlg, NULL, 1, FilterSearchTimerFunc );
+}
+
+static void FillFilterCombo(int enableKeywordFiltering, HWND hDlg, struct OptionsPageData * opd, int PageCount)
+{
+ int i;
+ int index;
+ HINSTANCE* KnownInstances = ( HINSTANCE* )alloca(sizeof(HINSTANCE)*PageCount);
+ int countKnownInst = 0;
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_RESETCONTENT, 0,0);
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)TranslateTS(ALL_MODULES_FILTER));
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)NULL);
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)TranslateTS(CORE_MODULES_FILTER));
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)hMirandaInst);
+ TCHAR* tszModuleName = ( TCHAR* )alloca(MAX_PATH*sizeof(TCHAR));
+ for (i=0; i<PageCount; i++) {
+ TCHAR * dllName = NULL;
+ int j;
+ HINSTANCE inst=opd[i].hInst;
+
+ if ( !enableKeywordFiltering )
+ FindFilterStrings( enableKeywordFiltering, FALSE, hDlg, &opd[i]); // only modules name ( fast enougth )
+
+ if (inst==hMirandaInst) continue;
+ for (j=0; j<countKnownInst; j++)
+ if (KnownInstances[j]==inst) break;
+ if (j!=countKnownInst) continue;
+ KnownInstances[countKnownInst]=inst;
+ countKnownInst++;
+ GetModuleFileName(inst, tszModuleName, MAX_PATH);
+ {
+ char * name = GetPluginNameByInstance( inst );
+ if ( name )
+ dllName = mir_a2t( name );
+ }
+
+ if (!dllName) dllName = mir_tstrdup( _tcsrchr(tszModuleName,_T('\\')) );
+ if (!dllName) dllName = mir_tstrdup( tszModuleName );
+
+ if (dllName) {
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)dllName);
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)inst);
+ mir_free( dllName );
+ }
+ }
+
+ FilterLoadProgress = 100;
+ if ( enableKeywordFiltering)
+ ExecuteFindFilterStringsTimer( hDlg );
+}
+
+static BOOL IsInsideTab( HWND hdlg, OptionsDlgData * dat, int i )
+{
+ int pages = 0;
+ if (dat->opd[i].pszTab != NULL)
+ {
+ // Count tabs to calc position
+ for (int j=0; j < dat->pageCount && pages < 2; j++ )
+ {
+ if (!CheckPageShow( hdlg, dat, j ) ) continue;
+ //if (( dat->opd[j].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ //if (( dat->opd[j].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if ( lstrcmp(dat->opd[j].pszTitle, dat->opd[i].pszTitle) || lstrcmpnull(dat->opd[j].pszGroup, dat->opd[i].pszGroup) ) continue;
+ pages++;
+ }
+ }
+ return (pages > 1);
+}
+
+static INT_PTR CALLBACK OptionsDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLongPtr( hdlg, GWLP_USERDATA );
+ HWND hwndTree = GetDlgItem(hdlg, IDC_PAGETREE);
+
+ switch ( message ) {
+ case WM_CTLCOLORSTATIC:
+ switch ( GetDlgCtrlID(( HWND )lParam ))
+ {
+ case IDC_WHITERECT:
+ case IDC_KEYWORD_FILTER:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW ));
+ return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW );
+ }
+ break;
+
+ case WM_INITDIALOG:
+ {
+ PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)psh->pStartPage;
+ OPTIONSDIALOGPAGE *odp;
+ int i;
+ struct DlgTemplateExBegin *dte;
+ TCHAR *lastPage = NULL, *lastGroup = NULL, *lastTab = NULL;
+ DBVARIANT dbv;
+ TCITEM tie;
+ LOGFONT lf;
+
+ typedef BOOL (STDAPICALLTYPE *pfnGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
+ pfnGetComboBoxInfo getComboBoxInfo = (pfnGetComboBoxInfo)GetProcAddress(GetModuleHandleA("user32"), "GetComboBoxInfo");
+ if (getComboBoxInfo) {
+ COMBOBOXINFO cbi;
+ cbi.cbSize = sizeof(COMBOBOXINFO);
+ getComboBoxInfo(GetDlgItem( hdlg, IDC_KEYWORD_FILTER), &cbi);
+ OptionsFilterDefaultProc = (WNDPROC)SetWindowLongPtr( cbi.hwndItem, GWLP_WNDPROC, (LONG_PTR) OptionsFilterSubclassProc );
+
+ if (IsAeroMode()) {
+ SetWindowLongPtr(cbi.hwndCombo, GWLP_USERDATA, GetWindowLongPtr(cbi.hwndCombo, GWLP_WNDPROC));
+ SetWindowLongPtr(cbi.hwndCombo, GWLP_WNDPROC, (LONG_PTR)AeroPaintSubclassProc);
+ SetWindowLongPtr(cbi.hwndItem, GWLP_USERDATA, GetWindowLongPtr(cbi.hwndItem, GWLP_WNDPROC));
+ SetWindowLongPtr(cbi.hwndItem, GWLP_WNDPROC, (LONG_PTR)AeroPaintSubclassProc);
+ } }
+
+ Utils_RestoreWindowPositionNoSize(hdlg, NULL, "Options", "");
+ TranslateDialogDefault(hdlg);
+ Window_SetIcon_IcoLib(hdlg, SKINICON_OTHER_OPTIONS);
+ CheckDlgButton(hdlg,IDC_EXPERT,DBGetContactSettingByte(NULL,"Options","Expert",SETTING_SHOWEXPERT_DEFAULT)?BST_CHECKED:BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ dat=(struct OptionsDlgData*)mir_alloc(sizeof(struct OptionsDlgData));
+ SetWindowLongPtr(hdlg,GWLP_USERDATA,(LONG_PTR)dat);
+ SetWindowText(hdlg,psh->pszCaption);
+
+ dat->hBoldFont=(HFONT)SendDlgItemMessage(hdlg,IDC_EXPERT,WM_GETFONT,0,0);
+ GetObject(dat->hBoldFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+
+ dat->pageCount = psh->nPages;
+ dat->opd = ( struct OptionsPageData* )mir_alloc( sizeof(struct OptionsPageData) * dat->pageCount );
+ odp = ( OPTIONSDIALOGPAGE* )psh->ppsp;
+
+ dat->currentPage = -1;
+ if ( ood->pszPage == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastPage", &dbv )) {
+ lastPage = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+
+ if ( ood->pszGroup == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastGroup", &dbv )) {
+ lastGroup = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastGroup = LangPackPcharToTchar( ood->pszGroup );
+ }
+ else
+ {
+ lastPage = LangPackPcharToTchar( ood->pszPage );
+ lastGroup = ( ood->pszGroup == NULL ) ? NULL : LangPackPcharToTchar( ood->pszGroup );
+ }
+
+ if ( ood->pszTab == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastTab", &dbv )) {
+ lastTab = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastTab = LangPackPcharToTchar( ood->pszTab );
+
+ for ( i=0; i < dat->pageCount; i++, odp++ ) {
+ struct OptionsPageData* opd = &dat->opd[i];
+ HRSRC hrsrc=FindResourceA(odp->hInstance,odp->pszTemplate,MAKEINTRESOURCEA(5));
+ HGLOBAL hglb=LoadResource(odp->hInstance,hrsrc);
+ DWORD resSize=SizeofResource(odp->hInstance,hrsrc);
+ opd->pTemplate = ( DLGTEMPLATE* )mir_alloc(resSize);
+ memcpy(opd->pTemplate,LockResource(hglb),resSize);
+ dte=(struct DlgTemplateExBegin*)opd->pTemplate;
+ if ( dte->signature == 0xFFFF ) {
+ //this feels like an access violation, and is according to boundschecker
+ //...but it works - for now
+ //may well have to remove and sort out the original dialogs
+ dte->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dte->style|=WS_CHILD;
+ }
+ else {
+ opd->pTemplate->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ opd->pTemplate->style|=WS_CHILD;
+ }
+ opd->dlgProc=odp->pfnDlgProc;
+ opd->hInst=odp->hInstance;
+ opd->hwnd=NULL;
+ opd->changed=0;
+ opd->simpleHeight=opd->expertHeight=0;
+ opd->simpleBottomControlId=odp->nIDBottomSimpleControl;
+ opd->simpleWidth=opd->expertWidth=0;
+ opd->simpleRightControlId=odp->nIDRightSimpleControl;
+ opd->nExpertOnlyControls=odp->nExpertOnlyControls;
+ opd->expertOnlyControls=odp->expertOnlyControls;
+ opd->flags=odp->flags;
+ opd->dwInitParam=odp->dwInitParam;
+ if ( odp->pszTitle == NULL )
+ opd->pszTitle = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszTitle = ( TCHAR* )mir_wstrdup( odp->ptszTitle );
+ #else
+ opd->pszTitle = mir_u2a(( WCHAR* )odp->ptszTitle );
+ #endif
+ }
+ else opd->pszTitle = ( TCHAR* )mir_strdup( odp->pszTitle );
+
+ if ( odp->pszGroup == NULL )
+ opd->pszGroup = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszGroup = ( TCHAR* )mir_wstrdup( odp->ptszGroup );
+ #else
+ opd->pszGroup = mir_u2a(( WCHAR* )odp->ptszGroup );
+ #endif
+ }
+ else opd->pszGroup = ( TCHAR* )mir_strdup( odp->pszGroup );
+
+ if ( odp->pszTab == NULL )
+ opd->pszTab = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszTab = ( TCHAR* )mir_wstrdup( odp->ptszTab );
+ #else
+ opd->pszTab = mir_u2a(( WCHAR* )odp->ptszTab );
+ #endif
+ }
+ else opd->pszTab = ( TCHAR* )mir_strdup( odp->pszTab );
+
+ if ( !lstrcmp( lastPage, odp->ptszTitle ) &&
+ !lstrcmpnull( lastGroup, odp->ptszGroup ) &&
+ (( ood->pszTab == NULL && dat->currentPage == -1 ) || !lstrcmpnull( lastTab, odp->ptszTab )))
+ dat->currentPage = i;
+ }
+ mir_free( lastGroup );
+ mir_free( lastPage );
+ mir_free( lastTab );
+
+ GetWindowRect(GetDlgItem(hdlg,IDC_STNOPAGE),&dat->rcDisplay);
+ MapWindowPoints(NULL, hdlg, (LPPOINT)&dat->rcDisplay, 2);
+
+ // Add an item to count in height
+ tie.mask = TCIF_TEXT | TCIF_IMAGE;
+ tie.iImage = -1;
+ tie.pszText = _T("X");
+ TabCtrl_InsertItem(GetDlgItem(hdlg,IDC_TAB), 0, &tie);
+
+ GetWindowRect(GetDlgItem(hdlg,IDC_TAB), &dat->rcTab);
+ MapWindowPoints(NULL, hdlg, (LPPOINT)&dat->rcTab, 2);
+ TabCtrl_AdjustRect(GetDlgItem(hdlg,IDC_TAB), FALSE, &dat->rcTab);
+
+ //!!!!!!!!!! int enableKeywordFiltering = DBGetContactSettingWord(NULL, "Options", "EnableKeywordFiltering", TRUE);
+ FillFilterCombo( 0, //!!!!!!!!!! enableKeywordFiltering,
+ hdlg, dat->opd, dat->pageCount);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+
+ return TRUE;
+ }
+ case DM_REBUILDPAGETREE:
+ {
+ int i;
+ TVINSERTSTRUCT tvis;
+ TVITEMA tvi;
+ BOOL bRemoveFocusFromFilter = FALSE;
+ char str[128],buf[130];
+
+ HINSTANCE FilterInst=NULL;
+
+ LPARAM oldSel = SendDlgItemMessage(hdlg, IDC_KEYWORD_FILTER, CB_GETEDITSEL, 0, 0);
+
+ GetDlgItemText(hdlg, IDC_KEYWORD_FILTER, dat->szFilterString, SIZEOF(dat->szFilterString));
+
+ //if filter string is set to all modules then make the filter string empty (this will return all modules)
+ if (_tcscmp(dat->szFilterString, TranslateTS( ALL_MODULES_FILTER ) ) == 0) {
+ dat->szFilterString[0] = 0;
+ bRemoveFocusFromFilter = TRUE;
+ }
+ //if filter string is set to core modules replace it with the name of the executable (this will return all core modules)
+ else if (_tcscmp(dat->szFilterString, TranslateTS( CORE_MODULES_FILTER) ) == 0) {
+ //replace string with process name - that will show core settings
+ TCHAR szFileName[300];
+ GetModuleFileName(NULL, szFileName, SIZEOF(szFileName));
+ TCHAR *pos = _tcsrchr(szFileName, _T('\\'));
+ if (pos)
+ pos++;
+ else
+ pos = szFileName;
+
+ _tcsncpy(dat->szFilterString, pos, SIZEOF(dat->szFilterString));
+ }
+ else {
+ int sel = SendMessage( GetDlgItem(hdlg, IDC_KEYWORD_FILTER ), (UINT) CB_GETCURSEL, 0,0 );
+ if (sel != -1) {
+ HINSTANCE hinst = (HINSTANCE)SendMessage( GetDlgItem(hdlg, IDC_KEYWORD_FILTER ), (UINT) CB_GETITEMDATA, sel ,0 );
+ TCHAR szFileName[300];
+ GetModuleFileName(hinst, szFileName, SIZEOF(szFileName));
+ TCHAR *pos = _tcsrchr(szFileName, _T('\\'));
+ if (pos) pos++;
+ else pos = szFileName;
+ _tcsncpy(dat->szFilterString, pos, SIZEOF(dat->szFilterString));
+ } }
+
+ _tcslwr_locale(dat->szFilterString); //all strings are stored as lowercase ... make sure filter string is lowercase too
+
+ ShowWindow(hwndTree, SW_HIDE); //deleteall is annoyingly visible
+
+ HWND oldWnd = NULL;
+ HWND oldTab = NULL;
+ if ( dat->currentPage != (-1)) {
+ oldWnd = dat->opd[dat->currentPage].hwnd;
+ if ( dat->opd[dat->currentPage].insideTab )
+ oldTab = GetDlgItem( hdlg,IDC_TAB );
+ }
+
+ dat->hCurrentPage = NULL;
+
+ TreeView_SelectItem(hwndTree, NULL);
+
+ TreeView_DeleteAllItems(hwndTree);
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ static TCHAR *fullTitle=NULL;
+ TCHAR * useTitle;
+ if (fullTitle) mir_free(fullTitle);
+ fullTitle=NULL;
+ if (! CheckPageShow( hdlg, dat, i ) ) continue;
+ tvis.hParent = NULL;
+ if ( FilterInst!=NULL ) {
+ size_t sz=dat->opd[i].pszGroup?_tcslen(dat->opd[i].pszGroup)+1:0;
+ if (sz) sz+=3;
+ sz+=dat->opd[i].pszTitle?_tcslen(dat->opd[i].pszTitle)+1:0;
+ fullTitle = ( TCHAR* )mir_alloc(sz*sizeof(TCHAR));
+ mir_sntprintf(fullTitle,sz,(dat->opd[i].pszGroup && dat->opd[i].pszTitle)?_T("%s - %s"):_T("%s%s"),dat->opd[i].pszGroup?dat->opd[i].pszGroup:_T(""),dat->opd[i].pszTitle?dat->opd[i].pszTitle:_T("") );
+ }
+ useTitle=fullTitle?fullTitle:dat->opd[i].pszTitle;
+ if(dat->opd[i].pszGroup != NULL && FilterInst==NULL) {
+ tvis.hParent = FindNamedTreeItemAtRoot(hwndTree, dat->opd[i].pszGroup);
+ if(tvis.hParent == NULL) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = dat->opd[i].pszGroup;
+ tvis.hParent = TreeView_InsertItem(hwndTree, &tvis);
+ }
+ }
+ else {
+ TVITEM tvi;
+ tvi.hItem = FindNamedTreeItemAtRoot(hwndTree,useTitle);
+ if( tvi.hItem != NULL ) {
+ if ( i == dat->currentPage ) dat->hCurrentPage=tvi.hItem;
+ tvi.mask = TVIF_PARAM;
+ TreeView_GetItem(hwndTree,&tvi);
+ if ( tvi.lParam == -1 ) {
+ tvi.lParam = i;
+ TreeView_SetItem(hwndTree,&tvi);
+ continue;
+ } } }
+
+ if ( dat->opd[i].pszTab != NULL ) {
+ HTREEITEM hItem;
+ if (tvis.hParent == NULL)
+ hItem = FindNamedTreeItemAtRoot(hwndTree,useTitle);
+ else
+ hItem = FindNamedTreeItemAtChildren(hwndTree,tvis.hParent,useTitle);
+ if( hItem != NULL ) {
+ if ( i == dat->currentPage ) {
+ TVITEM tvi;
+ tvi.hItem=hItem;
+ tvi.mask=TVIF_PARAM;
+ tvi.lParam=dat->currentPage;
+ TreeView_SetItem(hwndTree,&tvi);
+ dat->hCurrentPage=hItem;
+ }
+ continue;
+ }
+ }
+
+ tvis.item.pszText = useTitle;
+ tvis.item.lParam = i;
+ dat->opd[i].hTreeItem = TreeView_InsertItem(hwndTree, &tvis);
+ if ( i == dat->currentPage )
+ dat->hCurrentPage = dat->opd[i].hTreeItem;
+
+ if (fullTitle) mir_free(fullTitle);
+ fullTitle=NULL;
+ }
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( hwndTree, TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ mir_snprintf(buf, SIZEOF(buf), "%s%s",OPTSTATE_PREFIX,str);
+ if ( !DBGetContactSettingByte( NULL, "Options", buf, 1 ))
+ TreeView_Expand( hwndTree, tvi.hItem, TVE_COLLAPSE );
+ }
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ if(dat->hCurrentPage==NULL) {
+ dat->hCurrentPage=TreeView_GetRoot(hwndTree);
+ dat->currentPage=-1;
+ }
+ TreeView_SelectItem(hwndTree,dat->hCurrentPage);
+
+ if ( oldWnd ) {
+ if ( dat->currentPage == (-1) || oldWnd != dat->opd[dat->currentPage].hwnd ) {
+ ShowWindow( oldWnd, SW_HIDE);
+ if ( oldTab && ( dat->currentPage ==-1 || !dat->opd[dat->currentPage].insideTab ) )
+ ShowWindow( oldTab, SW_HIDE );
+ }
+ }
+
+ if ( dat->szFilterString[0] == 0 ) // Clear the keyword combo box
+ SetWindowText( GetDlgItem(hdlg, IDC_KEYWORD_FILTER), _T("") );
+ if ( !bRemoveFocusFromFilter )
+ SetFocus(GetDlgItem(hdlg, IDC_KEYWORD_FILTER)); //set the focus back to the combo box
+
+ SendDlgItemMessage(hdlg, IDC_KEYWORD_FILTER, CB_SETEDITSEL, 0, oldSel ); //but don't select any of the text
+
+ ShowWindow(hwndTree,SW_SHOW);
+ }
+ break;
+
+ case PSM_CHANGED:
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),TRUE);
+ if(dat->currentPage != (-1)) dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+
+ case PSM_ISEXPERT:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,IsDlgButtonChecked(hdlg,IDC_EXPERT));
+ return TRUE;
+
+ case PSM_GETBOLDFONT:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,(LONG_PTR)dat->hBoldFont);
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TAB:
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_ITEMEXPANDING:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,FALSE);
+ return TRUE;
+ case TCN_SELCHANGING:
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TCN_SELCHANGE:
+ case TVN_SELCHANGED:
+ { BOOL tabChange = (wParam == IDC_TAB);
+ ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_HIDE);
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ if (!tabChange) {
+ TVITEM tvi;
+ tvi.hItem=dat->hCurrentPage=TreeView_GetSelection(hwndTree);
+ if(tvi.hItem==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(hwndTree,&tvi);
+ dat->currentPage=tvi.lParam;
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_HIDE);
+ }
+ else {
+ TCITEM tie;
+ TVITEM tvi;
+
+ tie.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hdlg,IDC_TAB),TabCtrl_GetCurSel(GetDlgItem(hdlg,IDC_TAB)),&tie);
+ dat->currentPage=tie.lParam;
+
+ tvi.hItem=dat->hCurrentPage;
+ tvi.mask=TVIF_PARAM;
+ tvi.lParam=dat->currentPage;
+ TreeView_SetItem(hwndTree,&tvi);
+ }
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].hwnd == NULL ) {
+ RECT rcPage;
+ RECT rcControl,rc;
+ int w,h;
+
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParamA(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hdlg,dat->opd[dat->currentPage].dlgProc,dat->opd[dat->currentPage].dwInitParam);
+ if(dat->opd[dat->currentPage].flags&ODPF_BOLDGROUPS)
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,BoldGroupTitlesEnumChildren,(LPARAM)dat->hBoldFont);
+ GetClientRect(dat->opd[dat->currentPage].hwnd,&rcPage);
+ dat->opd[dat->currentPage].expertWidth=rcPage.right;
+ dat->opd[dat->currentPage].expertHeight=rcPage.bottom;
+ GetWindowRect(dat->opd[dat->currentPage].hwnd,&rc);
+
+ if(dat->opd[dat->currentPage].simpleBottomControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleBottomControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleHeight=rcControl.bottom-rc.top;
+ }
+ else dat->opd[dat->currentPage].simpleHeight=dat->opd[dat->currentPage].expertHeight;
+
+ if(dat->opd[dat->currentPage].simpleRightControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleRightControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleWidth=rcControl.right-rc.left;
+ }
+ else dat->opd[dat->currentPage].simpleWidth=dat->opd[dat->currentPage].expertWidth;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ w=dat->opd[dat->currentPage].expertWidth;
+ h=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ int i;
+ for(i=0;i<dat->opd[dat->currentPage].nExpertOnlyControls;i++)
+ ShowWindow(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].expertOnlyControls[i]),SW_HIDE);
+ w=dat->opd[dat->currentPage].simpleWidth;
+ h=dat->opd[dat->currentPage].simpleHeight;
+ }
+
+ dat->opd[dat->currentPage].offsetX = 0;
+ dat->opd[dat->currentPage].offsetY = 0;
+
+ dat->opd[dat->currentPage].insideTab = IsInsideTab( hdlg, dat, dat->currentPage );
+ if (dat->opd[dat->currentPage].insideTab) {
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcTab.left+dat->rcTab.right-w)>>1,dat->rcTab.top,w,h,0);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,TRUE);
+ } else {
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-w)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-h)>>1,w,h,0);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,FALSE);
+ }
+ }
+ if ( !tabChange )
+ {
+ dat->opd[ dat->currentPage].insideTab = IsInsideTab( hdlg, dat, dat->currentPage );
+ if ( dat->opd[dat->currentPage].insideTab ) {
+ // Make tabbed pane
+ int i,pages=0,sel=0;
+ TCITEM tie;
+ HWND hwndTab = GetDlgItem(hdlg,IDC_TAB);
+
+ TabCtrl_DeleteAllItems(hwndTab);
+ tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ tie.iImage = -1;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if (!CheckPageShow( hdlg, dat, i ) ) continue;
+ //if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ //if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if ( lstrcmp(dat->opd[i].pszTitle, dat->opd[dat->currentPage].pszTitle) || lstrcmpnull(dat->opd[i].pszGroup, dat->opd[dat->currentPage].pszGroup) ) continue;
+
+ tie.pszText = dat->opd[i].pszTab;
+ tie.lParam = i;
+ TabCtrl_InsertItem(hwndTab, pages, &tie);
+ if ( !lstrcmp(dat->opd[i].pszTab,dat->opd[dat->currentPage].pszTab) )
+ sel = pages;
+ pages++;
+ }
+ TabCtrl_SetCurSel(hwndTab,sel);
+ ShowWindow(hwndTab, dat->opd[dat->currentPage].insideTab ? SW_SHOW : SW_HIDE );
+ }
+
+ if (dat->opd[dat->currentPage].insideTab)
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,TRUE);
+ else
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,FALSE);
+ }
+
+ // Resizing
+ if (!dat->opd[dat->currentPage].simpleBottomControlId)
+ {
+ int pageWidth, pageHeight;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ pageWidth=dat->opd[dat->currentPage].expertWidth;
+ pageHeight=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ pageWidth=dat->opd[dat->currentPage].simpleWidth;
+ pageHeight=dat->opd[dat->currentPage].simpleHeight;
+ }
+
+ RECT * parentPageRect = &dat->rcDisplay;
+
+ if ( dat->opd[dat->currentPage].insideTab )
+ parentPageRect = &dat->rcTab;
+
+ pageHeight = min( pageHeight, parentPageRect->bottom - parentPageRect->top );
+ pageWidth = min( pageWidth, parentPageRect->right - parentPageRect->left );
+
+ int newOffsetX = ( parentPageRect->right - parentPageRect->left - pageWidth ) >> 1;
+ int newOffsetY = dat->opd[dat->currentPage].insideTab ? 0 : ( parentPageRect->bottom - parentPageRect->top - pageHeight ) >> 1;
+
+ struct MoveChildParam mcp;
+ mcp.hDlg = dat->opd[dat->currentPage].hwnd;
+ mcp.offset.x = newOffsetX - dat->opd[dat->currentPage].offsetX;
+ mcp.offset.y = newOffsetY - dat->opd[dat->currentPage].offsetY;
+
+
+ if ( mcp.offset.x || mcp.offset.y )
+ {
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,MoveEnumChildren,(LPARAM)(&mcp));
+
+ SetWindowPos( dat->opd[dat->currentPage].hwnd, NULL,
+ parentPageRect->left, parentPageRect->top,
+ parentPageRect->right - parentPageRect->left,
+ parentPageRect->bottom - parentPageRect->top,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ dat->opd[dat->currentPage].offsetX = newOffsetX;
+ dat->opd[dat->currentPage].offsetY = newOffsetY;
+ }
+
+ }
+
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ if(((LPNMTREEVIEW)lParam)->action==TVC_BYMOUSE) PostMessage(hdlg,DM_FOCUSPAGE,0,0);
+ else SetFocus(hwndTree);
+ }
+ else ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_SHOW);
+ break;
+ } } }
+ break;
+
+ case DM_FOCUSPAGE:
+ if (dat->currentPage != -1)
+ SetFocus(dat->opd[dat->currentPage].hwnd);
+ break;
+
+ case WM_TIMER:
+ if (wParam == FILTER_TIMEOUT_TIMER) {
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+
+ KillTimer(hdlg, FILTER_TIMEOUT_TIMER);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_KEYWORD_FILTER:
+ //add a timer - when the timer elapses filter the option pages
+ if ( (HIWORD(wParam)==CBN_SELCHANGE) || (HIWORD(wParam) == CBN_EDITCHANGE))
+ if (!SetTimer(hdlg, FILTER_TIMEOUT_TIMER, 400, NULL))
+ MessageBeep(MB_ICONSTOP);
+
+ break;
+
+ case IDC_EXPERT:
+ {
+ int expert=IsDlgButtonChecked(hdlg,IDC_EXPERT);
+ int i,j;
+ PSHNOTIFY pshn;
+ RECT rcPage;
+ int neww,newh;
+
+ DBWriteContactSettingByte(NULL,"Options","Expert",(BYTE)expert);
+ pshn.hdr.idFrom=0;
+ pshn.lParam=expert;
+ pshn.hdr.code=PSN_EXPERTCHANGED;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL) continue;
+ if (!CheckPageShow( hdlg, dat, i ) ) continue;
+ //if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && expert) continue;
+ //if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !expert) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+
+ for(j=0;j<dat->opd[i].nExpertOnlyControls;j++)
+ ShowWindow(GetDlgItem(dat->opd[i].hwnd,dat->opd[i].expertOnlyControls[j]),expert?SW_SHOW:SW_HIDE);
+
+ dat->opd[i].insideTab = IsInsideTab( hdlg, dat, i );
+
+ GetWindowRect(dat->opd[i].hwnd,&rcPage);
+ if(dat->opd[i].simpleBottomControlId) newh=expert?dat->opd[i].expertHeight:dat->opd[i].simpleHeight;
+ else newh=rcPage.bottom-rcPage.top;
+ if(dat->opd[i].simpleRightControlId) neww=expert?dat->opd[i].expertWidth:dat->opd[i].simpleWidth;
+ else neww=rcPage.right-rcPage.left;
+ if(i==dat->currentPage) {
+ POINT ptStart,ptEnd,ptNow;
+ DWORD thisTick,startTick;
+ RECT rc;
+
+ ptNow.x=ptNow.y=0;
+ ClientToScreen(hdlg,&ptNow);
+ GetWindowRect(dat->opd[i].hwnd,&rc);
+ ptStart.x=rc.left-ptNow.x;
+ ptStart.y=rc.top-ptNow.y;
+ if (dat->opd[i].insideTab) {
+ ptEnd.x=(dat->rcTab.left+dat->rcTab.right-neww)>>1;
+ ptEnd.y=dat->rcTab.top;
+ } else {
+ ptEnd.x=(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1;
+ ptEnd.y=(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1;
+ }
+ if(abs(ptEnd.x-ptStart.x)>5 || abs(ptEnd.y-ptStart.y)>5) {
+ startTick=GetTickCount();
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,0,0,min(neww,rcPage.right),min(newh,rcPage.bottom),SWP_NOMOVE);
+ UpdateWindow(dat->opd[i].hwnd);
+ for(;;) {
+ thisTick=GetTickCount();
+ if(thisTick>startTick+100) break;
+ ptNow.x=ptStart.x+(ptEnd.x-ptStart.x)*(int)(thisTick-startTick)/100;
+ ptNow.y=ptStart.y+(ptEnd.y-ptStart.y)*(int)(thisTick-startTick)/100;
+ SetWindowPos(dat->opd[i].hwnd,0,ptNow.x,ptNow.y,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ }
+ if (dat->opd[i].insideTab)
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_SHOW);
+ else
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_HIDE);
+ }
+
+ if (dat->opd[i].insideTab) {
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcTab.left+dat->rcTab.right-neww)>>1,dat->rcTab.top,neww,newh,0);
+ ThemeDialogBackground(dat->opd[i].hwnd,TRUE);
+ } else {
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1,neww,newh,0);
+ ThemeDialogBackground(dat->opd[i].hwnd,FALSE);
+ }
+ }
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ break;
+ }
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hdlg);
+ break;
+ }
+ case IDOK:
+ case IDC_APPLY:
+ {
+ int i;
+ PSHNOTIFY pshn;
+
+ if (LOWORD(wParam) == IDOK && GetParent(GetFocus()) == GetDlgItem(hdlg, IDC_KEYWORD_FILTER))
+ return TRUE;
+
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ SetFocus(hwndTree);
+ if(dat->currentPage!=(-1)) {
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ dat->opd[i].changed=0;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ dat->hCurrentPage=dat->opd[i].hTreeItem;
+ TreeView_SelectItem(hwndTree,dat->hCurrentPage);
+ if(dat->currentPage!=(-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ if (dat->currentPage != (-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ } }
+
+ if ( LOWORD( wParam ) == IDOK )
+ DestroyWindow(hdlg);
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( FilterTimerId ) KillTimer ( hdlg, FilterTimerId );
+ DestroyWindow ( hFilterSearchWnd );
+ ClearFilterStrings();
+ dat->szFilterString[0]=0;
+
+ SaveOptionsTreeState( hdlg );
+ Window_FreeIcon_IcoLib( hdlg );
+
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].pszTab )
+ DBWriteContactSettingTString( NULL, "Options", "LastTab", dat->opd[dat->currentPage].pszTab );
+ else DBDeleteContactSetting( NULL, "Options", "LastTab" );
+ if ( dat->opd[dat->currentPage].pszGroup )
+ DBWriteContactSettingTString( NULL, "Options", "LastGroup", dat->opd[dat->currentPage].pszGroup );
+ else DBDeleteContactSetting( NULL, "Options", "LastGroup" );
+ DBWriteContactSettingTString( NULL, "Options", "LastPage", dat->opd[dat->currentPage].pszTitle );
+ }
+ else {
+ DBDeleteContactSetting(NULL,"Options","LastTab");
+ DBDeleteContactSetting(NULL,"Options","LastGroup");
+ DBDeleteContactSetting(NULL,"Options","LastPage");
+ }
+ Utils_SaveWindowPosition(hdlg, NULL, "Options", "");
+ {
+ int i;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if ( dat->opd[i].hwnd != NULL )
+ DestroyWindow(dat->opd[i].hwnd);
+ mir_free(dat->opd[i].pszGroup);
+ mir_free(dat->opd[i].pszTab);
+ mir_free(dat->opd[i].pszTitle);
+ mir_free(dat->opd[i].pTemplate);
+ } }
+ mir_free( dat->opd );
+ DeleteObject( dat->hBoldFont );
+ mir_free( dat );
+ hwndOptions = NULL;
+
+ CallService(MS_MODERNOPT_RESTORE, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+static void FreeOptionsData( struct OptionsPageInit* popi )
+{
+ int i;
+ for ( i=0; i < popi->pageCount; i++ ) {
+ mir_free(( char* )popi->odp[i].pszTitle );
+ mir_free( popi->odp[i].pszGroup );
+ mir_free( popi->odp[i].pszTab );
+ if (( DWORD_PTR )popi->odp[i].pszTemplate & 0xFFFF0000 )
+ mir_free((char*)popi->odp[i].pszTemplate);
+ }
+ mir_free(popi->odp);
+}
+
+void OpenAccountOptions( PROTOACCOUNT* pa )
+{
+ struct OptionsPageInit opi = { 0 };
+ if ( pa->ppro == NULL )
+ return;
+
+ pa->ppro->OnEvent( EV_PROTO_ONOPTIONS, ( WPARAM )&opi, 0 );
+ if ( opi.pageCount > 0 ) {
+ TCHAR tszTitle[ 100 ];
+ OPENOPTIONSDIALOG ood = { 0 };
+ PROPSHEETHEADER psh = { 0 };
+
+ mir_sntprintf( tszTitle, SIZEOF(tszTitle), TranslateT("%s options"), pa->tszAccountName );
+
+ ood.cbSize = sizeof(ood);
+ ood.pszGroup = LPGEN("Network");
+ ood.pszPage = mir_t2a( pa->tszAccountName );
+
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = (LPCTSTR)&ood;
+ psh.pszCaption = tszTitle;
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp;
+ hwndOptions = CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_OPTIONSPAGE),NULL,OptionsDlgProc,(LPARAM)&psh);
+ mir_free(( void* )ood.pszPage );
+ FreeOptionsData( &opi );
+} }
+
+static void OpenOptionsNow(const char *pszGroup,const char *pszPage,const char *pszTab, bool bSinglePage=false)
+{
+ if ( IsWindow( hwndOptions )) {
+ ShowWindow( hwndOptions, SW_RESTORE );
+ SetForegroundWindow( hwndOptions );
+ if ( pszPage != NULL) {
+ TCHAR *ptszPage = LangPackPcharToTchar(pszPage);
+ HTREEITEM hItem = NULL;
+ if (pszGroup != NULL) {
+ TCHAR *ptszGroup = LangPackPcharToTchar(pszGroup);
+ hItem = FindNamedTreeItemAtRoot(GetDlgItem(hwndOptions,IDC_PAGETREE),ptszGroup);
+ if (hItem != NULL) {
+ hItem = FindNamedTreeItemAtChildren(GetDlgItem(hwndOptions,IDC_PAGETREE),hItem,ptszPage);
+ }
+ mir_free(ptszGroup);
+ } else {
+ hItem = FindNamedTreeItemAtRoot(GetDlgItem(hwndOptions,IDC_PAGETREE),ptszPage);
+ }
+ if (hItem != NULL) {
+ TreeView_SelectItem(GetDlgItem(hwndOptions,IDC_PAGETREE),hItem);
+ }
+ mir_free(ptszPage);
+ }
+ } else {
+ struct OptionsPageInit opi = { 0 };
+ NotifyEventHooks( hOptionsInitEvent, ( WPARAM )&opi, 0 );
+ if ( opi.pageCount > 0 ) {
+ OPENOPTIONSDIALOG ood = { 0 };
+ PROPSHEETHEADER psh = { 0 };
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
+ psh.nPages = opi.pageCount;
+ ood.pszGroup = pszGroup;
+ ood.pszPage = pszPage;
+ ood.pszTab = pszTab;
+ psh.pStartPage = (LPCTSTR)&ood; //more structure misuse
+ psh.pszCaption = TranslateT("Miranda IM Options");
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+
+ hwndOptions = CreateDialogParam(hMirandaInst,
+ MAKEINTRESOURCE(bSinglePage ? IDD_OPTIONSPAGE : IDD_OPTIONS),
+ NULL, OptionsDlgProc, (LPARAM)&psh);
+
+ FreeOptionsData( &opi );
+} } }
+
+static INT_PTR OpenOptions(WPARAM, LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if ( ood == NULL )
+ return 1;
+
+ if ( ood->cbSize == OPENOPTIONSDIALOG_OLD_SIZE )
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, NULL );
+ else if (ood->cbSize == sizeof(OPENOPTIONSDIALOG))
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, ood->pszTab );
+ else
+ return 1;
+
+ return 0;
+}
+
+static INT_PTR OpenOptionsPage(WPARAM, LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if ( ood == NULL )
+ return 1;
+
+ if ( ood->cbSize == OPENOPTIONSDIALOG_OLD_SIZE )
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, NULL, true );
+ else if (ood->cbSize == sizeof(OPENOPTIONSDIALOG))
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, ood->pszTab, true );
+ else
+ return 1;
+
+ return (INT_PTR)hwndOptions;
+}
+
+static INT_PTR OpenOptionsDialog(WPARAM, LPARAM)
+{
+ if (hwndOptions || GetAsyncKeyState(VK_CONTROL) || !ServiceExists(MS_MODERNOPT_SHOW))
+ OpenOptionsNow(NULL,NULL,NULL);
+ else
+ CallService(MS_MODERNOPT_SHOW, 0, 0);
+ return 0;
+}
+
+static INT_PTR AddOptionsPage(WPARAM wParam,LPARAM lParam)
+{ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct OptionsPageInit *opi=(struct OptionsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE2
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE3)
+ return 1;
+
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ memset( dst, 0, sizeof( OPTIONSDIALOGPAGE ));
+ memcpy( dst, odp, odp->cbSize );
+
+ if ( odp->ptszTitle != NULL ) {
+ if ( odp->flags & ODPF_DONTTRANSLATE ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( odp->ptszTitle );
+ else {
+ dst->ptszTitle = mir_a2u( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( odp->pszTitle );
+ #endif
+ }
+ else {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( TranslateW( odp->ptszTitle ));
+ else {
+ dst->ptszTitle = LangPackPcharToTchar( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( Translate( odp->pszTitle ));
+ #endif
+ }
+ }
+
+ if ( odp->ptszGroup != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszGroup = mir_wstrdup( TranslateW( odp->ptszGroup ));
+ else {
+ dst->ptszGroup = LangPackPcharToTchar( odp->pszGroup );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszGroup = mir_strdup( Translate( odp->pszGroup ));
+ #endif
+ }
+
+ if ( odp->cbSize > OPTIONPAGE_OLD_SIZE2 && odp->ptszTab != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTab = mir_wstrdup( TranslateW( odp->ptszTab ));
+ else {
+ dst->ptszTab = LangPackPcharToTchar( odp->pszTab );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTab = mir_strdup( Translate( odp->pszTab ));
+ #endif
+ }
+
+ if (( DWORD_PTR )odp->pszTemplate & 0xFFFF0000 )
+ dst->pszTemplate = mir_strdup( odp->pszTemplate );
+
+ opi->pageCount++;
+ return 0;
+}
+
+static int OptModulesLoaded(WPARAM, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_OPTIONS );
+ mi.position = 1900000000;
+ mi.pszName = LPGEN("&Options...");
+ mi.pszService = "Options/OptionsCommand";
+ CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ return 0;
+}
+
+int ShutdownOptionsModule(WPARAM, LPARAM)
+{
+ if (IsWindow(hwndOptions)) DestroyWindow(hwndOptions);
+ hwndOptions=NULL;
+
+ //!!!!!!!!!! UnhookFilterEvents();
+
+ return 0;
+}
+
+int LoadOptionsModule(void)
+{
+ hwndOptions=NULL;
+ hOptionsInitEvent=CreateHookableEvent(ME_OPT_INITIALISE);
+ CreateServiceFunction(MS_OPT_ADDPAGE,AddOptionsPage);
+ CreateServiceFunction(MS_OPT_OPENOPTIONS,OpenOptions);
+ CreateServiceFunction(MS_OPT_OPENOPTIONSPAGE,OpenOptionsPage);
+ CreateServiceFunction("Options/OptionsCommand",OpenOptionsDialog);
+ HookEvent(ME_SYSTEM_MODULESLOADED,OptModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownOptionsModule);
+
+ //!!!!!!!!!! HookFilterEvents();
+ return 0;
+}