view_audio.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403
  1. #include "main.h"
  2. #include "api__ml_local.h"
  3. #include "ml_local.h"
  4. #include <windowsx.h>
  5. #include "../nu/listview.h"
  6. #include "resource.h"
  7. #include "..\..\General\gen_ml/config.h"
  8. #include "..\..\General\gen_ml/ml_ipc.h"
  9. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  10. #include "..\..\General\gen_ml/gaystring.h"
  11. #include "../nde/nde_c.h"
  12. #include <shlwapi.h>
  13. #include "SimpleFilter.h"
  14. #include "AlbumFilter.h"
  15. #include "AlbumArtFilter.h"
  16. #include "../replicant/nu/AutoChar.h"
  17. #include "../replicant/nu/AutoWide.h"
  18. #include "../nu/CGlobalAtom.h"
  19. #include <tataki/export.h>
  20. #include <tataki/bitmap/bitmap.h>
  21. #include <tataki/canvas/bltcanvas.h>
  22. static CGlobalAtom PROPW_DIVDATA(L"DIVDATA");
  23. #define DELIMSTR "|"
  24. #define LDELIMSTR L"|"
  25. #define MAX_FILTERS 3
  26. ViewFilter *filter[MAX_FILTERS] = {0};
  27. int numFilters = 0;
  28. extern void queryStrEscape(const char *raw, GayString &str);
  29. extern void FixAmps(wchar_t *str, size_t size);
  30. static W_ListView m_list1;
  31. static W_ListView m_list2;
  32. static W_ListView m_list3;
  33. static HWND m_media_hwnd;
  34. static HWND m_hwnd;
  35. GayStringW l_query;
  36. static int IPC_LIBRARY_SENDTOMENU;
  37. static int m_sort_by, m_sort_dir, m_sort_which;
  38. static HRGN g_rgnUpdate = NULL;
  39. static int offsetX = 0, offsetY = 0;
  40. enum
  41. {
  42. PLAY=0,
  43. ENQUEUE=1,
  44. };
  45. #define ARTIST 0x01
  46. #define ALBUMARTIST 0x02
  47. #define GENRE 0x03
  48. #define PUBLISHER 0x04
  49. #define COMPOSER 0x05
  50. #define ALBUM 0x06
  51. #define YEAR 0x07
  52. #define ARTISTINDEX 0x08
  53. #define ALBUMARTISTINDEX 0x09
  54. #define PODCASTCHANNEL 0x0A
  55. #define ALBUMART 0x0B
  56. #define CATEGORY 0x0C
  57. #define DIRECTOR 0x0D
  58. #define PRODUCER 0x0E
  59. #define MAKEVIEW_3FILTER(a, b, c) (a | (b << 8) | (c << 16))
  60. #define MAKEVIEW_2FILTER(a, b) (a | (b << 8))
  61. static ViewFilter * getFilter(int n, HWND hwndDlg, int dlgitem, C_Config *c)
  62. {
  63. switch (n)
  64. {
  65. case 0: return new ArtistFilter();
  66. case 1: return new AlbumArtistFilter();
  67. case 2: return new GenreFilter();
  68. case 3: return new PublisherFilter();
  69. case 4: return new ComposerFilter();
  70. case 5: return new AlbumFilter();
  71. case 6: return new YearFilter();
  72. case 7: return new ArtistIndexFilter();
  73. case 8: return new AlbumArtistIndexFilter();
  74. case 9: return new PodcastChannelFilter();
  75. case 10: return new AlbumArtFilter(hwndDlg,dlgitem,c);
  76. case 11: return new CategoryFilter();
  77. case 12: return new DirectorFilter();
  78. case 13: return new ProducerFilter();
  79. }
  80. return new ArtistFilter();
  81. }
  82. const wchar_t *getFilterName(unsigned int filterId, wchar_t *buffer, size_t bufferSize) // for config
  83. {
  84. const int filterNames[] =
  85. {
  86. IDS_ARTIST,
  87. IDS_ALBUM_ARTIST,
  88. IDS_GENRE,
  89. IDS_PUBLISHER,
  90. IDS_COMPOSER,
  91. IDS_ALBUM,
  92. IDS_YEAR,
  93. IDS_ARTIST_INDEX,
  94. IDS_ALBUM_ARTIST_INDEX,
  95. IDS_PODCAST_CHANNEL,
  96. IDS_ALBUM_ART,
  97. IDS_CATEGORY,
  98. IDS_DIRECTOR,
  99. IDS_PRODUCER,
  100. };
  101. if (filterId >= ARRAYSIZE(filterNames))
  102. return NULL;
  103. return WASABI_API_LNGSTRINGW_BUF(filterNames[filterId], buffer, bufferSize);
  104. }
  105. static void mysearchCallbackAlbumUpdate(itemRecordW *items, int numitems, int user32, int *killswitch)
  106. {
  107. if (killswitch && *killswitch) return;
  108. // user32 specifies whether or not to bother with rebuilding artist list
  109. if (user32 == 2 && numFilters == 2) return;
  110. if (user32 <= 2 && numFilters >= 3)
  111. filter[2]->Fill(items,numitems,killswitch,0);
  112. if (user32 <= 1 && numFilters >= 2)
  113. filter[1]->Fill(items,numitems,killswitch,numFilters >= 3 ? filter[2]->numGroups : 0);
  114. if (user32 == 0 && numFilters >= 1)
  115. filter[0]->Fill(items, numitems, killswitch,numFilters >= 2 ? filter[1]->numGroups : 0);
  116. PostMessage(m_hwnd, WM_APP + 3, 0x69, user32);
  117. }
  118. static int makeFilterQuery(GayStringW *query, ViewFilter *f)
  119. {
  120. int ret = 0;
  121. if (!(f->list->GetSelected(0) && f->HasTopItem()))
  122. {
  123. int c = f->list->GetCount();
  124. int selCount = SendMessageW(f->list->getwnd(), LVM_GETSELECTEDCOUNT, 0, 0L);
  125. if (selCount && ((f->HasTopItem()) ? selCount < (c - 1) : selCount < c))
  126. {
  127. int needor = 0, needclose = 0;
  128. for (int x = f->HasTopItem()?1:0; x < c; x ++)
  129. {
  130. if (f->list->GetSelected(x))
  131. {
  132. if (needor)
  133. query->Append(L"|");
  134. else
  135. {
  136. if (query->Get()[0])
  137. query->Append(L"&(");
  138. else
  139. query->Set(L"(");
  140. needclose = 1;
  141. }
  142. if (!f->MakeFilterQuery(x,query))
  143. {
  144. const wchar_t *val = f->GetText(x);
  145. if (val && *val)
  146. {
  147. query->Append(f->GetField());
  148. query->Append(L" ");
  149. query->Append(f->GetComparisonOperator());
  150. query->Append(L" \"");
  151. GayStringW escaped;
  152. queryStrEscape(val, escaped);
  153. query->Append(escaped.Get());
  154. query->Append(L"\"");
  155. }
  156. else
  157. {
  158. const wchar_t *field = f->GetField();
  159. query->Append(field);
  160. query->Append(L" = \"\" | ");
  161. query->Append(field);
  162. query->Append(L" ISEMPTY");
  163. }
  164. }
  165. ret++;
  166. needor = 1;
  167. }
  168. }
  169. if (needclose) query->Append(L")");
  170. }
  171. }
  172. return ret;
  173. }
  174. static void getParentPlusSearchQuery(GayStringW *gs)
  175. {
  176. extern wchar_t* m_query;
  177. wchar_t *parq = m_query;
  178. if (parq && parq[0])
  179. {
  180. gs->Set(L"(");
  181. gs->Append(parq);
  182. gs->Append(L")");
  183. }
  184. else gs->Set(L"");
  185. GayStringW query;
  186. wchar_t buf[2048] = {0};
  187. GetWindowTextW(GetDlgItem(m_hwnd, IDC_QUICKSEARCH), buf, ARRAYSIZE(buf));
  188. if (buf[0]) makeQueryStringFromText(&query, buf);
  189. if (query.Get() && query.Get()[0])
  190. {
  191. if (gs->Get()[0])
  192. {
  193. gs->Append(L" & (");
  194. gs->Append(query.Get());
  195. gs->Append(L")");
  196. }
  197. else gs->Set(query.Get());
  198. }
  199. }
  200. static void playList(int enqueue, int pane)
  201. {
  202. GayStringW query;
  203. getParentPlusSearchQuery(&query);
  204. for (int i=0; i<=pane; i++)
  205. makeFilterQuery(&query,filter[i]);
  206. if (!g_table) return;
  207. main_playQuery(g_view_metaconf, query.Get(), enqueue);
  208. }
  209. static void playRandomList(int enqueue, int pane)
  210. {
  211. static int inited = 0;
  212. if (!inited)
  213. srand((unsigned)(time(0)));
  214. inited = 1;
  215. int n;
  216. n = filter[pane]->list->GetCount() * rand()/RAND_MAX;
  217. // Martin> dunno if we should display the results in ML then? atm we are
  218. filter[pane]->list->UnselectAll();
  219. filter[pane]->list->SetSelected(n);
  220. filter[pane]->list->ScrollTo(n);
  221. playList(enqueue, pane);
  222. }
  223. static void buildRecordListW(itemRecordListW *obj, int pane)
  224. {
  225. GayStringW query;
  226. getParentPlusSearchQuery(&query);
  227. for (int i=0; i<=pane; i++)
  228. makeFilterQuery(&query,filter[i]);
  229. if (!g_table) return;
  230. EnterCriticalSection(&g_db_cs);
  231. nde_scanner_t s = NDE_Table_CreateScanner(g_table);
  232. NDE_Scanner_Query(s, query.Get());
  233. saveQueryToListW(g_view_metaconf, s, obj, 0, 0, (resultsniff_funcW)-1);
  234. NDE_Table_DestroyScanner(g_table, s);
  235. LeaveCriticalSection(&g_db_cs);
  236. }
  237. void UpdateRating_RowCache(const wchar_t *filename, int new_rating);
  238. static bool rateList(int rate)
  239. {
  240. GayStringW query;
  241. getParentPlusSearchQuery(&query);
  242. int valid = 0;
  243. for (int i=0; i<numFilters; i++)
  244. valid += makeFilterQuery(&query,filter[i]);
  245. if (valid)
  246. {
  247. EnterCriticalSection(&g_db_cs);
  248. nde_scanner_t s = NDE_Table_CreateScanner(g_table);
  249. NDE_Scanner_Query(s, query.Get());
  250. NDE_Scanner_First(s);
  251. do
  252. {
  253. nde_field_t f = NDE_Scanner_GetFieldByID(s, MAINTABLE_ID_FILENAME);
  254. if (!f) break;
  255. // get filename here as calling later fails due to the edit for some reason
  256. // as was being called directly in the updateFileInfo(..) call previously..
  257. wchar_t *filename = NDE_StringField_GetString(f);
  258. if (!filename) break;
  259. // update before, so we can take advantage of row cache pointer equality (sometimes)
  260. UpdateRating_RowCache(filename, rate);
  261. NDE_Scanner_Edit(s);
  262. db_setFieldInt(s, MAINTABLE_ID_RATING, rate);
  263. NDE_Scanner_Post(s);
  264. if (g_config->ReadInt(L"writeratings", 0))
  265. {
  266. wchar_t buf[64] = {0};
  267. if (rate > 0)
  268. {
  269. wsprintfW(buf, L"%d", rate);
  270. }
  271. else
  272. buf[0] = 0;
  273. updateFileInfo(filename, DB_FIELDNAME_rating, buf);
  274. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITE_EXTENDED_FILE_INFO);
  275. }
  276. g_table_dirty++;
  277. }
  278. while (NDE_Scanner_Next(s));
  279. NDE_Table_DestroyScanner(g_table, s);
  280. if (g_table_dirty) NDE_Table_Sync(g_table);
  281. g_table_dirty = 0;
  282. LeaveCriticalSection(&g_db_cs);
  283. // refresh media list
  284. // SendMessage(m_media_hwnd, WM_APP + 1, (WPARAM)0, (LPARAM)0);
  285. return true;
  286. }
  287. return false;
  288. }
  289. static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  290. typedef void (WINAPI *DIVIDERMOVED)(HWND, INT, LPARAM);
  291. typedef struct _DIVIDER
  292. {
  293. BOOL fVertical;
  294. DIVIDERMOVED callback;
  295. LPARAM param;
  296. WNDPROC fnOldProc;
  297. BOOL fUnicode;
  298. INT clickoffs;
  299. } DIVIDER;
  300. BOOL AttachDivider(HWND hwnd, BOOL fVertical, DIVIDERMOVED callback, LPARAM param)
  301. {
  302. if (!hwnd) return FALSE;
  303. DIVIDER *pd = (DIVIDER*)calloc(1, sizeof(DIVIDER));
  304. if (!pd) return FALSE;
  305. pd->fUnicode = IsWindowUnicode(hwnd);
  306. pd->fnOldProc = (WNDPROC)((pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc) :
  307. SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)div_newWndProc));
  308. if (!pd->fnOldProc || !SetPropW(hwnd, PROPW_DIVDATA, pd))
  309. {
  310. free(pd);
  311. return FALSE;
  312. }
  313. pd->fVertical = fVertical;
  314. pd->param = param;
  315. pd->callback = callback;
  316. return TRUE;
  317. }
  318. #define GET_DIVIDER(hwnd) (DIVIDER*)GetPropW(hwnd, PROPW_DIVDATA)
  319. static LRESULT CALLBACK div_newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  320. {
  321. DIVIDER *pd;
  322. pd = GET_DIVIDER(hwnd);
  323. if (!pd) return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
  324. switch (uMsg)
  325. {
  326. case WM_DESTROY:
  327. RemovePropW(hwnd, PROPW_DIVDATA);
  328. (pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
  329. (pd->fUnicode) ? SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc) : SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)pd->fnOldProc);
  330. free(pd);
  331. return 0;
  332. case WM_LBUTTONDOWN:
  333. pd->clickoffs = (pd->fVertical) ? LOWORD(lParam) : HIWORD(lParam);
  334. SetCapture(hwnd);
  335. break;
  336. case WM_LBUTTONUP:
  337. ReleaseCapture();
  338. break;
  339. case WM_SETCURSOR:
  340. SetCursor(LoadCursor(NULL, (pd->fVertical) ? IDC_SIZEWE : IDC_SIZENS));
  341. return TRUE;
  342. case WM_MOUSEMOVE:
  343. {
  344. RECT rw;
  345. GetWindowRect(hwnd, &rw);
  346. GetCursorPos(((LPPOINT)&rw) + 1);
  347. (pd->fVertical) ? rw.right -= pd->clickoffs : rw.bottom -= pd->clickoffs;
  348. if ((pd->fVertical && rw.left != rw.right) || (!pd->fVertical && rw.top != rw.bottom))
  349. {
  350. MapWindowPoints(HWND_DESKTOP, GetParent(hwnd), ((LPPOINT)&rw) + 1, 1);
  351. if (pd->callback) pd->callback(hwnd, (pd->fVertical) ? rw.right : rw.bottom, pd->param);
  352. }
  353. }
  354. break;
  355. }
  356. return (pd->fUnicode) ? CallWindowProcW(pd->fnOldProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(pd->fnOldProc, hwnd, uMsg, wParam, lParam);
  357. }
  358. static int m_nodrawtopborders;
  359. static int adiv1_nodraw, adiv2_nodraw;
  360. #define DIVIDER_FILTER 0x1
  361. #define DIVIDER_FILTER2 0x3
  362. #define DIVIDER_MEDIA 0x2
  363. static int div_filterpos, div_filter2pos, div_mediapos;
  364. static BOOL g_displaysearch = TRUE;
  365. typedef struct _LAYOUT
  366. {
  367. INT id;
  368. HWND hwnd;
  369. INT x;
  370. INT y;
  371. INT cx;
  372. INT cy;
  373. DWORD flags;
  374. HRGN rgn;
  375. BOOL *pHidden;
  376. }LAYOUT, PLAYOUT;
  377. typedef struct _LCTRL
  378. {
  379. INT id;
  380. BOOL hidden;
  381. } LCTRL;
  382. #define SETLAYOUTPOS(_layout, _x, _y, _cx, _cy) { _layout->x=_x; _layout->y=_y;_layout->cx=_cx;_layout->cy=_cy;_layout->rgn=NULL; }
  383. #define SETLAYOUTFLAGS(_layout, _r) \
  384. { \
  385. BOOL fVis; \
  386. fVis = (WS_VISIBLE & (LONG)GetWindowLongPtr(_layout->hwnd, GWL_STYLE)); \
  387. if (_layout->x == _r.left && _layout->y == _r.top) _layout->flags |= SWP_NOMOVE; \
  388. if (_layout->cx == (_r.right - _r.left) && _layout->cy == (_r.bottom - _r.top)) _layout->flags |= SWP_NOSIZE; \
  389. if (fVis && (_layout->cx < 1 || _layout->cy < 1)) { _layout->flags |= SWP_HIDEWINDOW; *_layout->pHidden = TRUE; } \
  390. if (!fVis && *_layout->pHidden && _layout->cx > 0 && _layout->cy > 0) { _layout->flags |= SWP_SHOWWINDOW; *_layout->pHidden = FALSE; } \
  391. if ((SWP_HIDEWINDOW & _layout->flags) && !fVis) _layout->flags &= ~SWP_HIDEWINDOW; \
  392. if ((SWP_SHOWWINDOW & _layout->flags) && fVis) _layout->flags &= ~SWP_SHOWWINDOW; \
  393. }
  394. #define LAYOUTNEEEDUPDATE(_layout) ((SWP_NOMOVE | SWP_NOSIZE) != ((SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_SHOWWINDOW) & _layout->flags))
  395. #define GROUP_MIN 0x1
  396. #define GROUP_MAX 0x3
  397. #define GROUP_SEARCH 0x1
  398. #define GROUP_FILTER 0x2
  399. #define GROUP_MEDIA 0x3
  400. static void LayoutWindows(HWND hwnd, BOOL fRedraw)
  401. {
  402. static LCTRL controls[] =
  403. {
  404. {GROUP_SEARCH, FALSE}, {IDC_BUTTON_ARTMODE, FALSE}, {IDC_BUTTON_VIEWMODE, FALSE}, {IDC_BUTTON_COLUMNS, FALSE}, {IDC_SEARCHCAPTION, FALSE}, {IDC_CLEAR, FALSE}, {IDC_QUICKSEARCH, FALSE},
  405. {GROUP_MEDIA, FALSE}, {IDC_HDELIM, FALSE}, {IDD_VIEW_MEDIA, FALSE},
  406. {GROUP_FILTER, FALSE}, {IDC_LIST1, FALSE}, {IDC_DIV1, FALSE}, {IDC_LIST2, FALSE}, {IDC_DIV2, FALSE}, {IDC_LIST3, FALSE}
  407. };
  408. INT index, divY, divX, divX2;
  409. RECT rc, rg, ri;
  410. LAYOUT layout[sizeof(controls)/sizeof(controls[0])], *pl;
  411. BOOL skipgroup;
  412. HRGN rgn = NULL;
  413. GetClientRect(hwnd, &rc);
  414. if (rc.bottom == rc.top || rc.right == rc.left) return;
  415. SetRect(&rg, rc.left, rc.top, rc.right, rc.top);
  416. pl = layout;
  417. skipgroup = FALSE;
  418. divY = (div_mediapos * (rc.bottom- rc.top)) / 100000;
  419. divX = numFilters==1? rc.right : (div_filterpos * (rc.right- rc.left)) / 100000;
  420. divX2 = numFilters==3? (div_filter2pos * (rc.right- rc.left)) / 100000 : rc.right;
  421. if (divX > divX2 && numFilters==3)
  422. {
  423. div_filterpos=33333;
  424. div_filter2pos=66667;
  425. divX = (div_filterpos * (rc.right- rc.left)) / 100000;
  426. divX2 = (div_filter2pos * (rc.right- rc.left)) / 100000;
  427. }
  428. InvalidateRect(hwnd, NULL, TRUE);
  429. for (index = 0; index < sizeof(controls) / sizeof(LCTRL); index++)
  430. {
  431. if (controls[index].id >= GROUP_MIN && controls[index].id <= GROUP_MAX) // group id
  432. {
  433. skipgroup = FALSE;
  434. switch (controls[index].id)
  435. {
  436. case GROUP_SEARCH:
  437. if (g_displaysearch)
  438. {
  439. wchar_t buffer[128] = {0};
  440. HWND ctrl = GetDlgItem(hwnd, IDC_CLEAR);
  441. GetWindowTextW(ctrl, buffer, ARRAYSIZE(buffer));
  442. LRESULT idealSize = MLSkinnedButton_GetIdealSize(ctrl, buffer);
  443. SetRect(&rg, rc.left + WASABI_API_APP->getScaleX(1),
  444. rc.top + WASABI_API_APP->getScaleY(2),
  445. rc.right - WASABI_API_APP->getScaleX(2),
  446. rc.top + WASABI_API_APP->getScaleY(HIWORD(idealSize)+1));
  447. rc.top = rg.bottom + WASABI_API_APP->getScaleY(3);
  448. }
  449. skipgroup = !g_displaysearch;
  450. break;
  451. case GROUP_MEDIA:
  452. m_nodrawtopborders = 0;
  453. if (divY > (rc.bottom - WASABI_API_APP->getScaleY(85)))
  454. {
  455. RECT rw;
  456. GetWindowRect(GetDlgItem(hwnd, IDC_HDELIM), &rw);
  457. divY = rc.bottom - (rw.bottom - rw.top);
  458. }
  459. else if (divY < (rc.top + WASABI_API_APP->getScaleY(24)))
  460. {
  461. divY = rc.top; m_nodrawtopborders = 1;
  462. }
  463. SetRect(&rg, rc.left, divY, rc.right, rc.bottom);
  464. rc.bottom = rg.top;
  465. break;
  466. case GROUP_FILTER:
  467. if (divX < (rc.left + WASABI_API_APP->getScaleX(15)))
  468. {
  469. divX = rc.left;
  470. adiv1_nodraw = 1;
  471. }
  472. // fixes moving the dividers over to the far right so that the
  473. // 'docking' is consistant in both the two and three pain view
  474. else if (divX > (rc.right - (WASABI_API_APP->getScaleX(17)*(numFilters-1)+(numFilters==2?WASABI_API_APP->getScaleX(10):0))))
  475. {
  476. RECT rw;
  477. GetWindowRect(GetDlgItem(hwnd, IDC_DIV1), &rw);
  478. divX = rc.right - (rw.right - rw.left)*(numFilters-1);
  479. adiv1_nodraw = 2;
  480. }
  481. else adiv1_nodraw = 0;
  482. if (divX2 < (rc.left + WASABI_API_APP->getScaleX(15)*(numFilters-2)))
  483. {
  484. divX2 = rc.left;
  485. adiv2_nodraw = 1;
  486. }
  487. else if (divX2 > (rc.right - WASABI_API_APP->getScaleX(18*2)))
  488. {
  489. RECT rw;
  490. GetWindowRect(GetDlgItem(hwnd, IDC_DIV2), &rw);
  491. divX2 = rc.right - (rw.right - rw.left);
  492. adiv2_nodraw = 2;
  493. }
  494. else adiv2_nodraw = 0;
  495. SetRect(&rg, rc.left, rc.top, rc.right, rc.bottom);
  496. break;
  497. }
  498. continue;
  499. }
  500. if (skipgroup) continue;
  501. pl->id = controls[index].id;
  502. pl->hwnd = GetDlgItem(hwnd, pl->id);
  503. pl->pHidden = &controls[index].hidden;
  504. if (!pl->hwnd) continue;
  505. GetWindowRect(pl->hwnd, &ri);
  506. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 2);
  507. pl->flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS;
  508. switch (pl->id)
  509. {
  510. case IDC_BUTTON_ARTMODE:
  511. if(numFilters == 1)
  512. {
  513. SETLAYOUTPOS(pl, 0, 0, 0, 0);
  514. break;
  515. }
  516. case IDC_BUTTON_VIEWMODE:
  517. case IDC_BUTTON_COLUMNS:
  518. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  519. SETLAYOUTPOS(pl, rg.left, rg.top, (ri.right - ri.left), (rg.bottom - rg.top));
  520. if (SWP_SHOWWINDOW & pl->flags) rg.left += (pl->cx + WASABI_API_APP->getScaleX(1));
  521. break;
  522. case IDC_SEARCHCAPTION:
  523. {
  524. wchar_t buffer[128] = {0};
  525. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  526. LRESULT idealSize = MLSkinnedStatic_GetIdealSize(pl->hwnd, buffer);
  527. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(6),
  528. rg.top + WASABI_API_APP->getScaleY(1),
  529. WASABI_API_APP->getScaleX(LOWORD(idealSize)),
  530. (rg.bottom - rg.top));
  531. rg.left += (pl->cx + WASABI_API_APP->getScaleX(8));
  532. break;
  533. }
  534. case IDC_CLEAR:
  535. {
  536. wchar_t buffer[128] = {0};
  537. GetWindowTextW(pl->hwnd, buffer, ARRAYSIZE(buffer));
  538. LRESULT idealSize = MLSkinnedButton_GetIdealSize(pl->hwnd, buffer);
  539. LONG width = LOWORD(idealSize) + WASABI_API_APP->getScaleX(6);
  540. pl->flags |= (((rg.right - rg.left) - width) > WASABI_API_APP->getScaleX(40)) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  541. SETLAYOUTPOS(pl, rg.right - width, rg.top, width, (rg.bottom - rg.top));
  542. if (SWP_SHOWWINDOW & pl->flags) rg.right -= (pl->cx + WASABI_API_APP->getScaleX(4));
  543. break;
  544. }
  545. case IDC_QUICKSEARCH:
  546. pl->flags |= (rg.right > rg.left) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  547. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(1),
  548. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  549. break;
  550. case IDC_LIST1:
  551. SETLAYOUTPOS(pl, rg.left + WASABI_API_APP->getScaleX(1),
  552. rg.top + WASABI_API_APP->getScaleY(1),
  553. (numFilters == 1 ? rg.right - rg.left - WASABI_API_APP->getScaleX(3) : divX),
  554. (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  555. rg.left += pl->cx;
  556. break;
  557. case IDC_DIV1:
  558. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), ri.right - ri.left, (rg.bottom - rg.top));
  559. rg.left += pl->cx;
  560. break;
  561. case IDC_LIST2:
  562. if (numFilters == 3)
  563. {
  564. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), divX2 - rg.left, (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  565. }
  566. else
  567. {
  568. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) - WASABI_API_APP->getScaleX(3), (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  569. }
  570. rg.left += pl->cx;
  571. break;
  572. case IDC_DIV2:
  573. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), ri.right - ri.left, (rg.bottom - rg.top));
  574. rg.left += pl->cx;
  575. break;
  576. case IDC_LIST3:
  577. SETLAYOUTPOS(pl, rg.left, rg.top + WASABI_API_APP->getScaleY(1), (rg.right - rg.left) - WASABI_API_APP->getScaleX(3), (rg.bottom - rg.top) - WASABI_API_APP->getScaleY(1));
  578. break;
  579. case IDC_HDELIM:
  580. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left - WASABI_API_APP->getScaleX(2), (ri.bottom - ri.top));
  581. rg.top += pl->cy;
  582. break;
  583. case IDD_VIEW_MEDIA:
  584. pl->flags |= (rg.top < rg.bottom) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  585. if ((SWP_HIDEWINDOW & pl->flags) && !IsWindowVisible(pl->hwnd)) continue;
  586. SETLAYOUTPOS(pl, rg.left, rg.top, rg.right - rg.left, (rg.bottom - rg.top));
  587. break;
  588. }
  589. SETLAYOUTFLAGS(pl, ri);
  590. if (LAYOUTNEEEDUPDATE(pl))
  591. {
  592. if (SWP_NOSIZE == ((SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_NOSIZE) & pl->flags) &&
  593. ri.left == (pl->x + offsetX) && ri.top == (pl->y + offsetY) && IsWindowVisible(pl->hwnd))
  594. {
  595. SetRect(&ri, pl->x, pl->y, pl->cx + pl->x, pl->y + pl->cy);
  596. ValidateRect(hwnd, &ri);
  597. }
  598. pl++;
  599. }
  600. else if ((fRedraw || (!offsetX && !offsetY)) && IsWindowVisible(pl->hwnd))
  601. {
  602. ValidateRect(hwnd, &ri);
  603. if (GetUpdateRect(pl->hwnd, NULL, FALSE))
  604. {
  605. if (!rgn) rgn = CreateRectRgn(0,0,0,0);
  606. GetUpdateRgn(pl->hwnd, rgn, FALSE);
  607. OffsetRgn(rgn, pl->x, pl->y);
  608. InvalidateRgn(hwnd, rgn, FALSE);
  609. }
  610. }
  611. }
  612. if (pl != layout)
  613. {
  614. LAYOUT *pc;
  615. HDWP hdwp = BeginDeferWindowPos((INT)(pl - layout));
  616. for (pc = layout; pc < pl && hdwp; pc++)
  617. {
  618. if (IDD_VIEW_MEDIA == pc->id)
  619. {
  620. SetRect(&ri, pc->x, pc->y, pc->x + pc->cx, pc->y + pc->cy);
  621. ValidateRect(hwnd, &ri);
  622. pc->rgn = CreateRectRgn(0, 0, pc->cx, pc->cy);
  623. GetWindowRect(pc->hwnd, &ri);
  624. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&ri, 1);
  625. SendMessage(pc->hwnd, WM_USER + 0x201, MAKEWPARAM(offsetX + (pc->x - ri.left), offsetY + (pc->y - ri.top)), (LPARAM)pc->rgn);
  626. }
  627. hdwp = DeferWindowPos(hdwp, pc->hwnd, NULL, pc->x, pc->y, pc->cx, pc->cy, pc->flags);
  628. }
  629. if (hdwp) EndDeferWindowPos(hdwp);
  630. if (!rgn) rgn = CreateRectRgn(0,0,0,0);
  631. for (pc = layout; pc < pl && hdwp; pc++)
  632. {
  633. switch (pc->id)
  634. {
  635. case IDD_VIEW_MEDIA:
  636. SendMessage(pc->hwnd, WM_USER + 0x201, 0, 0L);
  637. break;
  638. }
  639. }
  640. if (fRedraw)
  641. {
  642. GetUpdateRgn(hwnd, rgn, FALSE);
  643. for (pc = layout; pc < pl && hdwp; pc++)
  644. {
  645. if (pc->rgn)
  646. {
  647. OffsetRgn(pc->rgn, pc->x, pc->y);
  648. CombineRgn(rgn, rgn, pc->rgn, RGN_OR);
  649. }
  650. }
  651. RedrawWindow(hwnd, NULL, rgn, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
  652. }
  653. if (g_rgnUpdate)
  654. {
  655. GetUpdateRgn(hwnd, g_rgnUpdate, FALSE);
  656. for (pc = layout; pc < pl && hdwp; pc++)
  657. {
  658. if (pc->rgn)
  659. {
  660. OffsetRgn(pc->rgn, pc->x, pc->y);
  661. CombineRgn(g_rgnUpdate, g_rgnUpdate, pc->rgn, RGN_OR);
  662. }
  663. }
  664. }
  665. for (pc = layout; pc < pl && hdwp; pc++)
  666. if (pc->rgn) DeleteObject(pc->rgn);
  667. }
  668. if (rgn) DeleteObject(rgn);
  669. ValidateRgn(hwnd, NULL);
  670. }
  671. static void WINAPI OnDividerMoved(HWND hwnd, INT nPos, LPARAM param)
  672. {
  673. RECT rc;
  674. HWND hwndParent;
  675. hwndParent = GetParent(hwnd);
  676. if (hwndParent)
  677. {
  678. GetClientRect(hwndParent, &rc);
  679. switch ((INT)param)
  680. {
  681. case DIVIDER_FILTER:
  682. div_filterpos = (nPos * 100000) / (rc.right - rc.left);
  683. if (div_filterpos + 500 > div_filter2pos) div_filter2pos = div_filterpos+500;
  684. break;
  685. case DIVIDER_FILTER2:
  686. div_filter2pos = (nPos * 100000) / (rc.right - rc.left);
  687. if (div_filter2pos - 500 < div_filterpos) div_filterpos = div_filter2pos-500;
  688. break;
  689. case DIVIDER_MEDIA:
  690. div_mediapos = (nPos * 100000) / (rc.bottom - rc.top);
  691. break;
  692. }
  693. LayoutWindows(hwndParent, TRUE);
  694. }
  695. }
  696. static int ignore_selections;
  697. //returns true if a selection has been set which needs to be propagated to the next pane
  698. static bool UpdateFilterPane(int pane, char* selconfigname)
  699. {
  700. filter[pane]->SortResults(g_view_metaconf, pane, 0);
  701. ListView_SetItemCount(filter[pane]->list->getwnd(), filter[pane]->Size());
  702. InvalidateRect(filter[pane]->list->getwnd(), NULL, TRUE);
  703. ignore_selections = 1;
  704. char *_selstr = g_config->ReadInt(L"remembersearch", 0) ? g_view_metaconf->ReadString(selconfigname, "") : NULL;
  705. wchar_t * selstr = AutoWide(_selstr, CP_UTF8);
  706. int a = 0;
  707. if (selstr && *selstr)
  708. {
  709. int len = (wcslen(selstr) + 2);
  710. wchar_t *t = (wchar_t*)calloc(len, sizeof(wchar_t));
  711. wcsncpy(t, selstr, len);
  712. g_view_metaconf->WriteString(selconfigname, "");
  713. t[wcslen(t)+1] = 0;
  714. wchar_t *outp = t;
  715. wchar_t *inp = t;
  716. while (inp && *inp)
  717. {
  718. if (*inp == *LDELIMSTR)
  719. {
  720. if (inp[1] == *LDELIMSTR)
  721. {
  722. *outp++ = *LDELIMSTR; // unescape the output
  723. inp += 2;
  724. }
  725. else
  726. {
  727. *outp++ = 0; inp++;
  728. }
  729. }
  730. else *outp++ = *inp++;
  731. }
  732. *outp = 0;
  733. int x;
  734. for (x = 1; x < filter[pane]->Size(); x ++)
  735. {
  736. wchar_t *p = t;
  737. while (p && *p)
  738. {
  739. if (!lstrcmpiW(filter[pane]->GetText(x), p)) break;
  740. p += wcslen(p) + 1;
  741. }
  742. if (p && *p)
  743. {
  744. if (!a)
  745. {
  746. ListView_SetSelectionMark(filter[pane]->list->getwnd(), x);
  747. ListView_SetItemState(filter[pane]->list->getwnd(), x, LVIS_FOCUSED, LVIS_FOCUSED);
  748. ListView_EnsureVisible(filter[pane]->list->getwnd(), x, NULL);
  749. }
  750. a++;
  751. filter[pane]->list->SetSelected(x);
  752. }
  753. }
  754. free(t);
  755. }
  756. if (a)
  757. {
  758. ignore_selections = 0;
  759. return true;
  760. }
  761. else
  762. {
  763. wchar_t buf[1024] = {0};
  764. GetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, buf, sizeof(buf));
  765. if (buf[0])
  766. {
  767. ignore_selections = 0;
  768. l_query.Set(L""); // force refresh
  769. }
  770. if(filter[pane]->HasTopItem())
  771. filter[pane]->list->SetSelected(0);
  772. ignore_selections = 0;
  773. return false;
  774. }
  775. }
  776. HBITMAP ConvertTo24bpp(HBITMAP bmp, int bpp)
  777. {
  778. HDC hdcMem, hdcMem2;
  779. HBITMAP hbm24;
  780. BITMAP bm;
  781. GetObjectW(bmp, sizeof(BITMAP), &bm);
  782. hdcMem = CreateCompatibleDC(0);
  783. hdcMem2 = CreateCompatibleDC(0);
  784. void *bits;
  785. BITMAPINFOHEADER bi;
  786. ZeroMemory(&bi, sizeof(bi));
  787. bi.biSize = sizeof(bi);
  788. bi.biWidth= bm.bmWidth;
  789. bi.biHeight = -bm.bmHeight;
  790. bi.biPlanes = 1;
  791. bi.biBitCount= (WORD)bpp;
  792. hbm24 = CreateDIBSection(hdcMem2, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &bits, NULL, NULL);
  793. HBITMAP oBmp = (HBITMAP)SelectObject(hdcMem, bmp);
  794. HBITMAP oBmp24 = (HBITMAP)SelectObject(hdcMem2, hbm24);
  795. BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
  796. SelectObject(hdcMem, oBmp);
  797. SelectObject(hdcMem2, oBmp24);
  798. DeleteDC(hdcMem);
  799. DeleteDC(hdcMem2);
  800. return hbm24;
  801. }
  802. static __forceinline BYTE pm(int a, int b)
  803. {
  804. return (BYTE)((a * b) / 0xff);
  805. }
  806. void SetToolbarButtonBitmap(HWND hwndDlg, int buttonrc, int bitmaprc, ARGB32 fc)
  807. {
  808. // benski> we could use this if it wasn't for the lack of WASABI_API_IMGLDR on classic skin
  809. // even though we have the resource loader ...
  810. // SkinBitmap *sbm = new SkinBitmap( bitmaprc);
  811. HBITMAP hbm1 = (HBITMAP)LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(bitmaprc),IMAGE_BITMAP,0,0,LR_VGACOLOR);
  812. HBITMAP hbm = ConvertTo24bpp(hbm1,32);
  813. DeleteObject(hbm1);
  814. BITMAP bm;
  815. GetObjectW(hbm, sizeof(BITMAP), &bm);
  816. int l = bm.bmWidth * bm.bmHeight;
  817. ARGB32 *x = (ARGB32*)bm.bmBits;
  818. ARGB32 *end = x+l;
  819. BYTE r = (BYTE)(fc & 0x00ff0000 >> 16);
  820. BYTE g = (BYTE)(fc & 0x0000ff00 >> 8);
  821. BYTE b = (BYTE)(fc & 0x000000ff);
  822. while (x < end)
  823. {
  824. BYTE a = (BYTE)((~(*x))&0xff);
  825. *(x++) = (a<<24) | (pm(r,a)<<16) | (pm(g,a)<<8) | pm(b,a);
  826. }
  827. void * mem = malloc(bm.bmWidth*bm.bmHeight*sizeof(ARGB32));
  828. memcpy(mem,bm.bmBits,bm.bmWidth*bm.bmHeight*sizeof(ARGB32));
  829. SkinBitmap *sbm = new SkinBitmap((ARGB32*)mem,bm.bmWidth,bm.bmHeight);
  830. DeleteObject(hbm);
  831. HWND btn = GetDlgItem(hwndDlg,buttonrc);
  832. if (IsWindow(btn))
  833. {
  834. SkinBitmap* old = (SkinBitmap*)SetWindowLongPtr(btn,GWLP_USERDATA,(LONG_PTR)sbm);
  835. if (old)
  836. {
  837. if (old->getBits()) free(old->getBits()); delete old;
  838. }
  839. InvalidateRect(btn, NULL, TRUE);
  840. }
  841. }
  842. int GetFilter(int mode, int n)
  843. {
  844. if (n==0) return ((mode & 0x0000ff));
  845. if (n==1)
  846. {
  847. int f=((mode & 0x00ff00) >> 8); if (f) return f; return 6;
  848. } // album
  849. if (n==2) return ((mode & 0xff0000) >> 16);
  850. return 0;
  851. }
  852. int GetNumFilters(int mode)
  853. {
  854. if (mode == 0) return 0;
  855. if (mode > 0xffffff) return 1;
  856. if (GetFilter(mode,2) == 0) return 2;
  857. return 3;
  858. }
  859. typedef struct { int id, id2; } hi;
  860. //extern "C"
  861. //{
  862. //void __cdecl do_help(HWND hwnd, UINT id, HWND hTooltipWnd);
  863. void do_help(HWND hwnd, UINT id, HWND hTooltipWnd)
  864. {
  865. RECT r;
  866. POINT p;
  867. GetWindowRect(GetDlgItem(hwnd, id), &r);
  868. GetCursorPos(&p);
  869. if (p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom)
  870. {}
  871. else
  872. {
  873. r.left += r.right;
  874. r.left /= 2;
  875. r.top += r.bottom;
  876. r.top /= 2;
  877. SetCursorPos(r.left, r.top);
  878. }
  879. SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_INITIAL, 0);
  880. SendMessage(hTooltipWnd, TTM_SETDELAYTIME, TTDT_RESHOW, 0);
  881. }
  882. #define C_BLAH
  883. #define DO_HELP() \
  884. static HWND hTooltipWnd; \
  885. C_BLAH \
  886. if (uMsg == WM_HELP) { \
  887. HELPINFO *hi=(HELPINFO *)(lParam); \
  888. if (hi->iContextType == HELPINFO_WINDOW) { do_help(hwndDlg,hi->iCtrlId,hTooltipWnd);} \
  889. return TRUE; \
  890. } \
  891. 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); } } \
  892. if (uMsg == WM_DESTROY && IsWindow(hTooltipWnd)) { DestroyWindow(hTooltipWnd); hTooltipWnd=NULL; } \
  893. if (uMsg == WM_INITDIALOG) { \
  894. int x; \
  895. hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,(LPCWSTR)NULL,TTS_ALWAYSTIP|TTS_NOPREFIX, \
  896. CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, hwndDlg,NULL,GetModuleHandle(NULL),NULL); \
  897. SendMessage(hTooltipWnd,TTM_SETMAXTIPWIDTH,0,587); \
  898. SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_INITIAL,250); \
  899. SendMessage(hTooltipWnd,TTM_SETDELAYTIME,TTDT_RESHOW,500); \
  900. for (x = 0; x < sizeof(helpinfo)/sizeof(helpinfo[0]); x ++) { \
  901. TOOLINFO ti; ti.cbSize = sizeof(ti); ti.uFlags = TTF_SUBCLASS|TTF_IDISHWND; \
  902. ti.uId=(UINT_PTR)GetDlgItem(hwndDlg,helpinfo[x].id); ti.hwnd=hwndDlg; ti.lpszText=WASABI_API_LNGSTRINGW(helpinfo[x].id2); \
  903. SendMessage(hTooltipWnd,TTM_ADDTOOL,0,(LPARAM) &ti); \
  904. } \
  905. }
  906. //}
  907. static int refresh;
  908. INT_PTR CALLBACK view_audioDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  909. {
  910. static int we_are_drag_and_dropping;
  911. static HMENU sendto_hmenu;
  912. static librarySendToMenuStruct s;
  913. hi helpinfo[]={
  914. {IDC_BUTTON_ARTMODE,IDS_AUDIO_BUTTON_TT1},
  915. {IDC_BUTTON_VIEWMODE,IDS_AUDIO_BUTTON_TT2},
  916. {IDC_BUTTON_COLUMNS,IDS_AUDIO_BUTTON_TT3},
  917. };
  918. DO_HELP();
  919. BOOL a = dialogSkinner.Handle(hwndDlg, uMsg, wParam, lParam); if (a) return a;
  920. if (numFilters>=1)
  921. {
  922. a = filter[0]->DialogProc(hwndDlg,uMsg,wParam,lParam); if (a) return a;
  923. }
  924. if (numFilters>=2)
  925. {
  926. a = filter[1]->DialogProc(hwndDlg,uMsg,wParam,lParam); if (a) return a;
  927. }
  928. if (numFilters>=3)
  929. {
  930. a = filter[2]->DialogProc(hwndDlg,uMsg,wParam,lParam); if (a) return a;
  931. }
  932. switch (uMsg)
  933. {
  934. case WM_INITMENUPOPUP:
  935. if (wParam)
  936. {
  937. if((HMENU)wParam == s.build_hMenu && s.mode == 1)
  938. {
  939. myMenu = TRUE;
  940. if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
  941. s.mode = 2;
  942. myMenu = FALSE;
  943. }
  944. // only populate the average rating when needed otherwise it makes all of the menu slow
  945. else if((HMENU)wParam == GetSubMenu(GetSubMenu(g_context_menus, 1),4))
  946. {
  947. int ave_rating = 0, valid = 0;
  948. GayStringW query;
  949. getParentPlusSearchQuery(&query);
  950. for (int i=0; i<numFilters; i++)
  951. {
  952. valid += makeFilterQuery(&query,filter[i]);
  953. }
  954. EnterCriticalSection(&g_db_cs);
  955. nde_scanner_t q = NDE_Table_CreateScanner(g_table);
  956. NDE_Scanner_Query(q, query.Get());
  957. NDE_Scanner_First(q);
  958. int count = 0;
  959. do
  960. {
  961. nde_field_t f = NDE_Scanner_GetFieldByID(q, MAINTABLE_ID_FILENAME);
  962. if (!f) break;
  963. nde_field_t g = NDE_Scanner_GetFieldByID(q, MAINTABLE_ID_RATING);
  964. int nde_rating = NDE_IntegerField_GetValue(g);
  965. if(nde_rating > 0) ave_rating += nde_rating;
  966. count++;
  967. }
  968. while (NDE_Scanner_Next(q));
  969. NDE_Table_DestroyScanner(g_table, q);
  970. LeaveCriticalSection(&g_db_cs);
  971. if(ave_rating > 0)
  972. {
  973. float ave = ave_rating/(count*1.0f);
  974. int diff = ave_rating/count;
  975. int adjust = (ave-diff)>=0.5f;
  976. ave_rating = (int)(ave+adjust);
  977. }
  978. Menu_SetRatingValue((HMENU)wParam, (valid?ave_rating:-1));
  979. }
  980. }
  981. return 0;
  982. case WM_DISPLAYCHANGE:
  983. {
  984. ARGB32 fc = dialogSkinner.Color(WADLG_BUTTONFG) & 0x00FFFFFF;
  985. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_ARTMODE,IDB_TOOL_ART,fc);
  986. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_VIEWMODE,IDB_TOOL_MODE,fc);
  987. SetToolbarButtonBitmap(hwndDlg,IDC_BUTTON_COLUMNS,IDB_TOOL_COLS,fc);
  988. if (IsWindow(m_media_hwnd)) SendNotifyMessageW(m_media_hwnd, WM_DISPLAYCHANGE, wParam, lParam);
  989. UpdateWindow(hwndDlg);
  990. LayoutWindows(hwndDlg, TRUE);
  991. }
  992. return 0;
  993. case WM_INITDIALOG:
  994. {
  995. hwndSearchGlobal = GetDlgItem(hwndDlg, IDC_QUICKSEARCH); // Set the hwnd for the search to a global so we can access it from the media view dialog
  996. ResumeCache();
  997. int numFilters0=GetNumFilters(m_query_mode);
  998. int f1 = GetFilter(m_query_mode,0);
  999. int f2 = GetFilter(m_query_mode,1);
  1000. int f3 = GetFilter(m_query_mode,2);
  1001. filter[0] = getFilter(f1-1,hwndDlg,IDC_LIST1,g_view_metaconf);
  1002. filter[0]->list = &m_list1;
  1003. filter[0]->nextFilter = NULL;
  1004. filter[0]->list->setwnd(GetDlgItem(hwndDlg, IDC_LIST1));
  1005. if (numFilters0>=2)
  1006. {
  1007. filter[1] = getFilter(f2-1,hwndDlg,IDC_LIST2,g_view_metaconf);
  1008. filter[1]->list = &m_list2;
  1009. filter[1]->list->setwnd(GetDlgItem(hwndDlg, IDC_LIST2));
  1010. filter[1]->nextFilter = NULL;
  1011. filter[0]->nextFilter = filter[1];
  1012. }
  1013. if (numFilters0>=3)
  1014. {
  1015. filter[2] = getFilter(f3-1,hwndDlg,IDC_LIST3,g_view_metaconf);
  1016. filter[2]->list = &m_list3;
  1017. filter[2]->list->setwnd(GetDlgItem(hwndDlg, IDC_LIST3));
  1018. filter[2]->nextFilter = NULL;
  1019. filter[1]->nextFilter = filter[2];
  1020. }
  1021. numFilters=numFilters0;
  1022. m_hwnd = hwndDlg;
  1023. getParentPlusSearchQuery(&l_query);
  1024. for (int j=0; j<numFilters0; j++)
  1025. {
  1026. filter[j]->list->ForceUnicode();
  1027. filter[j]->AddColumns();
  1028. }
  1029. div_mediapos = g_view_metaconf->ReadInt(L"adiv2pos", 50000);
  1030. if (numFilters == 1)
  1031. {
  1032. div_filterpos = g_view_metaconf->ReadInt(L"adiv1pos", 100000);
  1033. div_filter2pos = -1;
  1034. }
  1035. else if (numFilters == 2)
  1036. {
  1037. div_filterpos = g_view_metaconf->ReadInt(L"adiv1pos", 50000);
  1038. div_filter2pos = -1;
  1039. }
  1040. else if (numFilters == 3)
  1041. {
  1042. div_filterpos = g_view_metaconf->ReadInt(L"adiv1pos", 33333);
  1043. div_filter2pos = g_view_metaconf->ReadInt(L"adiv3pos", 66667);
  1044. if (div_filterpos + div_filter2pos > 200000) // sanity check?
  1045. {
  1046. div_filterpos = 33333;
  1047. div_filter2pos = 66667;
  1048. }
  1049. }
  1050. if (numFilters >= 2) AttachDivider(GetDlgItem(hwndDlg, IDC_DIV1), TRUE, OnDividerMoved, DIVIDER_FILTER);
  1051. if (numFilters >= 3) AttachDivider(GetDlgItem(hwndDlg, IDC_DIV2), TRUE, OnDividerMoved, DIVIDER_FILTER2);
  1052. AttachDivider(GetDlgItem(hwndDlg, IDC_HDELIM), FALSE, OnDividerMoved, DIVIDER_MEDIA);
  1053. m_media_hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_MEDIA, hwndDlg, view_mediaDialogProc, (LPARAM)!g_config->ReadInt(L"audiorefine", 0));
  1054. SetWindowLongPtr(m_media_hwnd, GWLP_ID, IDD_VIEW_MEDIA);
  1055. MLSKINWINDOW m = {0};
  1056. m.skinType = SKINNEDWND_TYPE_LISTVIEW;
  1057. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  1058. m.hwndToSkin = m_list1.getwnd();
  1059. MLSkinWindow(plugin.hwndLibraryParent, &m);
  1060. m.hwndToSkin = m_list2.getwnd();
  1061. MLSkinWindow(plugin.hwndLibraryParent, &m);
  1062. if (numFilters == 3)
  1063. {
  1064. m.hwndToSkin = m_list3.getwnd();
  1065. MLSkinWindow(plugin.hwndLibraryParent, &m);
  1066. }
  1067. if (!g_view_metaconf->ReadInt(L"av0_hscroll",0)) MLSkinnedScrollWnd_ShowHorzBar(m_list1.getwnd(), FALSE);
  1068. if (!g_view_metaconf->ReadInt(L"av1_hscroll",0)) MLSkinnedScrollWnd_ShowHorzBar(m_list2.getwnd(), FALSE);
  1069. if (!g_view_metaconf->ReadInt(L"av2_hscroll",0) && numFilters == 3) MLSkinnedScrollWnd_ShowHorzBar(m_list3.getwnd(), FALSE);
  1070. FLICKERFIX ff;
  1071. ff.mode = FFM_ERASEINPAINT;
  1072. m.skinType = SKINNEDWND_TYPE_AUTO;
  1073. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  1074. INT ffcl[] = { IDC_QUICKSEARCH, IDC_SEARCHCAPTION, IDC_CLEAR, IDC_BUTTON_ARTMODE, IDC_BUTTON_VIEWMODE, IDC_BUTTON_COLUMNS};
  1075. for (int i = 0; i < sizeof(ffcl) / sizeof(INT); i++)
  1076. {
  1077. ff.hwnd = GetDlgItem(hwndDlg, ffcl[i]);
  1078. if (IsWindow(ff.hwnd))
  1079. {
  1080. SendMessage(mediaLibrary.library, WM_ML_IPC, (WPARAM)&ff, ML_IPC_FLICKERFIX);
  1081. if (i < 3)
  1082. {
  1083. m.hwndToSkin = ff.hwnd;
  1084. MLSkinWindow(plugin.hwndLibraryParent, &m);
  1085. }
  1086. }
  1087. }
  1088. SendMessageW(hwndDlg, WM_DISPLAYCHANGE, 0, 0L);
  1089. // clear the media windows refine shit
  1090. SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1091. SetDlgItemText(m_media_hwnd, IDC_SEARCHCAPTION, WASABI_API_LNGSTRINGW(IDS_REFINE));
  1092. SetDlgItemText(m_media_hwnd, IDC_CLEAR, WASABI_API_LNGSTRINGW(IDS_CLEAR_REFINE));
  1093. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1094. if (g_config->ReadInt(L"remembersearch", 0))
  1095. {
  1096. char *query = g_view_metaconf->ReadString("lastquery_a_utf8", "");
  1097. SetDlgItemText(hwndDlg, IDC_QUICKSEARCH, AutoWide(query, CP_UTF8));
  1098. KillTimer(hwndDlg, 205);
  1099. }
  1100. for (int j=0; j<numFilters; j++)
  1101. filter[j]->SortResults(g_view_metaconf, j, 0);
  1102. {
  1103. wchar_t buf[32] = {0};
  1104. for (int i = 0; i < numFilters; i++)
  1105. {
  1106. int dlgitem = (i==0)?IDC_LIST1:((i==1)?IDC_LIST2:IDC_LIST3);
  1107. StringCchPrintfW(buf, ARRAYSIZE(buf), L"%hs_sort_by_%d", filter[i]->GetConfigId(), i);
  1108. int l_sc = g_view_metaconf->ReadInt(buf, 0);
  1109. StringCchPrintfW(buf, ARRAYSIZE(buf), L"%hs_sort_dir_%d", filter[i]->GetConfigId(), i);
  1110. int l_sd = g_view_metaconf->ReadInt(buf, 0);
  1111. SendMessage((HWND)SendMessage(GetDlgItem(hwndDlg,dlgitem), LVM_GETHEADER, 0, 0L),WM_ML_IPC,MAKEWPARAM(l_sc,!l_sd),ML_IPC_SKINNEDHEADER_DISPLAYSORT);
  1112. }
  1113. }
  1114. MLSKINWINDOW skin = {0};
  1115. skin.hwndToSkin = hwndDlg;
  1116. skin.skinType = SKINNEDWND_TYPE_AUTO;
  1117. skin.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWLVS_ALTERNATEITEMS;
  1118. MLSkinWindow(plugin.hwndLibraryParent, &skin);
  1119. return TRUE;
  1120. }
  1121. case WM_DRAWITEM:
  1122. {
  1123. DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT *)lParam;
  1124. if (di->CtlType == ODT_BUTTON)
  1125. {
  1126. if (di->CtlID == IDC_BUTTON_ARTMODE || di->CtlID == IDC_BUTTON_VIEWMODE || di->CtlID == IDC_BUTTON_COLUMNS)
  1127. {
  1128. // draw the toolbar buttons!
  1129. SkinBitmap* hbm = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,di->CtlID),GWLP_USERDATA);
  1130. if (hbm && di->rcItem.left != di->rcItem.right && di->rcItem.top != di->rcItem.bottom)
  1131. {
  1132. DCCanvas dc(di->hDC);
  1133. if (di->itemState & ODS_SELECTED) hbm->blitAlpha(&dc,di->rcItem.left+6,di->rcItem.top+5);
  1134. else hbm->blitAlpha(&dc,di->rcItem.left+4,di->rcItem.top+3);
  1135. }
  1136. return TRUE;
  1137. }
  1138. }
  1139. }
  1140. break;
  1141. case WM_TIMER:
  1142. if (wParam == 165) // list3 sel change
  1143. {
  1144. KillTimer(hwndDlg, 165);
  1145. if (numFilters < 3) break;
  1146. GayStringW query;
  1147. getParentPlusSearchQuery(&query);
  1148. int r = makeFilterQuery(&query,filter[0]);
  1149. r += makeFilterQuery(&query,filter[1]);
  1150. r += makeFilterQuery(&query,filter[2]);
  1151. if (wcscmp(query.Get(), l_query.Get()))
  1152. {
  1153. bgQuery_Stop();
  1154. l_query.Set(query.Get());
  1155. wchar_t buf[2048] = {0};
  1156. GetDlgItemTextW(m_media_hwnd, IDC_QUICKSEARCH, buf, ARRAYSIZE(buf));
  1157. if (buf[0]) makeQueryStringFromText(&query, buf);
  1158. if (!refresh) SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1159. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1160. EnterCriticalSection(&g_db_cs);
  1161. if (m_media_scanner) NDE_Scanner_Query(m_media_scanner, query.Get());
  1162. LeaveCriticalSection(&g_db_cs);
  1163. if (r > 0) SendMessage(m_media_hwnd, WM_APP + 3, 0x666, 0); // notify the child to use the first item as a media lookup
  1164. SendMessage(m_media_hwnd, WM_APP + 1, 0, 0);
  1165. }
  1166. }
  1167. if (wParam == 166) // album sel change
  1168. {
  1169. KillTimer(hwndDlg, 166);
  1170. GayStringW query;
  1171. getParentPlusSearchQuery(&query);
  1172. int r = makeFilterQuery(&query,filter[0]);
  1173. r += makeFilterQuery(&query,filter[1]);
  1174. if (wcscmp(query.Get(), l_query.Get()))
  1175. {
  1176. bgQuery_Stop();
  1177. l_query.Set(query.Get());
  1178. wchar_t buf[2048] = {0};
  1179. GetDlgItemTextW(m_media_hwnd, IDC_QUICKSEARCH, buf, ARRAYSIZE(buf));
  1180. if (buf[0]) makeQueryStringFromText(&query, buf);
  1181. if (!refresh) SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1182. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1183. EnterCriticalSection(&g_db_cs);
  1184. if (m_media_scanner) NDE_Scanner_Query(m_media_scanner, query.Get());
  1185. LeaveCriticalSection(&g_db_cs);
  1186. if (r > 0) SendMessage(m_media_hwnd, WM_APP + 3, 0x666, 0); // notify the child to use the first item as a media lookup
  1187. SendMessage(m_media_hwnd, WM_APP + 1, (WPARAM)mysearchCallbackAlbumUpdate, 2);
  1188. }
  1189. }
  1190. if (wParam == 167) // artist sel change
  1191. {
  1192. KillTimer(hwndDlg, 167);
  1193. GayStringW query;
  1194. getParentPlusSearchQuery(&query);
  1195. int r = makeFilterQuery(&query,filter[0]);
  1196. if (wcscmp(query.Get(), l_query.Get()))
  1197. {
  1198. bgQuery_Stop();
  1199. l_query.Set(query.Get());
  1200. if (!refresh) SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1201. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1202. EnterCriticalSection(&g_db_cs);
  1203. NDE_Scanner_Query(m_media_scanner, query.Get());
  1204. LeaveCriticalSection(&g_db_cs);
  1205. ListView_SetItemCount(m_list2.getwnd(), 0);
  1206. if (r > 0) SendMessage(m_media_hwnd, WM_APP + 3, 0x666, 0); // notify the child to use the first item as a media lookup
  1207. SendMessage(m_media_hwnd, WM_APP + 1, (WPARAM)mysearchCallbackAlbumUpdate, (LPARAM)1); // pass a callback for sort
  1208. }
  1209. }
  1210. if (wParam == 205)
  1211. {
  1212. KillTimer(hwndDlg, 205);
  1213. bgQuery_Stop();
  1214. getParentPlusSearchQuery(&l_query);
  1215. EnterCriticalSection(&g_db_cs);
  1216. NDE_Scanner_Query(m_media_scanner, l_query.Get());
  1217. LeaveCriticalSection(&g_db_cs);
  1218. ignore_selections = 1;
  1219. m_list3.SetSelected(0);
  1220. m_list2.SetSelected(0);
  1221. m_list1.SetSelected(0);
  1222. ListView_SetItemCount(m_list1.getwnd(), 0);
  1223. ListView_SetItemCount(m_list2.getwnd(), 0);
  1224. ListView_SetItemCount(m_list3.getwnd(), 0);
  1225. ignore_selections = 0;
  1226. if (!refresh) SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1227. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1228. SendMessage(m_media_hwnd, WM_APP + 1, (WPARAM)mysearchCallbackAlbumUpdate, (LPARAM)0);
  1229. refresh -= 1;
  1230. }
  1231. break;
  1232. case WM_MOUSEMOVE:
  1233. if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
  1234. {
  1235. POINT p;
  1236. p.x = GET_X_LPARAM(lParam);
  1237. p.y = GET_Y_LPARAM(lParam);
  1238. ClientToScreen(hwndDlg, &p);
  1239. mlDropItemStruct m;
  1240. ZeroMemory(&m, sizeof(mlDropItemStruct));
  1241. m.type = ML_TYPE_ITEMRECORDLIST;
  1242. m.p = p;
  1243. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  1244. if (m.result <= 0)
  1245. {
  1246. ZeroMemory(&m, sizeof(mlDropItemStruct));
  1247. m.type = ML_TYPE_QUERYSTRING;
  1248. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  1249. }
  1250. break;
  1251. }
  1252. break;
  1253. case WM_SETCURSOR:
  1254. case WM_LBUTTONDOWN:
  1255. {
  1256. static INT id[] = { IDC_HDELIM, IDC_DIV1, IDC_DIV2 };
  1257. RECT rw;
  1258. POINT pt;
  1259. INT count;
  1260. count = numFilters;
  1261. if (count > sizeof(id)/sizeof(INT)) count = sizeof(id)/sizeof(INT);
  1262. GetCursorPos(&pt);
  1263. for (INT i = 0; i < count; i++)
  1264. {
  1265. HWND hwndDiv = GetDlgItem(hwndDlg, id[i]);
  1266. if (!hwndDiv) continue;
  1267. GetWindowRect(hwndDiv, &rw);
  1268. if (PtInRect(&rw, pt))
  1269. {
  1270. if (WM_SETCURSOR == uMsg)
  1271. {
  1272. SetCursor(LoadCursor(NULL, (IDC_HDELIM != id[i]) ? IDC_SIZEWE : IDC_SIZENS));
  1273. return TRUE;
  1274. }
  1275. else
  1276. {
  1277. SendMessage(hwndDiv, uMsg, wParam, MAKELPARAM(pt.x - rw.left, pt.y - rw.top));
  1278. return TRUE;
  1279. }
  1280. }
  1281. }
  1282. }
  1283. break;
  1284. case WM_LBUTTONUP:
  1285. if (we_are_drag_and_dropping && GetCapture() == hwndDlg)
  1286. {
  1287. int whichlist = we_are_drag_and_dropping;
  1288. we_are_drag_and_dropping = 0;
  1289. ReleaseCapture();
  1290. POINT p;
  1291. p.x = GET_X_LPARAM(lParam);
  1292. p.y = GET_Y_LPARAM(lParam);
  1293. ClientToScreen(hwndDlg, &p);
  1294. mlDropItemStruct m = {0};
  1295. m.type = ML_TYPE_ITEMRECORDLISTW;
  1296. m.p = p;
  1297. m.flags = ML_HANDLEDRAG_FLAG_NOCURSOR;
  1298. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  1299. itemRecordListW obj = {0, };
  1300. buildRecordListW(&obj, whichlist-1);
  1301. if (m.result > 0)
  1302. {
  1303. /*
  1304. if (whichlist == 1 || m_list2.GetSelectionMark() <= 0)
  1305. buildRecordListW(&obj, 0);
  1306. else if(whichlist == 2 || m_list3.GetSelectionMark() <= 0 || numFilters < 3)
  1307. buildRecordListW(&obj,1);
  1308. else
  1309. buildRecordListW(&obj,2);
  1310. */
  1311. m.flags = 0;
  1312. m.result = 0;
  1313. m.data = (void*) & obj;
  1314. pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
  1315. }
  1316. else
  1317. {
  1318. m.result = 0;
  1319. m.type = ML_TYPE_ITEMRECORDLIST;
  1320. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  1321. if (m.result > 0)
  1322. {
  1323. itemRecordList objA = {0, };
  1324. convertRecordList(&objA, &obj);
  1325. /*
  1326. if (whichlist == 1 || m_list2.GetSelectionMark() <= 0)
  1327. buildRecordList(&obj, 0);
  1328. else if(whichlist == 2 || m_list3.GetSelectionMark() <= 0 || numFilters < 3)
  1329. buildRecordList(&obj, 1);
  1330. else
  1331. buildRecordList(&obj, 2);
  1332. */
  1333. m.flags = 0;
  1334. m.result = 0;
  1335. m.data = (void*) & objA;
  1336. GayString namebuf;
  1337. int wl = whichlist;
  1338. ViewFilter * filter1 = filter[wl-1];
  1339. {
  1340. int a = filter1->list->GetSelectionMark();
  1341. if (a < 0 || (filter1->HasTopItem() && filter1->list->GetSelected(0)))
  1342. {
  1343. filter1 = filter[0]; wl--;
  1344. }
  1345. if (wl > 0)
  1346. {
  1347. int x;
  1348. int cnt = 0;
  1349. for (x = filter1->HasTopItem()?1:0; x < filter1->Size(); x ++)
  1350. {
  1351. if (filter1->list->GetSelected(x))
  1352. {
  1353. if (cnt) namebuf.Append(", ");
  1354. if (cnt++ > 2)
  1355. {
  1356. namebuf.Append("..."); break;
  1357. }
  1358. namebuf.Append(AutoChar(filter1->GetText(x)));
  1359. }
  1360. }
  1361. }
  1362. }
  1363. if (namebuf.Get() && namebuf.Get()[0]) m.name = namebuf.Get();
  1364. if (m.name)
  1365. m.flags |= ML_HANDLEDRAG_FLAG_NAME;
  1366. pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
  1367. freeRecordList(&objA);
  1368. }
  1369. else
  1370. {
  1371. m.result = 0;
  1372. m.type = ML_TYPE_QUERYSTRING;
  1373. pluginHandleIpcMessage(ML_IPC_HANDLEDRAG, (WPARAM)&m);
  1374. if (m.result > 0)
  1375. {
  1376. GayStringW query;
  1377. getParentPlusSearchQuery(&query);
  1378. bool allSelected[3] = {false,false,false};
  1379. for (int k=0; k<numFilters; k++)
  1380. {
  1381. W_ListView &w = k==0?m_list1:(k==1?m_list2:m_list3);
  1382. if (filter[k]->HasTopItem()) allSelected[k] = (w.GetSelectionMark() <= 0);
  1383. else allSelected[k] = (w.GetSelectionMark() < 0);
  1384. }
  1385. if (whichlist == 1 || allSelected[1])
  1386. {
  1387. makeFilterQuery(&query,filter[0]);
  1388. }
  1389. else if (whichlist == 2 || allSelected[2] || numFilters < 3)
  1390. {
  1391. makeFilterQuery(&query,filter[0]);
  1392. makeFilterQuery(&query,filter[1]);
  1393. }
  1394. else
  1395. {
  1396. makeFilterQuery(&query,filter[0]);
  1397. makeFilterQuery(&query,filter[1]);
  1398. makeFilterQuery(&query,filter[2]);
  1399. }
  1400. m.data = (void*)query.Get();
  1401. m.result = 0;
  1402. GayString namebuf;
  1403. int wl = whichlist;
  1404. ViewFilter * filter1 = wl==2?filter[1]:filter[0];
  1405. {
  1406. int a = filter1->list->GetSelectionMark();
  1407. if (a < 0 || (filter1->HasTopItem() && filter1->list->GetSelected(0)))
  1408. {
  1409. if (wl==2)
  1410. {
  1411. filter1 = filter[0];
  1412. }
  1413. else m.name = WASABI_API_LNGSTRING(IDS_ALL_ARTISTS);
  1414. wl--;
  1415. }
  1416. if (wl > 0)
  1417. {
  1418. int x;
  1419. int cnt = 0;
  1420. for (x = filter1->HasTopItem()?1:0; x < filter1->Size(); x ++)
  1421. {
  1422. if (filter1->list->GetSelected(x))
  1423. {
  1424. if (cnt) namebuf.Append(", ");
  1425. if (cnt++ > 2)
  1426. {
  1427. namebuf.Append("..."); break;
  1428. }
  1429. namebuf.Append(AutoChar(filter1->GetText(x)));
  1430. }
  1431. }
  1432. }
  1433. }
  1434. if (namebuf.Get() && namebuf.Get()[0])
  1435. {
  1436. m.name = namebuf.Get();
  1437. m.flags |= ML_HANDLEDRAG_FLAG_NAME;
  1438. }
  1439. pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
  1440. }
  1441. }
  1442. }
  1443. freeRecordList(&obj);
  1444. }
  1445. break;
  1446. case WM_CONTEXTMENU:
  1447. {
  1448. HWND hwndFrom = (HWND)wParam;
  1449. int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
  1450. POINT pt = {x,y};
  1451. int idFrom = GetDlgCtrlID(hwndFrom);
  1452. HWND hHeader;
  1453. W_ListView m_list;
  1454. int editFilter=-1;
  1455. if (idFrom == IDC_LIST1)
  1456. {
  1457. m_list = m_list1;
  1458. hHeader = (HWND)SNDMSG(m_list.getwnd(), LVM_GETHEADER, 0, 0L);
  1459. RECT headerRect;
  1460. if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect))
  1461. {
  1462. if (FALSE != PtInRect(&headerRect, pt))
  1463. {
  1464. editFilter = 0;
  1465. }
  1466. }
  1467. }
  1468. else if (idFrom == IDC_LIST2)
  1469. {
  1470. m_list = m_list2;
  1471. hHeader = (HWND)SNDMSG(m_list.getwnd(), LVM_GETHEADER, 0, 0L);
  1472. RECT headerRect;
  1473. if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect))
  1474. {
  1475. if (FALSE != PtInRect(&headerRect, pt))
  1476. {
  1477. editFilter = 1;
  1478. }
  1479. }
  1480. }
  1481. else if (idFrom == IDC_LIST3)
  1482. {
  1483. m_list = m_list3;
  1484. hHeader = (HWND)SNDMSG(m_list.getwnd(), LVM_GETHEADER, 0, 0L);
  1485. RECT headerRect;
  1486. if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect))
  1487. {
  1488. if (FALSE != PtInRect(&headerRect, pt))
  1489. {
  1490. editFilter = 2;
  1491. }
  1492. }
  1493. }
  1494. else
  1495. break;
  1496. if (editFilter != -1)
  1497. {
  1498. HMENU themenu = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1499. HMENU menu = filter[editFilter]->GetMenu(true,editFilter,g_view_metaconf,themenu);
  1500. POINT p;
  1501. GetCursorPos(&p);
  1502. int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, hwndDlg, NULL);
  1503. DestroyMenu(themenu);
  1504. filter[editFilter]->ProcessMenuResult(r,true,editFilter,g_view_metaconf,hwndDlg);
  1505. MSG msg;
  1506. while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return
  1507. break;
  1508. }
  1509. int pane=0;
  1510. if (numFilters > 1)
  1511. {
  1512. if (idFrom == IDC_LIST2 && m_list2.GetSelectionMark() >= 0) pane=1;
  1513. }
  1514. if (numFilters > 2)
  1515. {
  1516. if (idFrom == IDC_LIST3 && m_list3.GetSelectionMark() >= 0) pane=2;
  1517. }
  1518. if (x == -1 || y == -1) // x and y are -1 if the user invoked a shift-f10 popup menu
  1519. {
  1520. RECT itemRect = {0};
  1521. int selected = m_list.GetNextSelected();
  1522. if (selected != -1) // if something is selected we'll drop the menu from there
  1523. {
  1524. m_list.GetItemRect(selected, &itemRect);
  1525. ClientToScreen(m_list.getwnd(), (POINT *)&itemRect);
  1526. }
  1527. else // otherwise we'll drop it from the top-left corner of the listview, adjusting for the header location
  1528. {
  1529. GetWindowRect(m_list.getwnd(), &itemRect);
  1530. HWND hHeader = (HWND)SNDMSG(m_list.getwnd(), LVM_GETHEADER, 0, 0L);
  1531. RECT headerRect;
  1532. if ((WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) && GetWindowRect(hHeader, &headerRect))
  1533. {
  1534. itemRect.top += (headerRect.bottom - headerRect.top);
  1535. }
  1536. }
  1537. x = itemRect.left;
  1538. y = itemRect.top;
  1539. }
  1540. RECT headerRect;
  1541. if (0 == (WS_VISIBLE & GetWindowLongPtr(hHeader, GWL_STYLE)) || FALSE == GetWindowRect(hHeader, &headerRect))
  1542. {
  1543. SetRectEmpty(&headerRect);
  1544. }
  1545. if (FALSE != PtInRect(&headerRect, pt))
  1546. {
  1547. break;
  1548. }
  1549. HMENU menu = GetSubMenu(g_context_menus, 1);
  1550. sendto_hmenu = GetSubMenu(menu, 2);
  1551. s.mode = 0;
  1552. s.hwnd = 0;
  1553. s.build_hMenu = 0;
  1554. IPC_LIBRARY_SENDTOMENU = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"LibrarySendToMenu", IPC_REGISTER_WINAMP_IPCMESSAGE);
  1555. if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
  1556. {
  1557. s.mode = 1;
  1558. s.hwnd = hwndDlg;
  1559. s.data_type = ML_TYPE_ITEMRECORDLIST;
  1560. s.ctx[1] = 1;
  1561. s.build_hMenu = sendto_hmenu;
  1562. }
  1563. wchar_t str[128] = {0};
  1564. StringCchPrintfW(str, 128, (!play_enq_rnd_alt?WASABI_API_LNGSTRINGW(IDS_PLAY_RANDOM_ITEM):L"%s"),
  1565. filter[pane]->GetNameSingularAlt(play_enq_rnd_alt?1:0));
  1566. FixAmps(str, 128);
  1567. MENUITEMINFOW mii =
  1568. {
  1569. sizeof(MENUITEMINFOW),
  1570. MIIM_TYPE | MIIM_ID,
  1571. MFT_STRING,
  1572. MFS_ENABLED,
  1573. ID_AUDIOWND_PLAYRANDOMITEM,
  1574. NULL,
  1575. NULL,
  1576. NULL,
  1577. 0,
  1578. str,
  1579. 0,
  1580. };
  1581. SetMenuItemInfoW(menu, ID_AUDIOWND_PLAYRANDOMITEM, false, &mii);
  1582. StringCchPrintfW(str, 128, (!play_enq_rnd_alt?WASABI_API_LNGSTRINGW(IDS_ENQUEUE_RANDOM_ITEM):L"%s"),
  1583. filter[pane]->GetNameSingularAlt(play_enq_rnd_alt?2:0));
  1584. FixAmps(str, 128);
  1585. mii.wID = ID_AUDIOWND_ENQUEUERANDOMITEM;
  1586. SetMenuItemInfoW(menu, ID_AUDIOWND_ENQUEUERANDOMITEM, false, &mii);
  1587. filter[pane]->DialogProc(hwndDlg,WM_USER+600,(WPARAM)menu,0x7000);
  1588. UpdateMenuItems(NULL, menu, IDR_VIEW_ACCELERATORS);
  1589. int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, x, y, hwndDlg, NULL);
  1590. filter[pane]->DialogProc(hwndDlg,WM_USER+601,(WPARAM)menu,0x7000);
  1591. if(r >= 0x7000 && r <= 0x8000) {
  1592. GayStringW query;
  1593. getParentPlusSearchQuery(&query);
  1594. for (int i=0; i<=pane; i++)
  1595. makeFilterQuery(&query,filter[i]);
  1596. filter[pane]->DialogProc(hwndDlg,WM_USER+602,(WPARAM)query.Get(),r - 0x7000);
  1597. }
  1598. switch (r)
  1599. {
  1600. case ID_AUDIOWND_PLAYSELECTION:
  1601. playList(PLAY,pane);
  1602. break;
  1603. case ID_AUDIOWND_ENQUEUESELECTION:
  1604. playList(ENQUEUE,pane);
  1605. break;
  1606. case ID_AUDIOWND_PLAYRANDOMITEM:
  1607. case ID_AUDIOWND_ENQUEUERANDOMITEM:
  1608. playRandomList(r == ID_AUDIOWND_PLAYRANDOMITEM ? PLAY : ENQUEUE, pane);
  1609. break;
  1610. case ID_RATE_1:
  1611. case ID_RATE_2:
  1612. case ID_RATE_3:
  1613. case ID_RATE_4:
  1614. case ID_RATE_5:
  1615. case ID_RATE_0:
  1616. {
  1617. int rate = r - ID_RATE_1 + 1;
  1618. if (r == ID_RATE_0) rate = 0;
  1619. if(rateList(rate))
  1620. {
  1621. wchar_t buf[10] = {0};
  1622. wsprintfW(buf,L"%d",rate);
  1623. int s = -1;
  1624. while((s = filter[pane]->list->GetNextSelected(s)) != -1)
  1625. filter[pane]->MetaUpdate(s, DB_FIELDNAME_rating,buf);
  1626. }
  1627. PostMessage(hwndDlg, WM_APP + 4, (WPARAM)rate, (LPARAM)0);
  1628. }
  1629. break;
  1630. default:
  1631. if (s.mode == 2)
  1632. {
  1633. s.menu_id = r;
  1634. if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
  1635. {
  1636. // build my data.
  1637. s.mode = 3;
  1638. s.data_type = ML_TYPE_ITEMRECORDLISTW;
  1639. itemRecordListW myObj = {0, };
  1640. buildRecordListW(&myObj, pane);
  1641. s.data = (void*) & myObj;
  1642. LRESULT result = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU);
  1643. if (result != 1)
  1644. {
  1645. s.mode = 3;
  1646. s.data_type = ML_TYPE_ITEMRECORDLIST;
  1647. itemRecordList objA = {0, };
  1648. convertRecordList(&objA, &myObj);
  1649. s.data = (void*) & objA;
  1650. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU);
  1651. freeRecordList(&objA);
  1652. }
  1653. freeRecordList(&myObj);
  1654. }
  1655. }
  1656. break;
  1657. }
  1658. if (s.mode)
  1659. {
  1660. s.mode = 4;
  1661. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_LIBRARY_SENDTOMENU); // cleanup
  1662. }
  1663. sendto_hmenu = 0;
  1664. EatKeyboard();
  1665. return 0;
  1666. }
  1667. case WM_NOTIFY:
  1668. {
  1669. LPNMHDR l = (LPNMHDR)lParam;
  1670. if (l->code == LVN_ODFINDITEMW)
  1671. {
  1672. ViewFilter * f;
  1673. if (l->idFrom == IDC_LIST2) f = filter[1];
  1674. else if (l->idFrom == IDC_LIST3) f = filter[2];
  1675. else f = filter[0];
  1676. NMLVFINDITEMW *t = (NMLVFINDITEMW *)lParam;
  1677. int i = t->iStart;
  1678. if (i >= f->Size()) i = 0;
  1679. int cnt = f->Size() - i;
  1680. if (t->lvfi.flags & LVFI_WRAP) cnt += i;
  1681. while (cnt-- > 0)
  1682. {
  1683. const wchar_t *name = f->GetText(i);
  1684. SKIP_THE_AND_WHITESPACEW(name)
  1685. if (t->lvfi.flags & (4 | LVFI_PARTIAL))
  1686. {
  1687. if (!StrCmpNIW(name, t->lvfi.psz, wcslen(t->lvfi.psz)))
  1688. {
  1689. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, i);
  1690. return 1;
  1691. }
  1692. }
  1693. else if (t->lvfi.flags & LVFI_STRING)
  1694. {
  1695. if (!lstrcmpiW(name, t->lvfi.psz))
  1696. {
  1697. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, i);
  1698. return 1;
  1699. }
  1700. }
  1701. else
  1702. {
  1703. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
  1704. return 1;
  1705. }
  1706. if (++i == f->Size()) i = 0;
  1707. }
  1708. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
  1709. return 1;
  1710. }
  1711. else if (l->code == LVN_GETDISPINFOW)
  1712. {
  1713. NMLVDISPINFOW *lpdi = (NMLVDISPINFOW*) lParam;
  1714. int item = lpdi->item.iItem;
  1715. if (item < 0) return 0;
  1716. if (lpdi->item.mask & LVIF_TEXT)
  1717. {
  1718. if (l->idFrom == IDC_LIST3 && numFilters == 3)
  1719. lpdi->item.pszText = (wchar_t*)filter[2]->CopyText2(item,lpdi->item.iSubItem,lpdi->item.pszText,lpdi->item.cchTextMax);
  1720. if (l->idFrom == IDC_LIST2)
  1721. lpdi->item.pszText = (wchar_t*)filter[1]->CopyText2(item,lpdi->item.iSubItem,lpdi->item.pszText,lpdi->item.cchTextMax);
  1722. else if (l->idFrom == IDC_LIST1)
  1723. lpdi->item.pszText = (wchar_t*)filter[0]->CopyText2(item, lpdi->item.iSubItem, lpdi->item.pszText, lpdi->item.cchTextMax);
  1724. }
  1725. return 0;
  1726. }
  1727. else if (l->code == LVN_COLUMNCLICK)
  1728. {
  1729. NMLISTVIEW *p = (NMLISTVIEW*)lParam;
  1730. int which = l->idFrom == IDC_LIST3 ? 2 : (l->idFrom == IDC_LIST2 ? 1 : 0);
  1731. wchar_t buf[32] = {0}, buf2[32] = {0};
  1732. StringCchPrintfW(buf, ARRAYSIZE(buf), L"%hs_sort_by_%d",filter[which]->GetConfigId(), which);
  1733. int l_sc = g_view_metaconf->ReadInt(buf, 0);
  1734. StringCchPrintfW(buf2, ARRAYSIZE(buf2), L"%hs_sort_dir_%d",filter[which]->GetConfigId(), which);
  1735. int l_sd = g_view_metaconf->ReadInt(buf2, 0);
  1736. if (p->iSubItem == l_sc) l_sd = !l_sd;
  1737. else l_sc = p->iSubItem;
  1738. g_view_metaconf->WriteInt(buf, l_sc);
  1739. g_view_metaconf->WriteInt(buf2, l_sd);
  1740. int s;
  1741. s = filter[which]->Size();
  1742. int dlgitem = (which==0)?IDC_LIST1:((which==1)?IDC_LIST2:IDC_LIST3);
  1743. SendMessage((HWND)SendMessage(GetDlgItem(hwndDlg,dlgitem), LVM_GETHEADER, 0, 0L),WM_ML_IPC,MAKEWPARAM(l_sc,!l_sd/* : !l_sd/*!l_sd : l_sd*/),ML_IPC_SKINNEDHEADER_DISPLAYSORT);
  1744. filter[which]->SortResults(g_view_metaconf, which);
  1745. ListView_SetItemCount(l->hwndFrom, s);
  1746. InvalidateRect(l->hwndFrom, NULL, TRUE);
  1747. }
  1748. else if (l->idFrom == IDC_LIST1 || l->idFrom == IDC_LIST2 || l->idFrom == IDC_LIST3)
  1749. {
  1750. int pane = 0;
  1751. if (l->idFrom == IDC_LIST2) pane = 1;
  1752. if (l->idFrom == IDC_LIST3) pane = 2;
  1753. if (l->code == NM_DBLCLK)
  1754. {
  1755. // allow doubleclick on all, yes
  1756. int c = filter[pane]->list->GetCount(), x=0;
  1757. for (x = 0; x < c; x ++) if (filter[pane]->list->GetSelected(x)) break;
  1758. if (!x && pane>0 && filter[pane]->HasTopItem())
  1759. playList((!!g_config->ReadInt(L"enqueuedef", PLAY)) ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000)),pane-1);
  1760. else if (x < c)
  1761. playList((!!g_config->ReadInt(L"enqueuedef", PLAY)) ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000)),pane);
  1762. }
  1763. else if (l->code == LVN_ITEMCHANGED)
  1764. {
  1765. LPNMLISTVIEW lv = (LPNMLISTVIEW)lParam;
  1766. if (ignore_selections || !((lv->uNewState ^ lv->uOldState) & LVIS_SELECTED)) return 0;
  1767. int t;
  1768. if (pane==0) t=167;
  1769. else if (pane==1) t=166;
  1770. else t=165;
  1771. KillTimer(hwndDlg, t);
  1772. SetTimer(hwndDlg, t, 100, NULL);
  1773. }
  1774. else if (l->code == LVN_BEGINDRAG)
  1775. {
  1776. if (pane==0) we_are_drag_and_dropping = 1;
  1777. else if (pane==1) we_are_drag_and_dropping = 2;
  1778. else we_are_drag_and_dropping = 3;
  1779. SetCapture(hwndDlg);
  1780. }
  1781. }
  1782. if (l->code == NM_RETURN)
  1783. {
  1784. extern void playFiles(int enqueue, int all);
  1785. playFiles(((!!g_config->ReadInt(L"enqueuedef", 0)) ^(!!(GetAsyncKeyState(VK_SHIFT)&0x8000))), 1);
  1786. }
  1787. }
  1788. break;
  1789. case WM_USER+710:
  1790. if(rateList(wParam))
  1791. {
  1792. ViewFilter *f = (ViewFilter *)lParam;
  1793. // first check the validity of lParam
  1794. bool found=false;
  1795. for(int i=0; i<numFilters; i++)
  1796. if(filter[i] == f) found=true;
  1797. if(!found) break;
  1798. wchar_t buf[10] = {0};
  1799. wsprintfW(buf,L"%d",wParam);
  1800. int s = -1;
  1801. while((s = f->list->GetNextSelected(s)) != -1)
  1802. f->MetaUpdate(s, DB_FIELDNAME_rating,buf);
  1803. }
  1804. break;
  1805. case WM_DROPFILES:
  1806. {
  1807. extern void Window_OnDropFiles(HWND hwndDlg, HDROP hdrop);
  1808. Window_OnDropFiles(hwndDlg, (HDROP)wParam);
  1809. break;
  1810. }
  1811. case WM_COMMAND:
  1812. switch (LOWORD(wParam))
  1813. {
  1814. case IDC_CLEAR:
  1815. SetDlgItemText(hwndDlg, IDC_QUICKSEARCH, L"");
  1816. break;
  1817. case IDC_QUICKSEARCH:
  1818. if (HIWORD(wParam) == EN_CHANGE)
  1819. {
  1820. KillTimer(hwndDlg, 205);
  1821. SetTimer(hwndDlg, 205, g_querydelay, NULL);
  1822. }
  1823. break;
  1824. case IDC_BUTTON_ARTMODE:
  1825. {
  1826. int changed=0;
  1827. int f[3]={0,0,0};
  1828. for (int i=0; i<numFilters; i++)
  1829. {
  1830. f[i] = GetFilter(m_query_mode,i);
  1831. if (f[i] == 6)
  1832. {
  1833. f[i] = 11; changed=true;
  1834. }
  1835. else if (f[i] == 11)
  1836. {
  1837. f[i] = 6; changed=true;
  1838. }
  1839. }
  1840. if (changed)
  1841. {
  1842. if (f[1] == 6) f[1]=0;
  1843. if (numFilters == 2) f[2]=0;
  1844. int m = f[0] | (f[1] << 8) | (f[2] << 16);
  1845. int par = mediaLibrary.GetSelectedTreeItem();
  1846. QueryList::iterator iter;
  1847. iter = m_query_list.find(par);
  1848. if (iter != m_query_list.end())
  1849. iter->second->mode = m;
  1850. saveQueryTree();
  1851. PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
  1852. }
  1853. }
  1854. break;
  1855. case IDC_BUTTON_VIEWMODE:
  1856. {
  1857. int presets[] =
  1858. {
  1859. MAKEVIEW_2FILTER(ARTIST,ALBUM),
  1860. MAKEVIEW_2FILTER(ARTIST,ALBUMART),
  1861. MAKEVIEW_2FILTER(ALBUMARTIST,ALBUM),
  1862. MAKEVIEW_2FILTER(ALBUMARTIST,ALBUMART),
  1863. MAKEVIEW_3FILTER(GENRE,ARTIST,ALBUM),
  1864. MAKEVIEW_2FILTER(GENRE,ALBUMART),
  1865. MAKEVIEW_3FILTER(YEAR,ARTIST,ALBUM),
  1866. MAKEVIEW_2FILTER(COMPOSER,ALBUM),
  1867. MAKEVIEW_3FILTER(PUBLISHER,ARTIST,ALBUM),
  1868. };
  1869. HMENU menu = CreatePopupMenu();
  1870. bool hasCheck=false;
  1871. for (int i=0; i < sizeof(presets)/sizeof(presets[0]); i++)
  1872. {
  1873. wchar_t buf[350] = {0}, filterName[128] = {0};
  1874. buf[0] = L'\0';
  1875. int l = GetNumFilters(presets[i]);
  1876. bool check = (l == GetNumFilters(m_query_mode));
  1877. for (int j=0; j<l; j++)
  1878. {
  1879. int f = GetFilter(presets[i],j)-1;
  1880. wcscat(buf,getFilterName(f, filterName, ARRAYSIZE(filterName)));
  1881. if (GetFilter(presets[i],j+1)) wcscat(buf,L"\\");
  1882. if (GetFilter(presets[i],j) != GetFilter(m_query_mode,j)) check=false;
  1883. }
  1884. AppendMenuW(menu,MF_STRING,i+1,buf);
  1885. if(check)
  1886. {
  1887. CheckMenuItem(menu,i+1,MF_CHECKED);
  1888. hasCheck=true;
  1889. }
  1890. }
  1891. AppendMenuW(menu,MF_STRING,0x4000,WASABI_API_LNGSTRINGW(IDS_OTHER2));
  1892. if(!hasCheck)
  1893. CheckMenuItem(menu,0x4000,MF_CHECKED);
  1894. RECT rc;
  1895. GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),&rc);
  1896. int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY,
  1897. rc.left, rc.bottom, hwndDlg, NULL);
  1898. DestroyMenu(menu);
  1899. if (r==0) break;
  1900. else if (r == 0x4000)
  1901. queryEditItem(mediaLibrary.GetSelectedTreeItem());
  1902. else
  1903. {
  1904. int par = mediaLibrary.GetSelectedTreeItem();
  1905. QueryList::iterator iter;
  1906. iter = m_query_list.find(par);
  1907. if (iter != m_query_list.end())
  1908. iter->second->mode = presets[r-1];;
  1909. saveQueryTree();
  1910. PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
  1911. }
  1912. }
  1913. break;
  1914. case IDC_BUTTON_COLUMNS:
  1915. {
  1916. HMENU themenu[3] = {0};
  1917. wchar_t *name[3] = {0}, filterName[128] = {0};
  1918. HMENU menu = CreatePopupMenu();
  1919. MENUITEMINFOW m={sizeof(m),MIIM_TYPE | MIIM_ID | MIIM_SUBMENU,MFT_STRING,0};
  1920. for (int i=0; i<numFilters; i++)
  1921. {
  1922. m.wID = i;
  1923. m.dwTypeData = name[i] = _wcsdup(getFilterName(GetFilter(m_query_mode,i)-1, filterName, ARRAYSIZE(filterName)));
  1924. themenu[i] = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  1925. m.hSubMenu = filter[i]->GetMenu(true,i,g_view_metaconf,themenu[i]);
  1926. InsertMenuItemW(menu,i,FALSE,&m);
  1927. }
  1928. m.wID = 3;
  1929. m.dwTypeData = WASABI_API_LNGSTRINGW(IDS_TRACKS_MENU);
  1930. m.hSubMenu = GetSubMenu(themenu[0], 4);
  1931. InsertMenuItemW(menu,3,FALSE,&m);
  1932. RECT rc;
  1933. GetWindowRect(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),&rc);
  1934. int r = DoTrackPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, rc.left,rc.bottom, hwndDlg, NULL);
  1935. DestroyMenu(menu);
  1936. if (r == ID_HEADERWND_CUSTOMIZECOLUMNS)
  1937. {
  1938. void customizeColumnsDialog(HWND hwndParent);
  1939. customizeColumnsDialog(hwndDlg);
  1940. }
  1941. for (int i=0; i<numFilters; i++)
  1942. {
  1943. filter[i]->ProcessMenuResult(r,true,i,g_view_metaconf,hwndDlg);
  1944. DestroyMenu(themenu[i]);
  1945. free(name[i]);
  1946. }
  1947. }
  1948. break;
  1949. }
  1950. break;
  1951. case WM_WINDOWPOSCHANGED:
  1952. if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE) & ((WINDOWPOS*)lParam)->flags) ||
  1953. (SWP_FRAMECHANGED & ((WINDOWPOS*)lParam)->flags))
  1954. {
  1955. LayoutWindows(hwndDlg, !(SWP_NOREDRAW & ((WINDOWPOS*)lParam)->flags));
  1956. }
  1957. return TRUE;
  1958. case WM_APP + 1: //sent by parent for resizing window
  1959. bgQuery_Stop();
  1960. getParentPlusSearchQuery(&l_query);
  1961. EnterCriticalSection(&g_db_cs);
  1962. NDE_Scanner_Query(m_media_scanner, l_query.Get());
  1963. LeaveCriticalSection(&g_db_cs);
  1964. ignore_selections = 1;
  1965. for (int i=0; i<numFilters; i++)
  1966. {
  1967. filter[i]->list->SetSelected(0);
  1968. ListView_SetItemCount(filter[i]->list->getwnd(), 0);
  1969. }
  1970. ignore_selections = 0;
  1971. if (!refresh) SetDlgItemText(m_media_hwnd, IDC_QUICKSEARCH, L"");
  1972. KillTimer(m_media_hwnd, UPDATE_QUERY_TIMER_ID); // keep it from researching :)
  1973. SendMessage(m_media_hwnd, WM_APP + 1, (WPARAM)mysearchCallbackAlbumUpdate, (LPARAM)0);
  1974. refresh -= 1;
  1975. break;
  1976. case WM_QUERYFILEINFO: if (m_media_hwnd) PostMessageW(m_media_hwnd, uMsg, wParam, lParam); break;
  1977. case WM_SHOWFILEINFO:
  1978. SendMessageW(GetParent(hwndDlg), uMsg, wParam, lParam); break;
  1979. case WM_USER + 66:
  1980. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam));
  1981. return TRUE;
  1982. case WM_APP + 2: //sent by media child to get current query
  1983. if (lParam) *((const wchar_t **)(lParam)) = l_query.Get();
  1984. break;
  1985. case WM_APP + 3: // sent by bg thread to update our shit
  1986. if (wParam == 0x69)
  1987. {
  1988. if (lParam == 0 && numFilters >= 1)
  1989. {
  1990. if (UpdateFilterPane(0,"artist_sel_utf8"))
  1991. {
  1992. PostMessage(hwndDlg,WM_TIMER,167,0);
  1993. break;
  1994. }
  1995. }
  1996. if (lParam <= 1 && numFilters >= 2)
  1997. {
  1998. if (UpdateFilterPane(1,"album_sel_utf8"))
  1999. {
  2000. PostMessage(hwndDlg,WM_TIMER,166,0);
  2001. break;
  2002. }
  2003. }
  2004. if (numFilters >= 3)
  2005. {
  2006. if (UpdateFilterPane(2,"list3_sel_utf8"))
  2007. {
  2008. PostMessage(hwndDlg,WM_TIMER,165,0);
  2009. }
  2010. }
  2011. }
  2012. break;
  2013. // used for working around some quirks with the ratings so it'll update on-the-fly(ish)
  2014. case WM_APP + 4:
  2015. {
  2016. if(!lParam)
  2017. {
  2018. wchar_t buf[64] = {0};
  2019. StringCchPrintfW(buf,64,L"%d",wParam);
  2020. for(int i=0; i<numFilters; i++)
  2021. {
  2022. int s = -1;
  2023. while((s = filter[i]->list->GetNextSelected(s)) != -1)
  2024. {
  2025. filter[i]->MetaUpdate(s, DB_FIELDNAME_rating, buf);
  2026. SendMessage(filter[i]->list->getwnd(),LVM_REDRAWITEMS,s,s);
  2027. }
  2028. }
  2029. }
  2030. else
  2031. {
  2032. PostMessage(m_media_hwnd, WM_APP + 1, (WPARAM)mysearchCallbackAlbumUpdate, (LPARAM)1);
  2033. }
  2034. }
  2035. break;
  2036. case WM_APP + 5:
  2037. // TODO
  2038. break;
  2039. case WM_APP + 6: // handles the ml_cloud 'first pull' announces so we
  2040. { // can then show the cloud column & update the cache
  2041. SendMessage(m_media_hwnd, WM_APP + 6, wParam, lParam);
  2042. break;
  2043. }
  2044. case WM_DESTROY:
  2045. FlushCache();
  2046. if (numFilters >= 2) g_view_metaconf->WriteInt(L"adiv1pos", div_filterpos);
  2047. if (numFilters >= 3) g_view_metaconf->WriteInt(L"adiv3pos", div_filter2pos);
  2048. g_view_metaconf->WriteInt(L"adiv2pos", div_mediapos);
  2049. // save a list of selected artists and albums
  2050. for (int i=0; i<numFilters; i++)
  2051. {
  2052. GayStringW gs;
  2053. if (!(filter[i]->list->GetSelected(0) && filter[i]->HasTopItem()))
  2054. {
  2055. int c = filter[i]->list->GetCount(), delim = 0;
  2056. for (int x = filter[i]->HasTopItem()?1:0; x < c; x ++)
  2057. {
  2058. if (filter[i]->list->GetSelected(x))
  2059. {
  2060. if (delim) gs.Append(LDELIMSTR);
  2061. const wchar_t *p = filter[i]->GetText(x);
  2062. while (p && *p)
  2063. {
  2064. if (*p == *LDELIMSTR) gs.Append(LDELIMSTR LDELIMSTR);
  2065. else
  2066. {
  2067. wchar_t buf[2] = {*p, 0};
  2068. gs.Append(buf);
  2069. }
  2070. p++;
  2071. }
  2072. delim = 1;
  2073. }
  2074. }
  2075. }
  2076. char *confname = "artist_sel_utf8";
  2077. if (i==1) confname = "album_sel_utf8";
  2078. if (i==2) confname = "list3_sel_utf8";
  2079. g_view_metaconf->WriteString(confname, AutoChar(gs.Get(), CP_UTF8));
  2080. }
  2081. {
  2082. wchar_t buf[2048] = {0};
  2083. GetDlgItemTextW(hwndDlg, IDC_QUICKSEARCH, buf, ARRAYSIZE(buf));
  2084. g_view_metaconf->WriteString("lastquery_a_utf8", AutoChar(buf, CP_UTF8));
  2085. }
  2086. bgQuery_Stop();
  2087. for (int i=0; i<numFilters; i++)
  2088. {
  2089. filter[i]->SaveColumnWidths();
  2090. filter[i]->Empty();
  2091. filter[i]->ClearColumns();
  2092. delete filter[i];
  2093. }
  2094. numFilters=0;
  2095. {
  2096. SkinBitmap *s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),GWLP_USERDATA);
  2097. if (s)
  2098. {
  2099. void *bits = s->getBits();
  2100. if (bits) free(bits); delete s;
  2101. SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_ARTMODE),GWLP_USERDATA, 0);
  2102. }
  2103. s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),GWLP_USERDATA);
  2104. if (s)
  2105. {
  2106. void *bits = s->getBits();
  2107. if (bits) free(bits); delete s;
  2108. SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_VIEWMODE),GWLP_USERDATA, 0);
  2109. }
  2110. s = (SkinBitmap*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),GWLP_USERDATA);
  2111. if (s)
  2112. {
  2113. void *bits = s->getBits();
  2114. if (bits) free(bits); delete s;
  2115. SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_BUTTON_COLUMNS),GWLP_USERDATA, 0);
  2116. }
  2117. }
  2118. break;
  2119. case WM_PAINT:
  2120. {
  2121. int tab[] =
  2122. {
  2123. IDC_HDELIM | DCW_DIVIDER, // 0
  2124. IDC_QUICKSEARCH | DCW_SUNKENBORDER, // 1
  2125. IDC_DIV1 | DCW_DIVIDER, // 2
  2126. IDC_LIST1 | DCW_SUNKENBORDER, //3
  2127. IDC_LIST2 | DCW_SUNKENBORDER, //4
  2128. IDC_LIST3 | DCW_SUNKENBORDER, //5
  2129. IDC_DIV2 | DCW_DIVIDER, //6
  2130. };
  2131. int size = 5;
  2132. if (numFilters == 3) size = 7;
  2133. if (m_nodrawtopborders) size = 2;
  2134. else
  2135. {
  2136. if (numFilters == 3)
  2137. {
  2138. if (adiv1_nodraw == 2) tab[4]=0;
  2139. if (adiv1_nodraw == 1) tab[3]=0;
  2140. if (adiv2_nodraw == 2) tab[5]=0;
  2141. if (adiv2_nodraw == 1) tab[4]=0;
  2142. }
  2143. else
  2144. {
  2145. if (adiv1_nodraw == 2) size = 4;
  2146. if (adiv1_nodraw == 1)
  2147. {
  2148. size = 4; tab[3] = tab[4];
  2149. }
  2150. }
  2151. }
  2152. dialogSkinner.Draw(hwndDlg, tab, size);
  2153. }
  2154. break;
  2155. case WM_ERASEBKGND:
  2156. return 1; //handled by WADlg_DrawChildWindowBorders in WM_PAINT
  2157. case WM_USER + 0x201:
  2158. offsetX = (short)LOWORD(wParam);
  2159. offsetY = (short)HIWORD(wParam);
  2160. g_rgnUpdate = (HRGN)lParam;
  2161. return TRUE;
  2162. case WM_ML_CHILDIPC:
  2163. switch (lParam)
  2164. {
  2165. case ML_CHILDIPC_GO_TO_SEARCHBAR:
  2166. SendDlgItemMessage(hwndDlg, IDC_QUICKSEARCH, EM_SETSEL, 0, -1);
  2167. SetFocus(GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
  2168. break;
  2169. case ML_CHILDIPC_REFRESH_SEARCH:
  2170. refresh = (1 + numFilters);
  2171. PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_QUICKSEARCH, EN_CHANGE), (LPARAM)GetDlgItem(hwndDlg, IDC_QUICKSEARCH));
  2172. break;
  2173. }
  2174. break;
  2175. }
  2176. return FALSE;
  2177. }