From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/options/descbutton.cpp | 332 ++++++++ src/modules/options/filter.cpp | 217 +++++ src/modules/options/filter.h | 108 +++ src/modules/options/headerbar.cpp | 372 +++++++++ src/modules/options/iconheader.cpp | 545 +++++++++++++ src/modules/options/options.cpp | 1521 ++++++++++++++++++++++++++++++++++++ 6 files changed, 3095 insertions(+) create mode 100644 src/modules/options/descbutton.cpp create mode 100644 src/modules/options/filter.cpp create mode 100644 src/modules/options/filter.h create mode 100644 src/modules/options/headerbar.cpp create mode 100644 src/modules/options/iconheader.cpp create mode 100644 src/modules/options/options.cpp (limited to 'src/modules/options') 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 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 +{ + CPageList(); +public: + CPageList( int aincr, FTSortFunc afunc = CPageKeywords::PageSortFunc ) : OBJLIST( 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 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 &pList, ItemDestuctor pItemDestructor) +{ + for (int i=0; irgbBkgBottom.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; ipList.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("") +#define CORE_MODULES_FILTER _T("") + +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; iopd[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;iopd[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;ipageCount;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;jopd[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;ipageCount;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;ipageCount;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; +} -- cgit v1.2.3