1051 lines
28 KiB
C++
1051 lines
28 KiB
C++
#include "priv.h"
|
|
#include "zaxxon.h"
|
|
#include "guids.h"
|
|
#include "shlwapip.h"
|
|
#include "mmreg.h"
|
|
#include "mmstream.h" // Multimedia stream interfaces
|
|
#include "amstream.h" // DirectShow multimedia stream interfaces
|
|
#include "ddstream.h" // DirectDraw multimedia stream interfaces
|
|
#include "resource.h"
|
|
#include "varutil.h"
|
|
#include "runtask.h"
|
|
|
|
#define COLOR3d (COLORREF)GetSysColor(COLOR_3DFACE)
|
|
#define COLORMASK (COLORREF)RGB( 255, 0, 255 )
|
|
|
|
#define PREV 0
|
|
#define PLAY 1
|
|
#define PAUSE 2
|
|
#define STOP 3
|
|
#define NEXT 4
|
|
#define MENU 5
|
|
|
|
|
|
void PlayMP3(LPTSTR pszFilename);
|
|
|
|
const TCHAR* g_crgstrStrings = TEXT("Play\0Pause\0Stop\0Previous\0Next\0Menu\0\0");
|
|
|
|
const TBBUTTON g_crgButtons[] =
|
|
{
|
|
{PLAY, PLAY, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
|
|
{PREV, PREV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
|
|
{NEXT, NEXT, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
|
|
{MENU, MENU, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
|
|
};
|
|
|
|
|
|
#define WMP_CONTROLS_COUNT 6
|
|
|
|
int GetButtonsWidth(HWND hwndTB)
|
|
{
|
|
LONG lButton = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0L);
|
|
return HIWORD(lButton) * SendMessage(hwndTB, TB_BUTTONCOUNT, 0, 0) + 1;
|
|
}
|
|
|
|
void CenterOnTopOf(BOOL fToolbar, HWND hwnd, HWND hwndOn)
|
|
{
|
|
RECT rcParent;
|
|
RECT rcSelf;
|
|
HMONITOR hmon;
|
|
|
|
GetWindowRect(hwnd, &rcSelf);
|
|
GetWindowRect(hwndOn, &rcParent);
|
|
if (fToolbar)
|
|
rcParent.right = rcParent.left + GetButtonsWidth(hwndOn);
|
|
|
|
int x = rcParent.left + (RECTWIDTH(rcParent) - RECTWIDTH(rcSelf))/2;
|
|
int y = rcParent.top - RECTHEIGHT(rcSelf);
|
|
|
|
hmon = MonitorFromWindow(hwndOn, MONITOR_DEFAULTTONEAREST);
|
|
if (hmon)
|
|
{
|
|
MONITORINFO mi;
|
|
mi.cbSize = sizeof(mi);
|
|
if (GetMonitorInfo(hmon, &mi))
|
|
{
|
|
if (x < mi.rcMonitor.left)
|
|
x = mi.rcMonitor.left;
|
|
|
|
if (y < mi.rcMonitor.top)
|
|
{
|
|
// Go below
|
|
y = rcParent.bottom;
|
|
}
|
|
|
|
if (y + RECTHEIGHT(rcSelf) > mi.rcMonitor.bottom)
|
|
y = mi.rcMonitor.bottom - RECTHEIGHT(rcSelf);
|
|
|
|
if (x + RECTWIDTH(rcSelf) > mi.rcMonitor.right)
|
|
x = mi.rcMonitor.right - RECTWIDTH(rcSelf);
|
|
}
|
|
}
|
|
|
|
SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSIZE);
|
|
}
|
|
|
|
void FillRectClr(HDC hdc, PRECT prc, COLORREF clr)
|
|
{
|
|
COLORREF clrSave = SetBkColor(hdc, clr);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
|
|
SetBkColor(hdc, clrSave);
|
|
}
|
|
|
|
class CMusicExtractionTask : public CRunnableTask
|
|
{
|
|
public:
|
|
CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile);
|
|
|
|
STDMETHODIMP RunInitRT(void);
|
|
|
|
private:
|
|
virtual ~CMusicExtractionTask();
|
|
|
|
TCHAR szFile[MAX_PATH];
|
|
HWND _hwnd;
|
|
CZaxxon* _pzaxxon;
|
|
|
|
};
|
|
|
|
|
|
CMusicExtractionTask::CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile)
|
|
: CRunnableTask(RTF_DEFAULT), _hwnd(hwnd), _pzaxxon(pzaxxon)
|
|
{
|
|
StrCpyN(szFile, pszFile, ARRAYSIZE(szFile));
|
|
}
|
|
|
|
CMusicExtractionTask::~CMusicExtractionTask()
|
|
{
|
|
}
|
|
|
|
STDMETHODIMP CMusicExtractionTask::RunInitRT()
|
|
{
|
|
BOOL fResetImage = TRUE;
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
PWSTR psz = StrDup(szFile);
|
|
if (psz)
|
|
{
|
|
LPITEMIDLIST pidl = ILCreateFromPath(szFile);
|
|
if (pidl)
|
|
{
|
|
LPCITEMIDLIST pidlChild;
|
|
IShellFolder2* psf;
|
|
|
|
hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder2, &psf), &pidlChild);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT v;
|
|
hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Artist, &v);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szValue[MAX_PATH];
|
|
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
|
|
SendMessage(_hwnd, WM_SETARTIST, 0, (LPARAM)szValue);
|
|
}
|
|
|
|
hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Album, &v);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szValue[MAX_PATH];
|
|
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
|
|
SendMessage(_hwnd, WM_SETALBUM, 0, (LPARAM)szValue);
|
|
}
|
|
|
|
hr = psf->GetDetailsEx(pidlChild, &SCID_Title, &v);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szValue[MAX_PATH];
|
|
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
|
|
SendMessage(_hwnd, WM_SETSONG, 0, (LPARAM)szValue);
|
|
}
|
|
|
|
InvalidateRect(_hwnd, NULL, TRUE);
|
|
|
|
psf->Release();
|
|
}
|
|
|
|
ILFree(pidl);
|
|
}
|
|
|
|
if (PathRemoveFileSpec(psz))
|
|
{
|
|
PathAppend(psz, TEXT("folder.gif"));
|
|
if (!PathFileExists(psz))
|
|
{
|
|
PathRemoveFileSpec(psz);
|
|
PathAppend(psz, TEXT("folder.jpg"));
|
|
}
|
|
|
|
if (PathFileExists(psz))
|
|
{
|
|
if (_pzaxxon->_pThumbnail)
|
|
{
|
|
_pzaxxon->_pThumbnail->Release();
|
|
_pzaxxon->_pThumbnail = NULL;
|
|
}
|
|
|
|
hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&(_pzaxxon->_pThumbnail));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(_hwnd, &rc);
|
|
SIZE sz;
|
|
sz.cy = (3 * RECTHEIGHT(rc)) / 4;
|
|
sz.cx = sz.cy;
|
|
_pzaxxon->_pThumbnail->Init(_hwnd, WM_SONGTHUMBDONE);
|
|
_pzaxxon->_pThumbnail->GetBitmap(psz, 0, sz.cx, sz.cy);
|
|
fResetImage = FALSE;
|
|
}
|
|
}
|
|
}
|
|
LocalFree(psz);
|
|
}
|
|
|
|
if (fResetImage)
|
|
SendMessage(_hwnd, WM_SONGTHUMBDONE, 0, 0);;
|
|
|
|
if (_pzaxxon->_bOpacity < 200)
|
|
{
|
|
_pzaxxon->_fHide = FALSE;
|
|
SetTimer(_hwnd, 1, 30, NULL);
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
void RenderTile(HWND hwnd, HDC hdc, CZaxxon* pzax)
|
|
{
|
|
BITMAP bm = {0};
|
|
RECT rc;
|
|
GetClientRect(hwnd, &rc);
|
|
MARGINS m = {0};
|
|
MARGINS s = {0};
|
|
RECT rcFrame = {0};
|
|
RECT rcText;
|
|
int y = 10;
|
|
|
|
if (pzax->_hbmpAlbumArt)
|
|
{
|
|
GetObject(pzax->_hbmpAlbumArt, sizeof (BITMAP), &bm);
|
|
HDC hdcBitmap = CreateCompatibleDC(hdc);
|
|
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcBitmap, pzax->_hbmpAlbumArt);
|
|
y = (RECTHEIGHT(rc) - bm.bmHeight) / 2;
|
|
|
|
if (pzax->_hTheme)
|
|
{
|
|
GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_SIZINGMARGINS, NULL, &s);
|
|
|
|
y = (RECTHEIGHT(rc) - bm.bmHeight - m.cyBottomHeight - m.cyTopHeight - s.cyBottomHeight - s.cyTopHeight) / 2;
|
|
|
|
GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_CONTENTMARGINS, NULL, &m);
|
|
|
|
rcFrame.left = 10;
|
|
rcFrame.top = y;
|
|
rcFrame.right = rcFrame.left + bm.bmWidth + m.cxLeftWidth + m.cxRightWidth;
|
|
rcFrame.bottom = rcFrame.top + bm.bmHeight + m.cyBottomHeight + m.cyTopHeight;
|
|
|
|
DrawThemeBackground(pzax->_hTheme, hdc, SPP_USERPICTURE, 0, &rcFrame, 0);
|
|
}
|
|
|
|
BitBlt(hdc, rcFrame.left+m.cxLeftWidth, y + m.cyTopHeight, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
|
|
SelectObject(hdcBitmap, hbmpOld);
|
|
DeleteDC(hdcBitmap);
|
|
}
|
|
|
|
SetBkMode(hdc, TRANSPARENT);
|
|
SIZE sz;
|
|
HFONT h = (HFONT)SelectObject(hdc, pzax->_hfont);
|
|
int cch = lstrlen(pzax->_szArtist);
|
|
GetTextExtentPoint32(hdc, pzax->_szArtist, cch, &sz);
|
|
rcText.left = bm.bmWidth + 20 + m.cxLeftWidth + m.cxRightWidth;
|
|
rcText.top = y + m.cyTopHeight;
|
|
rcText.right = rcText.left + sz.cx;
|
|
rcText.bottom = rcText.top + sz.cy;
|
|
DrawShadowText(hdc, pzax->_szArtist, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP, GetSysColor(COLOR_CAPTIONTEXT), RGB(0,0,0), 2, 2);
|
|
|
|
SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
|
|
|
|
cch = lstrlen(pzax->_szAlbum);
|
|
GetTextExtentPoint32(hdc, pzax->_szAlbum, cch, &sz);
|
|
rcText.top = rcText.bottom;
|
|
rcText.bottom = rcText.top + sz.cy;
|
|
rcText.right = rcText.left + sz.cx;
|
|
DrawText(hdc, pzax->_szAlbum, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
|
|
|
|
cch = lstrlen(pzax->_szSong);
|
|
GetTextExtentPoint32(hdc, pzax->_szSong, cch, &sz);
|
|
rcText.top = rcText.bottom;
|
|
rcText.bottom = rcText.top + sz.cy;
|
|
rcText.right = rcText.left + sz.cx;
|
|
DrawText(hdc, pzax->_szSong, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
|
|
|
|
SelectObject(hdc, h);
|
|
}
|
|
|
|
|
|
|
|
LRESULT ZaxxonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CZaxxon* pzaxxon = (CZaxxon*)GetProp(hwnd, TEXT("Zaxxon"));
|
|
if (!pzaxxon && uMsg != WM_CREATE)
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
pzaxxon = (CZaxxon*)((CREATESTRUCT*)lParam)->lpCreateParams;
|
|
SetProp(hwnd, TEXT("Zaxxon"), (HANDLE)pzaxxon);
|
|
pzaxxon->_hTheme = OpenThemeData(NULL, L"StartPanel");
|
|
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
|
|
pzaxxon->_hfont = CreateFontIndirect(&ncm.lfCaptionFont);
|
|
|
|
SIZE sz = {0};
|
|
if (pzaxxon->_hTheme)
|
|
GetThemePartSize(pzaxxon->_hTheme, NULL, SPP_USERPANE, 0, NULL, TS_TRUE, &sz);
|
|
|
|
int cy = 3 * GetSystemMetrics(SM_CYCAPTION);
|
|
if (sz.cy < cy)
|
|
sz.cy = cy;
|
|
|
|
if (sz.cx < 400)
|
|
sz.cx = 400;
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0, sz.cx, sz.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
if (pzaxxon->_hTheme)
|
|
CloseThemeData(pzaxxon->_hTheme);
|
|
}
|
|
break;
|
|
case WM_ERASEBKGND:
|
|
if (pzaxxon->_hTheme)
|
|
{
|
|
RECT rc;
|
|
HDC hdc = (HDC)wParam;
|
|
GetClientRect(hwnd, &rc);
|
|
FillRectClr(hdc, &rc, RGB(255,0,255));
|
|
DrawThemeBackground(pzaxxon->_hTheme, hdc, SPP_USERPANE, 0, &rc, 0);
|
|
RenderTile(hwnd, hdc, pzaxxon);
|
|
|
|
return TRUE;
|
|
}
|
|
break;
|
|
case WM_SETALBUM:
|
|
StrCpy(pzaxxon->_szAlbum, (PTSTR)lParam);
|
|
break;
|
|
|
|
case WM_SETARTIST:
|
|
StrCpy(pzaxxon->_szArtist, (PTSTR)lParam);
|
|
break;
|
|
|
|
case WM_SETSONG:
|
|
StrCpy(pzaxxon->_szSong, (PTSTR)lParam);
|
|
break;
|
|
|
|
|
|
case WM_SONGTHUMBDONE:
|
|
{
|
|
if (pzaxxon->_hbmpAlbumArt)
|
|
DeleteObject(pzaxxon->_hbmpAlbumArt);
|
|
|
|
pzaxxon->_hbmpAlbumArt = (HBITMAP)lParam;
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
|
|
if (pzaxxon->_pThumbnail)
|
|
{
|
|
pzaxxon->_pThumbnail->Release();
|
|
pzaxxon->_pThumbnail = NULL;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_TIMER:
|
|
if (wParam == 1)
|
|
{
|
|
BYTE bOld = pzaxxon->_bOpacity;
|
|
if (pzaxxon->_fHide)
|
|
{
|
|
if (pzaxxon->_bOpacity < 20)
|
|
{
|
|
pzaxxon->_bOpacity = 0;
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
KillTimer(hwnd, 1);
|
|
}
|
|
else
|
|
pzaxxon->_bOpacity -= 20;
|
|
}
|
|
else
|
|
{
|
|
if (pzaxxon->_bOpacity > 200)
|
|
{
|
|
pzaxxon->_bOpacity = 200;
|
|
KillTimer(hwnd, 1);
|
|
if (pzaxxon->_fAllowFadeout)
|
|
SetTimer(hwnd, 2, 1000, NULL);
|
|
}
|
|
else
|
|
pzaxxon->_bOpacity += 10;
|
|
}
|
|
|
|
if (bOld != pzaxxon->_bOpacity)
|
|
SetLayeredWindowAttributes(hwnd, RGB(255,0,255), pzaxxon->_bOpacity, LWA_COLORKEY | LWA_ALPHA);
|
|
|
|
BOOL fToolbar = TRUE;
|
|
HWND hwndToPutOnTopOf = pzaxxon->_hwnd;
|
|
if (pzaxxon->_fEditorShown)
|
|
{
|
|
fToolbar = FALSE;
|
|
hwndToPutOnTopOf = pzaxxon->_pEdit->_hwnd;
|
|
}
|
|
CenterOnTopOf(fToolbar, hwnd, hwndToPutOnTopOf);
|
|
}
|
|
else if (wParam == 2)
|
|
{
|
|
KillTimer(hwnd, 2);
|
|
SetTimer(hwnd, 1, 30, NULL);
|
|
pzaxxon->_fHide = TRUE;
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_SONGSTOP:
|
|
{
|
|
pzaxxon->SongStop();
|
|
DeleteObject(pzaxxon->_hbmpAlbumArt);
|
|
pzaxxon->_hbmpAlbumArt = NULL;
|
|
|
|
pzaxxon->_szArtist[0] = 0;
|
|
pzaxxon->_szSong[0] = 0;
|
|
pzaxxon->_szAlbum[0] = 0;
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_SONGCHANGE:
|
|
{
|
|
if (pzaxxon->_pScheduler)
|
|
{
|
|
CMusicExtractionTask* pme = new CMusicExtractionTask(pzaxxon, hwnd, (PWSTR)wParam);
|
|
|
|
pzaxxon->_pScheduler->AddTask(pme, CLSID_Zaxxon, 0, ITSAT_DEFAULT_PRIORITY);
|
|
pme->Release();
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
CZaxxon::CZaxxon()
|
|
{
|
|
CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler));
|
|
CoCreateInstance(CLSID_ZaxxonPlayer, NULL, CLSCTX_INPROC_SERVER, IID_IZaxxonPlayer, (void**)&_pzax);
|
|
_dwViewMode = NULL;
|
|
_himlHot = NULL;
|
|
_himlDef = NULL;
|
|
_hmenuOpenFolder = NULL;
|
|
_pThumbnail = NULL;
|
|
_bOpacity = 0;
|
|
_fHide = FALSE;
|
|
_fAllowFadeout = TRUE;
|
|
_fPlaying = FALSE;
|
|
_hbr = NULL;
|
|
_szArtist[0] = 0;
|
|
_szSong[0] = 0;
|
|
_szAlbum[0] = 0;
|
|
_hbmpAlbumArt = NULL;
|
|
}
|
|
|
|
CZaxxon::~CZaxxon()
|
|
{
|
|
if (_himlHot)
|
|
ImageList_Destroy(_himlHot);
|
|
if (_himlDef)
|
|
ImageList_Destroy(_himlDef);
|
|
|
|
if (_pzax)
|
|
_pzax->Release();
|
|
|
|
if (_pThumbnail)
|
|
_pThumbnail->Release();
|
|
|
|
if (_pScheduler)
|
|
_pScheduler->Release();
|
|
|
|
if (_hbr)
|
|
DeleteObject(_hbr);
|
|
|
|
if (_hmenuOpenFolder)
|
|
DestroyMenu(_hmenuOpenFolder);
|
|
}
|
|
|
|
HWND CZaxxon::_CreateWindow(HWND hwndParent)
|
|
{
|
|
if (_hwnd)
|
|
return _hwnd;
|
|
|
|
WNDCLASS wc = {0};
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpszClassName = TEXT("ZaxxonSongTile");
|
|
wc.lpfnWndProc = ZaxxonWndProc;
|
|
wc.hInstance = HINST_THISDLL;
|
|
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
|
|
RegisterClass(&wc);
|
|
|
|
|
|
_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
|
|
WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
|
|
WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
|
|
CCS_NODIVIDER | CCS_NOPARENTALIGN |
|
|
CCS_NORESIZE | TBSTYLE_REGISTERDROP,
|
|
0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
|
|
|
|
if (_hwnd)
|
|
{
|
|
// Set the format to ANSI or UNICODE as appropriate.
|
|
ToolBar_SetUnicodeFormat(_hwnd, TRUE);
|
|
|
|
SetWindowTheme(_hwnd, L"TaskBar", NULL);
|
|
|
|
SendMessage(_hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0);
|
|
SendMessage(_hwnd, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
|
|
// SendMessage(_hwnd, TB_ADDSTRING, NULL, (LPARAM)&g_crgstrStrings);
|
|
SendMessage(_hwnd, TB_ADDBUTTONS, ARRAYSIZE(g_crgButtons), (LPARAM)&g_crgButtons);
|
|
ToolBar_SetExtendedStyle(_hwnd, TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_DOUBLEBUFFER);
|
|
|
|
|
|
_himlHot = ImageList_LoadImage(HINST_THISDLL,
|
|
MAKEINTRESOURCE(IDB_ZAXXONHOT), 16, 0, COLORMASK,
|
|
IMAGE_BITMAP, LR_CREATEDIBSECTION);
|
|
|
|
SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, (LPARAM)_himlHot);
|
|
|
|
_himlDef = ImageList_LoadImage(HINST_THISDLL,
|
|
MAKEINTRESOURCE(IDB_ZAXXONDEF), 16, 0, COLORMASK,
|
|
IMAGE_BITMAP, LR_CREATEDIBSECTION);
|
|
|
|
SendMessage(_hwnd, TB_SETIMAGELIST, 0, (LPARAM)_himlDef);
|
|
|
|
|
|
_hwndSongTile = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT, TEXT("ZaxxonSongTile"), NULL,
|
|
WS_POPUP, 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, this);
|
|
|
|
_pEdit = new CZaxxonEditor(this);
|
|
_pEdit->Initialize();
|
|
|
|
_pzax->Register(_hwndSongTile);
|
|
}
|
|
|
|
return _hwnd;
|
|
}
|
|
|
|
void CZaxxon::SongStop()
|
|
{
|
|
_fPlaying = FALSE;
|
|
TBBUTTONINFO bi = {0};
|
|
bi.cbSize = sizeof(bi);
|
|
bi.dwMask = TBIF_IMAGE;
|
|
bi.iImage = PLAY;
|
|
ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
|
|
|
|
}
|
|
|
|
LRESULT CZaxxon::_OnCommand(WORD wNotifyCode, WORD wID, HWND hwnd)
|
|
{
|
|
if (!_pzax)
|
|
return 0;
|
|
|
|
switch (wNotifyCode)
|
|
{
|
|
case BN_CLICKED:
|
|
switch (wID)
|
|
{
|
|
case PLAY:
|
|
{
|
|
TBBUTTONINFO bi = {0};
|
|
bi.cbSize = sizeof(bi);
|
|
bi.dwMask = TBIF_IMAGE;
|
|
|
|
if (_fPlaying)
|
|
{
|
|
_pzax->Pause();
|
|
_fPlaying = FALSE;
|
|
bi.iImage = PLAY;
|
|
}
|
|
else
|
|
{
|
|
_pzax->Play();
|
|
_fPlaying = TRUE;
|
|
bi.iImage = PAUSE;
|
|
|
|
}
|
|
|
|
ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
|
|
}
|
|
break;
|
|
|
|
case PAUSE:
|
|
_pzax->Pause();
|
|
break;
|
|
|
|
case STOP:
|
|
_pzax->Stop();
|
|
_fPlaying = FALSE;
|
|
break;
|
|
|
|
case NEXT:
|
|
_pzax->NextSong();
|
|
break;
|
|
|
|
case PREV:
|
|
_pzax->PrevSong();
|
|
break;
|
|
|
|
case MENU:
|
|
{
|
|
_fEditorShown = !_fEditorShown;
|
|
BOOL fToolbar = TRUE;
|
|
HWND hwndToPutOnTopOf = _hwnd;
|
|
if (_fEditorShown)
|
|
{
|
|
fToolbar = FALSE;
|
|
hwndToPutOnTopOf = _pEdit->_hwnd;
|
|
}
|
|
_pEdit->Show(_fEditorShown);
|
|
|
|
CenterOnTopOf(fToolbar, _hwndSongTile, hwndToPutOnTopOf);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
HRESULT CZaxxon::RecurseAddFile(IShellFolder* psf)
|
|
{
|
|
LPITEMIDLIST pidlItem;
|
|
IEnumIDList* penum;
|
|
if (SUCCEEDED(psf->EnumObjects(NULL, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &penum)))
|
|
{
|
|
ULONG l;
|
|
while(S_OK == penum->Next(1, &pidlItem, &l))
|
|
{
|
|
|
|
if ((SHGetAttributes(psf, pidlItem, SFGAO_FOLDER) & SFGAO_FOLDER))
|
|
{
|
|
IShellFolder* psfNext;
|
|
if (SUCCEEDED(SHBindToObjectEx(psf, pidlItem, NULL, IID_PPV_ARG(IShellFolder, &psfNext))))
|
|
{
|
|
RecurseAddFile(psfNext);
|
|
|
|
psfNext->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR sz[MAX_PATH];
|
|
DisplayNameOf(psf, pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
|
|
PTSTR pszExtension = PathFindExtension(sz);
|
|
if (StrCmpI(pszExtension, TEXT(".mp3")) == 0 ||
|
|
StrCmpI(pszExtension, TEXT(".wma")) == 0)
|
|
{
|
|
_pzax->AddSong(sz);
|
|
}
|
|
}
|
|
|
|
ILFree(pidlItem);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CZaxxon::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
switch (uMsg)
|
|
{
|
|
|
|
case SMC_EXEC:
|
|
{
|
|
if (psmd->uId == 1)
|
|
{
|
|
IShellMenu* psm;
|
|
if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
|
|
{
|
|
DWORD dwFlags;
|
|
IShellFolder* psf;
|
|
LPITEMIDLIST pidl;
|
|
if (SUCCEEDED(psm->GetShellFolder(&dwFlags, &pidl, IID_PPV_ARG(IShellFolder, &psf))))
|
|
{
|
|
RecurseAddFile(psf);
|
|
|
|
hr = S_OK;
|
|
psf->Release();
|
|
ILFree(pidl);
|
|
}
|
|
psm->Release();
|
|
}
|
|
}
|
|
else if (psmd->uId == 2)
|
|
{
|
|
_pzax->ClearPlaylist();
|
|
}
|
|
}
|
|
break;
|
|
case SMC_SFEXEC:
|
|
{
|
|
TCHAR sz[MAX_PATH];
|
|
DisplayNameOf(psmd->psf, psmd->pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
|
|
PTSTR pszExtension = PathFindExtension(sz);
|
|
if (StrCmpI(pszExtension, TEXT(".mp3")) == 0)
|
|
{
|
|
_pzax->AddSong(sz);
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
|
|
case SMC_INITMENU:
|
|
{
|
|
IShellMenu* psm;
|
|
if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
|
|
{
|
|
HMENU hmenu;
|
|
DWORD dwFlags = SMSET_BOTTOM;
|
|
if (psmd->uIdParent == 100)
|
|
{
|
|
hmenu = CreateMenu();
|
|
AppendMenu(hmenu, MF_SEPARATOR, -1, NULL);
|
|
AppendMenu(hmenu, MF_STRING, 2, TEXT("Clear Playlist"));
|
|
AppendMenu(hmenu, MF_STRING, 1, TEXT("Play Folder"));
|
|
}
|
|
else
|
|
{
|
|
if (_hmenuOpenFolder == NULL)
|
|
{
|
|
_hmenuOpenFolder = CreateMenu();
|
|
AppendMenu(_hmenuOpenFolder, MF_SEPARATOR, -1, NULL);
|
|
AppendMenu(_hmenuOpenFolder, MF_STRING, 1, TEXT("Play Folder"));
|
|
}
|
|
|
|
dwFlags |= SMSET_DONTOWN;
|
|
hmenu = _hmenuOpenFolder;
|
|
}
|
|
|
|
psm->SetMenu(hmenu, NULL, dwFlags);
|
|
psm->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
void CZaxxon::_DoMenu()
|
|
{
|
|
HRESULT hr;
|
|
LPITEMIDLIST pidl = NULL;
|
|
if (FAILED(SHGetSpecialFolderLocation(_hwnd, CSIDL_MYMUSIC, &pidl)))
|
|
SHGetSpecialFolderLocation(_hwnd, CSIDL_MYDOCUMENTS, &pidl);
|
|
|
|
if (pidl)
|
|
{
|
|
IShellFolder* psf;
|
|
hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ITrackShellMenu* ptsm;
|
|
hr = CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER, IID_ITrackShellMenu, (void**)&ptsm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RECT rc;
|
|
POINTL pt;
|
|
ptsm->Initialize(this, 100, ANCESTORDEFAULT, SMINIT_TOPLEVEL | SMINIT_NOSETSITE | SMINIT_VERTICAL);
|
|
ptsm->SetShellFolder(psf, pidl, NULL, SMSET_TOP | SMSET_USEBKICONEXTRACTION);
|
|
ToolBar_GetRect(_hwnd, MENU, &rc);
|
|
MapWindowPoints(_hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
|
|
pt.x = rc.left;
|
|
pt.y = rc.top;
|
|
ptsm->Popup(_hwnd, &pt, (RECTL*)&rc, MPPF_TOP);
|
|
ptsm->Release();
|
|
}
|
|
psf->Release();
|
|
}
|
|
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
|
|
LRESULT CZaxxon::_OnNotify(LPNMHDR pnm)
|
|
{
|
|
LRESULT lres = 0;
|
|
switch(pnm->code)
|
|
{
|
|
|
|
case TBN_GETOBJECT:
|
|
{
|
|
NMOBJECTNOTIFY*pon = (NMOBJECTNOTIFY*)pnm;
|
|
pon->hResult = QueryInterface(*pon->piid, &pon->pObject);
|
|
lres = 1;
|
|
}
|
|
break;
|
|
|
|
case TBN_HOTITEMCHANGE:
|
|
{
|
|
NMTBHOTITEM* phi = (NMTBHOTITEM*)pnm;
|
|
if (phi->dwFlags & HICF_ENTERING)
|
|
{
|
|
_fAllowFadeout = FALSE;
|
|
_fHide = FALSE;
|
|
|
|
if (_fPlaying)
|
|
{
|
|
ShowWindow(_hwndSongTile, SW_SHOW);
|
|
SetTimer(_hwndSongTile, 1, 30, NULL);
|
|
KillTimer(_hwndSongTile, 2);
|
|
}
|
|
}
|
|
else if (phi->dwFlags & HICF_LEAVING)
|
|
{
|
|
_fAllowFadeout = TRUE;
|
|
_fHide = TRUE;
|
|
SetTimer(_hwndSongTile, 1, 30, NULL);
|
|
KillTimer(_hwndSongTile, 2);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
return lres;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CZaxxon::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CZaxxon, IWinEventHandler),
|
|
QITABENT(CZaxxon, IDropTarget),
|
|
{ 0 },
|
|
};
|
|
|
|
HRESULT hres = QISearch(this, qit, riid, ppvObj);
|
|
if (FAILED(hres))
|
|
hres = CToolBand::QueryInterface(riid, ppvObj);
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::GetWindow(HWND * phwnd)
|
|
{
|
|
|
|
*phwnd = _CreateWindow(_hwndParent);
|
|
|
|
return *phwnd? S_OK : E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
|
|
DESKBANDINFO* pdbi)
|
|
{
|
|
|
|
LONG lButton = SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0L);
|
|
UINT ucy;
|
|
UINT ucx;
|
|
if (fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL))
|
|
{
|
|
ucy = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
|
|
ucx = LOWORD(lButton);
|
|
}
|
|
else
|
|
{
|
|
ucx = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
|
|
ucy = LOWORD(lButton);
|
|
}
|
|
|
|
_dwBandID = dwBandID;
|
|
_dwViewMode = fViewMode;
|
|
|
|
pdbi->ptMinSize.x = LOWORD(lButton) * 1;
|
|
pdbi->ptMinSize.y = ucy;
|
|
|
|
pdbi->ptMaxSize.y = ucy;
|
|
pdbi->ptMaxSize.x = ucx;
|
|
|
|
pdbi->ptActual.y = ucy;
|
|
pdbi->ptActual.x = ucx;
|
|
|
|
pdbi->ptIntegral.y = 1;
|
|
pdbi->ptIntegral.x = 1;
|
|
|
|
if (pdbi->dwMask & DBIM_TITLE)
|
|
{
|
|
StrCpy(pdbi->wszTitle, TEXT("Zaxxon"));
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::ShowDW(BOOL fShow)
|
|
{
|
|
return CToolBand::ShowDW(fShow);
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::CloseDW(DWORD dw)
|
|
{
|
|
SendMessage(_hwnd, TB_SETIMAGELIST, 0, NULL);
|
|
SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, NULL);
|
|
return CToolBand::CloseDW(dw);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CZaxxon::TranslateAcceleratorIO(LPMSG lpMsg)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::HasFocusIO()
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CZaxxon::IsWindowOwner(HWND hwnd)
|
|
{
|
|
return (hwnd == _hwnd)? S_OK : S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
|
{
|
|
|
|
HRESULT hres = S_FALSE;
|
|
switch (dwMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
*plres = _OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
|
|
hres = S_OK;
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
*plres = _OnNotify((LPNMHDR)lParam);
|
|
hres = S_OK;
|
|
break;
|
|
|
|
case WM_ENDSESSION:
|
|
_pzax->Stop();
|
|
hres = S_OK;
|
|
break;
|
|
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CZaxxon::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::DragLeave(void)
|
|
{
|
|
return S_OK; // Yea so?
|
|
}
|
|
|
|
|
|
STDMETHODIMP CZaxxon::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (SUCCEEDED(pdtobj->GetData(&fmte, &medium)))
|
|
{
|
|
HDROP hdrop = (HDROP)medium.hGlobal;
|
|
|
|
if (hdrop)
|
|
{
|
|
int c = DragQueryFile(hdrop, -1, NULL, 0);
|
|
if (c > 0)
|
|
{
|
|
for (int i=0; i < c;i++)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
DragQueryFile(hdrop, i, szPath, ARRAYSIZE(szPath));
|
|
|
|
_pzax->AddSong(szPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CZaxxon_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hr;
|
|
CZaxxon *pzax = new CZaxxon;
|
|
if (pzax)
|
|
{
|
|
hr = pzax->QueryInterface(riid, ppv);
|
|
pzax->Release();
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
*ppv = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CZaxxon::GetClassID(CLSID *pClassID)
|
|
{
|
|
*pClassID = CLSID_Zaxxon;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::Load(IStream *pStm)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CZaxxon::Save(IStream *pStm, BOOL fClearDirty)
|
|
{
|
|
return S_OK;
|
|
|
|
}
|