1
0

DownloadsDialog.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. #include "main.h"
  2. #include "api__ml_wire.h"
  3. #include "Downloaded.h"
  4. #include "./navigation.h"
  5. #include "DownloadStatus.h"
  6. #include "Defaults.h"
  7. #include "../nu/listview.h"
  8. #include "..\..\General\gen_ml/ml_ipc.h"
  9. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  10. #include <vector>
  11. #include "../nu/menushortcuts.h"
  12. #include <commctrl.h>
  13. #include <shlwapi.h>
  14. #include <shellapi.h>
  15. #include <strsafe.h>
  16. #include <algorithm>
  17. HWND current_window = 0;
  18. int groupBtn = 1, enqueuedef = 0, customAllowed = 0;
  19. HMENU g_context_menus2 = NULL;
  20. viewButtons view = {0};
  21. #ifndef HDF_SORTUP
  22. #define HDF_SORTUP 0x0400
  23. #define HDF_SORTDOWN 0x0200
  24. #endif // !HDF_SORTUP
  25. using namespace Nullsoft::Utility;
  26. enum
  27. {
  28. COL_CHANNEL = 0,
  29. COL_ITEM,
  30. COL_PROGRESS,
  31. COL_PATH,
  32. NUM_COLUMNS,
  33. };
  34. int downloadsChannelWidth = DOWNLOADSCHANNELWIDTHDEFAULT;
  35. int downloadsItemWidth = DOWNLOADSITEMWIDTHDEFAULT;
  36. int downloadsProgressWidth = DOWNLOADSPROGRESSWIDTHDEFAULT;
  37. int downloadsPathWidth = DOWNLOADSPATHWIDTHDEFAULTS;
  38. W_ListView downloadList;
  39. int downloadsItemSort = -1; // -1 means no sort active
  40. bool downloadsSortAscending = true;
  41. enum
  42. {
  43. DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR = 0,
  44. };
  45. class DownloadListItem
  46. {
  47. public:
  48. DownloadedFile *f;
  49. DownloadToken token;
  50. wchar_t *channel, *item, *path;
  51. wchar_t status[ 20 ];
  52. DownloadListItem( DownloadedFile *fi ) : token( 0 ), channel( 0 ), item( 0 ), path( 0 )
  53. {
  54. f = new DownloadedFile( *fi );
  55. ZeroMemory( status, sizeof( status ) );
  56. }
  57. DownloadListItem( DownloadToken token, const wchar_t *channel0, const wchar_t *item0, const wchar_t *path0, size_t downloaded, size_t maxSize ) : token( token ), f( 0 )
  58. {
  59. if ( maxSize )
  60. StringCchPrintf( status, 20, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_PERCENT ), (int)( downloaded / ( maxSize / 100 ) ) );
  61. else
  62. {
  63. WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOADING, status, 20 );
  64. }
  65. channel = channel0 ? _wcsdup( channel0 ) : NULL;
  66. item = item0 ? _wcsdup( item0 ) : NULL;
  67. path = path0 ? _wcsdup( path0 ) : NULL;
  68. }
  69. ~DownloadListItem()
  70. {
  71. clean();
  72. if ( f )
  73. delete f;
  74. }
  75. void clean()
  76. {
  77. if ( channel )
  78. {
  79. free( channel );
  80. channel = 0;
  81. }
  82. if ( item )
  83. {
  84. free( item );
  85. item = 0;
  86. }
  87. if ( path )
  88. {
  89. free( path );
  90. path = 0;
  91. }
  92. }
  93. };
  94. static std::vector<DownloadListItem*> listContents;
  95. bool GetDownload( int &download )
  96. {
  97. download = ListView_GetNextItem( downloadList.getwnd(), download, LVNI_ALL | LVNI_SELECTED );
  98. if ( download == -1 )
  99. return false;
  100. else
  101. return true;
  102. }
  103. void Downloads_Play( bool enqueue = false )
  104. {
  105. int download = -1;
  106. AutoLock lock( downloadedFiles );
  107. while ( GetDownload( download ) )
  108. {
  109. if ( !enqueue )
  110. {
  111. if ( listContents[ download ]->f )
  112. mediaLibrary.PlayFile( listContents[ download ]->f->path );
  113. else if ( listContents[ download ]->path )
  114. mediaLibrary.PlayFile( listContents[ download ]->path );
  115. enqueue = true;
  116. }
  117. else
  118. {
  119. if ( listContents[ download ]->f )
  120. mediaLibrary.EnqueueFile( listContents[ download ]->f->path );
  121. else if ( listContents[ download ]->path )
  122. mediaLibrary.EnqueueFile( listContents[ download ]->path );
  123. }
  124. }
  125. }
  126. void DownloadsUpdated( const DownloadStatus::Status &s, DownloadToken token )
  127. {
  128. listContents.push_back( new DownloadListItem( token, s.channel, s.item, s.path, s.downloaded, s.maxSize ) );
  129. downloadList.SetVirtualCountAsync( (int)listContents.size() );
  130. }
  131. void DownloadsUpdated( DownloadToken token, const DownloadedFile *f )
  132. {
  133. for ( DownloadListItem *l_content : listContents )
  134. {
  135. if ( l_content->token == token )
  136. {
  137. l_content->token = 0;
  138. if ( f )
  139. {
  140. l_content->f = new DownloadedFile( *f );
  141. l_content->clean();
  142. }
  143. else
  144. lstrcpyn( l_content->status, L"Error", 20 );
  145. break;
  146. }
  147. }
  148. PostMessage( downloadList.getwnd(), LVM_REDRAWITEMS, 0, listContents.size() );
  149. }
  150. void DownloadsUpdated()
  151. {
  152. for ( DownloadListItem *l_content : listContents )
  153. delete l_content;
  154. listContents.clear();
  155. for ( DownloadedFile &l_download : downloadedFiles.downloadList )
  156. listContents.push_back( new DownloadListItem( &l_download ) );
  157. {
  158. AutoLock lock( downloadStatus.statusLock );
  159. for ( DownloadStatus::Downloads::iterator itr = downloadStatus.downloads.begin(); itr != downloadStatus.downloads.end(); itr++ )
  160. {
  161. listContents.push_back( new DownloadListItem( itr->first, itr->second.channel, itr->second.item, itr->second.path, itr->second.downloaded, itr->second.maxSize ) );
  162. }
  163. }
  164. downloadList.SetVirtualCountAsync( (int)listContents.size() );
  165. // Navigation_ShowService( SERVICE_DOWNLOADS, SHOWMODE_AUTO );
  166. }
  167. static void CleanupDownloads()
  168. {
  169. {
  170. AutoLock lock( downloadedFiles );
  171. DownloadList::DownloadedFileList &downloads = downloadedFiles.downloadList;
  172. DownloadList::iterator itr, next;
  173. for ( itr = downloads.begin(); itr != downloads.end();)
  174. {
  175. next = itr;
  176. ++next;
  177. if ( !PathFileExists( itr->path ) )
  178. downloads.erase( itr );
  179. else
  180. itr = next;
  181. }
  182. }
  183. // Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
  184. }
  185. void Downloads_UpdateStatusBar(HWND hwndDlg)
  186. {
  187. wchar_t status[256]=L"";
  188. downloadStatus.GetStatusString(status, 256);
  189. SetWindowText(GetDlgItem(hwndDlg, IDC_STATUS), status);
  190. }
  191. void Downloads_Paint(HWND hwndDlg)
  192. {
  193. int tab[] = { IDC_DOWNLOADLIST | DCW_SUNKENBORDER, };
  194. dialogSkinner.Draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
  195. }
  196. static HRGN g_rgnUpdate = NULL;
  197. static int offsetX = 0, offsetY = 0;
  198. typedef struct _LAYOUT
  199. {
  200. INT id;
  201. HWND hwnd;
  202. INT x;
  203. INT y;
  204. INT cx;
  205. INT cy;
  206. DWORD flags;
  207. HRGN rgn;
  208. }
  209. LAYOUT, PLAYOUT;
  210. #define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; }
  211. #define SETLAYOUTFLAGS(_layout, _r) \
  212. { \
  213. BOOL fVis; \
  214. fVis = (WS_VISIBLE & (LONG)GetWindowLongPtr(_layout->hwnd, GWL_STYLE)); \
  215. if (_layout->x == _r.left && _layout->y == _r.top) _layout->flags |= SWP_NOMOVE; \
  216. if (_layout->cx == (_r.right - _r.left) && _layout->cy == (_r.bottom - _r.top)) _layout->flags |= SWP_NOSIZE; \
  217. if ((SWP_HIDEWINDOW & _layout->flags) && !fVis) _layout->flags &= ~SWP_HIDEWINDOW; \
  218. if ((SWP_SHOWWINDOW & _layout->flags) && fVis) _layout->flags &= ~SWP_SHOWWINDOW; \
  219. }
  220. #define LAYOUTNEEEDUPDATE(_layout) ((SWP_NOMOVE | SWP_NOSIZE) != ((SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_SHOWWINDOW) & _layout->flags))
  221. #define GROUP_MIN 0x1
  222. #define GROUP_MAX 0x2
  223. #define GROUP_STATUSBAR 0x1
  224. #define GROUP_MAIN 0x2
  225. static void LayoutWindows(HWND hwnd, BOOL fRedraw, BOOL fUpdateAll = FALSE)
  226. {
  227. static INT controls[] =
  228. {
  229. GROUP_STATUSBAR, IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM, IDC_REMOVE, IDC_CLEANUP, IDC_STATUS,
  230. GROUP_MAIN, IDC_DOWNLOADLIST
  231. };
  232. INT index;
  233. RECT rc, rg, ri;
  234. LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
  235. BOOL skipgroup;
  236. HRGN rgn = NULL;
  237. GetClientRect(hwnd, &rc);
  238. if (rc.right == rc.left || rc.bottom == rc.top)
  239. return;
  240. if ( rc.right > WASABI_API_APP->getScaleX( 4 ) )
  241. rc.right -= WASABI_API_APP->getScaleX( 4 );
  242. SetRect( &rg, rc.left, rc.top, rc.right, rc.top );
  243. pl = layout;
  244. skipgroup = FALSE;
  245. InvalidateRect(hwnd, NULL, TRUE);
  246. for (index = 0; index < sizeof(controls) / sizeof(*controls); index++)
  247. {
  248. if (controls[index] >= GROUP_MIN && controls[index] <= GROUP_MAX) // group id
  249. {
  250. skipgroup = FALSE;
  251. switch (controls[index])
  252. {
  253. case GROUP_STATUSBAR:
  254. {
  255. wchar_t buffer[128] = {0};
  256. WASABI_API_LNGSTRINGW_BUF(IDC_PLAY, buffer, ARRAYSIZE(buffer));
  257. LRESULT idealSize = MLSkinnedButton_GetIdealSize(GetDlgItem(hwnd, IDC_PLAY), buffer);
  258. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
  259. rc.bottom - WASABI_API_APP->getScaleY(HIWORD(idealSize)),
  260. rc.right, rc.bottom);
  261. rc.bottom = rg.top - WASABI_API_APP->getScaleY(3);
  262. break;
  263. }
  264. case GROUP_MAIN:
  265. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, rc.bottom);
  266. break;
  267. }
  268. continue;
  269. }
  270. if (skipgroup) continue;
  271. pl->id = controls[index];
  272. pl->hwnd = GetDlgItem(hwnd, pl->id);
  273. if ( !pl->hwnd )
  274. continue;
  275. GetWindowRect(pl->hwnd, &ri);
  276. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2);
  277. pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS;
  278. switch (pl->id)
  279. {
  280. case IDC_PLAY:
  281. case IDC_ENQUEUE:
  282. case IDC_CUSTOM:
  283. case IDC_REMOVE:
  284. case IDC_CLEANUP:
  285. if ( IDC_CUSTOM != pl->id || customAllowed )
  286. {
  287. if ( groupBtn && pl->id == IDC_PLAY && enqueuedef == 1 )
  288. {
  289. pl->flags |= SWP_HIDEWINDOW;
  290. break;
  291. }
  292. if ( groupBtn && pl->id == IDC_ENQUEUE && enqueuedef != 1 )
  293. {
  294. pl->flags |= SWP_HIDEWINDOW;
  295. break;
  296. }
  297. if ( groupBtn && ( pl->id == IDC_PLAY || pl->id == IDC_ENQUEUE ) && customAllowed )
  298. {
  299. pl->flags |= SWP_HIDEWINDOW;
  300. break;
  301. }
  302. wchar_t buffer[ 128 ] = { 0 };
  303. GetWindowTextW( pl->hwnd, buffer, ARRAYSIZE( buffer ) );
  304. LRESULT idealSize = MLSkinnedButton_GetIdealSize( pl->hwnd, buffer );
  305. LONG width = LOWORD( idealSize ) + WASABI_API_APP->getScaleX( 6 );
  306. SETLAYOUTPOS( pl, rg.left, rg.bottom - WASABI_API_APP->getScaleY( HIWORD( idealSize ) ), width, WASABI_API_APP->getScaleY( HIWORD( idealSize ) ) );
  307. pl->flags |= ( ( rg.right - rg.left ) > width ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  308. if ( SWP_SHOWWINDOW & pl->flags )
  309. rg.left += ( pl->cx + WASABI_API_APP->getScaleX( 4 ) );
  310. }
  311. else
  312. pl->flags |= SWP_HIDEWINDOW;
  313. break;
  314. case IDC_STATUS:
  315. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left, (rg.bottom - rg.top));
  316. pl->flags |= (pl->cx > 16) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  317. break;
  318. case IDC_DOWNLOADLIST:
  319. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  320. SETLAYOUTPOS( pl, rg.left, rg.top + WASABI_API_APP->getScaleY( 1 ), rg.right - rg.left + WASABI_API_APP->getScaleY( 1 ), ( rg.bottom - rg.top ) - WASABI_API_APP->getScaleY( 2 ) );
  321. break;
  322. }
  323. SETLAYOUTFLAGS(pl, ri);
  324. if ( LAYOUTNEEEDUPDATE( pl ) )
  325. {
  326. if ( SWP_NOSIZE == ( ( SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_NOSIZE ) & pl->flags ) && ri.left == ( pl->x + offsetX ) && ri.top == ( pl->y + offsetY ) && IsWindowVisible( pl->hwnd ) )
  327. {
  328. SetRect( &ri, pl->x, pl->y, pl->cx + pl->x, pl->y + pl->cy );
  329. ValidateRect( hwnd, &ri );
  330. }
  331. pl++;
  332. }
  333. else if ( ( fRedraw || ( !offsetX && !offsetY ) ) && IsWindowVisible( pl->hwnd ) )
  334. {
  335. ValidateRect( hwnd, &ri );
  336. if ( GetUpdateRect( pl->hwnd, NULL, FALSE ) )
  337. {
  338. if ( !rgn )
  339. rgn = CreateRectRgn( 0, 0, 0, 0 );
  340. GetUpdateRgn( pl->hwnd, rgn, FALSE );
  341. OffsetRgn( rgn, pl->x, pl->y );
  342. InvalidateRgn( hwnd, rgn, FALSE );
  343. }
  344. }
  345. }
  346. if (pl != layout)
  347. {
  348. LAYOUT *pc;
  349. HDWP hdwp = BeginDeferWindowPos((INT)(pl - layout));
  350. for(pc = layout; pc < pl && hdwp; pc++)
  351. {
  352. hdwp = DeferWindowPos(hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags);
  353. }
  354. if (hdwp)
  355. EndDeferWindowPos(hdwp);
  356. if ( !rgn )
  357. rgn = CreateRectRgn( 0, 0, 0, 0 );
  358. if (fRedraw)
  359. {
  360. GetUpdateRgn(hwnd, rgn, FALSE);
  361. for ( pc = layout; pc < pl && hdwp; pc++ )
  362. {
  363. if ( pc->rgn )
  364. {
  365. OffsetRgn( pc->rgn, pc->x, pc->y );
  366. CombineRgn( rgn, rgn, pc->rgn, RGN_OR );
  367. }
  368. }
  369. RedrawWindow(hwnd, NULL, rgn, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN);
  370. }
  371. if (g_rgnUpdate)
  372. {
  373. GetUpdateRgn(hwnd, g_rgnUpdate, FALSE);
  374. for(pc = layout; pc < pl && hdwp; pc++)
  375. {
  376. if (pc->rgn)
  377. {
  378. OffsetRgn(pc->rgn, pc->x, pc->y);
  379. CombineRgn(g_rgnUpdate, g_rgnUpdate, pc->rgn, RGN_OR);
  380. }
  381. }
  382. }
  383. for(pc = layout; pc < pl && hdwp; pc++) if (pc->rgn) DeleteObject(pc->rgn);
  384. }
  385. if ( rgn )
  386. DeleteObject( rgn );
  387. ValidateRgn(hwnd, NULL);
  388. }
  389. void Downloads_DisplayChange(HWND hwndDlg)
  390. {
  391. ListView_SetTextColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMFG));
  392. ListView_SetBkColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMBG));
  393. ListView_SetTextBkColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMBG));
  394. downloadList.SetFont(dialogSkinner.GetFont());
  395. LayoutWindows(hwndDlg, TRUE);
  396. }
  397. static void DownloadsDialog_SkinControls(HWND hwnd, const INT *itemList, INT itemCount, UINT skinType, UINT skinStyle)
  398. {
  399. MLSKINWINDOW skinWindow = {0};
  400. skinWindow.style = skinStyle;
  401. skinWindow.skinType = skinType;
  402. for(INT i = 0; i < itemCount; i++)
  403. {
  404. skinWindow.hwndToSkin = GetDlgItem(hwnd, itemList[i]);
  405. if (NULL != skinWindow.hwndToSkin)
  406. {
  407. MLSkinWindow(plugin.hwndLibraryParent, &skinWindow);
  408. }
  409. }
  410. }
  411. static void DownloadDialog_InitializeList(HWND hwnd)
  412. {
  413. HWND hControl = GetDlgItem(hwnd, IDC_DOWNLOADLIST);
  414. if (NULL == hControl) return;
  415. UINT styleEx = (UINT)GetWindowLongPtr(hControl, GWL_EXSTYLE);
  416. SetWindowLongPtr(hControl, GWL_EXSTYLE, styleEx & ~WS_EX_NOPARENTNOTIFY);
  417. styleEx = LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP;
  418. SendMessage(hControl, LVM_SETEXTENDEDLISTVIEWSTYLE, styleEx, styleEx);
  419. SendMessage(hControl, LVM_SETUNICODEFORMAT, (WPARAM)TRUE, 0L);
  420. MLSKINWINDOW skinWindow;
  421. skinWindow.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_ALTERNATEITEMS;
  422. skinWindow.skinType = SKINNEDWND_TYPE_LISTVIEW;
  423. skinWindow.hwndToSkin = hControl;
  424. MLSkinWindow(plugin.hwndLibraryParent, &skinWindow);
  425. }
  426. bool COL_CHANNEL_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
  427. {
  428. return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  429. (item1->f?item1->f->channel:item1->channel), -1,
  430. (item2->f?item2->f->channel:item2->channel), -1));
  431. }
  432. bool COL_ITEM_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
  433. {
  434. return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  435. (item1->f?item1->f->item:item1->item), -1,
  436. (item2->f?item2->f->item:item2->item), -1));
  437. }
  438. bool COL_PROGRESS_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
  439. {
  440. return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  441. (item1->f?WASABI_API_LNGSTRINGW(IDS_DONE):item1->status), -1,
  442. (item2->f?WASABI_API_LNGSTRINGW(IDS_DONE):item2->status), -1));
  443. }
  444. bool COL_PATH_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
  445. {
  446. return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  447. (item1->f?item1->f->path:item1->path), -1,
  448. (item2->f?item2->f->path:item2->path), -1));
  449. }
  450. static BOOL Downloads_SortItems(int sortColumn)
  451. {
  452. AutoLock lock (downloadedFiles);
  453. switch (sortColumn)
  454. {
  455. case COL_CHANNEL:
  456. std::sort(listContents.begin(), listContents.end(), COL_CHANNEL_Sort);
  457. return TRUE;
  458. case COL_ITEM:
  459. std::sort(listContents.begin(), listContents.end(), COL_ITEM_Sort);
  460. return TRUE;
  461. case COL_PROGRESS:
  462. std::sort(listContents.begin(), listContents.end(), COL_PROGRESS_Sort);
  463. return TRUE;
  464. case COL_PATH:
  465. std::sort(listContents.begin(), listContents.end(), COL_PATH_Sort);
  466. return TRUE;
  467. }
  468. return FALSE;
  469. }
  470. static void Downloads_SetListSortColumn(HWND hwnd, INT listId, INT index, BOOL fAscending)
  471. {
  472. HWND hItems = GetDlgItem(hwnd, listId);
  473. if (NULL == hItems) return;
  474. HWND hHeader = (HWND)SNDMSG(hItems, LVM_GETHEADER, 0, 0L);
  475. if (NULL == hHeader) return;
  476. HDITEM item;
  477. item.mask = HDI_FORMAT;
  478. // reset first (ml req)
  479. INT count = (INT)SNDMSG(hHeader, HDM_GETITEMCOUNT, 0, 0L);
  480. for (INT i = 0; i < count; i++)
  481. {
  482. if (index != i && FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, i, (LPARAM)&item))
  483. {
  484. if (0 != ((HDF_SORTUP | HDF_SORTDOWN) & item.fmt))
  485. {
  486. item.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
  487. SNDMSG(hHeader, HDM_SETITEM, i, (LPARAM)&item);
  488. }
  489. }
  490. }
  491. if (FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, index, (LPARAM)&item))
  492. {
  493. INT fmt = item.fmt & ~(HDF_SORTUP | HDF_SORTDOWN);
  494. fmt |= (FALSE == fAscending) ? HDF_SORTDOWN : HDF_SORTUP;
  495. if (fmt != item.fmt)
  496. {
  497. item.fmt = fmt;
  498. SNDMSG(hHeader, HDM_SETITEM, index, (LPARAM)&item);
  499. }
  500. }
  501. }
  502. static BOOL Downloads_Sort(HWND hwnd, INT iColumn, bool fAscending)
  503. {
  504. BOOL result = TRUE;
  505. downloadsSortAscending = fAscending;
  506. Downloads_SortItems(iColumn);
  507. Downloads_SetListSortColumn(hwnd, IDC_DOWNLOADLIST, iColumn, fAscending);
  508. if (FALSE != result)
  509. {
  510. HWND hItems = GetDlgItem(hwnd, IDC_DOWNLOADLIST);
  511. if (NULL != hItems)
  512. InvalidateRect(hItems, NULL, TRUE);
  513. }
  514. return TRUE;
  515. }
  516. void Downloads_UpdateButtonText(HWND hwndDlg, int _enqueuedef)
  517. {
  518. if (groupBtn)
  519. {
  520. switch(_enqueuedef)
  521. {
  522. case 1:
  523. SetDlgItemTextW(hwndDlg, IDC_PLAY, view.enqueue);
  524. customAllowed = FALSE;
  525. break;
  526. default:
  527. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  528. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  529. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK_IN_USE, (INT_PTR)_enqueuedef, 0, 0};
  530. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  531. if (pszTextW && pszTextW[0] != 0)
  532. {
  533. // set this to be a bit different so we can just use one button and not the
  534. // mixable one as well (leaving that to prevent messing with the resources)
  535. SetDlgItemTextW(hwndDlg, IDC_PLAY, pszTextW);
  536. customAllowed = TRUE;
  537. }
  538. else
  539. {
  540. SetDlgItemTextW(hwndDlg, IDC_PLAY, view.play);
  541. customAllowed = FALSE;
  542. }
  543. break;
  544. }
  545. }
  546. }
  547. static void Downloads_ManageButtons( HWND hwndDlg )
  548. {
  549. int has_selection = downloadList.GetSelectedCount();
  550. const int buttonids[] = { IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM, IDC_REMOVE };
  551. for ( size_t i = 0; i != sizeof( buttonids ) / sizeof( buttonids[ 0 ] ); i++ )
  552. {
  553. HWND controlHWND = GetDlgItem( hwndDlg, buttonids[ i ] );
  554. EnableWindow( controlHWND, has_selection );
  555. }
  556. }
  557. void Downloads_Init(HWND hwndDlg)
  558. {
  559. HWND hLibrary = plugin.hwndLibraryParent;
  560. current_window = hwndDlg;
  561. if (!view.play)
  562. {
  563. SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
  564. }
  565. HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_VIEW_DOWNLOAD_ACCELERATORS);
  566. if (accel)
  567. WASABI_API_APP->app_addAccelerators(hwndDlg, &accel, 1, TRANSLATE_MODE_CHILD);
  568. g_context_menus2 = WASABI_API_LOADMENU(IDR_MENU1);
  569. groupBtn = ML_GROUPBTN_VAL();
  570. enqueuedef = (ML_ENQDEF_VAL() == 1);
  571. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  572. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  573. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG(IDC_CUSTOM, IDC_ENQUEUE), (INT_PTR)L"ml_downloads"};
  574. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  575. if (pszTextW && pszTextW[0] != 0)
  576. {
  577. // set this to be a bit different so we can just use one button and not the
  578. // mixable one as well (leaving that to prevent messing with the resources)
  579. customAllowed = TRUE;
  580. SetDlgItemTextW(hwndDlg, IDC_CUSTOM, pszTextW);
  581. }
  582. else
  583. customAllowed = FALSE;
  584. MLSkinWindow2(hLibrary, hwndDlg, SKINNEDWND_TYPE_AUTO, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS);
  585. const INT szControls[] = {IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM};
  586. DownloadsDialog_SkinControls(hwndDlg, szControls, ARRAYSIZE(szControls), SKINNEDWND_TYPE_AUTO,
  587. SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn ? SWBS_SPLITBUTTON : 0));
  588. const INT szControlz[] = {IDC_REMOVE, IDC_CLEANUP, IDC_STATUS};
  589. DownloadsDialog_SkinControls(hwndDlg, szControlz, ARRAYSIZE(szControlz), SKINNEDWND_TYPE_AUTO,
  590. SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS);
  591. DownloadDialog_InitializeList(hwndDlg);
  592. Downloads_UpdateStatusBar(hwndDlg);
  593. downloadList.setwnd(GetDlgItem(hwndDlg, IDC_DOWNLOADLIST));
  594. downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_CHANNEL), downloadsChannelWidth);
  595. downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_ITEM), downloadsItemWidth);
  596. downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_PROGRESS), downloadsProgressWidth);
  597. downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_PATH), downloadsPathWidth);
  598. DownloadsUpdated();
  599. downloadList.SetVirtualCount((int)listContents.size());
  600. Downloads_UpdateButtonText(hwndDlg, enqueuedef == 1);
  601. Downloads_ManageButtons(hwndDlg);
  602. Downloads_DisplayChange(hwndDlg);
  603. Downloads_Sort(hwndDlg, downloadsItemSort, downloadsSortAscending);
  604. SetTimer(hwndDlg, DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR , 1000, 0);
  605. }
  606. void Downloads_Timer( HWND hwndDlg, UINT timerId )
  607. {
  608. switch ( timerId )
  609. {
  610. case DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR:
  611. Downloads_UpdateStatusBar( hwndDlg );
  612. {
  613. AutoLock lock( downloadStatus.statusLock );
  614. for ( DownloadListItem *l_content : listContents )
  615. {
  616. if ( l_content->token )
  617. {
  618. size_t d = downloadStatus.downloads[ l_content->token ].downloaded;
  619. size_t s = downloadStatus.downloads[ l_content->token ].maxSize;
  620. if ( s )
  621. StringCchPrintf( l_content->status, 20, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_PERCENT ), (int)( d / ( s / 100 ) ) );
  622. else
  623. {
  624. WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOADING, l_content->status, 20 );
  625. }
  626. PostMessage( downloadList.getwnd(), LVM_REDRAWITEMS, 0, listContents.size() );
  627. }
  628. }
  629. }
  630. break;
  631. }
  632. }
  633. static INT Downloads_GetListSortColumn(HWND hwnd, INT listId, bool *fAscending)
  634. {
  635. HWND hItems = GetDlgItem(hwnd, listId);
  636. if (NULL != hItems)
  637. {
  638. HWND hHeader = (HWND)SNDMSG(hItems, LVM_GETHEADER, 0, 0L);
  639. if (NULL != hHeader)
  640. {
  641. HDITEM item;
  642. item.mask = HDI_FORMAT;
  643. INT count = (INT)SNDMSG(hHeader, HDM_GETITEMCOUNT, 0, 0L);
  644. for (INT i = 0; i < count; i++)
  645. {
  646. if (FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, i, (LPARAM)&item) &&
  647. 0 != ((HDF_SORTUP | HDF_SORTDOWN) & item.fmt))
  648. {
  649. if (NULL != fAscending)
  650. {
  651. *fAscending = (0 != (HDF_SORTUP & item.fmt));
  652. }
  653. return i;
  654. }
  655. }
  656. }
  657. }
  658. return -1;
  659. }
  660. void Downloads_Destroy( HWND hwndDlg )
  661. {
  662. downloadsChannelWidth = downloadList.GetColumnWidth( COL_CHANNEL );
  663. downloadsItemWidth = downloadList.GetColumnWidth( COL_ITEM );
  664. downloadsProgressWidth = downloadList.GetColumnWidth( COL_PROGRESS );
  665. downloadsPathWidth = downloadList.GetColumnWidth( COL_PATH );
  666. for ( DownloadListItem *l_content : listContents )
  667. delete l_content;
  668. listContents.clear();
  669. downloadList.setwnd( NULL );
  670. bool fAscending;
  671. downloadsItemSort = Downloads_GetListSortColumn( hwndDlg, IDC_DOWNLOADLIST, &fAscending );
  672. downloadsSortAscending = ( -1 != downloadsItemSort ) ? ( FALSE != fAscending ) : true;
  673. }
  674. void Downloads_Remove( bool del = false, HWND parent = NULL )
  675. {
  676. int d = -1;
  677. int r = 0;
  678. while ( GetDownload( d ) )
  679. {
  680. int download = d - r;
  681. DownloadListItem *item = listContents[ download ];
  682. if ( item->f )
  683. {
  684. AutoLock lock( downloadedFiles );
  685. int j = 0;
  686. for ( DownloadList::iterator i = downloadedFiles.begin(); i != downloadedFiles.end(); i++ )
  687. {
  688. if ( !_wcsicmp( i->path, item->f->path ) )
  689. {
  690. if ( del )
  691. {
  692. if ( !downloadedFiles.RemoveAndDelete( j ) )
  693. MessageBox( parent, WASABI_API_LNGSTRINGW( IDS_DELETEFAILED ), downloadedFiles.downloadList[ j ].path, 0 );
  694. }
  695. else
  696. downloadedFiles.Remove( j );
  697. delete item;
  698. listContents.erase(listContents.begin() + download);
  699. r++;
  700. break;
  701. }
  702. ++j;
  703. }
  704. }
  705. else if ( item->token )
  706. {
  707. AutoLock lock( downloadStatus.statusLock );
  708. downloadStatus.downloads[ item->token ].killswitch = 1;
  709. delete item;
  710. listContents.erase( listContents.begin() + download );
  711. r++;
  712. }
  713. else
  714. {
  715. delete item;
  716. listContents.erase( listContents.begin() + download );
  717. r++;
  718. }
  719. }
  720. downloadList.SetVirtualCountAsync( (int)listContents.size() );
  721. Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
  722. }
  723. void Downloads_Delete( HWND parent )
  724. {
  725. wchar_t message[ 256 ] = { 0 };
  726. int c = downloadList.GetSelectedCount();
  727. if ( !c )
  728. return;
  729. else if ( c == 1 )
  730. WASABI_API_LNGSTRINGW_BUF( IDS_PERM_DELETE_ARE_YOU_SURE, message, 256 );
  731. else
  732. StringCchPrintf( message, 256, WASABI_API_LNGSTRINGW( IDS_PERM_DELETE_THESE_ARE_YOU_SURE ), c );
  733. if ( MessageBox( NULL, message, WASABI_API_LNGSTRINGW( IDS_DELETION ), MB_ICONWARNING | MB_YESNO ) == IDNO )
  734. return;
  735. Downloads_Remove( true, parent );
  736. }
  737. void Downloads_CleanUp(HWND hwndDlg)
  738. {
  739. wchar_t titleStr[64] = {0};
  740. if ( MessageBox( hwndDlg, WASABI_API_LNGSTRINGW( IDS_CLEAR_ALL_FINISHED_DOWNLOADS ), WASABI_API_LNGSTRINGW_BUF( IDS_CLEAN_UP_LIST, titleStr, 64 ), MB_ICONWARNING | MB_YESNO ) == IDNO )
  741. return;
  742. {
  743. AutoLock lock( downloadedFiles );
  744. downloadedFiles.downloadList.clear();
  745. }
  746. DownloadsUpdated();
  747. }
  748. void Downloads_InfoBox( HWND parent )
  749. {
  750. int download = -1;
  751. if ( GetDownload( download ) )
  752. {
  753. const wchar_t *fn;
  754. if ( listContents[ download ]->f )
  755. fn = listContents[ download ]->f->path;
  756. else
  757. fn = listContents[ download ]->path;
  758. if ( fn )
  759. {
  760. infoBoxParamW p = { parent, fn };
  761. SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&p, IPC_INFOBOXW );
  762. }
  763. }
  764. }
  765. void Downloads_SelectAll()
  766. {
  767. int l = downloadList.GetCount();
  768. for ( int i = 0; i < l; i++ )
  769. downloadList.SetSelected( i );
  770. }
  771. static void exploreItemFolder( HWND hwndDlg )
  772. {
  773. if ( downloadList.GetSelectionMark() >= 0 )
  774. {
  775. int download = -1;
  776. while ( GetDownload( download ) )
  777. {
  778. wchar_t *file;
  779. if ( listContents[ download ]->f )
  780. file = listContents[ download ]->f->path;
  781. else
  782. file = listContents[ download ]->path;
  783. WASABI_API_EXPLORERFINDFILE->AddFile( file );
  784. }
  785. WASABI_API_EXPLORERFINDFILE->ShowFiles();
  786. }
  787. }
  788. int we_are_drag_and_dropping = 0;
  789. static void Downloads_OnColumnClick(HWND hwnd, NMLISTVIEW *plv)
  790. {
  791. bool fAscending;
  792. INT iSort = Downloads_GetListSortColumn(hwnd, IDC_DOWNLOADLIST, &fAscending);
  793. fAscending = (-1 != iSort && iSort == plv->iSubItem) ? (!fAscending) : true;
  794. Downloads_Sort(hwnd, plv->iSubItem, fAscending);
  795. }
  796. LRESULT DownloadList_Notify( LPNMHDR l, HWND hwndDlg )
  797. {
  798. switch ( l->code )
  799. {
  800. case LVN_COLUMNCLICK:
  801. Downloads_OnColumnClick( hwndDlg, (NMLISTVIEW *)l );
  802. break;
  803. case NM_DBLCLK:
  804. Downloads_Play( ( ( !!( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ) ^ ML_ENQDEF_VAL() ) );
  805. break;
  806. case LVN_BEGINDRAG:
  807. we_are_drag_and_dropping = 1;
  808. SetCapture( hwndDlg );
  809. break;
  810. case LVN_ITEMCHANGED:
  811. Downloads_ManageButtons( hwndDlg );
  812. break;
  813. case LVN_GETDISPINFO:
  814. NMLVDISPINFO *lpdi = (NMLVDISPINFO *)l;
  815. size_t item = lpdi->item.iItem;
  816. if ( item < 0 || item >= listContents.size() )
  817. return 0;
  818. if ( FALSE == downloadsSortAscending )
  819. item = listContents.size() - item - 1;
  820. DownloadListItem *l = listContents[ item ];
  821. if ( lpdi->item.mask & LVIF_TEXT )
  822. {
  823. lpdi->item.pszText[ 0 ] = 0;
  824. switch ( lpdi->item.iSubItem )
  825. {
  826. case COL_CHANNEL:
  827. if ( !l->token && l->f )
  828. lstrcpyn( lpdi->item.pszText, l->f->channel, lpdi->item.cchTextMax );
  829. else
  830. lstrcpyn( lpdi->item.pszText, l->channel, lpdi->item.cchTextMax );
  831. break;
  832. case COL_ITEM:
  833. if ( !l->token && l->f )
  834. lstrcpyn( lpdi->item.pszText, l->f->item, lpdi->item.cchTextMax );
  835. else
  836. lstrcpyn( lpdi->item.pszText, l->item, lpdi->item.cchTextMax );
  837. break;
  838. case COL_PROGRESS:
  839. if( !l->token && l->f )
  840. WASABI_API_LNGSTRINGW_BUF( IDS_DONE, lpdi->item.pszText, lpdi->item.cchTextMax );
  841. else
  842. lstrcpyn( lpdi->item.pszText, l->status, lpdi->item.cchTextMax );
  843. break;
  844. case COL_PATH:
  845. if ( !l->token && l->f )
  846. lstrcpyn( lpdi->item.pszText, l->f->path, lpdi->item.cchTextMax );
  847. else
  848. {
  849. if ( l->path )
  850. lstrcpyn( lpdi->item.pszText, l->path, lpdi->item.cchTextMax );
  851. }
  852. break;
  853. }
  854. }
  855. break;
  856. }
  857. return 0;
  858. }
  859. void listbuild( wchar_t **buf, int &buf_size, int &buf_pos, const wchar_t *tbuf )
  860. {
  861. if ( !*buf )
  862. {
  863. *buf = (wchar_t *)calloc( 4096, sizeof( wchar_t ) );
  864. if ( *buf )
  865. {
  866. buf_size = 4096;
  867. buf_pos = 0;
  868. }
  869. else
  870. {
  871. buf_size = buf_pos = 0;
  872. }
  873. }
  874. int newsize = buf_pos + lstrlenW( tbuf ) + 1;
  875. if ( newsize < buf_size )
  876. {
  877. size_t old_buf_size = buf_size;
  878. buf_size = newsize + 4096;
  879. wchar_t *new_buf = (wchar_t *)realloc( *buf, ( buf_size + 1 ) * sizeof( wchar_t ) );
  880. if ( new_buf )
  881. {
  882. *buf = new_buf;
  883. }
  884. else
  885. {
  886. new_buf = (wchar_t*)calloc( ( buf_size + 1 ), sizeof( wchar_t ) );
  887. if ( new_buf )
  888. {
  889. memcpy( new_buf, *buf, ( old_buf_size * sizeof( wchar_t ) ) );
  890. free( *buf );
  891. *buf = new_buf;
  892. }
  893. else buf_size = (int)old_buf_size;
  894. }
  895. }
  896. StringCchCopyW( *buf + buf_pos, buf_size, tbuf );
  897. buf_pos = newsize;
  898. }
  899. wchar_t *getSelectedList()
  900. {
  901. wchar_t *path = NULL;
  902. int buf_pos = 0;
  903. int buf_size = 0;
  904. int download = -1;
  905. while ( GetDownload( download ) )
  906. {
  907. if ( listContents[ download ]->f )
  908. listbuild( &path, buf_size, buf_pos, listContents[ download ]->f->path );
  909. }
  910. if ( path )
  911. path[ buf_pos ] = 0;
  912. return path;
  913. }
  914. void SwapPlayEnqueueInMenu( HMENU listMenu )
  915. {
  916. int playPos = -1, enqueuePos = -1;
  917. MENUITEMINFOW playItem = { sizeof( MENUITEMINFOW ), 0, }, enqueueItem = { sizeof( MENUITEMINFOW ), 0, };
  918. int numItems = GetMenuItemCount( listMenu );
  919. for ( int i = 0; i < numItems; i++ )
  920. {
  921. UINT id = GetMenuItemID( listMenu, i );
  922. if ( id == IDC_PLAY )
  923. {
  924. playItem.fMask = MIIM_ID;
  925. playPos = i;
  926. GetMenuItemInfoW( listMenu, i, TRUE, &playItem );
  927. }
  928. else if ( id == IDC_ENQUEUE )
  929. {
  930. enqueueItem.fMask = MIIM_ID;
  931. enqueuePos = i;
  932. GetMenuItemInfoW( listMenu, i, TRUE, &enqueueItem );
  933. }
  934. }
  935. playItem.wID = IDC_ENQUEUE;
  936. enqueueItem.wID = IDC_PLAY;
  937. SetMenuItemInfoW( listMenu, playPos, TRUE, &playItem );
  938. SetMenuItemInfoW( listMenu, enqueuePos, TRUE, &enqueueItem );
  939. }
  940. void SyncMenuWithAccelerators( HWND hwndDlg, HMENU menu )
  941. {
  942. HACCEL szAccel[ 24 ] = { 0 };
  943. INT c = WASABI_API_APP->app_getAccelerators( hwndDlg, szAccel, sizeof( szAccel ) / sizeof( szAccel[ 0 ] ), FALSE );
  944. AppendMenuShortcuts( menu, szAccel, c, MSF_REPLACE );
  945. }
  946. void UpdateMenuItems( HWND hwndDlg, HMENU menu )
  947. {
  948. bool swapPlayEnqueue = false;
  949. if ( ML_ENQDEF_VAL() )
  950. {
  951. SwapPlayEnqueueInMenu( menu );
  952. swapPlayEnqueue = true;
  953. }
  954. SyncMenuWithAccelerators( hwndDlg, menu );
  955. if ( swapPlayEnqueue )
  956. SwapPlayEnqueueInMenu( menu );
  957. }
  958. int IPC_LIBRARY_SENDTOMENU = 0;
  959. librarySendToMenuStruct s = { 0 };
  960. static void DownloadList_RightClick(HWND hwndDlg, HWND listHwnd, POINTS pts)
  961. {
  962. POINT pt;
  963. POINTSTOPOINT(pt, pts);
  964. RECT controlRect, headerRect;
  965. if (FALSE == GetClientRect(listHwnd, &controlRect))
  966. SetRectEmpty(&controlRect);
  967. else
  968. MapWindowPoints(listHwnd, HWND_DESKTOP, (POINT*)&controlRect, 2);
  969. if ( -1 == pt.x && -1 == pt.y )
  970. {
  971. RECT itemRect;
  972. int selected = downloadList.GetNextSelected();
  973. if ( selected != -1 ) // if something is selected we'll drop the menu from there
  974. {
  975. downloadList.GetItemRect( selected, &itemRect );
  976. ClientToScreen( listHwnd, (POINT *)&itemRect );
  977. }
  978. else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location
  979. {
  980. GetWindowRect( listHwnd, &itemRect );
  981. HWND hHeader = (HWND)SNDMSG( listHwnd, LVM_GETHEADER, 0, 0L );
  982. RECT headerRect;
  983. if ( ( WS_VISIBLE & GetWindowLongPtr( hHeader, GWL_STYLE ) ) && GetWindowRect( hHeader, &headerRect ) )
  984. {
  985. itemRect.top += ( headerRect.bottom - headerRect.top );
  986. }
  987. }
  988. pt.x = itemRect.left;
  989. pt.y = itemRect.top;
  990. }
  991. HWND hHeader = (HWND)SNDMSG(listHwnd, LVM_GETHEADER, 0, 0L);
  992. if ( 0 == ( WS_VISIBLE & GetWindowLongPtr( hHeader, GWL_STYLE ) ) || FALSE == GetWindowRect( hHeader, &headerRect ) )
  993. {
  994. SetRectEmpty( &headerRect );
  995. }
  996. if ( FALSE != PtInRect( &headerRect, pt ) )
  997. {
  998. return;
  999. }
  1000. LVHITTESTINFO hitTest;
  1001. hitTest.pt = pt;
  1002. MapWindowPoints( HWND_DESKTOP, listHwnd, &hitTest.pt, 1 );
  1003. int index = ( downloadList.GetNextSelected() != -1 ? ListView_HitTest( listHwnd, &hitTest ) : -1 );
  1004. HMENU baseMenu = WASABI_API_LOADMENU( IDR_MENU1 );
  1005. if ( baseMenu == NULL )
  1006. return;
  1007. HMENU menu = GetSubMenu( baseMenu, 2 );
  1008. if ( menu != NULL )
  1009. {
  1010. UINT enableExtras = MF_BYCOMMAND | MF_ENABLED;
  1011. if ( index == -1 )
  1012. enableExtras |= ( MF_GRAYED | MF_DISABLED );
  1013. EnableMenuItem( menu, IDC_PLAY, enableExtras );
  1014. EnableMenuItem( menu, IDC_ENQUEUE, enableExtras );
  1015. EnableMenuItem( menu, IDC_REMOVE, enableExtras );
  1016. EnableMenuItem( menu, IDC_DELETE, enableExtras );
  1017. EnableMenuItem( menu, IDC_INFOBOX, enableExtras );
  1018. EnableMenuItem( menu, ID_DOWNLOADS_EXPLORERITEMFOLDER, enableExtras );
  1019. EnableMenuItem( menu, 2, MF_BYPOSITION | ( index == -1 ? ( MF_GRAYED | MF_DISABLED ) : MF_ENABLED ) );
  1020. { // send-to menu shit...
  1021. ZeroMemory( &s, sizeof( s ) );
  1022. IPC_LIBRARY_SENDTOMENU = SendMessage( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "LibrarySendToMenu", IPC_REGISTER_WINAMP_IPCMESSAGE );
  1023. if ( IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
  1024. {
  1025. s.mode = 1;
  1026. s.hwnd = hwndDlg;
  1027. s.data_type = ML_TYPE_FILENAMESW;
  1028. s.ctx[ 1 ] = 1;
  1029. s.build_hMenu = GetSubMenu( menu, 2 );
  1030. }
  1031. }
  1032. UpdateMenuItems( hwndDlg, menu );
  1033. int r = Menu_TrackPopup( plugin.hwndLibraryParent, menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwndDlg, NULL );
  1034. if ( !SendMessage( hwndDlg, WM_COMMAND, r, 0 ) )
  1035. {
  1036. s.menu_id = r; // more send to menu shit...
  1037. if ( s.mode == 2 && SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
  1038. {
  1039. s.mode = 3;
  1040. s.data_type = ML_TYPE_FILENAMESW;
  1041. wchar_t *path = getSelectedList();
  1042. if ( path )
  1043. {
  1044. s.data = path;
  1045. SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU );
  1046. free( path );
  1047. }
  1048. }
  1049. }
  1050. if ( s.mode )
  1051. { // yet more send to menu shit...
  1052. s.mode = 4;
  1053. SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU ); // cleanup
  1054. }
  1055. if ( NULL != s.build_hMenu )
  1056. {
  1057. DestroyMenu( s.build_hMenu );
  1058. s.build_hMenu = NULL;
  1059. }
  1060. }
  1061. DestroyMenu( baseMenu );
  1062. }
  1063. static void Downloads_ContextMenu( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
  1064. {
  1065. HWND sourceWindow = (HWND)wParam;
  1066. if ( sourceWindow == downloadList.getwnd() )
  1067. DownloadList_RightClick( hwndDlg, sourceWindow, MAKEPOINTS( lParam ) );
  1068. }
  1069. BOOL Downloads_ButtonPopupMenu( HWND hwndDlg, int buttonId, HMENU menu, int flags )
  1070. {
  1071. RECT r;
  1072. HWND buttonHWND = GetDlgItem( hwndDlg, buttonId );
  1073. GetWindowRect( buttonHWND, &r );
  1074. UpdateMenuItems( hwndDlg, menu );
  1075. MLSkinnedButton_SetDropDownState( buttonHWND, TRUE );
  1076. UINT tpmFlags = TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN;
  1077. if ( !( flags & BPM_WM_COMMAND ) )
  1078. tpmFlags |= TPM_RETURNCMD;
  1079. int x = Menu_TrackPopup( plugin.hwndLibraryParent, menu, tpmFlags, r.left, r.top, hwndDlg, NULL );
  1080. if ( ( flags & BPM_ECHO_WM_COMMAND ) && x )
  1081. SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( x, 0 ), 0 );
  1082. MLSkinnedButton_SetDropDownState( buttonHWND, FALSE );
  1083. return x;
  1084. }
  1085. static void Downloads_Play( HWND hwndDlg, HWND from, UINT idFrom )
  1086. {
  1087. HMENU listMenu = GetSubMenu( g_context_menus2, 0 );
  1088. int count = GetMenuItemCount( listMenu );
  1089. if ( count > 2 )
  1090. {
  1091. for ( int i = 2; i < count; i++ )
  1092. {
  1093. DeleteMenu( listMenu, 2, MF_BYPOSITION );
  1094. }
  1095. }
  1096. Downloads_ButtonPopupMenu( hwndDlg, idFrom, listMenu, BPM_WM_COMMAND );
  1097. }
  1098. static BOOL WINAPI DownloadDialog_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1099. {
  1100. switch (msg)
  1101. {
  1102. case WM_INITMENUPOPUP: // yet yet more send to menu shit...
  1103. if (wParam && (HMENU)wParam == s.build_hMenu && s.mode==1)
  1104. {
  1105. if (SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&s,IPC_LIBRARY_SENDTOMENU)==0xffffffff)
  1106. s.mode=2;
  1107. }
  1108. break;
  1109. case WM_CONTEXTMENU:
  1110. Downloads_ContextMenu(hwndDlg, wParam, lParam);
  1111. return TRUE;
  1112. case WM_NOTIFYFORMAT:
  1113. return NFR_UNICODE;
  1114. case WM_INITDIALOG:
  1115. Downloads_Init(hwndDlg);
  1116. break;
  1117. case WM_NOTIFY:
  1118. {
  1119. LPNMHDR l = (LPNMHDR)lParam;
  1120. if (l->idFrom == IDC_DOWNLOADLIST)
  1121. return DownloadList_Notify(l,hwndDlg);
  1122. }
  1123. break;
  1124. case WM_DESTROY:
  1125. Downloads_Destroy(hwndDlg);
  1126. return 0;
  1127. case WM_DISPLAYCHANGE:
  1128. Downloads_DisplayChange(hwndDlg);
  1129. return 0;
  1130. case WM_TIMER:
  1131. Downloads_Timer(hwndDlg, wParam);
  1132. break;
  1133. case WM_MOUSEMOVE:
  1134. if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
  1135. {
  1136. POINT p = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
  1137. ClientToScreen(hwndDlg, &p);
  1138. mlDropItemStruct m;
  1139. ZeroMemory(&m, sizeof(mlDropItemStruct));
  1140. m.type = ML_TYPE_FILENAMESW;
  1141. m.p = p;
  1142. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
  1143. }
  1144. break;
  1145. case WM_LBUTTONUP:
  1146. if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
  1147. {
  1148. we_are_drag_and_dropping = 0;
  1149. ReleaseCapture();
  1150. POINT p = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
  1151. ClientToScreen(hwndDlg, &p);
  1152. mlDropItemStruct m = {0};
  1153. m.type = ML_TYPE_FILENAMESW;
  1154. m.p = p;
  1155. m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR;
  1156. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
  1157. if (m.result > 0)
  1158. {
  1159. m.flags = 0;
  1160. m.result = 0;
  1161. wchar_t* path = getSelectedList();
  1162. if(path)
  1163. {
  1164. m.data = path;
  1165. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
  1166. free(path);
  1167. }
  1168. }
  1169. }
  1170. break;
  1171. case WM_PAINT:
  1172. {
  1173. int tab[] = { IDC_DOWNLOADLIST|DCW_SUNKENBORDER};
  1174. dialogSkinner.Draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
  1175. }
  1176. return 0;
  1177. case WM_WINDOWPOSCHANGED:
  1178. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  1179. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  1180. {
  1181. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags));
  1182. }
  1183. return 0;
  1184. case WM_USER + 0x200:
  1185. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); // yes, we support no - redraw resize
  1186. return TRUE;
  1187. case WM_USER + 0x201:
  1188. offsetX = (short)LOWORD(wParam);
  1189. offsetY = (short)HIWORD(wParam);
  1190. g_rgnUpdate = (HRGN)lParam;
  1191. return TRUE;
  1192. case WM_APP + 104:
  1193. {
  1194. Downloads_UpdateButtonText(hwndDlg, wParam);
  1195. LayoutWindows(hwndDlg, TRUE);
  1196. return 0;
  1197. }
  1198. case WM_COMMAND:
  1199. switch ( LOWORD( wParam ) )
  1200. {
  1201. case IDC_PLAY:
  1202. case IDC_ENQUEUE:
  1203. case IDC_CUSTOM:
  1204. if ( HIWORD( wParam ) == MLBN_DROPDOWN )
  1205. {
  1206. Downloads_Play( hwndDlg, (HWND)lParam, LOWORD( wParam ) );
  1207. }
  1208. else
  1209. {
  1210. bool action;
  1211. if ( LOWORD( wParam ) == IDC_PLAY )
  1212. {
  1213. action = ( HIWORD( wParam ) == 1 ) ? ML_ENQDEF_VAL() == 1 : 0;
  1214. }
  1215. else if ( LOWORD( wParam ) == IDC_ENQUEUE )
  1216. {
  1217. action = ( HIWORD( wParam ) == 1 ) ? ML_ENQDEF_VAL() != 1 : 1;
  1218. }
  1219. else
  1220. break;
  1221. Downloads_Play( action );
  1222. }
  1223. break;
  1224. case IDC_REMOVE:
  1225. Downloads_Remove();
  1226. break;
  1227. case IDC_DELETE:
  1228. Downloads_Delete( hwndDlg );
  1229. break;
  1230. case IDC_CLEANUP:
  1231. Downloads_CleanUp( hwndDlg );
  1232. break;
  1233. case IDC_INFOBOX:
  1234. Downloads_InfoBox( hwndDlg );
  1235. break;
  1236. case IDC_SELECTALL:
  1237. Downloads_SelectAll();
  1238. break;
  1239. case ID_DOWNLOADS_EXPLORERITEMFOLDER:
  1240. exploreItemFolder( hwndDlg );
  1241. break;
  1242. default:
  1243. return 0;
  1244. }
  1245. return 1;
  1246. }
  1247. return 0;
  1248. }
  1249. HWND CALLBACK DownloadDialog_Create( HWND hParent, OmService *service )
  1250. {
  1251. return WASABI_API_CREATEDIALOGPARAMW( IDD_DOWNLOADS, hParent, DownloadDialog_DlgProc, (LPARAM)service );
  1252. }