/* 'Language Pack Manager'-Plugin for Miranda IM Copyright (C) 2005-2007 H. Herkenrath 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 (LangMan-License.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "common.h" #include #include extern HINSTANCE hInst; static HANDLE hHookOptInit; /************************* Utils **************************************/ #define BOX(str) BOX2("%s (err:%i)",str,GetLastError()) #define BOX2(fmt,p1,p2) { char str[256]; wsprintfA(str,fmt,p1,p2); MessageBoxA(NULL,str,"dbg",0); } // ImageList_Destroy() the return value // refresh on WM_THEMECHANGED static HIMAGELIST CreateRadioImages(COLORREF clrBk,COLORREF clrText) { register HDC hdc,hdcScreen; SIZE size; RECT rc; HBITMAP hbm,hbmPrev; HIMAGELIST himl=NULL; /* the WinXP+ themed way */ HMODULE hUxThemeDLL; HTHEME (WINAPI *pfnOpenThemeData)(HWND,const WCHAR*); HTHEME (WINAPI *pfnCloseThemeData)(HTHEME); HRESULT (WINAPI *pfnDrawThemeBackground)(HTHEME,HDC,int,int,const RECT*,const RECT*); hUxThemeDLL=LoadLibraryA("UXTHEME"); /* all ascii */ /* draw bitmap */ hdcScreen=GetDC(NULL); if(hdcScreen!=NULL) { hdc=CreateCompatibleDC(NULL); /* compatible to screen */ if(hdc!=NULL) { size.cx=GetSystemMetrics(SM_CXSMICON); size.cy=GetSystemMetrics(SM_CYSMICON); SetRect(&rc,0,0,2*size.cx,size.cy); hbm=CreateCompatibleBitmap(hdcScreen,rc.right,rc.bottom); if(hbm!=NULL) { hbmPrev=SelectObject(hdc,hbm); if(hbmPrev!=NULL) { /* error on select? */ /* the WinXP+ themed way */ if(hUxThemeDLL!=NULL) { *(PROC*)&pfnOpenThemeData=GetProcAddress(hUxThemeDLL,"OpenThemeData"); *(PROC*)&pfnCloseThemeData=GetProcAddress(hUxThemeDLL,"CloseThemeData"); *(PROC*)&pfnDrawThemeBackground=GetProcAddress(hUxThemeDLL,"DrawThemeBackground"); if(pfnOpenThemeData!=NULL && pfnCloseThemeData!=NULL && pfnDrawThemeBackground!=NULL) { HTHEME hTheme; hTheme=pfnOpenThemeData(NULL,L"Button"); if(hTheme!=NULL) { SetRect(&rc,0,0,size.cx,size.cy); /* unchecked */ if(!pfnDrawThemeBackground(hTheme,hdc,BP_RADIOBUTTON,RBS_UNCHECKEDNORMAL,&rc,NULL)) { /* checked */ OffsetRect(&rc,size.cx,0); if(!pfnDrawThemeBackground(hTheme,hdc,BP_RADIOBUTTON,RBS_CHECKEDNORMAL,&rc,NULL)) himl=ImageList_Create(size.cx,size.cy,ILC_COLOR32|ILC_MASK,3,0); } pfnCloseThemeData(hTheme); } } } /* the classic way */ if(himl==NULL) { register HDC hdcMono; HBITMAP hbmMono,hbmPrevMono; RECT rcRadio; COLORREF clrPrevText,clrPrevBk; HBRUSH hbrBk; hbrBk=CreateSolidBrush(clrBk); if(hbrBk!=NULL) { FillRect(hdc,&rc,hbrBk); DeleteObject(hbrBk); hdcMono=CreateCompatibleDC(hdc); if(hdcMono!=NULL) { hbmMono=CreateBitmap(rc.right,rc.bottom,1,1,NULL); if(hbmMono!=NULL) { hbmPrevMono=SelectObject(hdcMono,hbmMono); if(hbmPrevMono!=NULL) { /* error on select? */ /* draws a black-and-white mask (see docs) * we need to colorize it using BitBlt with text and background color */ clrPrevText=SetTextColor(hdc,clrText); clrPrevBk=SetBkColor(hdc,clrBk); /* check mark is slightly smaller than icon size */ SetRect(&rcRadio,0,0,GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK)); if(rcRadio.right>size.cx) rcRadio.right=size.cx; if(rcRadio.bottom>size.cy) rcRadio.bottom=size.cy; SetRect(&rc,((size.cx-rcRadio.right)/2)+1,((size.cy-rcRadio.bottom)/2)+1,rcRadio.right+1,rcRadio.bottom+1); /* unchecked */ if(BitBlt(hdcMono,0,0,rcRadio.right,rcRadio.bottom,NULL,0,0,WHITENESS)) { /* white back */ if(DrawFrameControl(hdcMono,&rcRadio,DFC_BUTTON,DFCS_BUTTONRADIO|DFCS_FLAT)) { if(BitBlt(hdc,rc.left,rc.top,rcRadio.right,rcRadio.bottom,hdcMono,0,0,SRCCOPY|NOMIRRORBITMAP)) { /* checked */ OffsetRect(&rc,size.cx,0); if(BitBlt(hdcMono,0,0,rcRadio.right,rcRadio.bottom,NULL,0,0,WHITENESS)) {/* white back */ if(DrawFrameControl(hdcMono,&rcRadio,DFC_BUTTON,DFCS_BUTTONRADIO|DFCS_FLAT|DFCS_CHECKED)) { if(BitBlt(hdc,rc.left,rc.top,rcRadio.right,rcRadio.bottom,hdcMono,0,0,SRCCOPY|NOMIRRORBITMAP)) himl=ImageList_Create(size.cx,size.cy,ILC_COLOR|ILC_MASK,3,0); } else BOX("second DrawFrameControl() failed"); } else BOX("second BitBlt() failed"); } else BOX("intermediate BitBlt() failed"); } else BOX("DrawFrameControl() failed"); } else BOX("first BitBlt() failed"); /* restore */ SetBkColor(hdc,clrPrevBk); SetTextColor(hdc,clrPrevText); SelectObject(hdcMono,hbmPrevMono); } else BOX("hbmPrevMono==NULL"); DeleteObject(hbmMono); } else BOX("hbmMono==NULL"); DeleteDC(hdcMono); } else BOX("hdcMono==NULL"); } } SelectObject(hdc,hbmPrev); /* create imagelist */ if(himl!=NULL) { if(himl==NULL) BOX("img list create failed"); if(himl!=NULL) if(ImageList_AddMasked(himl,hbm,clrBk)==-1) BOX("add failed"); } else BOX("Win9x: drawing code not reached"); } DeleteObject(hbm); } DeleteDC(hdc); } ReleaseDC(NULL,hdcScreen); } if(hUxThemeDLL!=NULL) FreeLibrary(hUxThemeDLL); return himl; } static void CleanupPluginName(char *szShortName) { char *p; int len; /* strip-off anything in brackets */ for(p=szShortName;*p!='\0';++p) if(*p=='(' || *p=='[') { *p='\0'; break; } /* remove trailing space */ len=lstrlenA(szShortName); while(szShortName[0]!='\0' && szShortName[len-1]==' ') szShortName[--len]=0; } static void DisplayNotIncludedPlugins(HWND hwndListBox,const LANGPACK_INFO *pack) { WIN32_FIND_DATA wfd; HANDLE hFind; TCHAR szSearch[MAX_PATH],szDir[MAX_PATH],*p; HMODULE hModule; BOOL fNeedsFree; char buf[128]; TCHAR buf2[128]; DWORD mirandaVersion; PLUGININFO *pluginInfo; PLUGININFO *(__cdecl *MirandaPluginInfo)(DWORD); /* enum plugins */ if(!(pack->flags&LPF_DEFAULT) && GetModuleFileName(NULL,szDir,SIZEOF(szDir))) { p=_tcsrchr(szDir,_T('\\')); if(p!=NULL) *p=_T('\0'); mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\Plugins\\*.dll"),szDir); hFind=FindFirstFile(szSearch, &wfd); if(hFind!=INVALID_HANDLE_VALUE) { mirandaVersion=CallService(MS_SYSTEM_GETVERSION,0,0); SendMessage(hwndListBox,LB_SETLOCALE,CallService(MS_LANGPACK_GETLOCALE,0,0),0); /* for sort order */ SendMessage(hwndListBox,LB_INITSTORAGE,128,lstrlenA(pack->szPluginsIncluded)); /* speed up */ do { if(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) continue; if((lstrlen(wfd.cFileName)<4) || (wfd.cFileName[lstrlen(wfd.cFileName)-4]!=_T('.'))) continue; /* file name */ lstrcpy(szSearch,wfd.cFileName); /* buffer safe */ p=_tcsrchr(szSearch,_T('.')); if(p!=NULL) *p=_T('\0'); #if defined(_UNICODE) { char cFileNameA[MAX_PATH]; cFileNameA[0]='\0'; WideCharToMultiByte(CP_ACP,0,szSearch,-1,cFileNameA,sizeof(cFileNameA),NULL,NULL); if(IsPluginIncluded(pack,cFileNameA)) continue; } #else if(IsPluginIncluded(pack,szSearch)) continue; #endif /* friendly name of the plugin */ mir_sntprintf(szSearch,SIZEOF(szSearch),_T("%s\\Plugins\\%s"),szDir,wfd.cFileName); hModule=GetModuleHandle(szSearch); fNeedsFree=(hModule==NULL); if(hModule==NULL) { hModule=LoadLibrary(szSearch); if(hModule==NULL) continue; } /* plugin info */ *(PROC*)&MirandaPluginInfo=GetProcAddress(hModule,"MirandaPluginInfo"); if(MirandaPluginInfo==NULL) /* v0.8 support */ *(PROC*)&MirandaPluginInfo=GetProcAddress(hModule,"MirandaPluginInfoEx"); if(MirandaPluginInfo!=NULL) { /* both structs have the same header */ pluginInfo=MirandaPluginInfo(mirandaVersion); if(pluginInfo!=NULL && pluginInfo->cbSize>=sizeof(PLUGININFO) && pluginInfo->shortName!=NULL) { lstrcpynA(buf,pluginInfo->shortName,sizeof(buf)); /* buffer safe */ CleanupPluginName(buf); mir_sntprintf(buf2,SIZEOF(buf2),TranslateT("%hs (%s)"),buf,CharLower(wfd.cFileName)); SendMessage(hwndListBox,LB_ADDSTRING,0,(LPARAM)buf2); } } if(fNeedsFree) FreeLibrary(hModule); } while(FindNextFile(hFind,&wfd)); FindClose(hFind); } } /* all are included? */ if(!SendMessage(hwndListBox,LB_GETCOUNT,0,0)) SendMessage(hwndListBox,LB_ADDSTRING,0,(LPARAM)TranslateT("All installed plugins are included.")); } static void DisplayPackInfo(HWND hwndDlg,const LANGPACK_INFO *pack) { /* compute not-included from included list */ SendDlgItemMessage(hwndDlg,IDC_LANGNOTINCLUDED,LB_RESETCONTENT,0,0); DisplayNotIncludedPlugins(GetDlgItem(hwndDlg,IDC_LANGNOTINCLUDED),pack); /* locale string */ if(!(pack->flags&LPF_NOLOCALE)) { TCHAR szLocaleName[128]; szLocaleName[0]=_T('\0'); /* can't use LOCALE_SNAME as it is not present on pre WinVista */ if(!GetLocaleInfo(pack->Locale,LOCALE_SISO639LANGNAME,szLocaleName,SIZEOF(szLocaleName))) { /* Win98/NT4+ */ if(!GetLocaleInfo(pack->Locale,LOCALE_SLANGUAGE,szLocaleName,SIZEOF(szLocaleName))) /* not unique! */ szLocaleName[0]=_T('\0'); } else { if(GetLocaleInfo(pack->Locale,LOCALE_SISO3166CTRYNAME,&szLocaleName[3],SIZEOF(szLocaleName)-3)) /* Win98/NT4+ */ szLocaleName[2]=_T('-'); } /* add some note if its incompatible */ if(szLocaleName[0]) { if(!IsValidLocale(pack->Locale,LCID_INSTALLED)) { TCHAR *pszIncompat; pszIncompat=TranslateT("(incompatible)"); szLocaleName[SIZEOF(szLocaleName)-lstrlen(pszIncompat)-1]=0; lstrcat(lstrcat(szLocaleName,_T(" ")),pszIncompat); /* buffer safe */ } SetDlgItemText(hwndDlg,IDC_LANGLOCALE,szLocaleName); } else SetDlgItemText(hwndDlg,IDC_LANGLOCALE,TranslateT("Unknown")); } else SetDlgItemText(hwndDlg,IDC_LANGLOCALE,TranslateT("Current")); /* file date */ { SYSTEMTIME stFileDate; TCHAR szDate[128]; szDate[0]=_T('\0'); if(FileTimeToSystemTime(&pack->ftFileDate,&stFileDate)) GetDateFormat((LCID)CallService(MS_LANGPACK_GETLOCALE,0,0),DATE_SHORTDATE,&stFileDate,NULL,szDate,SIZEOF(szDate)); SetDlgItemText(hwndDlg,IDC_LANGDATE,szDate); } /* version */ SetDlgItemTextA(hwndDlg,IDC_LANGVERSION,pack->szVersion); if(pack->szVersion[0] && pack->szFLName[0]) { if(!IsWindowVisible(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL))) { ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL),SW_SHOW); ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSION),SW_SHOW); } } else { ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSIONLABEL),SW_HIDE); ShowWindow(GetDlgItem(hwndDlg,IDC_LANGVERSION),SW_HIDE); } /* general */ SetDlgItemTextA(hwndDlg,IDC_LANGMODUSING,pack->szLastModifiedUsing); SetDlgItemTextA(hwndDlg,IDC_LANGAUTHORS,pack->szAuthors); SetDlgItemTextA(hwndDlg,IDC_LANGEMAIL,pack->szAuthorEmail); SetDlgItemText(hwndDlg,IDC_LANGINFOFRAME,TranslateTS(pack->szLanguage)); } /************************* Insert/Delete ******************************/ #define M_RELOADLIST (WM_APP+1) #define M_SHOWFILECOL (WM_APP+2) static void DeletePackFile(HWND hwndDlg,HWND hwndList,int iItem,LANGPACK_INFO *pack) { SHFILEOPSTRUCT sfo; TCHAR szFileName[MAX_PATH]; ZeroMemory(&sfo,sizeof(sfo)); sfo.hwnd=hwndDlg; sfo.wFunc=FO_DELETE; sfo.fFlags=FOF_SIMPLEPROGRESS|FOF_SILENT; /* silent = no progress */ /* double zero terminated */ if(GetPackPath(szFileName,SIZEOF(szFileName)-1,pack->flags&LPF_ENABLED,pack->szFileName)) { szFileName[lstrlen(szFileName)+1]=_T('\0'); sfo.pFrom=szFileName; /* ask to delete file */ if(!SHFileOperation(&sfo) && !sfo.fAnyOperationsAborted) { LVITEM lvi; int nCount; lvi.iItem=iItem; lvi.iSubItem=0; lvi.mask=LVIF_STATE; lvi.stateMask=LVIS_STATEIMAGEMASK|LVIS_SELECTED|LVIS_FOCUSED; if(ListView_GetItem(hwndList,&lvi)) { ListView_DeleteItem(hwndList,iItem); /* enable/select next item at same position */ nCount=ListView_GetItemCount(hwndList); if(iItemflags&LPF_DEFAULT) hIcon=(HICON)CallService(MS_FLAGS_CREATEMERGEDFLAGICON,CTRY_UNITED_STATES,CTRY_UNITED_KINGDOM); else { int countryId=0xFFFF; /* Unknown */ TCHAR szBuf[6]; /* get country id from locale */ if(!(pack->flags&LPF_NOLOCALE)) if(GetLocaleInfo(pack->Locale,LOCALE_ICOUNTRY,szBuf,SIZEOF(szBuf))) countryId=_ttoi(szBuf); hIcon=(HICON)CallService(MS_FLAGS_LOADFLAGICON,countryId,0); } if(hIcon==NULL) lvi.iImage=-1; else lvi.iImage=ImageList_AddIcon((HIMAGELIST)lParam,hIcon); lvi.mask|=LVIF_IMAGE; } /* insert */ lvi.iItem=lvi.iSubItem=0; lvi.stateMask=LVIS_STATEIMAGEMASK|LVIS_SELECTED; lvi.state=INDEXTOSTATEIMAGEMASK((pack->flags&LPF_ENABLED)?2:1); if(pack->flags&LPF_ENABLED) lvi.state|=LVIS_SELECTED|LVIS_FOCUSED; lvi.pszText=TranslateTS(pack->szLanguage); lvi.lParam=(LPARAM)pack2; ListView_InsertItem((HWND)wParam,&lvi); return TRUE; } static int CALLBACK CompareListItem(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort) { int cmp; cmp=CompareString((LCID)lParamSort,0,((LANGPACK_INFO*)lParam1)->szLanguage,-1,((LANGPACK_INFO*)lParam2)->szLanguage,-1); if(cmp!=0) cmp-=2; return cmp; } /************************* Options Page *******************************/ static HWND hwndLangOpt; static INT_PTR CALLBACK LangOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam) { switch(msg) { case WM_INITDIALOG: { HWND hwndList; LVCOLUMN lvc; hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST); hwndLangOpt=hwndDlg; TranslateDialogDefault(hwndDlg); ListView_SetExtendedListViewStyle(hwndList,LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP); ListView_SetImageList(hwndList,CreateRadioImages(ListView_GetBkColor(hwndList),ListView_GetTextColor(hwndList)),LVSIL_STATE); /* auto-destroyed */ lvc.mask=LVCF_TEXT; lvc.pszText=TranslateT("Installed Languages"); ListView_InsertColumn(hwndList,0,&lvc); if(ServiceExists(MS_FLAGS_LOADFLAGICON)) ListView_SetImageList(hwndList,ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR24,8,8),LVSIL_SMALL); CorrectPacks(_T("langpack_*.txt"),FALSE); CheckDlgButton(hwndDlg,IDC_ENABLEAUTOUPDATES,DBGetContactSettingByte(NULL,"LangMan","EnableAutoUpdates",SETTING_ENABLEAUTOUPDATES_DEFAULT)!=0); SendMessage(hwndDlg,M_RELOADLIST,0,0); SendMessage(hwndDlg,M_SHOWFILECOL,0,SendMessage(GetParent(hwndDlg),PSM_ISEXPERT,0,0)); return TRUE; } case M_RELOADLIST: { HWND hwndList; HIMAGELIST himl; int iItem; /* init list */ hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST); ListView_DeleteAllItems(hwndList); ListView_DeleteColumn(hwndList,1); /* if present */ himl=ListView_GetImageList(hwndList,LVSIL_SMALL); ImageList_RemoveAll(himl); /* enum all packs */ EnumPacks(InsertPackItemEnumProc,_T("langpack_*.txt"),"Miranda Language Pack Version 1",TRUE,(WPARAM)hwndList,(LPARAM)himl); /* make it use current langpack locale for sort */ ListView_SortItems(hwndList,CompareListItem,CallService(MS_LANGPACK_GETLOCALE,0,0)); CheckDlgButton(hwndDlg,IDC_ENABLEAUTOUPDATES,DBGetContactSettingByte(NULL,"LangMan","EnableAutoUpdates",SETTING_ENABLEAUTOUPDATES_DEFAULT)!=0); /* show selection */ iItem=ListView_GetNextItem(hwndList,-1,LVNI_SELECTED); if(iItem!=-1) ListView_EnsureVisible(hwndList,iItem,FALSE); return TRUE; } case M_SHOWFILECOL: { HWND hwndList; hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST); if((BOOL)lParam && ListView_GetItemCount(hwndList)>1) { LVCOLUMN lvc; LVITEM lvi; LANGPACK_INFO *pack; /* add column */ ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE_USEHEADER); lvc.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; lvc.pszText=TranslateT("File"); lvc.cx=160; ListView_InsertColumn(hwndList,lvc.iSubItem=1,&lvc); ListView_SetColumnWidth(hwndList,0,ListView_GetColumnWidth(hwndList,0)-lvc.cx); /* add text */ lvi.mask=LVIF_PARAM; lvi.iSubItem=0; for(lvi.iItem=0;ListView_GetItem(hwndList,&lvi);++lvi.iItem) { pack=(LANGPACK_INFO*)lvi.lParam; ListView_SetItemText(hwndList,lvi.iItem,1,(pack->flags&LPF_DEFAULT)?TranslateT("built-in"):pack->szFileName); } } else { ListView_DeleteColumn(hwndList,1); ListView_SetColumnWidth(hwndList,0,LVSCW_AUTOSIZE_USEHEADER); } return TRUE; } case WM_DESTROY: ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_LANGLIST)); return TRUE; case WM_THEMECHANGED: case WM_SETTINGCHANGE: { HIMAGELIST himl; HWND hwndList; hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST); himl=ListView_SetImageList(hwndList,CreateRadioImages(ListView_GetBkColor(hwndList),ListView_GetTextColor(hwndList)),LVSIL_STATE); /* auto-destroyed */ if(himl!=NULL) ImageList_Destroy(himl); break; } case WM_CTLCOLORLISTBOX: /* mimic readonly edit */ return (BOOL)SendMessage(hwndDlg,WM_CTLCOLORSTATIC,wParam,lParam); case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_LANGEMAIL: { char buf[512]; lstrcpyA(buf,"mailto:"); if(GetWindowTextA(GetDlgItem(hwndDlg,LOWORD(wParam)),&buf[7],sizeof(buf)-7)) CallService(MS_UTILS_OPENURL,FALSE,(LPARAM)buf); return TRUE; } case IDC_MORELANG: CallService(MS_UTILS_OPENURL,TRUE,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=23"); return TRUE; /* case IDC_ENABLEAUTOUPDATES: SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0); /* enable apply */ /* return TRUE; case IDC_DOWNLOADLANG: ServiceShowLangDialog(0,0); return TRUE;*/ } break; case WM_CONTEXTMENU: if(GetDlgCtrlID((HWND)wParam)==IDC_LANGLIST) { LVHITTESTINFO hti; HMENU hContextMenu; RECT rc; LVITEM lvi; LANGPACK_INFO *pack; /* get item */ POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam)); if(hti.pt.x==-1 && hti.pt.y==-1) { /* keyboard invoked */ hti.iItem=ListView_GetNextItem((HWND)wParam,-1,LVNI_SELECTED); if(hti.iItem!=-1) break; if(!ListView_GetItemRect((HWND)wParam,hti.iItem,&rc,LVIR_SELECTBOUNDS)) break; hti.pt.x=rc.left+(rc.right-rc.left)/2; hti.pt.y=rc.top+(rc.bottom-rc.top)/2; ClientToScreen((HWND)wParam,&hti.pt); } else { ScreenToClient((HWND)wParam,&hti.pt); if(ListView_HitTest((HWND)wParam,&hti)==-1 || !(hti.flags&LVHT_ONITEM)) break; POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam)); } /* param */ lvi.iItem=hti.iItem; lvi.iSubItem=0; lvi.mask=LVIF_PARAM; if(!ListView_GetItem((HWND)wParam,&lvi)) break; pack=(LANGPACK_INFO*)lvi.lParam; /* context menu */ if(!(pack->flags&LPF_DEFAULT)) { hContextMenu=CreatePopupMenu(); if(hContextMenu!=NULL) { AppendMenu(hContextMenu,MF_STRING,2,TranslateT("&Remove...")); if(TrackPopupMenuEx(hContextMenu,TPM_RETURNCMD|TPM_NONOTIFY|TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_HORPOSANIMATION|TPM_VERPOSANIMATION,hti.pt.x,hti.pt.y,(HWND)wParam,NULL)) DeletePackFile(hwndDlg,(HWND)wParam,hti.iItem,pack); DestroyMenu(hContextMenu); } } return TRUE; } break; #if defined(_UNICODE) case WM_NOTIFYFORMAT: SetWindowLong(hwndDlg,DWLP_MSGRESULT,NFR_UNICODE); return TRUE; #endif case WM_NOTIFY: { NMHDR *nmhdr=(NMHDR*)lParam; switch(nmhdr->idFrom) { case IDC_LANGLIST: switch(nmhdr->code) { case LVN_DELETEITEM: { LVITEM lvi; lvi.iItem=((NMLISTVIEW*)lParam)->iItem; /* nmlv->lParam is invalid */ lvi.iSubItem=0; lvi.mask=LVIF_PARAM; if(ListView_GetItem(nmhdr->hwndFrom,&lvi)) mir_free((LANGPACK_INFO*)lvi.lParam); break; } case LVN_ITEMCHANGED: { NMLISTVIEW *nmlv=(NMLISTVIEW*)lParam; if(!(nmlv->uChanged&LVIF_STATE)) break; /* display info and check radio item */ if(nmlv->uNewState&LVIS_SELECTED && !(nmlv->uOldState&LVIS_SELECTED)) { ListView_SetItemState(nmhdr->hwndFrom,nmlv->iItem,INDEXTOSTATEIMAGEMASK(2),LVIS_STATEIMAGEMASK); DisplayPackInfo(hwndDlg,(LANGPACK_INFO*)nmlv->lParam); } /* disable all other radio items */ else if(nmlv->uNewState&INDEXTOSTATEIMAGEMASK(2)) { int iItem; for(iItem=ListView_GetItemCount(nmhdr->hwndFrom)-1;iItem!=-1;--iItem) if(iItem!=nmlv->iItem) ListView_SetItemState(nmhdr->hwndFrom,iItem,INDEXTOSTATEIMAGEMASK(1),LVIS_STATEIMAGEMASK); /* enable apply */ if(nmlv->uOldState) { SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0); ShowWindow(GetDlgItem(hwndDlg,IDC_RESTART),SW_SHOW); } } break; } case LVN_KEYDOWN: { int iItem; iItem=ListView_GetNextItem(nmhdr->hwndFrom,-1,LVNI_SELECTED); switch(((NMLVKEYDOWN*)lParam)->wVKey) { case VK_SPACE: ListView_SetItemState(nmhdr->hwndFrom,iItem,INDEXTOSTATEIMAGEMASK(2),LVIS_STATEIMAGEMASK); break; case VK_DELETE: { LVITEM lvi; LANGPACK_INFO *pack; lvi.iItem=iItem; lvi.iSubItem=0; lvi.mask=LVIF_PARAM; if(ListView_GetItem(nmhdr->hwndFrom,&lvi)) { pack=(LANGPACK_INFO*)lvi.lParam; if(!(pack->flags&LPF_DEFAULT)) DeletePackFile(hwndDlg,nmhdr->hwndFrom,iItem,pack); } break; } } break; } case NM_CLICK: { LVHITTESTINFO hti; lParam=GetMessagePos(); POINTSTOPOINT(hti.pt,MAKEPOINTS(lParam)); ScreenToClient(nmhdr->hwndFrom,&hti.pt); if(ListView_HitTest(nmhdr->hwndFrom,&hti)!=-1) if(hti.flags&(LVHT_ONITEMSTATEICON|LVHT_ONITEMICON)) /* one of them */ ListView_SetItemState(nmhdr->hwndFrom,hti.iItem,LVIS_SELECTED,LVIS_SELECTED); break; } } /* switch nmhdr->code */ break; case 0: switch(nmhdr->code) { case PSN_APPLY: { HWND hwndList; LVITEM lvi; LANGPACK_INFO *pack; hwndList=GetDlgItem(hwndDlg,IDC_LANGLIST); lvi.mask=LVIF_STATE|LVIF_PARAM; lvi.stateMask=LVIS_STATEIMAGEMASK; lvi.iSubItem=0; for(lvi.iItem=0;ListView_GetItem(hwndList,&lvi);++lvi.iItem) { pack=(LANGPACK_INFO*)lvi.lParam; if(lvi.state&INDEXTOSTATEIMAGEMASK(2)) { EnablePack(pack,_T("langpack_*.txt")); pack->flags|=LPF_ENABLED; } else pack->flags&=~LPF_ENABLED; } DBWriteContactSettingByte(NULL,"LangMan","EnableAutoUpdates",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_ENABLEAUTOUPDATES)!=0)); return TRUE; } case PSN_EXPERTCHANGED: SendMessage(hwndDlg,M_SHOWFILECOL,0,((PSHNOTIFY*)lParam)->lParam); return TRUE; } /* switch nmhdr->code */ break; } /* switch nmhdr->idFrom */ break; } } return FALSE; } void ReloadLangOptList(void) { if(hwndLangOpt!=NULL) { SendMessage(hwndLangOpt,M_RELOADLIST,0,0); SendMessage(hwndLangOpt,M_SHOWFILECOL,0,SendMessage(GetParent(hwndLangOpt),PSM_ISEXPERT,0,0)); } } static int LangOptInit(WPARAM wParam,LPARAM lParam) { OPTIONSDIALOGPAGE odp; UNREFERENCED_PARAMETER(lParam); ZeroMemory(&odp,sizeof(odp)); odp.cbSize=sizeof(odp); odp.hInstance=hInst; odp.flags=ODPF_BOLDGROUPS|ODPF_TCHAR; odp.position=1200000090; /* plugin opts=1300000000 */ // odp.ptszGroup=_T("Appearance"); /* autotranslated */ odp.ptszTitle=_T("Appearance"); /* autotranslated */ // odp.ptszTab=_T("Language"); /* autotranslated, can be made a tab */ odp.pszTemplate=MAKEINTRESOURCEA(IDD_OPT_LANG); odp.pfnDlgProc=LangOptDlgProc; CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp); return 0; } /************************* Misc ***************************************/ void InitOptions(void) { hwndLangOpt=NULL; hHookOptInit=HookEvent(ME_OPT_INITIALISE,LangOptInit); CorrectPacks(_T("langpack_*.txt"),FALSE); } void UninitOptions(void) { UnhookEvent(hHookOptInit); }