view_pmp_media.cpp 110 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205
  1. #include "main.h"
  2. #include "..\..\General\gen_ml/ml.h"
  3. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  4. #include "..\..\General\gen_ml/itemlist.h"
  5. #include "../nu/listview.h"
  6. #include "..\..\General\gen_ml/childwnd.h"
  7. #include "../winamp/wa_ipc.h"
  8. #include "../winamp/wa_dlg.h"
  9. #include "resource1.h"
  10. #include "SkinnedListView.h"
  11. #include "DeviceView.h"
  12. #include "ArtistAlbumLists.h"
  13. #include "mt19937ar.h" // random number generator
  14. #include "api__ml_pmp.h"
  15. #include "..\..\General\gen_ml/graphics.h"
  16. #include <tataki/export.h>
  17. #include <tataki/bitmap/bitmap.h>
  18. #include <tataki/canvas/bltcanvas.h>
  19. #include "AlbumArtListView.h"
  20. #include "./local_menu.h"
  21. #include "metadata_utils.h"
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <stdio.h>
  25. #include <shlobj.h>
  26. extern winampMediaLibraryPlugin plugin;
  27. extern int currentViewedPlaylist;
  28. extern DeviceView * currentViewedDevice;
  29. extern HMENU m_context_menus;
  30. extern C_ItemList devices;
  31. extern void editInfo(C_ItemList * items, Device * dev, HWND centerWindow); // from editinfo.cpp
  32. static INT_PTR CALLBACK pmp_common_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
  33. int (*wad_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  34. static void (*wad_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize);
  35. HWND hwndMediaView;
  36. static SkinnedListView *artistList=NULL, *albumList=NULL, *albumList2=NULL, *tracksList=NULL;
  37. static int adiv1_nodraw=0,adiv3_nodraw=0;
  38. static int m_nodrawtopborders=0;
  39. static int numFilters;
  40. static int adiv1pos=-1, adiv2pos=-1, adiv3pos=-1;
  41. static int refineHidden=0;
  42. static BOOL g_displaysearch = TRUE;
  43. static BOOL g_displayrefine = TRUE;
  44. static BOOL g_displaystatus = TRUE;
  45. static HRGN g_rgnUpdate = NULL;
  46. static int offsetX = 0, offsetY = 0, header = 0;
  47. viewButtons view = {0};
  48. static bool noSearchTimer=false;
  49. static ArtistAlbumLists *aacontents=NULL;
  50. static PrimaryListContents *tracks=NULL;
  51. static void UpdateStatus(HWND hwndDlg, bool full = false) {
  52. wchar_t buf[1024]=L"";
  53. if (tracks)
  54. {
  55. tracks->GetInfoString(buf);
  56. SetDlgItemText(hwndDlg,IDC_STATUS,buf);
  57. }
  58. if (full && currentViewedDevice && currentViewedDevice->isCloudDevice)
  59. {
  60. int usedPercent = 0;
  61. __int64 available = currentViewedDevice->dev->getDeviceCapacityAvailable();
  62. __int64 capacity = currentViewedDevice->dev->getDeviceCapacityTotal();
  63. if(capacity > 0) usedPercent = (int)((((__int64)100)*available) / capacity);
  64. if (!header)
  65. {
  66. wchar_t buf[128], status[128], availStr[100]=L"";
  67. currentViewedDevice->dev->getTrackExtraInfo(0, L"cloud_status", status, ARRAYSIZE(status));
  68. WASABI_API_LNG->FormattedSizeString(availStr, ARRAYSIZE(availStr), (available > 0 ? available : capacity));
  69. wsprintf(buf, L"%s %s %s", availStr, (available > 0 ? L"free" : L"used"), status);
  70. SetDlgItemText(hwndDlg, IDC_HEADER_DEVICE_SIZE, buf);
  71. SendDlgItemMessage(hwndDlg, IDC_HEADER_DEVICE_BAR, PBM_SETPOS, (100 - usedPercent), 0);
  72. }
  73. }
  74. }
  75. static wchar_t *playmode = L"viewplaymode";
  76. typedef void (WINAPI *DIVIDERMOVED)(HWND, INT, LPARAM);
  77. typedef struct _DIVIDER
  78. {
  79. BOOL fVertical;
  80. DIVIDERMOVED callback;
  81. LPARAM param;
  82. WNDPROC fnOldProc;
  83. BOOL fUnicode;
  84. INT clickoffs;
  85. } DIVIDER;
  86. #define GET_DIVIDER(hwnd) (DIVIDER*)GetPropW(hwnd, L"DIVDATA")
  87. static BOOL AttachDivider(HWND hwnd, BOOL fVertical, DIVIDERMOVED callback, LPARAM param);
  88. static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  89. static void WINAPI OnDividerMoved(HWND hwnd, INT nPos, LPARAM param);
  90. void LayoutWindows(HWND hwnd, BOOL fRedraw, INT simple);
  91. static HBITMAP ConvertTo24bpp(HBITMAP bmp, int bpp)
  92. {
  93. HDC hdcMem, hdcMem2;
  94. HBITMAP hbm24;
  95. BITMAP bm;
  96. GetObjectW(bmp, sizeof(BITMAP), &bm);
  97. hdcMem = CreateCompatibleDC(0);
  98. hdcMem2 = CreateCompatibleDC(0);
  99. void *bits;
  100. BITMAPINFOHEADER bi;
  101. ZeroMemory (&bi, sizeof (bi));
  102. bi.biSize = sizeof (bi);
  103. bi.biWidth= bm.bmWidth;
  104. bi.biHeight = -bm.bmHeight;
  105. bi.biPlanes = 1;
  106. bi.biBitCount= bpp;
  107. hbm24 = CreateDIBSection(hdcMem2, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, NULL);
  108. HBITMAP oBmp = (HBITMAP)SelectObject(hdcMem, bmp);
  109. HBITMAP oBmp24 = (HBITMAP)SelectObject(hdcMem2, hbm24);
  110. BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
  111. SelectObject(hdcMem, oBmp);
  112. SelectObject(hdcMem2, oBmp24);
  113. DeleteDC(hdcMem);
  114. DeleteDC(hdcMem2);
  115. return hbm24;
  116. }
  117. C_ItemList * getSelectedItems(bool all=false) {
  118. if(!currentViewedDevice) return NULL;
  119. C_ItemList * selected = new C_ItemList;
  120. int l = tracks->GetNumRows();
  121. if(all || tracksList->listview.GetSelectedCount()==0) for(int i=0; i<l; i++) selected->Add((void*)tracks->GetTrack(i));
  122. else for(int i=0; i<l; i++) if(tracksList->listview.GetSelected(i)) selected->Add((void*)tracks->GetTrack(i));
  123. return selected;
  124. }
  125. int showContextMenu(int context, HWND hwndDlg, Device * dev, POINT pt) {
  126. // does cloud specific menu hacks
  127. int cloud_devices = 0;
  128. HMENU cloud_menu = 0;
  129. if (context < 2)
  130. {
  131. int mark = tracksList->listview.GetSelectionMark();
  132. if (mark != -1)
  133. {
  134. // if wanting to do on the selection then use getSelectedItems()
  135. //C_ItemList * items = getSelectedItems();
  136. // otherwise only work on the selection mark for speed (and like how ml_local does things)
  137. C_ItemList * items = new C_ItemList;
  138. items->Add((void*)tracks->GetTrack(mark));
  139. cloud_menu = (HMENU)dev->extraActions(DEVICE_GET_CLOUD_SOURCES_MENU, (intptr_t)&cloud_devices, 0, (intptr_t)items);
  140. delete items;
  141. }
  142. }
  143. HMENU menu = GetSubMenu(m_context_menus, context);
  144. HMENU sendto = GetSubMenu(menu, 2);
  145. int fieldsBits = (int)dev->extraActions(DEVICE_SUPPORTED_METADATA, 0, 0, 0);
  146. bool noRatings = !(!fieldsBits || (fieldsBits & SUPPORTS_RATING));
  147. bool noEdit = dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA, 0, 0, 0) != 0;
  148. HMENU ratingMenu = Menu_FindRatingMenu(menu, FALSE);
  149. if (NULL != ratingMenu)
  150. {
  151. Menu_SetRatingValue(ratingMenu, -1);
  152. }
  153. // toggle text of the delete menu item as needed
  154. MENUITEMINFOW mii = {sizeof(MENUITEMINFOW), 0};
  155. mii.fMask = MIIM_STRING;
  156. mii.dwTypeData = WASABI_API_LNGSTRINGW(!currentViewedDevice->isCloudDevice ? IDS_DELETE : IDS_REMOVE);
  157. mii.cch = wcslen(mii.dwTypeData);
  158. // just make sure we've got a string to use here
  159. if (mii.cch > 0)
  160. {
  161. SetMenuItemInfoW(menu, ID_TRACKSLIST_DELETE, FALSE, &mii);
  162. }
  163. EnableMenuItem(menu, ID_TRACKSLIST_DELETE, MF_BYCOMMAND |
  164. (!currentViewedDevice->isCloudDevice ||
  165. (currentViewedDevice->isCloudDevice &&
  166. !currentViewedDevice->dev->extraActions(DEVICE_NOT_READY_TO_VIEW, 0, 0, 0))) ? MF_ENABLED : MF_GRAYED);
  167. EnableMenuItem(menu, ID_TRACKSLIST_EDITSELECTEDITEMS, MF_BYCOMMAND | noEdit ? MF_GRAYED : MF_ENABLED);
  168. EnableMenuItem(menu, ID_RATE_0, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  169. EnableMenuItem(menu, ID_RATE_1, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  170. EnableMenuItem(menu, ID_RATE_2, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  171. EnableMenuItem(menu, ID_RATE_3, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  172. EnableMenuItem(menu, ID_RATE_4, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  173. EnableMenuItem(menu, ID_RATE_5, MF_BYCOMMAND | noRatings ? MF_GRAYED : MF_ENABLED);
  174. EnableMenuItem(menu, ID_TRACKSLIST_COPYTOLIBRARY, MF_BYCOMMAND | dev->copyToHardDriveSupported() ? MF_ENABLED : MF_GRAYED);
  175. int num = 0;
  176. // TODO remove once we've got cloud playlist implemented
  177. if (0 == dev->extraActions(DEVICE_PLAYLISTS_UNSUPPORTED,0,0,0))
  178. {
  179. if (EnableMenuItem(menu, ID_ADDTOPLAYLIST_NEWPLAYLIST, MF_BYCOMMAND | (!cloud_menu ? MF_ENABLED : MF_GRAYED)) == -1)
  180. {
  181. MENUITEMINFOW m = {sizeof(m), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU, MFT_STRING, 0};
  182. wchar_t a[100] = {0};
  183. m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_SEND_TO_PL, a, 100);
  184. m.wID = 2;
  185. sendto = m.hSubMenu = CreatePopupMenu();
  186. InsertMenuItemW(menu, 2, TRUE, &m);
  187. m.fMask -= MIIM_SUBMENU;
  188. m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CMD_PLAYLIST_CREATE, a, 100);
  189. m.wID = ID_ADDTOPLAYLIST_NEWPLAYLIST;
  190. m.fState = (!cloud_menu ? MF_ENABLED : MF_GRAYED);
  191. InsertMenuItemW(m.hSubMenu, 0, FALSE, &m);
  192. }
  193. num = dev->getPlaylistCount();
  194. if(num > 1) AppendMenu(sendto, MF_SEPARATOR, 0, L"");
  195. for(int i=1; i<num; i++) {
  196. wchar_t buf[100] = {0};
  197. dev->getPlaylistName(i, buf, sizeof(buf)/sizeof(wchar_t));
  198. AppendMenu(sendto, 0, 100000 + i, buf);
  199. }
  200. }
  201. else
  202. {
  203. if (DeleteMenu(menu, ID_ADDTOPLAYLIST_NEWPLAYLIST, MF_BYCOMMAND))
  204. {
  205. DeleteMenu(menu, 2, MF_BYPOSITION);
  206. sendto = NULL;
  207. }
  208. }
  209. if (cloud_menu)
  210. {
  211. MENUITEMINFOW m = {sizeof(m), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU, MFT_SEPARATOR, 0};
  212. m.wID = CLOUD_SOURCE_MENUS - 1;
  213. m.fType = MFT_SEPARATOR;
  214. InsertMenuItemW(menu, (sendto ? 3 : 2), TRUE, &m);
  215. wchar_t a[100] = {0};
  216. m.fType = MFT_STRING;
  217. m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_CLOUD_SOURCES, a, 100);
  218. m.wID = CLOUD_SOURCE_MENUS;
  219. m.hSubMenu = cloud_menu;
  220. InsertMenuItemW(menu, (sendto ? 4 : 3), TRUE, &m);
  221. }
  222. if (-1 == pt.x && -1 == pt.y)
  223. {
  224. RECT itemRect;
  225. int selected = ListView_GetNextItem(hwndDlg, -1, LVNI_ALL | LVNI_SELECTED);
  226. ListView_GetItemRect(hwndDlg, (selected != -1 ? selected : 0), &itemRect, LVIR_BOUNDS);
  227. pt.x = itemRect.left;
  228. pt.y = itemRect.top;
  229. MapWindowPoints(hwndDlg, HWND_DESKTOP, (POINT*)&pt, 1);
  230. }
  231. int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY, pt.x, pt.y, hwndDlg, NULL);
  232. if(num > 1) DeleteMenu(sendto,1,MF_BYPOSITION);
  233. for(int i = 1; i < num; i++) DeleteMenu(sendto, 100000+i, MF_BYCOMMAND);
  234. if (cloud_menu)
  235. {
  236. DeleteMenu(menu, (sendto ? 4 : 3), MF_BYPOSITION);
  237. DeleteMenu(menu, (sendto ? 3 : 2), MF_BYPOSITION);
  238. DestroyMenu(cloud_menu);
  239. }
  240. return r;
  241. }
  242. void handleContextMenuResult(int r, C_ItemList * items0=NULL, DeviceView * dev=NULL) {
  243. if(!dev) dev = currentViewedDevice;
  244. if(!dev) return;
  245. C_ItemList * items = items0;
  246. switch(r) {
  247. case ID_TRACKSLIST_PLAYSELECTION:
  248. case ID_TRACKSLIST_ENQUEUESELECTION:
  249. {
  250. if (!items) items = getSelectedItems();
  251. dev->PlayTracks(items, 0, r==ID_TRACKSLIST_ENQUEUESELECTION, true, hwndMediaView);
  252. if (!items0) delete items;
  253. }
  254. break;
  255. case ID_ADDTOPLAYLIST_NEWPLAYLIST:
  256. {
  257. int n = dev->CreatePlaylist();
  258. if (n == -1) return;
  259. r = 100000 + n;
  260. // the selected tracks will be added by the code at the end of this function
  261. }
  262. break;
  263. case ID_TRACKSLIST_SELECTALL:
  264. {
  265. int num = tracksList->listview.GetCount();
  266. for (int x = 0; x < num; x ++) tracksList->listview.SetSelected(x);
  267. }
  268. break;
  269. case ID_TRACKSLIST_EDITSELECTEDITEMS:
  270. {
  271. if (!items) items = getSelectedItems();
  272. editInfo(items, dev->dev, CENTER_OVER_ML_VIEW);
  273. }
  274. break;
  275. case ID_RATE_5:
  276. case ID_RATE_4:
  277. case ID_RATE_3:
  278. case ID_RATE_2:
  279. case ID_RATE_1:
  280. case ID_RATE_0:
  281. {
  282. if (!items) items = getSelectedItems();
  283. for(int i = 0; i<items->GetSize(); i++)
  284. dev->dev->setTrackRating((songid_t)items->Get(i), ID_RATE_0 - r);
  285. if (tracksList) tracksList->UpdateList(true);
  286. dev->DevicePropertiesChanges();
  287. }
  288. break;
  289. case ID_TRACKSLIST_DELETE:
  290. {
  291. wchar_t buf[256] = {0};
  292. if (!items) items = getSelectedItems();
  293. wsprintf(buf,WASABI_API_LNGSTRINGW((!currentViewedDevice->isCloudDevice ? IDS_PHYSICALLY_REMOVE_X_TRACKS : IDS_CLOUD_REMOVE_X_TRACKS)),items->GetSize());
  294. bool ckdev = (dev == currentViewedDevice);
  295. wchar_t titleStr[32] = {0};
  296. if (MessageBox(hwndMediaView, buf, WASABI_API_LNGSTRINGW_BUF(IDS_ARE_YOU_SURE, titleStr, 32), MB_YESNO | MB_ICONQUESTION) == IDYES) {
  297. if (ckdev && !currentViewedDevice) return;
  298. dev->DeleteTracks(items, CENTER_OVER_ML_VIEW);
  299. if (aacontents && dev == currentViewedDevice) { // full artist-album refresh
  300. GetDlgItemText(hwndMediaView, IDC_QUICKSEARCH, buf, sizeof(buf)/sizeof(wchar_t));
  301. // TODO async
  302. if (aacontents) aacontents->SetSearch(buf);
  303. GetDlgItemText(hwndMediaView, IDC_REFINE, buf, sizeof(buf)/sizeof(wchar_t));
  304. if (aacontents) aacontents->SetRefine(buf);
  305. if (artistList) artistList->UpdateList();
  306. if (albumList) albumList->UpdateList();
  307. if (albumList2) albumList2->UpdateList();
  308. }
  309. if (tracksList) tracksList->UpdateList();
  310. dev->DevicePropertiesChanges();
  311. UpdateStatus(hwndMediaView, true);
  312. }
  313. }
  314. break;
  315. case ID_TRACKSLIST_COPYTOLIBRARY:
  316. {
  317. if (!items) items = getSelectedItems();
  318. dev->CopyTracksToHardDrive(items);
  319. }
  320. break;
  321. }
  322. if(r > 100000) { // add songs to existing playlist
  323. int num = dev->dev->getPlaylistCount();
  324. if(r < num + 100000) {
  325. r-=100000;
  326. if(!items) items = getSelectedItems();
  327. for(int i = 0; i < items->GetSize(); i++) dev->dev->addTrackToPlaylist(r,(songid_t)items->Get(i));
  328. dev->DevicePropertiesChanges();
  329. }
  330. }
  331. else if (r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_UPPER) { // deals with cloud specific menus
  332. if (!items) items = getSelectedItems();
  333. int ret = dev->dev->extraActions(DEVICE_DO_CLOUD_SOURCES_MENU, (intptr_t)r, items->GetSize(), (intptr_t)items);
  334. // only send a removal from the view if plug-in says so
  335. if (ret) SendMessage(hwndMediaView, WM_USER+1, (WPARAM)items->Get(0), ret);
  336. }
  337. if (!items0) delete items;
  338. }
  339. void localizeFilter(const wchar_t *f, wchar_t *buf, int len) {
  340. int r=0;
  341. if(!_wcsicmp(f,L"Artist")) r = IDS_ARTIST;
  342. else if(!_wcsicmp(f,L"Album")) r = IDS_ALBUM;
  343. else if(!_wcsicmp(f,L"Genre")) r = IDS_GENRE;
  344. else if(!_wcsicmp(f,L"Artist Index")) r = IDS_ARTIST_INDEX;
  345. else if(!_wcsicmp(f,L"Year")) r = IDS_YEAR;
  346. else if(!_wcsicmp(f,L"Album Artist")) r = IDS_ALBUM_ARTIST;
  347. else if(!_wcsicmp(f,L"Publisher")) r = IDS_PUBLISHER;
  348. else if(!_wcsicmp(f,L"Composer")) r = IDS_COMPOSER;
  349. else if(!_wcsicmp(f,L"Album Artist Index")) r = IDS_ALBUM_ARTIST_INDEX;
  350. else if(!_wcsicmp(f,L"Album Art")) r = IDS_ALBUM_ART;
  351. else {buf[0]=0; return;}
  352. WASABI_API_LNGSTRINGW_BUF(r,buf,len);
  353. }
  354. wchar_t *GetDefFilter(int i,int n) {
  355. if(n==2) i++;
  356. if(i==0) return L"Genre";
  357. if(i==1) return L"Artist";
  358. return L"Album";
  359. }
  360. static __forceinline BYTE pm(int a, int b) {
  361. return (BYTE) ((a * b) / 0xff);
  362. }
  363. extern svc_imageLoader *GetPngLoaderService();
  364. static ARGB32 *LoadPngResource(HINSTANCE module, const wchar_t *name, const wchar_t *type,
  365. BOOL premultily, int *width, int *height)
  366. {
  367. svc_imageLoader *wasabiPngLoader;
  368. HRSRC resource;
  369. HANDLE resourceHandle;
  370. ARGB32 *result;
  371. if (NULL == WASABI_API_MEMMGR)
  372. return NULL;
  373. wasabiPngLoader = GetPngLoaderService();
  374. if (NULL == wasabiPngLoader)
  375. return NULL;
  376. resource = FindResourceW(module, name, type);
  377. if (NULL == resource)
  378. return NULL;
  379. result = NULL;
  380. resourceHandle = LoadResource(module, resource);
  381. if (NULL != resourceHandle)
  382. {
  383. unsigned long resourceSize = SizeofResource(module, resource);
  384. if (0 != resourceSize)
  385. {
  386. void *resourceData = LockResource(resourceHandle);
  387. if (NULL != resourceData)
  388. {
  389. result = (FALSE != premultily) ?
  390. wasabiPngLoader->loadImage(resourceData, resourceSize, width, height) :
  391. wasabiPngLoader->loadImageData(resourceData, resourceSize, width, height);
  392. }
  393. }
  394. }
  395. return result;
  396. }
  397. void DeleteSkinBitmap(SkinBitmap *skinBitmap)
  398. {
  399. void *bits;
  400. if (NULL == skinBitmap)
  401. return;
  402. bits = skinBitmap->getBits();
  403. if (NULL != bits)
  404. {
  405. if (NULL != WASABI_API_MEMMGR)
  406. WASABI_API_MEMMGR->sysFree(bits);
  407. }
  408. delete skinBitmap;
  409. }
  410. BOOL SetToolbarButtonBitmap(HWND hwnd, int controlId, const wchar_t *resourceName, ARGB32 fc)
  411. {
  412. int width, height;
  413. ARGB32 *data, *x, *end;
  414. BYTE r, g, b;
  415. SkinBitmap *sbm, *old;
  416. HWND controlWindow;
  417. controlWindow = GetDlgItem(hwnd, controlId);
  418. if (NULL == controlWindow)
  419. return FALSE;
  420. data = LoadPngResource(plugin.hDllInstance, resourceName, RT_RCDATA, FALSE, &width, &height);
  421. if (NULL == data)
  422. return FALSE;
  423. r = (BYTE)(fc & 0x00ff0000 >> 16);
  424. g = (BYTE)(fc & 0x0000ff00 >> 8);
  425. b = (BYTE)(fc & 0x000000ff);
  426. x = data;
  427. end = data + width*height;
  428. while(x < end)
  429. {
  430. BYTE a = (BYTE)(~(*x))&0xff;
  431. *(x++) = (a<<24) | (pm(r,a)<<16) | (pm(g,a)<<8) | pm(b,a);
  432. }
  433. sbm = new SkinBitmap(data, width, height);
  434. old = (SkinBitmap*)SetWindowLongPtr(controlWindow, GWLP_USERDATA,(LONG_PTR)sbm);
  435. DeleteSkinBitmap(old);
  436. InvalidateRect(controlWindow, NULL, TRUE);
  437. return TRUE;
  438. }
  439. typedef struct { int id, id2; } hi;
  440. void do_help(HWND hwnd, UINT id, HWND hTooltipWnd)
  441. {
  442. RECT r;
  443. POINT p;
  444. GetWindowRect(GetDlgItem(hwnd, id), &r);
  445. GetCursorPos(&p);
  446. if (p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom)
  447. {}
  448. else
  449. {
  450. r.left += r.right;
  451. r.left /= 2;
  452. r.top += r.bottom;
  453. r.top /= 2;
  454. SetCursorPos(r.left, r.top);
  455. }
  456. SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_INITIAL, 0);
  457. SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_RESHOW, 0);
  458. }
  459. #define C_BLAH
  460. #define DO_HELP() \
  461. static HWND hTooltipWnd; \
  462. C_BLAH \
  463. if (uMsg == WM_HELP) { \
  464. HELPINFO *hi=(HELPINFO *)(lParam); \
  465. if (hi->iContextType == HELPINFO_WINDOW) { do_help(hwndDlg,hi->iCtrlId,hTooltipWnd);} \
  466. return TRUE; \
  467. } \
  468. 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); } } \
  469. if (uMsg == WM_DESTROY && IsWindow(hTooltipWnd)) { DestroyWindow(hTooltipWnd); hTooltipWnd=NULL; } \
  470. if (uMsg == WM_INITDIALOG) { \
  471. int x; \
  472. hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,(LPCWSTR)NULL,TTS_ALWAYSTIP|TTS_NOPREFIX, \
  473. CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwndDlg,NULL,GetModuleHandle(NULL),NULL); \
  474. SendMessage(hTooltipWnd,TTM_SETMAXTIPWIDTH,0,587); \
  475. SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,250); \
  476. SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,500); \
  477. for (x = 0; x < sizeof(helpinfo)/sizeof(helpinfo[0]); x ++) { \
  478. TOOLINFO ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND; \
  479. ti.uId=(UINT_PTR)GetDlgItem(hwndDlg,helpinfo[x].id); ti.hwnd=hwndDlg; ti.lpszText=WASABI_API_LNGSTRINGW(helpinfo[x].id2); \
  480. SendMessage(hTooltipWnd,TTM_ADDTOOL,0,(LPARAM) &ti); \
  481. } \
  482. }
  483. static BOOL ListView_OnCustomDraw(HWND hwndDlg, NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
  484. {
  485. static BOOL bDrawFocus;
  486. static RECT rcView;
  487. static CLOUDCOLUMNPAINT cloudColumnPaint;
  488. *pResult = CDRF_DODEFAULT;
  489. switch (plvcd->nmcd.dwDrawStage)
  490. {
  491. case CDDS_PREPAINT:
  492. *pResult |= CDRF_NOTIFYITEMDRAW;
  493. CopyRect(&rcView, &plvcd->nmcd.rc);
  494. cloudColumnPaint.hwndList = plvcd->nmcd.hdr.hwndFrom;
  495. cloudColumnPaint.hdc = plvcd->nmcd.hdc;
  496. cloudColumnPaint.prcView = &rcView;
  497. return TRUE;
  498. case CDDS_ITEMPREPAINT:
  499. *pResult |= CDRF_NOTIFYSUBITEMDRAW;
  500. bDrawFocus = (CDIS_FOCUS & plvcd->nmcd.uItemState);
  501. if (bDrawFocus)
  502. {
  503. plvcd->nmcd.uItemState &= ~CDIS_FOCUS;
  504. *pResult |= CDRF_NOTIFYPOSTPAINT;
  505. }
  506. return TRUE;
  507. case CDDS_ITEMPOSTPAINT:
  508. if (bDrawFocus)
  509. {
  510. RECT rc;
  511. rc.left = LVIR_BOUNDS;
  512. SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&rc);
  513. rc.left += 3;
  514. DrawFocusRect(plvcd->nmcd.hdc, &rc);
  515. plvcd->nmcd.uItemState |= CDIS_FOCUS;
  516. bDrawFocus = FALSE;
  517. }
  518. *pResult = CDRF_SKIPDEFAULT;
  519. return TRUE;
  520. case(CDDS_SUBITEM | CDDS_ITEMPREPAINT):
  521. {
  522. if (aacontents && aacontents->bgThread_Handle || (0 == plvcd->iSubItem && 0 == plvcd->nmcd.rc.right)) break;
  523. cloudColumnPaint.iItem = plvcd->nmcd.dwItemSpec;
  524. cloudColumnPaint.iSubItem = plvcd->iSubItem;
  525. if (plvcd->nmcd.hdr.idFrom == IDC_LIST_TRACKS)
  526. {
  527. if (plvcd->iSubItem == tracks->cloudcol)
  528. {
  529. cloudColumnPaint.value = tracks->cloud_cache[plvcd->nmcd.dwItemSpec];
  530. }
  531. else
  532. break;
  533. }
  534. else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ARTIST)
  535. {
  536. if (plvcd->iSubItem == aacontents->GetFilterList(0)->cloudcol)
  537. {
  538. wchar_t buf[16] = {0};
  539. aacontents->GetFilterList(0)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
  540. cloudColumnPaint.value = _wtoi(buf);
  541. }
  542. else
  543. break;
  544. }
  545. else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ALBUM)
  546. {
  547. if (plvcd->iSubItem == aacontents->GetFilterList(1)->cloudcol)
  548. {
  549. wchar_t buf[16] = {0};
  550. aacontents->GetFilterList(1)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
  551. cloudColumnPaint.value = _wtoi(buf);
  552. }
  553. else
  554. break;
  555. }
  556. else if (plvcd->nmcd.hdr.idFrom == IDC_LIST_ALBUM2)
  557. {
  558. if (plvcd->iSubItem == aacontents->GetFilterList(2)->cloudcol)
  559. {
  560. wchar_t buf[16] = {0};
  561. aacontents->GetFilterList(2)->GetCellText(plvcd->nmcd.dwItemSpec, plvcd->iSubItem, buf, 16);
  562. cloudColumnPaint.value = _wtoi(buf);
  563. }
  564. else
  565. break;
  566. }
  567. cloudColumnPaint.prcItem = &plvcd->nmcd.rc;
  568. cloudColumnPaint.rgbBk = plvcd->clrTextBk;
  569. cloudColumnPaint.rgbFg = plvcd->clrText;
  570. if (MLCloudColumn_Paint(plugin.hwndLibraryParent, &cloudColumnPaint))
  571. {
  572. *pResult = CDRF_SKIPDEFAULT;
  573. return TRUE;
  574. }
  575. }
  576. break;
  577. }
  578. return FALSE;
  579. }
  580. void pmp_common_UpdateButtonText(HWND hwndDlg, int _enqueuedef)
  581. {
  582. if (groupBtn)
  583. {
  584. switch(_enqueuedef)
  585. {
  586. case 1:
  587. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, view.enqueue);
  588. customAllowed = FALSE;
  589. break;
  590. default:
  591. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  592. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  593. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK_IN_USE, (INT_PTR)_enqueuedef, 0, 0};
  594. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  595. if (pszTextW && pszTextW[0] != 0)
  596. {
  597. // set this to be a bit different so we can just use one button and not the
  598. // mixable one as well (leaving that to prevent messing with the resources)
  599. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, pszTextW);
  600. customAllowed = TRUE;
  601. }
  602. else
  603. {
  604. SetDlgItemTextW(hwndDlg, IDC_BUTTON_PLAY, view.play);
  605. customAllowed = FALSE;
  606. }
  607. break;
  608. }
  609. }
  610. }
  611. enum
  612. {
  613. BPM_ECHO_WM_COMMAND=0x1, // send WM_COMMAND and return value
  614. BPM_WM_COMMAND = 0x2, // just send WM_COMMAND
  615. };
  616. BOOL pmp_common_ButtonPopupMenu(HWND hwndDlg, int buttonId, HMENU menu, int flags=0)
  617. {
  618. RECT r;
  619. HWND buttonHWND = GetDlgItem(hwndDlg, buttonId);
  620. GetWindowRect(buttonHWND, &r);
  621. MLSkinnedButton_SetDropDownState(buttonHWND, TRUE);
  622. UINT tpmFlags = TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_BOTTOMALIGN | TPM_LEFTALIGN;
  623. if (!(flags & BPM_WM_COMMAND))
  624. tpmFlags |= TPM_RETURNCMD;
  625. int x = Menu_TrackSkinnedPopup(menu, tpmFlags, r.left, r.top, hwndDlg, NULL);
  626. if ((flags & BPM_ECHO_WM_COMMAND) && x)
  627. SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(x, 0), 0);
  628. MLSkinnedButton_SetDropDownState(buttonHWND, FALSE);
  629. return x;
  630. }
  631. static void pmp_common_PlayEnqueue(HWND hwndDlg, HWND from, UINT idFrom)
  632. {
  633. HMENU listMenu = GetSubMenu(m_context_menus2, 0);
  634. int count = GetMenuItemCount(listMenu);
  635. if (count > 2)
  636. {
  637. for (int i = 2; i < count; i++)
  638. {
  639. DeleteMenu(listMenu, 2, MF_BYPOSITION);
  640. }
  641. }
  642. pmp_common_ButtonPopupMenu(hwndDlg, idFrom, listMenu, BPM_WM_COMMAND);
  643. }
  644. static BOOL restoreDone;
  645. INT_PTR CALLBACK pmp_artistalbum_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
  646. hi helpinfo[]={
  647. {IDC_BUTTON_ARTMODE,IDS_AUDIO_BUTTON_TT1},
  648. {IDC_BUTTON_VIEWMODE,IDS_AUDIO_BUTTON_TT2},
  649. {IDC_BUTTON_COLUMNS,IDS_AUDIO_BUTTON_TT3},
  650. };
  651. DO_HELP();
  652. if(hwndMediaView != hwndDlg && uMsg != WM_INITDIALOG) return 0;
  653. if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; }
  654. if (artistList) { BOOL a=artistList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  655. if (albumList) { BOOL a=albumList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  656. if (albumList2) { BOOL a=albumList2->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  657. if (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  658. switch (uMsg) {
  659. case WM_INITDIALOG:
  660. {
  661. if (!view.play)
  662. {
  663. SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
  664. }
  665. groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
  666. enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 1);
  667. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  668. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  669. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG(IDC_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
  670. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  671. if (pszTextW && pszTextW[0] != 0)
  672. {
  673. // set this to be a bit different so we can just use one button and not the
  674. // mixable one as well (leaving that to prevent messing with the resources)
  675. customAllowed = TRUE;
  676. SetDlgItemTextW(hwndDlg, IDC_BUTTON_CUSTOM, pszTextW);
  677. }
  678. else
  679. {
  680. customAllowed = FALSE;
  681. }
  682. restoreDone = FALSE;
  683. playmode = L"viewplaymode";
  684. hwndMediaView = hwndDlg;
  685. *(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC);
  686. *(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC);
  687. if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
  688. header = 1;
  689. else
  690. header = currentViewedDevice->config->ReadInt(L"header",0);
  691. numFilters = currentViewedDevice->config->ReadInt(L"media_numfilters",2);
  692. if(numFilters != 3 && numFilters != 2) numFilters=2;
  693. wchar_t filters[300] = {0}, *filtersp[3] = {0};
  694. bool artfilter[3]={false,false,false};
  695. for(int i = 0; i < numFilters; i++) {
  696. filtersp[i]=&filters[i*100];
  697. wchar_t name[20] = {0};
  698. wsprintf(name,L"media_filter%d",i);
  699. lstrcpyn(filtersp[i],currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters)),100);
  700. if(!_wcsicmp(filtersp[i],L"Album Art")) artfilter[i]=true;
  701. }
  702. aacontents = new ArtistAlbumLists(currentViewedDevice->dev, currentViewedPlaylist, currentViewedDevice->config, filtersp,
  703. numFilters, (currentViewedDevice->videoView ? 0 : -1), (!!currentViewedDevice->isCloudDevice));
  704. if (!artfilter[0]) artistList = new SkinnedListView(aacontents->GetFilterList(0),IDC_LIST_ARTIST,plugin.hwndLibraryParent, hwndDlg, false);
  705. else artistList = new AlbumArtListView(aacontents->GetFilterList(0),IDC_LIST_ARTIST,plugin.hwndLibraryParent, hwndDlg, false);
  706. artistList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
  707. artistList->InitializeFilterData(0, currentViewedDevice->config);
  708. if (!artfilter[1]) albumList = new SkinnedListView(aacontents->GetFilterList(1),IDC_LIST_ALBUM,plugin.hwndLibraryParent, hwndDlg, false);
  709. else albumList = new AlbumArtListView(aacontents->GetFilterList(1),IDC_LIST_ALBUM,plugin.hwndLibraryParent, hwndDlg, false);
  710. albumList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
  711. albumList->InitializeFilterData(1, currentViewedDevice->config);
  712. if (numFilters == 3) {
  713. if(!artfilter[2]) albumList2 = new SkinnedListView(aacontents->GetFilterList(2),IDC_LIST_ALBUM2,plugin.hwndLibraryParent, hwndDlg, false);
  714. else albumList2 = new AlbumArtListView(aacontents->GetFilterList(2),IDC_LIST_ALBUM2,plugin.hwndLibraryParent, hwndDlg, false);
  715. albumList2->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
  716. albumList2->InitializeFilterData(2, currentViewedDevice->config);
  717. }
  718. if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
  719. {
  720. SetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, currentViewedDevice->config->ReadString(L"savedfilter", L""));
  721. SetDlgItemTextW(hwndDlg, IDC_REFINE, currentViewedDevice->config->ReadString(L"savedrefinefilter", L""));
  722. }
  723. else
  724. restoreDone = TRUE;
  725. HWND list = GetDlgItem(hwndDlg, IDC_LIST_TRACKS);
  726. // TODO need to be able to change the order of the tracks items (so cloud is in a more appropriate place)
  727. //ListView_SetExtendedListViewStyleEx(list, LVS_EX_HEADERDRAGDROP, LVS_EX_HEADERDRAGDROP);
  728. ListView_SetExtendedListViewStyle(list, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
  729. MLSKINWINDOW skin = {0};
  730. skin.hwndToSkin = list;
  731. skin.skinType = SKINNEDWND_TYPE_LISTVIEW;
  732. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  733. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  734. skin.hwndToSkin = artistList->listview.getwnd();
  735. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  736. skin.hwndToSkin = albumList->listview.getwnd();
  737. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  738. if (numFilters == 3) {
  739. skin.hwndToSkin = albumList2->listview.getwnd();
  740. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  741. }
  742. if(!currentViewedDevice->config->ReadInt(L"media_scroll_0",0))
  743. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,artistList->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
  744. if(!currentViewedDevice->config->ReadInt(L"media_scroll_1",0))
  745. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,albumList->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
  746. if(numFilters == 3 && !currentViewedDevice->config->ReadInt(L"media_scroll_2",0))
  747. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,albumList2->skinlistview_handle,ML_IPC_LISTVIEW_DISABLEHSCROLL);
  748. if (aacontents)
  749. {
  750. artistList->UpdateList();
  751. tracks = aacontents->GetTracksList();
  752. }
  753. adiv1pos = numFilters == 3?33333:50000;
  754. adiv3pos = numFilters == 3?66667:0;
  755. adiv2pos = 50000;
  756. adiv1pos = currentViewedDevice->config->ReadInt(L"adiv1pos",adiv1pos);
  757. if(numFilters == 3) adiv3pos = currentViewedDevice->config->ReadInt(L"adiv3pos",adiv3pos);
  758. adiv2pos = currentViewedDevice->config->ReadInt(L"adiv2pos",adiv2pos);
  759. if(numFilters == 3 && adiv1pos>adiv3pos) {
  760. adiv1pos=33333;
  761. adiv3pos=66667;
  762. }
  763. AttachDivider(GetDlgItem(hwndDlg, IDC_VDELIM), TRUE, OnDividerMoved, IDC_VDELIM);
  764. if(numFilters == 3) AttachDivider(GetDlgItem(hwndDlg, IDC_VDELIM2), TRUE, OnDividerMoved, IDC_VDELIM2);
  765. AttachDivider(GetDlgItem(hwndDlg, IDC_HDELIM), FALSE, OnDividerMoved, IDC_HDELIM);
  766. int fieldsBits = (int)currentViewedDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
  767. if(!fieldsBits) fieldsBits = -1;
  768. if(!(fieldsBits & SUPPORTS_ALBUMART))
  769. SetWindowPos(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),0,0,0,0,0,0); // get rid of art mode button if we don't support albumart
  770. FLICKERFIX ff = {0};
  771. ff.mode = FFM_ERASEINPAINT;
  772. skin.skinType = SKINNEDWND_TYPE_AUTO;
  773. INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM,
  774. IDC_BUTTON_CLEARSEARCH, IDC_BUTTON_CLEARREFINE,
  775. IDC_BUTTON_EJECT, IDC_BUTTON_SYNC, IDC_BUTTON_AUTOFILL,
  776. IDC_STATUS, IDC_SEARCH_TEXT, IDC_QUICKSEARCH, IDC_REFINE,
  777. IDC_REFINE_TEXT, IDC_BUTTON_ARTMODE, IDC_BUTTON_VIEWMODE,
  778. IDC_BUTTON_COLUMNS,
  779. // disabled cloud parts
  780. /*IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME, IDC_HEADER_DEVICE_BAR,
  781. IDC_HEADER_DEVICE_SIZE, IDC_HEADER_DEVICE_TRANSFER,*/
  782. };
  783. for (int i = 0; i < ARRAYSIZE(ffcl); i++)
  784. {
  785. ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
  786. if (IsWindow(ff.hwnd))
  787. {
  788. SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
  789. // skip the mode buttons
  790. if (i < 13)
  791. {
  792. if (i < 3)
  793. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn ? SWBS_SPLITBUTTON : 0);
  794. else
  795. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  796. skin.hwndToSkin = ff.hwnd;
  797. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  798. }
  799. }
  800. }
  801. if (0 != currentViewedDevice->dev->extraActions(DEVICE_SYNC_UNSUPPORTED,0,0,0))
  802. EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC), FALSE);
  803. skin.hwndToSkin = hwndDlg;
  804. skin.skinType = SKINNEDWND_TYPE_AUTO;
  805. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  806. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  807. // do this now to get the cloud columns correctly known (doesn't work correctly if done before the skinning is setup)
  808. MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_TRACKS)), tracks->cloudcol);
  809. MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ARTIST)), artistList->contents->cloudcol);
  810. MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ALBUM)), albumList->contents->cloudcol);
  811. if (numFilters == 3) MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(GetDlgItem(hwndDlg, IDC_LIST_ALBUM2)), albumList2->contents->cloudcol);
  812. g_displayrefine = !!(gen_mlconfig->ReadInt(L"audiorefine", 0));
  813. adiv1_nodraw=0;
  814. adiv3_nodraw=0;
  815. m_nodrawtopborders=0;
  816. PostMessage(hwndDlg, WM_DISPLAYCHANGE, 0, 0);
  817. break;
  818. }
  819. case WM_DISPLAYCHANGE:
  820. {
  821. int (*wad_getColor)(int idx);
  822. *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
  823. ARGB32 fc = (wad_getColor?wad_getColor(WADLG_BUTTONFG):RGB(0xFF,0xFF,0xFF)) & 0x00FFFFFF;
  824. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_ARTMODE, MAKEINTRESOURCE(IDR_TOOL_ALBUMART_ICON),fc);
  825. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_VIEWMODE, MAKEINTRESOURCE(IDR_TOOL_VIEWMODE_ICON),fc);
  826. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_COLUMNS, MAKEINTRESOURCE(IDR_TOOL_COLUMNS_ICON),fc);
  827. UpdateWindow(hwndDlg);
  828. LayoutWindows(hwndDlg, TRUE, 0);
  829. }
  830. break;
  831. case WM_DROPFILES:
  832. return currentViewedDevice->TransferFromDrop((HDROP)wParam);
  833. case WM_DESTROY:
  834. if (aacontents) aacontents->bgQuery_Stop();
  835. currentViewedDevice->config->WriteInt(L"adiv1pos",adiv1pos);
  836. if(numFilters == 3) currentViewedDevice->config->WriteInt(L"adiv3pos",adiv3pos);
  837. currentViewedDevice->config->WriteInt(L"adiv2pos",adiv2pos);
  838. tracks=NULL;
  839. hwndMediaView=NULL;
  840. if (albumList) delete albumList; albumList=NULL;
  841. if (artistList) delete artistList; artistList=NULL;
  842. if (albumList2) delete albumList2; albumList2=NULL;
  843. if (aacontents) delete aacontents; aacontents=NULL;
  844. {
  845. SkinBitmap *s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),GWLP_USERDATA);
  846. DeleteSkinBitmap(s);
  847. s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),GWLP_USERDATA);
  848. DeleteSkinBitmap(s);
  849. s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),GWLP_USERDATA);
  850. DeleteSkinBitmap(s);
  851. }
  852. break;
  853. case WM_DRAWITEM:
  854. {
  855. DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
  856. if (di->CtlType == ODT_BUTTON) {
  857. if(di->CtlID == IDC_BUTTON_ARTMODE || di->CtlID == IDC_BUTTON_VIEWMODE || di->CtlID == IDC_BUTTON_COLUMNS)
  858. { // draw the toolbar buttons!
  859. SkinBitmap* hbm = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,di->CtlID),GWLP_USERDATA);
  860. if(hbm && di->rcItem.left != di->rcItem.right && di->rcItem.top != di->rcItem.bottom) {
  861. DCCanvas dc(di->hDC);
  862. if (di->itemState & ODS_SELECTED) hbm->blitAlpha(&dc,di->rcItem.left+6,di->rcItem.top+5);
  863. else hbm->blitAlpha(&dc,di->rcItem.left+4,di->rcItem.top+3);
  864. }
  865. }
  866. }
  867. }
  868. break;
  869. case WM_SETCURSOR:
  870. case WM_LBUTTONDOWN:
  871. {
  872. static INT id[] = { IDC_VDELIM, IDC_HDELIM, IDC_VDELIM2 };
  873. RECT rw;
  874. POINT pt;
  875. GetCursorPos(&pt);
  876. for (INT i = 0; i < sizeof(id)/sizeof(INT); i++)
  877. {
  878. HWND hwndDiv = GetDlgItem(hwndDlg, id[i]);
  879. if (!hwndDiv) continue;
  880. GetWindowRect(hwndDiv, &rw);
  881. if (PtInRect(&rw, pt))
  882. {
  883. if (WM_SETCURSOR == uMsg)
  884. {
  885. SetCursor(LoadCursor(NULL, (IDC_VDELIM == id[i] || IDC_VDELIM2 == id[i]) ? IDC_SIZEWE : IDC_SIZENS));
  886. return TRUE;
  887. }
  888. else
  889. {
  890. SendMessage(hwndDiv, uMsg, wParam, MAKELPARAM(pt.x - rw.left, pt.y - rw.top));
  891. return TRUE;
  892. }
  893. }
  894. }
  895. }
  896. break;
  897. case WM_WINDOWPOSCHANGED:
  898. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  899. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  900. {
  901. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags), 0);
  902. }
  903. return TRUE;
  904. case WM_PAINT:
  905. {
  906. int tab[] = {(m_nodrawtopborders==2)?0:(IDC_LIST_TRACKS|DCW_SUNKENBORDER),
  907. IDC_QUICKSEARCH|DCW_SUNKENBORDER,
  908. (refineHidden!=0)?0:(IDC_REFINE|DCW_SUNKENBORDER),
  909. IDC_HDELIM|DCW_DIVIDER,
  910. (!header?IDC_HDELIM2|DCW_DIVIDER:0),
  911. IDC_VDELIM|DCW_DIVIDER,
  912. numFilters == 3?IDC_VDELIM2|DCW_DIVIDER:0,
  913. adiv1_nodraw==1?0:(IDC_LIST_ARTIST|DCW_SUNKENBORDER),
  914. (adiv1_nodraw==2 || adiv3_nodraw==1)?0:(IDC_LIST_ALBUM|DCW_SUNKENBORDER),
  915. (numFilters != 3 || adiv3_nodraw==2)?0:(IDC_LIST_ALBUM2|DCW_SUNKENBORDER)};
  916. int size = sizeof(tab) / sizeof(tab[0]);
  917. // do this to prevent drawing parts when the views are collapsed
  918. if (m_nodrawtopborders==1) size -= 6;
  919. if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
  920. }
  921. return TRUE;
  922. case WM_ERASEBKGND:
  923. return 1;
  924. case WM_USER:
  925. {
  926. if (aacontents && aacontents->bgThread_Handle) break;
  927. if (aacontents)
  928. {
  929. SkinnedListView * lists[3]={artistList,albumList,albumList2};
  930. aacontents->SelectionChanged(wParam==IDC_LIST_ARTIST?0:(wParam==IDC_LIST_ALBUM?1:2),lists);
  931. }
  932. noSearchTimer=true;
  933. SetDlgItemText(hwndDlg,IDC_REFINE,L"");
  934. noSearchTimer=false;
  935. UpdateStatus(hwndDlg);
  936. wParam=0;
  937. }
  938. // run through
  939. case WM_USER+2:
  940. if (tracksList) tracksList->UpdateList(wParam==1);
  941. break;
  942. case WM_USER+1:
  943. if (tracks) tracks->RemoveTrack((songid_t)wParam);
  944. if (aacontents) aacontents->RemoveTrack((songid_t)wParam);
  945. break;
  946. case WM_NOTIFY:
  947. {
  948. LPNMHDR l=(LPNMHDR)lParam;
  949. if(l->idFrom==IDC_LIST_ARTIST || l->idFrom==IDC_LIST_ALBUM || l->idFrom==IDC_LIST_ALBUM2)
  950. {
  951. switch(l->code) {
  952. case LVN_ITEMCHANGED:
  953. {
  954. LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam;
  955. if ((lv->uNewState ^ lv->uOldState) & LVIS_SELECTED) {
  956. PostMessage(hwndDlg,WM_USER,l->idFrom,0);
  957. }
  958. }
  959. break;
  960. case NM_RETURN:
  961. case NM_DBLCLK: // play some songs!
  962. {
  963. C_ItemList * items = getSelectedItems(true);
  964. currentViewedDevice->PlayTracks(items, 0, (!(GetAsyncKeyState(VK_SHIFT)&0x8000) ? (enqueuedef == 1) : (enqueuedef != 1)), false);
  965. delete items;
  966. break;
  967. }
  968. case LVN_KEYDOWN:
  969. switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
  970. case VK_DELETE:
  971. {
  972. if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  973. handleContextMenuResult(ID_TRACKSLIST_DELETE);
  974. }
  975. }
  976. break;
  977. case 0x43: //C
  978. if(GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  979. handleContextMenuResult(ID_TRACKSLIST_COPYTOLIBRARY);
  980. }
  981. break;
  982. }
  983. break;
  984. }
  985. }
  986. else if(l->idFrom == IDC_LIST_TRACKS)
  987. {
  988. switch(l->code) {
  989. case LVN_KEYDOWN:
  990. switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
  991. case VK_DELETE:
  992. {
  993. if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  994. handleContextMenuResult(ID_TRACKSLIST_DELETE);
  995. }
  996. }
  997. break;
  998. case 0x45: //E
  999. bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
  1000. if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  1001. C_ItemList * items = getSelectedItems();
  1002. editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
  1003. delete items;
  1004. }
  1005. break;
  1006. }
  1007. break;
  1008. }
  1009. }
  1010. }
  1011. break;
  1012. case WM_APP + 3: // send by bgthread
  1013. if (wParam == 0x69)
  1014. {
  1015. if (aacontents)
  1016. {
  1017. aacontents->bgQuery_Stop();
  1018. tracks = aacontents->GetTracksList();
  1019. if (artistList) artistList->UpdateList();
  1020. if (albumList) albumList->UpdateList();
  1021. if (albumList2) albumList2->UpdateList();
  1022. if (tracksList) tracksList->UpdateList();
  1023. UpdateStatus(hwndDlg, true);
  1024. }
  1025. }
  1026. break;
  1027. case WM_APP + 104:
  1028. {
  1029. pmp_common_UpdateButtonText(hwndDlg, wParam);
  1030. LayoutWindows(hwndDlg, TRUE, 0);
  1031. return 0;
  1032. }
  1033. case WM_TIMER:
  1034. switch(wParam) {
  1035. case 123:
  1036. {
  1037. if (aacontents && aacontents->bgThread_Handle)
  1038. {
  1039. HWND hwndList;
  1040. hwndList = tracksList->listview.getwnd();
  1041. if (1 != ListView_GetItemCount(hwndList)) ListView_SetItemCountEx(hwndList, 1, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
  1042. ListView_RedrawItems(hwndList, 0, 0);
  1043. }
  1044. }
  1045. break;
  1046. case 400:
  1047. KillTimer(hwndDlg,400);
  1048. currentViewedDevice->config->WriteInt(L"adiv1pos",adiv1pos);
  1049. if(numFilters == 3) currentViewedDevice->config->WriteInt(L"adiv3pos",adiv3pos);
  1050. currentViewedDevice->config->WriteInt(L"adiv2pos",adiv2pos);
  1051. break;
  1052. case 500:
  1053. {
  1054. KillTimer(hwndDlg,500);
  1055. wchar_t buf[256]=L"";
  1056. GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf)/sizeof(wchar_t));
  1057. noSearchTimer=true;
  1058. if (restoreDone) SetDlgItemText(hwndDlg,IDC_REFINE,L"");
  1059. noSearchTimer=false;
  1060. aacontents->SetSearch(buf, (!!currentViewedDevice->isCloudDevice));
  1061. if (!aacontents->bgThread_Handle)
  1062. {
  1063. if (artistList) artistList->UpdateList();
  1064. if (albumList) albumList->UpdateList();
  1065. if (albumList2) albumList2->UpdateList();
  1066. if (tracksList) tracksList->UpdateList();
  1067. UpdateStatus(hwndDlg);
  1068. }
  1069. if (!restoreDone)
  1070. {
  1071. restoreDone = TRUE;
  1072. KillTimer(hwndDlg,501);
  1073. SetTimer(hwndDlg,501,250,NULL);
  1074. }
  1075. }
  1076. break;
  1077. case 501:
  1078. {
  1079. KillTimer(hwndDlg,501);
  1080. wchar_t buf[256]=L"";
  1081. GetDlgItemText(hwndDlg,IDC_REFINE,buf,sizeof(buf)/sizeof(wchar_t));
  1082. aacontents->SetRefine(buf, (!!currentViewedDevice->isCloudDevice));
  1083. if (!aacontents->bgThread_Handle)
  1084. {
  1085. if (tracksList) tracksList->UpdateList();
  1086. UpdateStatus(hwndDlg);
  1087. }
  1088. }
  1089. break;
  1090. }
  1091. break;
  1092. case WM_MOUSEMOVE:
  1093. if(wParam==MK_LBUTTON) {
  1094. if(GetCapture() == hwndDlg) ReleaseCapture();
  1095. }
  1096. break;
  1097. case WM_COMMAND:
  1098. switch(LOWORD(wParam)) {
  1099. case IDC_BUTTON_ARTMODE:
  1100. {
  1101. int changed=0;
  1102. for(int i=0; i<3; i++) {
  1103. wchar_t name[20] = {0};
  1104. wsprintf(name,L"media_filter%d",i);
  1105. wchar_t * str = currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters));
  1106. if(!_wcsicmp(str,L"Album")) { currentViewedDevice->config->WriteString(name,L"Album Art"); changed=1; }
  1107. else if(!_wcsicmp(str,L"Album Art")) { currentViewedDevice->config->WriteString(name,L"Album"); changed=1; }
  1108. }
  1109. if (changed) PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
  1110. }
  1111. break;
  1112. case IDC_BUTTON_VIEWMODE:
  1113. {
  1114. struct {
  1115. const wchar_t *name;
  1116. int numfilters;
  1117. wchar_t* f[3];
  1118. int requiredFields;
  1119. } presets[] = {
  1120. {0,2,{L"Artist",L"Album"},0},
  1121. {0,2,{L"Artist",L"Album Art"},SUPPORTS_ALBUMART},
  1122. {0,2,{L"Album Artist",L"Album"},SUPPORTS_ALBUMARTIST},
  1123. {0,2,{L"Album Artist",L"Album Art"},SUPPORTS_ALBUMARTIST | SUPPORTS_ALBUMART},
  1124. {0,3,{L"Genre",L"Artist",L"Album"},SUPPORTS_GENRE | SUPPORTS_ALBUMART},
  1125. {0,2,{L"Genre",L"Album Art"},SUPPORTS_GENRE},
  1126. {0,3,{L"Year",L"Artist",L"Album"},SUPPORTS_YEAR},
  1127. {0,2,{L"Composer",L"Album"},SUPPORTS_COMPOSER},
  1128. {0,3,{L"Publisher",L"Artist",L"Album"},SUPPORTS_PUBLISHER},
  1129. };
  1130. HMENU menu = CreatePopupMenu();
  1131. int fieldsBits = (int)currentViewedDevice->dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
  1132. if(!fieldsBits) fieldsBits = -1;
  1133. bool checked=false;
  1134. wchar_t filters[300] = {0};
  1135. wchar_t *filtersp[3] = {0};
  1136. for(int i=0; i<numFilters; i++) {
  1137. filtersp[i]=&filters[i*100];
  1138. wchar_t name[20] = {0};
  1139. wsprintf(name,L"media_filter%d",i);
  1140. lstrcpyn(filtersp[i],currentViewedDevice->config->ReadString(name,GetDefFilter(i,numFilters)),100);
  1141. }
  1142. for(int i=0; i < sizeof(presets)/sizeof(presets[0]); i++) {
  1143. if(!presets[i].requiredFields || (presets[i].requiredFields & fieldsBits) == presets[i].requiredFields) {
  1144. wchar_t buf[350] = {0};
  1145. if(!presets[i].name) {
  1146. wchar_t a[100] = {0}, b[100] = {0}, c[100] = {0};
  1147. localizeFilter(presets[i].f[0],a,100);
  1148. localizeFilter(presets[i].f[1],b,100);
  1149. if(presets[i].numfilters == 3) localizeFilter(presets[i].f[2],c,100);
  1150. if(presets[i].numfilters == 3) wsprintf(buf,L"%s/%s/%s",a,b,c);
  1151. else wsprintf(buf,L"%s/%s",a,b);
  1152. }
  1153. AppendMenu(menu,MF_STRING,i+1,presets[i].name?presets[i].name:buf);
  1154. 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])))
  1155. { // this is our view...
  1156. CheckMenuItem(menu,i+1,MF_CHECKED);
  1157. checked=true;
  1158. }
  1159. }
  1160. }
  1161. AppendMenu(menu,MF_STRING,0x4000,WASABI_API_LNGSTRINGW(IDS_OTHER2));
  1162. if(!checked)
  1163. CheckMenuItem(menu,0x4000,MF_CHECKED);
  1164. RECT rc;
  1165. GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),&rc);
  1166. int r = Menu_TrackSkinnedPopup(menu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,rc.left,rc.bottom,hwndDlg,NULL);
  1167. DestroyMenu(menu);
  1168. if(r==0) break;
  1169. else if(r == 0x4000) {
  1170. extern int g_prefs_openpage;
  1171. g_prefs_openpage = (!currentViewedDevice->isCloudDevice ? 4 : 0);
  1172. SendMessage(plugin.hwndWinampParent, WM_WA_IPC,(WPARAM)&currentViewedDevice->devPrefsPage,IPC_OPENPREFSTOPAGE);
  1173. extern HWND m_hwndTab;
  1174. if (IsWindow(m_hwndTab))
  1175. {
  1176. TabCtrl_SetCurSel(m_hwndTab, g_prefs_openpage);
  1177. extern HWND OnSelChanged(HWND hwndDlg, HWND external = NULL, DeviceView *dev = NULL);
  1178. OnSelChanged(GetParent(m_hwndTab));
  1179. }
  1180. }
  1181. else {
  1182. r--;
  1183. for(int j=0; j<presets[r].numfilters; j++) {
  1184. wchar_t name[20] = {0};
  1185. wsprintf(name,L"media_filter%d",j);
  1186. currentViewedDevice->config->WriteString(name,presets[r].f[j]);
  1187. }
  1188. currentViewedDevice->config->WriteInt(L"media_numfilters",presets[r].numfilters);
  1189. PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
  1190. }
  1191. }
  1192. break;
  1193. case IDC_BUTTON_COLUMNS:
  1194. {
  1195. HMENU themenu1 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1196. HMENU themenu2 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1197. HMENU themenu3 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1198. HMENU themenu4 = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1199. HMENU menu = CreatePopupMenu();
  1200. MENUITEMINFO m={sizeof(m),MIIM_TYPE | MIIM_ID | MIIM_SUBMENU,MFT_STRING,0};
  1201. wchar_t a[100] = {0}, b[100] = {0}, c[100] = {0};
  1202. localizeFilter(currentViewedDevice->config->ReadString(L"media_filter0",GetDefFilter(0,numFilters)),a,100);
  1203. localizeFilter(currentViewedDevice->config->ReadString(L"media_filter1",GetDefFilter(1,numFilters)),b,100);
  1204. localizeFilter(currentViewedDevice->config->ReadString(L"media_filter2",GetDefFilter(2,numFilters)),c,100);
  1205. wchar_t * d = WASABI_API_LNGSTRINGW(IDS_TRACKS);
  1206. m.wID = 0;
  1207. m.dwTypeData = a;
  1208. m.hSubMenu = artistList->GetMenu(true,0,currentViewedDevice->config,themenu1);
  1209. InsertMenuItem(menu,0,FALSE,&m);
  1210. m.wID = 1;
  1211. m.dwTypeData = b;
  1212. m.hSubMenu = albumList->GetMenu(true,1,currentViewedDevice->config,themenu2);
  1213. InsertMenuItem(menu,1,FALSE,&m);
  1214. if(numFilters == 3) {
  1215. m.wID = 2;
  1216. m.dwTypeData = c;
  1217. m.hSubMenu = albumList2->GetMenu(true,2,currentViewedDevice->config,themenu3);
  1218. InsertMenuItem(menu,2,FALSE,&m);
  1219. }
  1220. m.wID = 3;
  1221. m.dwTypeData = d;
  1222. m.hSubMenu = tracksList->GetMenu(false,0,currentViewedDevice->config,themenu4);
  1223. InsertMenuItem(menu,3,FALSE,&m);
  1224. RECT rc;
  1225. GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),&rc);
  1226. int r = Menu_TrackSkinnedPopup(menu,TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,rc.left,rc.bottom,hwndDlg,NULL);
  1227. artistList->ProcessMenuResult(r,true,0,currentViewedDevice->config,hwndDlg);
  1228. albumList->ProcessMenuResult(r,true,1,currentViewedDevice->config,hwndDlg);
  1229. if(numFilters == 3) albumList2->ProcessMenuResult(r,true,2,currentViewedDevice->config,hwndDlg);
  1230. tracksList->ProcessMenuResult(r,false,0,currentViewedDevice->config,hwndDlg);
  1231. DestroyMenu(menu);
  1232. DestroyMenu(themenu1);
  1233. DestroyMenu(themenu2);
  1234. DestroyMenu(themenu3);
  1235. DestroyMenu(themenu4);
  1236. }
  1237. break;
  1238. case IDC_QUICKSEARCH:
  1239. if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
  1240. KillTimer(hwndDlg, 500);
  1241. SetTimer(hwndDlg, 500, 350, NULL);
  1242. HWND hwndList = artistList->listview.getwnd();
  1243. if (IsWindow(hwndList))
  1244. {
  1245. ListView_SetItemCountEx(hwndList, 0, 0);
  1246. ListView_RedrawItems(hwndList, 0, 0);
  1247. }
  1248. hwndList = albumList->listview.getwnd();
  1249. if (IsWindow(hwndList))
  1250. {
  1251. ListView_SetItemCountEx(hwndList, 0, 0);
  1252. ListView_RedrawItems(hwndList, 0, 0);
  1253. }
  1254. if (numFilters == 3)
  1255. {
  1256. hwndList = albumList2->listview.getwnd();
  1257. if (IsWindow(hwndList))
  1258. {
  1259. ListView_SetItemCountEx(hwndList, 0, 0);
  1260. ListView_RedrawItems(hwndList, 0, 0);
  1261. }
  1262. }
  1263. }
  1264. break;
  1265. case IDC_REFINE:
  1266. if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
  1267. KillTimer(hwndDlg,501);
  1268. SetTimer(hwndDlg,501,250,NULL);
  1269. }
  1270. break;
  1271. case IDC_BUTTON_CLEARSEARCH:
  1272. {
  1273. SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,L"");
  1274. break;
  1275. }
  1276. case IDC_BUTTON_CLEARREFINE:
  1277. SetDlgItemText(hwndDlg,IDC_REFINE,L"");
  1278. break;
  1279. case IDC_HEADER_DEVICE_TRANSFER:
  1280. {
  1281. if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC)))
  1282. {
  1283. MessageBox(hwndDlg, L"Transferring files from this device to another is not currently supported.",
  1284. L"Cloud Transfer Not Supported", MB_ICONINFORMATION);
  1285. break;
  1286. }
  1287. }
  1288. case IDC_BUTTON_SYNC:
  1289. if (!currentViewedDevice->isCloudDevice)
  1290. currentViewedDevice->Sync();
  1291. else
  1292. currentViewedDevice->CloudSync();
  1293. break;
  1294. case IDC_BUTTON_AUTOFILL:
  1295. currentViewedDevice->Autofill();
  1296. break;
  1297. case IDC_SEARCH_TEXT:
  1298. if (HIWORD(wParam) == STN_DBLCLK)
  1299. {
  1300. // TODO decide what to do for the 'all_sources'
  1301. if (currentViewedDevice->isCloudDevice &&
  1302. lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
  1303. {
  1304. header = !header;
  1305. currentViewedDevice->config->WriteInt(L"header",header);
  1306. LayoutWindows(hwndMediaView, TRUE, 0);
  1307. UpdateStatus(hwndDlg, true);
  1308. ShowWindow(hwndDlg, 0);
  1309. ShowWindow(hwndDlg, 1);
  1310. }
  1311. }
  1312. break;
  1313. }
  1314. break;
  1315. case WM_USER + 0x200:
  1316. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); // yes, we support no - redraw resize
  1317. return TRUE;
  1318. case WM_USER + 0x201:
  1319. offsetX = (short)LOWORD(wParam);
  1320. offsetY = (short)HIWORD(wParam);
  1321. g_rgnUpdate = (HRGN)lParam;
  1322. return TRUE;
  1323. }
  1324. return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
  1325. }
  1326. static void getStars(int stars, wchar_t * buf, int buflen) {
  1327. wchar_t * r=L"";
  1328. switch(stars) {
  1329. case 1: r=L"\u2605"; break;
  1330. case 2: r=L"\u2605\u2605"; break;
  1331. case 3: r=L"\u2605\u2605\u2605"; break;
  1332. case 4: r=L"\u2605\u2605\u2605\u2605"; break;
  1333. case 5: r=L"\u2605\u2605\u2605\u2605\u2605"; break;
  1334. }
  1335. lstrcpyn(buf,r,buflen);
  1336. }
  1337. __inline void TimetToFileTime(time_t t, LPFILETIME pft)
  1338. {
  1339. LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
  1340. pft->dwLowDateTime = (DWORD) ll;
  1341. pft->dwHighDateTime = ll >>32;
  1342. }
  1343. void timeToString(__time64_t time, wchar_t * buf, int buflen) {
  1344. if((__int64)time<=0) { lstrcpyn(buf,L"",buflen); return; }
  1345. FILETIME ft = {0};
  1346. SYSTEMTIME st = {0};
  1347. TimetToFileTime(time, &ft);
  1348. FileTimeToSystemTime(&ft, &st);
  1349. int adjust = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buf, buflen);
  1350. buf[adjust-1] = ' ';
  1351. GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &st, NULL, &buf[adjust], buflen - adjust);
  1352. }
  1353. extern void GetInfoString(wchar_t * buf, Device * dev, int numTracks, __int64 totalSize, int totalPlayLength, int cloud);
  1354. class PlaylistContents : public PrimaryListContents {
  1355. public:
  1356. int playlistId;
  1357. Device * dev;
  1358. PlaylistContents(int playlistId, Device * dev) {
  1359. this->playlistId = playlistId;
  1360. this->dev = dev;
  1361. int fieldsBits = (int)dev->extraActions(DEVICE_SUPPORTED_METADATA,0,0,0);
  1362. if(!fieldsBits) fieldsBits = -1;
  1363. C_Config *c = currentViewedDevice->config;
  1364. this->config = c;
  1365. fields.Add(new ListField(-1,20, WASABI_API_LNGSTRINGW(IDS_NUMBER),c));
  1366. if(fieldsBits & SUPPORTS_ARTIST) fields.Add(new ListField(1000, 200,WASABI_API_LNGSTRINGW(IDS_ARTIST),c));
  1367. if(fieldsBits & SUPPORTS_TITLE) fields.Add(new ListField(1001, 200,WASABI_API_LNGSTRINGW(IDS_TITLE),c));
  1368. if(fieldsBits & SUPPORTS_ALBUM) fields.Add(new ListField(1002, 200,WASABI_API_LNGSTRINGW(IDS_ALBUM),c));
  1369. if(fieldsBits & SUPPORTS_LENGTH) fields.Add(new ListField(1003, 64, WASABI_API_LNGSTRINGW(IDS_LENGTH),c));
  1370. if(fieldsBits & SUPPORTS_TRACKNUM) fields.Add(new ListField(1004, 50, WASABI_API_LNGSTRINGW(IDS_TRACK_NUMBER),c));
  1371. if(fieldsBits & SUPPORTS_DISCNUM) fields.Add(new ListField(1005, 38, WASABI_API_LNGSTRINGW(IDS_DISC),c));
  1372. if(fieldsBits & SUPPORTS_GENRE) fields.Add(new ListField(1006, 100,WASABI_API_LNGSTRINGW(IDS_GENRE),c));
  1373. if(fieldsBits & SUPPORTS_YEAR) fields.Add(new ListField(1007, 38, WASABI_API_LNGSTRINGW(IDS_YEAR),c));
  1374. if(fieldsBits & SUPPORTS_BITRATE) fields.Add(new ListField(1008, 45, WASABI_API_LNGSTRINGW(IDS_BITRATE),c));
  1375. if(fieldsBits & SUPPORTS_SIZE) fields.Add(new ListField(1009, 90, WASABI_API_LNGSTRINGW(IDS_SIZE),c));
  1376. if(fieldsBits & SUPPORTS_PLAYCOUNT) fields.Add(new ListField(1010, 64, WASABI_API_LNGSTRINGW(IDS_PLAY_COUNT),c));
  1377. if(fieldsBits & SUPPORTS_RATING) fields.Add(new ListField(1011, 64, WASABI_API_LNGSTRINGW(IDS_RATING),c));
  1378. if(fieldsBits & SUPPORTS_LASTPLAYED) fields.Add(new ListField(1012, 100,WASABI_API_LNGSTRINGW(IDS_LAST_PLAYED),c));
  1379. if(fieldsBits & SUPPORTS_ALBUMARTIST) fields.Add(new ListField(1013, 200,WASABI_API_LNGSTRINGW(IDS_ALBUM_ARTIST),c,true));
  1380. if(fieldsBits & SUPPORTS_PUBLISHER) fields.Add(new ListField(1014, 200,WASABI_API_LNGSTRINGW(IDS_PUBLISHER),c,true));
  1381. if(fieldsBits & SUPPORTS_COMPOSER) fields.Add(new ListField(1015, 200,WASABI_API_LNGSTRINGW(IDS_COMPOSER),c,true));
  1382. if(fieldsBits & SUPPORTS_MIMETYPE) fields.Add(new ListField(1016, 100,WASABI_API_LNGSTRINGW(IDS_MIME_TYPE),c,true));
  1383. if(fieldsBits & SUPPORTS_DATEADDED) fields.Add(new ListField(1017, 100,WASABI_API_LNGSTRINGW(IDS_DATE_ADDED),c,true));
  1384. this->SortColumns();
  1385. }
  1386. //virtual ~PlaylistContents() { }
  1387. virtual int GetNumColumns() { return fields.GetSize(); }
  1388. virtual int GetNumRows() { return dev->getPlaylistLength(playlistId); }
  1389. virtual int GetColumnWidth(int num) {
  1390. if(num >=0 && num < fields.GetSize())
  1391. return ((ListField *)fields.Get(num))->width;
  1392. return 0;
  1393. }
  1394. virtual wchar_t * GetColumnTitle(int num) {
  1395. if(num >=0 && num < fields.GetSize())
  1396. return ((ListField *)fields.Get(num))->name;
  1397. return L"";
  1398. }
  1399. virtual void GetCellText(int row, int col, wchar_t * buf, int buflen) {
  1400. if(col >=0 && col < fields.GetSize()) col = ((ListField *)fields.Get(col))->field;
  1401. if(col != -1) col -= 1000;
  1402. songid_t s = dev->getPlaylistTrack(playlistId,row);
  1403. buf[0]=0;
  1404. switch(col) {
  1405. case -1: wsprintf(buf,L"%d",row+1); return;
  1406. case 0: dev->getTrackArtist(s,buf,buflen); return;
  1407. case 1: dev->getTrackTitle(s,buf,buflen); return;
  1408. case 2: dev->getTrackAlbum(s,buf,buflen); return;
  1409. case 3: { int l=dev->getTrackLength(s); if (l>=0) wsprintf(buf,L"%d:%02d",l/1000/60,(l/1000)%60); return; }
  1410. case 4: { int d = dev->getTrackTrackNum(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
  1411. case 5: { int d = dev->getTrackDiscNum(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
  1412. case 6: dev->getTrackGenre(s,buf,buflen); return;
  1413. case 7: { int d = dev->getTrackYear(s); if(d>0) wsprintf(buf,L"%d",d); return; }
  1414. case 8: { int d = dev->getTrackBitrate(s); if(d>0) wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_KBPS),d); return; }
  1415. case 9: WASABI_API_LNG->FormattedSizeString(buf, buflen, dev->getTrackSize(s)); return;
  1416. case 10: { int d = dev->getTrackPlayCount(s); if(d>=0) wsprintf(buf,L"%d",d); return; }
  1417. case 11: getStars(dev->getTrackRating(s),buf,buflen); return;
  1418. case 12: timeToString(dev->getTrackLastPlayed(s),buf,buflen); return;
  1419. case 13: dev->getTrackAlbumArtist(s,buf,buflen); return;
  1420. case 14: dev->getTrackPublisher(s,buf,buflen); return;
  1421. case 15: dev->getTrackComposer(s,buf,buflen); return;
  1422. }
  1423. }
  1424. virtual void GetInfoString(wchar_t * buf) {
  1425. __int64 totalSize=0;
  1426. int totalPlayLength=0;
  1427. int millis=0;
  1428. int l = dev->getPlaylistLength(playlistId);
  1429. for(int i=0; i < l; i++) {
  1430. songid_t s = dev->getPlaylistTrack(playlistId,i);
  1431. totalSize += (__int64)dev->getTrackSize(s);
  1432. int len=dev->getTrackLength(s);
  1433. totalPlayLength += len/1000;
  1434. millis += len%1000;
  1435. }
  1436. totalPlayLength += millis/1000;
  1437. ::GetInfoString(buf, dev, l, totalSize, totalPlayLength, 0);
  1438. }
  1439. virtual songid_t GetTrack(int pos) { return dev->getPlaylistTrack(playlistId,pos); }
  1440. virtual void ColumnResize(int col, int newWidth) {
  1441. if(col >=0 && col < fields.GetSize()) {
  1442. ListField * lf = (ListField *)fields.Get(col);
  1443. lf->width = newWidth;
  1444. wchar_t buf[100] = {0};
  1445. wsprintf(buf,L"colWidth_%d",lf->field);
  1446. currentViewedDevice->config->WriteInt(buf,newWidth);
  1447. }
  1448. }
  1449. };
  1450. static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
  1451. switch (uMsg) {
  1452. case WM_INITDIALOG:
  1453. SetDlgItemText(hwndDlg,IDC_EDIT,currentViewedDevice->config->ReadString(L"plfind",L""));
  1454. if (FALSE != CenterWindow(hwndDlg, (HWND)lParam))
  1455. SendMessage(hwndDlg, DM_REPOSITION, 0, 0L);
  1456. break;
  1457. case WM_COMMAND:
  1458. switch(LOWORD(wParam)) {
  1459. case IDOK:
  1460. {
  1461. wchar_t buf[256] = {0};
  1462. GetDlgItemText(hwndDlg,IDC_EDIT,buf,sizeof(buf)/sizeof(wchar_t));
  1463. buf[255]=0;
  1464. currentViewedDevice->config->WriteString(L"plfind",buf);
  1465. EndDialog(hwndDlg,(INT_PTR)_wcsdup(buf));
  1466. }
  1467. break;
  1468. case IDCANCEL:
  1469. EndDialog(hwndDlg,0);
  1470. break;
  1471. }
  1472. break;
  1473. }
  1474. return 0;
  1475. }
  1476. extern C_ItemList * FilterSongs(const wchar_t * filter, const C_ItemList * songs, Device * dev, bool cloud);
  1477. static int m_pldrag;
  1478. INT_PTR CALLBACK pmp_playlist_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
  1479. static bool pldrag_changed;
  1480. if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; }
  1481. if (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  1482. switch (uMsg) {
  1483. case WM_INITDIALOG:
  1484. {
  1485. if (!view.play)
  1486. {
  1487. SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
  1488. }
  1489. groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
  1490. enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 1);
  1491. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  1492. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  1493. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG(IDC_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
  1494. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  1495. if (pszTextW && pszTextW[0] != 0)
  1496. {
  1497. // set this to be a bit different so we can just use one button and not the
  1498. // mixable one as well (leaving that to prevent messing with the resources)
  1499. customAllowed = TRUE;
  1500. SetDlgItemTextW(hwndDlg, IDC_BUTTON_CUSTOM, pszTextW);
  1501. }
  1502. else
  1503. {
  1504. customAllowed = FALSE;
  1505. }
  1506. playmode = L"plplaymode";
  1507. hwndMediaView = hwndDlg;
  1508. pldrag_changed=false;
  1509. *(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC);
  1510. *(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC);
  1511. tracks = new PlaylistContents(currentViewedPlaylist,currentViewedDevice->dev);
  1512. m_pldrag=-1;
  1513. {
  1514. MLSKINWINDOW skin = {0};
  1515. skin.skinType = SKINNEDWND_TYPE_AUTO;
  1516. FLICKERFIX ff = {0};
  1517. ff.mode = FFM_ERASEINPAINT;
  1518. INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM, IDC_BUTTON_SORT, IDC_BUTTON_EJECT, IDC_STATUS};
  1519. for (int i = 0; i < sizeof(ffcl) / sizeof(INT); i++)
  1520. {
  1521. ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
  1522. if (IsWindow(ff.hwnd))
  1523. {
  1524. SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
  1525. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn && (i < 3) ? SWBS_SPLITBUTTON : 0);
  1526. skin.hwndToSkin = ff.hwnd;
  1527. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  1528. }
  1529. }
  1530. }
  1531. }
  1532. break;
  1533. case WM_DESTROY:
  1534. if(tracks) delete tracks; tracks=0;
  1535. break;
  1536. case WM_DROPFILES:
  1537. return currentViewedDevice->TransferFromDrop((HDROP)wParam, currentViewedPlaylist);
  1538. case WM_NOTIFY:
  1539. {
  1540. LPNMHDR l=(LPNMHDR)lParam;
  1541. if(l->idFrom==IDC_LIST_TRACKS)
  1542. switch(l->code) {
  1543. case LVN_KEYDOWN:
  1544. switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
  1545. case 0x46: //F
  1546. {
  1547. if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  1548. wchar_t * findstr = (wchar_t*)WASABI_API_DIALOGBOXPARAMW(IDD_FIND,hwndDlg,find_dlgproc, (LPARAM)hwndDlg);
  1549. if(!findstr) break;
  1550. C_ItemList songs;
  1551. int l = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist);
  1552. int i;
  1553. for(i=0; i<l; i++) songs.Add((void*)currentViewedDevice->dev->getPlaylistTrack(currentViewedPlaylist,i));
  1554. C_ItemList * found = FilterSongs(findstr,&songs,currentViewedDevice->dev,0);
  1555. free(findstr);
  1556. int j=0;
  1557. HWND wnd = tracksList->listview.getwnd();
  1558. for(i=0; i<l; i++) {
  1559. if(found->Get(j) == songs.Get(i)) {
  1560. ListView_SetItemState(wnd,i,LVIS_SELECTED,LVIS_SELECTED);
  1561. if(j++ == 0) ListView_EnsureVisible(wnd,i,TRUE);
  1562. }
  1563. else ListView_SetItemState(wnd,i,0,LVIS_SELECTED);
  1564. }
  1565. delete found;
  1566. }
  1567. }
  1568. break;
  1569. case VK_DELETE:
  1570. if(!GetAsyncKeyState(VK_CONTROL)){
  1571. if(!GetAsyncKeyState(VK_SHIFT)){
  1572. handleContextMenuResult(ID_TRACKSLIST_DELETE);
  1573. }
  1574. else{
  1575. SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(ID_TRACKSLIST_REMOVEFROMPLAYLIST,0),0);
  1576. }
  1577. }
  1578. break;
  1579. case 0x43: //C
  1580. if(GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  1581. handleContextMenuResult(ID_TRACKSLIST_COPYTOLIBRARY);
  1582. }
  1583. break;
  1584. }
  1585. }
  1586. }
  1587. break;
  1588. case WM_WINDOWPOSCHANGED:
  1589. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  1590. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  1591. {
  1592. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags), 2);
  1593. }
  1594. return TRUE;
  1595. case WM_DISPLAYCHANGE:
  1596. {
  1597. UpdateWindow(hwndDlg);
  1598. LayoutWindows(hwndDlg, TRUE, 2);
  1599. }
  1600. break;
  1601. case WM_APP + 104:
  1602. {
  1603. pmp_common_UpdateButtonText(hwndDlg, wParam);
  1604. LayoutWindows(hwndDlg, TRUE, 2);
  1605. return 0;
  1606. }
  1607. case WM_PAINT:
  1608. {
  1609. int tab[] = {IDC_LIST_TRACKS|DCW_SUNKENBORDER};
  1610. int size = sizeof(tab) / sizeof(tab[0]);
  1611. if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
  1612. }
  1613. break;
  1614. case WM_LBUTTONDOWN:
  1615. m_pldrag=-1;
  1616. //m_pldrag = tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
  1617. break;
  1618. case WM_LBUTTONUP:
  1619. m_pldrag=-1;
  1620. if(GetCapture() == hwndDlg) ReleaseCapture();
  1621. if(pldrag_changed) { currentViewedDevice->DevicePropertiesChanges(); pldrag_changed=false;}
  1622. break;
  1623. case WM_MOUSEMOVE:
  1624. if(wParam==MK_LBUTTON) {
  1625. if(m_pldrag==-1) { m_pldrag=tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); break; } // m_pldrag=GET_Y_LPARAM(lParam);
  1626. int p = tracksList->listview.FindItemByPoint(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); // new point
  1627. if(p==-1) break;
  1628. //work out how much to move and how
  1629. int h=1; //height of one item
  1630. HWND listWnd = tracksList->listview.getwnd();
  1631. Device * dev = currentViewedDevice->dev;
  1632. if(p - m_pldrag >= h) {
  1633. //moved down
  1634. int start=-1,end=-1;
  1635. int i;
  1636. int l = dev->getPlaylistLength(currentViewedPlaylist);
  1637. for(i=l-1; i>=0; i--) if(ListView_GetItemState(listWnd, i, LVIS_SELECTED) == LVIS_SELECTED) {
  1638. if(i == l-1) break;
  1639. if(end == -1) end = i+1;
  1640. start = i;
  1641. //change playlist
  1642. dev->playlistSwapItems(currentViewedPlaylist,i,i+1);
  1643. pldrag_changed=true;
  1644. //set selection correctly
  1645. ListView_SetItemState(listWnd,i,0,LVIS_SELECTED);
  1646. ListView_SetItemState(listWnd,i+1,LVIS_SELECTED,LVIS_SELECTED);
  1647. if(ListView_GetItemState(listWnd, i, LVIS_FOCUSED)==LVIS_FOCUSED) {
  1648. ListView_SetItemState(listWnd,i,0,LVIS_FOCUSED);
  1649. ListView_SetItemState(listWnd,i+1,LVIS_FOCUSED,LVIS_FOCUSED);
  1650. }
  1651. }
  1652. if(start != -1) {
  1653. ListView_RedrawItems(listWnd,start,end);
  1654. m_pldrag += h;
  1655. }
  1656. }
  1657. else if(m_pldrag - p >= h){
  1658. //moved up
  1659. int start=-1,end=-1;
  1660. int i;
  1661. int l = dev->getPlaylistLength(currentViewedPlaylist);
  1662. for(i=0; i<l; i++) if(ListView_GetItemState(listWnd, i, LVIS_SELECTED) == LVIS_SELECTED) {
  1663. if(i == 0) break;
  1664. if(start == -1) start = i-1;
  1665. end = i;
  1666. //change playlist
  1667. dev->playlistSwapItems(currentViewedPlaylist,i,i-1);
  1668. pldrag_changed=true;
  1669. //set selection correctly
  1670. ListView_SetItemState(listWnd,i,0,LVIS_SELECTED);
  1671. ListView_SetItemState(listWnd,i-1,LVIS_SELECTED,LVIS_SELECTED);
  1672. if(ListView_GetItemState(listWnd, i, LVIS_FOCUSED)==LVIS_FOCUSED) {
  1673. ListView_SetItemState(listWnd,i,0,LVIS_FOCUSED);
  1674. ListView_SetItemState(listWnd,i-1,LVIS_FOCUSED,LVIS_FOCUSED);
  1675. }
  1676. }
  1677. if(start != -1) {
  1678. ListView_RedrawItems(listWnd,start,end);
  1679. m_pldrag -= h;
  1680. }
  1681. }
  1682. return 0;
  1683. }
  1684. break;
  1685. case WM_COMMAND:
  1686. switch(LOWORD(wParam)) {
  1687. case ID_TRACKSLIST_REMOVEFROMPLAYLIST:
  1688. {
  1689. int l = tracksList->listview.GetCount();
  1690. while(l-- > 0) if(tracksList->listview.GetSelected(l))
  1691. currentViewedDevice->dev->removeTrackFromPlaylist(currentViewedPlaylist,l);
  1692. tracksList->UpdateList();
  1693. currentViewedDevice->DevicePropertiesChanges();
  1694. }
  1695. break;
  1696. case IDC_BUTTON_SORT:
  1697. {
  1698. HMENU menu = GetSubMenu(m_context_menus,5);
  1699. POINT p;
  1700. GetCursorPos(&p);
  1701. int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY, p.x, p.y, hwndDlg, NULL);
  1702. if(r >= ID_SORTPLAYLIST_ARTIST && r <= ID_SORTPLAYLIST_LASTPLAYED) {
  1703. currentViewedDevice->dev->sortPlaylist(currentViewedPlaylist,r - ID_SORTPLAYLIST_ARTIST);
  1704. }
  1705. else if(r == ID_SORTPLAYLIST_RANDOMIZE) {
  1706. int elems = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist);
  1707. if (elems > 1) {
  1708. for (int p = 0; p < elems; p ++) {
  1709. int np=genrand_int31()%elems;
  1710. if (p != np) // swap pp and np
  1711. currentViewedDevice->dev->playlistSwapItems(currentViewedPlaylist,p,np);
  1712. }
  1713. }
  1714. }
  1715. else if(r == ID_SORTPLAYLIST_REVERSEPLAYLIST) {
  1716. int i=0;
  1717. int j = currentViewedDevice->dev->getPlaylistLength(currentViewedPlaylist) - 1;
  1718. while(i < j)
  1719. currentViewedDevice->dev->playlistSwapItems(currentViewedPlaylist,i++,j--);
  1720. }
  1721. if(r > 0) {
  1722. tracksList->UpdateList(true);
  1723. currentViewedDevice->DevicePropertiesChanges();
  1724. }
  1725. }
  1726. break;
  1727. }
  1728. break; // WM_COMMAND
  1729. }
  1730. return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
  1731. }
  1732. INT_PTR CALLBACK pmp_video_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1733. if (wad_handleDialogMsgs) { BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a; }
  1734. if (tracksList) { BOOL a=tracksList->DialogProc(hwndDlg,uMsg,wParam,lParam); if(a) return a; }
  1735. switch (uMsg) {
  1736. case WM_INITDIALOG:
  1737. {
  1738. if (!view.play)
  1739. {
  1740. SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GET_VIEW_BUTTON_TEXT, (WPARAM)&view);
  1741. }
  1742. groupBtn = gen_mlconfig->ReadInt(L"groupbtn", 1);
  1743. enqueuedef = (gen_mlconfig->ReadInt(L"enqueuedef", 0) == 1);
  1744. // v5.66+ - re-use the old predixis parts so the button can be used functionally via ml_enqplay
  1745. // pass the hwnd, button id and plug-in id so the ml plug-in can check things as needed
  1746. pluginMessage p = {ML_MSG_VIEW_BUTTON_HOOK, (INT_PTR)hwndDlg, (INT_PTR)MAKELONG(IDC_BUTTON_CUSTOM, IDC_BUTTON_ENQUEUE), (INT_PTR)L"ml_pmp"};
  1747. wchar_t *pszTextW = (wchar_t *)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p);
  1748. if (pszTextW && pszTextW[0] != 0)
  1749. {
  1750. // set this to be a bit different so we can just use one button and not the
  1751. // mixable one as well (leaving that to prevent messing with the resources)
  1752. customAllowed = TRUE;
  1753. SetDlgItemTextW(hwndDlg, IDC_BUTTON_CUSTOM, pszTextW);
  1754. }
  1755. else
  1756. {
  1757. customAllowed = FALSE;
  1758. }
  1759. playmode = L"viewplaymode";
  1760. hwndMediaView = hwndDlg;
  1761. *(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC);
  1762. *(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC);
  1763. if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
  1764. header = 1;
  1765. else
  1766. header = currentViewedDevice->config->ReadInt(L"header",0);
  1767. HWND list = GetDlgItem(hwndDlg, IDC_LIST_TRACKS);
  1768. // TODO need to be able to change the order of the tracks items (so cloud is in a more appropriate place)
  1769. //ListView_SetExtendedListViewStyleEx(list, LVS_EX_HEADERDRAGDROP, LVS_EX_HEADERDRAGDROP);
  1770. ListView_SetExtendedListViewStyle(list, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
  1771. if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
  1772. {
  1773. SetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, currentViewedDevice->config->ReadString(L"savedfilter", L""));
  1774. }
  1775. // depending on how this is called, it will either do a video only view or will be re-purposed as a 'simple' view
  1776. aacontents = new ArtistAlbumLists(currentViewedDevice->dev, currentViewedPlaylist, currentViewedDevice->config,
  1777. NULL, 0, (lParam ? -1 : (currentViewedDevice->videoView ? 1 : -1)), (lParam == 1));
  1778. if (aacontents)
  1779. {
  1780. tracks = aacontents->GetTracksList();
  1781. }
  1782. MLSKINWINDOW skin = {0};
  1783. skin.hwndToSkin = list;
  1784. skin.skinType = SKINNEDWND_TYPE_LISTVIEW;
  1785. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  1786. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  1787. MLSkinnedHeader_SetCloudColumn(ListView_GetHeader(list), tracks->cloudcol);
  1788. FLICKERFIX ff = {0};
  1789. ff.mode = FFM_ERASEINPAINT;
  1790. INT ffcl[] = { IDC_BUTTON_PLAY, IDC_BUTTON_ENQUEUE, IDC_BUTTON_CUSTOM,
  1791. IDC_BUTTON_CLEARSEARCH, IDC_BUTTON_CLEARREFINE,
  1792. IDC_BUTTON_EJECT, IDC_BUTTON_SYNC, IDC_BUTTON_AUTOFILL,
  1793. IDC_STATUS, IDC_SEARCH_TEXT, IDC_QUICKSEARCH, IDC_REFINE,
  1794. IDC_REFINE_TEXT,
  1795. // disabled cloud parts
  1796. /*IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME,
  1797. IDC_HEADER_DEVICE_BAR, IDC_HEADER_DEVICE_SIZE,
  1798. IDC_HEADER_DEVICE_TRANSFER,*/
  1799. };
  1800. skin.skinType = SKINNEDWND_TYPE_AUTO;
  1801. for (int i = 0; i < sizeof(ffcl) / sizeof(INT); i++)
  1802. {
  1803. ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
  1804. if (IsWindow(ff.hwnd))
  1805. {
  1806. SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
  1807. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | (groupBtn && (i < 3) ? SWBS_SPLITBUTTON : 0);
  1808. skin.hwndToSkin = ff.hwnd;
  1809. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  1810. }
  1811. }
  1812. skin.hwndToSkin = hwndDlg;
  1813. skin.skinType = SKINNEDWND_TYPE_AUTO;
  1814. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  1815. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  1816. if (0 != currentViewedDevice->dev->extraActions(DEVICE_SYNC_UNSUPPORTED,0,0,0))
  1817. EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC), FALSE);
  1818. }
  1819. break;
  1820. case WM_USER+1:
  1821. if (tracks)
  1822. {
  1823. if (lParam)
  1824. {
  1825. tracks->RemoveTrack((songid_t)wParam);
  1826. }
  1827. tracksList->UpdateList();
  1828. }
  1829. break;
  1830. case WM_DESTROY:
  1831. if (aacontents) aacontents->bgQuery_Stop();
  1832. tracks = NULL;
  1833. if (aacontents) delete aacontents; aacontents=NULL;
  1834. break;
  1835. case WM_DROPFILES:
  1836. return currentViewedDevice->TransferFromDrop((HDROP)wParam);
  1837. case WM_NOTIFY:
  1838. {
  1839. LPNMHDR l=(LPNMHDR)lParam;
  1840. if (l->idFrom == IDC_LIST_TRACKS)
  1841. {
  1842. switch (l->code)
  1843. {
  1844. case LVN_KEYDOWN:
  1845. switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
  1846. case VK_DELETE:
  1847. {
  1848. if(!GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  1849. handleContextMenuResult(ID_TRACKSLIST_DELETE);
  1850. }
  1851. }
  1852. break;
  1853. case 0x45: //E
  1854. bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
  1855. if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  1856. C_ItemList * items = getSelectedItems();
  1857. editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
  1858. delete items;
  1859. }
  1860. break;
  1861. }
  1862. break;
  1863. }
  1864. }
  1865. }
  1866. break;
  1867. case WM_WINDOWPOSCHANGED:
  1868. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  1869. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  1870. {
  1871. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags), 1);
  1872. }
  1873. return TRUE;
  1874. case WM_DISPLAYCHANGE:
  1875. {
  1876. UpdateWindow(hwndDlg);
  1877. LayoutWindows(hwndDlg, TRUE, 1);
  1878. }
  1879. break;
  1880. case WM_APP + 104:
  1881. {
  1882. pmp_common_UpdateButtonText(hwndDlg, wParam);
  1883. LayoutWindows(hwndDlg, TRUE, 1);
  1884. return 0;
  1885. }
  1886. case WM_PAINT:
  1887. {
  1888. int tab[] = {IDC_LIST_TRACKS|DCW_SUNKENBORDER,
  1889. IDC_QUICKSEARCH|DCW_SUNKENBORDER,
  1890. (!header?IDC_HDELIM2|DCW_DIVIDER:0),
  1891. };
  1892. int size = sizeof(tab) / sizeof(tab[0]);
  1893. // do this to prevent drawing parts when the views are collapsed
  1894. if (!currentViewedDevice->isCloudDevice) size -= 1;
  1895. if (wad_DrawChildWindowBorders) wad_DrawChildWindowBorders(hwndDlg,tab,size);
  1896. }
  1897. return TRUE;
  1898. case WM_APP + 3: // send by bgthread
  1899. if (wParam == 0x69)
  1900. {
  1901. if (aacontents)
  1902. {
  1903. aacontents->bgQuery_Stop();
  1904. tracks = aacontents->GetTracksList();
  1905. if (tracksList) tracksList->UpdateList();
  1906. UpdateStatus(hwndDlg, true);
  1907. }
  1908. }
  1909. break;
  1910. case WM_COMMAND:
  1911. switch(LOWORD(wParam)) {
  1912. case IDC_QUICKSEARCH:
  1913. if (HIWORD(wParam) == EN_CHANGE && !noSearchTimer) {
  1914. KillTimer(hwndDlg,500);
  1915. SetTimer(hwndDlg,500,250,NULL);
  1916. }
  1917. break;
  1918. case IDC_HEADER_DEVICE_TRANSFER:
  1919. {
  1920. if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BUTTON_SYNC)))
  1921. {
  1922. MessageBox(hwndDlg, L"Transferring files from this device to another is not currently supported.",
  1923. L"Cloud Transfer Not Supported", MB_ICONINFORMATION);
  1924. break;
  1925. }
  1926. }
  1927. case IDC_BUTTON_SYNC:
  1928. if (!currentViewedDevice->isCloudDevice)
  1929. currentViewedDevice->Sync();
  1930. else
  1931. currentViewedDevice->CloudSync();
  1932. break;
  1933. case IDC_SEARCH_TEXT:
  1934. if (HIWORD(wParam) == STN_DBLCLK)
  1935. {
  1936. // TODO decide what to do for the 'all_sources'
  1937. if (currentViewedDevice->isCloudDevice &&
  1938. lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
  1939. {
  1940. header = !header;
  1941. currentViewedDevice->config->WriteInt(L"header",header);
  1942. LayoutWindows(hwndMediaView, TRUE, 1);
  1943. UpdateStatus(hwndDlg);
  1944. ShowWindow(hwndDlg, 0);
  1945. ShowWindow(hwndDlg, 1);
  1946. }
  1947. }
  1948. break;
  1949. case IDC_BUTTON_CLEARSEARCH:
  1950. SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,L"");
  1951. break;
  1952. }
  1953. break; //WM_COMMAND
  1954. case WM_TIMER:
  1955. switch(wParam) {
  1956. case 123:
  1957. {
  1958. if (aacontents && aacontents->bgThread_Handle && tracksList)
  1959. {
  1960. HWND hwndList;
  1961. hwndList = tracksList->listview.getwnd();
  1962. if (1 != ListView_GetItemCount(hwndList)) ListView_SetItemCountEx(hwndList, 1, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
  1963. ListView_RedrawItems(hwndList, 0, 0);
  1964. }
  1965. }
  1966. break;
  1967. case 500:
  1968. {
  1969. KillTimer(hwndDlg,500);
  1970. if (currentViewedDevice && aacontents)
  1971. {
  1972. wchar_t buf[256]=L"";
  1973. GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf)/sizeof(wchar_t));
  1974. aacontents->SetSearch(buf, (!!currentViewedDevice->isCloudDevice));
  1975. if (!aacontents->bgThread_Handle)
  1976. {
  1977. if (tracksList) tracksList->UpdateList();
  1978. UpdateStatus(hwndDlg);
  1979. }
  1980. }
  1981. }
  1982. break;
  1983. }
  1984. break;
  1985. }
  1986. return pmp_common_dlgproc(hwndDlg,uMsg,wParam,lParam);
  1987. }
  1988. static INT_PTR CALLBACK pmp_common_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1989. switch (uMsg) {
  1990. case WM_INITDIALOG:
  1991. {
  1992. hwndMediaView = hwndDlg;
  1993. HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_ACCELERATORS);
  1994. if (accel)
  1995. WASABI_API_APP->app_addAccelerators(hwndDlg, &accel, 1, TRANSLATE_MODE_CHILD);
  1996. if (currentViewedDevice->isCloudDevice)
  1997. {
  1998. wchar_t buf[256] = {0};
  1999. currentViewedDevice->GetDisplayName(buf, 128);
  2000. SetDlgItemText(hwndDlg, IDC_HEADER_DEVICE_NAME, buf);
  2001. int icon_id = currentViewedDevice->dev->extraActions(0x22, 0, 0, 0);
  2002. HBITMAP bm = (HBITMAP)LoadImage(GetModuleHandle(L"pmp_cloud.dll"),
  2003. MAKEINTRESOURCE(icon_id > 0 ? icon_id : 103), IMAGE_BITMAP, 16, 16,
  2004. LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
  2005. SendDlgItemMessage(hwndDlg, IDC_HEADER_DEVICE_ICON, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bm);
  2006. HWND progress = GetDlgItem(hwndDlg, IDC_HEADER_DEVICE_BAR);
  2007. if (IsWindow(progress))
  2008. {
  2009. MLSKINWINDOW skin = {0};
  2010. skin.hwndToSkin = progress;
  2011. skin.skinType = SKINNEDWND_TYPE_PROGRESSBAR;
  2012. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  2013. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  2014. }
  2015. }
  2016. tracksList = new SkinnedListView(tracks,IDC_LIST_TRACKS,plugin.hwndLibraryParent, hwndDlg);
  2017. tracksList->DialogProc(hwndDlg,WM_INITDIALOG,0,0);
  2018. if (tracksList->contents && !tracksList->contents->cloud)
  2019. {
  2020. tracksList->UpdateList();
  2021. UpdateStatus(hwndDlg);
  2022. }
  2023. pmp_common_UpdateButtonText(hwndDlg, enqueuedef == 1);
  2024. }
  2025. case WM_DISPLAYCHANGE:
  2026. {
  2027. if (currentViewedDevice->isCloudDevice)
  2028. {
  2029. int (*wad_getColor)(int idx);
  2030. *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
  2031. ARGB32 fc = (!wad_getColor?wad_getColor(WADLG_WNDBG):RGB(0xFF,0xFF,0xFF)) & 0x00FFFFFF;
  2032. SetToolbarButtonBitmap(hwndDlg,IDC_HEADER_DEVICE_TRANSFER, MAKEINTRESOURCE(IDR_TRANSFER_SMALL_ICON),fc);
  2033. }
  2034. }
  2035. break;
  2036. case WM_DESTROY:
  2037. {
  2038. if (currentViewedDevice)
  2039. {
  2040. SkinBitmap *s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_HEADER_DEVICE_TRANSFER),GWLP_USERDATA);
  2041. if (s) DeleteSkinBitmap(s);
  2042. if (currentViewedDevice->config->ReadInt(L"savefilter", 1))
  2043. {
  2044. wchar_t buf[256] = {0};
  2045. GetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, buf, 256);
  2046. currentViewedDevice->config->WriteString(L"savedfilter", buf);
  2047. buf[0] = 0;
  2048. GetDlgItemTextW(hwndDlg, IDC_REFINE, buf, 256);
  2049. currentViewedDevice->config->WriteString(L"savedrefinefilter", buf);
  2050. }
  2051. }
  2052. WASABI_API_APP->app_removeAccelerators(hwndDlg);
  2053. hwndMediaView = NULL;
  2054. currentViewedDevice = NULL;
  2055. if (tracksList)
  2056. {
  2057. delete tracksList;
  2058. tracksList = NULL;
  2059. }
  2060. }
  2061. break;
  2062. case WM_DRAWITEM:
  2063. {
  2064. DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
  2065. if (di->CtlType == ODT_BUTTON || di->CtlType == ODT_STATIC) {
  2066. if(di->CtlID == IDC_HEADER_DEVICE_TRANSFER)
  2067. { // draw the toolbar buttons!
  2068. int (*wad_getColor)(int idx);
  2069. *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
  2070. HBRUSH hbr = CreateSolidBrush((wad_getColor?wad_getColor(WADLG_WNDBG):RGB(0xFF,0xFF,0xFF)));
  2071. FillRect(di->hDC, &di->rcItem, hbr);
  2072. DeleteBrush(hbr);
  2073. SkinBitmap* hbm = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,di->CtlID),GWLP_USERDATA);
  2074. if(hbm && di->rcItem.left != di->rcItem.right && di->rcItem.top != di->rcItem.bottom) {
  2075. DCCanvas dc(di->hDC);
  2076. if (di->itemState & ODS_SELECTED) hbm->blitAlpha(&dc,di->rcItem.left+1,di->rcItem.top+1);
  2077. else hbm->blitAlpha(&dc,di->rcItem.left,di->rcItem.top);
  2078. dc.Release();
  2079. }
  2080. }
  2081. }
  2082. }
  2083. break;
  2084. case WM_NOTIFY:
  2085. {
  2086. LPNMHDR l=(LPNMHDR)lParam;
  2087. if(l->code == LVN_KEYDOWN && ((LPNMLVKEYDOWN)lParam)->wVKey == VK_F5)
  2088. {
  2089. if (currentViewedDevice->dev->extraActions(DEVICE_REFRESH,0,0,0))
  2090. {
  2091. SetTimer(hwndDlg, (artistList ? 501 : 500), 250, NULL);
  2092. }
  2093. }
  2094. if(l->idFrom == IDC_LIST_TRACKS)
  2095. {
  2096. switch(l->code) {
  2097. case LVN_KEYDOWN:
  2098. switch(((LPNMLVKEYDOWN)lParam)->wVKey) {
  2099. case 0x45: //E
  2100. {
  2101. bool noEdit = currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA,0,0,0)!=0;
  2102. if(!noEdit && GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT)){
  2103. C_ItemList * items = getSelectedItems();
  2104. editInfo(items,currentViewedDevice->dev, CENTER_OVER_ML_VIEW);
  2105. delete items;
  2106. }
  2107. }
  2108. break;
  2109. }
  2110. break;
  2111. case NM_RETURN:
  2112. case NM_DBLCLK:
  2113. {
  2114. C_ItemList * items = getSelectedItems(true);
  2115. int start=0;
  2116. int l=tracksList->listview.GetCount();
  2117. int i = 0;
  2118. for (; i < l; i++)
  2119. if (tracksList->listview.GetSelected(i))
  2120. {
  2121. start = i;
  2122. break;
  2123. }
  2124. if (items->GetSize() && (!!(GetAsyncKeyState(VK_SHIFT)&0x8000) || !gen_mlconfig->ReadInt(playmode,1))) {
  2125. void* x = items->Get(i);
  2126. delete items;
  2127. items = new C_ItemList;
  2128. items->Add(x);
  2129. start = 0;
  2130. }
  2131. currentViewedDevice->PlayTracks(items, start, (!(GetAsyncKeyState(VK_SHIFT)&0x8000) ? (enqueuedef == 1) : (enqueuedef != 1)), false);
  2132. delete items;
  2133. }
  2134. break;
  2135. case NM_CUSTOMDRAW:
  2136. {
  2137. LRESULT result = 0;
  2138. if (ListView_OnCustomDraw(hwndDlg, (NMLVCUSTOMDRAW*)lParam, &result))
  2139. {
  2140. SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
  2141. return 1;
  2142. }
  2143. }
  2144. break;
  2145. case LVN_GETDISPINFOW:
  2146. {
  2147. NMLVDISPINFOW* pdi = (NMLVDISPINFOW*)lParam;
  2148. if (aacontents && aacontents->bgThread_Handle)
  2149. {
  2150. LVITEMW *pItem = &pdi->item;
  2151. if (0 == pItem->iItem && (LVIF_TEXT & pItem->mask))
  2152. {
  2153. if (0 == pItem->iSubItem)
  2154. {
  2155. static char bufpos = 0;
  2156. static int buflen = 17;
  2157. static wchar_t buffer[64];//L"Scanning _\0/-\\|";
  2158. if (!buffer[0])
  2159. {
  2160. //WASABI_API_LNGSTRINGW_BUF(IDS_SCANNING_PLAIN,buffer,54);
  2161. StringCchCopyW(buffer,64,L"Scanning");
  2162. StringCchCatW(buffer,64,L" _");
  2163. StringCchCatW(buffer+(buflen=lstrlenW(buffer)+1),64,L"/-\\|");
  2164. buflen+=4;
  2165. }
  2166. int pos = buflen - 5;;
  2167. buffer[pos - 1] = buffer[pos + (bufpos++&3) + 1];
  2168. pItem->pszText = buffer;
  2169. SetDlgItemText(hwndDlg, IDC_STATUS, buffer);
  2170. }
  2171. else
  2172. {
  2173. pItem->pszText = L"";
  2174. }
  2175. }
  2176. return 1;
  2177. }
  2178. }
  2179. break;
  2180. case NM_CLICK:
  2181. {
  2182. // prevent the right-click menus appearing when scanning
  2183. if (aacontents && aacontents->bgThread_Handle) break;
  2184. LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE)lParam;
  2185. if (lpnmitem->iItem != -1 && lpnmitem->iSubItem == tracks->cloudcol)
  2186. {
  2187. RECT itemRect = {0};
  2188. if (lpnmitem->iSubItem)
  2189. ListView_GetSubItemRect(l->hwndFrom, lpnmitem->iItem, lpnmitem->iSubItem, LVIR_BOUNDS, &itemRect);
  2190. else
  2191. {
  2192. ListView_GetItemRect(l->hwndFrom, lpnmitem->iItem, &itemRect, LVIR_BOUNDS);
  2193. itemRect.right = itemRect.left + ListView_GetColumnWidth(l->hwndFrom, tracks->cloudcol);
  2194. }
  2195. MapWindowPoints(l->hwndFrom, HWND_DESKTOP, (POINT*)&itemRect, 2);
  2196. int cloud_devices = 0;
  2197. int mark = tracksList->listview.GetSelectionMark();
  2198. if (mark != -1)
  2199. {
  2200. // if wanting to do on the selection then use getSelectedItems()
  2201. //C_ItemList * items = getSelectedItems();
  2202. // otherwise only work on the selection mark for speed (and like how ml_local does things)
  2203. C_ItemList * items = new C_ItemList;
  2204. items->Add((void*)tracks->GetTrack(mark));
  2205. HMENU cloud_menu = (HMENU)currentViewedDevice->dev->extraActions(DEVICE_GET_CLOUD_SOURCES_MENU, (intptr_t)&cloud_devices, 0, (intptr_t)items);
  2206. if (cloud_menu)
  2207. {
  2208. int r = Menu_TrackSkinnedPopup(cloud_menu, TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,
  2209. itemRect.right, itemRect.top, hwndDlg, NULL);
  2210. if (r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_UPPER) { // deals with cloud specific menus
  2211. int ret = currentViewedDevice->dev->extraActions(DEVICE_DO_CLOUD_SOURCES_MENU, (intptr_t)r, 1, (intptr_t)items);
  2212. // only send a removal from the view if plug-in says so
  2213. if (ret) SendMessage(hwndDlg, WM_USER+1, (WPARAM)items->Get(0), ret);
  2214. }
  2215. DestroyMenu(cloud_menu);
  2216. }
  2217. delete items;
  2218. }
  2219. }
  2220. }
  2221. break;
  2222. }
  2223. }
  2224. else if(l->idFrom==IDC_LIST_ARTIST || l->idFrom==IDC_LIST_ALBUM || l->idFrom==IDC_LIST_ALBUM2)
  2225. {
  2226. switch(l->code) {
  2227. case NM_CUSTOMDRAW:
  2228. {
  2229. LRESULT result = 0;
  2230. if (ListView_OnCustomDraw(hwndDlg, (NMLVCUSTOMDRAW*)lParam, &result))
  2231. {
  2232. SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
  2233. return 1;
  2234. }
  2235. }
  2236. break;
  2237. }
  2238. }
  2239. }
  2240. break; //WM_NOTIFY
  2241. case WM_COMMAND:
  2242. switch(LOWORD(wParam)) {
  2243. case IDC_BUTTON_EJECT:
  2244. currentViewedDevice->Eject();
  2245. break;
  2246. case IDC_BUTTON_PLAY:
  2247. case ID_TRACKSLIST_PLAYSELECTION:
  2248. case IDC_BUTTON_ENQUEUE:
  2249. case ID_TRACKSLIST_ENQUEUESELECTION:
  2250. case IDC_BUTTON_CUSTOM:
  2251. {
  2252. if (HIWORD(wParam) == MLBN_DROPDOWN)
  2253. {
  2254. pmp_common_PlayEnqueue(hwndDlg, (HWND)lParam, LOWORD(wParam));
  2255. }
  2256. else
  2257. {
  2258. bool action;
  2259. if (LOWORD(wParam) == IDC_BUTTON_PLAY || LOWORD(wParam) == ID_TRACKSLIST_PLAYSELECTION)
  2260. action = (HIWORD(wParam) == 1) ? enqueuedef == 1 : 0;
  2261. else if (LOWORD(wParam) == IDC_BUTTON_ENQUEUE || LOWORD(wParam) == ID_TRACKSLIST_ENQUEUESELECTION)
  2262. action = (HIWORD(wParam) == 1) ? (enqueuedef != 1) : 1;
  2263. else
  2264. // so custom can work with the menu item part
  2265. break;
  2266. C_ItemList * selected = getSelectedItems();
  2267. currentViewedDevice->PlayTracks(selected, 0, action, true);
  2268. delete selected;
  2269. }
  2270. }
  2271. break;
  2272. default:
  2273. handleContextMenuResult(LOWORD(wParam));
  2274. break;
  2275. }
  2276. break; //WM_COMMAND
  2277. case WM_CONTEXTMENU:
  2278. {
  2279. // prevent the right-click menus appearing when scanning
  2280. if (aacontents && aacontents->bgThread_Handle) break;
  2281. POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
  2282. UINT_PTR idFrom = GetDlgCtrlID((HWND)wParam);
  2283. HWND hwndFrom = (HWND)wParam;
  2284. HWND hwndFromChild = WindowFromPoint(pt);
  2285. // deal with the column headers first
  2286. SkinnedListView * list=NULL;
  2287. int n = 0;
  2288. if (artistList && hwndFromChild == ListView_GetHeader(artistList->listview.getwnd())) { n=0; list=artistList; }
  2289. if (albumList && hwndFromChild == ListView_GetHeader(albumList->listview.getwnd())) { n=1; list=albumList; }
  2290. if (albumList2 && hwndFromChild == ListView_GetHeader(albumList2->listview.getwnd())) { n=2; list=albumList2; }
  2291. if (list)
  2292. {
  2293. HMENU menu = list->GetMenu(true,n,currentViewedDevice->config,m_context_menus);
  2294. int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hwndDlg, NULL);
  2295. list->ProcessMenuResult(r,true,n,currentViewedDevice->config,hwndDlg);
  2296. return 0;
  2297. }
  2298. // and then do the list menus
  2299. if(idFrom==IDC_LIST_ARTIST || idFrom==IDC_LIST_ALBUM || idFrom==IDC_LIST_ALBUM2)
  2300. {
  2301. handleContextMenuResult(showContextMenu(1,hwndFrom,currentViewedDevice->dev,pt));
  2302. }
  2303. else if(idFrom == IDC_LIST_TRACKS)
  2304. {
  2305. // prevents funkiness if having shown the 'customize columns' menu before
  2306. // as well as alloing the shift+f10 key to work within the track listview
  2307. if ((hwndFrom == hwndFromChild) || (pt.x == -1 && pt.y == -1))
  2308. {
  2309. int r = showContextMenu((GetDlgItem(hwndDlg, IDC_BUTTON_SORT) ? 2 : 0), hwndFrom, currentViewedDevice->dev, pt);
  2310. switch(r) {
  2311. case ID_TRACKSLIST_REMOVEFROMPLAYLIST:
  2312. SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(ID_TRACKSLIST_REMOVEFROMPLAYLIST,0),0);
  2313. break;
  2314. default:
  2315. handleContextMenuResult(r);
  2316. break;
  2317. }
  2318. }
  2319. }
  2320. break;
  2321. }
  2322. case WM_ML_CHILDIPC:
  2323. if(lParam == ML_CHILDIPC_GO_TO_SEARCHBAR)
  2324. {
  2325. SendDlgItemMessage(hwndDlg, IDC_QUICKSEARCH, EM_SETSEL, 0, -1);
  2326. SetFocus(GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
  2327. }
  2328. else if (lParam == ML_CHILDIPC_REFRESH_SEARCH)
  2329. {
  2330. restoreDone = FALSE;
  2331. PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_QUICKSEARCH, EN_CHANGE), (LPARAM)GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
  2332. }
  2333. break;
  2334. }
  2335. return 0;
  2336. }
  2337. typedef struct _LAYOUT
  2338. {
  2339. INT id;
  2340. HWND hwnd;
  2341. INT x;
  2342. INT y;
  2343. INT cx;
  2344. INT cy;
  2345. DWORD flags;
  2346. HRGN rgn;
  2347. }LAYOUT, PLAYOUT;
  2348. #define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; }
  2349. #define SETLAYOUTFLAGS(_layout, _r) \
  2350. { \
  2351. BOOL fVis; \
  2352. fVis = (WS_VISIBLE & (LONG)GetWindowLongPtr(_layout->hwnd, GWL_STYLE)); \
  2353. if (_layout->x == _r.left && _layout->y == _r.top) _layout->flags |= SWP_NOMOVE; \
  2354. if (_layout->cx == (_r.right - _r.left) && _layout->cy == (_r.bottom - _r.top)) _layout->flags |= SWP_NOSIZE; \
  2355. if ((SWP_HIDEWINDOW & _layout->flags) && !fVis) _layout->flags &= ~SWP_HIDEWINDOW; \
  2356. if ((SWP_SHOWWINDOW & _layout->flags) && fVis) _layout->flags &= ~SWP_SHOWWINDOW; \
  2357. }
  2358. #define LAYOUTNEEEDUPDATE(_layout) ((SWP_NOMOVE | SWP_NOSIZE) != ((SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_SHOWWINDOW) & _layout->flags))
  2359. // disabled cloud parts
  2360. /*#define GROUP_MIN 0x1
  2361. #define GROUP_MAX 0x7
  2362. #define GROUP_HEADER 0x1
  2363. #define GROUP_SEARCH 0x2
  2364. #define GROUP_FILTER 0x3
  2365. #define GROUP_HDELIM 0x4
  2366. #define GROUP_REFINE 0x5
  2367. #define GROUP_TRACKS 0x6
  2368. #define GROUP_STATUS 0x7*/
  2369. #define GROUP_MIN 0x1
  2370. #define GROUP_MAX 0x6
  2371. #define GROUP_SEARCH 0x1
  2372. #define GROUP_FILTER 0x2
  2373. #define GROUP_HDELIM 0x3
  2374. #define GROUP_REFINE 0x4
  2375. #define GROUP_TRACKS 0x5
  2376. #define GROUP_STATUS 0x6
  2377. void LayoutWindows(HWND hwnd, BOOL fRedraw, int simple)
  2378. {
  2379. static INT controls[] =
  2380. {
  2381. // disabled cloud parts
  2382. //GROUP_HEADER, IDC_HEADER_DEVICE_TRANSFER, IDC_HEADER_DEVICE_ICON, IDC_HEADER_DEVICE_NAME, IDC_HEADER_DEVICE_BAR, IDC_HEADER_DEVICE_SIZE, IDC_HDELIM2,
  2383. GROUP_SEARCH, IDC_BUTTON_ARTMODE, IDC_BUTTON_VIEWMODE, IDC_BUTTON_COLUMNS, IDC_SEARCH_TEXT, IDC_BUTTON_CLEARSEARCH, IDC_QUICKSEARCH,
  2384. 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,
  2385. GROUP_HDELIM, IDC_HDELIM,
  2386. GROUP_REFINE, IDC_REFINE_TEXT, IDC_BUTTON_CLEARREFINE, IDC_REFINE,
  2387. GROUP_TRACKS, IDC_LIST_TRACKS,
  2388. GROUP_FILTER, IDC_LIST_ARTIST, IDC_VDELIM, IDC_LIST_ALBUM, IDC_VDELIM2, IDC_LIST_ALBUM2,
  2389. };
  2390. INT index, divY, divX, divX2, divCY;
  2391. RECT rc, rg, ri;
  2392. LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
  2393. BOOL skipgroup;
  2394. HRGN rgn;
  2395. rgn = NULL;
  2396. GetClientRect(hwnd, &rc);
  2397. if (rc.right == rc.left || rc.bottom == rc.top) return;
  2398. if (rc.right > 4) rc.right -= 4;
  2399. SetRect(&rg, rc.left, rc.top, rc.right, rc.top);
  2400. pl = layout;
  2401. skipgroup = FALSE;
  2402. divX = (adiv1pos * (rc.right- rc.left)) / 100000;
  2403. divX2 = numFilters == 3 ? ((adiv3pos * (rc.right- rc.left)) / 100000) : rc.right;
  2404. divY = (((-1 == adiv2pos) ? 50000 : adiv2pos) * (rc.bottom- rc.top)) / 100000;
  2405. divCY = 0;
  2406. InvalidateRect(hwnd, NULL, TRUE);
  2407. for (index = 0; index < sizeof(controls) / sizeof(INT); index++)
  2408. {
  2409. if (controls[index] >= GROUP_MIN && controls[index] <= GROUP_MAX) // group id
  2410. {
  2411. skipgroup = FALSE;
  2412. switch(controls[index])
  2413. {
  2414. // disabled cloud parts
  2415. /*case GROUP_HEADER:
  2416. if (currentViewedDevice->isCloudDevice && simple != 2)
  2417. {
  2418. SetRect(&rg, rc.left, rc.top + WASABI_API_APP->getScaleY(2),
  2419. rc.right + WASABI_API_APP->getScaleX(1),
  2420. (!header ? rc.top + WASABI_API_APP->getScaleY(18) : rc.top));
  2421. rc.top = rg.bottom + WASABI_API_APP->getScaleY(3);
  2422. }
  2423. else
  2424. skipgroup = 1;
  2425. break;*/
  2426. case GROUP_SEARCH:
  2427. if (g_displaysearch && simple != 2)
  2428. {
  2429. wchar_t buffer[128] = {0};
  2430. HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARSEARCH);
  2431. GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
  2432. LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
  2433. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
  2434. rc.top + WASABI_API_APP->getScaleY(2),
  2435. rc.right - WASABI_API_APP->getScaleX(2),
  2436. rc.top + WASABI_API_APP->getScaleY(HIWORD(idealSize)+1));
  2437. rc.top = rg.bottom + WASABI_API_APP->getScaleY(3);
  2438. }
  2439. else
  2440. skipgroup = 1;
  2441. break;
  2442. case GROUP_STATUS:
  2443. if (g_displaystatus)
  2444. {
  2445. wchar_t buffer[128] = {0};
  2446. HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_EJECT);
  2447. GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
  2448. LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
  2449. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
  2450. rc.bottom - WASABI_API_APP->getScaleY(HIWORD(idealSize)),
  2451. rc.right, rc.bottom);
  2452. rc.bottom = rg.top - WASABI_API_APP->getScaleY(3);
  2453. }
  2454. skipgroup = !g_displaystatus;
  2455. break;
  2456. case GROUP_HDELIM:
  2457. SetRect(&rg, rc.left, rc.top, rc.right, rc.bottom);
  2458. break;
  2459. case GROUP_REFINE:
  2460. {
  2461. wchar_t buffer[128] = {0};
  2462. HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARREFINE);
  2463. GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
  2464. LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
  2465. rg.top = divY + divCY;
  2466. refineHidden = (g_displayrefine) ? ((rg.top + WASABI_API_APP->getScaleY(HIWORD(idealSize))) >= rc.bottom) : TRUE;
  2467. SetRect(&rg, rc.left, rg.top, rc.right, (refineHidden) ? rg.top : (rg.top + WASABI_API_APP->getScaleY(HIWORD(idealSize))));
  2468. break;
  2469. }
  2470. case GROUP_TRACKS:
  2471. if (!simple)
  2472. {
  2473. wchar_t buffer[128] = {0};
  2474. HWND ctrl = GetDlgItem(hwnd, IDC_BUTTON_CLEARREFINE);
  2475. GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
  2476. LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
  2477. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
  2478. (divY + divCY) + ((!refineHidden) ? WASABI_API_APP->getScaleY(HIWORD(idealSize) + 3) : 0),
  2479. rc.right, rc.bottom);
  2480. }
  2481. else
  2482. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, rc.bottom);
  2483. break;
  2484. case GROUP_FILTER:
  2485. if (!simple)
  2486. {
  2487. if (divX < (rc.left + 15))
  2488. {
  2489. divX = rc.left;
  2490. adiv1_nodraw = 1;
  2491. }
  2492. else if (divX > (rc.right - (numFilters == 3 ? 16 * 2 : 24)))
  2493. {
  2494. RECT rw;
  2495. GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM), &rw);
  2496. divX = rc.right - (rw.right - rw.left) - (numFilters == 3 ? 6 : 0) + (numFilters == 2 ? 1 : -1);
  2497. adiv1_nodraw = 2;
  2498. }
  2499. else adiv1_nodraw = 0;
  2500. if (divX2 < (rc.left + 16 * (numFilters == 3 ? 2 : 1)))
  2501. {
  2502. RECT rw;
  2503. GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM), &rw);
  2504. divX2 = rc.left;
  2505. adiv3_nodraw = 1;
  2506. }
  2507. else if (divX2 > (rc.right - 16 * 2))
  2508. {
  2509. RECT rw;
  2510. GetWindowRect(GetDlgItem(hwnd, IDC_VDELIM2), &rw);
  2511. divX2 = rc.right - ((rw.right - rw.left) - 1) * 2;
  2512. adiv3_nodraw = 2;
  2513. }
  2514. else adiv3_nodraw = 0;
  2515. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1), rc.top, rc.right, divY);
  2516. }
  2517. else
  2518. skipgroup = 1;
  2519. break;
  2520. }
  2521. continue;
  2522. }
  2523. if (skipgroup) continue;
  2524. pl->id = controls[index];
  2525. pl->hwnd = GetDlgItem(hwnd, pl->id);
  2526. if (!pl->hwnd) continue;
  2527. GetWindowRect(pl->hwnd, &ri);
  2528. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2);
  2529. pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS;
  2530. switch(pl->id)
  2531. {
  2532. // disabled cloud parts
  2533. /*case IDC_HEADER_DEVICE_TRANSFER:
  2534. SETLAYOUTPOS(pl, rg.right - 18, rg.top - WASABI_API_APP->getScaleY(1),
  2535. WASABI_API_APP->getScaleX(16), WASABI_API_APP->getScaleY(16));
  2536. pl->flags |= (!header && (rg.right - rg.left) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2537. if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(3+16));
  2538. break;
  2539. case IDC_HEADER_DEVICE_ICON:
  2540. SETLAYOUTPOS(pl, rg.left, rg.top - WASABI_API_APP->getScaleY(1),
  2541. WASABI_API_APP->getScaleX(16), WASABI_API_APP->getScaleY(16));
  2542. pl->flags |= (!header && (rg.right - rg.left + WASABI_API_APP->getScaleX(16)) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2543. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2544. break;
  2545. case IDC_HEADER_DEVICE_NAME:
  2546. {
  2547. SIZE s = {0};
  2548. wchar_t buf[128] = {0};
  2549. HDC dc = GetDC(pl->hwnd);
  2550. HFONT font = (HFONT)SendMessage(pl->hwnd, WM_GETFONT, 0, 0), oldfont = (HFONT)SelectObject(dc, font);
  2551. int len = GetWindowText(pl->hwnd, buf, sizeof(buf));
  2552. GetTextExtentPoint32(dc, buf, len, &s);
  2553. SelectObject(dc, oldfont);
  2554. ReleaseDC(pl->hwnd, dc);
  2555. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top, s.cx + ((s.cx / len)), WASABI_API_APP->getScaleY(16));
  2556. pl->flags |= (!header && (rg.right - rg.left + WASABI_API_APP->getScaleX(12)) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2557. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2558. break;
  2559. }
  2560. case IDC_HEADER_DEVICE_BAR:
  2561. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top + WASABI_API_APP->getScaleY(2),
  2562. WASABI_API_APP->getScaleX(150), WASABI_API_APP->getScaleY(11));
  2563. pl->flags |= (!header && (rg.right - rg.left) > (ri.right - ri.left)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2564. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(8));
  2565. break;
  2566. case IDC_HEADER_DEVICE_SIZE:
  2567. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(4), rg.top, rg.right - rg.left, WASABI_API_APP->getScaleY(16));
  2568. pl->flags |= (!header && (ri.right - ri.left) > WASABI_API_APP->getScaleX(60)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2569. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2570. break;
  2571. case IDC_HDELIM2:
  2572. SETLAYOUTPOS(pl, 0, rg.bottom + WASABI_API_APP->getScaleY(1), rg.right + WASABI_API_APP->getScaleX(35), 0);
  2573. pl->flags |= (!header ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
  2574. break;*/
  2575. case IDC_BUTTON_ARTMODE:
  2576. case IDC_BUTTON_VIEWMODE:
  2577. case IDC_BUTTON_COLUMNS:
  2578. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2579. SETLAYOUTPOS(pl, rg.left, rg.top, (ri.right - ri.left), (rg.bottom - rg.top));
  2580. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(1));
  2581. break;
  2582. case IDC_SEARCH_TEXT:
  2583. {
  2584. wchar_t buffer[128] = {0};
  2585. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2586. LRESULT idealSize = MLSkinnedStatic_GetIdealSize(pl->hwnd, buffer);
  2587. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2588. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(6),
  2589. rg.top + WASABI_API_APP->getScaleY(1),
  2590. WASABI_API_APP->getScaleX(LOWORD(idealSize)),
  2591. (rg.bottom - rg.top));
  2592. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2593. break;
  2594. }
  2595. case IDC_REFINE_TEXT:
  2596. {
  2597. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2598. wchar_t buffer[128] = {0};
  2599. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2600. LRESULT idealSize = MLSkinnedStatic_GetIdealSize(pl->hwnd, buffer);
  2601. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(2),
  2602. rg.top + WASABI_API_APP->getScaleY(1),
  2603. WASABI_API_APP->getScaleX(LOWORD(idealSize)),
  2604. (rg.bottom - rg.top));
  2605. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2606. break;
  2607. }
  2608. case IDC_BUTTON_CLEARSEARCH:
  2609. {
  2610. wchar_t buffer[128] = {0};
  2611. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2612. LRESULT idealSize = MLSkinnedButton_GetIdealSize(pl->hwnd, buffer);
  2613. LONG width = LOWORD(idealSize) + WASABI_API_APP->getScaleX(6);
  2614. pl->flags |= (((rg.right - rg.left) - width) > WASABI_API_APP->getScaleX(40)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2615. SETLAYOUTPOS(pl, rg.right - width, rg.top, width, (rg.bottom - rg.top));
  2616. if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(4));
  2617. break;
  2618. }
  2619. case IDC_BUTTON_CLEARREFINE:
  2620. {
  2621. wchar_t buffer[128] = {0};
  2622. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2623. LRESULT idealSize = MLSkinnedButton_GetIdealSize(pl->hwnd, buffer);
  2624. LONG width = LOWORD(idealSize) + WASABI_API_APP->getScaleX(6);
  2625. pl->flags |= (((rg.right - rg.left) - width) > WASABI_API_APP->getScaleX(40)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW ;
  2626. SETLAYOUTPOS(pl, rg.right - width, rg.top, width, rg.bottom - rg.top);
  2627. if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(4));
  2628. break;
  2629. }
  2630. case IDC_QUICKSEARCH:
  2631. pl->flags |= SWP_SHOWWINDOW;
  2632. pl->flags |= (rg.right > rg.left) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2633. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(1),
  2634. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  2635. break;
  2636. case IDC_REFINE:
  2637. pl->flags |= ((rg.right > rg.left) && (rg.top < rg.bottom)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2638. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(1),
  2639. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  2640. break;
  2641. case IDC_BUTTON_EJECT:
  2642. {
  2643. if (currentViewedDevice->isCloudDevice)
  2644. {
  2645. if (currentViewedDevice->dev->extraActions(DEVICE_DOES_NOT_SUPPORT_REMOVE,0,0,0))
  2646. {
  2647. pl->flags |= SWP_HIDEWINDOW;
  2648. break;
  2649. }
  2650. }
  2651. wchar_t buffer[128] = {0};
  2652. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2653. LRESULT idealSize = MLSkinnedButton_GetIdealSize(pl->hwnd, buffer);
  2654. LONG width = LOWORD(idealSize) + WASABI_API_APP->getScaleX(6);
  2655. SETLAYOUTPOS(pl, rg.right - width + WASABI_API_APP->getScaleX(2),
  2656. rg.bottom - WASABI_API_APP->getScaleY(HIWORD(idealSize)),
  2657. width, WASABI_API_APP->getScaleY(HIWORD(idealSize)));
  2658. pl->flags |= ((rg.right - rg.left) > width) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2659. if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(3));
  2660. break;
  2661. }
  2662. case IDC_BUTTON_AUTOFILL:
  2663. if (currentViewedDevice->isCloudDevice)
  2664. {
  2665. pl->flags |= SWP_HIDEWINDOW;
  2666. break;
  2667. }
  2668. case IDC_BUTTON_SYNC:
  2669. if (currentViewedDevice->isCloudDevice)
  2670. {
  2671. if (!lstrcmpiA(currentViewedDevice->GetName(), "all_sources"))
  2672. {
  2673. pl->flags |= SWP_HIDEWINDOW;
  2674. break;
  2675. }
  2676. }
  2677. case IDC_BUTTON_PLAY:
  2678. case IDC_BUTTON_ENQUEUE:
  2679. case IDC_BUTTON_CUSTOM:
  2680. case IDC_BUTTON_SORT:
  2681. {
  2682. if (IDC_BUTTON_CUSTOM != pl->id || customAllowed)
  2683. {
  2684. if (groupBtn && (pl->id == IDC_BUTTON_PLAY) && (enqueuedef == 1))
  2685. {
  2686. pl->flags |= SWP_HIDEWINDOW;
  2687. break;
  2688. }
  2689. if (groupBtn && (pl->id == IDC_BUTTON_ENQUEUE) && (enqueuedef != 1))
  2690. {
  2691. pl->flags |= SWP_HIDEWINDOW;
  2692. break;
  2693. }
  2694. if (groupBtn && (pl->id == IDC_BUTTON_PLAY || pl->id == IDC_BUTTON_ENQUEUE) && customAllowed)
  2695. {
  2696. pl->flags |= SWP_HIDEWINDOW;
  2697. break;
  2698. }
  2699. wchar_t buffer[128] = {0};
  2700. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  2701. LRESULT idealSize = MLSkinnedButton_GetIdealSize(pl->hwnd, buffer);
  2702. LONG width = LOWORD(idealSize) + WASABI_API_APP->getScaleX(6);
  2703. SETLAYOUTPOS(pl, rg.left, rg.bottom - WASABI_API_APP->getScaleY(HIWORD(idealSize)),
  2704. width, WASABI_API_APP->getScaleY(HIWORD(idealSize)));
  2705. pl->flags |= ((rg.right - rg.left) > width) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2706. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(4));
  2707. }
  2708. else
  2709. pl->flags |= SWP_HIDEWINDOW;
  2710. break;
  2711. }
  2712. case IDC_STATUS:
  2713. SETLAYOUTPOS(pl, rg.left, rg.bottom - WASABI_API_APP->getScaleY(18), rg.right - rg.left, WASABI_API_APP->getScaleY(17));
  2714. if (SWP_SHOWWINDOW & pl->flags) rg.top = (pl->y + pl->cy + WASABI_API_APP->getScaleY(1));
  2715. break;
  2716. case IDC_HDELIM:
  2717. divCY = ri.bottom - ri.top;
  2718. if (divY > (rg.bottom - WASABI_API_APP->getScaleY(70))) { divY = rg.bottom - divCY; m_nodrawtopborders = 2; }
  2719. else if (divY < (rg.top + WASABI_API_APP->getScaleY(36))) { divY = rg.top; m_nodrawtopborders = 1; }
  2720. else m_nodrawtopborders = 0;
  2721. SETLAYOUTPOS(pl, rg.left, divY, rg.right - rg.left + WASABI_API_APP->getScaleX(2), (ri.bottom - ri.top));
  2722. break;
  2723. case IDC_LIST_TRACKS:
  2724. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  2725. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1),
  2726. (rg.right - rg.left) + WASABI_API_APP->getScaleX(1),
  2727. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(2));
  2728. break;
  2729. case IDC_LIST_ARTIST:
  2730. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), divX, (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  2731. rg.left += pl->cx;
  2732. break;
  2733. case IDC_VDELIM:
  2734. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (ri.right - ri.left), (rg.bottom - rg.top));
  2735. rg.left += pl->cx;
  2736. break;
  2737. case IDC_LIST_ALBUM:
  2738. if(numFilters == 3)
  2739. {
  2740. BOOL hide = ((divX2 - divX - 1) < WASABI_API_APP->getScaleX(15));
  2741. pl->flags |= hide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW;
  2742. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (hide ? 0 : divX2 - divX - WASABI_API_APP->getScaleX(1)),
  2743. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  2744. }
  2745. else { SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) + WASABI_API_APP->getScaleX(1),
  2746. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1)); }
  2747. rg.left += pl->cx;
  2748. break;
  2749. case IDC_VDELIM2:
  2750. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (numFilters == 2 ? 0 : ri.right - ri.left), (rg.bottom - rg.top));
  2751. rg.left += pl->cx;
  2752. break;
  2753. case IDC_LIST_ALBUM2:
  2754. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) + WASABI_API_APP->getScaleX(1),
  2755. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(2));
  2756. break;
  2757. }
  2758. SETLAYOUTFLAGS(pl, ri);
  2759. if (LAYOUTNEEEDUPDATE(pl))
  2760. {
  2761. if (SWP_NOSIZE == ((SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_NOSIZE) & pl->flags) &&
  2762. ri.left == (pl->x + offsetX) && ri.top == (pl->y + offsetY) && IsWindowVisible(pl->hwnd))
  2763. {
  2764. SetRect(&ri, pl->x, pl->y, pl->cx + pl->x, pl->y + pl->cy);
  2765. ValidateRect(hwnd, &ri);
  2766. }
  2767. pl++;
  2768. }
  2769. else if ((fRedraw || (!offsetX && !offsetY)) && IsWindowVisible(pl->hwnd))
  2770. {
  2771. ValidateRect(hwnd, &ri);
  2772. if (GetUpdateRect(pl->hwnd, NULL, FALSE))
  2773. {
  2774. if (!rgn) rgn = CreateRectRgn(0, 0, 0, 0);
  2775. GetUpdateRgn(pl->hwnd, rgn, FALSE);
  2776. OffsetRgn(rgn, pl->x, pl->y);
  2777. InvalidateRgn(hwnd, rgn, FALSE);
  2778. }
  2779. }
  2780. }
  2781. if (pl != layout)
  2782. {
  2783. LAYOUT *pc;
  2784. HDWP hdwp = BeginDeferWindowPos((INT)(pl - layout));
  2785. for(pc = layout; pc < pl && hdwp; pc++)
  2786. {
  2787. hdwp = DeferWindowPos(hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags);
  2788. }
  2789. if (hdwp) EndDeferWindowPos(hdwp);
  2790. if (!rgn) rgn = CreateRectRgn(0, 0, 0, 0);
  2791. if (fRedraw)
  2792. {
  2793. GetUpdateRgn(hwnd, rgn, FALSE);
  2794. for(pc = layout; pc < pl && hdwp; pc++)
  2795. {
  2796. if (pc->rgn)
  2797. {
  2798. OffsetRgn(pc->rgn, pc->x, pc->y);
  2799. CombineRgn(rgn, rgn, pc->rgn, RGN_OR);
  2800. }
  2801. }
  2802. RedrawWindow(hwnd, NULL, rgn, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASENOW | RDW_ALLCHILDREN);
  2803. }
  2804. if (g_rgnUpdate)
  2805. {
  2806. GetUpdateRgn(hwnd, g_rgnUpdate, FALSE);
  2807. for(pc = layout; pc < pl && hdwp; pc++)
  2808. {
  2809. if (pc->rgn)
  2810. {
  2811. OffsetRgn(pc->rgn, pc->x, pc->y);
  2812. CombineRgn(g_rgnUpdate, g_rgnUpdate, pc->rgn, RGN_OR);
  2813. }
  2814. }
  2815. }
  2816. for(pc = layout; pc < pl && hdwp; pc++) if (pc->rgn) DeleteObject(pc->rgn);
  2817. }
  2818. if (rgn) DeleteObject(rgn);
  2819. ValidateRgn(hwnd, NULL);
  2820. }
  2821. static void WINAPI OnDividerMoved(HWND hwnd, INT nPos, LPARAM param)
  2822. {
  2823. RECT rc;
  2824. HWND hwndParent;
  2825. hwndParent = GetParent(hwnd);
  2826. KillTimer(hwndParent,400);
  2827. SetTimer(hwndParent,400,1000,NULL);
  2828. if (hwndParent)
  2829. {
  2830. GetClientRect(hwndParent, &rc);
  2831. switch((INT)param)
  2832. {
  2833. case IDC_VDELIM:
  2834. {
  2835. adiv1pos = (nPos * 100000) / (rc.right - rc.left + 10);
  2836. if(adiv1pos + 500 >= adiv3pos) adiv3pos = adiv1pos + 500;
  2837. }
  2838. break;
  2839. case IDC_HDELIM:
  2840. adiv2pos = (nPos * 100000) / (rc.bottom - rc.top);
  2841. break;
  2842. case IDC_VDELIM2:
  2843. {
  2844. adiv3pos = (nPos * 100000) / (rc.right - rc.left + 10);
  2845. if(adiv3pos - 500 < adiv1pos) adiv1pos = adiv3pos - 500;
  2846. }
  2847. break;
  2848. }
  2849. LayoutWindows(hwndParent, TRUE, 0);
  2850. }
  2851. }
  2852. static BOOL AttachDivider(HWND hwnd, BOOL fVertical, DIVIDERMOVED callback, LPARAM param)
  2853. {
  2854. if (!hwnd) return FALSE;
  2855. DIVIDER *pd = (DIVIDER*)calloc(1, sizeof(DIVIDER));
  2856. if (!pd) return FALSE;
  2857. pd->fUnicode = IsWindowUnicode(hwnd);
  2858. pd->fnOldProc = (WNDPROC) ((pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc) :
  2859. SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc));
  2860. if (!pd->fnOldProc || !SetPropW(hwnd, L"DIVDATA", pd))
  2861. {
  2862. free(pd);
  2863. return FALSE;
  2864. }
  2865. pd->fVertical = fVertical;
  2866. pd->param = param;
  2867. pd->callback = callback;
  2868. return TRUE;
  2869. }
  2870. static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2871. {
  2872. DIVIDER *pd;
  2873. pd = GET_DIVIDER(hwnd);
  2874. if (!pd) return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
  2875. switch(uMsg)
  2876. {
  2877. case WM_DESTROY:
  2878. RemovePropW(hwnd, L"DIVDATA");
  2879. (pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
  2880. (pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc) : SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc);
  2881. free(pd);
  2882. return 0;
  2883. case WM_LBUTTONDOWN:
  2884. pd->clickoffs = (pd->fVertical) ? LOWORD(lParam) : HIWORD(lParam);
  2885. SetCapture(hwnd);
  2886. break;
  2887. case WM_LBUTTONUP:
  2888. ReleaseCapture();
  2889. break;
  2890. case WM_SETCURSOR:
  2891. SetCursor(LoadCursor(NULL, (pd->fVertical) ? IDC_SIZEWE : IDC_SIZENS));
  2892. return TRUE;
  2893. case WM_MOUSEMOVE:
  2894. {
  2895. RECT rw;
  2896. GetWindowRect(hwnd, &rw);
  2897. GetCursorPos(((LPPOINT)&rw) + 1);
  2898. (pd->fVertical) ? rw.right -= pd->clickoffs : rw.bottom -= pd->clickoffs;
  2899. if ((pd->fVertical && rw.left != rw.right) || (!pd->fVertical && rw.top != rw.bottom))
  2900. {
  2901. MapWindowPoints(HWND_DESKTOP, GetParent(hwnd), ((LPPOINT)&rw) + 1, 1);
  2902. if (pd->callback) pd->callback(hwnd, (pd->fVertical) ? rw.right : rw.bottom, pd->param);
  2903. }
  2904. }
  2905. break;
  2906. }
  2907. return (pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
  2908. }