infobox.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  1. #include "main.h"
  2. #include "api__in_vorbis.h"
  3. #include "genres.h"
  4. #include <commctrl.h>
  5. #include "../Agave/Language/api_language.h"
  6. #include "../nu/AutoWide.h"
  7. #include "../nu/AutoChar.h"
  8. #include "resource.h"
  9. #include <strsafe.h>
  10. extern In_Module mod;
  11. /* old PP info box. still used for streams */
  12. extern CfgFont cfg_font;
  13. extern CfgInt cfg_modeless,cfg_remember_infosize;
  14. static CfgInt
  15. cfg_hide_special_fields("hide_special_fields",1),
  16. cfg_adv_info("adv_info",0),
  17. cfg_infobox_sx("infobox_sx",0),
  18. cfg_infobox_sy("infobox_sy",0),
  19. cfg_infobox_x("infobox_x",0),
  20. cfg_infobox_y("infobox_y",0);
  21. void SetDlgItemTextWrap(HWND w,UINT id,wchar_t * tx)
  22. {
  23. SetDlgItemTextW(w,id,tx);
  24. }
  25. typedef struct
  26. {
  27. UINT id;
  28. wchar_t * name;
  29. } STD_TAG_ITEM;
  30. #define N_STD_TAGZ 7
  31. extern BOOL cfg_adv_warn;
  32. static const STD_TAG_ITEM std_tagz[N_STD_TAGZ]=
  33. {
  34. {IDC_TITLE,L"TITLE"},
  35. {IDC_ARTIST,L"ARTIST"},
  36. {IDC_ALBUM,L"ALBUM"},
  37. {IDC_GENRE,L"GENRE"},
  38. {IDC_DATE,L"DATE"},
  39. {IDC_COMMENT,L"COMMENT"},
  40. {IDC_TRACK,L"TRACKNUMBER"},
  41. };
  42. const wchar_t * special_fields[]={L"RG_PEAK",L"RG_RADIO",L"RG_AUDIOPHILE",L"LWING_GAIN",L"REPLAYGAIN_ALBUM_GAIN",L"REPLAYGAIN_ALBUM_PEAK",L"REPLAYGAIN_TRACK_GAIN",L"REPLAYGAIN_TRACK_PEAK"};
  43. #define N_SPECIAL_FIELDS (sizeof(special_fields)/sizeof(special_fields[0]))
  44. typedef struct tagTAG
  45. {
  46. tagTAG * next;
  47. wchar_t * name;
  48. wchar_t * value;
  49. } TAG;
  50. typedef struct
  51. {
  52. wchar_t *name,*value;
  53. } TAGDESC;
  54. class OggTagData
  55. {
  56. public:
  57. TAG * tags;
  58. TAG ** last;
  59. TAG * newtag()
  60. {
  61. TAG * t=new TAG;
  62. *last=t;
  63. last=&t->next;
  64. t->next=0;
  65. return t;
  66. }
  67. OggTagData()
  68. {
  69. tags=0;
  70. last=&tags;
  71. }
  72. String vendor;
  73. OggTagData(vorbis_comment * vc) : vendor(vc->vendor)
  74. {
  75. tags=0;
  76. last=&tags;
  77. int n;
  78. for(n=0;n<vc->comments;n++)
  79. {
  80. TAG * t=newtag();
  81. char * c=vc->user_comments[n];
  82. char * p=strchr(c,'=');
  83. if (p)
  84. {
  85. int size = MultiByteToWideChar(CP_UTF8, 0, c, (int)(p-c), 0,0);
  86. t->name=(wchar_t*)malloc((size+1)*sizeof(wchar_t));
  87. MultiByteToWideChar(CP_UTF8, 0, c, (int)(p-c), t->name, size);
  88. t->name[size]=0;
  89. p++;
  90. }
  91. else
  92. {
  93. t->name=_wcsdup(L"COMMENT");
  94. p=c;
  95. }
  96. int size = MultiByteToWideChar(CP_UTF8, 0, p, -1, 0,0);
  97. t->value=(wchar_t*)malloc((size)*sizeof(wchar_t));
  98. MultiByteToWideChar(CP_UTF8, 0, p, -1, t->value, size);
  99. }
  100. }
  101. void Clear()
  102. {
  103. TAG * t=tags;
  104. while(t)
  105. {
  106. TAG * t1=t->next;
  107. free(t->name);
  108. free(t->value);
  109. delete t;
  110. t=t1;
  111. }
  112. tags=0;
  113. last=&tags;
  114. }
  115. void AddTag(const wchar_t * name,const wchar_t * value)
  116. {
  117. TAG * t=newtag();
  118. t->name=_wcsdup(name);
  119. t->value=_wcsdup(value);
  120. }
  121. ~OggTagData()
  122. {
  123. Clear();
  124. }
  125. };
  126. static void SetWindowRect(HWND w,RECT * r)
  127. {
  128. SetWindowPos(w,0,r->left,r->top,r->right-r->left,r->bottom-r->top,SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOACTIVATE);
  129. }
  130. class DlgBase
  131. {
  132. protected:
  133. bool DieOnDestroyWindow,is_modeless,is_modal_ex,modal_ex_quit;
  134. int modal_ex_quit_val;
  135. void endDialog(int x)
  136. {
  137. if (is_modeless) DestroyWindow(wnd);
  138. else if (is_modal_ex)
  139. {
  140. modal_ex_quit=1;
  141. modal_ex_quit_val=x;
  142. DestroyWindow(wnd);
  143. }
  144. else EndDialog(wnd,x);
  145. }
  146. void _do_size_x(RECT * r,UINT id,UINT wx,UINT min_x)
  147. {
  148. RECT r1={r->left,r->top,(LONG)(wx-min_x)+r->right,r->bottom};
  149. SetWindowRect(GetDlgItem(wnd,id),&r1);
  150. }
  151. void _do_size_xy(RECT * r,UINT id,UINT wx,UINT wy,UINT min_x,UINT min_y)
  152. {
  153. RECT r1={r->left,r->top,(LONG)(wx-min_x)+r->right,(LONG)(wy-min_y)+r->bottom};
  154. SetWindowRect(GetDlgItem(wnd,id),&r1);
  155. }
  156. void _do_align_x_size_y(RECT * r,UINT id,UINT wx,UINT wy,UINT min_x,UINT min_y)
  157. {
  158. RECT r1={ (LONG)(wx-min_x)+r->left,r->top,(LONG)(wx-min_x)+r->right,(LONG)(wy-min_y)+r->bottom};
  159. SetWindowRect(GetDlgItem(wnd,id),&r1);
  160. }
  161. void _do_align_x(RECT * r,UINT id,UINT wx,UINT min_x)
  162. {
  163. RECT r1={ (LONG)(wx-min_x+r)->left,(LONG)r->top,(LONG)(wx-min_x+r)->right,(LONG)r->bottom};
  164. SetWindowRect(GetDlgItem(wnd,id),&r1);
  165. }
  166. void _do_align_xy(RECT * r,UINT id,UINT wx,UINT wy,UINT min_x,UINT min_y)
  167. {
  168. RECT r1={(LONG)(wx-min_x+r)->left,(LONG)(wy-min_y+r)->top,(LONG)(wx- min_x+r)->right,(LONG)(wy-min_y+r)->bottom};
  169. SetWindowRect(GetDlgItem(wnd,id),&r1);
  170. }
  171. #define do_size_x(id,r) _do_size_x(r,id,sx,min_size_x)
  172. #define do_size_xy(id,r) _do_size_xy(r,id,sx,sy,min_size_x,min_size_y)
  173. #define do_align_x_size_y(id,r) _do_align_x_size_y(r,id,sx,sy,min_size_x,min_size_y)
  174. #define do_align_xy(id,r) _do_align_xy(r,id,sx,sy,min_size_x,min_size_y)
  175. #define do_align_x(id,r) _do_align_x(r,id,sx,min_size_x)
  176. HWND wnd;
  177. UINT min_size_x,min_size_y;
  178. UINT min_size_x_w,min_size_y_w;
  179. void do_sizing(UINT wp,RECT * r)
  180. {
  181. UINT dx,dy;
  182. dx=r->right-r->left;
  183. dy=r->bottom-r->top;
  184. if (dx<min_size_x_w)
  185. {
  186. switch(wp)
  187. {
  188. case WMSZ_BOTTOMLEFT:
  189. case WMSZ_LEFT:
  190. case WMSZ_TOPLEFT:
  191. r->left=r->right-min_size_x_w;
  192. break;
  193. case WMSZ_BOTTOMRIGHT:
  194. case WMSZ_RIGHT:
  195. case WMSZ_TOPRIGHT:
  196. r->right=r->left+min_size_x_w;
  197. break;
  198. }
  199. }
  200. if (dy<min_size_y_w)
  201. {
  202. switch(wp)
  203. {
  204. case WMSZ_BOTTOMLEFT:
  205. case WMSZ_BOTTOM:
  206. case WMSZ_BOTTOMRIGHT:
  207. r->bottom=r->top+min_size_y_w;
  208. break;
  209. case WMSZ_TOPLEFT:
  210. case WMSZ_TOP:
  211. case WMSZ_TOPRIGHT:
  212. r->top=r->bottom-min_size_y_w;
  213. break;
  214. }
  215. }
  216. }
  217. void MakeComboEdit(UINT id,DWORD s)
  218. {
  219. HWND w=GetDlgItem(wnd,id);
  220. RECT r;
  221. GetChildRect(id,r);
  222. DestroyWindow(w);
  223. CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", 0, WS_CHILD | s, r.left - 1, r.top - 1, r.right - r.left, r.bottom - r.top, wnd, (HMENU)id, 0, 0 );
  224. }
  225. void GetChildRect(UINT id,RECT& child)
  226. {
  227. RECT r_parent,r_child;
  228. GetWindowRect(wnd,&r_parent);
  229. GetWindowRect(GetDlgItem(wnd,id),&r_child);
  230. int dx=r_parent.left;
  231. int dy=r_parent.top;
  232. if (!(GetWindowLong(wnd,GWL_STYLE)&WS_CHILD))
  233. {
  234. dy+=GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYDLGFRAME);
  235. dx+=GetSystemMetrics(SM_CXDLGFRAME);
  236. }
  237. child.left=r_child.left-dx;
  238. child.right=r_child.right-dx;
  239. child.top=r_child.top-dy;
  240. child.bottom=r_child.bottom-dy;
  241. }
  242. virtual BOOL DlgProc(UINT msg,WPARAM wp,LPARAM lp) {return 0;};
  243. static BOOL CALLBACK TheDialogProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
  244. {
  245. DlgBase * p;
  246. if (msg==WM_INITDIALOG)
  247. {
  248. p=(DlgBase*)lp;
  249. #ifdef WIN64
  250. SetWindowLong(wnd, DWLP_USER, (LONG)lp);
  251. #else
  252. SetWindowLong(wnd, DWL_USER, lp);
  253. #endif
  254. p->wnd=wnd;
  255. RECT r;
  256. GetClientRect(wnd,&r);
  257. p->min_size_x=r.right;
  258. p->min_size_y=r.bottom;
  259. GetWindowRect(wnd,&r);
  260. p->min_size_x_w=r.right-r.left;
  261. p->min_size_y_w=r.bottom-r.top;
  262. }
  263. #ifdef WIN64
  264. else p = (DlgBase*)GetWindowLong(wnd, DWLP_USER);
  265. #else
  266. else p = (DlgBase*)GetWindowLong(wnd, DWL_USER);
  267. #endif
  268. BOOL rv=0;
  269. if (p)
  270. {
  271. rv=p->DlgProc(msg,wp,lp);
  272. if (msg==WM_DESTROY)
  273. {
  274. p->wnd=0;
  275. if (p->DieOnDestroyWindow)
  276. {
  277. delete p;
  278. #ifdef WIN64
  279. SetWindowLong(wnd, DWLP_USER, 0);
  280. #else
  281. SetWindowLong(wnd, DWL_USER, 0);
  282. #endif
  283. }
  284. }
  285. }
  286. return rv;
  287. }
  288. HWND myCreateDialog(UINT id,HWND parent)
  289. {
  290. DieOnDestroyWindow=1;
  291. is_modeless=1;
  292. is_modal_ex=0;
  293. return WASABI_API_CREATEDIALOGPARAMW(id,parent,TheDialogProc,(LPARAM)this);
  294. }
  295. virtual void myProcessMessage(MSG * msg)
  296. {
  297. if (!IsDialogMessage(wnd,msg))
  298. {
  299. TranslateMessage(msg);
  300. DispatchMessage(msg);
  301. }
  302. }
  303. int myDialogBoxEx(UINT id,HWND parent)
  304. {
  305. DieOnDestroyWindow=0;
  306. is_modeless=0;
  307. is_modal_ex=1;
  308. modal_ex_quit=0;
  309. modal_ex_quit_val=-1;
  310. WASABI_API_CREATEDIALOGPARAMW(id,parent,TheDialogProc,(LPARAM)this);
  311. if (wnd)
  312. {
  313. BOOL b=IsWindowEnabled(parent);
  314. if (b) EnableWindow(parent,0);
  315. MSG msg;
  316. while(!modal_ex_quit && GetMessage(&msg,0,0,0))
  317. {
  318. myProcessMessage(&msg);
  319. }
  320. if (wnd)
  321. {
  322. DestroyWindow(wnd);
  323. wnd=0;
  324. }
  325. if (b) EnableWindow(parent,1);
  326. SetActiveWindow(parent);
  327. }
  328. return modal_ex_quit_val;
  329. }
  330. int myDialogBox(UINT id,HWND parent)
  331. {
  332. DieOnDestroyWindow=0;
  333. is_modeless=0;
  334. is_modal_ex=0;
  335. return (int)WASABI_API_DIALOGBOXPARAMW(id,parent,TheDialogProc,(LPARAM)this);
  336. }
  337. DlgBase()
  338. {
  339. wnd=0;
  340. DieOnDestroyWindow=0;
  341. is_modeless=0;
  342. is_modal_ex=0;
  343. modal_ex_quit=0;
  344. modal_ex_quit_val=0;
  345. min_size_x=min_size_y=min_size_x_w=min_size_y_w=0;
  346. }
  347. virtual ~DlgBase() {DieOnDestroyWindow=0;if (wnd) DestroyWindow(wnd);}
  348. public:
  349. BOOL isDialogMessage(MSG * m) {return wnd ? IsDialogMessage(wnd,m) : 0;}
  350. };
  351. static char tags_file[]="tags.txt";
  352. static wchar_t genres_file[] = L"genres.txt";
  353. class /*_declspec(novtable) */InfoDlgPanel : public DlgBase
  354. {
  355. protected:
  356. HFONT font;
  357. HWND list;
  358. RECT info_list;
  359. OggTagData hidden;
  360. InfoDlgPanel(UINT id,HWND parent,HFONT foo)
  361. {
  362. font=foo;
  363. myCreateDialog(id,parent);
  364. //SetWindowLong(wnd,GWL_STYLE,GetWindowLong(wnd,GWL_STYLE)|WS_TABSTOP);
  365. list=GetDlgItem(wnd,IDC_LIST);
  366. SendMessage(list,WM_SETFONT,(WPARAM)font,0);
  367. GetChildRect(IDC_LIST,info_list);
  368. }
  369. int lb_addstring(TAGDESC * tag,int idx=-1)
  370. {
  371. StringW tmp;
  372. tmp+=tag->name;
  373. tmp+=L"=";
  374. tmp+=tag->value;
  375. const WCHAR * p=(const WCHAR*)tmp;
  376. const WCHAR * foo=wcsstr(p,L"\x0d\x0a");
  377. if (foo)
  378. {
  379. tmp.Truncate((UINT)(foo-p));
  380. tmp.AddString(L" (...)");
  381. }
  382. int rv=
  383. (int)SendMessageW(list,
  384. idx<0 ? LB_ADDSTRING : LB_INSERTSTRING,
  385. idx<0 ? 0 : idx,
  386. ((LPARAM)(const WCHAR*)tmp)
  387. );
  388. if (rv>=0) SendMessage(list,LB_SETITEMDATA,rv,(LPARAM)tag);
  389. else
  390. {
  391. free(tag->name);
  392. free(tag->value);
  393. delete tag;
  394. }
  395. return rv;
  396. }
  397. virtual void OnUpdateRect(UINT sx,UINT sy)
  398. {//WM_SIZE-ish
  399. do_size_xy(IDC_LIST,&info_list);
  400. }
  401. virtual BOOL DlgProc(UINT msg,WPARAM wp,LPARAM lp)
  402. {
  403. switch(msg)
  404. {
  405. case WM_DESTROY:
  406. lb_clear();
  407. list=0;
  408. break;
  409. case WM_COMMAND:
  410. switch(wp)
  411. {
  412. case IDOK:
  413. case IDCANCEL:
  414. SendMessage(GetParent(wnd),msg,wp,lp);
  415. break;
  416. }
  417. break;
  418. // case WM_INITDIALOG:
  419. // return 1;
  420. }
  421. return 0;
  422. }
  423. void lb_clear()
  424. {
  425. if (!list) return;
  426. int num=(int)SendMessage(list,LB_GETCOUNT,0,0);
  427. while(num>0)
  428. {
  429. TAGDESC * l=(TAGDESC*)SendMessage(list,LB_GETITEMDATA,0,0);
  430. if (l)
  431. {
  432. free(l->name);
  433. free(l->value);
  434. delete l;
  435. }
  436. SendMessage(list,LB_DELETESTRING,0,0);
  437. num--;
  438. }
  439. }
  440. virtual void SetTag(wchar_t * name,wchar_t * value)
  441. {
  442. TAGDESC * l=new TAGDESC;
  443. l->name=_wcsdup(name);
  444. l->value=_wcsdup(value);
  445. lb_addstring(l);
  446. }
  447. public:
  448. virtual void Clear()
  449. {
  450. hidden.Clear();
  451. lb_clear();
  452. }
  453. void UpdateRect(RECT &r)
  454. {
  455. SetWindowPos(wnd,0,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
  456. RECT z;
  457. GetClientRect(wnd,&z);
  458. OnUpdateRect(z.right-z.left,z.bottom-z.top);
  459. }
  460. virtual void GetTags(OggTagData & tags)
  461. {
  462. if (!list) return;
  463. int num=(int)SendMessage(list,LB_GETCOUNT,0,0);
  464. int n;
  465. for(n=0;n<num;n++)
  466. {
  467. TAGDESC * l=(TAGDESC*)SendMessage(list,LB_GETITEMDATA,n,0);
  468. tags.AddTag(l->name,l->value);
  469. }
  470. TAG * t=hidden.tags;
  471. while(t)
  472. {
  473. tags.AddTag(t->name,t->value);
  474. t=t->next;
  475. }
  476. }
  477. void SetTags(OggTagData & tags,BOOL hidespec)
  478. {
  479. TAG * t=tags.tags;
  480. while(t)
  481. {
  482. bool hide=0;
  483. if (hidespec)
  484. {
  485. int n;
  486. for(n=0;n<N_SPECIAL_FIELDS;n++)
  487. {
  488. if (!_wcsicmp(t->name,special_fields[n]))
  489. {
  490. hidden.AddTag(t->name,t->value);
  491. hide=1;break;
  492. }
  493. }
  494. }
  495. if (!hide) SetTag(t->name,t->value);
  496. t=t->next;
  497. }
  498. }
  499. };
  500. class InfoDlgPanel_adv : public InfoDlgPanel
  501. {
  502. private:
  503. virtual void OnUpdateRect(UINT sx,UINT sy)
  504. {
  505. InfoDlgPanel::OnUpdateRect(sx,sy);
  506. }
  507. public:
  508. InfoDlgPanel_adv(HWND parent,HFONT foo) : InfoDlgPanel(IDD_INFO_PANEL_ADVANCED,parent,foo)
  509. {
  510. }
  511. };
  512. class InfoDlgPanel_simple : public InfoDlgPanel
  513. {
  514. private:
  515. RECT info_static_std,info_title,info_artist,info_album,info_track,info_genre,info_comment,info_static_track,info_static_tags;
  516. wchar_t *tag_bk[N_STD_TAGZ];
  517. BOOL STFU;
  518. protected:
  519. virtual void OnUpdateRect(UINT sx,UINT sy)
  520. {
  521. do_size_x(IDC_STATIC_STD,&info_static_std);
  522. do_size_x(IDC_TITLE,&info_title);
  523. do_size_x(IDC_ARTIST,&info_artist);
  524. do_size_x(IDC_ALBUM,&info_album);
  525. do_align_x(IDC_TRACK,&info_track);
  526. do_size_x(IDC_GENRE,&info_genre);
  527. do_size_x(IDC_COMMENT,&info_comment);
  528. do_align_x(IDC_STATIC_TRACK,&info_static_track);
  529. do_size_xy(IDC_STATIC_TAGS,&info_static_tags);
  530. InfoDlgPanel::OnUpdateRect(sx,sy);
  531. }
  532. virtual BOOL DlgProc(UINT msg,WPARAM wp,LPARAM lp)
  533. {
  534. switch(msg)
  535. {
  536. case WM_COMMAND:
  537. if (!STFU && (HIWORD(wp)==EN_CHANGE || HIWORD(wp)==CBN_EDITCHANGE || HIWORD(wp)==CBN_SELCHANGE))
  538. {
  539. UINT n;
  540. for(n=0;n<N_STD_TAGZ;n++)
  541. {
  542. if (LOWORD(wp)==std_tagz[n].id)
  543. {
  544. if (tag_bk[n]) {free(tag_bk[n]);tag_bk[n]=0;}
  545. break;
  546. }
  547. }
  548. }
  549. break;
  550. }
  551. return InfoDlgPanel::DlgProc(msg,wp,lp);
  552. }
  553. public:
  554. virtual void Clear()
  555. {
  556. int n;
  557. for(n=0;n<N_STD_TAGZ;n++)
  558. {
  559. if (tag_bk[n])
  560. {
  561. free(tag_bk[n]);
  562. tag_bk[n]=0;
  563. }
  564. SetDlgItemText(wnd,std_tagz[n].id,L"");
  565. }
  566. InfoDlgPanel::Clear();
  567. }
  568. ~InfoDlgPanel_simple()
  569. {
  570. UINT n;
  571. for(n=0;n<N_STD_TAGZ;n++)
  572. {
  573. if (tag_bk[n]) free(tag_bk[n]);
  574. }
  575. }
  576. InfoDlgPanel_simple(HWND parent,HFONT foo) : InfoDlgPanel(IDD_INFO_PANEL_SIMPLE,parent,foo)
  577. {
  578. STFU=0;
  579. memset(tag_bk,0,sizeof(tag_bk));
  580. UINT n;
  581. MakeComboEdit(IDC_GENRE,ES_READONLY|ES_AUTOHSCROLL|WS_VISIBLE);
  582. for(n=0;n<N_STD_TAGZ;n++)
  583. {
  584. HWND w=GetDlgItem(wnd,std_tagz[n].id);
  585. SendMessage(w,WM_SETFONT,(WPARAM)font,0);
  586. SendMessage(w,EM_SETREADONLY,1,0);
  587. }
  588. GetChildRect(IDC_STATIC_STD,info_static_std);
  589. GetChildRect(IDC_TITLE,info_title);
  590. GetChildRect(IDC_ARTIST,info_artist);
  591. GetChildRect(IDC_ALBUM,info_album);
  592. GetChildRect(IDC_TRACK,info_track);
  593. GetChildRect(IDC_GENRE,info_genre);
  594. GetChildRect(IDC_COMMENT,info_comment);
  595. GetChildRect(IDC_STATIC_TRACK,info_static_track);
  596. GetChildRect(IDC_STATIC_TAGS,info_static_tags);
  597. genres_read(GetDlgItem(wnd,IDC_GENRE), genres_file);
  598. }
  599. virtual void GetTags(OggTagData & tags)
  600. {
  601. genres_write(GetDlgItem(wnd,IDC_GENRE),genres_file);
  602. UINT n;
  603. for(n=0;n<N_STD_TAGZ;n++)
  604. {
  605. if (tag_bk[n])
  606. {
  607. tags.AddTag(std_tagz[n].name,tag_bk[n]);
  608. }
  609. else
  610. {
  611. StringW t;
  612. t.s_GetWindowText(GetDlgItem(wnd,std_tagz[n].id));
  613. if (t.Length()>0)
  614. {
  615. tags.AddTag(std_tagz[n].name,t);
  616. }
  617. }
  618. }
  619. InfoDlgPanel::GetTags(tags);
  620. }
  621. virtual void SetTag(wchar_t * name,wchar_t * value)
  622. {
  623. STFU=1;
  624. UINT n;
  625. for(n=0;n<N_STD_TAGZ;n++)
  626. {
  627. if (tag_bk[n]) continue;
  628. if (!_wcsicmp(name,std_tagz[n].name))
  629. {
  630. tag_bk[n]=_wcsdup(value);
  631. SetDlgItemTextWrap(wnd,std_tagz[n].id,value);
  632. STFU=0;
  633. return;
  634. }
  635. }
  636. STFU=0;
  637. InfoDlgPanel::SetTag(name,value);
  638. }
  639. };
  640. char * rstrcpy(char* s1,char* s2)
  641. {
  642. while(s2 && *s2) *(s1++)=*(s2++);
  643. return s1;
  644. }
  645. static void _inline print_misc(VorbisFile * _vf,int link,char * out,int len)
  646. {
  647. OggVorbis_File * vf=&_vf->vf;
  648. char* p=out, kbps_str[16] = {0};
  649. double t=ov_time_total(vf,link);
  650. vorbis_info * vi=ov_info(vf,link);
  651. vorbis_comment * vc=ov_comment(vf,link);
  652. if (!vi || !vc) {WASABI_API_LNGSTRING_BUF(IDS_FILE_ERROR,out,512);return;}
  653. StringCchPrintfA(kbps_str, 16, " %s\r\n", WASABI_API_LNGSTRING(IDS_KBPS));
  654. if (t>0)
  655. {
  656. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_LENGTH));
  657. int h=(int)(t/3600.0);
  658. if (h>0)
  659. {
  660. uitoa(h,p);
  661. while(p && *p) p++;
  662. *(p++)=':';
  663. }
  664. int m=(int)(t/60.0)%60;
  665. // if (m>0 || h>0)
  666. {
  667. sprintf(p,h>0 ? "%02u" : "%u",m);
  668. while(p && *p) p++;
  669. *(p++)=':';
  670. }
  671. int s=(int)t%60;
  672. //sprintf(p,(m>0 || h>0) ? "%02u" : "%u seconds",s);
  673. sprintf(p,"%02d",s);
  674. while(p && *p) p++;
  675. p=rstrcpy(p,"\r\n");
  676. // uitoa((int)(t*1000.0),p);
  677. // while(p && *p) p++;
  678. // p=rstrcpy(p," ms");
  679. UINT fs=_vf->FileSize();
  680. if (fs>0)
  681. {
  682. if (vf->links==1)
  683. {
  684. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_AVERAGE_BITRATE));
  685. uitoa((int)(((double)fs)/(t*125.0)),p);
  686. while(p && *p) p++;
  687. p=rstrcpy(p,kbps_str);
  688. }
  689. if (fs>0)
  690. {
  691. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_FILE_SIZE));
  692. UINT fs1=fs/1000000;
  693. UINT fs2=(fs/1000)%1000;
  694. UINT fs3=fs%1000;
  695. if (fs1) sprintf(p,"%u%03u%03u %s\r\n",fs1,fs2,fs3,WASABI_API_LNGSTRING(IDS_BYTES));
  696. else if (fs2) sprintf(p,"%u%03u %s\r\n",fs2,fs3,WASABI_API_LNGSTRING(IDS_BYTES));
  697. else sprintf(p,"%u %s\r\n",fs3,WASABI_API_LNGSTRING(IDS_BYTES));
  698. while(p && *p) p++;
  699. }
  700. }
  701. }
  702. if (vi->bitrate_nominal>0)
  703. {
  704. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_NOMINAL_BITRATE));
  705. uitoa(vi->bitrate_nominal/1000,p);
  706. while(p && *p) p++;
  707. p=rstrcpy(p,kbps_str);
  708. }
  709. if (vi->bitrate_lower>0)
  710. {
  711. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_MIN_BITRATE));
  712. uitoa(vi->bitrate_lower/1000,p);
  713. while(p && *p) p++;
  714. p=rstrcpy(p,kbps_str);
  715. }
  716. if (vi->bitrate_upper>0)
  717. {
  718. p=rstrcpy(p,WASABI_API_LNGSTRING(IDS_MAX_BITRATE));
  719. uitoa(vi->bitrate_upper/1000,p);
  720. while(p && *p) p++;
  721. p=rstrcpy(p,kbps_str);
  722. }
  723. char tmp[32] = {0}, tmp2[32] = {0}, tmp3[32] = {0}, tmp4[32] = {0}, tmp5[32] = {0}, tmp6[8] = {0};
  724. StringCchPrintfA(p,len, "%s : %u\r\n"
  725. "%s : %u %s\r\n"
  726. "%s : %u\r\n"
  727. "%s : %u\r\n"
  728. "%s : \r\n%s",
  729. WASABI_API_LNGSTRING_BUF(IDS_CHANNELS,tmp,32),vi->channels,
  730. WASABI_API_LNGSTRING_BUF(IDS_SAMPLING_RATE,tmp2,32),vi->rate,WASABI_API_LNGSTRING_BUF(IDS_HZ,tmp6,8),
  731. WASABI_API_LNGSTRING_BUF(IDS_SERIAL_NUMBER,tmp3,32),ov_serialnumber(vf,link),
  732. WASABI_API_LNGSTRING_BUF(IDS_VERSION,tmp4,32),vi->version,
  733. WASABI_API_LNGSTRING_BUF(IDS_VENDOR,tmp5,32),vc->vendor);
  734. }
  735. class InfoDlg : public DlgBase
  736. {
  737. private:
  738. InfoDlg * next;
  739. static InfoDlg* Instances;
  740. OggTagData **tags;
  741. char ** infos;
  742. int n_streams,cur_stream;
  743. StringW url;
  744. HFONT ui_font;
  745. BOOL is_adv;
  746. InfoDlgPanel* panel;
  747. RECT info_static_misc,info_misc,info_url,info_cancel,info_mode,info_static_cs,info_cs_next,info_cs_prev,info_hidespec;
  748. void calc_panel_rect(RECT &r)
  749. {
  750. RECT cr,cr1,cr2;
  751. GetClientRect(wnd,&cr);
  752. GetChildRect(IDC_STATIC_MISC,cr1);
  753. GetChildRect(IDC_URL,cr2);
  754. r.left=0;
  755. r.top=cr2.bottom+1;
  756. r.right=cr1.left-1;
  757. r.bottom=cr.bottom;
  758. }
  759. void do_size()
  760. {
  761. if (panel)
  762. {
  763. RECT r;
  764. calc_panel_rect(r);
  765. panel->UpdateRect(r);
  766. }
  767. }
  768. void do_panel(BOOL mode,int d_stream)
  769. {
  770. //if (panel && is_adv==mode && !d_stream) return;
  771. if (panel)
  772. {
  773. if (mode!=is_adv)
  774. {
  775. delete panel;
  776. panel=0;
  777. }
  778. else
  779. {
  780. panel->Clear();
  781. }
  782. }
  783. cur_stream+=d_stream;
  784. if (cur_stream<0) cur_stream=0;
  785. else if (cur_stream>=n_streams) cur_stream=n_streams-1;
  786. is_adv=mode;
  787. if (!panel)
  788. {
  789. panel = mode ? (InfoDlgPanel*) new InfoDlgPanel_adv(wnd,ui_font) : (InfoDlgPanel*) new InfoDlgPanel_simple(wnd,ui_font);
  790. do_size();
  791. }
  792. if (panel)
  793. {
  794. panel->SetTags(*tags[cur_stream],(BOOL)SendDlgItemMessage(wnd,IDC_HIDE_SPEC,BM_GETCHECK,0,0));
  795. }
  796. SetDlgItemText(wnd,IDC_MODE_TOGGLE,WASABI_API_LNGSTRINGW((is_adv ? IDS_TO_SIMPLE_MODE : IDS_TO_ADVANCED_MODE)));
  797. EnableWindow(GetDlgItem(wnd,IDC_PREV_STREAM),cur_stream>0);
  798. EnableWindow(GetDlgItem(wnd,IDC_NEXT_STREAM),cur_stream<n_streams-1);
  799. // TODO
  800. SetDlgItemTextA(wnd,IDC_MISC,infos[cur_stream]);
  801. }
  802. protected:
  803. virtual BOOL DlgProc(UINT msg,WPARAM wp,LPARAM lp)
  804. {
  805. switch(msg)
  806. {
  807. case WM_INITDIALOG:
  808. if (n_streams<=1)
  809. {
  810. ShowWindow(GetDlgItem(wnd,IDC_STATIC_CS),SW_HIDE);
  811. ShowWindow(GetDlgItem(wnd,IDC_PREV_STREAM),SW_HIDE);
  812. ShowWindow(GetDlgItem(wnd,IDC_NEXT_STREAM),SW_HIDE);
  813. }
  814. SendDlgItemMessage(wnd,IDC_HIDE_SPEC,BM_SETCHECK,cfg_hide_special_fields,0);
  815. do_panel(cfg_adv_info,0);
  816. url.s_SetDlgItemText(wnd,IDC_URL);
  817. GetChildRect(IDC_URL,info_url);
  818. GetChildRect(IDC_STATIC_MISC,info_static_misc);
  819. GetChildRect(IDC_MISC,info_misc);
  820. GetChildRect(IDCANCEL,info_cancel);
  821. GetChildRect(IDC_MODE_TOGGLE,info_mode);
  822. GetChildRect(IDC_STATIC_CS,info_static_cs);
  823. GetChildRect(IDC_NEXT_STREAM,info_cs_next);
  824. GetChildRect(IDC_PREV_STREAM,info_cs_prev);
  825. GetChildRect(IDC_HIDE_SPEC,info_hidespec);
  826. if (cfg_remember_infosize && cfg_infobox_sx>0 && cfg_infobox_sy>0)
  827. {
  828. int max_x=GetSystemMetrics(SM_CXSCREEN),max_y=GetSystemMetrics(SM_CYSCREEN);
  829. if (cfg_infobox_x<0) cfg_infobox_x=0;
  830. else if (cfg_infobox_x+cfg_infobox_sx>max_x) cfg_infobox_x=max_x-cfg_infobox_sx;
  831. if (cfg_infobox_y<0) cfg_infobox_y=0;
  832. else if (cfg_infobox_y+cfg_infobox_sy>max_y) cfg_infobox_y=max_y-cfg_infobox_sy;
  833. SetWindowPos(wnd,0,cfg_infobox_x,cfg_infobox_y,cfg_infobox_sx,cfg_infobox_sy,SWP_NOZORDER|SWP_NOACTIVATE);
  834. }
  835. StringPrintfW(WASABI_API_LNGSTRINGW(IDS_OGG_VORBIS_INFO),(const WCHAR*)StringF2T_W((const WCHAR*)url)).s_SetWindowText(wnd);
  836. return 1;
  837. case WM_SIZE:
  838. {
  839. UINT sx=LOWORD(lp),sy=HIWORD(lp);
  840. do_size_x(IDC_URL,&info_url);
  841. do_align_x(IDC_STATIC_MISC,&info_static_misc);
  842. do_align_x(IDC_MISC,&info_misc);
  843. do_align_xy(IDCANCEL,&info_cancel);
  844. do_align_xy(IDC_MODE_TOGGLE,&info_mode);
  845. do_align_xy(IDC_STATIC_CS,&info_static_cs);
  846. do_align_xy(IDC_PREV_STREAM,&info_cs_prev);
  847. do_align_xy(IDC_NEXT_STREAM,&info_cs_next);
  848. do_align_xy(IDC_HIDE_SPEC,&info_hidespec);
  849. }
  850. //RedrawWindow(wnd,0,0,RDW_INVALIDATE);
  851. do_size();
  852. break;
  853. case WM_SIZING:
  854. do_sizing((UINT)wp,(RECT*)lp);
  855. break;
  856. case WM_COMMAND:
  857. switch(wp)
  858. {
  859. case IDCANCEL:
  860. endDialog(0);
  861. break;
  862. case IDC_MODE_TOGGLE:
  863. do_panel(!is_adv,0);
  864. break;
  865. case IDC_PREV_STREAM:
  866. do_panel(is_adv,-1);
  867. break;
  868. case IDC_NEXT_STREAM:
  869. do_panel(is_adv,1);
  870. break;
  871. case IDC_HIDE_SPEC:
  872. cfg_hide_special_fields=(int)SendMessage((HWND)lp,BM_GETCHECK,0,0);
  873. do_panel(is_adv,0);
  874. break;
  875. }
  876. break;
  877. case WM_CLOSE:
  878. endDialog(0);
  879. break;
  880. case WM_DESTROY:
  881. if (!is_modeless)//fucko close
  882. {
  883. modal_ex_quit=1;
  884. }
  885. {
  886. RECT r;
  887. GetWindowRect(wnd,&r);
  888. cfg_infobox_sx=r.right-r.left;
  889. cfg_infobox_sy=r.bottom-r.top;
  890. cfg_infobox_x=r.left;
  891. cfg_infobox_y=r.top;
  892. }
  893. break;
  894. }
  895. return 0;
  896. }
  897. virtual void myProcessMessage(MSG * msg)
  898. {
  899. if (!panel || !panel->isDialogMessage(msg))
  900. {
  901. DlgBase::myProcessMessage(msg);
  902. }
  903. }
  904. public:
  905. InfoDlg(VorbisFile * _vf,const wchar_t * _url)
  906. : url(_url), is_adv(FALSE)
  907. {
  908. OggVorbis_File * vf=&_vf->vf;
  909. n_streams=vf->links;
  910. cur_stream=vf->current_link;
  911. tags=(OggTagData**)malloc(n_streams*sizeof(void*));
  912. int n;
  913. for(n=0;n<n_streams;n++) tags[n]=new OggTagData(ov_comment(vf,n));
  914. infos=(char**)malloc(sizeof(void*)*n_streams);
  915. for(n=0;n<n_streams;n++)
  916. {
  917. int l = 512+(int)strlen(vf->vc->vendor);
  918. infos[n]=(char*)malloc(l);
  919. print_misc(_vf,n,infos[n],l);
  920. }
  921. ui_font=CreateFontIndirect(&cfg_font.data);
  922. panel=0;
  923. next=0;
  924. }
  925. ~InfoDlg()
  926. {
  927. if (ui_font) DeleteObject((HGDIOBJ)ui_font);
  928. cfg_adv_info=is_adv;
  929. if (tags)
  930. {
  931. int n;
  932. for(n=0;n<n_streams;n++)
  933. delete tags[n];
  934. free(tags);
  935. }
  936. if (infos)
  937. {
  938. int n;
  939. for(n=0;n<n_streams;n++) free(infos[n]);
  940. free(infos);
  941. }
  942. InfoDlg ** pp=&Instances,*p=Instances;
  943. while(p)
  944. {
  945. if (p==this)
  946. {
  947. *pp=next;
  948. break;
  949. }
  950. else {pp=&p->next;p=*pp;}
  951. }
  952. }
  953. void Run(HWND parent,bool modeless)
  954. {
  955. next=Instances;
  956. Instances=this;//HACK - prevent crash on shutdown (used to be only for modeless)
  957. if (modeless)
  958. {
  959. myCreateDialog(IDD_INFO_DLG_NEW,parent);
  960. }
  961. else myDialogBoxEx(IDD_INFO_DLG_NEW,parent);
  962. }
  963. friend int RunInfoDlg(const in_char * url,HWND parent);
  964. };
  965. int RunInfoDlg(const in_char * url,HWND parent)
  966. {
  967. static bool in_modal;
  968. if (in_modal) return 1;
  969. else in_modal=1;
  970. VorbisFile * vf;
  971. bool vf_global=0;
  972. int ret=0;
  973. StringW _url;
  974. _url.AddString(url);
  975. {
  976. InfoDlg * p=InfoDlg::Instances;
  977. while(p)
  978. {
  979. if (!_wcsicmp(p->url,_url))
  980. {
  981. ShowWindow(p->wnd,SW_SHOW);
  982. SetActiveWindow(p->wnd);
  983. return 0;
  984. }
  985. p=p->next;
  986. }
  987. }
  988. EnterCriticalSection(&sync);
  989. if ((url==cur_file || !_wcsicmp(url,cur_file)) && theFile) {vf=theFile;vf_global=1;}
  990. else
  991. {
  992. LeaveCriticalSection(&sync);
  993. vf=VorbisFile::Create(url,1);
  994. if (!vf)
  995. {
  996. in_modal=0;
  997. return 0;
  998. }
  999. }
  1000. {
  1001. InfoDlg d(vf,_url);
  1002. if (vf_global) LeaveCriticalSection(&sync);
  1003. else delete vf;
  1004. d.Run(parent,0);
  1005. ret = !d.modal_ex_quit_val;
  1006. }
  1007. in_modal=0;
  1008. return ret;
  1009. }
  1010. InfoDlg* InfoDlg::Instances=0;
  1011. /* end crappy PP dialog */
  1012. bool VorbisTagToWinampTag(wchar_t * tag, int len)
  1013. {
  1014. #define TAG_ALIAS(b,a) if(!_wcsicmp(L ## a, tag)) { lstrcpynW(tag, L ## b, len); return true; }
  1015. TAG_ALIAS("title", "TITLE");
  1016. TAG_ALIAS("artist", "ARTIST");
  1017. TAG_ALIAS("album", "ALBUM");
  1018. TAG_ALIAS("genre", "GENRE");
  1019. TAG_ALIAS("comment", "COMMENT");
  1020. TAG_ALIAS("year", "DATE");
  1021. TAG_ALIAS("track", "TRACKNUMBER");
  1022. TAG_ALIAS("albumartist", "ALBUMARTIST");
  1023. TAG_ALIAS("composer", "COMPOSER");
  1024. TAG_ALIAS("disc", "DISCNUMBER");
  1025. TAG_ALIAS("publisher", "PUBLISHER");
  1026. TAG_ALIAS("conductor", "CONDUCTOR");
  1027. TAG_ALIAS("bpm", "BPM");
  1028. return false;
  1029. #undef TAG_ALIAS
  1030. }
  1031. bool WinampTagToVorbisTag(wchar_t * tag, int len)
  1032. {
  1033. #define TAG_ALIAS(a,b) if(!_wcsicmp(L ## a, tag)) { lstrcpynW(tag, L ## b, len); return true; }
  1034. TAG_ALIAS("title", "TITLE");
  1035. TAG_ALIAS("artist", "ARTIST");
  1036. TAG_ALIAS("album", "ALBUM");
  1037. TAG_ALIAS("genre", "GENRE");
  1038. TAG_ALIAS("comment", "COMMENT");
  1039. TAG_ALIAS("year", "DATE");
  1040. TAG_ALIAS("track", "TRACKNUMBER");
  1041. TAG_ALIAS("albumartist", "ALBUMARTIST");
  1042. TAG_ALIAS("composer", "COMPOSER");
  1043. TAG_ALIAS("disc", "DISCNUMBER");
  1044. TAG_ALIAS("publisher", "PUBLISHER");
  1045. TAG_ALIAS("conductor", "CONDUCTOR");
  1046. TAG_ALIAS("bpm", "BPM");
  1047. return false;
  1048. #undef TAG_ALIAS
  1049. }
  1050. static INT_PTR CALLBACK ChildProc_Advanced(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
  1051. static int sel=-1;
  1052. static int ismychange=0;
  1053. switch(msg)
  1054. {
  1055. case WM_NOTIFYFORMAT:
  1056. return NFR_UNICODE;
  1057. case WM_INITDIALOG:
  1058. {
  1059. #define ListView_InsertColumnW(hwnd, iCol, pcol) \
  1060. (int)SNDMSG((hwnd), LVM_INSERTCOLUMNW, (WPARAM)(int)(iCol), (LPARAM)(const LV_COLUMNW *)(pcol))
  1061. SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
  1062. sel=-1;
  1063. HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
  1064. ListView_SetExtendedListViewStyle(hwndlist, LVS_EX_FULLROWSELECT);
  1065. LVCOLUMNW lvc = {0, };
  1066. lvc.mask = LVCF_TEXT|LVCF_WIDTH;
  1067. lvc.pszText = WASABI_API_LNGSTRINGW(IDS_NAME);
  1068. lvc.cx = 82;
  1069. ListView_InsertColumnW(hwndlist, 0, &lvc);
  1070. lvc.pszText = WASABI_API_LNGSTRINGW(IDS_VALUE);
  1071. lvc.cx = 160;
  1072. ListView_InsertColumnW(hwndlist, 1, &lvc);
  1073. Info *info = (Info *)lParam;
  1074. int n = info->GetNumMetadataItems();
  1075. for(int i=0; i<n; i++) {
  1076. wchar_t key[512] = {0};
  1077. wchar_t value[2048] = {0};
  1078. info->EnumMetadata(i,key,512,value,2048);
  1079. if(value[0] && key[0]) {
  1080. LVITEMW lvi={LVIF_TEXT,i,0};
  1081. lvi.pszText = key;
  1082. SendMessage(hwndlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
  1083. lvi.iSubItem=1;
  1084. lvi.pszText = (wchar_t*)value;
  1085. SendMessage(hwndlist,LVM_SETITEMW,0,(LPARAM)&lvi);
  1086. }
  1087. }
  1088. ListView_SetColumnWidth(hwndlist,0,(n?LVSCW_AUTOSIZE:LVSCW_AUTOSIZE_USEHEADER));
  1089. ListView_SetColumnWidth(hwndlist,1,(n?LVSCW_AUTOSIZE:LVSCW_AUTOSIZE_USEHEADER));
  1090. SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
  1091. SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
  1092. EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
  1093. EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
  1094. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
  1095. }
  1096. break;
  1097. case WM_DESTROY:
  1098. {
  1099. HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
  1100. ListView_DeleteAllItems(hwndlist);
  1101. while(ListView_DeleteColumn(hwndlist,0));
  1102. Info * info = (Info*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
  1103. delete info;
  1104. }
  1105. break;
  1106. case WM_USER:
  1107. if(wParam && lParam && !ismychange)
  1108. {
  1109. wchar_t * value = (wchar_t*)lParam;
  1110. wchar_t tag[100] = {0};
  1111. lstrcpynW(tag,(wchar_t*)wParam,100);
  1112. WinampTagToVorbisTag(tag,100);
  1113. Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1114. if(!*value)
  1115. {
  1116. info->RemoveMetadata(tag);
  1117. if(!_wcsicmp(L"ALBUMARTIST",tag))
  1118. {
  1119. // need to remove these two, also, or else it's gonna look like delete doesn't work
  1120. // if the file was tagged using these alternate fields
  1121. info->RemoveMetadata(L"ALBUM ARTIST");
  1122. info->RemoveMetadata(L"ENSEMBLE");
  1123. }
  1124. if(!_wcsicmp(L"PUBLISHER",tag))
  1125. {
  1126. // need to remove this also, or else it's gonna look like delete doesn't work
  1127. // if the file was tagged using this alternate field
  1128. info->RemoveMetadata(L"ORGANIZATION");
  1129. }
  1130. if(!_wcsicmp(L"DATE",tag))
  1131. {
  1132. // need to remove this also, or else it's gonna look like delete doesn't work
  1133. // if the file was tagged using this alternate field
  1134. info->RemoveMetadata(L"YEAR");
  1135. }
  1136. if(!_wcsicmp(L"TRACKNUMBER",tag))
  1137. {
  1138. // need to remove this also, or else it's gonna look like delete doesn't work
  1139. // if the file was tagged using this alternate field
  1140. info->RemoveMetadata(L"TRACK");
  1141. }
  1142. }
  1143. else
  1144. {
  1145. info->SetMetadata(tag,value);
  1146. }
  1147. HWND hlist = GetDlgItem(hwndDlg,IDC_LIST);
  1148. int n = ListView_GetItemCount(hlist);
  1149. for(int i=0; i<n; i++)
  1150. {
  1151. wchar_t key[100]=L"";
  1152. LVITEMW lvi={LVIF_TEXT,i,0};
  1153. lvi.pszText=key;
  1154. lvi.cchTextMax=100;
  1155. SendMessage(hlist,LVM_GETITEMW,0,(LPARAM)&lvi);
  1156. if(!_wcsicmp(key,tag))
  1157. {
  1158. lvi.iSubItem = 1;
  1159. lvi.pszText = value;
  1160. SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
  1161. if(!*value)
  1162. ListView_DeleteItem(hlist,i);
  1163. else if(ListView_GetItemState(hlist,i,LVIS_SELECTED))
  1164. SetDlgItemTextW(hwndDlg,IDC_VALUE,value);
  1165. return 0;
  1166. }
  1167. }
  1168. // bew hew, not found
  1169. LVITEMW lvi={0,0x7FFFFFF0,0};
  1170. n = (int)SendMessage(hlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
  1171. lvi.mask = LVIF_TEXT;
  1172. lvi.iItem = n;
  1173. lvi.iSubItem = 0;
  1174. lvi.pszText = tag;
  1175. SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
  1176. lvi.iSubItem = 1;
  1177. lvi.pszText = value;
  1178. SendMessage(hlist,LVM_SETITEMW,0,(LPARAM)&lvi);
  1179. }
  1180. break;
  1181. case WM_NOTIFY:
  1182. {
  1183. LPNMHDR l=(LPNMHDR)lParam;
  1184. if(l->idFrom==IDC_LIST && l->code == LVN_KEYDOWN) {
  1185. if((((LPNMLVKEYDOWN)l)->wVKey) == VK_DELETE){
  1186. int selitem = ListView_GetNextItem(l->hwndFrom,-1,LVNI_SELECTED|LVNI_FOCUSED);
  1187. if(selitem != -1)
  1188. SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_BUTTON_DEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDC_BUTTON_DEL));
  1189. }
  1190. }
  1191. else if(l->idFrom==IDC_LIST && l->code == LVN_ITEMCHANGED) {
  1192. LPNMLISTVIEW lv=(LPNMLISTVIEW)lParam;
  1193. if(lv->uNewState & LVIS_SELECTED) {
  1194. int n = lv->iItem;
  1195. LVITEMW lvi={LVIF_TEXT,lv->iItem,0};
  1196. wchar_t key[100] = {0};
  1197. wchar_t value[1024] = {0};
  1198. lvi.pszText=key;
  1199. lvi.cchTextMax=100;
  1200. SendMessage(l->hwndFrom,LVM_GETITEMW,0,(LPARAM)&lvi);
  1201. lvi.pszText=value;
  1202. lvi.cchTextMax=1024;
  1203. lvi.iSubItem=1;
  1204. SendMessage(l->hwndFrom,LVM_GETITEMW,0,(LPARAM)&lvi);
  1205. SetDlgItemTextW(hwndDlg,IDC_NAME,key);
  1206. SetDlgItemTextW(hwndDlg,IDC_VALUE,value);
  1207. sel = n;
  1208. EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),TRUE);
  1209. EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),TRUE);
  1210. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),TRUE);
  1211. }
  1212. if(lv->uOldState & LVIS_SELECTED) {
  1213. sel = -1;
  1214. SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
  1215. SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
  1216. EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
  1217. EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
  1218. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
  1219. }
  1220. }
  1221. }
  1222. break;
  1223. case WM_COMMAND:
  1224. switch(LOWORD(wParam)) {
  1225. case IDOK:
  1226. {
  1227. Info * info = (Info*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
  1228. if (!info->Save())
  1229. {
  1230. MessageBox(hwndDlg,
  1231. L"Cannot save metadata: Error writing file or file is read-only.",
  1232. L"Error saving metadata.",
  1233. MB_OK);
  1234. }
  1235. }
  1236. break;
  1237. case IDC_NAME:
  1238. case IDC_VALUE:
  1239. if(HIWORD(wParam) == EN_CHANGE && sel>=0) {
  1240. wchar_t key[100] = {0};
  1241. wchar_t value[1024] = {0};
  1242. LVITEMW lvi={LVIF_TEXT,sel,0};
  1243. GetDlgItemTextW(hwndDlg,IDC_NAME,key,100);
  1244. GetDlgItemTextW(hwndDlg,IDC_VALUE,value,1024);
  1245. lvi.pszText=key;
  1246. lvi.cchTextMax=100;
  1247. SendMessage(GetDlgItem(hwndDlg,IDC_LIST),LVM_SETITEMW,0,(LPARAM)&lvi);
  1248. lvi.pszText=value;
  1249. lvi.cchTextMax=1024;
  1250. lvi.iSubItem=1;
  1251. SendMessage(GetDlgItem(hwndDlg,IDC_LIST),LVM_SETITEMW,0,(LPARAM)&lvi);
  1252. VorbisTagToWinampTag(key,100);
  1253. ismychange=1;
  1254. SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)key,(WPARAM)value);
  1255. ismychange=0;
  1256. }
  1257. else if(HIWORD(wParam) == EN_KILLFOCUS && sel>=0) {
  1258. wchar_t key[100] = {0};
  1259. wchar_t value[1024] = {0};
  1260. GetDlgItemTextW(hwndDlg,IDC_NAME,key,100);
  1261. GetDlgItemTextW(hwndDlg,IDC_VALUE,value,1024);
  1262. Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1263. wchar_t oldkey[100]=L"";
  1264. bool newitem=true;
  1265. if(sel < info->GetNumMetadataItems()) {
  1266. info->EnumMetadata(sel,oldkey,100,0,0);
  1267. newitem=false;
  1268. }
  1269. if(!newitem && wcscmp(oldkey,key)) { // key changed
  1270. info->SetTag(sel,key);
  1271. } else {
  1272. info->SetMetadata(key,value);
  1273. }
  1274. VorbisTagToWinampTag(key,100);
  1275. ismychange=1;
  1276. SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)key,(WPARAM)value);
  1277. ismychange=0;
  1278. }
  1279. break;
  1280. case IDC_BUTTON_DEL:
  1281. if(sel >= 0) {
  1282. wchar_t tag[100] = {0};
  1283. GetDlgItemTextW(hwndDlg,IDC_NAME,tag,100);
  1284. SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
  1285. SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
  1286. EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
  1287. EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
  1288. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
  1289. Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1290. if(sel < info->GetNumMetadataItems())
  1291. info->RemoveMetadata(sel);
  1292. ListView_DeleteItem(GetDlgItem(hwndDlg,IDC_LIST),sel);
  1293. sel=-1;
  1294. VorbisTagToWinampTag(tag,100);
  1295. ismychange=1;
  1296. SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)tag,(WPARAM)L"");
  1297. ismychange=0;
  1298. }
  1299. break;
  1300. case IDC_BUTTON_DELALL:
  1301. ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_LIST));
  1302. SetDlgItemTextW(hwndDlg,IDC_NAME,L"");
  1303. SetDlgItemTextW(hwndDlg,IDC_VALUE,L"");
  1304. EnableWindow(GetDlgItem(hwndDlg,IDC_NAME),FALSE);
  1305. EnableWindow(GetDlgItem(hwndDlg,IDC_VALUE),FALSE);
  1306. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_DEL),FALSE);
  1307. sel=-1;
  1308. {
  1309. Info *info = (Info *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  1310. int n = info->GetNumMetadataItems();
  1311. while(n>0) {
  1312. --n;
  1313. wchar_t tag[100] = {0};
  1314. info->EnumMetadata(n,tag,100,0,0);
  1315. VorbisTagToWinampTag(tag,100);
  1316. ismychange=1;
  1317. SendMessage(GetParent(hwndDlg),WM_USER,(WPARAM)tag,(WPARAM)L"");
  1318. ismychange=0;
  1319. info->RemoveMetadata(n);
  1320. }
  1321. }
  1322. break;
  1323. case IDC_BUTTON_ADD:
  1324. {
  1325. HWND hwndlist = GetDlgItem(hwndDlg,IDC_LIST);
  1326. LVITEMW lvi={0,0x7FFFFFF0,0};
  1327. int n = (int)SendMessage(hwndlist,LVM_INSERTITEMW,0,(LPARAM)&lvi);
  1328. ListView_SetItemState(hwndlist,n,LVIS_SELECTED,LVIS_SELECTED);
  1329. }
  1330. break;
  1331. }
  1332. break;
  1333. }
  1334. return 0;
  1335. }
  1336. extern "C"
  1337. {
  1338. // return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
  1339. // if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")!
  1340. __declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn)
  1341. {
  1342. if (PathIsURLW(fn))
  1343. return 0;
  1344. return 1;
  1345. }
  1346. // should return a child window of 513x271 pixels (341x164 in msvc dlg units), or return NULL for no tab.
  1347. // Fill in name (a buffer of namelen characters), this is the title of the tab (defaults to "Advanced").
  1348. // filename will be valid for the life of your window. n is the tab number. This function will first be
  1349. // called with n == 0, then n == 1 and so on until you return NULL (so you can add as many tabs as you like).
  1350. // The window you return will recieve WM_COMMAND, IDOK/IDCANCEL messages when the user clicks OK or Cancel.
  1351. // when the user edits a field which is duplicated in another pane, do a SendMessage(GetParent(hwnd),WM_USER,(WPARAM)L"fieldname",(LPARAM)L"newvalue");
  1352. // this will be broadcast to all panes (including yours) as a WM_USER.
  1353. __declspec(dllexport) HWND winampAddUnifiedFileInfoPane(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen)
  1354. {
  1355. if(n == 0) { // add first pane
  1356. SetPropW(parent,L"INBUILT_NOWRITEINFO", (HANDLE)1);
  1357. Info *info = new Info(filename);
  1358. if(info->Error())
  1359. {
  1360. delete info;
  1361. return NULL;
  1362. }
  1363. return WASABI_API_CREATEDIALOGPARAMW(IDD_INFO,parent,ChildProc_Advanced,(LPARAM)info);
  1364. }
  1365. return NULL;
  1366. }
  1367. };