#include "../Winamp/buildType.h" #include "api__ml_pmp.h" #include "main.h" #include "../ml_wire/ifc_podcast.h" #include "DeviceView.h" #include "nu/AutoWide.h" #include "transcoder_imp.h" #include "nu/listview.h" #include "nu/AutoLock.h" #include #include #include #include #if defined (_WIN64) #include "../Elevator/IFileTypeRegistrar_64.h" #else #include "../Elevator/IFileTypeRegistrar_32.h" #endif extern winampMediaLibraryPlugin plugin; extern DeviceView * currentViewedDevice; extern C_ItemList m_plugins; extern C_Config * global_config; extern C_ItemList devices; extern HWND hwndMediaView; static void link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); void link_startsubclass(HWND hwndDlg, UINT id); INT_PTR CALLBACK global_config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); INT_PTR CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_cloud_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_podcast_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_autofill(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_transcode(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_mediaview(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static INT_PTR CALLBACK config_dlgproc_cloud_mediaview(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); INT_PTR CALLBACK config_dlgproc_plugins(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); void myOpenURLWithFallback(HWND hwnd, wchar_t *loc, wchar_t *fallbackLoc); HWND m_hwndTab = NULL, m_hwndTabDisplay = NULL; int g_prefs_openpage=0; static C_Config * config; DeviceView * configDevice; enum { SYNC_PREF_IDX = 0, PODSYNC_PREF_IDX, AUTOFILL_PREF_IDX, TRANS_PREF_IDX, MEDIAVIEW_PREF_IDX }; static pref_tab tabs[] = { {L"",IDD_CONFIG_SYNC,config_dlgproc_sync,0}, {L"",IDD_CONFIG_PODCAST_SYNC,config_dlgproc_podcast_sync,0}, {L"",IDD_CONFIG_AUTOFILL,config_dlgproc_autofill,0}, {L"",IDD_CONFIG_TRANSCODE,config_dlgproc_transcode,0}, {L"",IDD_CONFIG_MEDIAVIEW,config_dlgproc_mediaview,0}, {L"",0,0,0}, // extra config for plugins }; static void config_tab_init(HWND tab,HWND m_hwndDlg) { RECT r; GetWindowRect(m_hwndTab,&r); TabCtrl_AdjustRect(m_hwndTab,FALSE,&r); MapWindowPoints(NULL,m_hwndDlg,(LPPOINT)&r,2); SetWindowPos(tab,HWND_TOP,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOACTIVATE); if(!SendMessage(plugin.hwndWinampParent,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC)) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)tab,IPC_USE_UXTHEME_FUNC); } HWND OnSelChanged(HWND hwndDlg, HWND external = NULL, DeviceView *dev = NULL) { static prefsParam p; int sel=(!external ? TabCtrl_GetCurSel(m_hwndTab) : MEDIAVIEW_PREF_IDX); if (!external) { g_prefs_openpage=sel; if(m_hwndTabDisplay!=NULL) DestroyWindow(m_hwndTabDisplay); p.config_tab_init = config_tab_init; p.dev = configDevice->dev; p.parent = hwndDlg; // copes with the Transcoding tab being hidden if (sel >= TRANS_PREF_IDX && tabs[TRANS_PREF_IDX].title[0] == 0) sel++; } else { configDevice = dev; config = dev->config; p.config_tab_init = config_tab_init; p.dev = dev->dev; p.parent = hwndDlg; } // copes with a cloud device which doesn't need podcast sync and autofill // as well as factoring in the transcoding page needing to be hidden, etc if (configDevice->isCloudDevice) { if (!external && (sel >= SYNC_PREF_IDX)) sel += (3 + (tabs[TRANS_PREF_IDX].title[0] == 0)); if (sel == MEDIAVIEW_PREF_IDX) { tabs[sel].res_id = IDD_CONFIG_CLOUD_MEDIAVIEW; tabs[sel].dlg_proc = config_dlgproc_cloud_mediaview; } } else { if (sel == SYNC_PREF_IDX) { tabs[sel].res_id = IDD_CONFIG_SYNC; tabs[sel].dlg_proc = config_dlgproc_sync; } if (sel == MEDIAVIEW_PREF_IDX) { tabs[sel].res_id = IDD_CONFIG_MEDIAVIEW; tabs[sel].dlg_proc = config_dlgproc_mediaview; } } if(!tabs[sel].hinst) m_hwndTabDisplay=WASABI_API_CREATEDIALOGPARAMW(tabs[sel].res_id, hwndDlg, tabs[sel].dlg_proc, (LPARAM)&p); else m_hwndTabDisplay=WASABI_API_LNG->CreateLDialogParamW(tabs[sel].hinst, tabs[sel].hinst, tabs[sel].res_id, hwndDlg, tabs[sel].dlg_proc, (LPARAM)&p); if (!external) { RECT r; GetClientRect(m_hwndTab, &r); TabCtrl_AdjustRect(m_hwndTab, FALSE, &r); SetWindowPos(m_hwndTabDisplay, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOACTIVATE | SWP_SHOWWINDOW); } return m_hwndTabDisplay; } void Shell_Free(void *p) { IMalloc *m = NULL; if (SUCCEEDED(SHGetMalloc(&m)) && m) { m->Free(p); } } wchar_t* GetDefaultSaveToFolder(wchar_t* path_to_store) { if(FAILED(SHGetFolderPath(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store))) { if(FAILED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store))) { // and if that all fails then do a reasonable default lstrcpyn(path_to_store, L"C:\\My Music", MAX_PATH); } // if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music else { PathCombine(path_to_store, path_to_store, L"My Music"); } } return path_to_store; } BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam) { wchar_t cl[32] = {0}; GetClassNameW(hwnd, cl, ARRAYSIZE(cl)); if (!lstrcmpiW(cl, WC_TREEVIEW)) { PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd)); return FALSE; } return TRUE; } int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { if(uMsg == BFFM_INITIALIZED) { wchar_t m_def_extract_path[MAX_PATH] = L"C:\\My Music"; SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)global_config->ReadString(L"extractpath", GetDefaultSaveToFolder(m_def_extract_path))); // this is not nice but it fixes the selection not working correctly on all OSes EnumChildWindows(hwnd, browseEnumProc, 0); } return 0; } extern void doFormatFileName(wchar_t out[MAX_PATH], wchar_t *fmt, int trackno, wchar_t *artist, wchar_t *album, wchar_t *title, wchar_t *genre, wchar_t *year, wchar_t *trackartist); INT_PTR CALLBACK global_config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { wchar_t m_def_extract_path[MAX_PATH] = L"C:\\My Music"; switch (uMsg) { case WM_INITDIALOG: { wchar_t m_def_filename_fmt[] = L" - \\## - - "; GetDefaultSaveToFolder(m_def_extract_path); if (global_config->ReadInt(L"extractusecdrip", 1)) CheckDlgButton(hwndDlg, IDC_CHECK_USECDRIP, BST_CHECKED); SendDlgItemMessage(hwndDlg, IDC_DESTPATH, EM_SETLIMITTEXT, MAX_PATH, 0); SetDlgItemText(hwndDlg, IDC_DESTPATH, global_config->ReadString(L"extractpath", m_def_extract_path)); SetDlgItemText(hwndDlg, IDC_FILENAMEFMT, global_config->ReadString(L"extractfmt2", m_def_filename_fmt)); SendMessage(hwndDlg,WM_USER,0,0); } break; case WM_USER: { BOOL enabled = !IsDlgButtonChecked(hwndDlg, IDC_CHECK_USECDRIP); EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_1),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_DESTPATH),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_2),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON2),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAMEFMT),enabled); EnableWindow(GetDlgItem(hwndDlg,IDC_FMTOUT),enabled); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_DESTPATH: if (HIWORD(wParam) == EN_CHANGE) { wchar_t buf[1024] = {0}; GetDlgItemText(hwndDlg, IDC_DESTPATH, buf, 1024); global_config->WriteString(L"extractpath", buf); } return 0; case IDC_CHECK_USECDRIP: { global_config->WriteInt(L"extractusecdrip", !!IsDlgButtonChecked(hwndDlg, IDC_CHECK_USECDRIP)); SendMessage(hwndDlg,WM_USER,0,0); } break; // run through... case IDC_FILENAMEFMT: if (HIWORD(wParam) == EN_CHANGE) { wchar_t buf[1024] = {0}; GetDlgItemText(hwndDlg, IDC_FILENAMEFMT, buf, 1024); if(LOWORD(wParam) == IDC_FILENAMEFMT) global_config->WriteString(L"extractfmt2", buf); wchar_t str[MAX_PATH] = {0}; doFormatFileName(WASABI_API_LNGSTRINGW_BUF(IDS_EXAMPLE_FORMATTING_STRING,str,MAX_PATH), buf, 10, L"U2", L"The Joshua Tree", L"Exit", L"Rock", L"1987", L"U2"); wchar_t fmt[5]=L"mp3"; StringCchCat(str, MAX_PATH, L"."); StringCchCat(str, MAX_PATH, fmt); SetDlgItemText(hwndDlg, IDC_FMTOUT, str); } return 0; case IDC_BUTTON1: { //browse for folder BROWSEINFO bi = {0}; wchar_t name[MAX_PATH] = {0}; bi.hwndOwner = hwndDlg; bi.pidlRoot = NULL; bi.pszDisplayName = name; bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_A_FOLDER); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; bi.lpfn = BrowseCallbackProc; ITEMIDLIST *idlist = SHBrowseForFolder(&bi); if (idlist) { wchar_t path[MAX_PATH] = {0}; SHGetPathFromIDList( idlist, path ); Shell_Free(idlist); global_config->WriteString(L"extractpath", path); SetDlgItemText(hwndDlg, IDC_DESTPATH, global_config->ReadString(L"extractpath", m_def_extract_path)); } } break; case IDC_BUTTON2: wchar_t titleStr[64] = {0}; MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_COPIED_FILE_FORMAT_INFO), WASABI_API_LNGSTRINGW_BUF(IDS_COPIED_FILE_FORMAT_HELP,titleStr,64), MB_OK); break; } break; } return 0; } INT_PTR CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { config = global_config; DeviceView * dev = NULL; for(int i=0; i<devices.GetSize(); i++) { dev = (DeviceView *)devices.Get(i); if(&dev->devPrefsPage == (prefsDlgRecW *)lParam) { configDevice = dev; config = dev->config; break; } } if(config == global_config) { EndDialog(hwndDlg,0); return 0; } // set the prefs page titles at this stage so that we can have localised versions int title_ids[] = {IDS_PREFS_SYNC,IDS_PODCAST_SYNC,IDS_PREFS_AUTOFILL,IDS_PREFS_TRANSCODING,IDS_PREFS_VIEW}; for(int i=0; i<sizeof(title_ids)/sizeof(title_ids[0]); i++) WASABI_API_LNGSTRINGW_BUF(title_ids[i],tabs[i].title,(sizeof(tabs[i].title)/sizeof(wchar_t))); // set the last item's title to zero otherwise it can cause a dialog to appear incorrectly tabs[sizeof(tabs)/sizeof(tabs[0])-1].title[0] = 0; m_hwndTab = GetDlgItem(hwndDlg,IDC_TAB1); TCITEM tie; tie.mask = TCIF_TEXT; int num = 0; for(int i=0; i<sizeof(tabs)/sizeof(pref_tab); i++) { if (dev) { if(tabs[i].title[0] == 0) { dev->dev->extraActions(DEVICE_GET_PREFS_DIALOG,(intptr_t)&tabs[i],num++,0); } // check if we need to show the Transcoding page or not if (i == TRANS_PREF_IDX && dev->dev->extraActions(DEVICE_VETO_TRANSCODING,0,0,0)) { tabs[i].title[0] = 0; } else { // check if a cloud device and drop sync, podcast sync and autofill as appropriate if (configDevice->isCloudDevice && (i == SYNC_PREF_IDX || i == PODSYNC_PREF_IDX || i == AUTOFILL_PREF_IDX)) { tabs[i].title[0] = 0; } } } if(tabs[i].title[0] != 0) { tie.pszText=tabs[i].title; TabCtrl_InsertItem(m_hwndTab,i,&tie); } } TabCtrl_SetCurSel(m_hwndTab,g_prefs_openpage); OnSelChanged(hwndDlg); } break; case WM_NOTIFY: { LPNMHDR lpn = (LPNMHDR) lParam; if(lpn) if(lpn->code==TCN_SELCHANGE) OnSelChanged(hwndDlg); } break; case WM_DESTROY: tabs[4].title[0]=0; configDevice = NULL; break; } return 0; } static INT_PTR CALLBACK config_dlgproc_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { static W_ListView m_list; static int nonotif; switch(uMsg) { case WM_INITDIALOG: { nonotif=1; if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); if(config->ReadInt(L"syncOnConnect",configDevice->SyncConnectionDefault)==1) CheckDlgButton(hwndDlg,IDC_SYNCONCONNECT,BST_CHECKED); else EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),FALSE); SetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,config->ReadString(L"syncOnConnect_hours",L"12")); SetDlgItemText(hwndDlg,IDC_SYNC_QUERY_STRING,config->ReadString(L"SyncQuery",L"type=0")); if(config->ReadInt(L"plsyncwhitelist",1)) CheckDlgButton(hwndDlg,IDC_PL_WHITELIST,BST_CHECKED); else CheckDlgButton(hwndDlg,IDC_PL_BLACKLIST,BST_CHECKED); if(config->ReadInt(L"syncAllLibrary",1)) CheckDlgButton(hwndDlg,IDC_LIBRARYSYNC,BST_CHECKED); m_list.setwnd(GetDlgItem(hwndDlg,IDC_PL_LIST)); ListView_SetExtendedListViewStyle(m_list.getwnd(), LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); m_list.AddCol(L"",353); m_list.SetColumnWidth(0, 200); mlPlaylistInfo playlist = {0}; playlist.size = sizeof(mlPlaylistInfo); int playlistsnum = SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,0,ML_IPC_PLAYLIST_COUNT); for(int i=0; i<playlistsnum; i++) { playlist.playlistNum = i; SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&playlist,ML_IPC_PLAYLIST_INFO); m_list.InsertItem(i,playlist.playlistName,0); } ListView_SetColumnWidth(m_list.getwnd(),0,LVSCW_AUTOSIZE); for(int i=0; i<playlistsnum; i++) { playlist.playlistNum = i; SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&playlist,ML_IPC_PLAYLIST_INFO); wchar_t buf[150] = {0}; StringCchPrintf(buf,150,L"sync-%s",playlist.playlistName); BOOL state = config->ReadInt(buf,0)?TRUE:FALSE; ListView_SetCheckState(m_list.getwnd(),i,state); } nonotif=0; if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(m_list.getwnd(), TRUE); } break; case WM_DESTROY: if (NULL != WASABI_API_APP) { HWND listWindow; listWindow = GetDlgItem(hwndDlg,IDC_PL_LIST); if (NULL != listWindow) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE); } break; case WM_NOTIFY: { LPNMHDR l=(LPNMHDR)lParam; if (l->idFrom==IDC_PL_LIST && l->code == LVN_ITEMCHANGED && !nonotif) { LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam; if(lv->iItem == -1) break; wchar_t buf[150] = {0}, buf1[125] = {0}; m_list.GetText(lv->iItem,0,buf1,125); StringCchPrintf(buf,150,L"sync-%s",buf1); BOOL state = ListView_GetCheckState(m_list.getwnd(),lv->iItem); config->WriteInt(buf,state?1:0); } } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_SYNCONCONNECT: config->WriteInt(L"syncOnConnect",IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)?1:0); EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)); break; case IDC_SYNCONCONNECT_TIME: if(HIWORD(wParam) == EN_CHANGE) { wchar_t buf[100]=L""; GetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,buf,100); config->WriteInt(L"syncOnConnect_hours",_wtoi(buf)); } break; case IDC_PL_WHITELIST: case IDC_PL_BLACKLIST: config->WriteInt(L"plsyncwhitelist",IsDlgButtonChecked(hwndDlg,IDC_PL_WHITELIST)?1:0); break; case IDC_LIBRARYSYNC: config->WriteInt(L"syncAllLibrary",IsDlgButtonChecked(hwndDlg,IDC_LIBRARYSYNC)?1:0); break; case IDC_SYNC_QUERY_STRING: if (HIWORD(wParam) == EN_KILLFOCUS) { wchar_t buf[1024] = {0}; GetDlgItemText(hwndDlg,IDC_SYNC_QUERY_STRING,buf,1024); config->WriteString(L"SyncQuery",buf); } break; case IDC_SYNC_QUERY_EDIT: { char temp[1024] = {0}; GetDlgItemTextA(hwndDlg, IDC_SYNC_QUERY_STRING, temp, sizeof(temp) - 1); ml_editview meq = {hwndDlg,temp,"Sync Query",-1}; meq.name = WASABI_API_LNGSTRING(IDS_SYNC_QUERY); if(!(int)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(LPARAM)&meq,ML_IPC_EDITVIEW)) return 0; SetDlgItemTextA(hwndDlg, IDC_SYNC_QUERY_STRING, meq.query); config->WriteString(L"SyncQuery",AutoWide(meq.query)); } break; } break; } return 0; } static INT_PTR CALLBACK config_dlgproc_cloud_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { static W_ListView m_list; static int nonotif; switch(uMsg) { case WM_INITDIALOG: { nonotif=1; if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); if(config->ReadInt(L"syncOnConnect",configDevice->SyncConnectionDefault)==1) CheckDlgButton(hwndDlg,IDC_SYNCONCONNECT,BST_CHECKED); else EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),FALSE); SetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,config->ReadString(L"syncOnConnect_hours",L"12")); SetDlgItemText(hwndDlg,IDC_SYNC_QUERY_STRING,config->ReadString(L"SyncQuery",L"type=0")); if(config->ReadInt(L"plsyncwhitelist",1)) CheckDlgButton(hwndDlg,IDC_PL_WHITELIST,BST_CHECKED); else CheckDlgButton(hwndDlg,IDC_PL_BLACKLIST,BST_CHECKED); if(config->ReadInt(L"syncAllLibrary",1)) CheckDlgButton(hwndDlg,IDC_LIBRARYSYNC,BST_CHECKED); m_list.setwnd(GetDlgItem(hwndDlg,IDC_PL_LIST)); ListView_SetExtendedListViewStyle(m_list.getwnd(), LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); m_list.AddCol(L"",353); mlPlaylistInfo playlist = {0}; playlist.size = sizeof(mlPlaylistInfo); int playlistsnum = SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,0,ML_IPC_PLAYLIST_COUNT); for(int i=0; i<playlistsnum; i++) { playlist.playlistNum = i; SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&playlist,ML_IPC_PLAYLIST_INFO); m_list.InsertItem(i,playlist.playlistName,0); } ListView_SetColumnWidth(m_list.getwnd(),0,LVSCW_AUTOSIZE); for(int i=0; i<playlistsnum; i++) { playlist.playlistNum = i; SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&playlist,ML_IPC_PLAYLIST_INFO); wchar_t buf[150] = {0}; StringCchPrintf(buf,150,L"sync-%s",playlist.playlistName); BOOL state = config->ReadInt(buf,0)?TRUE:FALSE; ListView_SetCheckState(m_list.getwnd(),i,state); } nonotif=0; if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(m_list.getwnd(), TRUE); } break; case WM_DESTROY: if (NULL != WASABI_API_APP) { HWND listWindow; listWindow = GetDlgItem(hwndDlg,IDC_PL_LIST); if (NULL != listWindow) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE); } break; case WM_NOTIFY: { LPNMHDR l=(LPNMHDR)lParam; if (l->idFrom==IDC_PL_LIST && l->code == LVN_ITEMCHANGED && !nonotif) { LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam; if(lv->iItem == -1) break; wchar_t buf[150] = {0}, buf1[125] = {0}; m_list.GetText(lv->iItem,0,buf1,125); StringCchPrintf(buf,150,L"sync-%s",buf1); BOOL state = ListView_GetCheckState(m_list.getwnd(),lv->iItem); config->WriteInt(buf,state?1:0); } } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_SYNCONCONNECT: config->WriteInt(L"syncOnConnect",IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)?1:0); EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)); break; case IDC_SYNCONCONNECT_TIME: if(HIWORD(wParam) == EN_CHANGE) { wchar_t buf[100]=L""; GetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,buf,100); config->WriteInt(L"syncOnConnect_hours",_wtoi(buf)); } break; case IDC_PL_WHITELIST: case IDC_PL_BLACKLIST: config->WriteInt(L"plsyncwhitelist",IsDlgButtonChecked(hwndDlg,IDC_PL_WHITELIST)?1:0); break; case IDC_LIBRARYSYNC: config->WriteInt(L"syncAllLibrary",IsDlgButtonChecked(hwndDlg,IDC_LIBRARYSYNC)?1:0); break; case IDC_SYNC_QUERY_STRING: if (HIWORD(wParam) == EN_KILLFOCUS) { wchar_t buf[1024] = {0}; GetDlgItemText(hwndDlg,IDC_SYNC_QUERY_STRING,buf,1024); config->WriteString(L"SyncQuery",buf); } break; case IDC_SYNC_QUERY_EDIT: { char temp[1024] = {0}; GetDlgItemTextA(hwndDlg, IDC_SYNC_QUERY_STRING, temp, sizeof(temp) - 1); ml_editview meq = {hwndDlg,temp,"Sync Query",-1}; meq.name = WASABI_API_LNGSTRING(IDS_SYNC_QUERY); if(!(int)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(LPARAM)&meq,ML_IPC_EDITVIEW)) return 0; SetDlgItemTextA(hwndDlg, IDC_SYNC_QUERY_STRING, meq.query); config->WriteString(L"SyncQuery",AutoWide(meq.query)); } break; } break; } return 0; } static INT_PTR CALLBACK config_dlgproc_podcast_sync(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { static W_ListView m_list2; static int nonotif; switch(uMsg) { case WM_INITDIALOG: { nonotif=1; if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); m_list2.setwnd(GetDlgItem(hwndDlg,IDC_PC_LIST)); ListView_SetExtendedListViewStyle(m_list2.getwnd(), LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); m_list2.AddCol(L"",215); if (configDevice->dev->extraActions(DEVICE_SUPPORTS_PODCASTS, 0,0, 0) == 0) { int podcastsnum = AGAVE_API_PODCASTS?AGAVE_API_PODCASTS->GetNumPodcasts():0; for(int i=0; i<podcastsnum; i++) { ifc_podcast *podcast = AGAVE_API_PODCASTS->EnumPodcast(i); if (podcast) { wchar_t podcast_name[256] = {0}; if (podcast->GetTitle(podcast_name, 256) == 0 && podcast_name[0]) { m_list2.InsertItem(i,podcast_name,0); } } } ListView_SetColumnWidth(m_list2.getwnd(),0,LVSCW_AUTOSIZE); for(int i=0; i<podcastsnum; i++) { ifc_podcast *podcast = AGAVE_API_PODCASTS->EnumPodcast(i); if (podcast) { wchar_t podcast_name[256] = {0}; if (podcast->GetTitle(podcast_name, 256) == 0 && podcast_name[0]) { wchar_t buf[300] = {0}; StringCchPrintf(buf,300,L"podcast-sync-%s",podcast_name); BOOL state = config->ReadInt(buf,0)?TRUE:FALSE; ListView_SetCheckState(m_list2.getwnd(),i,state); } } } int podcast_eps = config->ReadInt(L"podcast-sync_episodes",0); if(podcast_eps == 0) { podcast_eps=3; } else CheckDlgButton(hwndDlg,IDC_CHECK_PC,BST_CHECKED); for(int i=0; i<6; i++) { int a,d; if(i==0) { a = SendDlgItemMessage(hwndDlg,IDC_COMBO_PC_NUM,CB_ADDSTRING,0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_ALL)); d = -1; } else { wchar_t buf[10] = {0}; StringCchPrintf(buf,100,L"%d",i); a = SendDlgItemMessage(hwndDlg,IDC_COMBO_PC_NUM,CB_ADDSTRING,0,(LPARAM)buf); d = i; } SendDlgItemMessage(hwndDlg,IDC_COMBO_PC_NUM,CB_SETITEMDATA,a,(LPARAM)d); if(d == podcast_eps) SendDlgItemMessage(hwndDlg, IDC_COMBO_PC_NUM, CB_SETCURSEL, (WPARAM)a, 0); } if(config->ReadInt(L"podcast-sync_all",1)) CheckDlgButton(hwndDlg,IDC_PC_ALL,BST_CHECKED); else CheckDlgButton(hwndDlg,IDC_PC_SEL,BST_CHECKED); } else { EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_PC), FALSE); } SendMessage(hwndDlg,WM_COMMAND,IDC_CHECK_PC,0xdeadbeef); nonotif=0; if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(m_list2.getwnd(), TRUE); } break; case WM_DESTROY: if (NULL != WASABI_API_APP) { HWND listWindow; listWindow = GetDlgItem(hwndDlg,IDC_PL_LIST); if (NULL != listWindow) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE); } break; case WM_NOTIFY: { LPNMHDR l=(LPNMHDR)lParam; if (l->idFrom==IDC_PC_LIST && l->code == LVN_ITEMCHANGED && !nonotif) { LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam; if(lv->iItem == -1) break; wchar_t buf[150] = {0}, buf1[125] = {0}; m_list2.GetText(lv->iItem,0,buf1,125); StringCchPrintf(buf,150,L"podcast-sync-%s",buf1); BOOL state = ListView_GetCheckState(m_list2.getwnd(),lv->iItem); config->WriteInt(buf,state?1:0); } } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_CHECK_PC: { BOOL e = IsDlgButtonChecked(hwndDlg,IDC_CHECK_PC); EnableWindow(GetDlgItem(hwndDlg,IDC_COMBO_PC_NUM),e); EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_PODTXT),e); EnableWindow(GetDlgItem(hwndDlg,IDC_PC_ALL),e); EnableWindow(GetDlgItem(hwndDlg,IDC_PC_SEL),e); EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC_PODTIP),e); EnableWindow(GetDlgItem(hwndDlg,IDC_PC_LIST),e && IsDlgButtonChecked(hwndDlg,IDC_PC_SEL)); if(lParam != 0xdeadbeef) { if(e) { int b = SendDlgItemMessage(hwndDlg, IDC_COMBO_PC_NUM, CB_GETCURSEL, 0, 0); if(b>=0) { int x = SendDlgItemMessage(hwndDlg, IDC_COMBO_PC_NUM, CB_GETITEMDATA, b, 0); config->WriteInt(L"podcast-sync_episodes", x); } } else config->WriteInt(L"podcast-sync_episodes",0); } } break; case IDC_PC_SEL: case IDC_PC_ALL: { BOOL e = IsDlgButtonChecked(hwndDlg,IDC_PC_SEL); EnableWindow(GetDlgItem(hwndDlg,IDC_PC_LIST),e); config->WriteInt(L"podcast-sync_all",!e); } break; case IDC_COMBO_PC_NUM: if(HIWORD(wParam) == CBN_SELCHANGE) { int b = SendDlgItemMessage(hwndDlg, IDC_COMBO_PC_NUM, CB_GETCURSEL, 0, 0); if (b >= 0) { int x = SendDlgItemMessage(hwndDlg, IDC_COMBO_PC_NUM, CB_GETITEMDATA, b, 0); config->WriteInt(L"podcast-sync_episodes", x); } } break; } break; } return 0; } static INT_PTR CALLBACK config_dlgproc_autofill(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); if(config->ReadInt(L"syncOnConnect",configDevice->SyncConnectionDefault)==2) CheckDlgButton(hwndDlg,IDC_SYNCONCONNECT,BST_CHECKED); else EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),FALSE); SetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,config->ReadString(L"syncOnConnect_hours",L"12")); if(lstrlen(config->ReadString(L"AutoFillRatings",L""))!=0) CheckDlgButton(hwndDlg,IDC_BOOSTRATINGS,BST_CHECKED); if(config->ReadInt(L"AlbumAutoFill",0)) CheckDlgButton(hwndDlg,IDC_AUTOFILLALBUMS,BST_CHECKED); SetDlgItemText(hwndDlg,IDC_AUTOFILL_QUERY_STRING,config->ReadString(L"AutoFillQuery",L"length > 30")); SendMessage(GetDlgItem(hwndDlg,IDC_SPACESLIDER),TBM_SETRANGEMAX, TRUE, 100); SendMessage(GetDlgItem(hwndDlg,IDC_SPACESLIDER),TBM_SETRANGEMIN, TRUE, 0); SendMessage(GetDlgItem(hwndDlg,IDC_SPACESLIDER),TBM_SETPOS, TRUE, config->ReadInt(L"FillPercent",90)); break; case WM_NOTIFY: switch (LOWORD(wParam)) { case IDC_SPACESLIDER: { int spaceToAutofill = SendMessage(GetDlgItem(hwndDlg,IDC_SPACESLIDER),TBM_GETPOS,0,0); wchar_t tmp[100]=L""; StringCchPrintf(tmp,100,WASABI_API_LNGSTRINGW(IDS_AIM_TO_AUTOFILL_DEVICE),spaceToAutofill); SetDlgItemText(hwndDlg, IDC_FILLCAPTION, tmp); config->WriteInt(L"FillPercent",spaceToAutofill); } break; } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_SYNCONCONNECT: config->WriteInt(L"syncOnConnect",IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)?2:0); EnableWindow(GetDlgItem(hwndDlg,IDC_SYNCONCONNECT_TIME),IsDlgButtonChecked(hwndDlg,IDC_SYNCONCONNECT)); break; case IDC_SYNCONCONNECT_TIME: if(HIWORD(wParam) == EN_CHANGE) { wchar_t buf[100]=L""; GetDlgItemText(hwndDlg,IDC_SYNCONCONNECT_TIME,buf,100); config->WriteInt(L"syncOnConnect_hours",_wtoi(buf)); } break; case IDC_AUTOFILL_QUERY_STRING: if (HIWORD(wParam) == EN_KILLFOCUS) { wchar_t buf[1024] = {0}; GetDlgItemText(hwndDlg,IDC_AUTOFILL_QUERY_STRING,buf,1024); config->WriteString(L"AutoFillQuery",buf); } break; case IDC_AUTOFILL_QUERY_EDIT: { char temp[1024] = {0}; GetDlgItemTextA(hwndDlg, IDC_AUTOFILL_QUERY_STRING, temp, sizeof(temp) - 1); ml_editview meq = {hwndDlg,temp,0,-1}; meq.name = WASABI_API_LNGSTRING(IDS_AUTOFILL_QUERY); if(!(int)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(LPARAM)&meq,ML_IPC_EDITVIEW)) return 0; SetDlgItemTextA(hwndDlg, IDC_AUTOFILL_QUERY_STRING, meq.query); config->WriteString(L"AutoFillQuery",AutoWide(meq.query)); } break; case IDC_BOOSTRATINGS: if(IsDlgButtonChecked(hwndDlg,IDC_BOOSTRATINGS)) config->WriteString(L"AutoFillRatings",L"20:18:15:13:11:10"); else config->WriteString(L"AutoFillRatings",L""); break; case IDC_AUTOFILLALBUMS: config->WriteInt(L"AlbumAutoFill",IsDlgButtonChecked(hwndDlg,IDC_AUTOFILLALBUMS)?1:0); break; } break; } const int controls[] = { IDC_SPACESLIDER, }; if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls))) return TRUE; return 0; } static INT_PTR CALLBACK config_dlgproc_transcode(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { Device *dev = 0; if(lParam) { config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); dev = ((prefsParam*)lParam)->dev; } lParam = (LPARAM)TranscoderImp::ConfigureTranscoder(L"ml_pmp",plugin.hwndWinampParent,config, dev); } break; } return TranscoderImp::transcodeconfig_dlgproc(hwndDlg,uMsg,wParam,lParam); } static INT_PTR CALLBACK config_dlgproc_mediaview(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); int fieldsBits = (int)configDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0); if(!fieldsBits) fieldsBits=-1; // used to ensure that the filters will work irrespective of language in use wchar_t * filters[] = { (fieldsBits&SUPPORTS_ARTIST)?L"Artist":0, (fieldsBits&SUPPORTS_ALBUM)?L"Album":0, (fieldsBits&SUPPORTS_GENRE)?L"Genre":0, (fieldsBits&SUPPORTS_YEAR)?L"Year":0, (fieldsBits&SUPPORTS_ALBUMARTIST)?L"Album Artist":0, (fieldsBits&SUPPORTS_PUBLISHER)?L"Publisher":0, (fieldsBits&SUPPORTS_COMPOSER)?L"Composer":0, (fieldsBits&SUPPORTS_ARTIST)?L"Artist Index":0, (fieldsBits&SUPPORTS_ALBUMARTIST)?L"Album Artist Index":0, (fieldsBits&SUPPORTS_ALBUMART)?L"Album Art":0, (fieldsBits&SUPPORTS_MIMETYPE)?L"Mime":0, (fieldsBits&SUPPORTS_DATEADDED)?L"Date Added":0, }; // used for displayed items - localised crazyness, heh int filters_idx[] = { (fieldsBits&SUPPORTS_ARTIST)?IDS_ARTIST:0, (fieldsBits&SUPPORTS_ALBUM)?IDS_ALBUM:0, (fieldsBits&SUPPORTS_GENRE)?IDS_GENRE:0, (fieldsBits&SUPPORTS_YEAR)?IDS_YEAR:0, (fieldsBits&SUPPORTS_ALBUMARTIST)?IDS_ALBUM_ARTIST:0, (fieldsBits&SUPPORTS_PUBLISHER)?IDS_PUBLISHER:0, (fieldsBits&SUPPORTS_COMPOSER)?IDS_COMPOSER:0, (fieldsBits&SUPPORTS_ARTIST)?IDS_ARTIST_INDEX:0, (fieldsBits&SUPPORTS_ALBUMARTIST)?IDS_ALBUM_ARTIST_INDEX:0, (fieldsBits&SUPPORTS_ALBUMART)?IDS_ALBUM_ART:0, (fieldsBits&SUPPORTS_MIMETYPE)?IDS_MIME_TYPE:0, (fieldsBits&SUPPORTS_DATEADDED)?IDS_DATE_ADDED:0, }; int numFilters = config->ReadInt(L"media_numfilters",2); CheckRadioButton(hwndDlg, IDC_RADIO_FILTERS1, IDC_RADIO_FILTERS3, (IDC_RADIO_FILTERS1 + numFilters - 1)); CheckDlgButton(hwndDlg, IDC_REMEMBER_SEARCH, config->ReadInt(L"savefilter", 1)); for(int i=0; i<3; i++) { int id = (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3); for(int j=0; j<(sizeof(filters)/sizeof(wchar_t*)); j++) { if(filters[j]) { int a = SendDlgItemMessage(hwndDlg,id,CB_ADDSTRING,0, (LPARAM)WASABI_API_LNGSTRINGW(filters_idx[j])); SendDlgItemMessage(hwndDlg,id,CB_SETITEMDATA,a,(LPARAM)filters[j]); } } wchar_t name[20] = {0}; StringCchPrintf(name,20,L"media_filter%d",i); extern wchar_t *GetDefFilter(int i,int n); SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,0,0); wchar_t* filterStr = config->ReadString(name,GetDefFilter(i,numFilters)); for(int l = 0; l < (sizeof(filters)/sizeof(wchar_t*)); l++) { wchar_t* x = (wchar_t*)SendDlgItemMessage(hwndDlg,id,CB_GETITEMDATA,l,0); if(x && x != (wchar_t*)-1 && !_wcsicmp(filterStr,x)) { SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,(WPARAM)l,0); break; } } } if(configDevice->videoView) CheckDlgButton(hwndDlg,IDC_CHECK_VIDEOVIEW,TRUE); } SendMessage(hwndDlg,WM_USER,0,0); break; case WM_USER: { BOOL full_enable = (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS1) != BST_CHECKED); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER1), full_enable); EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_FILTER2), full_enable); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER2), full_enable); BOOL enable = (IsDlgButtonChecked(hwndDlg, IDC_RADIO_FILTERS3) == BST_CHECKED) && full_enable; EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_FILTER3), enable); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER3), enable); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_RADIO_FILTERS3: case IDC_RADIO_FILTERS2: case IDC_RADIO_FILTERS1: SendMessage(hwndDlg,WM_USER,0,0); break; case IDC_CHECK_VIDEOVIEW: configDevice->SetVideoView(IsDlgButtonChecked(hwndDlg,IDC_CHECK_VIDEOVIEW)); break; case IDC_REMEMBER_SEARCH: config->WriteInt(L"savefilter", IsDlgButtonChecked(hwndDlg,IDC_REMEMBER_SEARCH)); config->WriteString(L"savedfilter", L""); config->WriteString(L"savedrefinefilter", L""); break; } break; case WM_DESTROY: { int update_needed = false; int numFilters = config->ReadInt(L"media_numfilters",2); int new_numFilters = 1; if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS1)) new_numFilters = 1; else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS2)) new_numFilters = 2; else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS3)) new_numFilters = 3; if (new_numFilters != numFilters) update_needed++; config->WriteInt(L"media_numfilters",new_numFilters); for(int i=0; i<3; i++) { int id = (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3); int sel = SendDlgItemMessage(hwndDlg, id, CB_GETCURSEL, 0, 0); wchar_t * x = (wchar_t*)SendDlgItemMessage(hwndDlg, id, CB_GETITEMDATA, sel, 0); wchar_t name[20] = {0}; StringCchPrintf(name,20,L"media_filter%d",i); extern wchar_t *GetDefFilter(int i,int n); SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,0,0); wchar_t* filterStr = config->ReadString(name,GetDefFilter(i,new_numFilters)); if(x && x != (wchar_t*)-1) { config->WriteString(name,x); update_needed += (wcscmp(filterStr, x)); } } // only refresh the view if it is one of ours (is a bit silly // otherwise) and also not refresh unless there was a change // with the configDevice check to cope with going elsewhere if (update_needed && ((configDevice && configDevice == currentViewedDevice) || IsWindow(hwndMediaView))) { PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0); } } break; } return 0; } static INT_PTR CALLBACK config_dlgproc_cloud_mediaview(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { if(lParam) config_tab_init(hwndDlg,((prefsParam*)lParam)->parent); int fieldsBits = (int)configDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0); if(!fieldsBits) fieldsBits=-1; // used to ensure that the filters will work irrespective of language in use wchar_t * filters[] = { (fieldsBits&SUPPORTS_ARTIST)?L"Artist":0, (fieldsBits&SUPPORTS_ALBUM)?L"Album":0, (fieldsBits&SUPPORTS_GENRE)?L"Genre":0, (fieldsBits&SUPPORTS_YEAR)?L"Year":0, (fieldsBits&SUPPORTS_ALBUMARTIST)?L"Album Artist":0, (fieldsBits&SUPPORTS_PUBLISHER)?L"Publisher":0, (fieldsBits&SUPPORTS_COMPOSER)?L"Composer":0, (fieldsBits&SUPPORTS_ARTIST)?L"Artist Index":0, (fieldsBits&SUPPORTS_ALBUMARTIST)?L"Album Artist Index":0, (fieldsBits&SUPPORTS_ALBUMART)?L"Album Art":0, (fieldsBits&SUPPORTS_MIMETYPE)?L"Mime":0, (fieldsBits&SUPPORTS_DATEADDED)?L"Date Added":0, }; // used for displayed items - localised crazyness, heh int filters_idx[] = { (fieldsBits&SUPPORTS_ARTIST)?IDS_ARTIST:0, (fieldsBits&SUPPORTS_ALBUM)?IDS_ALBUM:0, (fieldsBits&SUPPORTS_GENRE)?IDS_GENRE:0, (fieldsBits&SUPPORTS_YEAR)?IDS_YEAR:0, (fieldsBits&SUPPORTS_ALBUMARTIST)?IDS_ALBUM_ARTIST:0, (fieldsBits&SUPPORTS_PUBLISHER)?IDS_PUBLISHER:0, (fieldsBits&SUPPORTS_COMPOSER)?IDS_COMPOSER:0, (fieldsBits&SUPPORTS_ARTIST)?IDS_ARTIST_INDEX:0, (fieldsBits&SUPPORTS_ALBUMARTIST)?IDS_ALBUM_ARTIST_INDEX:0, (fieldsBits&SUPPORTS_ALBUMART)?IDS_ALBUM_ART:0, (fieldsBits&SUPPORTS_MIMETYPE)?IDS_MIME_TYPE:0, (fieldsBits&SUPPORTS_DATEADDED)?IDS_DATE_ADDED:0, }; int numFilters = config->ReadInt(L"media_numfilters",2); CheckRadioButton(hwndDlg, IDC_RADIO_FILTERS1, IDC_RADIO_FILTERS3, (IDC_RADIO_FILTERS1 + numFilters - 1)); CheckDlgButton(hwndDlg, IDC_REMEMBER_SEARCH, config->ReadInt(L"savefilter", 1)); for(int i=0; i<3; i++) { int id = (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3); for(int j=0; j<(sizeof(filters)/sizeof(wchar_t*)); j++) { if(filters[j]) { int a = SendDlgItemMessage(hwndDlg,id,CB_ADDSTRING,0, (LPARAM)WASABI_API_LNGSTRINGW(filters_idx[j])); SendDlgItemMessage(hwndDlg,id,CB_SETITEMDATA,a,(LPARAM)filters[j]); } } wchar_t name[20] = {0}; StringCchPrintf(name,20,L"media_filter%d",i); extern wchar_t *GetDefFilter(int i,int n); SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,0,0); wchar_t* filterStr = config->ReadString(name,GetDefFilter(i,numFilters)); for(int l = 0; l < (sizeof(filters)/sizeof(wchar_t*)); l++) { wchar_t* x = (wchar_t*)SendDlgItemMessage(hwndDlg,id,CB_GETITEMDATA,l,0); if(x && x != (wchar_t*)-1 && !_wcsicmp(filterStr,x)) { SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,(WPARAM)l,0); break; } } } } SendMessage(hwndDlg,WM_USER,0,0); break; case WM_USER: { BOOL full_enable = (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS1) != BST_CHECKED); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER1), full_enable); EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_FILTER2), full_enable); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER2), full_enable); BOOL enable = (IsDlgButtonChecked(hwndDlg, IDC_RADIO_FILTERS3) == BST_CHECKED) && full_enable; EnableWindow(GetDlgItem(hwndDlg, IDC_STATIC_FILTER3), enable); EnableWindow(GetDlgItem(hwndDlg, IDC_COMBO_FILTER3), enable); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_RADIO_FILTERS3: case IDC_RADIO_FILTERS2: case IDC_RADIO_FILTERS1: SendMessage(hwndDlg,WM_USER,0,0); break; case IDC_REMEMBER_SEARCH: config->WriteInt(L"savefilter", IsDlgButtonChecked(hwndDlg,IDC_REMEMBER_SEARCH)); config->WriteString(L"savedfilter", L""); config->WriteString(L"savedrefinefilter", L""); break; } break; case WM_DESTROY: { int update_needed = false; int numFilters = config->ReadInt(L"media_numfilters",2); int new_numFilters = 1; if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS1)) new_numFilters = 1; else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS2)) new_numFilters = 2; else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO_FILTERS3)) new_numFilters = 3; if (new_numFilters != numFilters) update_needed++; config->WriteInt(L"media_numfilters",new_numFilters); for(int i=0; i<3; i++) { int id = (i==0)?IDC_COMBO_FILTER1:((i==1)?IDC_COMBO_FILTER2:IDC_COMBO_FILTER3); int sel = SendDlgItemMessage(hwndDlg, id, CB_GETCURSEL, 0, 0); wchar_t * x = (wchar_t*)SendDlgItemMessage(hwndDlg, id, CB_GETITEMDATA, sel, 0); wchar_t name[20] = {0}; StringCchPrintf(name,20,L"media_filter%d",i); extern wchar_t *GetDefFilter(int i,int n); SendDlgItemMessage(hwndDlg,id,CB_SETCURSEL,0,0); wchar_t* filterStr = config->ReadString(name,GetDefFilter(i,new_numFilters)); if(x && x != (wchar_t*)-1) { config->WriteString(name,x); update_needed += (wcscmp(filterStr, x)); } } // only refresh the view if it is one of ours (is a bit silly // otherwise) and also not refresh unless there was a change // with the configDevice check to cope with going elsewhere if (update_needed && ((configDevice && configDevice == currentViewedDevice) || IsWindow(hwndMediaView))) { PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0); } } break; } return 0; } extern void unloadPlugin(PMPDevicePlugin *devplugin, int n=-1); extern PMPDevicePlugin * loadPlugin(wchar_t * file); HRESULT RemovePMPPlugin(LPCWSTR file, HINSTANCE hDllInstance) { if(!hDllInstance) { SHFILEOPSTRUCT op = {0}; wchar_t srcFile[MAX_PATH+1], *end; op.wFunc = FO_DELETE; StringCchCopyExW(srcFile, MAX_PATH, file, &end, 0, 0); if (end) end[1]=0; // double null terminate op.pFrom = srcFile; op.fFlags=FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_SIMPLEPROGRESS|FOF_NORECURSION|FOF_NOERRORUI|FOF_SILENT; return (!SHFileOperation(&op)? S_OK : E_FAIL); } else { wchar_t buf[1024], *ini = (wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILEW); GetModuleFileName(hDllInstance, buf, ARRAYSIZE(buf)); WritePrivateProfileString(L"winamp", L"remove_genplug", buf, ini); WritePrivateProfileString(L"winamp", L"show_prefs", L"-1", ini); PostMessage(plugin.hwndWinampParent, WM_USER, 0, IPC_RESTARTWINAMP); return S_OK; } } static bool pluginsLoaded; INT_PTR CALLBACK config_dlgproc_plugins(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { pluginsLoaded = false; link_startsubclass(hwndDlg, IDC_PLUGINVERS); { HWND listWindow = GetDlgItem(hwndDlg, IDC_PLUGINSLIST); if (NULL != listWindow) { RECT r = {0}, rc = {0}; GetWindowRect(listWindow, &r); GetClientRect(listWindow, &r); MapWindowPoints(listWindow, hwndDlg, (LPPOINT)&r, 2); InflateRect(&r, 2, 2); DestroyWindow(listWindow); listWindow = CreateWindowEx(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER, r.left, r.top, r.right - r.left, r.bottom - r.top, hwndDlg, (HMENU)IDC_PLUGINSLIST, NULL, NULL); SetWindowPos(listWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); SendMessage(listWindow, WM_SETFONT, SendMessage(hwndDlg, WM_GETFONT, 0, 0), FALSE); LVCOLUMNW lvc = {0}; ListView_InsertColumn(listWindow, 0, &lvc); ListView_InsertColumn(listWindow, 1, &lvc); wchar_t buf[1024] = {0}, fn[MAX_PATH] = {0}; for (int x = 0; x < m_plugins.GetSize(); x ++) { PMPDevicePlugin * devplugin=(PMPDevicePlugin *)m_plugins.Get(x); if (devplugin) { GetModuleFileNameW(devplugin->hDllInstance, fn, MAX_PATH); PathStripPath(fn); LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, x, 0}; lvi.pszText = devplugin->description; lvi.lParam = x; lvi.iItem = ListView_InsertItem(listWindow, &lvi); lvi.mask = LVIF_TEXT; lvi.iSubItem = 1; lvi.pszText = fn; ListView_SetItem(listWindow, &lvi); } } WIN32_FIND_DATA d = {0}; wchar_t *pluginPath = (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW); wchar_t dirstr[MAX_PATH] = {0}; PathCombine(dirstr, pluginPath, L"PMP_*.DLL"); HANDLE h = FindFirstFile(dirstr, &d); if (h != INVALID_HANDLE_VALUE) { do { PathCombine(dirstr, pluginPath, d.cFileName); HMODULE b = LoadLibraryEx(dirstr, NULL, LOAD_LIBRARY_AS_DATAFILE); int x = 0; for (; b && (x != m_plugins.GetSize()); x ++) { PMPDevicePlugin *devplugin = (PMPDevicePlugin *)m_plugins.Get(x); if (devplugin->hDllInstance == b) { break; } } if (x == m_plugins.GetSize() || !b) { LVITEMW lvi = {LVIF_TEXT | LVIF_PARAM, x, 0}; lvi.pszText = d.cFileName; lvi.lParam = -2; lvi.iItem = ListView_InsertItem(listWindow, &lvi); lvi.mask = LVIF_TEXT; lvi.iSubItem = 1; lvi.pszText = WASABI_API_LNGSTRINGW(IDS_NOT_LOADED); ListView_SetItem(listWindow, &lvi); } FreeLibrary(b); } while (FindNextFile(h, &d)); FindClose(h); } GetClientRect(listWindow, &r); ListView_SetColumnWidth(listWindow, 1, LVSCW_AUTOSIZE); ListView_SetColumnWidth(listWindow, 0, (r.right - r.left) - ListView_GetColumnWidth(listWindow, 1)); if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(listWindow, TRUE); pluginsLoaded = true; } } break; } case WM_NOTIFY: { LPNMHDR p = (LPNMHDR)lParam; if (p->idFrom == IDC_PLUGINSLIST) { if (p->code == LVN_ITEMCHANGED) { LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; LVITEM lvi = {LVIF_PARAM, pnmv->iItem}; if (ListView_GetItem(p->hwndFrom, &lvi) && (pnmv->uNewState & LVIS_SELECTED)) { int loaded = (lvi.lParam != -2); if (loaded) { PMPDevicePlugin *devplugin; if (lvi.lParam >= 0 && lvi.lParam < m_plugins.GetSize() && (devplugin = (PMPDevicePlugin *)m_plugins.Get(lvi.lParam))) { // enables / disables the config button as applicable instead of the // "This plug-in has no configuration implemented" message (opt-in) EnableWindow(GetDlgItem(hwndDlg, IDC_CONFIGPLUGIN), (!devplugin->MessageProc(PMP_NO_CONFIG, 0, 0, 0))); } } else { EnableWindow(GetDlgItem(hwndDlg, IDC_CONFIGPLUGIN), 0); } EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTALLPLUGIN), 1); } else { EnableWindow(GetDlgItem(hwndDlg, IDC_CONFIGPLUGIN), 0); EnableWindow(GetDlgItem(hwndDlg, IDC_UNINSTALLPLUGIN), 0); } } else if (p->code == NM_DBLCLK) { PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CONFIGPLUGIN, 0), (LPARAM)GetDlgItem(hwndDlg, IDC_CONFIGPLUGIN)); } } else if (p->code == HDN_ITEMCHANGINGW) { if (pluginsLoaded) { #if defined(_WIN64) SetWindowLong(hwndDlg, DWLP_MSGRESULT, TRUE); #else SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE); #endif return TRUE; } } break; } case WM_DESTROY: { HWND listWindow = GetDlgItem(hwndDlg, IDC_PLUGINSLIST); if (IsWindow(listWindow) && (NULL != WASABI_API_APP)) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(listWindow, FALSE); } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_CONFIGPLUGIN: { if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CONFIGPLUGIN))) { HWND listWindow = GetDlgItem(hwndDlg, IDC_PLUGINSLIST); LVITEM lvi = {LVIF_PARAM, ListView_GetSelectionMark(listWindow)}; if (ListView_GetItem(listWindow, &lvi)) { PMPDevicePlugin *devplugin; if(lvi.lParam >= 0 && lvi.lParam < m_plugins.GetSize() && (devplugin=(PMPDevicePlugin *)m_plugins.Get(lvi.lParam))) { if(devplugin->MessageProc(PMP_CONFIG,(intptr_t)hwndDlg,0,0) == 0) { wchar_t titleStr[64] = {0}; MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_PLUGIN_HAS_NO_CONFIG_IMPLEMENTED), WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_PLUGINS,titleStr,64),0); } } } } } break; case IDC_UNINSTALLPLUGIN: { if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_UNINSTALLPLUGIN))) { HWND listWindow = GetDlgItem(hwndDlg, IDC_PLUGINSLIST); int which_sel = ListView_GetSelectionMark(listWindow); LVITEM lvi = {LVIF_PARAM, which_sel}; if (ListView_GetItem(listWindow, &lvi)) { PMPDevicePlugin *devplugin = 0; wchar_t titleStr[32] = {0}; int msgBox = MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_PERMANENTLY_UNINSTALL_THIS_PLUGIN), WASABI_API_LNGSTRINGW_BUF(IDS_CONFIRMATION, titleStr, 32), MB_YESNO | MB_ICONEXCLAMATION); if (lvi.lParam >= 0 && lvi.lParam <= m_plugins.GetSize() && (devplugin=(PMPDevicePlugin *)m_plugins.Get(lvi.lParam)) && msgBox == IDYES) { wchar_t buf[1024] = {0}; GetModuleFileName(devplugin->hDllInstance,buf,sizeof(buf)/sizeof(wchar_t)); int ret = PMP_PLUGIN_UNINSTALL_NOW; int (*pr)(HINSTANCE hDllInst, HWND hwndDlg, int param); *(void**)&pr = (void*)GetProcAddress(devplugin->hDllInstance,"winampUninstallPlugin"); if(pr) ret = pr(devplugin->hDllInstance,hwndDlg,0); if(pr && ret == PMP_PLUGIN_UNINSTALL_NOW) { // dynamic unload ListView_DeleteItem(listWindow, lvi.lParam); unloadPlugin(devplugin,lvi.lParam); // removing the plugin (bit convoluted to hopefully not cause crashes with dynamic removal) // try to use the elevator to do this IFileTypeRegistrar *registrar = (IFileTypeRegistrar*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT); if(registrar && (registrar != (IFileTypeRegistrar*)1)) { if(registrar->DeleteItem(buf) != S_OK) { // we don't always free by default as it can cause some crashes FreeLibrary(devplugin->hDllInstance); if(registrar->DeleteItem(buf) != S_OK) { // all gone wrong so non-dynamic unload (restart winamp) RemovePMPPlugin(buf, devplugin->hDllInstance); } } registrar->Release(); } // otherwise revert to a standard method else { if(RemovePMPPlugin(buf, 0) != S_OK){ // we don't always free by default as it can cause some crashes FreeLibrary(devplugin->hDllInstance); if(RemovePMPPlugin(buf, 0) != S_OK) { // all gone wrong so non-dynamic unload (restart winamp) RemovePMPPlugin(buf, devplugin->hDllInstance); } } } } else if(!pr) { // non-dynamic unload (restart winamp) RemovePMPPlugin(buf,devplugin->hDllInstance); } } // will cope with not loaded plug-ins so we can still remove them, etc else if (lvi.lParam == -2 && msgBox == IDYES) { wchar_t buf[1024] = {0}, base[1024] = {0}; GetModuleFileName(plugin.hDllInstance,base,sizeof(base)/sizeof(wchar_t)); LVITEM lvi = {LVIF_TEXT, which_sel}; lvi.pszText = buf; lvi.cchTextMax = ARRAYSIZE(buf); ListView_GetItem(listWindow, &lvi); wchar_t *p = wcschr(buf, L'.'); if (p && *p == L'.') { p += 4; *p = 0; PathRemoveFileSpec(base); PathAppend(base, buf); } // try to use the elevator to do this IFileTypeRegistrar *registrar = (IFileTypeRegistrar*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT); if(registrar && (registrar != (IFileTypeRegistrar*)1)) { if(registrar->DeleteItem(base) != S_OK){ RemovePMPPlugin(base, 0); } else ListView_DeleteItem(listWindow, which_sel); registrar->Release(); } // otherwise revert to a standard method else { RemovePMPPlugin(base, 0); } } // resets the focus to the listbox so it'll keep ui response working SetFocus(GetDlgItem(hwndDlg, IDC_PLUGINSLIST)); } } } break; case IDC_PLUGINVERS: myOpenURLWithFallback(hwndDlg, L"http://www.google.com/search?q=Winamp+Portable+Plugins",L"http://www.google.com/search?q=Winamp+Portable+Plugins"); break; } break; } link_handledraw(hwndDlg,uMsg,wParam,lParam); return 0; } void myOpenURLWithFallback(HWND hwnd, wchar_t *loc, wchar_t *fallbackLoc) { bool override=false; if (loc) { WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override)); } if (!override && fallbackLoc) ShellExecuteW(hwnd, L"open", fallbackLoc, NULL, NULL, SW_SHOWNORMAL); } static HCURSOR link_hand_cursor; LRESULT link_handlecursor(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT ret = CallWindowProcW((WNDPROC)GetPropW(hwndDlg, L"link_proc"), hwndDlg, uMsg, wParam, lParam); // override the normal cursor behaviour so we have a hand to show it is a link if(uMsg == WM_SETCURSOR) { if((HWND)wParam == hwndDlg) { if(!link_hand_cursor) { link_hand_cursor = LoadCursor(NULL, IDC_HAND); } SetCursor(link_hand_cursor); return TRUE; } } return ret; } void link_startsubclass(HWND hwndDlg, UINT id){ HWND ctrl = GetDlgItem(hwndDlg, id); SetPropW(ctrl, L"link_proc", (HANDLE)SetWindowLongPtrW(ctrl, GWLP_WNDPROC, (LONG_PTR)link_handlecursor)); } static void link_handledraw(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_DRAWITEM) { DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam; if (di->CtlType == ODT_BUTTON) { wchar_t wt[123] = {0}; int y; RECT r; HPEN hPen, hOldPen; GetDlgItemText(hwndDlg, wParam, wt, sizeof(wt)/sizeof(wchar_t)); // draw text SetTextColor(di->hDC, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220)); r = di->rcItem; r.left += 2; DrawText(di->hDC, wt, -1, &r, DT_VCENTER | DT_SINGLELINE); memset(&r, 0, sizeof(r)); DrawText(di->hDC, wt, -1, &r, DT_SINGLELINE | DT_CALCRECT); // draw underline y = di->rcItem.bottom - ((di->rcItem.bottom - di->rcItem.top) - (r.bottom - r.top)) / 2 - 1; hPen = CreatePen(PS_SOLID, 0, (di->itemState & ODS_SELECTED) ? RGB(220, 0, 0) : RGB(0, 0, 220)); hOldPen = (HPEN) SelectObject(di->hDC, hPen); MoveToEx(di->hDC, di->rcItem.left + 2, y, NULL); LineTo(di->hDC, di->rcItem.right + 2 - ((di->rcItem.right - di->rcItem.left) - (r.right - r.left)), y); SelectObject(di->hDC, hOldPen); DeleteObject(hPen); } } }