mirror of
https://github.com/libretro/Play-.git
synced 2025-01-09 18:10:57 +00:00
PsfPlayer v0.30
git-svn-id: http://svn.purei.org/purei/trunk@561 b36208d7-6611-0410-8bec-b1987f11c4a2
This commit is contained in:
parent
8273d783d1
commit
2188aa037f
@ -205,6 +205,14 @@
|
||||
RelativePath=".\Source\HighResTimer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Playlist.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Playlist.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\PsfBase.cpp"
|
||||
>
|
||||
@ -320,6 +328,10 @@
|
||||
RelativePath=".\Source\win32_ui\MiniDebugger.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\Panel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\PlayerWnd.cpp"
|
||||
>
|
||||
@ -328,6 +340,14 @@
|
||||
RelativePath=".\Source\win32_ui\PlayerWnd.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\PlaylistPanel.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\PlaylistPanel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\Res.rc"
|
||||
>
|
||||
@ -368,6 +388,10 @@
|
||||
RelativePath=".\Source\win32_ui\StdAfx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32_ui\TimeToString.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
28
tools/PsfPlayer/Source/Playlist.cpp
Normal file
28
tools/PsfPlayer/Source/Playlist.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "Playlist.h"
|
||||
|
||||
CPlaylist::CPlaylist()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CPlaylist::~CPlaylist()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CPlaylist::AddItem(const char* path, const CPsfTags& tags)
|
||||
{
|
||||
PLAYLIST_ITEM item;
|
||||
item.title = tags.GetTagValue("title");
|
||||
item.length = CPsfTags::ConvertTimeString(tags.GetTagValue("length").c_str());
|
||||
m_playlistItems[path] = item;
|
||||
|
||||
PlaylistItemMapIterator itemIterator(m_playlistItems.find(path));
|
||||
|
||||
OnItemChange(itemIterator);
|
||||
}
|
||||
|
||||
bool CPlaylist::DoesItemExist(const char* path)
|
||||
{
|
||||
return true;
|
||||
}
|
33
tools/PsfPlayer/Source/Playlist.h
Normal file
33
tools/PsfPlayer/Source/Playlist.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef _PLAYLIST_H_
|
||||
#define _PLAYLIST_H_
|
||||
|
||||
#include "PsfTags.h"
|
||||
#include <boost/signal.hpp>
|
||||
|
||||
class CPlaylist
|
||||
{
|
||||
public:
|
||||
struct PLAYLIST_ITEM
|
||||
{
|
||||
std::wstring title;
|
||||
double length;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, PLAYLIST_ITEM> PlaylistItemMap;
|
||||
typedef PlaylistItemMap::const_iterator PlaylistItemMapIterator;
|
||||
|
||||
typedef boost::signal<void (const PlaylistItemMapIterator&)> OnItemChangeEvent;
|
||||
|
||||
CPlaylist();
|
||||
virtual ~CPlaylist();
|
||||
|
||||
void AddItem(const char*, const CPsfTags&);
|
||||
bool DoesItemExist(const char*);
|
||||
|
||||
OnItemChangeEvent OnItemChange;
|
||||
|
||||
private:
|
||||
PlaylistItemMap m_playlistItems;
|
||||
};
|
||||
|
||||
#endif
|
@ -32,29 +32,105 @@ void CPsfTags::SetDefaultCharEncoding(const CHAR_ENCODING& encoding)
|
||||
m_defaultEncoding = encoding;
|
||||
}
|
||||
|
||||
bool CPsfTags::HasTag(const char* tagName)
|
||||
bool CPsfTags::HasTag(const char* tagName) const
|
||||
{
|
||||
ConstTagIterator tagIterator = m_tags.find(tagName);
|
||||
return tagIterator != m_tags.end();
|
||||
}
|
||||
|
||||
string CPsfTags::GetRawTagValue(const char* tagName)
|
||||
string CPsfTags::GetRawTagValue(const char* tagName) const
|
||||
{
|
||||
ConstTagIterator tagIterator = m_tags.find(tagName);
|
||||
if(tagIterator == m_tags.end()) return "";
|
||||
return tagIterator->second;
|
||||
}
|
||||
|
||||
wstring CPsfTags::GetTagValue(const char* tagName)
|
||||
wstring CPsfTags::GetTagValue(const char* tagName) const
|
||||
{
|
||||
return m_stringConverter(GetRawTagValue(tagName));
|
||||
}
|
||||
|
||||
wstring CPsfTags::DecodeTagValue(const char* value)
|
||||
wstring CPsfTags::DecodeTagValue(const char* value) const
|
||||
{
|
||||
return m_stringConverter(string(value));
|
||||
}
|
||||
|
||||
double CPsfTags::ConvertTimeString(const wchar_t* value)
|
||||
{
|
||||
double time = 0;
|
||||
|
||||
enum
|
||||
{
|
||||
STATE_CHECK_HAS_SEPARATOR,
|
||||
STATE_CHECK_HAS_OTHER_SEPARATOR,
|
||||
STATE_SPLIT_SECONDS_DECIMAL,
|
||||
STATE_DONE
|
||||
};
|
||||
|
||||
struct FindSeparator
|
||||
{
|
||||
const wchar_t* operator()(const wchar_t* string)
|
||||
{
|
||||
const wchar_t* separator = wcschr(string, ':');
|
||||
if(separator == NULL)
|
||||
{
|
||||
separator = wcschr(string, ';');
|
||||
}
|
||||
return separator;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int currentState = STATE_CHECK_HAS_SEPARATOR;
|
||||
std::wstring firstUnit;
|
||||
|
||||
while(currentState != STATE_DONE)
|
||||
{
|
||||
if(currentState == STATE_CHECK_HAS_SEPARATOR)
|
||||
{
|
||||
const wchar_t* separator = FindSeparator()(value);
|
||||
if(separator == NULL)
|
||||
{
|
||||
//No colon found -> doesn't have hours or minutes
|
||||
currentState = STATE_SPLIT_SECONDS_DECIMAL;
|
||||
continue;
|
||||
}
|
||||
|
||||
firstUnit = std::wstring(value, separator);
|
||||
currentState = STATE_CHECK_HAS_OTHER_SEPARATOR;
|
||||
value = separator + 1;
|
||||
}
|
||||
else if(currentState == STATE_CHECK_HAS_OTHER_SEPARATOR)
|
||||
{
|
||||
const wchar_t* separator = FindSeparator()(value);
|
||||
std::wstring minutesStr, hoursStr;
|
||||
if(separator == NULL)
|
||||
{
|
||||
//No colon found -> first unit is minutes
|
||||
minutesStr = firstUnit;
|
||||
}
|
||||
else
|
||||
{
|
||||
hoursStr = firstUnit;
|
||||
minutesStr = std::wstring(value, separator);
|
||||
value = separator + 1;
|
||||
}
|
||||
int hours = wcstol(hoursStr.c_str(), NULL, 10);
|
||||
int minutes = wcstol(minutesStr.c_str(), NULL, 10);
|
||||
currentState = STATE_SPLIT_SECONDS_DECIMAL;
|
||||
time += minutes * 60;
|
||||
time += hours * 60 * 60;
|
||||
}
|
||||
else if(currentState == STATE_SPLIT_SECONDS_DECIMAL)
|
||||
{
|
||||
double seconds = wcstod(value, NULL);
|
||||
time += seconds;
|
||||
currentState = STATE_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
CPsfTags::ConstTagIterator CPsfTags::GetTagsBegin() const
|
||||
{
|
||||
return m_tags.begin();
|
||||
|
@ -22,10 +22,12 @@ public:
|
||||
CPsfTags(const TagMap&);
|
||||
virtual ~CPsfTags();
|
||||
void SetDefaultCharEncoding(const CHAR_ENCODING&);
|
||||
bool HasTag(const char*);
|
||||
std::string GetRawTagValue(const char*);
|
||||
std::wstring GetTagValue(const char*);
|
||||
std::wstring DecodeTagValue(const char*);
|
||||
bool HasTag(const char*) const;
|
||||
std::string GetRawTagValue(const char*) const;
|
||||
std::wstring GetTagValue(const char*) const;
|
||||
std::wstring DecodeTagValue(const char*) const;
|
||||
|
||||
static double ConvertTimeString(const wchar_t*);
|
||||
|
||||
ConstTagIterator GetTagsBegin() const;
|
||||
ConstTagIterator GetTagsEnd() const;
|
||||
|
@ -275,7 +275,7 @@ void CPsfVm::ThreadProc()
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
#else
|
||||
if(!m_spuHandler || !m_spuHandler->HasFreeBuffers())
|
||||
if(m_spuHandler && !m_spuHandler->HasFreeBuffers())
|
||||
{
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(16));
|
||||
m_spuHandler->RecycleBuffers();
|
||||
@ -309,7 +309,10 @@ void CPsfVm::ThreadProc()
|
||||
currentBlock++;
|
||||
if(currentBlock == blockCount)
|
||||
{
|
||||
m_spuHandler->Write(samples, blockSize * blockCount, 44100);
|
||||
if(m_spuHandler)
|
||||
{
|
||||
m_spuHandler->Write(samples, blockSize * blockCount, 44100);
|
||||
}
|
||||
currentBlock = 0;
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,9 @@
|
||||
|
||||
CMainWindow::SPUHANDLER_INFO CMainWindow::m_handlerInfo[] =
|
||||
{
|
||||
{ 1, _T("Win32 WaveOut"), _T("SH_WaveOut.dll") },
|
||||
{ 2, _T("OpenAL"), _T("SH_OpenAL.dll") },
|
||||
{ NULL, NULL, NULL },
|
||||
{ 1, _T("Win32 WaveOut"), _T("SH_WaveOut.dll") },
|
||||
{ 2, _T("OpenAL"), _T("SH_OpenAL.dll") },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
using namespace Framework;
|
||||
@ -35,19 +35,27 @@ m_virtualMachine(virtualMachine),
|
||||
m_ready(false),
|
||||
m_frames(0),
|
||||
m_writes(0),
|
||||
m_selectedAudioHandler(0),
|
||||
m_ejectButton(NULL),
|
||||
m_pauseButton(NULL),
|
||||
m_aboutButton(NULL)
|
||||
m_aboutButton(NULL),
|
||||
m_playlistPanel(NULL)
|
||||
{
|
||||
m_selectedAudioHandler = m_handlerInfo[0].id;
|
||||
for(unsigned int i = 0; i < MAX_PANELS; i++)
|
||||
{
|
||||
m_panels[i] = NULL;
|
||||
}
|
||||
|
||||
if(!DoesWindowClassExist(CLSNAME))
|
||||
if(!DoesWindowClassExist(CLSNAME))
|
||||
{
|
||||
RegisterClassEx(&Win32::CWindow::MakeWndClass(CLSNAME));
|
||||
}
|
||||
|
||||
// Create(WNDSTYLEEX, CLSNAME, APP_NAME, WNDSTYLE, Win32::CRect(0, 0, 320, 480), NULL, NULL);
|
||||
Create(WNDSTYLEEX, CLSNAME, APP_NAME, WNDSTYLE, Win32::CRect(0, 0, 200, 175), NULL, NULL);
|
||||
|
||||
Win32::CRect clientRect(0, 0, 320, 480);
|
||||
AdjustWindowRectEx(clientRect, WNDSTYLE, FALSE, WNDSTYLEEX);
|
||||
Create(WNDSTYLEEX, CLSNAME, APP_NAME, WNDSTYLE, clientRect, NULL, NULL);
|
||||
SetClassPtr();
|
||||
|
||||
SetTimer(m_hWnd, 0, 1000, NULL);
|
||||
@ -61,11 +69,13 @@ m_aboutButton(NULL)
|
||||
m_virtualMachine.OnNewFrame.connect(std::tr1::bind(&CMainWindow::OnNewFrame, this));
|
||||
m_virtualMachine.OnBufferWrite.connect(std::tr1::bind(&CMainWindow::OnBufferWrite, this, std::tr1::placeholders::_1));
|
||||
|
||||
m_virtualMachine.SetSpuHandler(std::tr1::bind(&CMainWindow::CreateHandler, m_handlerInfo[0].dllName));
|
||||
ChangeAudioPlugin(0);
|
||||
|
||||
m_timerLabel = new Win32::CStatic(m_hWnd, _T(""), SS_CENTER);
|
||||
m_titleLabel = new Win32::CStatic(m_hWnd, _T(""), SS_CENTER | SS_NOPREFIX);
|
||||
|
||||
m_placeHolder = new Win32::CStatic(m_hWnd, Win32::CRect(0, 0, 1, 1), SS_BLACKRECT);
|
||||
|
||||
m_nextButton = new Win32::CButton(_T(">>"), m_hWnd, Win32::CRect(0, 0, 1, 1));
|
||||
m_prevButton = new Win32::CButton(_T("<<"), m_hWnd, Win32::CRect(0, 0, 1, 1));
|
||||
m_pauseButton = new Win32::CButton(_T("Pause"), m_hWnd, Win32::CRect(0, 0, 1, 1));
|
||||
@ -77,7 +87,7 @@ m_aboutButton(NULL)
|
||||
VerticalLayoutContainer(
|
||||
LayoutExpression(Win32::CLayoutWindow::CreateTextBoxBehavior(100, 15, m_titleLabel)) +
|
||||
LayoutExpression(Win32::CLayoutWindow::CreateTextBoxBehavior(100, 15, m_timerLabel)) +
|
||||
LayoutExpression(CLayoutStretch::Create()) +
|
||||
LayoutExpression(Win32::CLayoutWindow::CreateCustomBehavior(300, 200, 1, 1, m_placeHolder)) +
|
||||
HorizontalLayoutContainer(
|
||||
LayoutExpression(Win32::CLayoutWindow::CreateTextBoxBehavior(100, 30, m_prevButton)) +
|
||||
LayoutExpression(CLayoutStretch::Create()) +
|
||||
@ -92,6 +102,7 @@ m_aboutButton(NULL)
|
||||
)
|
||||
);
|
||||
|
||||
//Create tray icon
|
||||
Win32::CTrayIcon* trayIcon = m_trayIconServer.Insert();
|
||||
trayIcon->SetIcon(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN)));
|
||||
trayIcon->SetTip(_T("PsfPlayer"));
|
||||
@ -99,12 +110,21 @@ m_aboutButton(NULL)
|
||||
m_trayIconServer.RegisterHandler(std::tr1::bind(&CMainWindow::OnTrayIconEvent, this,
|
||||
std::tr1::placeholders::_1, std::tr1::placeholders::_2));
|
||||
|
||||
//Create play list panel
|
||||
m_playlistPanel = new CPlaylistPanel(m_placeHolder->m_hWnd, m_playlist);
|
||||
m_playlistPanel->OnItemDblClick.connect(std::tr1::bind(&CMainWindow::OnPlaylistItemDblClick, this, std::tr1::placeholders::_1));
|
||||
|
||||
//Initialize panels
|
||||
m_panels[0] = m_playlistPanel;
|
||||
|
||||
CreateAudioPluginMenu();
|
||||
UpdateAudioPluginMenu();
|
||||
UpdateTimer();
|
||||
UpdateTitle();
|
||||
UpdateButtons();
|
||||
RefreshLayout();
|
||||
|
||||
m_panels[0]->Show(SW_SHOW);
|
||||
}
|
||||
|
||||
CMainWindow::~CMainWindow()
|
||||
@ -117,14 +137,42 @@ void CMainWindow::RefreshLayout()
|
||||
RECT rc = GetClientRect();
|
||||
m_layout->SetRect(rc.left + 10, rc.top + 10, rc.right - 10, rc.bottom - 10);
|
||||
m_layout->RefreshGeometry();
|
||||
|
||||
for(unsigned int i = 0; i < MAX_PANELS; i++)
|
||||
{
|
||||
CPanel* panel(m_panels[i]);
|
||||
if(panel != NULL)
|
||||
{
|
||||
panel->RefreshLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSoundHandler* CMainWindow::CreateHandler(const TCHAR* libraryPath)
|
||||
{
|
||||
typedef CSoundHandler* (*HandlerFactoryFunction)();
|
||||
HMODULE module = LoadLibrary(libraryPath);
|
||||
HandlerFactoryFunction handlerFactory = reinterpret_cast<HandlerFactoryFunction>(GetProcAddress(module, "HandlerFactory"));
|
||||
CSoundHandler* result = handlerFactory();
|
||||
CSoundHandler* result = NULL;
|
||||
try
|
||||
{
|
||||
HMODULE module = LoadLibrary(libraryPath);
|
||||
if(module == NULL)
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
HandlerFactoryFunction handlerFactory = reinterpret_cast<HandlerFactoryFunction>(GetProcAddress(module, "HandlerFactory"));
|
||||
if(handlerFactory == NULL)
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
result = handlerFactory();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
tstring errorMessage = _T("Couldn't create sound handler present in '") + tstring(libraryPath) + _T("'.");
|
||||
MessageBox(m_hWnd, errorMessage.c_str(), APP_NAME, 16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -196,6 +244,11 @@ long CMainWindow::OnSize(unsigned int type, unsigned int width, unsigned int hei
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CMainWindow::OnPlaylistItemDblClick(const char* path)
|
||||
{
|
||||
Load(path);
|
||||
}
|
||||
|
||||
void CMainWindow::OnTrayIconEvent(Win32::CTrayIcon* icon, LPARAM param)
|
||||
{
|
||||
switch(param)
|
||||
@ -297,7 +350,7 @@ void CMainWindow::ChangeAudioPlugin(unsigned int pluginIdx)
|
||||
{
|
||||
SPUHANDLER_INFO* handlerInfo = m_handlerInfo + pluginIdx;
|
||||
m_selectedAudioHandler = handlerInfo->id;
|
||||
m_virtualMachine.SetSpuHandler(std::tr1::bind(&CMainWindow::CreateHandler, handlerInfo->dllName));
|
||||
m_virtualMachine.SetSpuHandler(std::tr1::bind(&CMainWindow::CreateHandler, this, handlerInfo->dllName));
|
||||
UpdateAudioPluginMenu();
|
||||
}
|
||||
|
||||
@ -365,6 +418,9 @@ void CMainWindow::Load(const char* path)
|
||||
|
||||
}
|
||||
m_virtualMachine.Resume();
|
||||
|
||||
m_playlist.AddItem(path, m_tags);
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
catch(const exception& except)
|
||||
@ -374,6 +430,7 @@ void CMainWindow::Load(const char* path)
|
||||
MessageBox(m_hWnd, errorString.c_str(), NULL, 16);
|
||||
m_ready = false;
|
||||
}
|
||||
|
||||
UpdateTitle();
|
||||
UpdateButtons();
|
||||
UpdateTimer();
|
||||
|
@ -4,11 +4,14 @@
|
||||
#include "../PsfVm.h"
|
||||
#include "../PsfBase.h"
|
||||
#include "../PsfTags.h"
|
||||
#include "../Playlist.h"
|
||||
#include "win32/Window.h"
|
||||
#include "win32/Static.h"
|
||||
#include "win32/Button.h"
|
||||
#include "win32/Layouts.h"
|
||||
#include "win32/TrayIconServer.h"
|
||||
#include "Panel.h"
|
||||
#include "PlaylistPanel.h"
|
||||
|
||||
class CMainWindow : public Framework::Win32::CWindow
|
||||
{
|
||||
@ -24,6 +27,11 @@ protected:
|
||||
long OnTimer();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
MAX_PANELS = 1,
|
||||
};
|
||||
|
||||
struct SPUHANDLER_INFO
|
||||
{
|
||||
int id;
|
||||
@ -31,7 +39,7 @@ private:
|
||||
const TCHAR* dllName;
|
||||
};
|
||||
|
||||
static CSoundHandler* CreateHandler(const TCHAR*);
|
||||
CSoundHandler* CreateHandler(const TCHAR*);
|
||||
|
||||
void OnNewFrame();
|
||||
void OnBufferWrite(int);
|
||||
@ -41,6 +49,7 @@ private:
|
||||
void OnAbout();
|
||||
void Load(const char*);
|
||||
|
||||
void OnPlaylistItemDblClick(const char*);
|
||||
void OnTrayIconEvent(Framework::Win32::CTrayIcon*, LPARAM);
|
||||
void DisplayTrayMenu();
|
||||
void UpdateTimer();
|
||||
@ -55,6 +64,8 @@ private:
|
||||
Framework::Win32::CStatic* m_titleLabel;
|
||||
Framework::LayoutObjectPtr m_layout;
|
||||
|
||||
Framework::Win32::CStatic* m_placeHolder;
|
||||
|
||||
Framework::Win32::CButton* m_nextButton;
|
||||
Framework::Win32::CButton* m_prevButton;
|
||||
Framework::Win32::CButton* m_pauseButton;
|
||||
@ -63,10 +74,14 @@ private:
|
||||
|
||||
Framework::Win32::CTrayIconServer m_trayIconServer;
|
||||
|
||||
CPanel* m_panels[MAX_PANELS];
|
||||
CPlaylistPanel* m_playlistPanel;
|
||||
|
||||
HMENU m_popupMenu;
|
||||
|
||||
CPsfVm& m_virtualMachine;
|
||||
CPsfTags m_tags;
|
||||
CPlaylist m_playlist;
|
||||
bool m_ready;
|
||||
uint64 m_frames;
|
||||
int m_writes;
|
||||
|
16
tools/PsfPlayer/Source/win32_ui/Panel.h
Normal file
16
tools/PsfPlayer/Source/win32_ui/Panel.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _PANEL_H_
|
||||
#define _PANEL_H_
|
||||
|
||||
#include "win32/Window.h"
|
||||
|
||||
class CPanel : public Framework::Win32::CWindow
|
||||
{
|
||||
public:
|
||||
virtual ~CPanel() {}
|
||||
virtual void RefreshLayout() = 0;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif
|
150
tools/PsfPlayer/Source/win32_ui/PlaylistPanel.cpp
Normal file
150
tools/PsfPlayer/Source/win32_ui/PlaylistPanel.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
#include "PlaylistPanel.h"
|
||||
#include "win32/Rect.h"
|
||||
#include "TimeToString.h"
|
||||
#include "string_cast.h"
|
||||
|
||||
#define CLSNAME _T("PlaylistPanel")
|
||||
#define WNDSTYLE (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD)
|
||||
#define WNDSTYLEEX (0)
|
||||
#define WM_UPDATEVIS (WM_USER + 1)
|
||||
|
||||
using namespace Framework;
|
||||
|
||||
CPlaylistPanel::CPlaylistPanel(HWND parentWnd, CPlaylist& playlist)
|
||||
: m_playlistView(NULL)
|
||||
, m_playlist(playlist)
|
||||
, m_nextListViewKey(0)
|
||||
{
|
||||
if(!DoesWindowClassExist(CLSNAME))
|
||||
{
|
||||
RegisterClassEx(&Win32::CWindow::MakeWndClass(CLSNAME));
|
||||
}
|
||||
|
||||
Create(WNDSTYLEEX, CLSNAME, _T(""), WNDSTYLE, Win32::CRect(0, 0, 1, 1), parentWnd, NULL);
|
||||
SetClassPtr();
|
||||
|
||||
m_playlistView = new Win32::CListView(m_hWnd, Win32::CRect(0, 0, 1, 1), LVS_REPORT | LVS_SORTASCENDING);
|
||||
m_playlistView->SetExtendedListViewStyle(m_playlistView->GetExtendedListViewStyle() | LVS_EX_FULLROWSELECT);
|
||||
|
||||
CreateColumns();
|
||||
|
||||
m_playlist.OnItemChange.connect(std::tr1::bind(&CPlaylistPanel::OnPlaylistItemChange, this, std::tr1::placeholders::_1));
|
||||
|
||||
m_nextListViewKey = 0;
|
||||
}
|
||||
|
||||
CPlaylistPanel::~CPlaylistPanel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
long CPlaylistPanel::OnNotify(WPARAM wParam, NMHDR* hdr)
|
||||
{
|
||||
if(CWindow::IsNotifySource(m_playlistView, hdr))
|
||||
{
|
||||
switch(hdr->code)
|
||||
{
|
||||
case NM_DBLCLK:
|
||||
OnPlaylistViewDblClick(reinterpret_cast<NMITEMACTIVATE*>(hdr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CPlaylistPanel::OnPlaylistViewDblClick(NMITEMACTIVATE* itemActivate)
|
||||
{
|
||||
if(itemActivate->iItem == -1) return;
|
||||
uint32 param = m_playlistView->GetItemData(itemActivate->iItem);
|
||||
ListViewKeyMap::right_const_iterator keyIterator = m_listViewKeys.right.find(param);
|
||||
assert(keyIterator != m_listViewKeys.right.end());
|
||||
if(keyIterator != m_listViewKeys.right.end())
|
||||
{
|
||||
OnItemDblClick(keyIterator->second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void CPlaylistPanel::AddItem(uint32 key, const TCHAR* title, const TCHAR* length)
|
||||
{
|
||||
LVITEM item;
|
||||
memset(&item, 0, sizeof(LVITEM));
|
||||
item.pszText = const_cast<TCHAR*>(title);
|
||||
item.lParam = key;
|
||||
item.mask = LVIF_TEXT | LVIF_PARAM;
|
||||
int itemIdx = m_playlistView->InsertItem(&item);
|
||||
|
||||
// m_playlist->SetItemText(itemIndex, 1, TimeToString<std::tstring>(length).c_str());
|
||||
m_playlistView->SetItemText(itemIdx, 1, length);
|
||||
}
|
||||
|
||||
void CPlaylistPanel::ModifyItem(uint32 key, const TCHAR* title, const TCHAR* length)
|
||||
{
|
||||
int itemIdx = m_playlistView->FindItemData(key);
|
||||
assert(itemIdx != -1);
|
||||
if(itemIdx == -1) return;
|
||||
|
||||
m_playlistView->SetItemText(itemIdx, 0, title);
|
||||
m_playlistView->SetItemText(itemIdx, 1, length);
|
||||
}
|
||||
|
||||
void CPlaylistPanel::CreateColumns()
|
||||
{
|
||||
LVCOLUMN column;
|
||||
memset(&column, 0, sizeof(LVCOLUMN));
|
||||
column.pszText = _T("Title");
|
||||
column.mask = LVCF_TEXT;
|
||||
m_playlistView->InsertColumn(0, &column);
|
||||
|
||||
memset(&column, 0, sizeof(LVCOLUMN));
|
||||
column.pszText = _T("Length");
|
||||
column.mask = LVCF_TEXT;
|
||||
m_playlistView->InsertColumn(1, &column);
|
||||
}
|
||||
|
||||
void CPlaylistPanel::OnPlaylistItemChange(const CPlaylist::PlaylistItemMapIterator& itemIterator)
|
||||
{
|
||||
const CPlaylist::PLAYLIST_ITEM& item(itemIterator->second);
|
||||
|
||||
std::tstring title, length;
|
||||
title = string_cast<std::tstring>(item.title);
|
||||
length = TimeToString<std::tstring>(item.length);
|
||||
|
||||
ListViewKeyMap::left_const_iterator keyIterator(m_listViewKeys.left.find(itemIterator->first));
|
||||
if(keyIterator == m_listViewKeys.left.end())
|
||||
{
|
||||
//Element
|
||||
uint32 newKey = ++m_nextListViewKey;
|
||||
m_listViewKeys.insert(ListViewKeyMap::value_type(itemIterator->first, newKey));
|
||||
AddItem(newKey, title.c_str(), length.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 key = keyIterator->second;
|
||||
ModifyItem(key, title.c_str(), length.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void CPlaylistPanel::RefreshLayout()
|
||||
{
|
||||
//Resize panel
|
||||
{
|
||||
Win32::CRect clientRect(0, 0, 0, 0);
|
||||
::GetClientRect(GetParent(), clientRect);
|
||||
SetSizePosition(clientRect);
|
||||
}
|
||||
|
||||
//Resize list view
|
||||
{
|
||||
Win32::CRect clientRect(0, 0, 0, 0);
|
||||
GetClientRect(clientRect);
|
||||
m_playlistView->SetSizePosition(clientRect);
|
||||
}
|
||||
|
||||
//Resize columns
|
||||
{
|
||||
RECT clientRect = m_playlistView->GetClientRect();
|
||||
|
||||
m_playlistView->SetColumnWidth(0, 3 * clientRect.right / 4);
|
||||
m_playlistView->SetColumnWidth(1, 1 * clientRect.right / 4);
|
||||
}
|
||||
}
|
40
tools/PsfPlayer/Source/win32_ui/PlaylistPanel.h
Normal file
40
tools/PsfPlayer/Source/win32_ui/PlaylistPanel.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef _PLAYLISTPANEL_H_
|
||||
#define _PLAYLISTPANEL_H_
|
||||
|
||||
#include "Panel.h"
|
||||
#include "Playlist.h"
|
||||
#include "win32/ListView.h"
|
||||
#include <boost/bimap.hpp>
|
||||
|
||||
class CPlaylistPanel : public CPanel, public boost::signals::trackable
|
||||
{
|
||||
public:
|
||||
typedef boost::signal<void (const char*)> OnItemDblClickEvent;
|
||||
|
||||
CPlaylistPanel(HWND, CPlaylist&);
|
||||
virtual ~CPlaylistPanel();
|
||||
|
||||
void RefreshLayout();
|
||||
|
||||
OnItemDblClickEvent OnItemDblClick;
|
||||
|
||||
protected:
|
||||
long OnNotify(WPARAM, NMHDR*);
|
||||
|
||||
private:
|
||||
typedef boost::bimap<std::string, unsigned int> ListViewKeyMap;
|
||||
|
||||
void CreateColumns();
|
||||
void OnPlaylistItemChange(const CPlaylist::PlaylistItemMapIterator&);
|
||||
void AddItem(uint32, const TCHAR*, const TCHAR*);
|
||||
void ModifyItem(uint32, const TCHAR*, const TCHAR*);
|
||||
void OnPlaylistViewDblClick(NMITEMACTIVATE*);
|
||||
|
||||
CPlaylist& m_playlist;
|
||||
Framework::Win32::CListView* m_playlistView;
|
||||
ListViewKeyMap m_listViewKeys;
|
||||
|
||||
uint32 m_nextListViewKey;
|
||||
};
|
||||
|
||||
#endif
|
26
tools/PsfPlayer/Source/win32_ui/TimeToString.h
Normal file
26
tools/PsfPlayer/Source/win32_ui/TimeToString.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _TIMETOSTRING_H_
|
||||
#define _TIMETOSTRING_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
template <typename StringType>
|
||||
static StringType TimeToString(double time)
|
||||
{
|
||||
// StringType result, separator;
|
||||
StringType separator;
|
||||
separator += ':';
|
||||
unsigned int secs = static_cast<unsigned int>(time) % 60;
|
||||
unsigned int mins = static_cast<unsigned int>(time) / 60;
|
||||
std::basic_stringstream<StringType::value_type> result;
|
||||
result << mins << separator;
|
||||
result.width(2);
|
||||
result.fill('0');
|
||||
result << secs;
|
||||
// result =
|
||||
// boost::lexical_cast<StringType>(mins) +
|
||||
// separator +
|
||||
// boost::lexical_cast<StringType>(secs);
|
||||
return result.str();
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user