#include "Main.h" #include "VideoOSD.h" #include "resource.h" #include "draw.h" #include "../nu/AutoChar.h" #define OSD_TEXT_R 192 #define OSD_TEXT_G 192 #define OSD_TEXT_B 192 #define OSD_TEXT_R_HILITE 255 #define OSD_TEXT_G_HILITE 255 #define OSD_TEXT_B_HILITE 255 #define OSD_VOL_COL_R 0 #define OSD_VOL_COL_G 0 #define OSD_VOL_COL_B 192 #define OSD_VOL_BKCOL_R 0 #define OSD_VOL_BKCOL_G 0 #define OSD_VOL_BKCOL_B 64 #define CTRL_PROGRESSTEXT 0 #define CTRL_PROGRESS 1 #define CTRL_PROGRESSSPACER 2 #define CTRL_REW 3 #define CTRL_PLAY 4 #define CTRL_PAUSE 5 #define CTRL_STOP 6 #define CTRL_FFWD 7 #define CTRL_VOLSPACER 8 #define CTRL_VOLTEXT 9 #define CTRL_VOL 10 #define CTRLTYPE_SYMBOL 0 #define CTRLTYPE_TEXT 1 #define CTRLTYPE_PROGRESS 2 #define CTRLTYPE_SPACER 3 IVideoOSD *temp; int g_ctrl_type[ NUM_WIDGETS ] = { CTRLTYPE_TEXT, CTRLTYPE_PROGRESS, CTRLTYPE_SPACER, CTRLTYPE_SYMBOL, CTRLTYPE_SYMBOL, CTRLTYPE_SYMBOL, CTRLTYPE_SYMBOL, CTRLTYPE_SYMBOL, CTRLTYPE_SPACER, CTRLTYPE_TEXT, CTRLTYPE_PROGRESS }; #define SHOW_STREAM_TITLE_AT_TOP 1 char progStr[64] = {0}, volStr[64] = {0}; const char *g_ctrl_text[NUM_WIDGETS] = { progStr/*"Progress "*/, "", "", "7", // rew "4", // play ";", // pause "<", // stop "8", // ffwd "", volStr/*"Volume "*/, "" }; int g_ctrl_force_width[NUM_WIDGETS] = { 0, 256/*96*/, // progress bar width 32, // spacer width 0, // rew 0, // play 0, // pause 0, // stop 0, // ffwd 32, // spacer width 0, 96/*64*/ // volume bar width }; IVideoOSD::IVideoOSD() : ctrlrects_ready(0), parent(0) { temp = this; getString(IDS_OSD_PROGRESS_TEXT,progStr,64); getString(IDS_OSD_VOLUME_TEXT,volStr,64); last_close_height = 0; last_close_width = 0; osdMemBMW = 0; osdMemBMH = 0; osdLastMouseX = -1; osdLastMouseY = -1; ignore_mousemove_count = 0; osdLastClickItem = 0; show_osd = false; for (int i = 0; i < NUM_WIDGETS; i++) SetRect(&ctrlrect[i], 0, 0, 0, 0); } IVideoOSD::~IVideoOSD() { KillTimer(parent, (UINT_PTR)this); } bool IVideoOSD::Showing() { return show_osd; } bool IVideoOSD::Ready() { return !!ctrlrects_ready; } int IVideoOSD::GetBarHeight() { return (/*show_osd && */ctrlrects_ready) ? (ctrlrect_all.bottom - ctrlrect_all.top) : 0; } void IVideoOSD::HitTest(int x, int y, int dragging) { if (!show_osd) return ; // dragging == -1: just a mousemove (no clicking) // dragging == 0: user clicked // dragging == 1: user clicked before, and is now dragging/moving mouse if (dragging < 1) osdLastClickItem = -1; // transform (x,y) from screen coords into coords relative to the memDC RECT lastfsrect; getViewport(&lastfsrect, parent, 1, NULL); y = y - ((lastfsrect.bottom - lastfsrect.top) - (ctrlrect_all.bottom - ctrlrect_all.top)); int i0 = 0; int i1 = NUM_WIDGETS; if (dragging == 1) { i0 = osdLastClickItem; i1 = osdLastClickItem + 1; } for (int i = i0; i < i1; i++) { if (dragging == 1 || (x >= ctrlrect[i].left && x <= ctrlrect[i].right && y >= ctrlrect[i].top && y <= ctrlrect[i].bottom)) { float t = (x - ctrlrect[i].left) / (float)(ctrlrect[i].right - ctrlrect[i].left); if (t < 0) t = 0; if (t > 1) t = 1; if (dragging < 1) osdLastClickItem = i; switch (i) { case CTRL_VOL: if (dragging >= 0) { int v = (int)(t * 255); config_volume = v; in_setvol(v); draw_volumebar(config_volume, 0); } return ; case CTRL_PROGRESS: if (dragging >= 0) { int len = in_getlength(); if (len > 0 && !PlayList_ishidden(PlayList_getPosition())) { if (in_seek((int)(t*len*1000)) < 0) SendMessageW(hMainWindow, WM_WA_MPEG_EOF, 0, 0); } } return ; case CTRL_PAUSE: if (dragging == 0) { PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0); } return ; case CTRL_PLAY: if (dragging == 0) { PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0); } return ; case CTRL_STOP: if (dragging == 0) { PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0); } return ; case CTRL_REW: case CTRL_FFWD: if (dragging == 0) { if (i == CTRL_REW) PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0); else PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0); } return ; default: if (dragging < 1) osdLastClickItem = -1; break; } } } } void IVideoOSD::Show() { if (!show_osd) { show_osd = true; SetCursor(LoadCursor(NULL, IDC_ARROW)); RECT r; GetClientRect(parent, &r); r.bottom = r.top + GetBarHeight(); InvalidateRect(parent, &r, TRUE); GetClientRect(parent, &r); r.top = r.bottom - GetBarHeight(); InvalidateRect(parent, &r, TRUE); PostMessageW(parent, WM_USER + 0x888, 0, 0); } KillTimer(parent, (UINT_PTR)this); SetTimer(parent, (UINT_PTR)this, 3000, IVideoOSD::TimerCallback); // Draw(); } void CALLBACK IVideoOSD::TimerCallback(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR idEvent, DWORD/* dwTime*/) { IVideoOSD *videoOSD = (IVideoOSD *)idEvent; videoOSD->Hide(); } void IVideoOSD::Hide() { RECT r; GetClientRect(parent, &r); r.bottom = r.top + GetBarHeight(); InvalidateRect(parent, &r, TRUE); GetClientRect(parent, &r); r.top = r.bottom - GetBarHeight(); InvalidateRect(parent, &r, TRUE); PostMessageW(parent, WM_USER + 0x888, 0, 0); if (show_osd) { //MessageBeep(0xFFFFFFFF); show_osd = false; KillTimer(parent, (UINT_PTR)this); SetCursor(NULL); } //ctrlrects_ready = 0; } void IVideoOSD::Draw() { HDC hdc = GetDC(parent); if (show_osd) { HGDIOBJ osdProgressBrushBg = CreateSolidBrush(RGB(OSD_VOL_BKCOL_R, OSD_VOL_BKCOL_G, OSD_VOL_BKCOL_B)); HGDIOBJ osdProgressBrushFg = CreateSolidBrush(RGB(OSD_VOL_COL_R, OSD_VOL_COL_G, OSD_VOL_COL_B)); HGDIOBJ osdProgressPenBg = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B)); HGDIOBJ osdProgressPenFg = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); HGDIOBJ osdProgressPenBgHilite = CreatePen(PS_SOLID, 0, RGB(OSD_TEXT_R_HILITE, OSD_TEXT_G_HILITE, OSD_TEXT_B_HILITE)); HGDIOBJ osdBlackBrush = CreateSolidBrush(RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B)); 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"); HDC osdMemDC = CreateCompatibleDC(hdc); HBITMAP osdMemBM = 0; // memory bitmap (for memDC) HBITMAP osdOldBM = 0; // old bitmap (from memDC) COLORREF fg = GetTextColor(osdMemDC); COLORREF bg = GetBkColor(osdMemDC); SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B)); SetBkColor(osdMemDC, RGB(0, 0, 0)); //OV_COL_R,OV_COL_G,OV_COL_B)); HGDIOBJ oldfont = SelectObject(osdMemDC, osdFontText); HGDIOBJ oldbrush = SelectObject(osdMemDC, osdProgressBrushBg); HGDIOBJ oldpen = SelectObject(osdMemDC, osdProgressPenBg); RECT fullr; GetClientRect(parent, &fullr); /* ClientToScreen(parent, (LPPOINT)&fullr); ClientToScreen(parent, ((LPPOINT)&fullr) + 1); // transform coords from windows desktop coords (where 0,0==upper-left corner of the primary monitor) // to the coords for the monitor we're displaying on: fullr.top -= m_mon_y; fullr.left -= m_mon_x; fullr.right -= m_mon_x; fullr.bottom -= m_mon_y; */ int streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable; if (ctrlrects_ready != streaming + 1) { ctrlrects_ready = streaming + 1; int net_width = 0; int max_height = 0; int i; for (i = 0; i < NUM_WIDGETS; i++) { SetRect(&ctrlrect[i], 0, 0, 0, 0); if (streaming && (i == CTRL_PROGRESS || i == CTRL_PROGRESSTEXT || i == CTRL_PROGRESSSPACER || i == CTRL_FFWD || i == CTRL_REW)) { // disable progress bar + seek arrows when the NSV is a stream ctrlrect[i].right = -1; continue; } else if (g_ctrl_force_width[i] != 0) { SetRect(&ctrlrect[i], 0, 0, g_ctrl_force_width[i], 0); } else { SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText); SetRect(&ctrlrect[i], 0, 0, 256, 256); ctrlrect[i].bottom = DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE | DT_CALCRECT); } net_width += ctrlrect[i].right - ctrlrect[i].left; max_height = max(max_height, ctrlrect[i].bottom - ctrlrect[i].top); } // now we know the size of all the controls; now place them. int x = (fullr.right + fullr.left) / 2 - net_width / 2; SetRect(&ctrlrect_all, 0, 0, 0, 0); for (i = 0; i < NUM_WIDGETS; i++) { if (ctrlrect[i].right >= 0) // if control is not disabled... { int this_width = ctrlrect[i].right - ctrlrect[i].left; int this_height = ctrlrect[i].bottom - ctrlrect[i].top ; if (this_height == 0) this_height = max_height * 2 / 3; // progress bars ctrlrect[i].top = max_height / 2 - this_height / 2; ctrlrect[i].bottom = max_height / 2 + this_height / 2; ctrlrect[i].left = x; ctrlrect[i].right = x + this_width; if (ctrlrect_all.bottom == 0) { ctrlrect_all.top = ctrlrect[i].top ; ctrlrect_all.bottom = ctrlrect[i].bottom; } else { ctrlrect_all.top = min(ctrlrect_all.top , ctrlrect[i].top); ctrlrect_all.bottom = max(ctrlrect_all.bottom, ctrlrect[i].bottom); } x += this_width; } } } int w = fullr.right - fullr.left; int h = ctrlrect_all.bottom - ctrlrect_all.top; if (!osdMemBM || osdMemBMW != w || osdMemBMH != h) { if (osdMemBM) { SelectObject(osdMemDC, osdOldBM); DeleteObject(osdMemBM); } osdMemBM = CreateCompatibleBitmap(hdc, w, h); osdOldBM = (HBITMAP)SelectObject(osdMemDC, osdMemBM); osdMemBMW = w; osdMemBMH = h; } RECT temp; SetRect(&temp, 0, 0, w, h); FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush); for (int i = 0; i < NUM_WIDGETS; i++) { if (g_ctrl_type[i] == CTRLTYPE_PROGRESS) { int progress = 0; int max_progress = ctrlrect[i].right - ctrlrect[i].left; switch (i) { case CTRL_VOL: progress = config_volume * max_progress / 255; break; case CTRL_PROGRESS: if (playing) { int len = in_getlength(); if (len > 0) progress = (in_getouttime() / 1000) * max_progress / len; } if (progress > max_progress) progress = max_progress; break; } SelectObject(osdMemDC, osdProgressBrushBg); SelectObject(osdMemDC, (i == osdLastClickItem) ? osdProgressPenBgHilite : osdProgressPenBg); RoundRect(osdMemDC, ctrlrect[i].left, ctrlrect[i].top, ctrlrect[i].right, ctrlrect[i].bottom, 3, 3); SelectObject(osdMemDC, osdProgressBrushFg); SelectObject(osdMemDC, osdProgressPenFg); Rectangle(osdMemDC, ctrlrect[i].left + 1, ctrlrect[i].top + 1, ctrlrect[i].left + progress, ctrlrect[i].bottom); } else if (g_ctrl_type[i] == CTRLTYPE_SYMBOL || g_ctrl_type[i] == CTRLTYPE_TEXT) { SelectObject(osdMemDC, (g_ctrl_type[i] == CTRLTYPE_SYMBOL) ? osdFontSymbol : osdFontText); 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)); DrawTextA(osdMemDC, g_ctrl_text[i], -1, &ctrlrect[i], DT_SINGLELINE); } } int x0 = fullr.left; int y0 = fullr.bottom - (ctrlrect_all.bottom - ctrlrect_all.top); BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY); // display stream title @ the top: #if (SHOW_STREAM_TITLE_AT_TOP) if (1) { RECT temp; SetRect(&temp, 0, 0, w, h); FillRect(osdMemDC, &temp, (HBRUSH)osdBlackBrush); SelectObject(osdMemDC, osdFontText); SetTextColor(osdMemDC, RGB(OSD_TEXT_R, OSD_TEXT_G, OSD_TEXT_B)); AutoChar narrowTitle(FileTitle); wchar_t buf[FILETITLE_SIZE+32] = {0}; StringCchPrintfW(buf, sizeof(buf)/sizeof(*buf), L"%s (%d %s)", FileTitle ? FileTitle : L"", g_brate, getStringW(IDS_KBPS,NULL,0)); if ((config_fixtitles&2)) { wchar_t *p = buf; while (p && *p) { if (*p == '_') // replace _ with space *p = ' '; p = CharNextW(p); } } DrawTextW(osdMemDC, buf, -1, &temp, DT_SINGLELINE | DT_CENTER); SelectObject(osdMemDC, osdFontSymbol); DrawTextW(osdMemDC, L"2", -1, &temp, DT_SINGLELINE | DT_RIGHT); RECT rr = {0, 0, w, h}; DrawTextW(osdMemDC, L"2", -1, &rr, DT_SINGLELINE | DT_RIGHT | DT_CALCRECT); last_close_height = rr.bottom - rr.top; last_close_width = rr.right - rr.left; int x0 = fullr.left; int y0 = fullr.top; BitBlt(hdc, x0, y0, w, h, osdMemDC, 0, 0, SRCCOPY); } SelectObject(osdMemDC, oldpen); SelectObject(osdMemDC, oldbrush); SelectObject(osdMemDC, oldfont); SetTextColor(osdMemDC, fg); SetBkColor(osdMemDC, bg); DeleteObject(osdProgressBrushBg); DeleteObject(osdProgressBrushFg); DeleteObject(osdBlackBrush); DeleteObject(osdProgressPenBg); DeleteObject(osdProgressPenFg); DeleteObject(osdProgressPenBgHilite); DeleteObject(osdFontSymbol); if (osdMemDC) { SelectObject(osdMemDC, osdOldBM); // delete our doublebuffer DeleteDC(osdMemDC); } if (osdMemBM) DeleteObject(osdMemBM); } #endif ReleaseDC(parent, hdc); } bool IVideoOSD::CloseHitTest(int x, int y) { RECT r; GetClientRect(parent, &r); return (x > r.right - last_close_width && y < last_close_height); } bool IVideoOSD::Mouse(int x, int y, WPARAM wParam, bool moving) { if (wParam & MK_LBUTTON) { Show(); if (CloseHitTest(x, y)) return true; ignore_mousemove_count = 2; HitTest(x, y, moving ? 1 : 0); } else { if (((osdLastMouseX - x) || (osdLastMouseY - y)) && (ignore_mousemove_count--)) { Show(); HitTest(x, y, moving ? -1 : 0); ignore_mousemove_count = 2; } } osdLastMouseX = x; osdLastMouseY = y; return false; }