aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp')
-rw-r--r--Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp1657
1 files changed, 1657 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp b/Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp
new file mode 100644
index 00000000..adb2b008
--- /dev/null
+++ b/Src/Plugins/Library/ml_downloads/DownloadsDialog.cpp
@@ -0,0 +1,1657 @@
+#include "main.h"
+#include "api__ml_downloads.h"
+#include "RFCDate.h"
+#include "Downloaded.h"
+#include "DownloadStatus.h"
+#include "Defaults.h"
+#include "../nu/listview.h"
+#include "..\..\General\gen_ml/ml_ipc.h"
+#include "..\..\General\gen_ml/menu.h"
+#include <vector>
+#include "../nu/menushortcuts.h"
+#include <commctrl.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+#include <strsafe.h>
+#include <algorithm>
+
+HWND downloads_window = 0;
+extern int downloads_treeItem;
+extern int no_auto_hide;
+int groupBtn = 1, enqueuedef = 0, customAllowed = 0;
+HMENU g_context_menus2 = NULL;
+static viewButtons view;
+
+#ifndef HDF_SORTUP
+#define HDF_SORTUP 0x0400
+#define HDF_SORTDOWN 0x0200
+#endif // !HDF_SORTUP
+
+using namespace Nullsoft::Utility;
+
+enum
+{
+ COL_TITLE = 0,
+ COL_PROGRESS,
+ COL_DATE,
+ COL_SOURCE,
+ COL_SIZE,
+ COL_PATH,
+ NUM_COLUMNS,
+};
+
+int downloadsSourceWidth = DOWNLOADSSOURCEWIDTHDEFAULT;
+int downloadsTitleWidth = DOWNLOADSTITLEWIDTHDEFAULT;
+int downloadsProgressWidth = DOWNLOADSPROGRESSWIDTHDEFAULT;
+int downloadsDateWidth = DOWNLOADSDATEWIDTHDEFAULTS;
+int downloadsSizeWidth = DOWNLOADSSIZEWIDTHDEFAULTS;
+int downloadsPathWidth = DOWNLOADSPATHWIDTHDEFAULTS;
+
+
+W_ListView downloadList;
+int downloadsItemSort = 2; // -1 means no sort active
+bool downloadsSortAscending = false;
+
+enum
+{
+ DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR = 0,
+};
+
+class DownloadListItem
+{
+public:
+ DownloadedFile *f = NULL;
+ DownloadToken token = NULL;
+ wchar_t *source = 0;
+ wchar_t *title = 0;
+ wchar_t *path = 0;
+ wchar_t status[ 20 ] = { 0 };
+
+ DownloadListItem( DownloadedFile *fi )
+ {
+ f = new DownloadedFile( *fi );
+ ZeroMemory( status, sizeof( status ) );
+ }
+
+ DownloadListItem( DownloadToken p_token, const wchar_t *p_source, const wchar_t *p_title, const wchar_t *p_path, size_t p_downloaded, size_t p_maxSize ) : token( p_token )
+ {
+ if ( p_maxSize )
+ StringCchPrintf( status, 20, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_PERCENT ), (int)( p_downloaded / ( p_maxSize / 100 ) ) );
+ else
+ {
+ if ( WAC_API_DOWNLOADMANAGER->IsPending( p_token ) )
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOAD_PENDING, status, 20 );
+ else
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOADING, status, 20 );
+ }
+
+ source = p_source ? _wcsdup( p_source ) : NULL;
+ title = p_title ? _wcsdup( p_title ) : NULL;
+ path = p_path ? _wcsdup( p_path ) : NULL;
+ }
+
+ ~DownloadListItem()
+ {
+ clean();
+
+ if ( f )
+ delete f;
+ }
+
+ void clean()
+ {
+ if ( source )
+ {
+ free( source );
+ source = 0;
+ }
+
+ if ( title )
+ {
+ free( title );
+ title = 0;
+ }
+
+ if ( path )
+ {
+ free( path );
+ path = 0;
+ }
+ }
+};
+
+static std::vector<DownloadListItem*> listContents;
+
+bool GetDownload( int &download )
+{
+ download = ListView_GetNextItem( downloadList.getwnd(), download, LVNI_ALL | LVNI_SELECTED );
+ if ( download == -1 )
+ return false;
+ else
+ return true;
+}
+
+void Downloads_Play( bool enqueue = false )
+{
+ int download = -1;
+ AutoLock lock( downloadedFiles );
+ while ( GetDownload( download ) )
+ {
+ if ( !enqueue )
+ {
+ if ( listContents[ download ]->f )
+ mediaLibrary.PlayFile( listContents[ download ]->f->path );
+ else if ( listContents[ download ]->path )
+ mediaLibrary.PlayFile( listContents[ download ]->path );
+
+ enqueue = true;
+ }
+ else
+ {
+ if ( listContents[ download ]->f )
+ mediaLibrary.EnqueueFile( listContents[ download ]->f->path );
+ else if ( listContents[ download ]->path )
+ mediaLibrary.EnqueueFile( listContents[ download ]->path );
+ }
+ }
+}
+
+void DownloadsUpdated( const DownloadStatus::Status &s, DownloadToken token )
+{
+ listContents.push_back( new DownloadListItem( token, s.source, s.title, s.path, s.downloaded, s.maxSize ) );
+
+ downloadList.SetVirtualCountAsync( (int)listContents.size() );
+}
+
+void DownloadsUpdated( DownloadToken token, const DownloadedFile *f )
+{
+ for ( DownloadListItem *l_content : listContents )
+ {
+ if ( l_content->token == token )
+ {
+ l_content->token = 0;
+ if ( f )
+ {
+ l_content->f = new DownloadedFile( *f );
+
+ l_content->clean();
+ }
+ else
+ lstrcpyn( l_content->status, L"Error", 20 );
+
+ break;
+ }
+ }
+
+ PostMessage( downloadList.getwnd(), LVM_REDRAWITEMS, 0, listContents.size() );
+}
+
+void DownloadsUpdated()
+{
+ for ( DownloadListItem *l_content : listContents )
+ delete l_content;
+
+ listContents.clear();
+
+ for ( DownloadedFile &l_download : downloadedFiles.downloadList )
+ listContents.push_back( new DownloadListItem( &l_download ) );
+
+ {
+ AutoLock lock( downloadStatus.statusLock );
+ for ( DownloadStatus::Downloads::iterator itr = downloadStatus.downloads.begin(); itr != downloadStatus.downloads.end(); itr++ )
+ {
+ listContents.push_back( new DownloadListItem( itr->first, itr->second.source, itr->second.title, itr->second.path, itr->second.downloaded, itr->second.maxSize ) );
+ }
+ }
+
+ downloadList.SetVirtualCountAsync( (int)listContents.size() );
+// Navigation_ShowService( SERVICE_DOWNLOADS, SHOWMODE_AUTO );
+}
+
+static void CleanupDownloads()
+{
+ {
+ AutoLock lock( downloadedFiles );
+ DownloadList::DownloadedFileList &downloads = downloadedFiles.downloadList;
+ DownloadList::iterator itr, next;
+ for ( itr = downloads.begin(); itr != downloads.end();)
+ {
+ next = itr;
+ ++next;
+ if ( !PathFileExists( itr->path ) )
+ downloads.erase( itr );
+ else
+ itr = next;
+ }
+ }
+
+// Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
+}
+
+void Downloads_UpdateStatusBar(HWND hwndDlg)
+{
+ wchar_t status[256]=L"";
+ downloadStatus.GetStatusString(status, 256);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_STATUS), status);
+}
+
+void Downloads_Paint(HWND hwndDlg)
+{
+ int tab[] = { IDC_DOWNLOADLIST | DCW_SUNKENBORDER, };
+ dialogSkinner.Draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
+}
+
+
+static HRGN g_rgnUpdate = NULL;
+static int offsetX = 0, offsetY = 0;
+
+typedef struct _LAYOUT
+{
+ INT id;
+ HWND hwnd;
+ INT x;
+ INT y;
+ INT cx;
+ INT cy;
+ DWORD flags;
+ HRGN rgn;
+}
+LAYOUT, PLAYOUT;
+
+#define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; }
+#define SETLAYOUTFLAGS(_layout, _r) \
+ { \
+ BOOL fVis; \
+ fVis = (WS_VISIBLE & (LONG)GetWindowLongPtr(_layout->hwnd, GWL_STYLE)); \
+ if (_layout->x == _r.left && _layout->y == _r.top) _layout->flags |= SWP_NOMOVE; \
+ if (_layout->cx == (_r.right - _r.left) && _layout->cy == (_r.bottom - _r.top)) _layout->flags |= SWP_NOSIZE; \
+ if ((SWP_HIDEWINDOW & _layout->flags) && !fVis) _layout->flags &= ~SWP_HIDEWINDOW; \
+ if ((SWP_SHOWWINDOW & _layout->flags) && fVis) _layout->flags &= ~SWP_SHOWWINDOW; \
+ }
+
+#define LAYOUTNEEEDUPDATE(_layout) ((SWP_NOMOVE | SWP_NOSIZE) != ((SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_SHOWWINDOW) & _layout->flags))
+
+#define GROUP_MIN 0x1
+#define GROUP_MAX 0x2
+#define GROUP_STATUSBAR 0x1
+#define GROUP_MAIN 0x2
+
+static void LayoutWindows(HWND hwnd, BOOL fRedraw, BOOL fUpdateAll = FALSE)
+{
+ static INT controls[] =
+ {
+ GROUP_STATUSBAR, IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM, IDC_REMOVE, IDC_CLEANUP, IDC_STATUS,
+ GROUP_MAIN, IDC_DOWNLOADLIST
+ };
+
+ INT index;
+ RECT rc, rg, ri;
+ LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
+ BOOL skipgroup;
+ HRGN rgn = NULL;
+
+ GetClientRect(hwnd, &rc);
+
+ if (rc.right == rc.left || rc.bottom == rc.top)
+ return;
+
+ if ( rc.right > WASABI_API_APP->getScaleX( 4 ) )
+ rc.right -= WASABI_API_APP->getScaleX( 4 );
+
+ SetRect( &rg, rc.left, rc.top, rc.right, rc.top );
+
+ pl = layout;
+ skipgroup = FALSE;
+
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ for (index = 0; index < sizeof(controls) / sizeof(*controls); index++)
+ {
+ if (controls[index] >= GROUP_MIN && controls[index] <= GROUP_MAX) // group id
+ {
+ skipgroup = FALSE;
+ switch (controls[index])
+ {
+ case GROUP_STATUSBAR:
+ {
+ wchar_t buffer[128] = {0};
+ WASABI_API_LNGSTRINGW_BUF(IDC_PLAY, buffer, ARRAYSIZE(buffer));
+ LRESULT idealSize = MLSkinnedButton_GetIdealSize(GetDlgItem(hwnd, IDC_PLAY), buffer);
+
+ SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
+ rc.bottom - WASABI_API_APP->getScaleY(HIWORD(idealSize)),
+ rc.right, rc.bottom);
+ rc.bottom = rg.top - WASABI_API_APP->getScaleY(3);
+ break;
+ }
+ case GROUP_MAIN:
+ SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, rc.bottom);
+ break;
+ }
+ continue;
+ }
+ if (skipgroup) continue;
+
+ pl->id = controls[index];
+ pl->hwnd = GetDlgItem(hwnd, pl->id);
+
+ if ( !pl->hwnd )
+ continue;
+
+ GetWindowRect(pl->hwnd, &ri);
+ MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2);
+ pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS;
+
+ switch (pl->id)
+ {
+ case IDC_PLAY:
+ case IDC_ENQUEUE:
+ case IDC_CUSTOM:
+ case IDC_REMOVE:
+ case IDC_CLEANUP:
+ if ( IDC_CUSTOM != pl->id || customAllowed )
+ {
+ if ( groupBtn && pl->id == IDC_PLAY && enqueuedef == 1 )
+ {
+ pl->flags |= SWP_HIDEWINDOW;
+ break;
+ }
+
+ if ( groupBtn && pl->id == IDC_ENQUEUE && enqueuedef != 1 )
+ {
+ pl->flags |= SWP_HIDEWINDOW;
+ break;
+ }
+
+ if ( groupBtn && ( pl->id == IDC_PLAY || pl->id == IDC_ENQUEUE ) && customAllowed )
+ {
+ pl->flags |= SWP_HIDEWINDOW;
+ break;
+ }
+
+ wchar_t buffer[ 128 ] = { 0 };
+ GetWindowTextW( pl->hwnd, buffer, ARRAYSIZE( buffer ) );
+
+ LRESULT idealSize = MLSkinnedButton_GetIdealSize( pl->hwnd, buffer );
+ LONG width = LOWORD( idealSize ) + WASABI_API_APP->getScaleX( 6 );
+
+ SETLAYOUTPOS( pl, rg.left, rg.bottom - WASABI_API_APP->getScaleY( HIWORD( idealSize ) ), width, WASABI_API_APP->getScaleY( HIWORD( idealSize ) ) );
+
+ pl->flags |= ( ( rg.right - rg.left ) > width ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
+
+ if ( SWP_SHOWWINDOW & pl->flags )
+ rg.left += ( pl->cx + WASABI_API_APP->getScaleX( 4 ) );
+ }
+ else
+ pl->flags |= SWP_HIDEWINDOW;
+ break;
+ case IDC_STATUS:
+ SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left, (rg.bottom - rg.top));
+ pl->flags |= (pl->cx > 16) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
+ break;
+ case IDC_DOWNLOADLIST:
+ pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
+ 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 ) );
+ break;
+ }
+
+ SETLAYOUTFLAGS(pl, ri);
+ if ( LAYOUTNEEEDUPDATE( pl ) )
+ {
+ if ( SWP_NOSIZE == ( ( SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_NOSIZE ) & pl->flags ) && ri.left == ( pl->x + offsetX ) && ri.top == ( pl->y + offsetY ) && IsWindowVisible( pl->hwnd ) )
+ {
+ SetRect( &ri, pl->x, pl->y, pl->cx + pl->x, pl->y + pl->cy );
+ ValidateRect( hwnd, &ri );
+ }
+
+ pl++;
+ }
+ else if ( ( fRedraw || ( !offsetX && !offsetY ) ) && IsWindowVisible( pl->hwnd ) )
+ {
+ ValidateRect( hwnd, &ri );
+ if ( GetUpdateRect( pl->hwnd, NULL, FALSE ) )
+ {
+ if ( !rgn )
+ rgn = CreateRectRgn( 0, 0, 0, 0 );
+
+ GetUpdateRgn( pl->hwnd, rgn, FALSE );
+ OffsetRgn( rgn, pl->x, pl->y );
+ InvalidateRgn( hwnd, rgn, FALSE );
+ }
+ }
+ }
+
+ if (pl != layout)
+ {
+ LAYOUT *pc;
+ HDWP hdwp = BeginDeferWindowPos((INT)(pl - layout));
+ for(pc = layout; pc < pl && hdwp; pc++)
+ {
+ hdwp = DeferWindowPos(hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags);
+ }
+
+ if (hdwp)
+ EndDeferWindowPos(hdwp);
+
+ if ( !rgn )
+ rgn = CreateRectRgn( 0, 0, 0, 0 );
+
+ if (fRedraw)
+ {
+ GetUpdateRgn(hwnd, rgn, FALSE);
+ for ( pc = layout; pc < pl && hdwp; pc++ )
+ {
+ if ( pc->rgn )
+ {
+ OffsetRgn( pc->rgn, pc->x, pc->y );
+ CombineRgn( rgn, rgn, pc->rgn, RGN_OR );
+ }
+ }
+
+ RedrawWindow(hwnd, NULL, rgn, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN);
+ }
+
+ if (g_rgnUpdate)
+ {
+ GetUpdateRgn(hwnd, g_rgnUpdate, FALSE);
+ for(pc = layout; pc < pl && hdwp; pc++)
+ {
+ if (pc->rgn)
+ {
+ OffsetRgn(pc->rgn, pc->x, pc->y);
+ CombineRgn(g_rgnUpdate, g_rgnUpdate, pc->rgn, RGN_OR);
+ }
+ }
+ }
+
+ for(pc = layout; pc < pl && hdwp; pc++) if (pc->rgn) DeleteObject(pc->rgn);
+ }
+
+ if ( rgn )
+ DeleteObject( rgn );
+
+ ValidateRgn(hwnd, NULL);
+}
+
+void Downloads_DisplayChange(HWND hwndDlg)
+{
+ ListView_SetTextColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMFG));
+ ListView_SetBkColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMBG));
+ ListView_SetTextBkColor(downloadList.getwnd(), dialogSkinner.Color(WADLG_ITEMBG));
+ downloadList.SetFont(dialogSkinner.GetFont());
+ LayoutWindows(hwndDlg, TRUE);
+}
+
+static void DownloadsDialog_SkinControls(HWND hwnd, const INT *itemList, INT itemCount, UINT skinType, UINT skinStyle)
+{
+ MLSKINWINDOW skinWindow = {0};
+ skinWindow.style = skinStyle;
+ skinWindow.skinType = skinType;
+
+ for(INT i = 0; i < itemCount; i++)
+ {
+ skinWindow.hwndToSkin = GetDlgItem(hwnd, itemList[i]);
+ if (NULL != skinWindow.hwndToSkin)
+ {
+ MLSkinWindow(plugin.hwndLibraryParent, &skinWindow);
+ }
+ }
+}
+
+static void DownloadDialog_InitializeList(HWND hwnd)
+{
+ HWND hControl = GetDlgItem(hwnd, IDC_DOWNLOADLIST);
+ if (NULL == hControl) return;
+
+ UINT styleEx = (UINT)GetWindowLongPtr(hControl, GWL_EXSTYLE);
+ SetWindowLongPtr(hControl, GWL_EXSTYLE, styleEx & ~WS_EX_NOPARENTNOTIFY);
+
+ styleEx = LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP;
+ SendMessage(hControl, LVM_SETEXTENDEDLISTVIEWSTYLE, styleEx, styleEx);
+ SendMessage(hControl, LVM_SETUNICODEFORMAT, (WPARAM)TRUE, 0L);
+
+ MLSKINWINDOW skinWindow;
+ skinWindow.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_ALTERNATEITEMS;
+ skinWindow.skinType = SKINNEDWND_TYPE_LISTVIEW;
+ skinWindow.hwndToSkin = hControl;
+ MLSkinWindow(plugin.hwndLibraryParent, &skinWindow);
+}
+
+bool COL_SOURCE_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
+{
+ if (item1->f && item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->f->source), -1, (item2->f->source), -1));
+ else if (!item1->f && !item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->source), -1, (item2->source), -1));
+ else if (!item1->f)
+ return (FALSE == downloadsSortAscending)?0:1;
+ else //if (!item2->f)
+ return (FALSE == downloadsSortAscending)?1:0;
+
+ //return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
+ // (item1->f?item1->f->source:item1->source), -1,
+ // (item2->f?item2->f->source:item2->source), -1));
+}
+
+bool COL_TITLE_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
+{
+ if (item1->f && item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->f->title), -1, (item2->f->title), -1));
+ else if (!item1->f && !item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->title), -1, (item2->title), -1));
+ else if (!item1->f)
+ return (FALSE == downloadsSortAscending)?0:1;
+ else //if (!item2->f)
+ return (FALSE == downloadsSortAscending)?1:0;
+
+ //return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
+ // (item1->f?item1->f->title:item1->title), -1,
+ // (item2->f?item2->f->title:item2->title), -1));
+}
+
+bool COL_PROGRESS_Sort( const DownloadListItem *item1, const DownloadListItem *item2 )
+{
+ if ( item1->f && item2->f )
+ return ( item1->f->downloadStatus > item2->f->downloadStatus );
+ else if ( !item1->f && !item2->f )
+ return ( item1->token < item2->token );
+ else if ( !item1->f )
+ return ( FALSE == downloadsSortAscending ) ? 0 : 1;
+ else //if (!item2->f)
+ return ( FALSE == downloadsSortAscending ) ? 1 : 0;
+
+ //return ((item1->f?item1->f->downloadStatus:-1) < (item2->f?item2->f->downloadStatus:-1));
+
+ //return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
+ // (item1->f?GetDownloadStatus(item1->f->downloadStatus):item1->status), -1,
+ // (item2->f?GetDownloadStatus(item2->f->downloadStatus):item2->status), -1));
+}
+
+bool COL_PATH_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
+{
+ if (item1->f && item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->f->path), -1, (item2->f->path), -1));
+ else if (!item1->f && !item2->f)
+ return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, (item1->path), -1, (item2->path), -1));
+ else if (!item1->f)
+ return (FALSE == downloadsSortAscending)?0:1;
+ else //if (!item2->f)
+ return (FALSE == downloadsSortAscending)?1:0;
+
+ //return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
+ // (item1->f?item1->f->path:item1->path), -1,
+ // (item2->f?item2->f->path:item2->path), -1));
+}
+
+bool COL_DATE_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
+{
+ if (item1->f && item2->f)
+ return item1->f->downloadDate < item2->f->downloadDate;
+ else if (!item1->f && !item2->f)
+ return item1->token < item2->token;
+ else if (!item1->f)
+ return (FALSE == downloadsSortAscending)?0:1;
+ else //if (!item2->f)
+ return (FALSE == downloadsSortAscending)?1:0;
+}
+
+bool COL_SIZE_Sort(const DownloadListItem* item1, const DownloadListItem* item2)
+{
+ if (item1->f && item2->f)
+ return item1->f->totalSize < item2->f->totalSize;
+ else if (!item1->f && !item2->f)
+ return item1->token < item2->token;
+ else if (!item1->f)
+ return (FALSE == downloadsSortAscending)?0:1;
+ else //if (!item2->f)
+ return (FALSE == downloadsSortAscending)?1:0;
+}
+
+static BOOL Downloads_SortItems(int sortColumn)
+{
+ AutoLock lock (downloadedFiles);
+ switch (sortColumn)
+ {
+ case COL_TITLE:
+ std::sort(listContents.begin(), listContents.end(), COL_TITLE_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ case COL_PROGRESS:
+ std::sort(listContents.begin(), listContents.end(), COL_PROGRESS_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ case COL_DATE:
+ std::sort(listContents.begin(), listContents.end(), COL_DATE_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ case COL_SOURCE:
+ std::sort(listContents.begin(), listContents.end(), COL_SOURCE_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ case COL_SIZE:
+ std::sort(listContents.begin(), listContents.end(), COL_SIZE_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ case COL_PATH:
+ std::sort(listContents.begin(), listContents.end(), COL_PATH_Sort);
+ if (FALSE == downloadsSortAscending) std::reverse(listContents.begin(), listContents.end());
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void Downloads_SetListSortColumn(HWND hwnd, INT listId, INT index, BOOL fAscending)
+{
+ HWND hItems = GetDlgItem(hwnd, listId);
+ if (NULL == hItems) return;
+
+ HWND hHeader = (HWND)SNDMSG(hItems, LVM_GETHEADER, 0, 0L);
+ if (NULL == hHeader) return;
+
+ HDITEM item;
+ item.mask = HDI_FORMAT;
+ // reset first (ml req)
+ INT count = (INT)SNDMSG(hHeader, HDM_GETITEMCOUNT, 0, 0L);
+ for (INT i = 0; i < count; i++)
+ {
+ if (index != i && FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, i, (LPARAM)&item))
+ {
+ if (0 != ((HDF_SORTUP | HDF_SORTDOWN) & item.fmt))
+ {
+ item.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
+ SNDMSG(hHeader, HDM_SETITEM, i, (LPARAM)&item);
+ }
+ }
+ }
+
+ if (FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, index, (LPARAM)&item))
+ {
+ INT fmt = item.fmt & ~(HDF_SORTUP | HDF_SORTDOWN);
+ fmt |= (FALSE == fAscending) ? HDF_SORTDOWN : HDF_SORTUP;
+ if (fmt != item.fmt)
+ {
+ item.fmt = fmt;
+ SNDMSG(hHeader, HDM_SETITEM, index, (LPARAM)&item);
+ }
+ }
+}
+
+static BOOL Downloads_Sort(HWND hwnd, INT iColumn, bool fAscending)
+{
+ BOOL result = TRUE;
+ downloadsSortAscending = fAscending;
+ Downloads_SortItems(iColumn);
+ Downloads_SetListSortColumn(hwnd, IDC_DOWNLOADLIST, iColumn, fAscending);
+
+ if (FALSE != result)
+ {
+ HWND hItems = GetDlgItem(hwnd, IDC_DOWNLOADLIST);
+ if (NULL != hItems)
+ InvalidateRect(hItems, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+void Downloads_UpdateButtonText(HWND hwndDlg, int _enqueuedef)
+{
+ if (groupBtn)
+ {
+ switch(_enqueuedef)
+ {
+ case 1:
+ SetDlgItemTextW(hwndDlg, IDC_PLAY, view.enqueue);
+ customAllowed = FALSE;
+ break;
+
+ default:
+ // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
+ // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
+ pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK_IN_USE, (INT_PTR)_enqueuedef, 0, 0};
+
+ wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
+ if (pszTextW && pszTextW[0] != 0)
+ {
+ // set this to be a bit different so we can just use one button and not the
+ // mixable one as well (leaving that to prevent messing with the resources)
+ SetDlgItemTextW(hwndDlg, IDC_PLAY, pszTextW);
+ customAllowed = TRUE;
+ }
+ else
+ {
+ SetDlgItemTextW(hwndDlg, IDC_PLAY, view.play);
+ customAllowed = FALSE;
+ }
+ break;
+ }
+ }
+}
+
+static void Downloads_ManageButtons( HWND hwndDlg )
+{
+ int has_selection = downloadList.GetSelectedCount();
+
+ const int buttonids[] = { IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM, IDC_REMOVE };
+ for ( size_t i = 0; i != sizeof( buttonids ) / sizeof( buttonids[ 0 ] ); i++ )
+ {
+ HWND controlHWND = GetDlgItem( hwndDlg, buttonids[ i ] );
+ EnableWindow( controlHWND, has_selection );
+ }
+}
+
+void Downloads_Init(HWND hwndDlg)
+{
+ HWND hLibrary = plugin.hwndLibraryParent;
+ downloads_window = hwndDlg;
+
+ if (!view.play)
+ {
+ SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
+ }
+
+ HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_VIEW_DOWNLOAD_ACCELERATORS);
+ if (accel)
+ WASABI_API_APP->app_addAccelerators(hwndDlg, &accel, 1, TRANSLATE_MODE_CHILD);
+
+ g_context_menus2 = WASABI_API_LOADMENU(IDR_MENU1);
+ groupBtn = ML_GROUPBTN_VAL();
+ enqueuedef = (ML_ENQDEF_VAL() == 1);
+
+ // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
+ // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
+ pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG(IDC_CUSTOM, IDC_ENQUEUE), (INT_PTR)L"ml_downloads"};
+ wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
+ if (pszTextW && pszTextW[0] != 0)
+ {
+ // set this to be a bit different so we can just use one button and not the
+ // mixable one as well (leaving that to prevent messing with the resources)
+ customAllowed = TRUE;
+ SetDlgItemTextW(hwndDlg, IDC_CUSTOM, pszTextW);
+ }
+ else
+ customAllowed = FALSE;
+
+ MLSkinWindow2(hLibrary, hwndDlg, SKINNEDWND_TYPE_AUTO, SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS);
+
+ const INT szControls[] = {IDC_PLAY, IDC_ENQUEUE, IDC_CUSTOM};
+ DownloadsDialog_SkinControls(hwndDlg, szControls, ARRAYSIZE(szControls), SKINNEDWND_TYPE_AUTO,
+ SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn ? SWBS_SPLITBUTTON : 0));
+
+ const INT szControlz[] = {IDC_REMOVE, IDC_CLEANUP, IDC_STATUS};
+ DownloadsDialog_SkinControls(hwndDlg, szControlz, ARRAYSIZE(szControlz), SKINNEDWND_TYPE_AUTO,
+ SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS);
+
+ DownloadDialog_InitializeList(hwndDlg);
+ Downloads_UpdateStatusBar(hwndDlg);
+
+ downloadList.setwnd(GetDlgItem(hwndDlg, IDC_DOWNLOADLIST));
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_TITLE), downloadsTitleWidth);
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_PROGRESS), downloadsProgressWidth);
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_DATE), downloadsDateWidth);
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_SOURCE), downloadsSourceWidth);
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_SIZE), downloadsSizeWidth);
+ downloadList.AddCol(WASABI_API_LNGSTRINGW(IDS_PATH), downloadsPathWidth);
+
+ DownloadsUpdated();
+
+ downloadList.SetVirtualCount((int)listContents.size());
+ Downloads_UpdateButtonText(hwndDlg, enqueuedef == 1);
+ Downloads_ManageButtons(hwndDlg);
+ Downloads_DisplayChange(hwndDlg);
+ Downloads_Sort(hwndDlg, downloadsItemSort, downloadsSortAscending);
+ SetTimer(hwndDlg, DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR , 1000, 0);
+}
+
+void Downloads_Timer( HWND hwndDlg, UINT timerId )
+{
+ switch ( timerId )
+ {
+ case DOWNLOADSDIALOG_TIMER_UPDATESTATUSBAR:
+ Downloads_UpdateStatusBar( hwndDlg );
+ {
+ AutoLock lock( downloadStatus.statusLock );
+ for ( DownloadListItem *l_content : listContents )
+ {
+ if ( l_content->token )
+ {
+ size_t d = downloadStatus.downloads[ l_content->token ].downloaded;
+ size_t s = downloadStatus.downloads[ l_content->token ].maxSize;
+
+ if ( s )
+ StringCchPrintf( l_content->status, 20, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_PERCENT ), (int)( d / ( s / 100 ) ) );
+ else
+ {
+ if ( WAC_API_DOWNLOADMANAGER->IsPending( l_content->token ) )
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOAD_PENDING, l_content->status, 20 );
+ else
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOADING, l_content->status, 20 );
+ }
+
+ PostMessage( downloadList.getwnd(), LVM_REDRAWITEMS, 0, listContents.size() );
+ }
+ }
+ }
+ break;
+ }
+}
+
+static INT Downloads_GetListSortColumn(HWND hwnd, INT listId, bool *fAscending)
+{
+ HWND hItems = GetDlgItem(hwnd, listId);
+ if (NULL != hItems)
+ {
+ HWND hHeader = (HWND)SNDMSG(hItems, LVM_GETHEADER, 0, 0L);
+ if (NULL != hHeader)
+ {
+ HDITEM item;
+ item.mask = HDI_FORMAT;
+
+ INT count = (INT)SNDMSG(hHeader, HDM_GETITEMCOUNT, 0, 0L);
+ for (INT i = 0; i < count; i++)
+ {
+ if (FALSE != (BOOL)SNDMSG(hHeader, HDM_GETITEM, i, (LPARAM)&item) &&
+ 0 != ((HDF_SORTUP | HDF_SORTDOWN) & item.fmt))
+ {
+ if (NULL != fAscending)
+ {
+ *fAscending = (0 != (HDF_SORTUP & item.fmt));
+ }
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+void Downloads_Destroy( HWND hwndDlg )
+{
+ downloads_window = 0;
+ downloadsSourceWidth = downloadList.GetColumnWidth( COL_SOURCE );
+ downloadsTitleWidth = downloadList.GetColumnWidth( COL_TITLE );
+ downloadsProgressWidth = downloadList.GetColumnWidth( COL_PROGRESS );
+ downloadsPathWidth = downloadList.GetColumnWidth( COL_PATH );
+ downloadsDateWidth = downloadList.GetColumnWidth( COL_DATE );
+ downloadsSizeWidth = downloadList.GetColumnWidth( COL_SIZE );
+
+ for ( DownloadListItem *l_content : listContents )
+ delete l_content;
+
+ listContents.clear();
+
+ downloadList.setwnd( NULL );
+
+ bool fAscending;
+ downloadsItemSort = Downloads_GetListSortColumn( hwndDlg, IDC_DOWNLOADLIST, &fAscending );
+ downloadsSortAscending = ( -1 != downloadsItemSort ) ? ( FALSE != fAscending ) : true;
+
+ int activeDownloads = 0;
+ int historyDownloads = 0;
+ {
+ Nullsoft::Utility::AutoLock historylock( downloadedFiles.downloadedLock );
+ Nullsoft::Utility::AutoLock statuslock( downloadStatus.statusLock );
+ historyDownloads = (int)downloadedFiles.downloadList.size();
+ activeDownloads = (int)downloadStatus.downloads.size();
+ }
+
+ if ( !activeDownloads && !historyDownloads && !no_auto_hide )
+ {
+ HNAVITEM hItem = MLNavCtrl_FindItemById( plugin.hwndLibraryParent, downloads_treeItem );
+ if ( hItem )
+ {
+ MLNavCtrl_DeleteItem( plugin.hwndLibraryParent, hItem );
+ downloads_treeItem = 0;
+ }
+ }
+}
+
+void Downloads_Remove( bool del = false, HWND parent = NULL )
+{
+ int d = -1;
+ int r = 0;
+ while ( GetDownload( d ) )
+ {
+ int download = d - r;
+ DownloadListItem *item = listContents[ download ];
+ if ( item->f )
+ {
+ AutoLock lock( downloadedFiles );
+ int j = 0;
+ for ( DownloadList::iterator i = downloadedFiles.begin(); i != downloadedFiles.end(); ++i )
+ {
+ if ( !_wcsicmp( i->path, item->f->path ) )
+ {
+ if ( del )
+ {
+ if ( !downloadedFiles.RemoveAndDelete( j ) )
+ MessageBox( parent, WASABI_API_LNGSTRINGW( IDS_DELETEFAILED ), downloadedFiles.downloadList[ j ].path, 0 );
+ }
+ else
+ downloadedFiles.Remove( j );
+
+ delete item;
+ listContents.erase( listContents.begin() + download );
+ r++;
+ dirty++;
+
+ break;
+ }
+
+ ++j;
+ }
+ }
+ else if ( item->token )
+ {
+ AutoLock lock( downloadStatus.statusLock );
+ downloadStatus.downloads[ item->token ].killswitch = 1;
+ delete item;
+ listContents.erase( listContents.begin() + download );
+ r++;
+ }
+ else
+ {
+ delete item;
+ listContents.erase( listContents.begin() + download );
+ r++;
+ }
+ }
+
+ downloadList.SetVirtualCountAsync( (int)listContents.size() );
+ downloadList.UnselectAll();
+ // Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
+}
+
+void Downloads_Delete( HWND parent )
+{
+ wchar_t message[ 256 ] = { 0 };
+ int c = downloadList.GetSelectedCount();
+
+ if ( !c )
+ return;
+ else if ( c == 1 )
+ WASABI_API_LNGSTRINGW_BUF( IDS_PERM_DELETE_ARE_YOU_SURE, message, 256 );
+ else
+ StringCchPrintf( message, 256, WASABI_API_LNGSTRINGW( IDS_PERM_DELETE_THESE_ARE_YOU_SURE ), c );
+
+ if ( MessageBox( NULL, message, WASABI_API_LNGSTRINGW( IDS_DELETION ), MB_ICONWARNING | MB_YESNO ) == IDNO )
+ return;
+
+ Downloads_Remove( true, parent );
+}
+
+void Downloads_CleanUp(HWND hwndDlg)
+{
+ wchar_t titleStr[64] = {0};
+ 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 )
+ return;
+
+ {
+ AutoLock lock( downloadedFiles );
+ downloadedFiles.downloadList.clear();
+ }
+
+ dirty++;
+
+ DownloadsUpdated();
+}
+
+void Downloads_InfoBox( HWND parent )
+{
+ int download = -1;
+ if ( GetDownload( download ) )
+ {
+ const wchar_t *fn;
+ if ( listContents[ download ]->f )
+ fn = listContents[ download ]->f->path;
+ else
+ fn = listContents[ download ]->path;
+
+ if ( fn )
+ {
+ infoBoxParamW p = { parent, fn };
+ SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&p, IPC_INFOBOXW );
+ }
+ }
+}
+
+void Downloads_SelectAll()
+{
+ int l = downloadList.GetCount();
+ for ( int i = 0; i < l; i++ )
+ downloadList.SetSelected( i );
+}
+
+static void exploreItemFolder( HWND hwndDlg )
+{
+ if ( downloadList.GetSelectionMark() >= 0 )
+ {
+ int download = -1;
+ while ( GetDownload( download ) )
+ {
+ wchar_t *file;
+ if ( listContents[ download ]->f )
+ file = listContents[ download ]->f->path;
+ else
+ file = listContents[ download ]->path;
+
+ WASABI_API_EXPLORERFINDFILE->AddFile( file );
+ }
+ WASABI_API_EXPLORERFINDFILE->ShowFiles();
+ }
+}
+
+void Downloads_Cancel()
+{
+ int l_selected_count = downloadList.GetSelectedCount();
+ for ( int i = -1; i < l_selected_count; ++i )
+ {
+ if ( GetDownload( i ) )
+ {
+ dirty++;
+ if ( !listContents[ i ]->f )
+ WAC_API_DOWNLOADMANAGER->CancelDownload( listContents[ i ]->token );
+
+ break; // Workaround for 5.9.1 to avoid crash if cancel of many downloads in same time
+ }
+ }
+}
+
+int we_are_drag_and_dropping = 0;
+
+static void Downloads_OnColumnClick(HWND hwnd, NMLISTVIEW *plv)
+{
+ bool fAscending;
+ INT iSort = Downloads_GetListSortColumn(hwnd, IDC_DOWNLOADLIST, &fAscending);
+ fAscending = (-1 != iSort && iSort == plv->iSubItem) ? (!fAscending) : true;
+ Downloads_Sort(hwnd, plv->iSubItem, fAscending);
+}
+
+LRESULT DownloadList_Notify( LPNMHDR l, HWND hwndDlg )
+{
+ switch ( l->code )
+ {
+ case LVN_COLUMNCLICK:
+ Downloads_OnColumnClick( hwndDlg, (NMLISTVIEW *)l );
+ break;
+ case NM_DBLCLK:
+ Downloads_Play( ( ( !!( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ) ^ ML_ENQDEF_VAL() ) );
+ break;
+ case LVN_BEGINDRAG:
+ we_are_drag_and_dropping = 1;
+ SetCapture( hwndDlg );
+ break;
+ case LVN_ITEMCHANGED:
+ Downloads_ManageButtons( hwndDlg );
+ break;
+ case LVN_GETDISPINFO:
+ NMLVDISPINFO *lpdi = (NMLVDISPINFO *)l;
+ size_t item = lpdi->item.iItem;
+
+ if ( item < 0 || item >= listContents.size() )
+ return 0;
+
+ //if (FALSE == downloadsSortAscending) item = listContents.size() - item - 1;
+
+ DownloadListItem *l = listContents[ item ];
+
+ if ( lpdi->item.mask & LVIF_TEXT )
+ {
+ lpdi->item.pszText[ 0 ] = 0;
+ switch ( lpdi->item.iSubItem )
+ {
+ case COL_TITLE:
+ if ( !l->token && l->f )
+ {
+ wchar_t *l_title = L"";
+
+ if ( l->f->title != NULL )
+ l_title = l->f->title;
+
+ lstrcpyn( lpdi->item.pszText, l_title, lpdi->item.cchTextMax );
+ }
+ else
+ {
+ if ( l->title ) lstrcpyn( lpdi->item.pszText, l->title, lpdi->item.cchTextMax );
+ }
+ break;
+ case COL_PROGRESS:
+ if ( !l->token && l->f )
+ {
+ switch ( l->f->downloadStatus )
+ {
+ case DownloadedFile::DOWNLOAD_SUCCESS:
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOAD_SUCCESS, lpdi->item.pszText, lpdi->item.cchTextMax );
+ break;
+ case DownloadedFile::DOWNLOAD_FAILURE:
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOAD_FAILURE, lpdi->item.pszText, lpdi->item.cchTextMax );
+ break;
+ case DownloadedFile::DOWNLOAD_CANCELED:
+ WASABI_API_LNGSTRINGW_BUF( IDS_DOWNLOAD_CANCELED, lpdi->item.pszText, lpdi->item.cchTextMax );
+ break;
+ }
+ }
+ else lstrcpyn( lpdi->item.pszText, l->status, lpdi->item.cchTextMax );
+ break;
+ case COL_DATE:
+ {
+ if ( !l->token && l->f && l->f->downloadDate )
+ {
+ wchar_t tmp[ 128 ] = { 0 };
+ MakeDateString( l->f->downloadDate, tmp, 128 );
+ lstrcpyn( lpdi->item.pszText, tmp, lpdi->item.cchTextMax );
+ }
+ else
+ {
+ WASABI_API_LNGSTRINGW_BUF( IDS_N_A, lpdi->item.pszText, lpdi->item.cchTextMax );
+ }
+ break;
+ }
+ case COL_SOURCE:
+ if ( !l->token && l->f )
+ {
+ wchar_t *l_source = L"";
+
+ if ( l->f->source != NULL )
+ l_source = l->f->source;
+
+ lstrcpyn( lpdi->item.pszText, l_source, lpdi->item.cchTextMax );
+ }
+ else
+ lstrcpyn( lpdi->item.pszText, l->source, lpdi->item.cchTextMax );
+ break;
+ case COL_SIZE:
+ {
+ if ( !l->token && l->f && l->f->totalSize > 0 )
+ WASABI_API_LNG->FormattedSizeString( lpdi->item.pszText, lpdi->item.cchTextMax, l->f->totalSize );
+ else
+ WASABI_API_LNGSTRINGW_BUF( IDS_N_A, lpdi->item.pszText, lpdi->item.cchTextMax );
+ break;
+ }
+ case COL_PATH:
+ if ( !l->token && l->f )
+ {
+ wchar_t *l_path = L"";
+
+ if ( l->f->path != NULL )
+ l_path = l->f->path;
+
+ lstrcpyn( lpdi->item.pszText, l_path, lpdi->item.cchTextMax );
+ }
+ else
+ {
+ if ( l->path )
+ lstrcpyn( lpdi->item.pszText, l->path, lpdi->item.cchTextMax );
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+void listbuild( wchar_t **buf, int &buf_size, int &buf_pos, const wchar_t *tbuf )
+{
+ if ( !*buf )
+ {
+ *buf = (wchar_t *)calloc( 4096, sizeof( wchar_t ) );
+ if ( *buf )
+ {
+ buf_size = 4096;
+ buf_pos = 0;
+ }
+ else
+ {
+ buf_size = buf_pos = 0;
+ }
+ }
+ int newsize = buf_pos + lstrlenW( tbuf ) + 1;
+ if ( newsize < buf_size )
+ {
+ size_t old_buf_size = buf_size;
+ buf_size = newsize + 4096;
+ wchar_t *new_buf = (wchar_t *)realloc( *buf, ( buf_size + 1 ) * sizeof( wchar_t ) );
+ if ( new_buf )
+ {
+ *buf = new_buf;
+ }
+ else
+ {
+ new_buf = (wchar_t*)calloc( ( buf_size + 1 ), sizeof( wchar_t ) );
+ if ( new_buf )
+ {
+ memcpy( new_buf, *buf, ( old_buf_size * sizeof( wchar_t ) ) );
+ free( *buf );
+ *buf = new_buf;
+ }
+ else buf_size = (int)old_buf_size;
+ }
+ }
+
+ StringCchCopyW( *buf + buf_pos, buf_size, tbuf );
+ buf_pos = newsize;
+}
+
+wchar_t *getSelectedList()
+{
+ wchar_t *path = NULL;
+ int buf_pos = 0;
+ int buf_size = 0;
+ int download = -1;
+
+ while ( GetDownload( download ) )
+ {
+ if ( listContents[ download ]->f )
+ listbuild( &path, buf_size, buf_pos, listContents[ download ]->f->path );
+ }
+
+ if ( path )
+ path[ buf_pos ] = 0;
+
+ return path;
+}
+
+static void SwapPlayEnqueueInMenu( HMENU listMenu )
+{
+ int playPos = -1, enqueuePos = -1;
+ MENUITEMINFOW playItem = { sizeof( MENUITEMINFOW ), 0, }, enqueueItem = { sizeof( MENUITEMINFOW ), 0, };
+
+ int numItems = GetMenuItemCount( listMenu );
+
+ for ( int i = 0; i < numItems; i++ )
+ {
+ UINT id = GetMenuItemID( listMenu, i );
+ if ( id == IDC_PLAY )
+ {
+ playItem.fMask = MIIM_ID;
+ playPos = i;
+ GetMenuItemInfoW( listMenu, i, TRUE, &playItem );
+ }
+ else if ( id == IDC_ENQUEUE )
+ {
+ enqueueItem.fMask = MIIM_ID;
+ enqueuePos = i;
+ GetMenuItemInfoW( listMenu, i, TRUE, &enqueueItem );
+ }
+ }
+
+ playItem.wID = IDC_ENQUEUE;
+ enqueueItem.wID = IDC_PLAY;
+ SetMenuItemInfoW( listMenu, playPos, TRUE, &playItem );
+ SetMenuItemInfoW( listMenu, enqueuePos, TRUE, &enqueueItem );
+}
+
+static void SyncMenuWithAccelerators( HWND hwndDlg, HMENU menu )
+{
+ HACCEL szAccel[ 24 ] = { 0 };
+ INT c = WASABI_API_APP->app_getAccelerators( hwndDlg, szAccel, sizeof( szAccel ) / sizeof( szAccel[ 0 ] ), FALSE );
+ AppendMenuShortcuts( menu, szAccel, c, MSF_REPLACE );
+}
+
+void UpdateMenuItems( HWND hwndDlg, HMENU menu )
+{
+ bool swapPlayEnqueue = false;
+ if ( ML_ENQDEF_VAL() )
+ {
+ SwapPlayEnqueueInMenu( menu );
+ swapPlayEnqueue = true;
+ }
+
+ SyncMenuWithAccelerators( hwndDlg, menu );
+ if ( swapPlayEnqueue )
+ SwapPlayEnqueueInMenu( menu );
+}
+
+static int IPC_LIBRARY_SENDTOMENU = 0;
+static librarySendToMenuStruct s = { 0 };
+
+static void DownloadList_RightClick(HWND hwndDlg, HWND listHwnd, POINTS pts)
+{
+ POINT pt;
+ POINTSTOPOINT(pt, pts);
+
+ RECT controlRect, headerRect;
+ if (FALSE == GetClientRect(listHwnd, &controlRect))
+ SetRectEmpty(&controlRect);
+ else
+ MapWindowPoints(listHwnd, HWND_DESKTOP, (POINT*)&controlRect, 2);
+
+ if ( -1 == pt.x && -1 == pt.y )
+ {
+ RECT itemRect;
+ int selected = downloadList.GetNextSelected();
+ if ( selected != -1 ) // if something is selected we'll drop the menu from there
+ {
+ downloadList.GetItemRect( selected, &itemRect );
+ ClientToScreen( listHwnd, (POINT *)&itemRect );
+ }
+ else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location
+ {
+ GetWindowRect( listHwnd, &itemRect );
+
+ HWND hHeader = (HWND)SNDMSG( listHwnd, LVM_GETHEADER, 0, 0L );
+ RECT headerRect;
+ if ( ( WS_VISIBLE & GetWindowLongPtr( hHeader, GWL_STYLE ) ) && GetWindowRect( hHeader, &headerRect ) )
+ {
+ itemRect.top += ( headerRect.bottom - headerRect.top );
+ }
+ }
+
+ pt.x = itemRect.left;
+ pt.y = itemRect.top;
+ }
+
+ HWND hHeader = (HWND)SNDMSG(listHwnd, LVM_GETHEADER, 0, 0L);
+ if ( 0 == ( WS_VISIBLE & GetWindowLongPtr( hHeader, GWL_STYLE ) ) || FALSE == GetWindowRect( hHeader, &headerRect ) )
+ {
+ SetRectEmpty( &headerRect );
+ }
+
+ if ( FALSE != PtInRect( &headerRect, pt ) )
+ {
+ return;
+ }
+
+ LVHITTESTINFO hitTest;
+ hitTest.pt = pt;
+ MapWindowPoints( HWND_DESKTOP, listHwnd, &hitTest.pt, 1 );
+
+ int index = ( downloadList.GetNextSelected() != -1 ? ListView_HitTest( listHwnd, &hitTest ) : -1 );
+
+ HMENU baseMenu = WASABI_API_LOADMENU( IDR_MENU1 );
+
+ if ( baseMenu == NULL )
+ return;
+
+ HMENU menu = GetSubMenu( baseMenu, 0 );
+ if ( menu != NULL )
+ {
+ if ( ( index == -1 ) || ( index != -1 ) && listContents[ index ]->f )
+ DeleteMenu( menu, ID_DOWNLOADS_CANCELDOWNLOAD, MF_BYCOMMAND );
+
+ UINT enableExtras = MF_ENABLED;
+ if ( ( index == -1 ) || ( index != -1 ) && !listContents[ index ]->f
+ || ( index != -1 ) && ( listContents[ index ]->f->downloadStatus != 1 ) )
+ enableExtras = ( MF_GRAYED | MF_DISABLED );
+
+ UINT enableViewExtras = MF_ENABLED;
+ if ( index == -1 )
+ enableViewExtras = ( MF_GRAYED | MF_DISABLED );
+
+ EnableMenuItem( menu, IDC_PLAY, MF_BYCOMMAND | enableExtras );
+ EnableMenuItem( menu, IDC_ENQUEUE, MF_BYCOMMAND | enableExtras );
+ EnableMenuItem( menu, IDC_REMOVE, MF_BYCOMMAND | enableViewExtras );
+ EnableMenuItem( menu, IDC_DELETE, MF_BYCOMMAND | enableExtras );
+ EnableMenuItem( menu, IDC_INFOBOX, MF_BYCOMMAND | enableExtras );
+ EnableMenuItem( menu, ID_DOWNLOADS_EXPLORERITEMFOLDER, MF_BYCOMMAND | enableExtras );
+ EnableMenuItem( menu, 2, MF_BYPOSITION | enableExtras );
+
+ { // send-to menu shit...
+ ZeroMemory( &s, sizeof( s ) );
+ IPC_LIBRARY_SENDTOMENU = (int)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "LibrarySendToMenu", IPC_REGISTER_WINAMP_IPCMESSAGE );
+ if ( IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
+ {
+ s.mode = 1;
+ s.hwnd = hwndDlg;
+ s.data_type = ML_TYPE_FILENAMESW;
+ s.ctx[ 1 ] = 1;
+ s.build_hMenu = GetSubMenu( menu, 2 );
+ }
+ }
+
+ UpdateMenuItems( hwndDlg, menu );
+
+ int r = Menu_TrackPopup( plugin.hwndLibraryParent, menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwndDlg, NULL );
+ if ( !SendMessage( hwndDlg, WM_COMMAND, r, 0 ) )
+ {
+ s.menu_id = r; // more send to menu shit...
+ if ( s.mode == 2 && SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU ) == 0xffffffff )
+ {
+ s.mode = 3;
+ wchar_t *path = getSelectedList();
+ if ( path )
+ {
+ s.data = path;
+ SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU );
+ free( path );
+ }
+ }
+ }
+
+ if ( s.mode )
+ { // yet more send to menu shit...
+ s.mode = 4;
+ SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU ); // cleanup
+ }
+ }
+
+ DestroyMenu( baseMenu );
+}
+
+static void Downloads_ContextMenu( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
+{
+ HWND sourceWindow = (HWND)wParam;
+ if ( sourceWindow == downloadList.getwnd() )
+ DownloadList_RightClick( hwndDlg, sourceWindow, MAKEPOINTS( lParam ) );
+}
+
+enum
+{
+ BPM_ECHO_WM_COMMAND=0x1, // send WM_COMMAND and return value
+ BPM_WM_COMMAND = 0x2, // just send WM_COMMAND
+};
+
+BOOL Downloads_ButtonPopupMenu( HWND hwndDlg, int buttonId, HMENU menu, int flags = 0 )
+{
+ RECT r;
+ HWND buttonHWND = GetDlgItem( hwndDlg, buttonId );
+ GetWindowRect( buttonHWND, &r );
+ UpdateMenuItems( hwndDlg, menu );
+ MLSkinnedButton_SetDropDownState( buttonHWND, TRUE );
+ UINT tpmFlags = TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN;
+ if ( !( flags & BPM_WM_COMMAND ) )
+ tpmFlags |= TPM_RETURNCMD;
+ int x = Menu_TrackPopup( plugin.hwndLibraryParent, menu, tpmFlags, r.left, r.top, hwndDlg, NULL );
+ if ( ( flags & BPM_ECHO_WM_COMMAND ) && x )
+ SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( x, 0 ), 0 );
+ MLSkinnedButton_SetDropDownState( buttonHWND, FALSE );
+ return x;
+}
+
+static void Downloads_Play( HWND hwndDlg, HWND from, UINT idFrom )
+{
+ HMENU listMenu = GetSubMenu( g_context_menus2, 0 );
+ int count = GetMenuItemCount( listMenu );
+ if ( count > 2 )
+ {
+ for ( int i = 2; i < count; i++ )
+ {
+ DeleteMenu( listMenu, 2, MF_BYPOSITION );
+ }
+ }
+
+ Downloads_ButtonPopupMenu( hwndDlg, idFrom, listMenu, BPM_WM_COMMAND );
+}
+
+static BOOL WINAPI DownloadDialog_DlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITMENUPOPUP: // yet yet more send to menu shit...
+ if (wParam && (HMENU)wParam == s.build_hMenu && s.mode==1)
+ {
+ if (SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&s,IPC_LIBRARY_SENDTOMENU)==0xffffffff)
+ s.mode=2;
+ }
+ break;
+
+ case WM_USER+543:
+ Navigation_Update();
+ break;
+
+ case WM_CONTEXTMENU:
+ Downloads_ContextMenu(hwndDlg, wParam, lParam);
+ return TRUE;
+
+ case WM_NOTIFYFORMAT:
+ return NFR_UNICODE;
+
+ case WM_INITDIALOG:
+ Downloads_Init(hwndDlg);
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR l = (LPNMHDR)lParam;
+ if (l->idFrom == IDC_DOWNLOADLIST)
+ return (BOOL)DownloadList_Notify(l,hwndDlg);
+ }
+ break;
+
+ case WM_DESTROY:
+ Downloads_Destroy(hwndDlg);
+ return 0;
+
+ case WM_DISPLAYCHANGE:
+ Downloads_DisplayChange(hwndDlg);
+ return 0;
+
+ case WM_TIMER:
+ Downloads_Timer(hwndDlg, (UINT)wParam);
+ break;
+
+ case WM_MOUSEMOVE:
+ if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
+ {
+ POINT p = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ClientToScreen(hwndDlg, &p);
+ mlDropItemStruct m;
+ ZeroMemory(&m, sizeof(mlDropItemStruct));
+ m.type = ML_TYPE_FILENAMESW;
+ m.p = p;
+ SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
+ {
+ we_are_drag_and_dropping = 0;
+ ReleaseCapture();
+ POINT p = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ClientToScreen(hwndDlg, &p);
+ mlDropItemStruct m = {0};
+ m.type = ML_TYPE_FILENAMESW;
+ m.p = p;
+ m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR;
+ SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
+ if (m.result > 0)
+ {
+ m.flags = 0;
+ m.result = 0;
+ wchar_t* path = getSelectedList();
+ if(path)
+ {
+ m.data = path;
+ SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
+ free(path);
+ }
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ int tab[] = { IDC_DOWNLOADLIST|DCW_SUNKENBORDER};
+ dialogSkinner.Draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
+ }
+ return 0;
+
+ case WM_WINDOWPOSCHANGED:
+ if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
+ (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
+ {
+ LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags));
+ }
+ return 0;
+
+ case WM_USER + 0x200:
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); // yes, we support no - redraw resize
+ return TRUE;
+
+ case WM_USER + 0x201:
+ offsetX = (short)LOWORD(wParam);
+ offsetY = (short)HIWORD(wParam);
+ g_rgnUpdate = (HRGN)lParam;
+ return TRUE;
+
+ case WM_APP + 104:
+ {
+ Downloads_UpdateButtonText(hwndDlg, (int)wParam);
+ LayoutWindows(hwndDlg, TRUE);
+ return 0;
+ }
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam ) )
+ {
+ case IDC_PLAY:
+ case IDC_ENQUEUE:
+ case IDC_CUSTOM:
+ if ( HIWORD( wParam ) == MLBN_DROPDOWN )
+ {
+ Downloads_Play( hwndDlg, (HWND)lParam, LOWORD( wParam ) );
+ }
+ else
+ {
+ bool action;
+ if ( LOWORD( wParam ) == IDC_PLAY )
+ {
+ action = ( HIWORD( wParam ) == 1 ) ? ML_ENQDEF_VAL() == 1 : 0;
+ }
+ else if ( LOWORD( wParam ) == IDC_ENQUEUE )
+ {
+ action = ( HIWORD( wParam ) == 1 ) ? ML_ENQDEF_VAL() != 1 : 1;
+ }
+ else
+ break;
+
+ Downloads_Play( action );
+ }
+ break;
+ case IDC_REMOVE:
+ Downloads_Remove();
+ break;
+ case IDC_DELETE:
+ Downloads_Delete( hwndDlg );
+ break;
+ case IDC_CLEANUP:
+ Downloads_CleanUp( hwndDlg );
+ break;
+ case IDC_INFOBOX:
+ Downloads_InfoBox( hwndDlg );
+ break;
+ case IDC_SELECTALL:
+ Downloads_SelectAll();
+ break;
+ case ID_DOWNLOADS_EXPLORERITEMFOLDER:
+ exploreItemFolder( hwndDlg );
+ break;
+ case ID_DOWNLOADS_CANCELDOWNLOAD:
+ Downloads_Cancel();
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+HWND CALLBACK DownloadDialog_Create( HWND hParent )
+{
+ return WASABI_API_CREATEDIALOGPARAMW( IDD_DOWNLOADS, hParent, DownloadDialog_DlgProc, 0 );
+} \ No newline at end of file