view.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512
  1. #include "main.h"
  2. #include "../nu/AutoCharFn.h"
  3. #include "../nu/DialogSkinner.h"
  4. #include "Bookmark.h"
  5. #include "../../General/gen_ml/ml_ipc.h"
  6. #include <string>
  7. #include "../nu/ListView.h"
  8. #include "../nu/AutoChar.h"
  9. #include "../nu/AutoWide.h"
  10. #include "../nu/menushortcuts.h"
  11. #include <strsafe.h>
  12. #include "../../General/gen_ml/menu.h"
  13. INT_PTR CALLBACK view_bmDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
  14. static W_ListView m_bmlist;
  15. static HWND m_headerhwnd, m_hwnd;
  16. extern C_Config *g_config;
  17. static int customAllowed, groupBtn = 1, enqueuedef;
  18. static viewButtons view;
  19. // used for the send-to menu bits
  20. static INT_PTR IPC_LIBRARY_SENDTOMENU;
  21. static librarySendToMenuStruct s;
  22. BOOL myMenu = FALSE;
  23. extern HMENU g_context_menus, g_context_menus2;
  24. extern HCURSOR hDragNDropCursor;
  25. static int bookmark_contextMenu( INT_PTR param1, HWND parent, POINTS pts );
  26. static void bookmarks_contextMenu( HWND hwndDlg, HWND from, int x, int y );
  27. static void bookmark_onTreeEnterDblClk();
  28. static int pluginHandleIpcMessage(int msg, int param)
  29. {
  30. return (int)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, param, msg);
  31. }
  32. void bookmark_notifyAdd(wchar_t *filenametitle)
  33. {
  34. if (!m_hwnd || !filenametitle) return;
  35. int cnt=m_bmlist.GetCount();
  36. m_bmlist.InsertItem(cnt,filenametitle+lstrlenW(filenametitle)+1,0);
  37. m_bmlist.SetItemText(cnt,1,filenametitle);
  38. }
  39. INT_PTR bm_pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  40. {
  41. if (message_type == ML_MSG_NO_CONFIG)
  42. {
  43. return TRUE;
  44. }
  45. else if (message_type == ML_MSG_TREE_ONCLICK)
  46. {
  47. switch(param2)
  48. {
  49. case ML_ACTION_ENTER:
  50. case ML_ACTION_DBLCLICK:
  51. if (param1 == bookmark_treeItem)
  52. bookmark_onTreeEnterDblClk();
  53. break;
  54. }
  55. }
  56. else if (message_type == ML_MSG_TREE_ONCREATEVIEW && param1 == bookmark_treeItem)
  57. {
  58. return (INT_PTR)WASABI_API_CREATEDIALOGW(IDD_VIEW_BM, (HWND)param2, view_bmDialogProc);
  59. }
  60. else if (message_type == ML_MSG_NAVIGATION_CONTEXTMENU)
  61. {
  62. return bookmark_contextMenu(param1, (HWND)param2, MAKEPOINTS(param3));
  63. }
  64. else if (message_type == ML_MSG_ONSENDTOBUILD)
  65. {
  66. if (!myMenu &&
  67. (param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_ITEMRECORDLIST ||
  68. param1 == ML_TYPE_FILENAMES || param1 == ML_TYPE_STREAMNAMES ||
  69. param1 == ML_TYPE_FILENAMESW || param1 == ML_TYPE_STREAMNAMESW ||
  70. param1 == ML_TYPE_CDTRACKS))
  71. mediaLibrary.AddToSendTo(WASABI_API_LNGSTRINGW(IDS_ADD_TO_BOOKMARKS),
  72. param2, (INT_PTR)bm_pluginMessageProc);
  73. }
  74. else if (message_type == ML_MSG_ONSENDTOSELECT || message_type == ML_MSG_TREE_ONDROPTARGET)
  75. {
  76. // set with droptarget defaults =)
  77. UINT_PTR type = 0,data = 0;
  78. if (message_type == ML_MSG_ONSENDTOSELECT)
  79. {
  80. if (param3 != (INT_PTR)bm_pluginMessageProc) return 0;
  81. type=(int)param1;
  82. data = (int)param2;
  83. }
  84. else
  85. {
  86. if (param1 != bookmark_treeItem) return 0;
  87. type=(int)param2;
  88. data=(int)param3;
  89. if (!data)
  90. {
  91. return (type == ML_TYPE_ITEMRECORDLISTW || type == ML_TYPE_ITEMRECORDLIST ||
  92. type == ML_TYPE_FILENAMES || type == ML_TYPE_STREAMNAMES ||
  93. type == ML_TYPE_FILENAMESW || type == ML_TYPE_STREAMNAMESW ||
  94. type == ML_TYPE_CDTRACKS ||
  95. type == ML_TYPE_PLAYLIST || type == ML_TYPE_PLAYLISTS) ? 1 : -1;
  96. }
  97. }
  98. if (data)
  99. {
  100. if (type == ML_TYPE_ITEMRECORDLIST || type == ML_TYPE_CDTRACKS)
  101. {
  102. itemRecordList *p=(itemRecordList*)data;
  103. for (int x = 0; x < p->Size; x ++)
  104. mediaLibrary.AddBookmarkW(AutoWide(p->Items[x].filename));
  105. return 1;
  106. }
  107. else if (type == ML_TYPE_ITEMRECORDLISTW)
  108. {
  109. itemRecordListW *p=(itemRecordListW *)data;
  110. for (int x = 0; x < p->Size; x ++)
  111. mediaLibrary.AddBookmarkW(p->Items[x].filename);
  112. return 1;
  113. }
  114. else if (type == ML_TYPE_FILENAMES || type == ML_TYPE_STREAMNAMES)
  115. {
  116. char *p=(char*)data;
  117. while (p && *p)
  118. {
  119. mediaLibrary.AddBookmark(p);
  120. p+=lstrlenA(p)+1;
  121. }
  122. return 1;
  123. }
  124. else if (type == ML_TYPE_FILENAMESW || type == ML_TYPE_STREAMNAMESW)
  125. {
  126. wchar_t *p=(wchar_t*)data;
  127. while (p && *p)
  128. {
  129. mediaLibrary.AddBookmarkW(p);
  130. p+=wcslen(p)+1;
  131. }
  132. return 1;
  133. }
  134. else if(type == ML_TYPE_PLAYLIST)
  135. {
  136. mediaLibrary.AddBookmarkW((wchar_t*)((mlPlaylist*)data)->filename);
  137. return 1;
  138. }
  139. else if(type == ML_TYPE_PLAYLISTS)
  140. {
  141. mlPlaylist **playlists = (mlPlaylist **)data;
  142. while (playlists && *playlists)
  143. {
  144. mlPlaylist *pl = *playlists;
  145. mediaLibrary.AddBookmarkW((wchar_t*)pl->filename);
  146. playlists++;
  147. }
  148. return 1;
  149. }
  150. }
  151. }
  152. else if (message_type == ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE)
  153. {
  154. enqueuedef = (int)param1;
  155. groupBtn = (int)param2;
  156. PostMessage(m_hwnd, WM_APP + 104, param1, param2);
  157. return 0;
  158. }
  159. return 0;
  160. }
  161. static void playFiles(int enqueue, int all)
  162. {
  163. int cnt=0;
  164. int l=m_bmlist.GetCount();
  165. for(int i=0;i<l;i++)
  166. {
  167. if(all || m_bmlist.GetSelected(i))
  168. {
  169. if (!cnt)
  170. {
  171. if(!enqueue) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
  172. cnt++;
  173. }
  174. //send the file to winamp
  175. COPYDATASTRUCT cds = {0};
  176. cds.dwData = IPC_ENQUEUEFILEW;
  177. wchar_t buf[1024] = {0};
  178. m_bmlist.GetText(i,1,buf,sizeof(buf)-1);
  179. buf[1023]=0;
  180. cds.lpData = (void *) buf;
  181. cds.cbData = (lstrlenW((wchar_t*)cds.lpData)+1)*sizeof(wchar_t); // include space for null char
  182. SendMessage(plugin.hwndWinampParent,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
  183. }
  184. }
  185. if (cnt)
  186. {
  187. if(!enqueue) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_STARTPLAY);
  188. }
  189. }
  190. static wchar_t *g_bmedit_fn, *g_bmedit_ft;
  191. static BOOL CALLBACK BookMarkEditProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  192. {
  193. switch (uMsg)
  194. {
  195. case WM_INITDIALOG:
  196. SetDlgItemTextW(hwndDlg,IDC_TITLE,g_bmedit_ft);
  197. SetDlgItemTextW(hwndDlg,IDC_FILE,g_bmedit_fn);
  198. return 0;
  199. case WM_COMMAND:
  200. switch (LOWORD(wParam))
  201. {
  202. case IDOK:
  203. GetDlgItemTextW(hwndDlg,IDC_TITLE,g_bmedit_ft,1024);
  204. GetDlgItemTextW(hwndDlg,IDC_FILE,g_bmedit_fn,1024);
  205. case IDCANCEL:
  206. EndDialog(hwndDlg,0);
  207. return 0;
  208. case IDC_EDIT_FN:
  209. {
  210. wchar_t fn[1024] = {0};
  211. GetDlgItemTextW(hwndDlg,IDC_FILE,fn,1024);
  212. OPENFILENAMEW of = {0};
  213. of.lStructSize = sizeof(OPENFILENAMEW);
  214. of.hwndOwner = hwndDlg;
  215. of.nMaxFileTitle = 32;
  216. of.lpstrFilter = (wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,1,IPC_GET_EXTLISTW);
  217. of.nMaxCustFilter = 1024;
  218. of.lpstrFile = fn;
  219. of.nMaxFile = 1024;
  220. of.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_BROWSE_FOR_BM_ENTRY);
  221. of.Flags = OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_EXPLORER|
  222. OFN_PATHMUSTEXIST|OFN_ENABLESIZING;
  223. if(GetOpenFileNameW(&of))
  224. {
  225. SetDlgItemTextW(hwndDlg,IDC_FILE,fn);
  226. }
  227. GlobalFree((void*)of.lpstrFilter);
  228. }
  229. break;
  230. }
  231. return 0;
  232. }
  233. return 0;
  234. }
  235. static void readbookmarks(int play1enqueue2=0)
  236. {
  237. if (!play1enqueue2) m_bmlist.Clear();
  238. int x=0;
  239. FILE *fp=NULL;
  240. wchar_t *fnp=(wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,666,IPC_ADDBOOKMARKW);
  241. if ((unsigned int)fnp < 65536) return;
  242. fp=_wfopen(fnp,L"rt");
  243. if (fp)
  244. {
  245. while (1)
  246. {
  247. char ft[4096] = {0}, fn[4096] = {0};
  248. fgets(fn,4096,fp);
  249. if (feof(fp)) break;
  250. fgets(ft,4096,fp);
  251. if (feof(fp)) break;
  252. if (ft[0] && fn[0])
  253. {
  254. if (fn[strlen(fn)-1]=='\n') fn[strlen(fn)-1]=0;
  255. if (ft[strlen(ft)-1]=='\n') ft[strlen(ft)-1]=0;
  256. if (ft[0] && fn[0])
  257. {
  258. if (!play1enqueue2)
  259. {
  260. m_bmlist.InsertItem(x,AutoWide(ft,CP_UTF8),0);
  261. m_bmlist.SetItemText(x,1,AutoWide(fn,CP_UTF8));
  262. }
  263. else
  264. {
  265. if (!x)
  266. {
  267. if(play1enqueue2==1) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
  268. }
  269. //send the file to winamp
  270. COPYDATASTRUCT cds = {0};
  271. cds.dwData = IPC_ENQUEUEFILEW;
  272. cds.lpData = (void *)AutoWideDup(fn,CP_UTF8);
  273. cds.cbData = (lstrlenW((wchar_t *) cds.lpData)+1)*sizeof(wchar_t); // include space for null char
  274. SendMessage(plugin.hwndWinampParent,WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds);
  275. }
  276. x++;
  277. }
  278. }
  279. }
  280. fclose(fp);
  281. }
  282. if (!play1enqueue2 && AGAVE_API_STATS)
  283. {
  284. AGAVE_API_STATS->SetStat(api_stats::BOOKMARK_COUNT, m_bmlist.GetCount());
  285. }
  286. if (x && play1enqueue2 == 1)
  287. {
  288. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_STARTPLAY);
  289. }
  290. }
  291. static void writebookmarks()
  292. {
  293. wchar_t *fnp = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 666, IPC_ADDBOOKMARKW );
  294. if ( (unsigned int)fnp < 65536 )
  295. return;
  296. BookmarkWriter bookmarks;
  297. bookmarks.New( fnp );
  298. int l = m_bmlist.GetCount();
  299. for ( int x = 0; x < l; x++ )
  300. {
  301. wchar_t ftW[ 4096 ] = { 0 }, fnW[ 4096 ] = { 0 };
  302. m_bmlist.GetText( x, 0, ftW, ARRAYSIZE( ftW ) );
  303. m_bmlist.GetText( x, 1, fnW, ARRAYSIZE( fnW ) );
  304. bookmarks.Write( AutoChar( fnW, CP_UTF8 ), AutoChar( ftW, CP_UTF8 ) );
  305. }
  306. bookmarks.Close();
  307. fnp = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_ADDBOOKMARKW );
  308. if ( (unsigned int)fnp < 65536 )
  309. return;
  310. bookmarks.New( fnp );
  311. for ( int x = 0; x < l; x++ )
  312. {
  313. char ft[ 4096 ] = { 0 }, fn[ 4096 ] = { 0 };
  314. m_bmlist.GetText( x, 0, ft, sizeof( ft ) );
  315. m_bmlist.GetText( x, 1, fn, sizeof( fn ) );
  316. bookmarks.Write( fn, ft );
  317. }
  318. bookmarks.Close();
  319. }
  320. static void bookmark_onTreeEnterDblClk()
  321. {
  322. int enq = ( ( !!( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ) ^ ( !!g_config->ReadInt( L"enqueuedef", 0 ) ) );
  323. readbookmarks( enq ? 2 : 1 );
  324. }
  325. void SyncMenuWithAccelerators(HWND hwndDlg, HMENU menu)
  326. {
  327. HACCEL szAccel[24] = {0};
  328. INT c = WASABI_API_APP->app_getAccelerators(hwndDlg, szAccel, sizeof(szAccel)/sizeof(szAccel[0]), FALSE);
  329. AppendMenuShortcuts(menu, szAccel, c, MSF_REPLACE);
  330. }
  331. void SwapPlayEnqueueInMenu(HMENU listMenu)
  332. {
  333. int playPos=-1, enqueuePos=-1;
  334. MENUITEMINFOW playItem={sizeof(MENUITEMINFOW), 0,}, enqueueItem={sizeof(MENUITEMINFOW), 0,};
  335. int numItems = GetMenuItemCount(listMenu);
  336. for (int i=0;i<numItems;i++)
  337. {
  338. UINT id = GetMenuItemID(listMenu, i);
  339. if (id == ID_BMWND_PLAYSELECTEDFILES)
  340. {
  341. playItem.fMask = MIIM_ID;
  342. playPos = i;
  343. GetMenuItemInfoW(listMenu, i, TRUE, &playItem);
  344. }
  345. else if (id == ID_BMWND_ENQUEUESELECTEDFILES)
  346. {
  347. enqueueItem.fMask = MIIM_ID;
  348. enqueuePos= i;
  349. GetMenuItemInfoW(listMenu, i, TRUE, &enqueueItem);
  350. }
  351. }
  352. playItem.wID = ID_BMWND_ENQUEUESELECTEDFILES;
  353. enqueueItem.wID = ID_BMWND_PLAYSELECTEDFILES;
  354. SetMenuItemInfoW(listMenu, playPos, TRUE, &playItem);
  355. SetMenuItemInfoW(listMenu, enqueuePos, TRUE, &enqueueItem);
  356. }
  357. void UpdateMenuItems(HWND hwndDlg, HMENU menu)
  358. {
  359. bool swapPlayEnqueue=false;
  360. if (g_config->ReadInt(L"enqueuedef", 0) == 1)
  361. {
  362. SwapPlayEnqueueInMenu(menu);
  363. swapPlayEnqueue=true;
  364. }
  365. SyncMenuWithAccelerators(hwndDlg, menu);
  366. if (swapPlayEnqueue) SwapPlayEnqueueInMenu(menu);
  367. }
  368. static int bookmark_contextMenu(INT_PTR param1, HWND hHost, POINTS pts)
  369. {
  370. HNAVITEM hItem = (HNAVITEM)param1;
  371. HNAVITEM myItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent, bookmark_treeItem);
  372. if (hItem != myItem)
  373. return FALSE;
  374. POINT pt;
  375. POINTSTOPOINT(pt, pts);
  376. if (-1 == pt.x || -1 == pt.y)
  377. {
  378. NAVITEMGETRECT itemRect;
  379. itemRect.fItem = FALSE;
  380. itemRect.hItem = hItem;
  381. if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect))
  382. {
  383. MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2);
  384. pt.x = itemRect.rc.left + 2;
  385. pt.y = itemRect.rc.top + 2;
  386. }
  387. }
  388. HMENU menu=GetSubMenu(g_context_menus,1);
  389. bool swapPlayEnqueue=false;
  390. if (g_config->ReadInt(L"enqueuedef", 0) == 1)
  391. {
  392. SwapPlayEnqueueInMenu(menu);
  393. swapPlayEnqueue=true;
  394. }
  395. if(!IsWindow(m_hwnd))
  396. {
  397. HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_VIEW_BM_ACCELERATORS);
  398. int size = CopyAcceleratorTable(accel,0,0);
  399. AppendMenuShortcuts(menu, &accel, size, MSF_REPLACE);
  400. }
  401. else
  402. {
  403. SyncMenuWithAccelerators(m_hwnd, menu);
  404. }
  405. if (swapPlayEnqueue)
  406. SwapPlayEnqueueInMenu(menu);
  407. int r = Menu_TrackPopup(plugin.hwndLibraryParent, menu,
  408. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY,
  409. pt.x, pt.y, hHost, NULL);
  410. switch(r)
  411. {
  412. case ID_BMWND_PLAYSELECTEDFILES:
  413. readbookmarks(1);
  414. break;
  415. case ID_BMWND_ENQUEUESELECTEDFILES:
  416. readbookmarks(2);
  417. break;
  418. case ID_BMWND_HELP:
  419. SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8105304048660-The-Winamp-Media-Library");
  420. break;
  421. }
  422. Sleep(100);
  423. MSG msg;
  424. while(PeekMessage(&msg,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE)); //eat return
  425. return TRUE;
  426. }
  427. static void bookmarks_contextMenu(HWND hwndDlg, HWND from, int x, int y)
  428. {
  429. if (from != m_bmlist.getwnd())
  430. return ;
  431. POINT pt = {x,y};
  432. if (x == -1 || y == -1) // x and y are -1 if the user invoked a shift-f10 popup menu
  433. {
  434. RECT itemRect = {0};
  435. int selected = m_bmlist.GetNextSelected();
  436. if (selected != -1) // if something is selected we'll drop the menu from there
  437. {
  438. m_bmlist.GetItemRect(selected, &itemRect);
  439. ClientToScreen(hwndDlg, (POINT *)&itemRect);
  440. }
  441. else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location
  442. {
  443. GetWindowRect(hwndDlg, &itemRect);
  444. HWND hHeader = (HWND)SNDMSG(from, LVM_GETHEADER, 0, 0L);
  445. RECT headerRect;
  446. if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect))
  447. {
  448. itemRect.top += (headerRect.bottom - headerRect.top);
  449. }
  450. }
  451. x = itemRect.left;
  452. y = itemRect.top;
  453. }
  454. HWND hHeader = (HWND)SNDMSG(from, LVM_GETHEADER, 0, 0L);
  455. RECT headerRect;
  456. if (0 == (WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) || FALSE == GetWindowRect(hHeader, &headerRect))
  457. {
  458. SetRectEmpty(&headerRect);
  459. }
  460. if (FALSE != PtInRect(&headerRect, pt))
  461. {
  462. return;
  463. }
  464. HMENU menu=GetSubMenu(g_context_menus,0);
  465. UpdateMenuItems(hwndDlg, menu);
  466. ZeroMemory(&s, sizeof(librarySendToMenuStruct));
  467. IPC_LIBRARY_SENDTOMENU = (INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&"LibrarySendToMenu",IPC_REGISTER_WINAMP_IPCMESSAGE);
  468. if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)0,IPC_LIBRARY_SENDTOMENU)==0xffffffff)
  469. {
  470. s.mode = 1;
  471. s.hwnd = hwndDlg;
  472. s.data_type = ML_TYPE_FILENAMESW;
  473. s.ctx[1] = 1;
  474. s.build_hMenu = CreatePopupMenu();
  475. MENUITEMINFOW mii = {0};
  476. mii.cbSize = sizeof(MENUITEMINFOW);
  477. mii.fMask = MIIM_SUBMENU;
  478. mii.hSubMenu = s.build_hMenu;
  479. SetMenuItemInfoW(menu, 2, TRUE, &mii);
  480. }
  481. UINT menuStatus;
  482. if (m_bmlist.GetNextSelected(-1) == -1)
  483. {
  484. menuStatus = MF_BYCOMMAND | MF_GRAYED;
  485. EnableMenuItem(menu, 2, MF_BYPOSITION | MF_GRAYED);
  486. }
  487. else
  488. {
  489. menuStatus = MF_BYCOMMAND | MF_ENABLED;
  490. EnableMenuItem(menu, 2, MF_BYPOSITION | MF_ENABLED);
  491. }
  492. EnableMenuItem(menu, ID_BMWND_PLAYSELECTEDFILES, menuStatus);
  493. EnableMenuItem(menu, ID_BMWND_ENQUEUESELECTEDFILES, menuStatus);
  494. EnableMenuItem(menu, ID_BMWND_REMOVESELECTEDBOOKMARKS, menuStatus);
  495. EnableMenuItem(menu, ID_BMWND_EDITSELECTEDBOOKMARKS, menuStatus);
  496. int r = Menu_TrackPopup(plugin.hwndLibraryParent, menu,
  497. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
  498. x, y, hwndDlg, NULL);
  499. switch(LOWORD(r))
  500. {
  501. case ID_BMWND_PLAYSELECTEDFILES:
  502. case ID_BMWND_ENQUEUESELECTEDFILES:
  503. case ID_BMWND_REMOVESELECTEDBOOKMARKS:
  504. case ID_BMWND_EDITSELECTEDBOOKMARKS:
  505. case ID_BMWND_SELECTALL:
  506. SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(r,0),0);
  507. break;
  508. default:
  509. if (s.mode == 2)
  510. {
  511. s.menu_id = r;
  512. if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU) == 0xffffffff)
  513. {
  514. s.mode=3;
  515. s.data_type=ML_TYPE_FILENAMESW;
  516. //std::vector<wchar_t> sendStr;
  517. std::wstring sendStr;
  518. int l=m_bmlist.GetCount();
  519. for(int i=0;i<l;i++)
  520. {
  521. if (m_bmlist.GetSelected(i))
  522. {
  523. wchar_t buf[1023] = {0};
  524. m_bmlist.GetText(i,1,buf,ARRAYSIZE(buf)-1);
  525. // HAKAN: why (len + 1) ?
  526. //sendStr.append(buf, wcslen(buf)+1);
  527. sendStr.append(buf, wcslen(buf));
  528. }
  529. }
  530. // HAKAN: No need to add trailing zero
  531. //sendStr.push_back(0);
  532. s.data = (void*)sendStr.c_str();
  533. if(SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s,IPC_LIBRARY_SENDTOMENU)!=1)
  534. {
  535. s.mode=3;
  536. s.data_type=ML_TYPE_FILENAMES;
  537. //std::vector<char> sendStrA;
  538. std::string sendStrA;
  539. int l=m_bmlist.GetCount();
  540. for(int i=0;i<l;i++)
  541. {
  542. if (m_bmlist.GetSelected(i))
  543. {
  544. wchar_t buf[1023] = {0};
  545. m_bmlist.GetText(i,1,buf,ARRAYSIZE(buf)-1);
  546. // HAKAN: why (len + 1) ?
  547. //sendStrA.append(AutoCharFn(buf), strlen(AutoCharFn(buf)) + 1);
  548. sendStrA.append(AutoCharFn(buf), strlen(AutoCharFn(buf)));
  549. }
  550. }
  551. // HAKAN: No need to add trailing zero
  552. //sendStrA.push_back(0);
  553. s.data = (void*)sendStrA.c_str();
  554. SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s,IPC_LIBRARY_SENDTOMENU);
  555. }
  556. }
  557. }
  558. break;
  559. }
  560. if (s.mode)
  561. {
  562. s.mode=4;
  563. SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&s,IPC_LIBRARY_SENDTOMENU); // cleanup
  564. }
  565. if (NULL != s.build_hMenu)
  566. {
  567. DestroyMenu(s.build_hMenu);
  568. s.build_hMenu = NULL;
  569. }
  570. Sleep(100);
  571. MSG msg;
  572. while(PeekMessage(&msg,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE)); //eat return
  573. }
  574. static HRGN g_rgnUpdate = NULL;
  575. static int offsetX = 0, offsetY = 0;
  576. typedef struct _LAYOUT
  577. {
  578. INT id;
  579. HWND hwnd;
  580. INT x;
  581. INT y;
  582. INT cx;
  583. INT cy;
  584. DWORD flags;
  585. HRGN rgn;
  586. }
  587. LAYOUT, PLAYOUT;
  588. #define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; }
  589. #define SETLAYOUTFLAGS(_layout, _r) \
  590. { \
  591. BOOL fVis; \
  592. fVis = (WS_VISIBLE & (LONG)GetWindowLongPtr(_layout->hwnd, GWL_STYLE)); \
  593. if (_layout->x == _r.left && _layout->y == _r.top) _layout->flags |= SWP_NOMOVE; \
  594. if (_layout->cx == (_r.right - _r.left) && _layout->cy == (_r.bottom - _r.top)) _layout->flags |= SWP_NOSIZE; \
  595. if ((SWP_HIDEWINDOW & _layout->flags) && !fVis) _layout->flags &= ~SWP_HIDEWINDOW; \
  596. if ((SWP_SHOWWINDOW & _layout->flags) && fVis) _layout->flags &= ~SWP_SHOWWINDOW; \
  597. }
  598. #define LAYOUTNEEEDUPDATE(_layout) ((SWP_NOMOVE | SWP_NOSIZE) != ((SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_SHOWWINDOW) & _layout->flags))
  599. #define GROUP_MIN 0x1
  600. #define GROUP_MAX 0x2
  601. #define GROUP_STATUSBAR 0x1
  602. #define GROUP_MAIN 0x2
  603. static void LayoutWindows(HWND hwnd, BOOL fRedraw, BOOL fUpdateAll = FALSE)
  604. {
  605. static INT controls[] =
  606. {
  607. GROUP_STATUSBAR, IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM, IDC_EDITBOOK, IDC_REMOVEBOOK,
  608. GROUP_MAIN, IDC_LIST
  609. };
  610. INT index;
  611. RECT rc;
  612. RECT rg;
  613. RECT ri;
  614. LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
  615. BOOL skipgroup;
  616. HRGN rgn = NULL;
  617. GetClientRect(hwnd, &rc);
  618. if ( rc.right == rc.left || rc.bottom == rc.top )
  619. return;
  620. if ( rc.right > WASABI_API_APP->getScaleX( 4 ) )
  621. rc.right -= WASABI_API_APP->getScaleX( 4 );
  622. SetRect(&rg, rc.left, rc.top, rc.right, rc.top);
  623. pl = layout;
  624. skipgroup = FALSE;
  625. InvalidateRect( hwnd, NULL, TRUE );
  626. for (index = 0; index < sizeof(controls) / sizeof(*controls); index++)
  627. {
  628. if ( controls[ index ] >= GROUP_MIN && controls[ index ] <= GROUP_MAX ) // group id
  629. {
  630. skipgroup = FALSE;
  631. switch ( controls[ index ] )
  632. {
  633. case GROUP_STATUSBAR:
  634. {
  635. wchar_t buffer[ 128 ] = { 0 };
  636. WASABI_API_LNGSTRINGW_BUF( IDC_BUTTON_PLAY, buffer, ARRAYSIZE( buffer ) );
  637. LRESULT idealSize = MLSkinnedButton_GetIdealSize( GetDlgItem( hwnd, IDC_BUTTON_PLAY ), buffer );
  638. SetRect( &rg, rc.left + WASABI_API_APP->getScaleX( 1 ),
  639. rc.bottom - WASABI_API_APP->getScaleY( HIWORD( idealSize ) ), rc.right, rc.bottom );
  640. rc.bottom = rg.top - WASABI_API_APP->getScaleY( 3 );
  641. break;
  642. }
  643. case GROUP_MAIN:
  644. SetRect( &rg, rc.left + WASABI_API_APP->getScaleX( 1 ), rc.top, rc.right, rc.bottom );
  645. break;
  646. }
  647. continue;
  648. }
  649. if (skipgroup)
  650. continue;
  651. pl->id = controls[ index ];
  652. pl->hwnd = GetDlgItem( hwnd, pl->id );
  653. if (!pl->hwnd)
  654. continue;
  655. GetWindowRect(pl->hwnd, &ri);
  656. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2);
  657. pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS;
  658. switch ( pl->id )
  659. {
  660. case IDC_BUTTON_PLAY:
  661. case IDC_BUTTON_ENQUEUE:
  662. case IDC_BUTTON_CUSTOM:
  663. case IDC_EDITBOOK:
  664. case IDC_REMOVEBOOK:
  665. if ( IDC_BUTTON_CUSTOM != pl->id || customAllowed )
  666. {
  667. if ( groupBtn && pl->id == IDC_BUTTON_PLAY && enqueuedef == 1 )
  668. {
  669. pl->flags |= SWP_HIDEWINDOW;
  670. break;
  671. }
  672. if ( groupBtn && pl->id == IDC_BUTTON_ENQUEUE && enqueuedef != 1 )
  673. {
  674. pl->flags |= SWP_HIDEWINDOW;
  675. break;
  676. }
  677. if ( groupBtn && ( pl->id == IDC_BUTTON_PLAY || pl->id == IDC_BUTTON_ENQUEUE ) && customAllowed )
  678. {
  679. pl->flags |= SWP_HIDEWINDOW;
  680. break;
  681. }
  682. wchar_t buffer[ 128 ] = { 0 };
  683. GetWindowTextW( pl->hwnd, buffer, ARRAYSIZE( buffer ) );
  684. LRESULT idealSize = MLSkinnedButton_GetIdealSize( pl->hwnd, buffer );
  685. LONG width = LOWORD( idealSize ) + WASABI_API_APP->getScaleX( 6 );
  686. SETLAYOUTPOS( pl, rg.left, rg.bottom - WASABI_API_APP->getScaleY( HIWORD( idealSize ) ), width, WASABI_API_APP->getScaleY( HIWORD( idealSize ) ) );
  687. pl->flags |= ( ( rg.right - rg.left ) > width ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  688. if ( SWP_SHOWWINDOW & pl->flags ) rg.left += ( pl->cx + WASABI_API_APP->getScaleX( 4 ) );
  689. }
  690. else
  691. pl->flags |= SWP_HIDEWINDOW;
  692. break;
  693. case IDC_LIST:
  694. pl->flags |= ( rg.top < rg.bottom ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  695. SETLAYOUTPOS( pl, rg.left, rg.top + WASABI_API_APP->getScaleY( 1 ),
  696. rg.right - rg.left + WASABI_API_APP->getScaleY( 1 ),
  697. ( rg.bottom - rg.top ) - WASABI_API_APP->getScaleY( 2 ) );
  698. break;
  699. }
  700. SETLAYOUTFLAGS(pl, ri);
  701. if ( LAYOUTNEEEDUPDATE( pl ) )
  702. {
  703. if ( SWP_NOSIZE == ( ( SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_NOSIZE ) & pl->flags ) &&
  704. ri.left == ( pl->x + offsetX ) && ri.top == ( pl->y + offsetY ) && IsWindowVisible( pl->hwnd ) )
  705. {
  706. SetRect( &ri, pl->x, pl->y, pl->cx + pl->x, pl->y + pl->cy );
  707. ValidateRect( hwnd, &ri );
  708. }
  709. pl++;
  710. }
  711. else if ( ( fRedraw || ( !offsetX && !offsetY ) ) && IsWindowVisible( pl->hwnd ) )
  712. {
  713. ValidateRect( hwnd, &ri );
  714. if ( GetUpdateRect( pl->hwnd, NULL, FALSE ) )
  715. {
  716. if ( !rgn ) rgn = CreateRectRgn( 0, 0, 0, 0 );
  717. GetUpdateRgn( pl->hwnd, rgn, FALSE );
  718. OffsetRgn( rgn, pl->x, pl->y );
  719. InvalidateRgn( hwnd, rgn, FALSE );
  720. }
  721. }
  722. }
  723. if ( pl != layout )
  724. {
  725. LAYOUT *pc;
  726. HDWP hdwp = BeginDeferWindowPos( (INT)( pl - layout ) );
  727. for ( pc = layout; pc < pl && hdwp; pc++ )
  728. {
  729. hdwp = DeferWindowPos( hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags );
  730. }
  731. if ( hdwp )
  732. EndDeferWindowPos( hdwp );
  733. if ( !rgn )
  734. rgn = CreateRectRgn( 0, 0, 0, 0 );
  735. if ( fRedraw )
  736. {
  737. GetUpdateRgn( hwnd, rgn, FALSE );
  738. for ( pc = layout; pc < pl && hdwp; pc++ )
  739. {
  740. if ( pc->rgn )
  741. {
  742. OffsetRgn( pc->rgn, pc->x, pc->y );
  743. CombineRgn( rgn, rgn, pc->rgn, RGN_OR );
  744. }
  745. }
  746. RedrawWindow( hwnd, NULL, rgn, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN );
  747. }
  748. if ( g_rgnUpdate )
  749. {
  750. GetUpdateRgn( hwnd, g_rgnUpdate, FALSE );
  751. for ( pc = layout; pc < pl && hdwp; pc++ )
  752. {
  753. if ( pc->rgn )
  754. {
  755. OffsetRgn( pc->rgn, pc->x, pc->y );
  756. CombineRgn( g_rgnUpdate, g_rgnUpdate, pc->rgn, RGN_OR );
  757. }
  758. }
  759. }
  760. for ( pc = layout; pc < pl && hdwp; pc++ )
  761. if ( pc->rgn )
  762. DeleteObject( pc->rgn );
  763. }
  764. if ( rgn )
  765. DeleteObject( rgn );
  766. ValidateRgn( hwnd, NULL );
  767. }
  768. static BOOL Bookmark_OnDisplayChange()
  769. {
  770. ListView_SetTextColor(m_bmlist.getwnd(),dialogSkinner.Color(WADLG_ITEMFG));
  771. ListView_SetBkColor(m_bmlist.getwnd(),dialogSkinner.Color(WADLG_ITEMBG));
  772. ListView_SetTextBkColor(m_bmlist.getwnd(),dialogSkinner.Color(WADLG_ITEMBG));
  773. m_bmlist.SetFont(dialogSkinner.GetFont());
  774. LayoutWindows(m_hwnd, TRUE);
  775. return 0;
  776. }
  777. static BOOL Bookmark_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  778. {
  779. if (GetCapture()==hwnd)
  780. {
  781. POINT p={x,y};
  782. ClientToScreen(hwnd,&p);
  783. if (WindowFromPoint(p) == m_bmlist.getwnd())
  784. {
  785. SetCursor(hDragNDropCursor);
  786. }
  787. else
  788. {
  789. mlDropItemStruct m={0};
  790. m.type=ML_TYPE_FILENAMES;
  791. m.p=p;
  792. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG,(int)&m);
  793. }
  794. }
  795. return FALSE;
  796. }
  797. static BOOL Bookmark_OnLButtonUp(HWND hwnd, int x, int y, UINT flags)
  798. {
  799. if (GetCapture()==hwnd)
  800. {
  801. ReleaseCapture();
  802. POINT p={x,y};
  803. ClientToScreen(hwnd,&p);
  804. if (WindowFromPoint(p) == m_bmlist.getwnd())
  805. {
  806. LVHITTESTINFO lvi;
  807. lvi.pt=p;
  808. ScreenToClient(m_bmlist.getwnd(),&lvi.pt);
  809. ListView_HitTest(m_bmlist.getwnd(),&lvi);
  810. int num_items = m_bmlist.GetCount();
  811. int destination_position=lvi.iItem;
  812. if ((lvi.flags & (LVHT_ONITEM)));
  813. else if (lvi.flags & LVHT_ABOVE) destination_position=0;
  814. else if (lvi.flags & (LVHT_BELOW|LVHT_NOWHERE )) destination_position=num_items;
  815. else return 0;
  816. int x = 0, dirty=0;
  817. for (; x < num_items; x ++)
  818. {
  819. m_bmlist.SetItemParam(x,0);
  820. }
  821. for (x = 0; x < num_items; x ++)
  822. {
  823. int sel=m_bmlist.GetSelected(x);
  824. if (sel && x != destination_position)
  825. {
  826. wchar_t ft[1024] = {0}, fn[1024] = {0};
  827. m_bmlist.GetText(x,0,ft,ARRAYSIZE(ft));
  828. m_bmlist.GetText(x,1,fn,ARRAYSIZE(fn));
  829. m_bmlist.DeleteItem(x);
  830. if (x < destination_position)
  831. {
  832. x--;
  833. }
  834. if (destination_position >= num_items) destination_position--;
  835. m_bmlist.InsertItem(destination_position,ft,1);
  836. m_bmlist.SetItemText(destination_position,1,fn);
  837. // have to do this otherwise first item isn't correctly flagged & reselected
  838. m_bmlist.SetItemParam(destination_position,1);
  839. destination_position++;
  840. dirty=1;
  841. }
  842. else if (sel) destination_position++;
  843. }
  844. int w=0;
  845. for (x = 0; x < num_items; x ++)
  846. {
  847. if (m_bmlist.GetParam(x))
  848. {
  849. if (!w)
  850. {
  851. w=1;
  852. ListView_SetItemState(m_bmlist.getwnd(),x,LVIS_FOCUSED,LVIS_FOCUSED);
  853. }
  854. m_bmlist.SetSelected(x);
  855. }
  856. }
  857. if (dirty) writebookmarks();
  858. }
  859. else
  860. {
  861. mlDropItemStruct m={0};
  862. m.type=ML_TYPE_FILENAMESW;
  863. m.p=p;
  864. m.flags=ML_HANDLEDRAG_FLAG_NOCURSOR;
  865. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG,(int)&m);
  866. if (m.result>0)
  867. {
  868. wchar_t *buf=(wchar_t*)calloc(4096, sizeof(wchar_t));
  869. size_t buf_size=4096;
  870. size_t buf_pos=0;
  871. int l=m_bmlist.GetCount();
  872. for(int i=0;i<l;i++)
  873. {
  874. if (m_bmlist.GetSelected(i))
  875. {
  876. wchar_t tbuf[1024]={0};
  877. m_bmlist.GetText(i,1,tbuf,ARRAYSIZE(tbuf)-1);
  878. tbuf[1023]=0;
  879. size_t newsize=buf_pos + wcslen(tbuf) + 1;
  880. if (newsize < buf_size)
  881. {
  882. size_t old_buf_size=buf_size;
  883. buf_size=newsize+4096;
  884. wchar_t *data = (wchar_t*)realloc(buf, (buf_size + 1) * sizeof(wchar_t));
  885. if (data)
  886. {
  887. buf=data;
  888. }
  889. else
  890. {
  891. data=(wchar_t*)calloc((buf_size + 1), sizeof(wchar_t));
  892. if (data)
  893. {
  894. memcpy(data, buf, sizeof(wchar_t)*old_buf_size);
  895. free(buf);
  896. buf=data;
  897. }
  898. else buf_size = old_buf_size;
  899. }
  900. }
  901. lstrcpynW(buf+buf_pos,tbuf,(int)buf_size);
  902. buf_pos=newsize;
  903. }
  904. }
  905. if (buf_pos)
  906. {
  907. buf[buf_pos]=0;
  908. m.flags=0;
  909. m.result=0;
  910. m.data=(void*)buf;
  911. pluginHandleIpcMessage(ML_IPC_HANDLEDROP,(int)&m);
  912. }
  913. free(buf);
  914. }
  915. }
  916. }
  917. return FALSE;
  918. }
  919. void Bookmark_SelectAll(void)
  920. {
  921. LVITEM item;
  922. item.state = LVIS_SELECTED;
  923. item.stateMask = LVIS_SELECTED;
  924. SendMessageW(m_bmlist.getwnd(), LVM_SETITEMSTATE, -1, (LPARAM)&item);
  925. }
  926. enum
  927. {
  928. BPM_ECHO_WM_COMMAND = 0x1, // send WM_COMMAND and return value
  929. BPM_WM_COMMAND = 0x2, // just send WM_COMMAND
  930. };
  931. BOOL Bookmark_ButtonPopupMenu( HWND hwndDlg, int buttonId, HMENU menu, int flags = 0 )
  932. {
  933. RECT r;
  934. HWND buttonHWND = GetDlgItem( hwndDlg, buttonId );
  935. GetWindowRect( buttonHWND, &r );
  936. UpdateMenuItems( hwndDlg, menu );
  937. MLSkinnedButton_SetDropDownState( buttonHWND, TRUE );
  938. UINT tpmFlags = TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN;
  939. if ( !( flags & BPM_WM_COMMAND ) )
  940. tpmFlags |= TPM_RETURNCMD;
  941. int x = Menu_TrackPopup( plugin.hwndLibraryParent, menu, tpmFlags, r.left, r.top, hwndDlg, NULL );
  942. if ( ( flags & BPM_ECHO_WM_COMMAND ) && x )
  943. SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( x, 0 ), 0 );
  944. MLSkinnedButton_SetDropDownState( buttonHWND, FALSE );
  945. return x;
  946. }
  947. static void Bookmark_Play(HWND hwndDlg, HWND from, UINT idFrom)
  948. {
  949. HMENU listMenu = GetSubMenu(g_context_menus2, 0);
  950. int count = GetMenuItemCount(listMenu);
  951. if (count > 2)
  952. {
  953. for (int i = 2; i < count; i++)
  954. {
  955. DeleteMenu(listMenu, 2, MF_BYPOSITION);
  956. }
  957. }
  958. Bookmark_ButtonPopupMenu(hwndDlg, idFrom, listMenu, BPM_WM_COMMAND);
  959. }
  960. static BOOL Bookmark_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  961. {
  962. switch(LOWORD(id))
  963. {
  964. case IDC_BUTTON_PLAY:
  965. case ID_BMWND_PLAYSELECTEDFILES:
  966. case IDC_BUTTON_ENQUEUE:
  967. case ID_BMWND_ENQUEUESELECTEDFILES:
  968. case IDC_BUTTON_CUSTOM:
  969. {
  970. if (codeNotify == MLBN_DROPDOWN)
  971. {
  972. Bookmark_Play(hwnd, hwndCtl, id);
  973. }
  974. else
  975. {
  976. int action;
  977. if (LOWORD(id) == IDC_BUTTON_PLAY || LOWORD(id) == ID_BMWND_PLAYSELECTEDFILES)
  978. {
  979. action = (codeNotify == 1) ? g_config->ReadInt(L"enqueuedef", 0) == 1 : 0;
  980. }
  981. else if (LOWORD(id) == IDC_BUTTON_ENQUEUE || LOWORD(id) == ID_BMWND_ENQUEUESELECTEDFILES)
  982. {
  983. action = (codeNotify == 1) ? g_config->ReadInt(L"enqueuedef", 0) != 1 : 1;
  984. }
  985. else
  986. break;
  987. playFiles(action, 0);
  988. }
  989. break;
  990. }
  991. case ID_BMWND_EDITSELECTEDBOOKMARKS:
  992. case IDC_EDITBOOK:
  993. {
  994. int dirty=0;
  995. int x=0,l=m_bmlist.GetCount();
  996. while (x < l)
  997. {
  998. if (m_bmlist.GetSelected(x))
  999. {
  1000. dirty=1;
  1001. wchar_t fn[1024] = {0}, ft[1024] = {0};
  1002. m_bmlist.GetText(x,0,ft,ARRAYSIZE(ft));
  1003. m_bmlist.GetText(x,1,fn,ARRAYSIZE(fn));
  1004. g_bmedit_fn=fn;
  1005. g_bmedit_ft=ft;
  1006. WASABI_API_DIALOGBOXW(IDD_EDITBOOKMARK,hwnd,BookMarkEditProc);
  1007. m_bmlist.SetItemText(x,0,ft);
  1008. m_bmlist.SetItemText(x,1,fn);
  1009. }
  1010. x++;
  1011. }
  1012. if (dirty) writebookmarks();
  1013. }
  1014. break;
  1015. case ID_BMWND_REMOVESELECTEDBOOKMARKS:
  1016. case IDC_REMOVEBOOK: // remove
  1017. {
  1018. int dirty=0;
  1019. int x=0,l=m_bmlist.GetCount();
  1020. while (x < l)
  1021. {
  1022. if (m_bmlist.GetSelected(x))
  1023. {
  1024. dirty=1;
  1025. m_bmlist.DeleteItem(x);
  1026. l--;
  1027. }
  1028. else x++;
  1029. }
  1030. if (dirty) writebookmarks();
  1031. }
  1032. break;
  1033. case ID_BMWND_SELECTALL:
  1034. Bookmark_SelectAll();
  1035. break;
  1036. }
  1037. return FALSE;
  1038. }
  1039. static BOOL Bookmark_OnDestroy(HWND hwnd)
  1040. {
  1041. if (m_bmlist.getwnd())
  1042. {
  1043. g_config->WriteInt(L"bm_col_title",m_bmlist.GetColumnWidth(0));
  1044. g_config->WriteInt(L"bm_col_filename",m_bmlist.GetColumnWidth(1));
  1045. }
  1046. m_hwnd=0;
  1047. return FALSE;
  1048. }
  1049. static void Bookmark_ManageButtons(HWND hwndDlg)
  1050. {
  1051. int has_selection = m_bmlist.GetSelectedCount();
  1052. const int buttonids[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM, IDC_EDITBOOK, IDC_REMOVEBOOK};
  1053. for (size_t i = 0; i != sizeof(buttonids)/sizeof(buttonids[0]); i++)
  1054. {
  1055. HWND controlHWND = GetDlgItem(hwndDlg, buttonids[i]);
  1056. EnableWindow(controlHWND, has_selection);
  1057. }
  1058. }
  1059. static BOOL Bookmark_OnNotify( HWND hwnd, NMHDR *notification )
  1060. {
  1061. if ( notification->idFrom == IDC_LIST )
  1062. {
  1063. if ( notification->code == NM_DBLCLK )
  1064. {
  1065. playFiles( ( !!( g_config->ReadInt( L"enqueuedef", 0 ) == 1 ) ) ^ ( !!( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ), 0 );
  1066. }
  1067. else if ( notification->code == LVN_BEGINDRAG )
  1068. {
  1069. SetCapture( hwnd );
  1070. }
  1071. else if ( notification->code == LVN_ITEMCHANGED )
  1072. {
  1073. Bookmark_ManageButtons( hwnd );
  1074. }
  1075. }
  1076. return FALSE;
  1077. }
  1078. void Bookmark_UpdateButtonText(HWND hwndDlg, int _enqueuedef)
  1079. {
  1080. if (groupBtn)
  1081. {
  1082. switch(_enqueuedef)
  1083. {
  1084. case 1:
  1085. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, view.enqueue);
  1086. customAllowed = FALSE;
  1087. break;
  1088. default:
  1089. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  1090. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  1091. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK_IN_USE, (INT_PTR)_enqueuedef, 0, 0};
  1092. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  1093. if (pszTextW && pszTextW[0] != 0)
  1094. {
  1095. // set this to be a bit different so we can just use one button and not the
  1096. // mixable one as well (leaving that to prevent messing with the resources)
  1097. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, pszTextW);
  1098. customAllowed = TRUE;
  1099. }
  1100. else
  1101. {
  1102. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, view.play);
  1103. customAllowed = FALSE;
  1104. }
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. static BOOL Bookmark_OnInitDialog( HWND hwndDlg, HWND hwndFocus, LPARAM lParam )
  1110. {
  1111. m_hwnd = hwndDlg;
  1112. m_bmlist.setwnd( GetDlgItem( hwndDlg, IDC_LIST ) );
  1113. HACCEL accel = WASABI_API_LOADACCELERATORSW( IDR_VIEW_BM_ACCELERATORS );
  1114. if ( accel )
  1115. WASABI_API_APP->app_addAccelerators( hwndDlg, &accel, 1, TRANSLATE_MODE_CHILD );
  1116. if ( !view.play )
  1117. {
  1118. SENDMLIPC( plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view );
  1119. }
  1120. // check the column widths and ensure that if <=0 it'll re-show
  1121. // (based on some forum reports where the width is set to zero somehow)
  1122. // -> shouldn't annoy anyone but you never know with the users, heh
  1123. int col_width1 = g_config->ReadInt( L"bm_col_title", 400 );
  1124. if ( col_width1 <= 0 )
  1125. col_width1 = 400;
  1126. int col_width2 = g_config->ReadInt( L"bm_col_filename", 240 );
  1127. if ( col_width2 <= 0 )
  1128. col_width2 = 240;
  1129. m_bmlist.AddCol( WASABI_API_LNGSTRINGW( IDS_BOOKMARK_TITLE ), col_width1 );
  1130. m_bmlist.AddCol( WASABI_API_LNGSTRINGW( IDS_BOOKMARK_FN_URL ), col_width2 );
  1131. groupBtn = g_config->ReadInt( L"groupbtn", 1 );
  1132. enqueuedef = ( g_config->ReadInt( L"enqueuedef", 0 ) == 1 );
  1133. Bookmark_OnDisplayChange();
  1134. m_headerhwnd = ListView_GetHeader( m_bmlist.getwnd() );
  1135. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  1136. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  1137. pluginMessage p = { ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG( IDC_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE ), (INT_PTR)L"ml_bookmark" };
  1138. wchar_t *pszTextW = (wchar_t *)SENDMLIPC( plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p );
  1139. if ( pszTextW && pszTextW[ 0 ] != 0 )
  1140. {
  1141. // set this to be a bit different so we can just use one button and not the
  1142. // mixable one as well (leaving that to prevent messing with the resources)
  1143. customAllowed = TRUE;
  1144. SetDlgItemTextW( hwndDlg, IDC_BUTTON_CUSTOM, pszTextW );
  1145. }
  1146. else
  1147. customAllowed = FALSE;
  1148. MLSKINWINDOW m = { 0 };
  1149. m.skinType = SKINNEDWND_TYPE_DIALOG;
  1150. m.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT;
  1151. m.hwndToSkin = hwndDlg;
  1152. MLSkinWindow( plugin.hwndLibraryParent, &m );
  1153. m.skinType = SKINNEDWND_TYPE_LISTVIEW;
  1154. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  1155. m.hwndToSkin = m_bmlist.getwnd();
  1156. MLSkinWindow( mediaLibrary.library, &m );
  1157. m.skinType = SKINNEDWND_TYPE_BUTTON;
  1158. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | ( groupBtn ? SWBS_SPLITBUTTON : 0 );
  1159. FLICKERFIX ff = { 0, FFM_ERASEINPAINT };
  1160. const int buttonids[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM };
  1161. for ( size_t i = 0; i != sizeof( buttonids ) / sizeof( buttonids[ 0 ] ); i++ )
  1162. {
  1163. ff.hwnd = m.hwndToSkin = GetDlgItem( hwndDlg, buttonids[ i ] );
  1164. if ( IsWindow( m.hwndToSkin ) )
  1165. {
  1166. MLSkinWindow( plugin.hwndLibraryParent, &m );
  1167. SENDMLIPC( plugin.hwndLibraryParent, ML_IPC_FLICKERFIX, (WPARAM)&ff );
  1168. }
  1169. }
  1170. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  1171. const int buttonidz[] = { IDC_EDITBOOK, IDC_REMOVEBOOK };
  1172. for ( size_t i = 0; i != sizeof( buttonidz ) / sizeof( buttonidz[ 0 ] ); i++ )
  1173. {
  1174. ff.hwnd = m.hwndToSkin = GetDlgItem( hwndDlg, buttonidz[ i ] );
  1175. if ( IsWindow( m.hwndToSkin ) )
  1176. {
  1177. MLSkinWindow( plugin.hwndLibraryParent, &m );
  1178. SENDMLIPC( plugin.hwndLibraryParent, ML_IPC_FLICKERFIX, (WPARAM)&ff );
  1179. }
  1180. }
  1181. Bookmark_ManageButtons( hwndDlg );
  1182. Bookmark_UpdateButtonText( hwndDlg, enqueuedef == 1 );
  1183. SetTimer( hwndDlg, 100, 15, NULL );
  1184. return TRUE;
  1185. }
  1186. static void Bookmark_OnTimer(HWND hwnd, UINT id)
  1187. {
  1188. if (id == 100)
  1189. {
  1190. KillTimer(hwnd,100);
  1191. // populate list
  1192. readbookmarks();
  1193. }
  1194. }
  1195. void Bookmark_DropFiles(HWND hwnd, HDROP hDrop)
  1196. {
  1197. wchar_t temp[2048] = {0};
  1198. int y = DragQueryFileW(hDrop, 0xffffffff, temp, 2048);
  1199. for (int x = 0; x < y; x ++)
  1200. {
  1201. DragQueryFileW(hDrop, x, temp, 2048);
  1202. mediaLibrary.AddBookmarkW(temp);
  1203. }
  1204. }
  1205. static BOOL Bookmark_OnMLDropItem(mlDropItemStruct *dis)
  1206. {
  1207. if (dis)
  1208. {
  1209. if (dis->type != ML_TYPE_ITEMRECORDLISTW && dis->type != ML_TYPE_ITEMRECORDLIST &&
  1210. dis->type != ML_TYPE_FILENAMES && dis->type != ML_TYPE_FILENAMESW &&
  1211. dis->type != ML_TYPE_STREAMNAMES && dis->type != ML_TYPE_STREAMNAMESW &&
  1212. dis->type != ML_TYPE_CDTRACKS &&
  1213. dis->type != ML_TYPE_PLAYLIST && dis->type != ML_TYPE_PLAYLISTS)
  1214. {
  1215. dis->result=-1;
  1216. }
  1217. else
  1218. {
  1219. dis->result=1;
  1220. if (dis->data)
  1221. {
  1222. if (dis->type == ML_TYPE_ITEMRECORDLIST || dis->type == ML_TYPE_CDTRACKS)
  1223. {
  1224. itemRecordList *p=(itemRecordList *)dis->data;
  1225. for (int x = 0; x < p->Size; x ++)
  1226. mediaLibrary.AddBookmark(p->Items[x].filename);
  1227. }
  1228. else if (dis->type == ML_TYPE_ITEMRECORDLISTW)
  1229. {
  1230. itemRecordListW *p=(itemRecordListW *)dis->data;
  1231. for (int x = 0; x < p->Size; x ++)
  1232. mediaLibrary.AddBookmark(AutoChar(p->Items[x].filename));
  1233. }
  1234. else if (dis->type == ML_TYPE_FILENAMES || dis->type == ML_TYPE_STREAMNAMES) // playlist
  1235. {
  1236. char *p=(char*)dis->data;
  1237. while (p && *p)
  1238. {
  1239. mediaLibrary.AddBookmark(p);
  1240. p+=strlen(p)+1;
  1241. }
  1242. }
  1243. else if (dis->type == ML_TYPE_FILENAMESW || dis->type == ML_TYPE_STREAMNAMESW) // playlist
  1244. {
  1245. wchar_t *p=(wchar_t*)dis->data;
  1246. while (p && *p)
  1247. {
  1248. mediaLibrary.AddBookmarkW(p);
  1249. p+=wcslen(p)+1;
  1250. }
  1251. }
  1252. else if(dis->type == ML_TYPE_PLAYLIST)
  1253. {
  1254. mediaLibrary.AddBookmarkW((wchar_t*)((mlPlaylist*)dis->data)->filename);
  1255. }
  1256. else if(dis->type == ML_TYPE_PLAYLISTS)
  1257. {
  1258. mlPlaylist **playlists = (mlPlaylist **)dis->data;
  1259. while (playlists && *playlists)
  1260. {
  1261. mlPlaylist *pl = *playlists;
  1262. mediaLibrary.AddBookmarkW((wchar_t*)pl->filename);
  1263. playlists++;
  1264. }
  1265. }
  1266. }
  1267. }
  1268. }
  1269. return FALSE;
  1270. }
  1271. #define HANDLE_ML_DROPITEM(func) case ML_CHILDIPC_DROPITEM: return Bookmark_OnMLDropItem((mlDropItemStruct *)wParam);
  1272. INT_PTR CALLBACK view_bmDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  1273. {
  1274. INT_PTR a = dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam);
  1275. if (a) return a;
  1276. switch(uMsg)
  1277. {
  1278. HANDLE_MSG(hwndDlg, WM_INITDIALOG, Bookmark_OnInitDialog);
  1279. HANDLE_MSG(hwndDlg, WM_TIMER, Bookmark_OnTimer);
  1280. HANDLE_MSG(hwndDlg, WM_COMMAND, Bookmark_OnCommand);
  1281. HANDLE_MSG(hwndDlg, WM_DESTROY, Bookmark_OnDestroy);
  1282. HANDLE_MSG(hwndDlg, WM_MOUSEMOVE, Bookmark_OnMouseMove);
  1283. HANDLE_MSG(hwndDlg, WM_LBUTTONUP, Bookmark_OnLButtonUp);
  1284. HANDLE_MSG(hwndDlg, WM_DROPFILES, Bookmark_DropFiles);
  1285. case WM_WINDOWPOSCHANGED:
  1286. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  1287. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  1288. {
  1289. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags));
  1290. }
  1291. return 0;
  1292. case WM_USER + 0x200:
  1293. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); // yes, we support no - redraw resize
  1294. return TRUE;
  1295. case WM_USER + 0x201:
  1296. offsetX = (short)LOWORD(wParam);
  1297. offsetY = (short)HIWORD(wParam);
  1298. g_rgnUpdate = (HRGN)lParam;
  1299. return TRUE;
  1300. case WM_PAINT:
  1301. {
  1302. int tab[] = { IDC_LIST|DCW_SUNKENBORDER};
  1303. dialogSkinner.Draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
  1304. }
  1305. return 0;
  1306. case WM_INITMENUPOPUP:
  1307. if (wParam && (HMENU)wParam == s.build_hMenu && s.mode==1)
  1308. {
  1309. myMenu = TRUE;
  1310. if(SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU)==0xffffffff)
  1311. s.mode=2;
  1312. myMenu = FALSE;
  1313. }
  1314. return 0;
  1315. case WM_DISPLAYCHANGE:
  1316. return Bookmark_OnDisplayChange();
  1317. case WM_NOTIFY:
  1318. return Bookmark_OnNotify(hwndDlg, (LPNMHDR)lParam);
  1319. case WM_CONTEXTMENU:
  1320. bookmarks_contextMenu(hwndDlg, (HWND)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  1321. return 0;
  1322. case WM_APP + 104:
  1323. {
  1324. Bookmark_UpdateButtonText(hwndDlg, (int)wParam);
  1325. LayoutWindows(hwndDlg, TRUE);
  1326. return 0;
  1327. }
  1328. case WM_ML_CHILDIPC:
  1329. if (lParam == ML_CHILDIPC_DROPITEM && wParam)
  1330. HANDLE_ML_DROPITEM(Bookmark_OnMLDropItem);
  1331. }
  1332. return FALSE;
  1333. }