VideoOSD.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. #include "Main.h"
  2. #include "VideoOSD.h"
  3. #include "resource.h"
  4. #include "draw.h"
  5. #include "../nu/AutoChar.h"
  6. #define OSD_TEXT_R 192
  7. #define OSD_TEXT_G 192
  8. #define OSD_TEXT_B 192
  9. #define OSD_TEXT_R_HILITE 255
  10. #define OSD_TEXT_G_HILITE 255
  11. #define OSD_TEXT_B_HILITE 255
  12. #define OSD_VOL_COL_R 0
  13. #define OSD_VOL_COL_G 0
  14. #define OSD_VOL_COL_B 192
  15. #define OSD_VOL_BKCOL_R 0
  16. #define OSD_VOL_BKCOL_G 0
  17. #define OSD_VOL_BKCOL_B 64
  18. #define CTRL_PROGRESSTEXT 0
  19. #define CTRL_PROGRESS 1
  20. #define CTRL_PROGRESSSPACER 2
  21. #define CTRL_REW 3
  22. #define CTRL_PLAY 4
  23. #define CTRL_PAUSE 5
  24. #define CTRL_STOP 6
  25. #define CTRL_FFWD 7
  26. #define CTRL_VOLSPACER 8
  27. #define CTRL_VOLTEXT 9
  28. #define CTRL_VOL 10
  29. #define CTRLTYPE_SYMBOL 0
  30. #define CTRLTYPE_TEXT 1
  31. #define CTRLTYPE_PROGRESS 2
  32. #define CTRLTYPE_SPACER 3
  33. IVideoOSD *temp;
  34. int g_ctrl_type[ NUM_WIDGETS ] =
  35. {
  36. CTRLTYPE_TEXT,
  37. CTRLTYPE_PROGRESS,
  38. CTRLTYPE_SPACER,
  39. CTRLTYPE_SYMBOL,
  40. CTRLTYPE_SYMBOL,
  41. CTRLTYPE_SYMBOL,
  42. CTRLTYPE_SYMBOL,
  43. CTRLTYPE_SYMBOL,
  44. CTRLTYPE_SPACER,
  45. CTRLTYPE_TEXT,
  46. CTRLTYPE_PROGRESS
  47. };
  48. #define SHOW_STREAM_TITLE_AT_TOP 1
  49. char progStr[64] = {0}, volStr[64] = {0};
  50. const char *g_ctrl_text[NUM_WIDGETS] =
  51. {
  52. progStr/*"Progress "*/,
  53. "",
  54. "",
  55. "7", // rew
  56. "4", // play
  57. ";", // pause
  58. "<", // stop
  59. "8", // ffwd
  60. "",
  61. volStr/*"Volume "*/,
  62. ""
  63. };
  64. int g_ctrl_force_width[NUM_WIDGETS] =
  65. {
  66. 0,
  67. 256/*96*/, // progress bar width
  68. 32, // spacer width
  69. 0, // rew
  70. 0, // play
  71. 0, // pause
  72. 0, // stop
  73. 0, // ffwd
  74. 32, // spacer width
  75. 0,
  76. 96/*64*/ // volume bar width
  77. };
  78. IVideoOSD::IVideoOSD()
  79. : ctrlrects_ready(0), parent(0)
  80. {
  81. temp = this;
  82. getString(IDS_OSD_PROGRESS_TEXT,progStr,64);
  83. getString(IDS_OSD_VOLUME_TEXT,volStr,64);
  84. last_close_height = 0;
  85. last_close_width = 0;
  86. osdMemBMW = 0;
  87. osdMemBMH = 0;
  88. osdLastMouseX = -1;
  89. osdLastMouseY = -1;
  90. ignore_mousemove_count = 0;
  91. osdLastClickItem = 0;
  92. show_osd = false;
  93. for (int i = 0; i < NUM_WIDGETS; i++)
  94. SetRect(&ctrlrect[i], 0, 0, 0, 0);
  95. }
  96. IVideoOSD::~IVideoOSD()
  97. {
  98. KillTimer(parent, (UINT_PTR)this);
  99. }
  100. bool IVideoOSD::Showing()
  101. {
  102. return show_osd;
  103. }
  104. bool IVideoOSD::Ready()
  105. {
  106. return !!ctrlrects_ready;
  107. }
  108. int IVideoOSD::GetBarHeight()
  109. {
  110. return (/*show_osd && */ctrlrects_ready) ? (ctrlrect_all.bottom - ctrlrect_all.top) : 0;
  111. }
  112. void IVideoOSD::HitTest(int x, int y, int dragging)
  113. {
  114. if (!show_osd) return ;
  115. // dragging == -1: just a mousemove (no clicking)
  116. // dragging == 0: user clicked
  117. // dragging == 1: user clicked before, and is now dragging/moving mouse
  118. if (dragging < 1)
  119. osdLastClickItem = -1;
  120. // transform (x,y) from screen coords into coords relative to the memDC
  121. RECT lastfsrect;
  122. getViewport(&lastfsrect, parent, 1, NULL);
  123. y = y - ((lastfsrect.bottom - lastfsrect.top) - (ctrlrect_all.bottom - ctrlrect_all.top));
  124. int i0 = 0;
  125. int i1 = NUM_WIDGETS;
  126. if (dragging == 1)
  127. {
  128. i0 = osdLastClickItem;
  129. i1 = osdLastClickItem + 1;
  130. }
  131. for (int i = i0; i < i1; i++)
  132. {
  133. if (dragging == 1 || (x >= ctrlrect[i].left && x <= ctrlrect[i].right && y >= ctrlrect[i].top && y <= ctrlrect[i].bottom))
  134. {
  135. float t = (x - ctrlrect[i].left) / (float)(ctrlrect[i].right - ctrlrect[i].left);
  136. if (t < 0) t = 0;
  137. if (t > 1) t = 1;
  138. if (dragging < 1)
  139. osdLastClickItem = i;
  140. switch (i)
  141. {
  142. case CTRL_VOL:
  143. if (dragging >= 0)
  144. {
  145. int v = (int)(t * 255);
  146. config_volume = v;
  147. in_setvol(v);
  148. draw_volumebar(config_volume, 0);
  149. }
  150. return ;
  151. case CTRL_PROGRESS:
  152. if (dragging >= 0)
  153. {
  154. int len = in_getlength();
  155. if (len > 0 && !PlayList_ishidden(PlayList_getPosition()))
  156. {
  157. if (in_seek((int)(t*len*1000)) < 0)
  158. SendMessageW(hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  159. }
  160. }
  161. return ;
  162. case CTRL_PAUSE:
  163. if (dragging == 0)
  164. {
  165. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0);
  166. }
  167. return ;
  168. case CTRL_PLAY:
  169. if (dragging == 0)
  170. {
  171. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0);
  172. }
  173. return ;
  174. case CTRL_STOP:
  175. if (dragging == 0)
  176. {
  177. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
  178. }
  179. return ;
  180. case CTRL_REW:
  181. case CTRL_FFWD:
  182. if (dragging == 0)
  183. {
  184. if (i == CTRL_REW)
  185. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
  186. else
  187. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
  188. }
  189. return ;
  190. default:
  191. if (dragging < 1)
  192. osdLastClickItem = -1;
  193. break;
  194. }
  195. }
  196. }
  197. }
  198. void IVideoOSD::Show()
  199. {
  200. if (!show_osd)
  201. {
  202. show_osd = true;
  203. SetCursor(LoadCursor(NULL, IDC_ARROW));
  204. RECT r;
  205. GetClientRect(parent, &r);
  206. r.bottom = r.top + GetBarHeight();
  207. InvalidateRect(parent, &r, TRUE);
  208. GetClientRect(parent, &r);
  209. r.top = r.bottom - GetBarHeight();
  210. InvalidateRect(parent, &r, TRUE);
  211. PostMessageW(parent, WM_USER + 0x888, 0, 0);
  212. }
  213. KillTimer(parent, (UINT_PTR)this);
  214. SetTimer(parent, (UINT_PTR)this, 3000, IVideoOSD::TimerCallback);
  215. // Draw();
  216. }
  217. void CALLBACK IVideoOSD::TimerCallback(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR idEvent, DWORD/* dwTime*/)
  218. {
  219. IVideoOSD *videoOSD = (IVideoOSD *)idEvent;
  220. videoOSD->Hide();
  221. }
  222. void IVideoOSD::Hide()
  223. {
  224. RECT r;
  225. GetClientRect(parent, &r);
  226. r.bottom = r.top + GetBarHeight();
  227. InvalidateRect(parent, &r, TRUE);
  228. GetClientRect(parent, &r);
  229. r.top = r.bottom - GetBarHeight();
  230. InvalidateRect(parent, &r, TRUE);
  231. PostMessageW(parent, WM_USER + 0x888, 0, 0);
  232. if (show_osd)
  233. {
  234. //MessageBeep(0xFFFFFFFF);
  235. show_osd = false;
  236. KillTimer(parent, (UINT_PTR)this);
  237. SetCursor(NULL);
  238. }
  239. //ctrlrects_ready = 0;
  240. }
  241. void IVideoOSD::Draw()
  242. {
  243. HDC hdc = GetDC(parent);
  244. if (show_osd)
  245. {
  246. HGDIOBJ osdProgressBrushBg = CreateSolidBrush(RGB(OSD_VOL_BKCOL_R, OSD_VOL_BKCOL_G, OSD_VOL_BKCOL_B));
  247. HGDIOBJ osdProgressBrushFg = CreateSolidBrush(RGB(OSD_VOL_COL_R, OSD_VOL_COL_G, OSD_VOL_COL_B));
  248. HGDIOBJ osdProgressPenBg = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
  249. HGDIOBJ osdProgressPenFg = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
  250. HGDIOBJ osdProgressPenBgHilite = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R_HILITE, OSD_TEXT_G_HILITE, OSD_TEXT_B_HILITE));
  251. HGDIOBJ osdBlackBrush = CreateSolidBrush(RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B));
  252. HFONT osdFontSymbol = CreateFontA(OSD_TEXT_SIZE, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, "Webdings");
  253. HDC osdMemDC = CreateCompatibleDC(hdc);
  254. HBITMAP osdMemBM = 0; // memory bitmap (for memDC)
  255. HBITMAP osdOldBM = 0; // old bitmap (from memDC)
  256. COLORREF fg = GetTextColor(osdMemDC);
  257. COLORREF bg = GetBkColor(osdMemDC);
  258. SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
  259. SetBkColor(osdMemDC, RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B));
  260. HGDIOBJ oldfont = SelectObject(osdMemDC, osdFontText);
  261. HGDIOBJ oldbrush = SelectObject(osdMemDC, osdProgressBrushBg);
  262. HGDIOBJ oldpen = SelectObject(osdMemDC, osdProgressPenBg);
  263. RECT fullr;
  264. GetClientRect(parent, &fullr);
  265. /* ClientToScreen(parent, (LPPOINT)&fullr);
  266. ClientToScreen(parent, ((LPPOINT)&fullr) + 1);
  267. // transform coords from windows desktop coords (where 0,0==upper-left corner of the primary monitor)
  268. // to the coords for the monitor we're displaying on:
  269. fullr.top -= m_mon_y;
  270. fullr.left -= m_mon_x;
  271. fullr.right -= m_mon_x;
  272. fullr.bottom -= m_mon_y;
  273. */
  274. int streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable;
  275. if (ctrlrects_ready != streaming + 1)
  276. {
  277. ctrlrects_ready = streaming + 1;
  278. int net_width = 0;
  279. int max_height = 0;
  280. int i;
  281. for (i = 0; i < NUM_WIDGETS; i++)
  282. {
  283. SetRect(&ctrlrect[i], 0, 0, 0, 0);
  284. if (streaming && (i == CTRL_PROGRESS || i == CTRL_PROGRESSTEXT || i == CTRL_PROGRESSSPACER || i == CTRL_FFWD || i == CTRL_REW))
  285. {
  286. // disable progress bar + seek arrows when the NSV is a stream
  287. ctrlrect[i].right = -1;
  288. continue;
  289. }
  290. else if (g_ctrl_force_width[i] != 0)
  291. {
  292. SetRect(&ctrlrect[i], 0, 0, g_ctrl_force_width[i], 0);
  293. }
  294. else
  295. {
  296. SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
  297. SetRect(&ctrlrect[i], 0, 0, 256, 256);
  298. ctrlrect[i].bottom = DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE | DT_CALCRECT);
  299. }
  300. net_width += ctrlrect[i].right - ctrlrect[i].left;
  301. max_height = max(max_height, ctrlrect[i].bottom - ctrlrect[i].top);
  302. }
  303. // now we know the size of all the controls; now place them.
  304. int x = (fullr.right + fullr.left) / 2 - net_width / 2;
  305. SetRect(&ctrlrect_all, 0, 0, 0, 0);
  306. for (i = 0; i < NUM_WIDGETS; i++)
  307. {
  308. if (ctrlrect[i].right >= 0) // if control is not disabled...
  309. {
  310. int this_width = ctrlrect[i].right - ctrlrect[i].left;
  311. int this_height = ctrlrect[i].bottom - ctrlrect[i].top ;
  312. if (this_height == 0) this_height = max_height * 2 / 3; // progress bars
  313. ctrlrect[i].top = max_height / 2 - this_height / 2;
  314. ctrlrect[i].bottom = max_height / 2 + this_height / 2;
  315. ctrlrect[i].left = x;
  316. ctrlrect[i].right = x + this_width;
  317. if (ctrlrect_all.bottom == 0)
  318. {
  319. ctrlrect_all.top = ctrlrect[i].top ;
  320. ctrlrect_all.bottom = ctrlrect[i].bottom;
  321. }
  322. else
  323. {
  324. ctrlrect_all.top = min(ctrlrect_all.top , ctrlrect[i].top);
  325. ctrlrect_all.bottom = max(ctrlrect_all.bottom, ctrlrect[i].bottom);
  326. }
  327. x += this_width;
  328. }
  329. }
  330. }
  331. int w = fullr.right - fullr.left;
  332. int h = ctrlrect_all.bottom - ctrlrect_all.top;
  333. if (!osdMemBM || osdMemBMW != w || osdMemBMH != h)
  334. {
  335. if (osdMemBM)
  336. {
  337. SelectObject(osdMemDC, osdOldBM);
  338. DeleteObject(osdMemBM);
  339. }
  340. osdMemBM = CreateCompatibleBitmap(hdc, w, h);
  341. osdOldBM = (HBITMAP)SelectObject(osdMemDC, osdMemBM);
  342. osdMemBMW = w;
  343. osdMemBMH = h;
  344. }
  345. RECT temp;
  346. SetRect(&temp, 0, 0, w, h);
  347. FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
  348. for (int i = 0; i < NUM_WIDGETS; i++)
  349. {
  350. if (g_ctrl_type[i] == CTRLTYPE_PROGRESS)
  351. {
  352. int progress = 0;
  353. int max_progress = ctrlrect[i].right - ctrlrect[i].left;
  354. switch (i)
  355. {
  356. case CTRL_VOL:
  357. progress = config_volume * max_progress / 255;
  358. break;
  359. case CTRL_PROGRESS:
  360. if (playing)
  361. {
  362. int len = in_getlength();
  363. if (len > 0) progress = (in_getouttime() / 1000) * max_progress / len;
  364. }
  365. if (progress > max_progress) progress = max_progress;
  366. break;
  367. }
  368. SelectObject(osdMemDC, osdProgressBrushBg);
  369. SelectObject(osdMemDC, (i == osdLastClickItem) ? osdProgressPenBgHilite : osdProgressPenBg);
  370. RoundRect(osdMemDC, ctrlrect[i].left, ctrlrect[i].top, ctrlrect[i].right, ctrlrect[i].bottom, 3, 3);
  371. SelectObject(osdMemDC, osdProgressBrushFg);
  372. SelectObject(osdMemDC, osdProgressPenFg);
  373. Rectangle(osdMemDC, ctrlrect[i].left + 1, ctrlrect[i].top + 1, ctrlrect[i].left + progress, ctrlrect[i].bottom);
  374. }
  375. else if (g_ctrl_type[i] == CTRLTYPE_SYMBOL ||
  376. g_ctrl_type[i] == CTRLTYPE_TEXT)
  377. {
  378. SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText);
  379. SetTextColor(osdMemDC, (i == osdLastClickItem) ? RGB(OSD_TEXT_R_HILITE, OSD_TEXT_G_HILITE, OSD_TEXT_B_HILITE) : RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
  380. DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE);
  381. }
  382. }
  383. int x0 = fullr.left;
  384. int y0 = fullr.bottom - (ctrlrect_all.bottom - ctrlrect_all.top);
  385. BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY);
  386. // display stream title @ the top:
  387. #if (SHOW_STREAM_TITLE_AT_TOP)
  388. if (1)
  389. {
  390. RECT temp;
  391. SetRect(&temp, 0, 0, w, h);
  392. FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush);
  393. SelectObject(osdMemDC, osdFontText);
  394. SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B));
  395. AutoChar narrowTitle(FileTitle);
  396. wchar_t buf[FILETITLE_SIZE+32] = {0};
  397. StringCchPrintfW(buf, sizeof(buf)/sizeof(*buf), L"%s (%d %s)", FileTitle ? FileTitle : L"", g_brate, getStringW(IDS_KBPS,NULL,0));
  398. if ((config_fixtitles&2))
  399. {
  400. wchar_t *p = buf;
  401. while (p && *p)
  402. {
  403. if (*p == '_') // replace _ with space
  404. *p = ' ';
  405. p = CharNextW(p);
  406. }
  407. }
  408. DrawTextW(osdMemDC, buf, -1, &temp, DT_SINGLELINE | DT_CENTER);
  409. SelectObject(osdMemDC, osdFontSymbol);
  410. DrawTextW(osdMemDC, L"2", -1, &temp, DT_SINGLELINE | DT_RIGHT);
  411. RECT rr = {0, 0, w, h};
  412. DrawTextW(osdMemDC, L"2", -1, &rr, DT_SINGLELINE | DT_RIGHT | DT_CALCRECT);
  413. last_close_height = rr.bottom - rr.top;
  414. last_close_width = rr.right - rr.left;
  415. int x0 = fullr.left;
  416. int y0 = fullr.top;
  417. BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY);
  418. }
  419. SelectObject(osdMemDC, oldpen);
  420. SelectObject(osdMemDC, oldbrush);
  421. SelectObject(osdMemDC, oldfont);
  422. SetTextColor(osdMemDC, fg);
  423. SetBkColor(osdMemDC, bg);
  424. DeleteObject(osdProgressBrushBg);
  425. DeleteObject(osdProgressBrushFg);
  426. DeleteObject(osdBlackBrush);
  427. DeleteObject(osdProgressPenBg);
  428. DeleteObject(osdProgressPenFg);
  429. DeleteObject(osdProgressPenBgHilite);
  430. DeleteObject(osdFontSymbol);
  431. if (osdMemDC)
  432. {
  433. SelectObject(osdMemDC, osdOldBM); // delete our doublebuffer
  434. DeleteDC(osdMemDC);
  435. }
  436. if (osdMemBM) DeleteObject(osdMemBM);
  437. }
  438. #endif
  439. ReleaseDC(parent, hdc);
  440. }
  441. bool IVideoOSD::CloseHitTest(int x, int y)
  442. {
  443. RECT r;
  444. GetClientRect(parent, &r);
  445. return (x > r.right - last_close_width && y < last_close_height);
  446. }
  447. bool IVideoOSD::Mouse(int x, int y, WPARAM wParam, bool moving)
  448. {
  449. if (wParam & MK_LBUTTON)
  450. {
  451. Show();
  452. if (CloseHitTest(x, y))
  453. return true;
  454. ignore_mousemove_count = 2;
  455. HitTest(x, y, moving ? 1 : 0);
  456. }
  457. else
  458. {
  459. if (((osdLastMouseX - x) || (osdLastMouseY - y)) && (ignore_mousemove_count--))
  460. {
  461. Show();
  462. HitTest(x, y, moving ? -1 : 0);
  463. ignore_mousemove_count = 2;
  464. }
  465. }
  466. osdLastMouseX = x;
  467. osdLastMouseY = y;
  468. return false;
  469. }