winamp/Src/Plugins/Library/ml_pmp/view_pmp_media.cpp
2024-09-24 14:54:57 +02:00

3205 lines
110 KiB
C++

#include "main.h"
#include "..\..\General\gen_ml/ml.h"
#include "..\..\General\gen_ml/ml_ipc_0313.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 "ArtistAlbumLists.h"
#include "mt19937ar.h" // random number generator
#include "api__ml_pmp.h"
#include "..\..\General\gen_ml/graphics.h"
#include <tataki/export.h>
#include <tataki/bitmap/bitmap.h>
#include <tataki/canvas/bltcanvas.h>
#include "AlbumArtListView.h"
#include "./local_menu.h"
#include "metadata_utils.h"
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <shlobj.h>
extern winampMediaLibraryPlugin plugin;
extern int currentViewedPlaylist;
extern DeviceView * currentViewedDevice;
extern HMENU m_context_menus;
extern C_ItemList devices;
extern void editInfo(C_ItemList * items, Device * dev, HWND centerWindow); // from editinfo.cpp
static INT_PTR CALLBACK pmp_common_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
int (*wad_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void (*wad_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize);
HWND hwndMediaView;
static SkinnedListView *artistList=NULL, *albumList=NULL, *albumList2=NULL, *tracksList=NULL;
static int adiv1_nodraw=0,adiv3_nodraw=0;
static int m_nodrawtopborders=0;
static int numFilters;
static int adiv1pos=-1, adiv2pos=-1, adiv3pos=-1;
static int refineHidden=0;
static BOOL g_displaysearch = TRUE;
static BOOL g_displayrefine = TRUE;
static BOOL g_displaystatus = TRUE;
static HRGN g_rgnUpdate = NULL;
static int offsetX = 0, offsetY = 0, header = 0;
viewButtons view = {0};
static bool noSearchTimer=false;
static ArtistAlbumLists *aacontents=NULL;
static PrimaryListContents *tracks=NULL;
static void UpdateStatus(HWND hwndDlg, bool full = false) {
wchar_t buf[1024]=L"";
if (tracks)
{
tracks->GetInfoString(buf);
SetDlgItemText(hwndDlg,IDC_STATUS,buf);
}
if (full && currentViewedDevice && currentViewedDevice->isCloudDevice)
{
int usedPercent = 0;
__int64 available = currentViewedDevice->dev->getDeviceCapacityAvailable();
__int64 capacity = currentViewedDevice->dev->getDeviceCapacityTotal();
if(capacity > 0) usedPercent = (int)((((__int64)100)*available) / capacity);
if (!header)
{
wchar_t buf[128], status[128], availStr[100]=L"";
currentViewedDevice->dev->getTrackExtraInfo(0, L"cloud_status", status, ARRAYSIZE(status));
WASABI_API_LNG->FormattedSizeString(availStr, ARRAYSIZE(availStr), (available > 0 ? available : capacity));
wsprintf(buf, L"%s %s %s", availStr, (available > 0 ? L"free" : L"used"), status);
SetDlgItemText(hwndDlg, IDC_HEADER_DEVICE_SIZE, buf);
SendDlgItemMessage(hwndDlg, IDC_HEADER_DEVICE_BAR, PBM_SETPOS, (100 - usedPercent), 0);
}
}
}
static wchar_t *playmode = L"viewplaymode";
typedef void (WINAPI *DIVIDERMOVED)(HWND, INT, LPARAM);
typedef struct _DIVIDER
{
BOOL fVertical;
DIVIDERMOVED callback;
LPARAM param;
WNDPROC fnOldProc;
BOOL fUnicode;
INT clickoffs;
} DIVIDER;
#define GET_DIVIDER(hwnd) (DIVIDER*)GetPropW(hwnd, L"DIVDATA")
static BOOL AttachDivider(HWND hwnd, BOOL fVertical, DIVIDERMOVED callback, LPARAM param);
static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void WINAPI OnDividerMoved(HWND hwnd, INT nPos, LPARAM param);
void LayoutWindows(HWND hwnd, BOOL fRedraw, INT simple);
static HBITMAP ConvertTo24bpp(HBITMAP bmp, int bpp)
{
HDC hdcMem, hdcMem2;
HBITMAP hbm24;
BITMAP bm;
GetObjectW(bmp, sizeof(BITMAP), &bm);
hdcMem = CreateCompatibleDC(0);
hdcMem2 = CreateCompatibleDC(0);
void *bits;
BITMAPINFOHEADER bi;
ZeroMemory (&bi, sizeof (bi));
bi.biSize = sizeof (bi);
bi.biWidth= bm.bmWidth;
bi.biHeight = -bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount= bpp;
hbm24 = CreateDIBSection(hdcMem2, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, NULL);
HBITMAP oBmp = (HBITMAP)SelectObject(hdcMem, bmp);
HBITMAP oBmp24 = (HBITMAP)SelectObject(hdcMem2, hbm24);
BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oBmp);
SelectObject(hdcMem2, oBmp24);
DeleteDC(hdcMem);
DeleteDC(hdcMem2);
return hbm24;
}
C_ItemList * getSelectedItems(bool all=false) {
if(!currentViewedDevice) return NULL;
C_ItemList * selected = new C_ItemList;
int l = tracks->GetNumRows();
if(all || tracksList->listview.GetSelectedCount()==0) for(int i=0; i<l; i++) selected->Add((void*)tracks->GetTrack(i));
else for(int i=0; i<l; i++) if(tracksList->listview.GetSelected(i)) selected->Add((void*)tracks->GetTrack(i));
return selected;
}
int showContextMenu(int context, HWND hwndDlg, Device * dev, POINT pt) {
// does cloud specific menu hacks
int cloud_devices = 0;
HMENU cloud_menu = 0;
if (context < 2)
{
int mark = tracksList->listview.GetSelectionMark();
if (mark != -1)
{
// if wanting to do on the selection then use getSelectedItems()
//C_ItemList * items = getSelectedItems();
// otherwise only work on the selection mark for speed (and like how ml_local does things)
C_ItemList * items = new C_ItemList;
items->Add((void*)tracks->GetTrack(mark));
cloud_menu = (HMENU)dev->extraActions(DEVICE_GET_CLOUD_SOURCES_MENU, (intptr_t)&cloud_devices, 0, (intptr_t)items);
delete items;
}
}
HMENU menu = GetSubMenu(m_context_menus, context);
HMENU sendto = GetSubMenu(menu, 2);
int fieldsBits = (int)dev->extraActions(DEVICE_SUPPORTED_METADATA, 0, 0, 0);
bool noRatings = !(!fieldsBits || (fieldsBits & SUPPORTS_RATING));
bool noEdit = dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA, 0, 0, 0) != 0;
HMENU ratingMenu = Menu_FindRatingMenu(menu, FALSE);
if (NULL != ratingMenu)
{
Menu_SetRatingValue(ratingMenu, -1);
}
// toggle text of the delete menu item as needed
MENUITEMINFOW mii = {sizeof(MENUITEMINFOW), 0};
mii.fMask = MIIM_STRING;
mii.dwTypeData = WASABI_API_LNGSTRINGW(!currentViewedDevice->isCloudDevice ? IDS_DELETE : IDS_REMOVE);
mii.cch = wcslen(mii.dwTypeData);
// just make sure we've got a string to use here
if (mii.cch > 0)
{
SetMenuItemInfoW(menu, ID_TRACKSLIST_DELETE, FALSE, &mii);
}
EnableMenuItem(menu, ID_TRACKSLIST_DELETE, MF_BYCOMMAND |
(!currentViewedDevice->isCloudDevice ||
(currentViewedDevice->isCloudDevice &&
!currentViewedDevice->dev->extraActions(DEVICE_NOT_READY_TO_VIEW, 0, 0, 0))) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_TRACKSLIST_EDITSELECTEDITEMS, MF_BYCOMMAND | noEdit ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_0, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_1, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_2, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_3, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_4, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_RATE_5, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(menu, ID_TRACKSLIST_COPYTOLIBRARY, MF_BYCOMMAND | dev->copyToHardDriveSupported() ? MF_ENABLED : MF_GRAYED);
int num = 0;
// TODO remove once we've got cloud playlist implemented
if (0 == dev->extraActions(DEVICE_PLAYLISTS_UNSUPPORTED,0,0,0))
{
if (EnableMenuItem(menu, ID_ADDTOPLAYLIST_NEWPLAYLIST, MF_BYCOMMAND | (!cloud_menu ? MF_ENABLED : MF_GRAYED)) == -1)
{
MENUITEMINFOW m = {sizeof(m), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU, MFT_STRING, 0};
wchar_t a[100] = {0};
m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_SEND_TO_PL, a, 100);
m.wID = 2;
sendto = m.hSubMenu = CreatePopupMenu();
InsertMenuItemW(menu, 2, TRUE, &m);
m.fMask -= MIIM_SUBMENU;
m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CMD_PLAYLIST_CREATE, a, 100);
m.wID = ID_ADDTOPLAYLIST_NEWPLAYLIST;
m.fState = (!cloud_menu ? MF_ENABLED : MF_GRAYED);
InsertMenuItemW(m.hSubMenu, 0, FALSE, &m);
}
num = dev->getPlaylistCount();
if(num > 1) AppendMenu(sendto, MF_SEPARATOR, 0, L"");
for(int i=1; i<num; i++) {
wchar_t buf[100] = {0};
dev->getPlaylistName(i, buf, sizeof(buf)/sizeof(wchar_t));
AppendMenu(sendto, 0, 100000 + i, buf);
}
}
else
{
if (DeleteMenu(menu, ID_ADDTOPLAYLIST_NEWPLAYLIST, MF_BYCOMMAND))
{
DeleteMenu(menu, 2, MF_BYPOSITION);
sendto = NULL;
}
}
if (cloud_menu)
{
MENUITEMINFOW m = {sizeof(m), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU, MFT_SEPARATOR, 0};
m.wID = CLOUD_SOURCE_MENUS - 1;
m.fType = MFT_SEPARATOR;
InsertMenuItemW(menu, (sendto ? 3 : 2), TRUE, &m);
wchar_t a[100] = {0};
m.fType = MFT_STRING;
m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_CLOUD_SOURCES, a, 100);
m.wID = CLOUD_SOURCE_MENUS;
m.hSubMenu = cloud_menu;
InsertMenuItemW(menu, (sendto ? 4 : 3), TRUE, &m);
}
if (-1 == pt.x && -1 == pt.y)
{
RECT itemRect;
int selected = ListView_GetNextItem(hwndDlg, -1, LVNI_ALL | LVNI_SELECTED);
ListView_GetItemRect(hwndDlg, (selected != -1 ? selected : 0), &itemRect, LVIR_BOUNDS);
pt.x = itemRect.left;
pt.y = itemRect.top;
MapWindowPoints(hwndDlg, HWND_DESKTOP, (POINT*)&pt, 1);
}
int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY, pt.x, pt.y, hwndDlg, NULL);
if(num > 1) DeleteMenu(sendto,1,MF_BYPOSITION);
for(int i = 1; i < num; i++) DeleteMenu(sendto, 100000+i, MF_BYCOMMAND);
if (cloud_menu)
{
DeleteMenu(menu, (sendto ? 4 : 3), MF_BYPOSITION);
DeleteMenu(menu, (sendto ? 3 : 2), MF_BYPOSITION);
DestroyMenu(cloud_menu);
}
return r;
}
void handleContextMenuResult(int r, C_ItemList * items0=NULL, DeviceView * dev=NULL) {
if(!dev) dev = currentViewedDevice;
if(!dev) return;
C_ItemList * items = items0;
switch(r) {
case ID_TRACKSLIST_PLAYSELECTION:
case ID_TRACKSLIST_ENQUEUESELECTION:
{
if (!items) items = getSelectedItems();
dev->PlayTracks(items, 0, r==ID_TRACKSLIST_ENQUEUESELECTION, true, hwndMediaView);
if (!items0) delete items;
}
break;
case ID_ADDTOPLAYLIST_NEWPLAYLIST:
{
int n = dev->CreatePlaylist();
if (n == -1) return;
r = 100000 + n;
// the selected tracks will be added by the code at the end of this function
}
break;
case ID_TRACKSLIST_SELECTALL:
{
int num = tracksList->listview.GetCount();
for (int x = 0; x < num; x ++) tracksList->listview.SetSelected(x);
}
break;
case ID_TRACKSLIST_EDITSELECTEDITEMS:
{
if (!items) items = getSelectedItems();
editInfo(items, dev->dev, CENTER_OVER_ML_VIEW);
}
break;
case ID_RATE_5:
case ID_RATE_4:
case ID_RATE_3:
case ID_RATE_2:
case ID_RATE_1:
case ID_RATE_0:
{
if (!items) items = getSelectedItems();
for(int i = 0; i<items->GetSize(); i++)
dev->dev->setTrackRating((songid_t)items->Get(i), ID_RATE_0 - r);
if (tracksList) tracksList->UpdateList(true);
dev->DevicePropertiesChanges();
}
break;
case ID_TRACKSLIST_DELETE:
{
wchar_t buf[256] = {0};
if (!items) items = getSelectedItems();
wsprintf(buf,WASABI_API_LNGSTRINGW((!currentViewedDevice->isCloudDevice ? IDS_PHYSICALLY_REMOVE_X_TRACKS : IDS_CLOUD_REMOVE_X_TRACKS)),items->GetSize());
bool ckdev = (dev == currentViewedDevice);
wchar_t titleStr[32] = {0};
if (MessageBox(hwndMediaView, buf, WASABI_API_LNGSTRINGW_BUF(IDS_ARE_YOU_SURE, titleStr, 32), MB_YESNO | MB_ICONQUESTION) == IDYES) {
if (ckdev && !currentViewedDevice) return;
dev->DeleteTracks(items, CENTER_OVER_ML_VIEW);
if (aacontents && dev == currentViewedDevice) { // full artist-album refresh
GetDlgItemText(hwndMediaView, IDC_QUICKSEARCH, buf, sizeof(buf)/sizeof(wchar_t));
// TODO async
if (aacontents) aacontents->SetSearch(buf);
GetDlgItemText(hwndMediaView, IDC_REFINE, buf, sizeof(buf)/sizeof(wchar_t));
if (aacontents) aacontents->SetRefine(buf);
if (artistList) artistList->UpdateList();
if (albumList) albumList->UpdateList();
if (albumList2) albumList2->UpdateList();
}
if (tracksList) tracksList->UpdateList();
dev->DevicePropertiesChanges();
UpdateStatus(hwndMediaView, true);
}
}
break;
case ID_TRACKSLIST_COPYTOLIBRARY:
{
if (!items) items = getSelectedItems();
dev->CopyTracksToHardDrive(items);
}
break;
}
if(r > 100000) { // add songs to existing playlist
int num = dev->dev->getPlaylistCount();
if(r < num + 100000) {
r-=100000;
if(!items) items = getSelectedItems();
for(int i = 0; i < items->GetSize(); i++) dev->dev->addTrackToPlaylist(r,(songid_t)items->Get(i));
dev->DevicePropertiesChanges();
}
}
else if (r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_UPPER) { // deals with cloud specific menus
if (!items) items = getSelectedItems();
int ret = dev->dev->extraActions(DEVICE_DO_CLOUD_SOURCES_MENU, (intptr_t)r, items->GetSize(), (intptr_t)items);
// only send a removal from the view if plug-in says so
if (ret) SendMessage(hwndMediaView, WM_USER+1, (WPARAM)items->Get(0), ret);
}
if (!items0) delete items;
}
void localizeFilter(const wchar_t *f, wchar_t *buf, int len) {
int r=0;
if(!_wcsicmp(f,L"Artist")) r = IDS_ARTIST;
else if(!_wcsicmp(f,L"Album")) r = IDS_ALBUM;
else if(!_wcsicmp(f,L"Genre")) r = IDS_GENRE;
else if(!_wcsicmp(f,L"Artist Index")) r = IDS_ARTIST_INDEX;
else if(!_wcsicmp(f,L"Year")) r = IDS_YEAR;
else if(!_wcsicmp(f,L"Album Artist")) r = IDS_ALBUM_ARTIST;
else if(!_wcsicmp(f,L"Publisher")) r = IDS_PUBLISHER;
else if(!_wcsicmp(f,L"Composer")) r = IDS_COMPOSER;
else if(!_wcsicmp(f,L"Album Artist Index")) r = IDS_ALBUM_ARTIST_INDEX;
else if(!_wcsicmp(f,L"Album Art")) r = IDS_ALBUM_ART;
else {buf[0]=0; return;}
WASABI_API_LNGSTRINGW_BUF(r,buf,len);
}
wchar_t *GetDefFilter(int i,int n) {
if(n==2) i++;
if(i==0) return L"Genre";
if(i==1) return L"Artist";
return L"Album";
}
static __forceinline BYTE pm(int a, int b) {
return (BYTE) ((a * b) / 0xff);
}
extern svc_imageLoader *GetPngLoaderService();
static ARGB32 *LoadPngResource(HINSTANCE module, const wchar_t *name, const wchar_t *type,
BOOL premultily, int *width, int *height)
{
svc_imageLoader *wasabiPngLoader;
HRSRC resource;
HANDLE resourceHandle;
ARGB32 *result;
if (NULL == WASABI_API_MEMMGR)
return NULL;
wasabiPngLoader = GetPngLoaderService();
if (NULL == wasabiPngLoader)
return NULL;
resource = FindResourceW(module, name, type);
if (NULL == resource)
return NULL;
result = NULL;
resourceHandle = LoadResource(module, resource);
if (NULL != resourceHandle)
{
unsigned long resourceSize = SizeofResource(module, resource);
if (0 != resourceSize)
{
void *resourceData = LockResource(resourceHandle);
if (NULL != resourceData)
{
result = (FALSE != premultily) ?
wasabiPngLoader->loadImage(resourceData, resourceSize, width, height) :
wasabiPngLoader->loadImageData(resourceData, resourceSize, width, height);
}
}
}
return result;
}
void DeleteSkinBitmap(SkinBitmap *skinBitmap)
{
void *bits;
if (NULL == skinBitmap)
return;
bits = skinBitmap->getBits();
if (NULL != bits)
{
if (NULL != WASABI_API_MEMMGR)
WASABI_API_MEMMGR->sysFree(bits);
}
delete skinBitmap;
}
BOOL SetToolbarButtonBitmap(HWND hwnd, int controlId, const wchar_t *resourceName, ARGB32 fc)
{
int width, height;
ARGB32 *data, *x, *end;
BYTE r, g, b;
SkinBitmap *sbm, *old;
HWND controlWindow;
controlWindow = GetDlgItem(hwnd, controlId);
if (NULL == controlWindow)
return FALSE;
data = LoadPngResource(plugin.hDllInstance, resourceName, RT_RCDATA, FALSE, &width, &height);
if (NULL == data)
return FALSE;
r = (BYTE)(fc & 0x00ff0000 >> 16);
g = (BYTE)(fc & 0x0000ff00 >> 8);
b = (BYTE)(fc & 0x000000ff);
x = data;
end = data + width*height;
while(x < end)
{
BYTE a = (BYTE)(~(*x))&0xff;
*(x++) = (a<<24) | (pm(r,a)<<16) | (pm(g,a)<<8) | pm(b,a);
}
sbm = new SkinBitmap(data, width, height);
old = (SkinBitmap*)SetWindowLongPtr(controlWindow, GWLP_USERDATA,(LONG_PTR)sbm);
DeleteSkinBitmap(old);
InvalidateRect(controlWindow, NULL, TRUE);
return TRUE;
}
typedef struct { int id, id2; } hi;
void do_help(HWND hwnd, UINT id, HWND hTooltipWnd)
{
RECT r;
POINT p;
GetWindowRect(GetDlgItem(hwnd, id), &r);
GetCursorPos(&p);
if (p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom)
{}
else
{
r.left += r.right;
r.left /= 2;
r.top += r.bottom;
r.top /= 2;
SetCursorPos(r.left, r.top);
}
SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_INITIAL, 0);
SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_RESHOW, 0);
}
#define C_BLAH
#define DO_HELP() \
static HWND hTooltipWnd; \
C_BLAH \
if (uMsg == WM_HELP) { \
HELPINFO *hi=(HELPINFO *)(lParam); \
if (hi->iContextType == HELPINFO_WINDOW) { do_help(hwndDlg,hi->iCtrlId,hTooltipWnd);} \
return TRUE; \
} \
if (uMsg == WM_NOTIFY) { LPNMHDR t=(LPNMHDR)lParam; if (t->code == TTN_POP) { SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,1000); SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,1000); } } \
if (uMsg == WM_DESTROY && IsWindow(hTooltipWnd)) { DestroyWindow(hTooltipWnd); hTooltipWnd=NULL; } \
if (uMsg == WM_INITDIALOG) { \
int x; \
hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,(LPCWSTR)NULL,TTS_ALWAYSTIP|TTS_NOPREFIX, \
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwndDlg,NULL,GetModuleHandle(NULL),NULL); \
SendMessage(hTooltipWnd,TTM_SETMAXTIPWIDTH,0,587); \
SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,250); \
SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,500); \
for (x = 0; x < sizeof(helpinfo)/sizeof(helpinfo[0]); x ++) { \
TOOLINFO ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND; \
ti.uId=(UINT_PTR)GetDlgItem(hwndDlg,helpinfo[x].id); ti.hwnd=hwndDlg; ti.lpszText=WASABI_API_LNGSTRINGW(helpinfo[x].id2); \
SendMessage(hTooltipWnd,TTM_ADDTOOL,0,(LPARAM) &ti); \
} \
}
static BOOL ListView_OnCustomDraw(HWND hwndDlg, NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
{
static BOOL bDrawFocus;
static RECT rcView;
static CLOUDCOLUMNPAINT cloudColumnPaint;
*pResult = CDRF_DODEFAULT;
switch (plvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult |= CDRF_NOTIFYITEMDRAW;
CopyRect(&rcView, &plvcd->nmcd.rc);
cloudColumnPaint.hwndList = plvcd->nmcd.hdr.hwndFrom;
cloudColumnPaint.hdc = plvcd->nmcd.hdc;
cloudColumnPaint.prcView = &rcView;
return TRUE;
case CDDS_ITEMPREPAINT:
*pResult |= CDRF_NOTIFYSUBITEMDRAW;
bDrawFocus = (CDIS_FOCUS & plvcd->nmcd.uItemState);
if (bDrawFocus)
{
plvcd->nmcd.uItemState &= ~CDIS_FOCUS;
*pResult |= CDRF_NOTIFYPOSTPAINT;
}
return TRUE;
case CDDS_ITEMPOSTPAINT:
if (bDrawFocus)
{
RECT rc;
rc.left = LVIR_BOUNDS;
SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&rc);
rc.left += 3;
DrawFocusRect(plvcd->nmcd.hdc, &rc);
plvcd->nmcd.uItemState |= CDIS_FOCUS;
bDrawFocus = FALSE;
}
*pResult = CDRF_SKIPDEFAULT;
return TRUE;
case(CDDS_SUBITEM | CDDS_ITEMPREPAINT):
{
if (aacontents && aacontents->bgThread_Handle || (0 == plvcd->iSubItem && 0 == plvcd->nmcd.rc.right)) break;
cloudColumnPaint.iItem = plvcd->nmcd.dwItemSpec;
cloudColumnPaint.iSubItem = plvcd->iSubItem;
if (plvcd->nmcd.hdr.idFrom == IDC_LIST_TRACKS)
{
if (plvcd->iSubItem == tracks->cloudcol)
{
cloudColumnPaint.value = tracks->cloud_cache[plvcd->nmcd.dwItemSpec];
}
else
break;
}
else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ARTIST)
{
if (plvcd->iSubItem == aacontents->GetFilterList(0)->cloudcol)
{
wchar_t buf[16] = {0};
aacontents->GetFilterList(0)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
cloudColumnPaint.value = _wtoi(buf);
}
else
break;
}
else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ALBUM)
{
if (plvcd->iSubItem == aacontents->GetFilterList(1)->cloudcol)
{
wchar_t buf[16] = {0};
aacontents->GetFilterList(1)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
cloudColumnPaint.value = _wtoi(buf);
}
else
break;
}
else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ALBUM2)
{
if (plvcd->iSubItem == aacontents->GetFilterList(2)->cloudcol)
{
wchar_t buf[16] = {0};
aacontents->GetFilterList(2)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
cloudColumnPaint.value = _wtoi(buf);
}
else
break;
}
cloudColumnPaint.prcItem = &plvcd->nmcd.rc;
cloudColumnPaint.rgbBk = plvcd->clrTextBk;
cloudColumnPaint.rgbFg = plvcd->clrText;
if (MLCloudColumn_Paint(plugin.hwndLibraryParent, &cloudColumnPaint))
{
*pResult = CDRF_SKIPDEFAULT;
return TRUE;
}
}
break;
}
return FALSE;
}
void pmp_common_UpdateButtonText(HWND hwndDlg, int _enqueuedef)
{
if (groupBtn)
{
switch(_enqueuedef)
{
case 1:
SetDlgItemTextW(hwndDlg, IDC_BUTTON_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_BUTTON_PLAY, pszTextW);
customAllowed = TRUE;
}
else
{
SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, view.play);
customAllowed = FALSE;
}
break;
}
}
}
enum
{
BPM_ECHO_WM_COMMAND=0x1, // send WM_COMMAND and return value
BPM_WM_COMMAND = 0x2, // just send WM_COMMAND
};
BOOL pmp_common_ButtonPopupMenu(HWND hwndDlg, int buttonId, HMENU menu, int flags=0)
{
RECT r;
HWND buttonHWND = GetDlgItem(hwndDlg, buttonId);
GetWindowRect(buttonHWND, &r);
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_TrackSkinnedPopup(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 pmp_common_PlayEnqueue(HWND hwndDlg, HWND from, UINT idFrom)
{
HMENU listMenu = GetSubMenu(m_context_menus2, 0);
int count = GetMenuItemCount(listMenu);
if (count > 2)
{
for (int i = 2; i < count; i++)
{
DeleteMenu(listMenu, 2, MF_BYPOSITION);
}
}
pmp_common_ButtonPopupMenu(hwndDlg, idFrom, listMenu, BPM_WM_COMMAND);
}
static BOOL restoreDone;
INT_PTR CALLBACK pmp_artistalbum_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
hi helpinfo[]={
{IDC_BUTTON_ARTMODE,IDS_AUDIO_BUTTON_TT1},
{IDC_BUTTON_VIEWMODE,IDS_AUDIO_BUTTON_TT2},
{IDC_BUTTON_COLUMNS,IDS_AUDIO_BUTTON_TT3},
};
DO_HELP();
if(hwndMediaView != hwndDlg && uMsg != WM_INITDIALOG) return 0;
if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; }
if (artistList) { BOOL a=artistList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
if (albumList) { BOOL a=albumList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
if (albumList2) { BOOL a=albumList2->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
if (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
switch (uMsg) {
case WM_INITDIALOG:
{
if (!view.play)
{
SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
}
groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 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_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
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_BUTTON_CUSTOM, pszTextW);
}
else
{
customAllowed = FALSE;
}
restoreDone = FALSE;
playmode = L"viewplaymode";
hwndMediaView = 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);
if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
header = 1;
else
header = currentViewedDevice->config->ReadInt(L"header",0);
numFilters = currentViewedDevice->config->ReadInt(L"media_numfilters",2);
if(numFilters != 3 && numFilters != 2) numFilters=2;
wchar_t filters[300] = {0}, *filtersp[3] = {0};
bool artfilter[3]={false,false,false};
for(int i = 0; i < numFilters; i++) {
filtersp[i]=&filters[i*100];
wchar_t name[20] = {0};
wsprintf(name,L"media_filter%d",i);
lstrcpyn(filtersp[i],currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters)),100);
if(!_wcsicmp(filtersp[i],L"Album Art")) artfilter[i]=true;
}
aacontents = new ArtistAlbumLists(currentViewedDevice->dev, currentViewedPlaylist, currentViewedDevice->config, filtersp,
numFilters, (currentViewedDevice->videoView ? 0 : -1), (!!currentViewedDevice->isCloudDevice));
if (!artfilter[0]) artistList = new SkinnedListView(aacontents->GetFilterList(0),IDC_LIST_ARTIST,plugin.hwndLibraryParent, hwndDlg, false);
else artistList = new AlbumArtListView(aacontents->GetFilterList(0),IDC_LIST_ARTIST,plugin.hwndLibraryParent, hwndDlg, false);
artistList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
artistList->InitializeFilterData(0, currentViewedDevice->config);
if (!artfilter[1]) albumList = new SkinnedListView(aacontents->GetFilterList(1),IDC_LIST_ALBUM,plugin.hwndLibraryParent, hwndDlg, false);
else albumList = new AlbumArtListView(aacontents->GetFilterList(1),IDC_LIST_ALBUM,plugin.hwndLibraryParent, hwndDlg, false);
albumList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
albumList->InitializeFilterData(1, currentViewedDevice->config);
if (numFilters == 3) {
if(!artfilter[2]) albumList2 = new SkinnedListView(aacontents->GetFilterList(2),IDC_LIST_ALBUM2,plugin.hwndLibraryParent, hwndDlg, false);
else albumList2 = new AlbumArtListView(aacontents->GetFilterList(2),IDC_LIST_ALBUM2,plugin.hwndLibraryParent, hwndDlg, false);
albumList2->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
albumList2->InitializeFilterData(2, currentViewedDevice->config);
}
if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
{
SetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, currentViewedDevice->config->ReadString(L"savedfilter", L""));
SetDlgItemTextW(hwndDlg, IDC_REFINE, currentViewedDevice->config->ReadString(L"savedrefinefilter", L""));
}
else
restoreDone = TRUE;
HWND list = GetDlgItem(hwndDlg, IDC_LIST_TRACKS);
// TODO need to be able to change the order of the tracks items (so cloud is in a more appropriate place)
//ListView_SetExtendedListViewStyleEx(list, LVS_EX_HEADERDRAGDROP, LVS_EX_HEADERDRAGDROP);
ListView_SetExtendedListViewStyle(list, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
MLSKINWINDOW skin = {0};
skin.hwndToSkin = list;
skin.skinType = SKINNEDWND_TYPE_LISTVIEW;
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
skin.hwndToSkin = artistList->listview.getwnd();
MLSkinWindow(plugin.hwndLibraryParent, &skin);
skin.hwndToSkin = albumList->listview.getwnd();
MLSkinWindow(plugin.hwndLibraryParent, &skin);
if (numFilters == 3) {
skin.hwndToSkin = albumList2->listview.getwnd();
MLSkinWindow(plugin.hwndLibraryParent, &skin);
}
if(!currentViewedDevice->config->ReadInt(L"media_scroll_0",0))
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,artistList->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
if(!currentViewedDevice->config->ReadInt(L"media_scroll_1",0))
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,albumList->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
if(numFilters == 3 && !currentViewedDevice->config->ReadInt(L"media_scroll_2",0))
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,albumList2->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
if (aacontents)
{
artistList->UpdateList();
tracks = aacontents->GetTracksList();
}
adiv1pos = numFilters == 3?33333:50000;
adiv3pos = numFilters == 3?66667:0;
adiv2pos = 50000;
adiv1pos = currentViewedDevice->config->ReadInt(L"adiv1pos",adiv1pos);
if(numFilters == 3) adiv3pos = currentViewedDevice->config->ReadInt(L"adiv3pos",adiv3pos);
adiv2pos = currentViewedDevice->config->ReadInt(L"adiv2pos",adiv2pos);
if(numFilters == 3 && adiv1pos>adiv3pos) {
adiv1pos=33333;
adiv3pos=66667;
}
AttachDivider(GetDlgItem(hwndDlg, IDC_VDELIM), TRUE, OnDividerMoved, IDC_VDELIM);
if(numFilters == 3) AttachDivider(GetDlgItem(hwndDlg, IDC_VDELIM2), TRUE, OnDividerMoved, IDC_VDELIM2);
AttachDivider(GetDlgItem(hwndDlg, IDC_HDELIM), FALSE, OnDividerMoved, IDC_HDELIM);
int fieldsBits = (int)currentViewedDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
if(!fieldsBits) fieldsBits = -1;
if(!(fieldsBits & SUPPORTS_ALBUMART))
SetWindowPos(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),0,0,0,0,0,0); // get rid of art mode button if we don't support albumart
FLICKERFIX ff = {0};
ff.mode = FFM_ERASEINPAINT;
skin.skinType = SKINNEDWND_TYPE_AUTO;
INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM,
IDC_BUTTON_CLEARSEARCH, IDC_BUTTON_CLEARREFINE,
IDC_BUTTON_EJECT, IDC_BUTTON_SYNC, IDC_BUTTON_AUTOFILL,
IDC_STATUS, IDC_SEARCH_TEXT, IDC_QUICKSEARCH, IDC_REFINE,
IDC_REFINE_TEXT, IDC_BUTTON_ARTMODE, IDC_BUTTON_VIEWMODE,
IDC_BUTTON_COLUMNS,
// disabled cloud parts
/*IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME, IDC_HEADER_DEVICE_BAR,
IDC_HEADER_DEVICE_SIZE, IDC_HEADER_DEVICE_TRANSFER,*/
};
for (int i = 0; i < ARRAYSIZE(ffcl); i++)
{
ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
if (IsWindow(ff.hwnd))
{
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
// skip the mode buttons
if (i < 13)
{
if (i < 3)
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn ? SWBS_SPLITBUTTON : 0);
else
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
skin.hwndToSkin = ff.hwnd;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
}
}
}
if (0 != currentViewedDevice->dev->extraActions(DEVICE_SYNC_UNSUPPORTED,0,0,0))
EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC), FALSE);
skin.hwndToSkin = hwndDlg;
skin.skinType = SKINNEDWND_TYPE_AUTO;
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
// do this now to get the cloud columns correctly known (doesn't work correctly if done before the skinning is setup)
MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_TRACKS)), tracks->cloudcol);
MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ARTIST)), artistList->contents->cloudcol);
MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ALBUM)), albumList->contents->cloudcol);
if (numFilters == 3) MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ALBUM2)), albumList2->contents->cloudcol);
g_displayrefine = !!(gen_mlconfig->ReadInt(L"audiorefine", 0));
adiv1_nodraw=0;
adiv3_nodraw=0;
m_nodrawtopborders=0;
PostMessage(hwndDlg, WM_DISPLAYCHANGE, 0, 0);
break;
}
case WM_DISPLAYCHANGE:
{
int (*wad_getColor)(int idx);
*(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
ARGB32 fc = (wad_getColor?wad_getColor(WADLG_BUTTONFG):RGB(0xFF,0xFF,0xFF)) & 0x00FFFFFF;
SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_ARTMODE, MAKEINTRESOURCE(IDR_TOOL_ALBUMART_ICON),fc);
SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_VIEWMODE, MAKEINTRESOURCE(IDR_TOOL_VIEWMODE_ICON),fc);
SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_COLUMNS, MAKEINTRESOURCE(IDR_TOOL_COLUMNS_ICON),fc);
UpdateWindow(hwndDlg);
LayoutWindows(hwndDlg, TRUE, 0);
}
break;
case WM_DROPFILES:
return currentViewedDevice->TransferFromDrop((HDROP)wParam);
case WM_DESTROY:
if (aacontents) aacontents->bgQuery_Stop();
currentViewedDevice->config->WriteInt(L"adiv1pos",adiv1pos);
if(numFilters == 3) currentViewedDevice->config->WriteInt(L"adiv3pos",adiv3pos);
currentViewedDevice->config->WriteInt(L"adiv2pos",adiv2pos);
tracks=NULL;
hwndMediaView=NULL;
if (albumList) delete albumList; albumList=NULL;
if (artistList) delete artistList; artistList=NULL;
if (albumList2) delete albumList2; albumList2=NULL;
if (aacontents) delete aacontents; aacontents=NULL;
{
SkinBitmap *s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),GWLP_USERDATA);
DeleteSkinBitmap(s);
s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),GWLP_USERDATA);
DeleteSkinBitmap(s);
s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),GWLP_USERDATA);
DeleteSkinBitmap(s);
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
if (di->CtlType == ODT_BUTTON) {
if(di->CtlID == IDC_BUTTON_ARTMODE || di->CtlID == IDC_BUTTON_VIEWMODE || di->CtlID == IDC_BUTTON_COLUMNS)
{ // draw the toolbar buttons!
SkinBitmap* hbm = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,di->CtlID),GWLP_USERDATA);
if(hbm && di->rcItem.left != di->rcItem.right && di->rcItem.top != di->rcItem.bottom) {
DCCanvas dc(di->hDC);
if (di->itemState & ODS_SELECTED) hbm->blitAlpha(&dc,di->rcItem.left+6,di->rcItem.top+5);
else hbm->blitAlpha(&dc,di->rcItem.left+4,di->rcItem.top+3);
}
}
}
}
break;
case WM_SETCURSOR:
case WM_LBUTTONDOWN:
{
static INT id[] = { IDC_VDELIM, IDC_HDELIM, IDC_VDELIM2 };
RECT rw;
POINT pt;
GetCursorPos(&pt);
for (INT i = 0; i < sizeof(id)/sizeof(INT); i++)
{
HWND hwndDiv = GetDlgItem(hwndDlg, id[i]);
if (!hwndDiv) continue;
GetWindowRect(hwndDiv, &rw);
if (PtInRect(&rw, pt))
{
if (WM_SETCURSOR == uMsg)
{
SetCursor(LoadCursor(NULL, (IDC_VDELIM == id[i] || IDC_VDELIM2 == id[i]) ? IDC_SIZEWE : IDC_SIZENS));
return TRUE;
}
else
{
SendMessage(hwndDiv, uMsg, wParam, MAKELPARAM(pt.x - rw.left, pt.y - rw.top));
return TRUE;
}
}
}
}
break;
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), 0);
}
return TRUE;
case WM_PAINT:
{
int tab[] = {(m_nodrawtopborders==2)?0:(IDC_LIST_TRACKS|DCW_SUNKENBORDER),
IDC_QUICKSEARCH|DCW_SUNKENBORDER,
(refineHidden!=0)?0:(IDC_REFINE|DCW_SUNKENBORDER),
IDC_HDELIM|DCW_DIVIDER,
(!header?IDC_HDELIM2|DCW_DIVIDER:0),
IDC_VDELIM|DCW_DIVIDER,
numFilters == 3?IDC_VDELIM2|DCW_DIVIDER:0,
adiv1_nodraw==1?0:(IDC_LIST_ARTIST|DCW_SUNKENBORDER),
(adiv1_nodraw==2 || adiv3_nodraw==1)?0:(IDC_LIST_ALBUM|DCW_SUNKENBORDER),
(numFilters != 3 || adiv3_nodraw==2)?0:(IDC_LIST_ALBUM2|DCW_SUNKENBORDER)};
int size = sizeof(tab) / sizeof(tab[0]);
// do this to prevent drawing parts when the views are collapsed
if (m_nodrawtopborders==1) size -= 6;
if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
}
return TRUE;
case WM_ERASEBKGND:
return 1;
case WM_USER:
{
if (aacontents && aacontents->bgThread_Handle) break;
if (aacontents)
{
SkinnedListView * lists[3]={artistList,albumList,albumList2};
aacontents->SelectionChanged(wParam==IDC_LIST_ARTIST?0:(wParam==IDC_LIST_ALBUM?1:2),lists);
}
noSearchTimer=true;
SetDlgItemText(hwndDlg,IDC_REFINE,L"");
noSearchTimer=false;
UpdateStatus(hwndDlg);
wParam=0;
}
// run through
case WM_USER+2:
if (tracksList) tracksList->UpdateList(wParam==1);
break;
case WM_USER+1:
if (tracks) tracks->RemoveTrack((songid_t)wParam);
if (aacontents) aacontents->RemoveTrack((songid_t)wParam);
break;
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if(l->idFrom==IDC_LIST_ARTIST || l->idFrom==IDC_LIST_ALBUM || l->idFrom==IDC_LIST_ALBUM2)
{
switch(l->code) {
case LVN_ITEMCHANGED:
{
LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam;
if ((lv->uNewState ^ lv->uOldState) & LVIS_SELECTED) {
PostMessage(hwndDlg,WM_USER,l->idFrom,0);
}
}
break;
case NM_RETURN:
case NM_DBLCLK: // play some songs!
{
C_ItemList * items = getSelectedItems(true);
currentViewedDevice->PlayTracks(items, 0, (!(GetAsyncKeyState(VK_SHIFT)&0x8000) ? (enqueuedef == 1) : (enqueuedef != 1)), false);
delete items;
break;
}
case LVN_KEYDOWN:
switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
case VK_DELETE:
{
if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_DELETE);
}
}
break;
case 0x43: //C
if(GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_COPYTOLIBRARY);
}
break;
}
break;
}
}
else if(l->idFrom == IDC_LIST_TRACKS)
{
switch(l->code) {
case LVN_KEYDOWN:
switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
case VK_DELETE:
{
if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_DELETE);
}
}
break;
case 0x45: //E
bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
C_ItemList * items = getSelectedItems();
editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
delete items;
}
break;
}
break;
}
}
}
break;
case WM_APP + 3: // send by bgthread
if (wParam == 0x69)
{
if (aacontents)
{
aacontents->bgQuery_Stop();
tracks = aacontents->GetTracksList();
if (artistList) artistList->UpdateList();
if (albumList) albumList->UpdateList();
if (albumList2) albumList2->UpdateList();
if (tracksList) tracksList->UpdateList();
UpdateStatus(hwndDlg, true);
}
}
break;
case WM_APP + 104:
{
pmp_common_UpdateButtonText(hwndDlg, wParam);
LayoutWindows(hwndDlg, TRUE, 0);
return 0;
}
case WM_TIMER:
switch(wParam) {
case 123:
{
if (aacontents && aacontents->bgThread_Handle)
{
HWND hwndList;
hwndList = tracksList->listview.getwnd();
if (1 != ListView_GetItemCount(hwndList)) ListView_SetItemCountEx(hwndList, 1, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
ListView_RedrawItems(hwndList, 0, 0);
}
}
break;
case 400:
KillTimer(hwndDlg,400);
currentViewedDevice->config->WriteInt(L"adiv1pos",adiv1pos);
if(numFilters == 3) currentViewedDevice->config->WriteInt(L"adiv3pos",adiv3pos);
currentViewedDevice->config->WriteInt(L"adiv2pos",adiv2pos);
break;
case 500:
{
KillTimer(hwndDlg,500);
wchar_t buf[256]=L"";
GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf)/sizeof(wchar_t));
noSearchTimer=true;
if (restoreDone) SetDlgItemText(hwndDlg,IDC_REFINE,L"");
noSearchTimer=false;
aacontents->SetSearch(buf, (!!currentViewedDevice->isCloudDevice));
if (!aacontents->bgThread_Handle)
{
if (artistList) artistList->UpdateList();
if (albumList) albumList->UpdateList();
if (albumList2) albumList2->UpdateList();
if (tracksList) tracksList->UpdateList();
UpdateStatus(hwndDlg);
}
if (!restoreDone)
{
restoreDone = TRUE;
KillTimer(hwndDlg,501);
SetTimer(hwndDlg,501,250,NULL);
}
}
break;
case 501:
{
KillTimer(hwndDlg,501);
wchar_t buf[256]=L"";
GetDlgItemText(hwndDlg,IDC_REFINE,buf,sizeof(buf)/sizeof(wchar_t));
aacontents->SetRefine(buf, (!!currentViewedDevice->isCloudDevice));
if (!aacontents->bgThread_Handle)
{
if (tracksList) tracksList->UpdateList();
UpdateStatus(hwndDlg);
}
}
break;
}
break;
case WM_MOUSEMOVE:
if(wParam==MK_LBUTTON) {
if(GetCapture() == hwndDlg) ReleaseCapture();
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_BUTTON_ARTMODE:
{
int changed=0;
for(int i=0; i<3; i++) {
wchar_t name[20] = {0};
wsprintf(name,L"media_filter%d",i);
wchar_t * str = currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters));
if(!_wcsicmp(str,L"Album")) { currentViewedDevice->config->WriteString(name,L"Album Art"); changed=1; }
else if(!_wcsicmp(str,L"Album Art")) { currentViewedDevice->config->WriteString(name,L"Album"); changed=1; }
}
if (changed) PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
}
break;
case IDC_BUTTON_VIEWMODE:
{
struct {
const wchar_t *name;
int numfilters;
wchar_t* f[3];
int requiredFields;
} presets[] = {
{0,2,{L"Artist",L"Album"},0},
{0,2,{L"Artist",L"Album Art"},SUPPORTS_ALBUMART},
{0,2,{L"Album Artist",L"Album"},SUPPORTS_ALBUMARTIST},
{0,2,{L"Album Artist",L"Album Art"},SUPPORTS_ALBUMARTIST | SUPPORTS_ALBUMART},
{0,3,{L"Genre",L"Artist",L"Album"},SUPPORTS_GENRE | SUPPORTS_ALBUMART},
{0,2,{L"Genre",L"Album Art"},SUPPORTS_GENRE},
{0,3,{L"Year",L"Artist",L"Album"},SUPPORTS_YEAR},
{0,2,{L"Composer",L"Album"},SUPPORTS_COMPOSER},
{0,3,{L"Publisher",L"Artist",L"Album"},SUPPORTS_PUBLISHER},
};
HMENU menu = CreatePopupMenu();
int fieldsBits = (int)currentViewedDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
if(!fieldsBits) fieldsBits = -1;
bool checked=false;
wchar_t filters[300] = {0};
wchar_t *filtersp[3] = {0};
for(int i=0; i<numFilters; i++) {
filtersp[i]=&filters[i*100];
wchar_t name[20] = {0};
wsprintf(name,L"media_filter%d",i);
lstrcpyn(filtersp[i],currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters)),100);
}
for(int i=0; i < sizeof(presets)/sizeof(presets[0]); i++) {
if(!presets[i].requiredFields || (presets[i].requiredFields & fieldsBits) == presets[i].requiredFields) {
wchar_t buf[350] = {0};
if(!presets[i].name) {
wchar_t a[100] = {0}, b[100] = {0}, c[100] = {0};
localizeFilter(presets[i].f[0],a,100);
localizeFilter(presets[i].f[1],b,100);
if(presets[i].numfilters == 3) localizeFilter(presets[i].f[2],c,100);
if(presets[i].numfilters == 3) wsprintf(buf,L"%s/%s/%s",a,b,c);
else wsprintf(buf,L"%s/%s",a,b);
}
AppendMenu(menu,MF_STRING,i+1,presets[i].name?presets[i].name:buf);
if(numFilters == presets[i].numfilters && !_wcsicmp(presets[i].f[0],filtersp[0]) && !_wcsicmp(presets[i].f[1],filtersp[1]) && (numFilters == 2 || !_wcsicmp(presets[i].f[2],filtersp[2])))
{ // this is our view...
CheckMenuItem(menu,i+1,MF_CHECKED);
checked=true;
}
}
}
AppendMenu(menu,MF_STRING,0x4000,WASABI_API_LNGSTRINGW(IDS_OTHER2));
if(!checked)
CheckMenuItem(menu,0x4000,MF_CHECKED);
RECT rc;
GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),&rc);
int r = Menu_TrackSkinnedPopup(menu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,rc.left,rc.bottom,hwndDlg,NULL);
DestroyMenu(menu);
if(r==0) break;
else if(r == 0x4000) {
extern int g_prefs_openpage;
g_prefs_openpage = (!currentViewedDevice->isCloudDevice ? 4 : 0);
SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&currentViewedDevice->devPrefsPage,IPC_OPENPREFSTOPAGE);
extern HWND m_hwndTab;
if (IsWindow(m_hwndTab))
{
TabCtrl_SetCurSel(m_hwndTab, g_prefs_openpage);
extern HWND OnSelChanged(HWND hwndDlg, HWND external = NULL, DeviceView *dev = NULL);
OnSelChanged(GetParent(m_hwndTab));
}
}
else {
r--;
for(int j=0; j<presets[r].numfilters; j++) {
wchar_t name[20] = {0};
wsprintf(name,L"media_filter%d",j);
currentViewedDevice->config->WriteString(name,presets[r].f[j]);
}
currentViewedDevice->config->WriteInt(L"media_numfilters",presets[r].numfilters);
PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
}
}
break;
case IDC_BUTTON_COLUMNS:
{
HMENU themenu1 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
HMENU themenu2 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
HMENU themenu3 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
HMENU themenu4 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
HMENU menu = CreatePopupMenu();
MENUITEMINFO m={sizeof(m),MIIM_TYPE | MIIM_ID | MIIM_SUBMENU,MFT_STRING,0};
wchar_t a[100] = {0}, b[100] = {0}, c[100] = {0};
localizeFilter(currentViewedDevice->config->ReadString(L"media_filter0",GetDefFilter(0,numFilters)),a,100);
localizeFilter(currentViewedDevice->config->ReadString(L"media_filter1",GetDefFilter(1,numFilters)),b,100);
localizeFilter(currentViewedDevice->config->ReadString(L"media_filter2",GetDefFilter(2,numFilters)),c,100);
wchar_t * d = WASABI_API_LNGSTRINGW(IDS_TRACKS);
m.wID = 0;
m.dwTypeData = a;
m.hSubMenu = artistList->GetMenu(true,0,currentViewedDevice->config,themenu1);
InsertMenuItem(menu,0,FALSE,&m);
m.wID = 1;
m.dwTypeData = b;
m.hSubMenu = albumList->GetMenu(true,1,currentViewedDevice->config,themenu2);
InsertMenuItem(menu,1,FALSE,&m);
if(numFilters == 3) {
m.wID = 2;
m.dwTypeData = c;
m.hSubMenu = albumList2->GetMenu(true,2,currentViewedDevice->config,themenu3);
InsertMenuItem(menu,2,FALSE,&m);
}
m.wID = 3;
m.dwTypeData = d;
m.hSubMenu = tracksList->GetMenu(false,0,currentViewedDevice->config,themenu4);
InsertMenuItem(menu,3,FALSE,&m);
RECT rc;
GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),&rc);
int r = Menu_TrackSkinnedPopup(menu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,rc.left,rc.bottom,hwndDlg,NULL);
artistList->ProcessMenuResult(r,true,0,currentViewedDevice->config,hwndDlg);
albumList->ProcessMenuResult(r,true,1,currentViewedDevice->config,hwndDlg);
if(numFilters == 3) albumList2->ProcessMenuResult(r,true,2,currentViewedDevice->config,hwndDlg);
tracksList->ProcessMenuResult(r,false,0,currentViewedDevice->config,hwndDlg);
DestroyMenu(menu);
DestroyMenu(themenu1);
DestroyMenu(themenu2);
DestroyMenu(themenu3);
DestroyMenu(themenu4);
}
break;
case IDC_QUICKSEARCH:
if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
KillTimer(hwndDlg, 500);
SetTimer(hwndDlg, 500, 350, NULL);
HWND hwndList = artistList->listview.getwnd();
if (IsWindow(hwndList))
{
ListView_SetItemCountEx(hwndList, 0, 0);
ListView_RedrawItems(hwndList, 0, 0);
}
hwndList = albumList->listview.getwnd();
if (IsWindow(hwndList))
{
ListView_SetItemCountEx(hwndList, 0, 0);
ListView_RedrawItems(hwndList, 0, 0);
}
if (numFilters == 3)
{
hwndList = albumList2->listview.getwnd();
if (IsWindow(hwndList))
{
ListView_SetItemCountEx(hwndList, 0, 0);
ListView_RedrawItems(hwndList, 0, 0);
}
}
}
break;
case IDC_REFINE:
if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
KillTimer(hwndDlg,501);
SetTimer(hwndDlg,501,250,NULL);
}
break;
case IDC_BUTTON_CLEARSEARCH:
{
SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,L"");
break;
}
case IDC_BUTTON_CLEARREFINE:
SetDlgItemText(hwndDlg,IDC_REFINE,L"");
break;
case IDC_HEADER_DEVICE_TRANSFER:
{
if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC)))
{
MessageBox(hwndDlg, L"Transferring files from this device to another is not currently supported.",
L"Cloud Transfer Not Supported", MB_ICONINFORMATION);
break;
}
}
case IDC_BUTTON_SYNC:
if (!currentViewedDevice->isCloudDevice)
currentViewedDevice->Sync();
else
currentViewedDevice->CloudSync();
break;
case IDC_BUTTON_AUTOFILL:
currentViewedDevice->Autofill();
break;
case IDC_SEARCH_TEXT:
if (HIWORD(wParam) == STN_DBLCLK)
{
// TODO decide what to do for the 'all_sources'
if (currentViewedDevice->isCloudDevice &&
lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
{
header = !header;
currentViewedDevice->config->WriteInt(L"header",header);
LayoutWindows(hwndMediaView, TRUE, 0);
UpdateStatus(hwndDlg, true);
ShowWindow(hwndDlg, 0);
ShowWindow(hwndDlg, 1);
}
}
break;
}
break;
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;
}
return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
}
static void getStars(int stars, wchar_t * buf, int buflen) {
wchar_t * r=L"";
switch(stars) {
case 1: r=L"\u2605"; break;
case 2: r=L"\u2605\u2605"; break;
case 3: r=L"\u2605\u2605\u2605"; break;
case 4: r=L"\u2605\u2605\u2605\u2605"; break;
case 5: r=L"\u2605\u2605\u2605\u2605\u2605"; break;
}
lstrcpyn(buf,r,buflen);
}
__inline void TimetToFileTime(time_t t, LPFILETIME pft)
{
LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD) ll;
pft->dwHighDateTime = ll >>32;
}
void timeToString(__time64_t time, wchar_t * buf, int buflen) {
if((__int64)time<=0) { lstrcpyn(buf,L"",buflen); return; }
FILETIME ft = {0};
SYSTEMTIME st = {0};
TimetToFileTime(time, &ft);
FileTimeToSystemTime(&ft, &st);
int adjust = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buf, buflen);
buf[adjust-1] = ' ';
GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &st, NULL, &buf[adjust], buflen - adjust);
}
extern void GetInfoString(wchar_t * buf, Device * dev, int numTracks, __int64 totalSize, int totalPlayLength, int cloud);
class PlaylistContents : public PrimaryListContents {
public:
int playlistId;
Device * dev;
PlaylistContents(int playlistId, Device * dev) {
this->playlistId = playlistId;
this->dev = dev;
int fieldsBits = (int)dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
if(!fieldsBits) fieldsBits = -1;
C_Config *c = currentViewedDevice->config;
this->config = c;
fields.Add(new ListField(-1,20, WASABI_API_LNGSTRINGW(IDS_NUMBER),c));
if(fieldsBits & SUPPORTS_ARTIST) fields.Add(new ListField(1000, 200,WASABI_API_LNGSTRINGW(IDS_ARTIST),c));
if(fieldsBits & SUPPORTS_TITLE) fields.Add(new ListField(1001, 200,WASABI_API_LNGSTRINGW(IDS_TITLE),c));
if(fieldsBits & SUPPORTS_ALBUM) fields.Add(new ListField(1002, 200,WASABI_API_LNGSTRINGW(IDS_ALBUM),c));
if(fieldsBits & SUPPORTS_LENGTH) fields.Add(new ListField(1003, 64, WASABI_API_LNGSTRINGW(IDS_LENGTH),c));
if(fieldsBits & SUPPORTS_TRACKNUM) fields.Add(new ListField(1004, 50, WASABI_API_LNGSTRINGW(IDS_TRACK_NUMBER),c));
if(fieldsBits & SUPPORTS_DISCNUM) fields.Add(new ListField(1005, 38, WASABI_API_LNGSTRINGW(IDS_DISC),c));
if(fieldsBits & SUPPORTS_GENRE) fields.Add(new ListField(1006, 100,WASABI_API_LNGSTRINGW(IDS_GENRE),c));
if(fieldsBits & SUPPORTS_YEAR) fields.Add(new ListField(1007, 38, WASABI_API_LNGSTRINGW(IDS_YEAR),c));
if(fieldsBits & SUPPORTS_BITRATE) fields.Add(new ListField(1008, 45, WASABI_API_LNGSTRINGW(IDS_BITRATE),c));
if(fieldsBits & SUPPORTS_SIZE) fields.Add(new ListField(1009, 90, WASABI_API_LNGSTRINGW(IDS_SIZE),c));
if(fieldsBits & SUPPORTS_PLAYCOUNT) fields.Add(new ListField(1010, 64, WASABI_API_LNGSTRINGW(IDS_PLAY_COUNT),c));
if(fieldsBits & SUPPORTS_RATING) fields.Add(new ListField(1011, 64, WASABI_API_LNGSTRINGW(IDS_RATING),c));
if(fieldsBits & SUPPORTS_LASTPLAYED) fields.Add(new ListField(1012, 100,WASABI_API_LNGSTRINGW(IDS_LAST_PLAYED),c));
if(fieldsBits & SUPPORTS_ALBUMARTIST) fields.Add(new ListField(1013, 200,WASABI_API_LNGSTRINGW(IDS_ALBUM_ARTIST),c,true));
if(fieldsBits & SUPPORTS_PUBLISHER) fields.Add(new ListField(1014, 200,WASABI_API_LNGSTRINGW(IDS_PUBLISHER),c,true));
if(fieldsBits & SUPPORTS_COMPOSER) fields.Add(new ListField(1015, 200,WASABI_API_LNGSTRINGW(IDS_COMPOSER),c,true));
if(fieldsBits & SUPPORTS_MIMETYPE) fields.Add(new ListField(1016, 100,WASABI_API_LNGSTRINGW(IDS_MIME_TYPE),c,true));
if(fieldsBits & SUPPORTS_DATEADDED) fields.Add(new ListField(1017, 100,WASABI_API_LNGSTRINGW(IDS_DATE_ADDED),c,true));
this->SortColumns();
}
//virtual ~PlaylistContents() { }
virtual int GetNumColumns() { return fields.GetSize(); }
virtual int GetNumRows() { return dev->getPlaylistLength(playlistId); }
virtual int GetColumnWidth(int num) {
if(num >=0 && num < fields.GetSize())
return ((ListField *)fields.Get(num))->width;
return 0;
}
virtual wchar_t * GetColumnTitle(int num) {
if(num >=0 && num < fields.GetSize())
return ((ListField *)fields.Get(num))->name;
return L"";
}
virtual void GetCellText(int row, int col, wchar_t * buf, int buflen) {
if(col >=0 && col < fields.GetSize()) col = ((ListField *)fields.Get(col))->field;
if(col != -1) col -= 1000;
songid_t s = dev->getPlaylistTrack(playlistId,row);
buf[0]=0;
switch(col) {
case -1: wsprintf(buf,L"%d",row+1); return;
case 0: dev->getTrackArtist(s,buf,buflen); return;
case 1: dev->getTrackTitle(s,buf,buflen); return;
case 2: dev->getTrackAlbum(s,buf,buflen); return;
case 3: { int l=dev->getTrackLength(s); if (l>=0) wsprintf(buf,L"%d:%02d",l/1000/60,(l/1000)%60); return; }
case 4: { int d = dev->getTrackTrackNum(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
case 5: { int d = dev->getTrackDiscNum(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
case 6: dev->getTrackGenre(s,buf,buflen); return;
case 7: { int d = dev->getTrackYear(s); if(d>0) wsprintf(buf,L"%d",d); return; }
case 8: { int d = dev->getTrackBitrate(s); if(d>0) wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_KBPS),d); return; }
case 9: WASABI_API_LNG->FormattedSizeString(buf, buflen, dev->getTrackSize(s)); return;
case 10: { int d = dev->getTrackPlayCount(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
case 11: getStars(dev->getTrackRating(s),buf,buflen); return;
case 12: timeToString(dev->getTrackLastPlayed(s),buf,buflen); return;
case 13: dev->getTrackAlbumArtist(s,buf,buflen); return;
case 14: dev->getTrackPublisher(s,buf,buflen); return;
case 15: dev->getTrackComposer(s,buf,buflen); return;
}
}
virtual void GetInfoString(wchar_t * buf) {
__int64 totalSize=0;
int totalPlayLength=0;
int millis=0;
int l = dev->getPlaylistLength(playlistId);
for(int i=0; i < l; i++) {
songid_t s = dev->getPlaylistTrack(playlistId,i);
totalSize += (__int64)dev->getTrackSize(s);
int len=dev->getTrackLength(s);
totalPlayLength += len/1000;
millis += len%1000;
}
totalPlayLength += millis/1000;
::GetInfoString(buf, dev, l, totalSize, totalPlayLength, 0);
}
virtual songid_t GetTrack(int pos) { return dev->getPlaylistTrack(playlistId,pos); }
virtual void ColumnResize(int col, int newWidth) {
if(col >=0 && col < fields.GetSize()) {
ListField * lf = (ListField *)fields.Get(col);
lf->width = newWidth;
wchar_t buf[100] = {0};
wsprintf(buf,L"colWidth_%d",lf->field);
currentViewedDevice->config->WriteInt(buf,newWidth);
}
}
};
static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
SetDlgItemText(hwndDlg,IDC_EDIT,currentViewedDevice->config->ReadString(L"plfind",L""));
if (FALSE != CenterWindow(hwndDlg, (HWND)lParam))
SendMessage(hwndDlg, DM_REPOSITION, 0, 0L);
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDOK:
{
wchar_t buf[256] = {0};
GetDlgItemText(hwndDlg,IDC_EDIT,buf,sizeof(buf)/sizeof(wchar_t));
buf[255]=0;
currentViewedDevice->config->WriteString(L"plfind",buf);
EndDialog(hwndDlg,(INT_PTR)_wcsdup(buf));
}
break;
case IDCANCEL:
EndDialog(hwndDlg,0);
break;
}
break;
}
return 0;
}
extern C_ItemList * FilterSongs(const wchar_t * filter, const C_ItemList * songs, Device * dev, bool cloud);
static int m_pldrag;
INT_PTR CALLBACK pmp_playlist_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
static bool pldrag_changed;
if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; }
if (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
switch (uMsg) {
case WM_INITDIALOG:
{
if (!view.play)
{
SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
}
groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 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_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
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_BUTTON_CUSTOM, pszTextW);
}
else
{
customAllowed = FALSE;
}
playmode = L"plplaymode";
hwndMediaView = hwndDlg;
pldrag_changed=false;
*(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);
tracks = new PlaylistContents(currentViewedPlaylist,currentViewedDevice->dev);
m_pldrag=-1;
{
MLSKINWINDOW skin = {0};
skin.skinType = SKINNEDWND_TYPE_AUTO;
FLICKERFIX ff = {0};
ff.mode = FFM_ERASEINPAINT;
INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM, IDC_BUTTON_SORT, IDC_BUTTON_EJECT, IDC_STATUS};
for (int i = 0; i < sizeof(ffcl) / sizeof(INT); i++)
{
ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
if (IsWindow(ff.hwnd))
{
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn && (i < 3) ? SWBS_SPLITBUTTON : 0);
skin.hwndToSkin = ff.hwnd;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
}
}
}
}
break;
case WM_DESTROY:
if(tracks) delete tracks; tracks=0;
break;
case WM_DROPFILES:
return currentViewedDevice->TransferFromDrop((HDROP)wParam, currentViewedPlaylist);
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if(l->idFrom==IDC_LIST_TRACKS)
switch(l->code) {
case LVN_KEYDOWN:
switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
case 0x46: //F
{
if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
wchar_t * findstr = (wchar_t*)WASABI_API_DIALOGBOXPARAMW(IDD_FIND,hwndDlg,find_dlgproc, (LPARAM)hwndDlg);
if(!findstr) break;
C_ItemList songs;
int l = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist);
int i;
for(i=0; i<l; i++) songs.Add((void*)currentViewedDevice->dev->getPlaylistTrack(currentViewedPlaylist,i));
C_ItemList * found = FilterSongs(findstr,&songs,currentViewedDevice->dev,0);
free(findstr);
int j=0;
HWND wnd = tracksList->listview.getwnd();
for(i=0; i<l; i++) {
if(found->Get(j) == songs.Get(i)) {
ListView_SetItemState(wnd,i,LVIS_SELECTED,LVIS_SELECTED);
if(j++ == 0) ListView_EnsureVisible(wnd,i,TRUE);
}
else ListView_SetItemState(wnd,i,0,LVIS_SELECTED);
}
delete found;
}
}
break;
case VK_DELETE:
if(!GetAsyncKeyState(VK_CONTROL)){
if(!GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_DELETE);
}
else{
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(ID_TRACKSLIST_REMOVEFROMPLAYLIST,0),0);
}
}
break;
case 0x43: //C
if(GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_COPYTOLIBRARY);
}
break;
}
}
}
break;
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), 2);
}
return TRUE;
case WM_DISPLAYCHANGE:
{
UpdateWindow(hwndDlg);
LayoutWindows(hwndDlg, TRUE, 2);
}
break;
case WM_APP + 104:
{
pmp_common_UpdateButtonText(hwndDlg, wParam);
LayoutWindows(hwndDlg, TRUE, 2);
return 0;
}
case WM_PAINT:
{
int tab[] = {IDC_LIST_TRACKS|DCW_SUNKENBORDER};
int size = sizeof(tab) / sizeof(tab[0]);
if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
}
break;
case WM_LBUTTONDOWN:
m_pldrag=-1;
//m_pldrag = tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
break;
case WM_LBUTTONUP:
m_pldrag=-1;
if(GetCapture() == hwndDlg) ReleaseCapture();
if(pldrag_changed) { currentViewedDevice->DevicePropertiesChanges(); pldrag_changed=false;}
break;
case WM_MOUSEMOVE:
if(wParam==MK_LBUTTON) {
if(m_pldrag==-1) { m_pldrag=tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); break; } // m_pldrag=GET_Y_LPARAM(lParam);
int p = tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); // new point
if(p==-1) break;
//work out how much to move and how
int h=1; //height of one item
HWND listWnd = tracksList->listview.getwnd();
Device * dev = currentViewedDevice->dev;
if(p - m_pldrag >= h) {
//moved down
int start=-1,end=-1;
int i;
int l = dev->getPlaylistLength(currentViewedPlaylist);
for(i=l-1; i>=0; i--) if(ListView_GetItemState(listWnd, i, LVIS_SELECTED) == LVIS_SELECTED) {
if(i == l-1) break;
if(end == -1) end = i+1;
start = i;
//change playlist
dev->playlistSwapItems(currentViewedPlaylist,i,i+1);
pldrag_changed=true;
//set selection correctly
ListView_SetItemState(listWnd,i,0,LVIS_SELECTED);
ListView_SetItemState(listWnd,i+1,LVIS_SELECTED,LVIS_SELECTED);
if(ListView_GetItemState(listWnd, i, LVIS_FOCUSED)==LVIS_FOCUSED) {
ListView_SetItemState(listWnd,i,0,LVIS_FOCUSED);
ListView_SetItemState(listWnd,i+1,LVIS_FOCUSED,LVIS_FOCUSED);
}
}
if(start != -1) {
ListView_RedrawItems(listWnd,start,end);
m_pldrag += h;
}
}
else if(m_pldrag - p >= h){
//moved up
int start=-1,end=-1;
int i;
int l = dev->getPlaylistLength(currentViewedPlaylist);
for(i=0; i<l; i++) if(ListView_GetItemState(listWnd, i, LVIS_SELECTED) == LVIS_SELECTED) {
if(i == 0) break;
if(start == -1) start = i-1;
end = i;
//change playlist
dev->playlistSwapItems(currentViewedPlaylist,i,i-1);
pldrag_changed=true;
//set selection correctly
ListView_SetItemState(listWnd,i,0,LVIS_SELECTED);
ListView_SetItemState(listWnd,i-1,LVIS_SELECTED,LVIS_SELECTED);
if(ListView_GetItemState(listWnd, i, LVIS_FOCUSED)==LVIS_FOCUSED) {
ListView_SetItemState(listWnd,i,0,LVIS_FOCUSED);
ListView_SetItemState(listWnd,i-1,LVIS_FOCUSED,LVIS_FOCUSED);
}
}
if(start != -1) {
ListView_RedrawItems(listWnd,start,end);
m_pldrag -= h;
}
}
return 0;
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case ID_TRACKSLIST_REMOVEFROMPLAYLIST:
{
int l = tracksList->listview.GetCount();
while(l-- > 0) if(tracksList->listview.GetSelected(l))
currentViewedDevice->dev->removeTrackFromPlaylist(currentViewedPlaylist,l);
tracksList->UpdateList();
currentViewedDevice->DevicePropertiesChanges();
}
break;
case IDC_BUTTON_SORT:
{
HMENU menu = GetSubMenu(m_context_menus,5);
POINT p;
GetCursorPos(&p);
int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY, p.x, p.y, hwndDlg, NULL);
if(r >= ID_SORTPLAYLIST_ARTIST && r <= ID_SORTPLAYLIST_LASTPLAYED) {
currentViewedDevice->dev->sortPlaylist(currentViewedPlaylist,r - ID_SORTPLAYLIST_ARTIST);
}
else if(r == ID_SORTPLAYLIST_RANDOMIZE) {
int elems = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist);
if (elems > 1) {
for (int p = 0; p < elems; p ++) {
int np=genrand_int31()%elems;
if (p != np) // swap pp and np
currentViewedDevice->dev->playlistSwapItems(currentViewedPlaylist,p,np);
}
}
}
else if(r == ID_SORTPLAYLIST_REVERSEPLAYLIST) {
int i=0;
int j = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist) - 1;
while(i < j)
currentViewedDevice->dev->playlistSwapItems(currentViewedPlaylist,i++,j--);
}
if(r > 0) {
tracksList->UpdateList(true);
currentViewedDevice->DevicePropertiesChanges();
}
}
break;
}
break; // WM_COMMAND
}
return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
}
INT_PTR CALLBACK pmp_video_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 (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
switch (uMsg) {
case WM_INITDIALOG:
{
if (!view.play)
{
SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
}
groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 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_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
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_BUTTON_CUSTOM, pszTextW);
}
else
{
customAllowed = FALSE;
}
playmode = L"viewplaymode";
hwndMediaView = 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);
if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
header = 1;
else
header = currentViewedDevice->config->ReadInt(L"header",0);
HWND list = GetDlgItem(hwndDlg, IDC_LIST_TRACKS);
// TODO need to be able to change the order of the tracks items (so cloud is in a more appropriate place)
//ListView_SetExtendedListViewStyleEx(list, LVS_EX_HEADERDRAGDROP, LVS_EX_HEADERDRAGDROP);
ListView_SetExtendedListViewStyle(list, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
{
SetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, currentViewedDevice->config->ReadString(L"savedfilter", L""));
}
// depending on how this is called, it will either do a video only view or will be re-purposed as a 'simple' view
aacontents = new ArtistAlbumLists(currentViewedDevice->dev, currentViewedPlaylist, currentViewedDevice->config,
NULL, 0, (lParam ? -1 : (currentViewedDevice->videoView ? 1 : -1)), (lParam == 1));
if (aacontents)
{
tracks = aacontents->GetTracksList();
}
MLSKINWINDOW skin = {0};
skin.hwndToSkin = list;
skin.skinType = SKINNEDWND_TYPE_LISTVIEW;
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(list), tracks->cloudcol);
FLICKERFIX ff = {0};
ff.mode = FFM_ERASEINPAINT;
INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM,
IDC_BUTTON_CLEARSEARCH, IDC_BUTTON_CLEARREFINE,
IDC_BUTTON_EJECT, IDC_BUTTON_SYNC, IDC_BUTTON_AUTOFILL,
IDC_STATUS, IDC_SEARCH_TEXT, IDC_QUICKSEARCH, IDC_REFINE,
IDC_REFINE_TEXT,
// disabled cloud parts
/*IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME,
IDC_HEADER_DEVICE_BAR, IDC_HEADER_DEVICE_SIZE,
IDC_HEADER_DEVICE_TRANSFER,*/
};
skin.skinType = SKINNEDWND_TYPE_AUTO;
for (int i = 0; i < sizeof(ffcl) / sizeof(INT); i++)
{
ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
if (IsWindow(ff.hwnd))
{
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn && (i < 3) ? SWBS_SPLITBUTTON : 0);
skin.hwndToSkin = ff.hwnd;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
}
}
skin.hwndToSkin = hwndDlg;
skin.skinType = SKINNEDWND_TYPE_AUTO;
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
if (0 != currentViewedDevice->dev->extraActions(DEVICE_SYNC_UNSUPPORTED,0,0,0))
EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC), FALSE);
}
break;
case WM_USER+1:
if (tracks)
{
if (lParam)
{
tracks->RemoveTrack((songid_t)wParam);
}
tracksList->UpdateList();
}
break;
case WM_DESTROY:
if (aacontents) aacontents->bgQuery_Stop();
tracks = NULL;
if (aacontents) delete aacontents; aacontents=NULL;
break;
case WM_DROPFILES:
return currentViewedDevice->TransferFromDrop((HDROP)wParam);
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if (l->idFrom == IDC_LIST_TRACKS)
{
switch (l->code)
{
case LVN_KEYDOWN:
switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
case VK_DELETE:
{
if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
handleContextMenuResult(ID_TRACKSLIST_DELETE);
}
}
break;
case 0x45: //E
bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
C_ItemList * items = getSelectedItems();
editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
delete items;
}
break;
}
break;
}
}
}
break;
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), 1);
}
return TRUE;
case WM_DISPLAYCHANGE:
{
UpdateWindow(hwndDlg);
LayoutWindows(hwndDlg, TRUE, 1);
}
break;
case WM_APP + 104:
{
pmp_common_UpdateButtonText(hwndDlg, wParam);
LayoutWindows(hwndDlg, TRUE, 1);
return 0;
}
case WM_PAINT:
{
int tab[] = {IDC_LIST_TRACKS|DCW_SUNKENBORDER,
IDC_QUICKSEARCH|DCW_SUNKENBORDER,
(!header?IDC_HDELIM2|DCW_DIVIDER:0),
};
int size = sizeof(tab) / sizeof(tab[0]);
// do this to prevent drawing parts when the views are collapsed
if (!currentViewedDevice->isCloudDevice) size -= 1;
if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
}
return TRUE;
case WM_APP + 3: // send by bgthread
if (wParam == 0x69)
{
if (aacontents)
{
aacontents->bgQuery_Stop();
tracks = aacontents->GetTracksList();
if (tracksList) tracksList->UpdateList();
UpdateStatus(hwndDlg, true);
}
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_QUICKSEARCH:
if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
KillTimer(hwndDlg,500);
SetTimer(hwndDlg,500,250,NULL);
}
break;
case IDC_HEADER_DEVICE_TRANSFER:
{
if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC)))
{
MessageBox(hwndDlg, L"Transferring files from this device to another is not currently supported.",
L"Cloud Transfer Not Supported", MB_ICONINFORMATION);
break;
}
}
case IDC_BUTTON_SYNC:
if (!currentViewedDevice->isCloudDevice)
currentViewedDevice->Sync();
else
currentViewedDevice->CloudSync();
break;
case IDC_SEARCH_TEXT:
if (HIWORD(wParam) == STN_DBLCLK)
{
// TODO decide what to do for the 'all_sources'
if (currentViewedDevice->isCloudDevice &&
lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
{
header = !header;
currentViewedDevice->config->WriteInt(L"header",header);
LayoutWindows(hwndMediaView, TRUE, 1);
UpdateStatus(hwndDlg);
ShowWindow(hwndDlg, 0);
ShowWindow(hwndDlg, 1);
}
}
break;
case IDC_BUTTON_CLEARSEARCH:
SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,L"");
break;
}
break; //WM_COMMAND
case WM_TIMER:
switch(wParam) {
case 123:
{
if (aacontents && aacontents->bgThread_Handle && tracksList)
{
HWND hwndList;
hwndList = tracksList->listview.getwnd();
if (1 != ListView_GetItemCount(hwndList)) ListView_SetItemCountEx(hwndList, 1, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
ListView_RedrawItems(hwndList, 0, 0);
}
}
break;
case 500:
{
KillTimer(hwndDlg,500);
if (currentViewedDevice && aacontents)
{
wchar_t buf[256]=L"";
GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf)/sizeof(wchar_t));
aacontents->SetSearch(buf, (!!currentViewedDevice->isCloudDevice));
if (!aacontents->bgThread_Handle)
{
if (tracksList) tracksList->UpdateList();
UpdateStatus(hwndDlg);
}
}
}
break;
}
break;
}
return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
}
static INT_PTR CALLBACK pmp_common_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
{
hwndMediaView = hwndDlg;
HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_ACCELERATORS);
if (accel)
WASABI_API_APP->app_addAccelerators(hwndDlg, &accel, 1, TRANSLATE_MODE_CHILD);
if (currentViewedDevice->isCloudDevice)
{
wchar_t buf[256] = {0};
currentViewedDevice->GetDisplayName(buf, 128);
SetDlgItemText(hwndDlg, IDC_HEADER_DEVICE_NAME, buf);
int icon_id = currentViewedDevice->dev->extraActions(0x22, 0, 0, 0);
HBITMAP bm = (HBITMAP)LoadImage(GetModuleHandle(L"pmp_cloud.dll"),
MAKEINTRESOURCE(icon_id > 0 ? icon_id : 103), IMAGE_BITMAP, 16, 16,
LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
SendDlgItemMessage(hwndDlg, IDC_HEADER_DEVICE_ICON, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bm);
HWND progress = GetDlgItem(hwndDlg, IDC_HEADER_DEVICE_BAR);
if (IsWindow(progress))
{
MLSKINWINDOW skin = {0};
skin.hwndToSkin = progress;
skin.skinType = SKINNEDWND_TYPE_PROGRESSBAR;
skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
MLSkinWindow(plugin.hwndLibraryParent, &skin);
}
}
tracksList = new SkinnedListView(tracks,IDC_LIST_TRACKS,plugin.hwndLibraryParent, hwndDlg);
tracksList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
if (tracksList->contents && !tracksList->contents->cloud)
{
tracksList->UpdateList();
UpdateStatus(hwndDlg);
}
pmp_common_UpdateButtonText(hwndDlg, enqueuedef == 1);
}
case WM_DISPLAYCHANGE:
{
if (currentViewedDevice->isCloudDevice)
{
int (*wad_getColor)(int idx);
*(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
ARGB32 fc = (!wad_getColor?wad_getColor(WADLG_WNDBG):RGB(0xFF,0xFF,0xFF)) & 0x00FFFFFF;
SetToolbarButtonBitmap(hwndDlg,IDC_HEADER_DEVICE_TRANSFER, MAKEINTRESOURCE(IDR_TRANSFER_SMALL_ICON),fc);
}
}
break;
case WM_DESTROY:
{
if (currentViewedDevice)
{
SkinBitmap *s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_HEADER_DEVICE_TRANSFER),GWLP_USERDATA);
if (s) DeleteSkinBitmap(s);
if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
{
wchar_t buf[256] = {0};
GetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, buf, 256);
currentViewedDevice->config->WriteString(L"savedfilter", buf);
buf[0] = 0;
GetDlgItemTextW(hwndDlg, IDC_REFINE, buf, 256);
currentViewedDevice->config->WriteString(L"savedrefinefilter", buf);
}
}
WASABI_API_APP->app_removeAccelerators(hwndDlg);
hwndMediaView = NULL;
currentViewedDevice = NULL;
if (tracksList)
{
delete tracksList;
tracksList = NULL;
}
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
if (di->CtlType == ODT_BUTTON || di->CtlType == ODT_STATIC) {
if(di->CtlID == IDC_HEADER_DEVICE_TRANSFER)
{ // draw the toolbar buttons!
int (*wad_getColor)(int idx);
*(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
HBRUSH hbr = CreateSolidBrush((wad_getColor?wad_getColor(WADLG_WNDBG):RGB(0xFF,0xFF,0xFF)));
FillRect(di->hDC, &di->rcItem, hbr);
DeleteBrush(hbr);
SkinBitmap* hbm = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,di->CtlID),GWLP_USERDATA);
if(hbm && di->rcItem.left != di->rcItem.right && di->rcItem.top != di->rcItem.bottom) {
DCCanvas dc(di->hDC);
if (di->itemState & ODS_SELECTED) hbm->blitAlpha(&dc,di->rcItem.left+1,di->rcItem.top+1);
else hbm->blitAlpha(&dc,di->rcItem.left,di->rcItem.top);
dc.Release();
}
}
}
}
break;
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if(l->code == LVN_KEYDOWN && ((LPNMLVKEYDOWN)lParam)->wVKey == VK_F5)
{
if (currentViewedDevice->dev->extraActions(DEVICE_REFRESH,0,0,0))
{
SetTimer(hwndDlg, (artistList ? 501 : 500), 250, NULL);
}
}
if(l->idFrom == IDC_LIST_TRACKS)
{
switch(l->code) {
case LVN_KEYDOWN:
switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
case 0x45: //E
{
bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
C_ItemList * items = getSelectedItems();
editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
delete items;
}
}
break;
}
break;
case NM_RETURN:
case NM_DBLCLK:
{
C_ItemList * items = getSelectedItems(true);
int start=0;
int l=tracksList->listview.GetCount();
int i = 0;
for (; i < l; i++)
if (tracksList->listview.GetSelected(i))
{
start = i;
break;
}
if (items->GetSize() && (!!(GetAsyncKeyState(VK_SHIFT)&0x8000) || !gen_mlconfig->ReadInt(playmode,1))) {
void* x = items->Get(i);
delete items;
items = new C_ItemList;
items->Add(x);
start = 0;
}
currentViewedDevice->PlayTracks(items, start, (!(GetAsyncKeyState(VK_SHIFT)&0x8000) ? (enqueuedef == 1) : (enqueuedef != 1)), false);
delete items;
}
break;
case NM_CUSTOMDRAW:
{
LRESULT result = 0;
if (ListView_OnCustomDraw(hwndDlg, (NMLVCUSTOMDRAW*)lParam, &result))
{
SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
return 1;
}
}
break;
case LVN_GETDISPINFOW:
{
NMLVDISPINFOW* pdi = (NMLVDISPINFOW*)lParam;
if (aacontents && aacontents->bgThread_Handle)
{
LVITEMW *pItem = &pdi->item;
if (0 == pItem->iItem && (LVIF_TEXT & pItem->mask))
{
if (0 == pItem->iSubItem)
{
static char bufpos = 0;
static int buflen = 17;
static wchar_t buffer[64];//L"Scanning _\0/-\\|";
if (!buffer[0])
{
//WASABI_API_LNGSTRINGW_BUF(IDS_SCANNING_PLAIN,buffer,54);
StringCchCopyW(buffer,64,L"Scanning");
StringCchCatW(buffer,64,L" _");
StringCchCatW(buffer+(buflen=lstrlenW(buffer)+1),64,L"/-\\|");
buflen+=4;
}
int pos = buflen - 5;;
buffer[pos - 1] = buffer[pos + (bufpos++&3) + 1];
pItem->pszText = buffer;
SetDlgItemText(hwndDlg, IDC_STATUS, buffer);
}
else
{
pItem->pszText = L"";
}
}
return 1;
}
}
break;
case NM_CLICK:
{
// prevent the right-click menus appearing when scanning
if (aacontents && aacontents->bgThread_Handle) break;
LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
if (lpnmitem->iItem != -1 && lpnmitem->iSubItem == tracks->cloudcol)
{
RECT itemRect = {0};
if (lpnmitem->iSubItem)
ListView_GetSubItemRect(l->hwndFrom, lpnmitem->iItem, lpnmitem->iSubItem, LVIR_BOUNDS, &itemRect);
else
{
ListView_GetItemRect(l->hwndFrom, lpnmitem->iItem, &itemRect, LVIR_BOUNDS);
itemRect.right = itemRect.left + ListView_GetColumnWidth(l->hwndFrom, tracks->cloudcol);
}
MapWindowPoints(l->hwndFrom, HWND_DESKTOP, (POINT*)&itemRect, 2);
int cloud_devices = 0;
int mark = tracksList->listview.GetSelectionMark();
if (mark != -1)
{
// if wanting to do on the selection then use getSelectedItems()
//C_ItemList * items = getSelectedItems();
// otherwise only work on the selection mark for speed (and like how ml_local does things)
C_ItemList * items = new C_ItemList;
items->Add((void*)tracks->GetTrack(mark));
HMENU cloud_menu = (HMENU)currentViewedDevice->dev->extraActions(DEVICE_GET_CLOUD_SOURCES_MENU, (intptr_t)&cloud_devices, 0, (intptr_t)items);
if (cloud_menu)
{
int r = Menu_TrackSkinnedPopup(cloud_menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,
itemRect.right, itemRect.top, hwndDlg, NULL);
if (r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_UPPER) { // deals with cloud specific menus
int ret = currentViewedDevice->dev->extraActions(DEVICE_DO_CLOUD_SOURCES_MENU, (intptr_t)r, 1, (intptr_t)items);
// only send a removal from the view if plug-in says so
if (ret) SendMessage(hwndDlg, WM_USER+1, (WPARAM)items->Get(0), ret);
}
DestroyMenu(cloud_menu);
}
delete items;
}
}
}
break;
}
}
else if(l->idFrom==IDC_LIST_ARTIST || l->idFrom==IDC_LIST_ALBUM || l->idFrom==IDC_LIST_ALBUM2)
{
switch(l->code) {
case NM_CUSTOMDRAW:
{
LRESULT result = 0;
if (ListView_OnCustomDraw(hwndDlg, (NMLVCUSTOMDRAW*)lParam, &result))
{
SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
return 1;
}
}
break;
}
}
}
break; //WM_NOTIFY
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_BUTTON_EJECT:
currentViewedDevice->Eject();
break;
case IDC_BUTTON_PLAY:
case ID_TRACKSLIST_PLAYSELECTION:
case IDC_BUTTON_ENQUEUE:
case ID_TRACKSLIST_ENQUEUESELECTION:
case IDC_BUTTON_CUSTOM:
{
if (HIWORD(wParam) == MLBN_DROPDOWN)
{
pmp_common_PlayEnqueue(hwndDlg, (HWND)lParam, LOWORD(wParam));
}
else
{
bool action;
if (LOWORD(wParam) == IDC_BUTTON_PLAY || LOWORD(wParam) == ID_TRACKSLIST_PLAYSELECTION)
action = (HIWORD(wParam) == 1) ? enqueuedef == 1 : 0;
else if (LOWORD(wParam) == IDC_BUTTON_ENQUEUE || LOWORD(wParam) == ID_TRACKSLIST_ENQUEUESELECTION)
action = (HIWORD(wParam) == 1) ? (enqueuedef != 1) : 1;
else
// so custom can work with the menu item part
break;
C_ItemList * selected = getSelectedItems();
currentViewedDevice->PlayTracks(selected, 0, action, true);
delete selected;
}
}
break;
default:
handleContextMenuResult(LOWORD(wParam));
break;
}
break; //WM_COMMAND
case WM_CONTEXTMENU:
{
// prevent the right-click menus appearing when scanning
if (aacontents && aacontents->bgThread_Handle) break;
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
UINT_PTR idFrom = GetDlgCtrlID((HWND)wParam);
HWND hwndFrom = (HWND)wParam;
HWND hwndFromChild = WindowFromPoint(pt);
// deal with the column headers first
SkinnedListView * list=NULL;
int n = 0;
if (artistList && hwndFromChild == ListView_GetHeader(artistList->listview.getwnd())) { n=0; list=artistList; }
if (albumList && hwndFromChild == ListView_GetHeader(albumList->listview.getwnd())) { n=1; list=albumList; }
if (albumList2 && hwndFromChild == ListView_GetHeader(albumList2->listview.getwnd())) { n=2; list=albumList2; }
if (list)
{
HMENU menu = list->GetMenu(true,n,currentViewedDevice->config,m_context_menus);
int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwndDlg, NULL);
list->ProcessMenuResult(r,true,n,currentViewedDevice->config,hwndDlg);
return 0;
}
// and then do the list menus
if(idFrom==IDC_LIST_ARTIST || idFrom==IDC_LIST_ALBUM || idFrom==IDC_LIST_ALBUM2)
{
handleContextMenuResult(showContextMenu(1,hwndFrom,currentViewedDevice->dev,pt));
}
else if(idFrom == IDC_LIST_TRACKS)
{
// prevents funkiness if having shown the 'customize columns' menu before
// as well as alloing the shift+f10 key to work within the track listview
if ((hwndFrom == hwndFromChild) || (pt.x == -1 && pt.y == -1))
{
int r = showContextMenu((GetDlgItem(hwndDlg, IDC_BUTTON_SORT) ? 2 : 0), hwndFrom, currentViewedDevice->dev, pt);
switch(r) {
case ID_TRACKSLIST_REMOVEFROMPLAYLIST:
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(ID_TRACKSLIST_REMOVEFROMPLAYLIST,0),0);
break;
default:
handleContextMenuResult(r);
break;
}
}
}
break;
}
case WM_ML_CHILDIPC:
if(lParam == ML_CHILDIPC_GO_TO_SEARCHBAR)
{
SendDlgItemMessage(hwndDlg, IDC_QUICKSEARCH, EM_SETSEL, 0, -1);
SetFocus(GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
}
else if (lParam == ML_CHILDIPC_REFRESH_SEARCH)
{
restoreDone = FALSE;
PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_QUICKSEARCH, EN_CHANGE), (LPARAM)GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
}
break;
}
return 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))
// disabled cloud parts
/*#define GROUP_MIN 0x1
#define GROUP_MAX 0x7
#define GROUP_HEADER 0x1
#define GROUP_SEARCH 0x2
#define GROUP_FILTER 0x3
#define GROUP_HDELIM 0x4
#define GROUP_REFINE 0x5
#define GROUP_TRACKS 0x6
#define GROUP_STATUS 0x7*/
#define GROUP_MIN 0x1
#define GROUP_MAX 0x6
#define GROUP_SEARCH 0x1
#define GROUP_FILTER 0x2
#define GROUP_HDELIM 0x3
#define GROUP_REFINE 0x4
#define GROUP_TRACKS 0x5
#define GROUP_STATUS 0x6
void LayoutWindows(HWND hwnd, BOOL fRedraw, int simple)
{
static INT controls[] =
{
// disabled cloud parts
//GROUP_HEADER, IDC_HEADER_DEVICE_TRANSFER, IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME, IDC_HEADER_DEVICE_BAR, IDC_HEADER_DEVICE_SIZE, IDC_HDELIM2,
GROUP_SEARCH, IDC_BUTTON_ARTMODE, IDC_BUTTON_VIEWMODE, IDC_BUTTON_COLUMNS, IDC_SEARCH_TEXT, IDC_BUTTON_CLEARSEARCH, IDC_QUICKSEARCH,
GROUP_STATUS, IDC_BUTTON_EJECT, IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM, IDC_BUTTON_SYNC, IDC_BUTTON_AUTOFILL, IDC_BUTTON_SORT, IDC_STATUS,
GROUP_HDELIM, IDC_HDELIM,
GROUP_REFINE, IDC_REFINE_TEXT, IDC_BUTTON_CLEARREFINE, IDC_REFINE,
GROUP_TRACKS, IDC_LIST_TRACKS,
GROUP_FILTER, IDC_LIST_ARTIST, IDC_VDELIM, IDC_LIST_ALBUM, IDC_VDELIM2, IDC_LIST_ALBUM2,
};
INT index, divY, divX, divX2, divCY;
RECT rc, rg, ri;
LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
BOOL skipgroup;
HRGN rgn;
rgn = NULL;
GetClientRect(hwnd, &rc);
if (rc.right == rc.left || rc.bottom == rc.top) return;
if (rc.right > 4) rc.right -= 4;
SetRect(&rg, rc.left, rc.top, rc.right, rc.top);
pl = layout;
skipgroup = FALSE;
divX = (adiv1pos * (rc.right- rc.left)) / 100000;
divX2 = numFilters == 3 ? ((adiv3pos * (rc.right- rc.left)) / 100000) : rc.right;
divY = (((-1 == adiv2pos) ? 50000 : adiv2pos) * (rc.bottom- rc.top)) / 100000;
divCY = 0;
InvalidateRect(hwnd, NULL, TRUE);
for (index = 0; index < sizeof(controls) / sizeof(INT); index++)
{
if (controls[index] >= GROUP_MIN && controls[index] <= GROUP_MAX) // group id
{
skipgroup = FALSE;
switch(controls[index])
{
// disabled cloud parts
/*case GROUP_HEADER:
if (currentViewedDevice->isCloudDevice && simple != 2)
{
SetRect(&rg, rc.left, rc.top + WASABI_API_APP->getScaleY(2),
rc.right + WASABI_API_APP->getScaleX(1),
(!header ? rc.top + WASABI_API_APP->getScaleY(18) : rc.top));
rc.top = rg.bottom + WASABI_API_APP->getScaleY(3);
}
else
skipgroup = 1;
break;*/
case GROUP_SEARCH:
if (g_displaysearch && simple != 2)
{
wchar_t buffer[128] = {0};
HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARSEARCH);
GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
rc.top + WASABI_API_APP->getScaleY(2),
rc.right - WASABI_API_APP->getScaleX(2),
rc.top + WASABI_API_APP->getScaleY(HIWORD(idealSize)+1));
rc.top = rg.bottom + WASABI_API_APP->getScaleY(3);
}
else
skipgroup = 1;
break;
case GROUP_STATUS:
if (g_displaystatus)
{
wchar_t buffer[128] = {0};
HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_EJECT);
GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, 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);
}
skipgroup = !g_displaystatus;
break;
case GROUP_HDELIM:
SetRect(&rg, rc.left, rc.top, rc.right, rc.bottom);
break;
case GROUP_REFINE:
{
wchar_t buffer[128] = {0};
HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARREFINE);
GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
rg.top = divY + divCY;
refineHidden = (g_displayrefine) ? ((rg.top + WASABI_API_APP->getScaleY(HIWORD(idealSize))) >= rc.bottom) : TRUE;
SetRect(&rg, rc.left, rg.top, rc.right, (refineHidden) ? rg.top : (rg.top + WASABI_API_APP->getScaleY(HIWORD(idealSize))));
break;
}
case GROUP_TRACKS:
if (!simple)
{
wchar_t buffer[128] = {0};
HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARREFINE);
GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
(divY + divCY) + ((!refineHidden) ? WASABI_API_APP->getScaleY(HIWORD(idealSize) + 3) : 0),
rc.right, rc.bottom);
}
else
SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, rc.bottom);
break;
case GROUP_FILTER:
if (!simple)
{
if (divX < (rc.left + 15))
{
divX = rc.left;
adiv1_nodraw = 1;
}
else if (divX > (rc.right - (numFilters == 3 ? 16 * 2 : 24)))
{
RECT rw;
GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM), &rw);
divX = rc.right - (rw.right - rw.left) - (numFilters == 3 ? 6 : 0) + (numFilters == 2 ? 1 : -1);
adiv1_nodraw = 2;
}
else adiv1_nodraw = 0;
if (divX2 < (rc.left + 16 * (numFilters == 3 ? 2 : 1)))
{
RECT rw;
GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM), &rw);
divX2 = rc.left;
adiv3_nodraw = 1;
}
else if (divX2 > (rc.right - 16 * 2))
{
RECT rw;
GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM2), &rw);
divX2 = rc.right - ((rw.right - rw.left) - 1) * 2;
adiv3_nodraw = 2;
}
else adiv3_nodraw = 0;
SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, divY);
}
else
skipgroup = 1;
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)
{
// disabled cloud parts
/*case IDC_HEADER_DEVICE_TRANSFER:
SETLAYOUTPOS(pl, rg.right - 18, rg.top - WASABI_API_APP->getScaleY(1),
WASABI_API_APP->getScaleX(16), WASABI_API_APP->getScaleY(16));
pl->flags |= (!header && (rg.right - rg.left) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(3+16));
break;
case IDC_HEADER_DEVICE_ICON:
SETLAYOUTPOS(pl, rg.left, rg.top - WASABI_API_APP->getScaleY(1),
WASABI_API_APP->getScaleX(16), WASABI_API_APP->getScaleY(16));
pl->flags |= (!header && (rg.right - rg.left + WASABI_API_APP->getScaleX(16)) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
break;
case IDC_HEADER_DEVICE_NAME:
{
SIZE s = {0};
wchar_t buf[128] = {0};
HDC dc = GetDC(pl->hwnd);
HFONT font = (HFONT)SendMessage(pl->hwnd, WM_GETFONT, 0, 0), oldfont = (HFONT)SelectObject(dc, font);
int len = GetWindowText(pl->hwnd, buf, sizeof(buf));
GetTextExtentPoint32(dc, buf, len, &s);
SelectObject(dc, oldfont);
ReleaseDC(pl->hwnd, dc);
SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top, s.cx + ((s.cx / len)), WASABI_API_APP->getScaleY(16));
pl->flags |= (!header && (rg.right - rg.left + WASABI_API_APP->getScaleX(12)) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
break;
}
case IDC_HEADER_DEVICE_BAR:
SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top + WASABI_API_APP->getScaleY(2),
WASABI_API_APP->getScaleX(150), WASABI_API_APP->getScaleY(11));
pl->flags |= (!header && (rg.right - rg.left) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(8));
break;
case IDC_HEADER_DEVICE_SIZE:
SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top, rg.right - rg.left, WASABI_API_APP->getScaleY(16));
pl->flags |= (!header && (ri.right - ri.left) > WASABI_API_APP->getScaleX(60)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
break;
case IDC_HDELIM2:
SETLAYOUTPOS(pl, 0, rg.bottom + WASABI_API_APP->getScaleY(1), rg.right + WASABI_API_APP->getScaleX(35), 0);
pl->flags |= (!header ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
break;*/
case IDC_BUTTON_ARTMODE:
case IDC_BUTTON_VIEWMODE:
case IDC_BUTTON_COLUMNS:
pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
SETLAYOUTPOS(pl, rg.left, rg.top, (ri.right - ri.left), (rg.bottom - rg.top));
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(1));
break;
case IDC_SEARCH_TEXT:
{
wchar_t buffer[128] = {0};
GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedStatic_GetIdealSize(pl->hwnd, buffer);
pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(6),
rg.top + WASABI_API_APP->getScaleY(1),
WASABI_API_APP->getScaleX(LOWORD(idealSize)),
(rg.bottom - rg.top));
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
break;
}
case IDC_REFINE_TEXT:
{
pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
wchar_t buffer[128] = {0};
GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
LRESULT idealSize = MLSkinnedStatic_GetIdealSize(pl->hwnd, buffer);
SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(2),
rg.top + WASABI_API_APP->getScaleY(1),
WASABI_API_APP->getScaleX(LOWORD(idealSize)),
(rg.bottom - rg.top));
if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
break;
}
case IDC_BUTTON_CLEARSEARCH:
{
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);
pl->flags |= (((rg.right - rg.left) - width) > WASABI_API_APP->getScaleX(40)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
SETLAYOUTPOS(pl, rg.right - width, rg.top, width, (rg.bottom - rg.top));
if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(4));
break;
}
case IDC_BUTTON_CLEARREFINE:
{
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);
pl->flags |= (((rg.right - rg.left) - width) > WASABI_API_APP->getScaleX(40)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW ;
SETLAYOUTPOS(pl, rg.right - width, rg.top, width, rg.bottom - rg.top);
if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(4));
break;
}
case IDC_QUICKSEARCH:
pl->flags |= SWP_SHOWWINDOW;
pl->flags |= (rg.right > rg.left) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(1),
(rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
break;
case IDC_REFINE:
pl->flags |= ((rg.right > rg.left) && (rg.top < rg.bottom)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(1),
(rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
break;
case IDC_BUTTON_EJECT:
{
if (currentViewedDevice->isCloudDevice)
{
if (currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_REMOVE,0,0,0))
{
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.right - width + WASABI_API_APP->getScaleX(2),
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.right -= (pl->cx + WASABI_API_APP->getScaleX(3));
break;
}
case IDC_BUTTON_AUTOFILL:
if (currentViewedDevice->isCloudDevice)
{
pl->flags |= SWP_HIDEWINDOW;
break;
}
case IDC_BUTTON_SYNC:
if (currentViewedDevice->isCloudDevice)
{
if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
{
pl->flags |= SWP_HIDEWINDOW;
break;
}
}
case IDC_BUTTON_PLAY:
case IDC_BUTTON_ENQUEUE:
case IDC_BUTTON_CUSTOM:
case IDC_BUTTON_SORT:
{
if (IDC_BUTTON_CUSTOM != pl->id || customAllowed)
{
if (groupBtn && (pl->id == IDC_BUTTON_PLAY) && (enqueuedef == 1))
{
pl->flags |= SWP_HIDEWINDOW;
break;
}
if (groupBtn && (pl->id == IDC_BUTTON_ENQUEUE) && (enqueuedef != 1))
{
pl->flags |= SWP_HIDEWINDOW;
break;
}
if (groupBtn && (pl->id == IDC_BUTTON_PLAY || pl->id == IDC_BUTTON_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.bottom - WASABI_API_APP->getScaleY(18), rg.right - rg.left, WASABI_API_APP->getScaleY(17));
if (SWP_SHOWWINDOW & pl->flags) rg.top = (pl->y + pl->cy + WASABI_API_APP->getScaleY(1));
break;
case IDC_HDELIM:
divCY = ri.bottom - ri.top;
if (divY > (rg.bottom - WASABI_API_APP->getScaleY(70))) { divY = rg.bottom - divCY; m_nodrawtopborders = 2; }
else if (divY < (rg.top + WASABI_API_APP->getScaleY(36))) { divY = rg.top; m_nodrawtopborders = 1; }
else m_nodrawtopborders = 0;
SETLAYOUTPOS(pl, rg.left, divY, rg.right - rg.left + WASABI_API_APP->getScaleX(2), (ri.bottom - ri.top));
break;
case IDC_LIST_TRACKS:
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->getScaleX(1),
(rg.bottom - rg.top) - WASABI_API_APP->getScaleY(2));
break;
case IDC_LIST_ARTIST:
SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), divX, (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
rg.left += pl->cx;
break;
case IDC_VDELIM:
SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (ri.right - ri.left), (rg.bottom - rg.top));
rg.left += pl->cx;
break;
case IDC_LIST_ALBUM:
if(numFilters == 3)
{
BOOL hide = ((divX2 - divX - 1) < WASABI_API_APP->getScaleX(15));
pl->flags |= hide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW;
SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (hide ? 0 : divX2 - divX - WASABI_API_APP->getScaleX(1)),
(rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
}
else { SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) + WASABI_API_APP->getScaleX(1),
(rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1)); }
rg.left += pl->cx;
break;
case IDC_VDELIM2:
SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (numFilters == 2 ? 0 : ri.right - ri.left), (rg.bottom - rg.top));
rg.left += pl->cx;
break;
case IDC_LIST_ALBUM2:
SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) + WASABI_API_APP->getScaleX(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);
}
static void WINAPI OnDividerMoved(HWND hwnd, INT nPos, LPARAM param)
{
RECT rc;
HWND hwndParent;
hwndParent = GetParent(hwnd);
KillTimer(hwndParent,400);
SetTimer(hwndParent,400,1000,NULL);
if (hwndParent)
{
GetClientRect(hwndParent, &rc);
switch((INT)param)
{
case IDC_VDELIM:
{
adiv1pos = (nPos * 100000) / (rc.right - rc.left + 10);
if(adiv1pos + 500 >= adiv3pos) adiv3pos = adiv1pos + 500;
}
break;
case IDC_HDELIM:
adiv2pos = (nPos * 100000) / (rc.bottom - rc.top);
break;
case IDC_VDELIM2:
{
adiv3pos = (nPos * 100000) / (rc.right - rc.left + 10);
if(adiv3pos - 500 < adiv1pos) adiv1pos = adiv3pos - 500;
}
break;
}
LayoutWindows(hwndParent, TRUE, 0);
}
}
static BOOL AttachDivider(HWND hwnd, BOOL fVertical, DIVIDERMOVED callback, LPARAM param)
{
if (!hwnd) return FALSE;
DIVIDER *pd = (DIVIDER*)calloc(1, sizeof(DIVIDER));
if (!pd) return FALSE;
pd->fUnicode = IsWindowUnicode(hwnd);
pd->fnOldProc = (WNDPROC) ((pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc) :
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc));
if (!pd->fnOldProc || !SetPropW(hwnd, L"DIVDATA", pd))
{
free(pd);
return FALSE;
}
pd->fVertical = fVertical;
pd->param = param;
pd->callback = callback;
return TRUE;
}
static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DIVIDER *pd;
pd = GET_DIVIDER(hwnd);
if (!pd) return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
switch(uMsg)
{
case WM_DESTROY:
RemovePropW(hwnd, L"DIVDATA");
(pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
(pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc) : SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc);
free(pd);
return 0;
case WM_LBUTTONDOWN:
pd->clickoffs = (pd->fVertical) ? LOWORD(lParam) : HIWORD(lParam);
SetCapture(hwnd);
break;
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_SETCURSOR:
SetCursor(LoadCursor(NULL, (pd->fVertical) ? IDC_SIZEWE : IDC_SIZENS));
return TRUE;
case WM_MOUSEMOVE:
{
RECT rw;
GetWindowRect(hwnd, &rw);
GetCursorPos(((LPPOINT)&rw) + 1);
(pd->fVertical) ? rw.right -= pd->clickoffs : rw.bottom -= pd->clickoffs;
if ((pd->fVertical && rw.left != rw.right) || (!pd->fVertical && rw.top != rw.bottom))
{
MapWindowPoints(HWND_DESKTOP, GetParent(hwnd), ((LPPOINT)&rw) + 1, 1);
if (pd->callback) pd->callback(hwnd, (pd->fVertical) ? rw.right : rw.bottom, pd->param);
}
}
break;
}
return (pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
}