#include "main.h" #include #include #include #include #include "..\..\General\gen_ml/ml.h" #include "..\..\General\gen_ml/itemlist.h" #include "../nu/listview.h" #include "..\..\General\gen_ml/childwnd.h" #include "../winamp/wa_ipc.h" #include "../winamp/wa_dlg.h" #include "resource1.h" #include "SkinnedListView.h" #include "DeviceView.h" #include "api__ml_pmp.h" #include "metadata_utils.h" static int (*wad_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static void (*wad_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize); static void (*cr_init)(HWND hwndDlg, ChildWndResizeItem *list, int num); static void (*cr_resize)(HWND hwndDlg, ChildWndResizeItem *list, int num); static HWND m_hwnd; static ChildWndResizeItem resize_rlist[]= { {IDC_LIST_DEVICES, 0x0010}, {IDC_LIST_TRANSFERS, 0x0011}, {IDC_TQ_STATIC, 0x0000}, {IDC_HDELIM, 0x0010}, {IDC_BUTTON_PAUSETRANSFERS, 0x0101}, {IDC_BUTTON_CLEARFINISHED, 0x0101}, {IDC_BUTTON_REMOVESELECTED, 0x0101}, {IDC_STATUS,0x0111}, }; static int m_nodrawtopborders=0,adiv_clickoffs,adivpos=-1; SkinnedListView * listDevices=NULL; static SkinnedListView * listTransfers=NULL; //CRITICAL_SECTION listTransfersLock; static INT_PTR CALLBACK adiv_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static void adiv_UpdPos(int xp); static WNDPROC adiv_oldWndProc; class DeviceContents : public ListContents { public: virtual int GetNumColumns() { return 2; } virtual int GetNumRows() { return devices.GetSize(); } virtual wchar_t * GetColumnTitle(int num) { switch (num) { case 0: return WASABI_API_LNGSTRINGW(IDS_NAME); case 1: return WASABI_API_LNGSTRINGW(IDS_CAPACITY_FREE); } return L""; } virtual int GetColumnWidth(int num) { switch (num) { case 0: return global_config->ReadInt(L"devices_col0_width",150); case 1: return global_config->ReadInt(L"devices_col1_width",100); default: return 0; } } virtual void ColumnResize(int col, int newWidth) { if (col==0) global_config->WriteInt(L"devices_col0_width",newWidth); else if (col==1) global_config->WriteInt(L"devices_col1_width",newWidth); } virtual void GetCellText(int row, int col, wchar_t * buf, int buflen) { switch (col) { case 0: ((DeviceView *)devices.Get(row))->dev->getPlaylistName(0,buf,buflen); return; case 1: { wchar_t capacity[20]=L""; Device * dev = ((DeviceView *)devices.Get(row))->dev; WASABI_API_LNG->FormattedSizeString(capacity, ARRAYSIZE(capacity), dev->getDeviceCapacityTotal()); __int64 cap = dev->getDeviceCapacityTotal(); int pc; if (cap) pc = (int)((((__int64)100)*dev->getDeviceCapacityAvailable()) / cap); else pc = 0; wsprintf(buf,L"%s (%d%%)",capacity,pc); } return; } } virtual songid_t GetTrack(int pos) { return 0; } }; static DeviceContents deviceListContents; class TransferItemShadow { public: CopyInst * c; wchar_t * status, * type, * track; wchar_t device[128]; bool changed; TransferItemShadow(CopyInst * c) { changed = false; this->c = c; status = _wcsdup(c->statusCaption); type = _wcsdup(c->typeCaption); track = _wcsdup(c->trackCaption); device[0] = 0; c->dev->dev->getPlaylistName(0,device,128); } ~TransferItemShadow() { free(status); free(type); free(track); } bool Equals(TransferItemShadow * a) { if (!a) return false; return (c == a->c) && !wcscmp(track,a->track) && !wcscmp(status,a->status) && !wcscmp(device,a->device) && !wcscmp(type,a->type); } }; static C_ItemList *getTransferListShadow() { C_ItemList * list = new C_ItemList; for (int i=0; i < devices.GetSize(); i++) { DeviceView *device = (DeviceView*)devices.Get(i); LinkedQueue * txQueue = getTransferQueue(device); LinkedQueue * finishedTX = getFinishedTransferQueue(device); if (txQueue) { txQueue->lock(); int l = txQueue->GetSize(); for (int j=0; jAdd(new TransferItemShadow((CopyInst*)txQueue->Get(j))); txQueue->unlock(); } if (finishedTX) { finishedTX->lock(); int l = finishedTX->GetSize(); for (int j=0; jAdd(new TransferItemShadow((CopyInst*)finishedTX->Get(j))); finishedTX->unlock(); } } return list; } class TransferContents2 : public ListContents { public: CRITICAL_SECTION cs; C_ItemList * listShadow; TransferContents2() : listShadow(0) { oldSize = 0; listShadow = getTransferListShadow(); InitializeCriticalSection(&cs); } virtual ~TransferContents2() { DeleteCriticalSection(&cs); delete listShadow; } virtual int GetNumColumns() { return 4; } virtual int GetNumRows() { return (listShadow ? listShadow->GetSize() : 0); } virtual wchar_t * GetColumnTitle(int num) { switch (num) { case 0: return WASABI_API_LNGSTRINGW(IDS_TYPE); case 1: return WASABI_API_LNGSTRINGW(IDS_TRACK); case 2: return WASABI_API_LNGSTRINGW(IDS_STATUS); case 3: return WASABI_API_LNGSTRINGW(IDS_DEVICE); } return L""; } virtual int GetColumnWidth(int num) { switch (num) { case 0: return global_config->ReadInt(L"transfers_col0_width",100); case 1: return global_config->ReadInt(L"transfers_col1_width",300); case 2: return global_config->ReadInt(L"transfers_col2_width",150); case 3: return global_config->ReadInt(L"transfers_col3_width",150); default: return 0; } } virtual void ColumnResize(int col, int newWidth) { if (col==0) global_config->WriteInt(L"transfers_col0_width",newWidth); else if (col==1) global_config->WriteInt(L"transfers_col1_width",newWidth); else if (col==2) global_config->WriteInt(L"transfers_col2_width",newWidth); else if (col==3) global_config->WriteInt(L"transfers_col3_width",newWidth); } void lock() { EnterCriticalSection(&cs); } void unlock() { LeaveCriticalSection(&cs); } virtual void GetCellText(int row, int col, wchar_t * buf, int buflen) { lock(); if (row >= listShadow->GetSize()) { unlock(); return; } TransferItemShadow * t = (TransferItemShadow *)listShadow->Get(row); switch (col) { case 0: lstrcpyn(buf,t->type,buflen); break; case 1: lstrcpyn(buf,t->track,buflen); break; case 2: lstrcpyn(buf,t->status,buflen); break; case 3: lstrcpyn(buf,t->device,buflen); break; } unlock(); } void PushPopItem(CopyInst *c) { lock(); int size = listShadow->GetSize(); for (int i=0; iGet(i); if (c == t->c) { t->changed=true; listShadow->Del(i); listShadow->Add(t); if (listTransfers) { HWND hwnd = listTransfers->listview.getwnd(); PostMessage(hwnd,LVM_DELETEITEM,i,0); PostMessage(hwnd,LVM_SETITEMCOUNT,size,LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL); } unlock(); return; } } unlock(); } void ItemUpdate(CopyInst * c) { lock(); int size = listShadow->GetSize(); for (int i=0; iGet(i); if (c == t->c) { TransferItemShadow * n = new TransferItemShadow(c); n->changed=true; listShadow->Set(i,n); delete t; if (listTransfers) { HWND hwnd = listTransfers->listview.getwnd(); PostMessage(hwnd,LVM_REDRAWITEMS,i,i); } unlock(); return; } } unlock(); } int oldSize; void FullUpdate() { C_ItemList * newListShadow = getTransferListShadow(); int newSize = newListShadow->GetSize(); lock(); oldSize = listShadow->GetSize(); for (int i=0; iGet(i); TransferItemShadow * oldt = iGet(i):NULL; newt->changed = !newt->Equals(oldt); } C_ItemList * oldListShadow = listShadow; listShadow = newListShadow; for (int i=0; iGetSize(); i++) delete(TransferItemShadow *)oldListShadow->Get(i); delete oldListShadow; if (listTransfers) { HWND hwnd = listTransfers->listview.getwnd(); if (newSize != oldSize) PostMessage(hwnd,LVM_SETITEMCOUNT,newSize, 0); for (int i=0; iGet(i); if (t->changed) PostMessage(hwnd,LVM_REDRAWITEMS,i,i); } } unlock(); } virtual songid_t GetTrack(int pos) { return 0; } }; static void updateStatus() { int pcnum=0,num=0,time=0,total=0; for (int i=0; iGetSize() : 0); int n = (s * 100) - txProgress; total += s * 100; total += 100 * (finishedTX ? finishedTX->GetSize() : 0); pcnum += n; num += s; int t = (int)(device->transferRate * (((double)n) / 100.0)); if (time < t) time = t; } if (total) { wchar_t caption[256] = {0}; int pc = ((total-pcnum)*100)/total; wsprintf(caption,WASABI_API_LNGSTRINGW((time > 0 ? IDS_TRANFERS_PERCENT_REMAINING : IDS_TRANFERS_PERCENT_REMAINING_NOT_TIME)),num,pc,time/60,time%60); SetDlgItemText(m_hwnd,IDC_STATUS,caption); } else SetDlgItemText(m_hwnd,IDC_STATUS,L""); } static TransferContents2 transferListContents; void TransfersListUpdateItem(CopyInst * item) { transferListContents.ItemUpdate(item); } void TransfersListPushPopItem(CopyInst * item) { transferListContents.PushPopItem(item); } void UpdateDevicesListView(bool softUpdate) { if (listDevices) listDevices->UpdateList(softUpdate); } static bool AddSelectedItems(C_ItemList *items, W_ListView *listview, LinkedQueue *transfer_queue, int &row, DeviceView *&dev) { transfer_queue->lock(); int l = transfer_queue->GetSize(); for (int j=0; jGetSelected(row++)) { CopyInst * c = (CopyInst *)transfer_queue->Get(j); if (c->songid) { if (!dev && c->dev) dev = c->dev; if (dev) { if (c->dev != dev) { transfer_queue->unlock(); return false; } else items->Add((void*)c->songid); } } } } transfer_queue->unlock(); return true; } static void RemoveSelectedItems(DeviceView *device, W_ListView *listview, LinkedQueue *transfer_queue, int &row, bool finished_queue) { transfer_queue->lock(); int j = transfer_queue->GetSize(); while (j-- > 0) { if (listview->GetSelected(--row)) { if (j == 0 && !finished_queue) { CopyInst * d = (CopyInst *)transfer_queue->Get(j); if (d && d->status == STATUS_WAITING && device->transferContext.IsPaused()) { transfer_queue->Del(j); d->Cancelled(); delete d; } // otherwise don't bother } else { CopyInst * d = (CopyInst*)transfer_queue->Del(j); if (d) { if (d->status == STATUS_WAITING && !finished_queue) d->Cancelled(); delete d; } } } } transfer_queue->unlock(); } extern void handleContextMenuResult(int r, C_ItemList * items=NULL, DeviceView * dev=NULL); extern int showContextMenu(int context,HWND hwndDlg, Device * dev, POINT pt); extern int (*wad_getColor)(int idx); INT_PTR CALLBACK pmp_devices_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; } if (listDevices) { BOOL a=listDevices->DialogProc(hwndDlg,uMsg,wParam,lParam); if (a) return a; } if (listTransfers) { BOOL a=listTransfers->DialogProc(hwndDlg,uMsg,wParam,lParam); if (a) return a; } switch (uMsg) { case WM_INITDIALOG: m_hwnd=hwndDlg; *(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC); *(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC); *(void **)&cr_init=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,32,ML_IPC_SKIN_WADLG_GETFUNC); *(void **)&cr_resize=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,33,ML_IPC_SKIN_WADLG_GETFUNC); if (cr_init) cr_init(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0])); listDevices = new SkinnedListView(&deviceListContents,IDC_LIST_DEVICES,plugin.hwndLibraryParent, hwndDlg); listDevices->DialogProc(hwndDlg,uMsg,0,0); transferListContents.lock(); listTransfers = new SkinnedListView(&transferListContents,IDC_LIST_TRANSFERS,plugin.hwndLibraryParent, hwndDlg); listTransfers->DialogProc(hwndDlg,uMsg,0,0); transferListContents.unlock(); adiv_oldWndProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_HDELIM),GWLP_WNDPROC,(LONG_PTR)adiv_newWndProc); SetDlgItemText(hwndDlg,IDC_BUTTON_PAUSETRANSFERS,WASABI_API_LNGSTRINGW((TransferContext::IsAllPaused()?IDS_RESUME:IDS_PAUSE))); SetTimer(hwndDlg,1,250,NULL); updateStatus(); break; case WM_TIMER: if (wParam == 1) { updateStatus(); if (device_update_map[0]) { device_update_map[0]=0; transferListContents.FullUpdate(); } } break; case WM_DISPLAYCHANGE: break; case WM_SETCURSOR: // set cursor when near the dividers { RECT r; POINT p; GetCursorPos(&p); GetWindowRect(GetDlgItem(hwndDlg,IDC_HDELIM),&r); r.top-=3; r.bottom+=3; if (PtInRect(&r,p)) { SetCursor(LoadCursor(NULL,IDC_SIZENS)); return uMsg == WM_SETCURSOR; } break; } case WM_LBUTTONDOWN: { // forward dialog clicks to the dividers if they get near them POINT p; RECT r3; GetWindowRect(GetDlgItem(hwndDlg,IDC_VDELIM),&r3); GetCursorPos(&p); GetWindowRect(GetDlgItem(hwndDlg,IDC_HDELIM),&r3); if (p.x >= r3.left && p.x <= r3.right) { int d=p.y-r3.bottom; int d2=p.y-r3.top; if (d<0)d=-d; if (d2<0)d2=-d2; if (d < 6 || d2 < 6) SendDlgItemMessage(hwndDlg,IDC_HDELIM,uMsg,0,0); } } break; case WM_SIZE: if (wParam != SIZE_MINIMIZED) { if (cr_resize) cr_resize(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0])); } break; case WM_PAINT: { if (wad_DrawChildWindowBorders) { int tab[] = {m_nodrawtopborders==1?0:(IDC_LIST_DEVICES|DCW_SUNKENBORDER), m_nodrawtopborders==2?0:(IDC_LIST_TRANSFERS|DCW_SUNKENBORDER), IDC_HDELIM|DCW_DIVIDER }; wad_DrawChildWindowBorders(hwndDlg,tab,3); } } break; case WM_DESTROY: { KillTimer(hwndDlg, 1); m_hwnd=NULL; SkinnedListView * ld = listDevices; listDevices=NULL; delete ld; SkinnedListView * lt = listTransfers; transferListContents.lock(); listTransfers=NULL; transferListContents.unlock(); delete lt; } break; case WM_NOTIFY: { LPNMHDR l=(LPNMHDR)lParam; if (l->idFrom==IDC_LIST_TRANSFERS) switch (l->code) { case NM_RETURN: // enter! case NM_RCLICK: // right click! case LVN_KEYDOWN: { DeviceView * dev = NULL; C_ItemList items; int row = 0; for (int i=0; ilistview, getTransferQueue(device), row, dev)) return 0; if (!AddSelectedItems(&items, &listTransfers->listview, getFinishedTransferQueue(device), row, dev)) return 0; } bool foundDev=false; for (int k=0; kcode == NM_RCLICK) { LPNMITEMACTIVATE lva=(LPNMITEMACTIVATE)lParam; handleContextMenuResult(showContextMenu(7,l->hwndFrom,dev->dev,lva->ptAction),&items,dev); } else if (l->code == NM_RETURN) { handleContextMenuResult((!GetAsyncKeyState(VK_SHIFT)?ID_TRACKSLIST_PLAYSELECTION:ID_TRACKSLIST_ENQUEUESELECTION),&items,dev); } else if (l->code == LVN_KEYDOWN) { switch (((LPNMLVKEYDOWN)lParam)->wVKey) { case VK_DELETE: { if (!(GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_SHIFT)&0x8000)) { handleContextMenuResult(ID_TRACKSLIST_DELETE,&items,dev); } } break; case 0x45: //E if ((GetAsyncKeyState(VK_CONTROL)&0x8000) && !(GetAsyncKeyState(VK_SHIFT)&0x8000)) { handleContextMenuResult(ID_TRACKSLIST_EDITSELECTEDITEMS,&items,dev); } break; } } } break; } } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTON_CLEARFINISHED: { for (int i=0; ilock(); int j=finishedTX->GetSize(); while (j-- > 0) delete(CopyInst*)finishedTX->Del(j); finishedTX->unlock(); } } transferListContents.FullUpdate(); } break; case IDC_BUTTON_REMOVESELECTED: { int row = transferListContents.GetNumRows(); int i = devices.GetSize(); while (i-- > 0) { DeviceView *device = (DeviceView *)devices.Get(i); RemoveSelectedItems(device, &listTransfers->listview, getTransferQueue(device), row, false); RemoveSelectedItems(device, &listTransfers->listview, getFinishedTransferQueue(device), row, true); } transferListContents.FullUpdate(); } break; case IDC_BUTTON_PAUSETRANSFERS: if (false != TransferContext::IsAllPaused()) TransferContext::ResumeAll(); else TransferContext::PauseAll(); for (int i=0;itransferContext.notifier); } SetDlgItemText(hwndDlg,IDC_BUTTON_PAUSETRANSFERS,WASABI_API_LNGSTRINGW((TransferContext::IsAllPaused()?IDS_RESUME:IDS_PAUSE))); break; } break; case WM_MOUSEMOVE: if (wParam==MK_LBUTTON) { if (GetCapture() == hwndDlg) ReleaseCapture(); } break; } return 0; } // deals with the horizontal (IDC_HDELIM) divider static void adiv_UpdPos(int yp) { RECT r,old_divider_rect; GetClientRect(m_hwnd,&r); GetWindowRect(GetDlgItem(m_hwnd,IDC_HDELIM),&old_divider_rect); ScreenToClient(m_hwnd,(LPPOINT)&old_divider_rect); ScreenToClient(m_hwnd,((LPPOINT)&old_divider_rect)+1); if (yp < 50) { m_nodrawtopborders=1; yp=20; } else m_nodrawtopborders=0; if (yp > r.bottom-42-30) { yp=r.bottom-42; m_nodrawtopborders=2; } int x; for (x = 0; x < 4; x ++) { RECT myoldr; GetWindowRect(GetDlgItem(m_hwnd,resize_rlist[x].id),&myoldr); ScreenToClient(m_hwnd,(LPPOINT)&myoldr); ScreenToClient(m_hwnd,((LPPOINT)&myoldr)+1); switch (x) { case 0: resize_rlist[x].rinfo.bottom=yp - old_divider_rect.top + myoldr.bottom; break; case 1: resize_rlist[x].rinfo.top=yp - old_divider_rect.top + myoldr.top; break; case 2: case 3: { int h=resize_rlist[x].rinfo.bottom - resize_rlist[x].rinfo.top; resize_rlist[x].rinfo.top = yp - old_divider_rect.top + resize_rlist[x].rinfo.top; resize_rlist[x].rinfo.bottom = resize_rlist[x].rinfo.top + h; } break; } } cr_resize(m_hwnd,resize_rlist,4); } static INT_PTR CALLBACK adiv_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { if (uMsg == WM_LBUTTONDOWN) { SetForegroundWindow(hwndDlg); SetCapture(hwndDlg); SetCursor(LoadCursor(NULL,IDC_SIZENS)); POINT p; GetCursorPos(&p); ScreenToClient(hwndDlg,&p); adiv_clickoffs=p.y; } else if (uMsg == WM_SETCURSOR) { SetCursor(LoadCursor(NULL,IDC_SIZENS)); return TRUE; } else if (uMsg == WM_MOUSEMOVE && GetCapture()==hwndDlg) { POINT p; GetCursorPos(&p); ScreenToClient(GetParent(hwndDlg),&p); adiv_UpdPos(p.y-adiv_clickoffs); RECT r; GetClientRect(GetParent(hwndDlg),&r); if (r.bottom > r.top) { int percent = ((p.y-adiv_clickoffs) * 100000) / (r.bottom-r.top); adivpos = percent; } } else if (uMsg == WM_MOUSEMOVE) { SetCursor(LoadCursor(NULL,IDC_SIZENS)); } else if (uMsg == WM_LBUTTONUP) { ReleaseCapture(); } return CallWindowProc(adiv_oldWndProc,hwndDlg,uMsg,wParam,lParam); }