view_ex.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. /*
  2. ** Copyright (C) 2003 Nullsoft, Inc.
  3. **
  4. ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
  5. ** liable for any damages arising from the use of this software.
  6. **
  7. ** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
  8. ** alter it and redistribute it freely, subject to the following restrictions:
  9. **
  10. ** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
  11. ** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  12. **
  13. ** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  14. **
  15. ** 3. This notice may not be removed or altered from any source distribution.
  16. **
  17. */
  18. #include <windows.h>
  19. #include <windowsx.h>
  20. #include <stdio.h>
  21. #include "../ml.h"
  22. #include "resource.h"
  23. #include "../listview.h"
  24. #include "../childwnd.h"
  25. #include "../../winamp/wa_dlg.h"
  26. #include "../itemlist.h"
  27. // configuration section in winamp.ini
  28. #define CONFIG_SEC "ml_ex"
  29. // columns in our big treeview
  30. #define COL_ARTIST 0
  31. #define COL_TITLE 1
  32. #define COL_ALBUM 2
  33. #define COL_LENGTH 3
  34. #define COL_TRACK 4
  35. #define COL_GENRE 5
  36. #define COL_YEAR 6
  37. #define COL_FILENAME 7
  38. // makes a NULL char * an empty string
  39. #define MAKESAFE(x) ((x)?(x):"")
  40. // yes, we could easily use an itemRecord / itemRecordList here instead of 'Song's, but the point of this example
  41. // is to show how to integrate with some other native structure
  42. typedef struct
  43. {
  44. char *artist;
  45. char *title;
  46. char *album;
  47. int songlen; // seconds?
  48. int track_nr;
  49. char *genre;
  50. int year;
  51. char *filename;
  52. } Song;
  53. // our leading crap reduction agent for use with sorting/etc
  54. #define SKIP_THE_AND_WHITESPACE(x) { while (!isalnum(*x) && *x) x++; if (!_strnicmp(x,"the ",4)) x+=4; while (*x == ' ') x++; }
  55. extern winampMediaLibraryPlugin plugin;
  56. static int myParam; // param of our tree item
  57. static C_ItemList m_songs, *m_songs_sorted;
  58. static W_ListView m_list;
  59. static HWND m_hwnd;
  60. static HMENU m_context_menus;
  61. static int m_skinlistview_handle;
  62. void config(HWND parent);
  63. void sortResults();
  64. static void deleteSongPtr(Song *song)
  65. {
  66. free(song->album);
  67. free(song->artist);
  68. free(song->title);
  69. free(song->genre);
  70. free(song->filename);
  71. free(song);
  72. }
  73. static void clearSongList()
  74. {
  75. int i=m_songs.GetSize();
  76. while (i>0)
  77. {
  78. Song *song=(Song *)m_songs.Get(--i);
  79. deleteSongPtr(song);
  80. m_songs.Del(i);
  81. }
  82. }
  83. // this doesnt actually alloc the memory for all the strings, just references them (so it is only temporarily valid at best)
  84. void SongsToItemList(itemRecordList *p, int all)
  85. {
  86. if (!m_hwnd) all=1;
  87. p->Alloc=p->Size=0;
  88. p->Items=0;
  89. C_ItemList *list=(C_ItemList *)m_songs_sorted;
  90. if (!list) { list=&m_songs; all=1; }
  91. int x,l=list->GetSize();
  92. for (x = 0 ; x < l; x ++)
  93. {
  94. if (!all && !m_list.GetSelected(x)) continue;
  95. allocRecordList(p,p->Size+1,256);
  96. if (!p->Items) break;
  97. Song *s=(Song *)list->Get(x);
  98. memset(&p->Items[p->Size],0,sizeof(itemRecord));
  99. p->Items[p->Size].album=s->album;
  100. p->Items[p->Size].artist=s->artist;
  101. p->Items[p->Size].title=s->title;
  102. p->Items[p->Size].genre=s->genre;
  103. p->Items[p->Size].filename=s->filename;
  104. p->Items[p->Size].track=s->track_nr;
  105. p->Items[p->Size].year=s->year;
  106. p->Items[p->Size].length=s->songlen;
  107. p->Size++;
  108. }
  109. }
  110. static void playFiles(int enqueue, int all)
  111. {
  112. if (!m_songs_sorted) return;
  113. if (!m_hwnd && !all) return;
  114. itemRecordList obj={0,};
  115. SongsToItemList(&obj,all);
  116. if (obj.Size)
  117. {
  118. mlSendToWinampStruct s={ML_TYPE_ITEMRECORDLIST,(void*)&obj,!!enqueue};
  119. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_SENDTOWINAMP);
  120. }
  121. free(obj.Items);
  122. }
  123. void addItemListToSongs(itemRecordList *p)
  124. {
  125. if (p) for (int x = 0 ; x < p->Size; x ++)
  126. {
  127. Song *s=(Song *)calloc(1,sizeof(Song));
  128. if (p->Items[x].album) s->album=_strdup(p->Items[x].album);
  129. if (p->Items[x].artist) s->artist=_strdup(p->Items[x].artist);
  130. if (p->Items[x].title) s->title=_strdup(p->Items[x].title);
  131. if (p->Items[x].genre) s->genre=_strdup(p->Items[x].genre);
  132. if (p->Items[x].filename) s->filename=_strdup(p->Items[x].filename);
  133. s->track_nr=p->Items[x].track;
  134. s->year=p->Items[x].year;
  135. s->songlen=p->Items[x].length;
  136. m_songs.Add((void*)s);
  137. }
  138. }
  139. char *conf_file;
  140. int init() {
  141. mlAddTreeItemStruct mla={
  142. 0, // if you used 0, it would put it on top level, or ML_TREEVIEW_ID_DEVICES
  143. "Item Cache Example",
  144. 1,
  145. };
  146. conf_file=(char*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILE); // get winamp.ini name :)
  147. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&mla,ML_IPC_ADDTREEITEM);
  148. myParam=mla.this_id;
  149. m_context_menus=LoadMenu(plugin.hDllInstance,MAKEINTRESOURCE(IDR_CONTEXTMENUS));
  150. return 0;
  151. }
  152. void quit()
  153. {
  154. clearSongList();
  155. }
  156. void loadSongList()
  157. {
  158. clearSongList();
  159. // populate m_songs from whatever source we have
  160. Song *p=(Song *)calloc(sizeof(Song),1);
  161. p->filename = _strdup("http://www.firehose.net/~deadbeef/media/Misc/music/030223%20-%20pervert-in-a-satellite.mp3");
  162. p->album=_strdup("SEP");
  163. p->artist=_strdup("Nullsoft Band");
  164. p->genre=_strdup("Shit");
  165. p->songlen = 666;
  166. p->track_nr=1;
  167. p->title=_strdup("Pervert In A Satellite");
  168. p->year=2003;
  169. m_songs.Add((void*)p);
  170. }
  171. // this is uberadvancedsearchtechnology[tm]
  172. static void parsequicksearch(char *out, char *in) // parses a list into a list of terms that we are searching for
  173. {
  174. int inquotes=0, neednull=0;
  175. while (*in)
  176. {
  177. char c=*in++;
  178. if (c != ' ' && c != '\t' && c != '\"')
  179. {
  180. neednull=1;
  181. *out++=c;
  182. }
  183. else if (c == '\"')
  184. {
  185. inquotes=!inquotes;
  186. if (!inquotes)
  187. {
  188. *out++=0;
  189. neednull=0;
  190. }
  191. }
  192. else
  193. {
  194. if (inquotes) *out++=c;
  195. else if (neednull)
  196. {
  197. *out++=0;
  198. neednull=0;
  199. }
  200. }
  201. }
  202. *out++=0;
  203. *out++=0;
  204. }
  205. static int in_string(char *string, char *substring)
  206. {
  207. if (!string) return 0;
  208. if (!*substring) return 1;
  209. int l=strlen(substring);
  210. while (string[0]) if (!_strnicmp(string++,substring,l)) return 1;
  211. return 0;
  212. }
  213. static void updateList()
  214. {
  215. if(!m_hwnd) return;
  216. char filterstr[256],filteritems[300];
  217. GetDlgItemText(m_hwnd,IDC_QUICKSEARCH,filterstr,sizeof(filterstr)-1);
  218. parsequicksearch(filteritems,filterstr);
  219. delete m_songs_sorted;
  220. m_songs_sorted=new C_ItemList;
  221. unsigned int totallen=0,filterlen=0,filterval=0;
  222. for(int i=0;i<m_songs.GetSize();i++)
  223. {
  224. Song *s=(Song *)m_songs.Get(i);
  225. totallen+=s->songlen;
  226. char year[32]="";
  227. if (s->year < 5000 && s->year > 0) sprintf(year,"%d",s->year);
  228. char *p=filteritems;
  229. if (*p)
  230. {
  231. while (*p)
  232. {
  233. // search for 'p' in the song
  234. if (!in_string(s->album,p) && !in_string(s->artist,p) && !in_string(s->title,p) && !in_string(s->genre,p) && !in_string(year,p))
  235. break;
  236. p+=strlen(p)+1;
  237. }
  238. if (*p) continue;
  239. }
  240. filterval++;
  241. filterlen+=s->songlen;
  242. m_songs_sorted->Add((void *)s);
  243. }
  244. sortResults();
  245. char tmp[512];
  246. if (m_songs.GetSize() != m_songs_sorted->GetSize())
  247. wsprintf(tmp,"Found: %d items [%d:%02d:%02d]",
  248. m_songs_sorted->GetSize(),filterval,
  249. filterlen/3600,(filterlen/60)%60,filterlen%60);
  250. else
  251. wsprintf(tmp,"%d items [%d:%02d:%02d]",m_songs.GetSize(),totallen/3600,(totallen/60)%60,totallen%60);
  252. SetDlgItemText(m_hwnd,IDC_STATUS,tmp);
  253. }
  254. static ChildWndResizeItem resize_rlist[]={
  255. {IDC_QUICKSEARCH,0x0010},
  256. {IDC_LIST,0x0011},
  257. {IDC_BUTTON_CONFIG,0x0101},
  258. {IDC_STATUS,0x0111}
  259. };
  260. int g_sortcol, g_sortdir;
  261. static int STRCMP_NULLOK(const char *pa, const char *pb)
  262. {
  263. if (!pa) pa="";
  264. else SKIP_THE_AND_WHITESPACE(pa)
  265. if (!pb) pb="";
  266. else SKIP_THE_AND_WHITESPACE(pb)
  267. return _stricmp(pa,pb);
  268. }
  269. static int sortFunc(const void *elem1, const void *elem2)
  270. {
  271. Song *a=(Song *)*(void **)elem1;
  272. Song *b=(Song *)*(void **)elem2;
  273. int use_by=g_sortcol;
  274. int use_dir=g_sortdir;
  275. #define RETIFNZ(v) if ((v)<0) return use_dir?1:-1; if ((v)>0) return use_dir?-1:1;
  276. // this might be too slow, but it'd be nice
  277. int x;
  278. for (x = 0; x < 4; x ++)
  279. {
  280. if (use_by == COL_YEAR) // year -> artist -> album -> track
  281. {
  282. int v1=a->year;
  283. int v2=b->year;
  284. if (v1<0)v1=0;
  285. if (v2<0)v2=0;
  286. RETIFNZ(v1-v2)
  287. use_by=COL_ARTIST;
  288. }
  289. else if (use_by == COL_TITLE) // title -> artist -> album -> track
  290. {
  291. int v=STRCMP_NULLOK(a->title,b->title);
  292. RETIFNZ(v)
  293. use_by=COL_ARTIST;
  294. }
  295. else if (use_by == COL_ARTIST) // artist -> album -> track -> title
  296. {
  297. int v=STRCMP_NULLOK(a->artist,b->artist);
  298. RETIFNZ(v)
  299. use_by=COL_ALBUM;
  300. }
  301. else if (use_by == COL_ALBUM) // album -> track -> title -> artist
  302. {
  303. int v=STRCMP_NULLOK(a->album,b->album);
  304. RETIFNZ(v)
  305. use_dir=0;
  306. use_by=COL_TRACK;
  307. }
  308. else if (use_by == COL_GENRE) // genre -> artist -> album -> track
  309. {
  310. int v=STRCMP_NULLOK(a->genre,b->genre);
  311. RETIFNZ(v)
  312. use_by=COL_ARTIST;
  313. }
  314. else if (use_by == COL_TRACK) // track -> title -> artist -> album
  315. {
  316. int v1=a->track_nr;
  317. int v2=b->track_nr;
  318. if (v1<0)v1=0;
  319. if (v2<0)v2=0;
  320. RETIFNZ(v1-v2)
  321. use_by=COL_TITLE;
  322. }
  323. else if (use_by == COL_LENGTH) // length -> artist -> album -> track
  324. {
  325. int v1=a->songlen;
  326. int v2=b->songlen;
  327. if (v1<0)v1=0;
  328. if (v2<0)v2=0;
  329. RETIFNZ(v1-v2)
  330. use_by=COL_ARTIST;
  331. }
  332. else break; // no sort order?
  333. }
  334. #undef RETIFNZ
  335. return 0;
  336. }
  337. void sortResults()
  338. {
  339. if (!m_songs_sorted) return;
  340. qsort(m_songs_sorted->GetAll(),m_songs_sorted->GetSize(),sizeof(void*),sortFunc);
  341. ListView_SetItemCount(m_list.getwnd(),0);
  342. ListView_SetItemCount(m_list.getwnd(),m_songs_sorted->GetSize());
  343. ListView_RedrawItems(m_list.getwnd(),0,m_songs_sorted->GetSize()-1);
  344. }
  345. int (*wad_getColor)(int idx);
  346. int (*wad_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  347. void (*wad_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize);
  348. void (*cr_init)(HWND hwndDlg, ChildWndResizeItem *list, int num);
  349. void (*cr_resize)(HWND hwndDlg, ChildWndResizeItem *list, int num);
  350. static BOOL CALLBACK dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  351. {
  352. if (wad_handleDialogMsgs)
  353. {
  354. BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a;
  355. }
  356. switch (uMsg)
  357. {
  358. case WM_DISPLAYCHANGE:
  359. ListView_SetTextColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMFG):RGB(0xff,0xff,0xff));
  360. ListView_SetBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
  361. ListView_SetTextBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
  362. m_list.refreshFont();
  363. return 0;
  364. case WM_INITDIALOG:
  365. m_hwnd=hwndDlg;
  366. *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
  367. *(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC);
  368. *(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC);
  369. *(void **)&cr_init=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,32,ML_IPC_SKIN_WADLG_GETFUNC);
  370. // woof: *(void **)&cr_resize=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,33,ML_IPC_SKIN_WADLG_GETFUNC);
  371. if (cr_init) cr_init(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0]));
  372. m_list.setLibraryParentWnd(plugin.hwndLibraryParent);
  373. m_list.setwnd(GetDlgItem(hwndDlg,IDC_LIST));
  374. m_list.AddCol("Artist",200);
  375. m_list.AddCol("Title",200);
  376. m_list.AddCol("Album",200);
  377. m_list.AddCol("Length",64);
  378. m_list.AddCol("Track #",64);
  379. m_list.AddCol("Genre",100);
  380. m_list.AddCol("Year",64);
  381. m_list.AddCol("Filename",80);
  382. ListView_SetTextColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMFG):RGB(0xff,0xff,0xff));
  383. ListView_SetBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
  384. ListView_SetTextBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
  385. g_sortdir=GetPrivateProfileInt(CONFIG_SEC,"sortdir",0,conf_file);
  386. g_sortcol=GetPrivateProfileInt(CONFIG_SEC,"sortcol",g_sortcol,conf_file);
  387. m_skinlistview_handle=SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(int)m_list.getwnd(),ML_IPC_SKIN_LISTVIEW);
  388. SetTimer(hwndDlg,32,50,NULL);
  389. return 0;
  390. case WM_NOTIFY:
  391. {
  392. LPNMHDR l=(LPNMHDR)lParam;
  393. if (l->idFrom==IDC_LIST)
  394. {
  395. if (l->code == NM_DBLCLK)
  396. {
  397. playFiles(!!(GetAsyncKeyState(VK_SHIFT)&0x8000),0);
  398. }
  399. else if (l->code == LVN_BEGINDRAG)
  400. {
  401. SetCapture(hwndDlg);
  402. }
  403. else if (l->code == LVN_ODFINDITEM) // yay we find an item (for kb shortcuts)
  404. {
  405. NMLVFINDITEM *t = (NMLVFINDITEM *)lParam;
  406. int i=t->iStart;
  407. if (i >= m_songs_sorted->GetSize()) i=0;
  408. int cnt=m_songs_sorted->GetSize()-i;
  409. if (t->lvfi.flags & LVFI_WRAP) cnt+=i;
  410. while (cnt-->0)
  411. {
  412. Song *thissong = (Song *)m_songs_sorted->Get(i);
  413. char tmp[128];
  414. char *name=0;
  415. switch (g_sortcol)
  416. {
  417. case COL_ARTIST: name=thissong->artist; break;
  418. case COL_TITLE: name=thissong->title; break;
  419. case COL_ALBUM: name=thissong->album; break;
  420. case COL_LENGTH:
  421. wsprintf(tmp,"%d:%02d",thissong->songlen/60,(thissong->songlen)%60); name=tmp;
  422. break;
  423. case COL_TRACK: if (thissong->track_nr > 0 && thissong->track_nr < 1000) { wsprintf(tmp,"%d",thissong->track_nr); name=tmp; } break;
  424. case COL_GENRE: name=thissong->genre; break;
  425. case COL_YEAR: if (thissong->year < 5000 && thissong->year > 0) { wsprintf(tmp,"%d",thissong->year); name=tmp; } break;
  426. case COL_FILENAME: name=thissong->filename; break;
  427. }
  428. if (!name) name="";
  429. else SKIP_THE_AND_WHITESPACE(name)
  430. if (t->lvfi.flags & (4|LVFI_PARTIAL))
  431. {
  432. if (!_strnicmp(name,t->lvfi.psz,strlen(t->lvfi.psz)))
  433. {
  434. SetWindowLong(hwndDlg,DWL_MSGRESULT,i);
  435. return 1;
  436. }
  437. }
  438. else if (t->lvfi.flags & LVFI_STRING)
  439. {
  440. if (!_stricmp(name,t->lvfi.psz))
  441. {
  442. SetWindowLong(hwndDlg,DWL_MSGRESULT,i);
  443. return 1;
  444. }
  445. }
  446. else
  447. {
  448. SetWindowLong(hwndDlg,DWL_MSGRESULT,-1);
  449. return 1;
  450. }
  451. if (++i == m_songs_sorted->GetSize()) i=0;
  452. }
  453. SetWindowLong(hwndDlg,DWL_MSGRESULT,-1);
  454. return 1;
  455. }
  456. else if (l->code == LVN_GETDISPINFO)
  457. {
  458. NMLVDISPINFO *lpdi = (NMLVDISPINFO*) lParam;
  459. int item=lpdi->item.iItem;
  460. if (item < 0 || item >= m_songs_sorted->GetSize()) return 0;
  461. Song *thissong = (Song *)m_songs_sorted->Get(item);
  462. if (lpdi->item.mask & (LVIF_TEXT|/*LVIF_IMAGE*/0)) // we can always do images too :)
  463. {
  464. if (lpdi->item.mask & LVIF_TEXT)
  465. {
  466. char tmpbuf[128];
  467. char *nameptr=0;
  468. switch (lpdi->item.iSubItem)
  469. {
  470. case COL_ARTIST: nameptr=thissong->artist; break;
  471. case COL_TITLE: nameptr=thissong->title; break;
  472. case COL_ALBUM: nameptr=thissong->album; break;
  473. case COL_LENGTH:
  474. wsprintf(tmpbuf,"%d:%02d",thissong->songlen/60,(thissong->songlen)%60); nameptr=tmpbuf;
  475. break;
  476. case COL_TRACK: if (thissong->track_nr > 0 && thissong->track_nr < 1000) { wsprintf(tmpbuf,"%d",thissong->track_nr); nameptr=tmpbuf; } break;
  477. case COL_GENRE: nameptr=thissong->genre; break;
  478. case COL_YEAR: if (thissong->year>0 && thissong->year<5000) { wsprintf(tmpbuf,"%d",thissong->year); nameptr=tmpbuf; } break;
  479. case COL_FILENAME: nameptr=thissong->filename; break;
  480. }
  481. if (nameptr) lstrcpyn(lpdi->item.pszText,nameptr,lpdi->item.cchTextMax);
  482. else lpdi->item.pszText[0]=0;
  483. }
  484. // if(lpdi->item.mask & LVIF_IMAGE)
  485. } // bother
  486. return 0;
  487. } // LVN_GETDISPINFO
  488. else if (l->code == LVN_COLUMNCLICK)
  489. {
  490. NMLISTVIEW *p=(NMLISTVIEW*)lParam;
  491. if (p->iSubItem == g_sortcol) g_sortdir=!g_sortdir;
  492. else g_sortcol=p->iSubItem;
  493. char str[32];
  494. sprintf(str,"%d",g_sortdir);
  495. WritePrivateProfileString(CONFIG_SEC,"sortdir",str,conf_file);
  496. sprintf(str,"%d",g_sortcol);
  497. WritePrivateProfileString(CONFIG_SEC,"sortcol",str,conf_file);
  498. sortResults();
  499. }
  500. }
  501. }
  502. break;
  503. case WM_COMMAND:
  504. switch(LOWORD(wParam))
  505. {
  506. case IDC_BUTTON_CONFIG:
  507. config(hwndDlg);
  508. break;
  509. case IDC_QUICKSEARCH:
  510. if (HIWORD(wParam) == EN_CHANGE)
  511. {
  512. KillTimer(hwndDlg,500);
  513. SetTimer(hwndDlg,500,150,NULL);
  514. }
  515. break;
  516. }
  517. break;
  518. case WM_TIMER:
  519. if (wParam == 500)
  520. {
  521. KillTimer(hwndDlg,500);
  522. char buf[256];
  523. GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf));
  524. buf[255]=0;
  525. WritePrivateProfileString(CONFIG_SEC,"lastfilter",buf,conf_file);
  526. updateList();
  527. }
  528. else if (wParam == 32)
  529. {
  530. KillTimer(hwndDlg,32);
  531. if (!m_songs.GetSize()) loadSongList();
  532. char buf[256];
  533. GetPrivateProfileString(CONFIG_SEC,"lastfilter","",buf,sizeof(buf),conf_file);
  534. SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf); // automatically updates the list via EN_CHANGE
  535. }
  536. break;
  537. case WM_SIZE:
  538. #if 0 // BP:
  539. if (wParam != SIZE_MINIMIZED)
  540. {
  541. if (cr_resize) cr_resize(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0]));
  542. }
  543. #endif
  544. break;
  545. case WM_PAINT:
  546. {
  547. if (wad_DrawChildWindowBorders)
  548. {
  549. int tab[] = { IDC_QUICKSEARCH|DCW_SUNKENBORDER, IDC_LIST|DCW_SUNKENBORDER};
  550. wad_DrawChildWindowBorders(hwndDlg,tab,2);
  551. }
  552. }
  553. return 0;
  554. case WM_DESTROY:
  555. //clearSongList();
  556. m_hwnd=NULL;
  557. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,m_skinlistview_handle,ML_IPC_UNSKIN_LISTVIEW);
  558. return 0;
  559. case WM_ML_CHILDIPC:
  560. if (lParam == ML_CHILDIPC_DROPITEM && wParam)
  561. {
  562. mlDropItemStruct *t=(mlDropItemStruct*)wParam;
  563. if (t->type == ML_TYPE_ITEMRECORDLIST) t->result=1;
  564. if (t->data)
  565. {
  566. if (t->type == ML_TYPE_ITEMRECORDLIST) // we got a drag&drop to our window, hot!
  567. {
  568. addItemListToSongs((itemRecordList*)t->data);
  569. updateList();
  570. }
  571. }
  572. }
  573. return 0;
  574. case WM_LBUTTONUP:
  575. if (GetCapture() == hwndDlg)
  576. {
  577. ReleaseCapture();
  578. POINT p;
  579. p.x=GET_X_LPARAM(lParam);
  580. p.y=GET_Y_LPARAM(lParam);
  581. ClientToScreen(hwndDlg,&p);
  582. HWND h=WindowFromPoint(p);
  583. if (h != hwndDlg && !IsChild(hwndDlg,h))
  584. {
  585. mlDropItemStruct m={ML_TYPE_ITEMRECORDLIST,NULL,0};
  586. m.p=p;
  587. m.flags=ML_HANDLEDRAG_FLAG_NOCURSOR;
  588. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
  589. if (m.result>0)
  590. {
  591. itemRecordList o={0,};
  592. SongsToItemList(&o,0);
  593. if (o.Size)
  594. {
  595. //fill in this itemCacheObject if you want to provide drag&drop out of the window
  596. m.flags=0;
  597. m.result=0;
  598. m.data=(void*)&o;
  599. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
  600. }
  601. free(o.Items);
  602. }
  603. }
  604. }
  605. break;
  606. case WM_MOUSEMOVE:
  607. if (GetCapture()==hwndDlg)
  608. {
  609. POINT p;
  610. p.x=GET_X_LPARAM(lParam);
  611. p.y=GET_Y_LPARAM(lParam);
  612. ClientToScreen(hwndDlg,&p);
  613. mlDropItemStruct m={ML_TYPE_ITEMRECORDLIST,NULL,0};
  614. m.p=p;
  615. HWND h=WindowFromPoint(p);
  616. if (!h || h == hwndDlg || IsChild(hwndDlg,h))
  617. {
  618. SetCursor(LoadCursor(NULL,IDC_NO));
  619. }
  620. else
  621. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
  622. }
  623. break;
  624. }
  625. return 0;
  626. }
  627. static BOOL CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  628. {
  629. switch (uMsg)
  630. {
  631. case WM_INITDIALOG:
  632. return 0;
  633. case WM_COMMAND:
  634. switch (LOWORD(wParam))
  635. {
  636. case IDOK:
  637. // save combo box
  638. case IDCANCEL:
  639. EndDialog(hwndDlg,LOWORD(wParam) == IDOK);
  640. break;
  641. }
  642. return 0;
  643. }
  644. return 0;
  645. }
  646. static void config(HWND parent)
  647. {
  648. DialogBox(plugin.hDllInstance,MAKEINTRESOURCE(IDD_CONFIG),parent,config_dlgproc);
  649. }
  650. int onTreeItemClick(int param, int action, HWND hwndParent) // if param is not yours, return 0
  651. {
  652. if (action == ML_ACTION_RCLICK)
  653. {
  654. POINT p;
  655. GetCursorPos(&p);
  656. int r=TrackPopupMenu(GetSubMenu(m_context_menus,0),TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,p.x,p.y,0,hwndParent,NULL);
  657. switch (r)
  658. {
  659. case ID_ABOUT:
  660. MessageBox(hwndParent,"ml_ex!!!","About ml_ex!!!",MB_OK);
  661. break;
  662. case ID_CONFIG:
  663. config(hwndParent);
  664. break;
  665. }
  666. }
  667. return 1;
  668. }
  669. int onTreeItemDropTarget(int param, int type, void *obj)
  670. {
  671. if (type != ML_TYPE_ITEMRECORDLIST) return -1;
  672. if (!obj) return 1;
  673. // do somethihng with the itemCache object. do not free it however, since the caller owns it
  674. addItemListToSongs((itemRecordList*)obj);
  675. updateList();
  676. return 1;
  677. }
  678. int onTreeItemDrag(int param, POINT p, int *type)
  679. {
  680. HWND h=WindowFromPoint(p);
  681. if (h && (h == m_hwnd || IsChild(m_hwnd,h))) return -1; // prevent from dropping into ourselves
  682. // if we wanted to be able to drag&drop our tree item to other people, we'd
  683. // return 1 and set type to ML_TYPE_ITEMRECORDLIST or ML_TYPE_FILENAMES etc.
  684. // *type = ML_TYPE_ITEMRECORDLIST;
  685. return -1;
  686. }
  687. int onTreeItemDrop(int param, POINT p) // you should send the appropriate ML_IPC_HANDLEDROP if you support it
  688. {
  689. HWND h=WindowFromPoint(p);
  690. if (h && (h == m_hwnd || IsChild(m_hwnd,h))) return -1; // prevent from dropping into ourselves
  691. // if we wanted to be able to drag&drop our tree item to other people, we'd
  692. // create an itemCacheObject or a doublenull terminated list (depending on what we want),
  693. // and send it back to the media library so it can route it to the appropriate destination:
  694. //
  695. // itemCacheObject o={0,};
  696. // fillInMyObject(&o);
  697. // mlDropItemStruct m={0,};
  698. // m.type = ML_TYPE_ITEMRECORDLIST;
  699. // m.data = (void*)&o;
  700. // m.p=p;
  701. // SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
  702. // freeMyObject(&o);
  703. // or this:
  704. itemRecordList o={0,};
  705. SongsToItemList(&o,1);
  706. if (o.Size)
  707. {
  708. mlDropItemStruct m={0,};
  709. m.type = ML_TYPE_ITEMRECORDLIST;
  710. m.data = (void*)&o;
  711. m.p=p;
  712. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
  713. }
  714. free(o.Items);
  715. return 1;
  716. }
  717. int PluginMessageProc(int message_type, int param1, int param2, int param3)
  718. {
  719. // check for any global messages here
  720. if (message_type >= ML_MSG_TREE_BEGIN && message_type <= ML_MSG_TREE_END)
  721. {
  722. if (param1 != myParam) return 0;
  723. // local messages for a tree item
  724. switch (message_type)
  725. {
  726. case ML_MSG_TREE_ONCREATEVIEW:
  727. return (int)CreateDialog(plugin.hDllInstance,MAKEINTRESOURCE(IDD_VIEW_EX),(HWND)param2,dlgproc);
  728. case ML_MSG_TREE_ONCLICK:
  729. return onTreeItemClick(param1,param2,(HWND)param3);
  730. case ML_MSG_TREE_ONDROPTARGET:
  731. return onTreeItemDropTarget(param1,param2,(void*)param3);
  732. case ML_MSG_TREE_ONDRAG:
  733. return onTreeItemDrag(param1,*(POINT*)param2,(int*)param3);
  734. case ML_MSG_TREE_ONDROP:
  735. return onTreeItemDrop(param1,*(POINT*)param2);
  736. }
  737. }
  738. else if (message_type == ML_MSG_ONSENDTOBUILD)
  739. {
  740. if (param1 == ML_TYPE_ITEMRECORDLIST)
  741. {
  742. mlAddToSendToStruct s;
  743. s.context=param2;
  744. s.desc="ItemCacheEx";
  745. s.user32=(int)PluginMessageProc;
  746. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_ADDTOSENDTO);
  747. }
  748. }
  749. else if (message_type == ML_MSG_ONSENDTOSELECT)
  750. {
  751. if (param1 == ML_TYPE_ITEMRECORDLIST && param2 && param3 == (int)PluginMessageProc)
  752. {
  753. addItemListToSongs((itemRecordList*)param2);
  754. updateList();
  755. return 1;
  756. }
  757. }
  758. return 0;
  759. }
  760. winampMediaLibraryPlugin plugin =
  761. {
  762. MLHDR_VER,
  763. "ml_ex v0.1",
  764. init,
  765. quit,
  766. PluginMessageProc,
  767. };
  768. extern "C" {
  769. __declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
  770. {
  771. return &plugin;
  772. }
  773. };