571 lines
13 KiB
C
Executable File
571 lines
13 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* This program is free software ; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* $Id: playlist.c 332 2005-11-06 14:31:57Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../../common/common.h"
|
|
#include "../win.h"
|
|
#include "playlst.h"
|
|
#include "openfile_win32.h"
|
|
#include "resource.h"
|
|
|
|
#if defined(TARGET_WINCE) || defined(TARGET_WIN32)
|
|
|
|
#ifndef STRICT
|
|
#define STRICT
|
|
#endif
|
|
#include <windows.h>
|
|
#if _MSC_VER > 1000
|
|
#pragma warning(disable : 4201)
|
|
#endif
|
|
#include <commctrl.h>
|
|
|
|
#define MSG_PLAYER2 WM_APP + 0x300
|
|
|
|
typedef struct playlistwin
|
|
{
|
|
win Win;
|
|
HWND WndList;
|
|
int DlgWidth[3];
|
|
player* Player;
|
|
DWORD ThreadId;
|
|
int Pos;
|
|
int Current;
|
|
bool_t InUpdate;
|
|
|
|
} playlistwin;
|
|
|
|
static const datatable Params[] =
|
|
{
|
|
{ PLAYLIST_WIDTH_NAME, TYPE_INT, DF_SETUP|DF_HIDDEN },
|
|
{ PLAYLIST_WIDTH_LENGTH,TYPE_INT, DF_SETUP|DF_HIDDEN },
|
|
{ PLAYLIST_WIDTH_URL, TYPE_INT, DF_SETUP|DF_HIDDEN },
|
|
|
|
DATATABLE_END(PLAYLIST_ID)
|
|
};
|
|
|
|
static void UpdateList(playlistwin* p)
|
|
{
|
|
tchar_t s[256];
|
|
tchar_t s2[256];
|
|
LVITEM Item;
|
|
tick_t Length;
|
|
int i;
|
|
int Count=0;
|
|
p->Current = -1;
|
|
|
|
p->Player->Get(p->Player,PLAYER_LIST_COUNT,&Count,sizeof(int));
|
|
p->Player->Get(p->Player,PLAYER_LIST_CURRENT,&p->Current,sizeof(int));
|
|
|
|
i = ListView_GetItemCount(p->WndList);
|
|
while (i > Count)
|
|
ListView_DeleteItem(p->WndList,--i);
|
|
|
|
Item.mask=LVIF_TEXT;
|
|
Item.pszText=T("");
|
|
Item.cchTextMax=1;
|
|
Item.iSubItem=0;
|
|
|
|
while (i < Count)
|
|
{
|
|
Item.iItem = i++;
|
|
ListView_InsertItem(p->WndList,&Item);
|
|
}
|
|
|
|
for (i=0;i<Count;++i)
|
|
{
|
|
s[0] = 0;
|
|
p->Player->Get(p->Player,PLAYER_LIST_AUTOTITLE+i,s,sizeof(s));
|
|
|
|
ListView_GetItemText(p->WndList,i,0,s2,256);
|
|
if (tcscmp(s,s2)!=0)
|
|
ListView_SetItemText(p->WndList,i,0,s);
|
|
|
|
Length = -1;
|
|
p->Player->Get(p->Player,PLAYER_LIST_LENGTH+i,&Length,sizeof(int));
|
|
if (Length>=0)
|
|
TickToString(s,TSIZEOF(s),Length,0,0,0);
|
|
else
|
|
s[0] = 0;
|
|
ListView_GetItemText(p->WndList,i,1,s2,256);
|
|
if (tcscmp(s,s2)!=0)
|
|
ListView_SetItemText(p->WndList,i,1,s);
|
|
|
|
s[0] = 0;
|
|
p->Player->Get(p->Player,PLAYER_LIST_URL+i,s,sizeof(s));
|
|
ListView_GetItemText(p->WndList,i,2,s2,256);
|
|
if (tcscmp(s,s2)!=0)
|
|
ListView_SetItemText(p->WndList,i,2,s);
|
|
}
|
|
}
|
|
|
|
static int Enum(playlistwin* p, int* No, datadef* Param )
|
|
{
|
|
return NodeEnumTable(No,Param,Params);
|
|
}
|
|
|
|
static int Get(playlistwin* p,int No,void* Data,int Size)
|
|
{
|
|
int Result = ERR_INVALID_PARAM;
|
|
switch (No)
|
|
{
|
|
case PLAYLIST_WIDTH_NAME: GETVALUE(p->DlgWidth[0],int); break;
|
|
case PLAYLIST_WIDTH_LENGTH: GETVALUE(p->DlgWidth[1],int); break;
|
|
case PLAYLIST_WIDTH_URL: GETVALUE(p->DlgWidth[2],int); break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static int Set(playlistwin* p,int No,const void* Data,int Size)
|
|
{
|
|
int Result = ERR_INVALID_PARAM;
|
|
switch (No)
|
|
{
|
|
case PLAYLIST_WIDTH_NAME: SETVALUE(p->DlgWidth[0],int,ERR_NONE); break;
|
|
case PLAYLIST_WIDTH_LENGTH: SETVALUE(p->DlgWidth[1],int,ERR_NONE); break;
|
|
case PLAYLIST_WIDTH_URL: SETVALUE(p->DlgWidth[2],int,ERR_NONE); break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static int GetColWidth(playlistwin* p, int Index)
|
|
{
|
|
int cx = ListView_GetColumnWidth(p->WndList,Index);
|
|
return WinPixelToUnitX(&p->Win,cx);
|
|
}
|
|
|
|
static void AddCol(playlistwin* p, int Index, const tchar_t* Name, int Width, int Format )
|
|
{
|
|
LVCOLUMN Col;
|
|
Col.mask=LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
|
|
Col.cx=WinUnitToPixelX(&p->Win,Width);
|
|
Col.pszText=(tchar_t*)Name;
|
|
Col.cchTextMax=tcslen(Name)+1;
|
|
Col.fmt=Format;
|
|
|
|
ListView_InsertColumn(p->WndList,Index,&Col);
|
|
}
|
|
|
|
static void CreateButtons(playlistwin* p)
|
|
{
|
|
if (QueryPlatform(PLATFORM_TYPENO) != TYPE_SMARTPHONE)
|
|
{
|
|
WinBitmap(&p->Win,IDB_PLAYLIST16,IDB_PLAYLIST32,5);
|
|
WinAddButton(&p->Win,-1,-1,NULL,0);
|
|
WinAddButton(&p->Win,PLAYLIST_ADD_FILES,2,NULL,0);
|
|
WinAddButton(&p->Win,PLAYLIST_UP,0,NULL,0);
|
|
WinAddButton(&p->Win,PLAYLIST_DOWN,1,NULL,0);
|
|
WinAddButton(&p->Win,PLAYLIST_DELETE,3,NULL,0);
|
|
//WinAddButton(&p->Win,PLAYLIST_PLAY,4,NULL,0);
|
|
}
|
|
}
|
|
|
|
static void Resize(playlistwin* p)
|
|
{
|
|
RECT r;
|
|
GetClientRect(p->Win.Wnd,&r);
|
|
|
|
r.top += p->Win.ToolBarHeight;
|
|
MoveWindow(p->WndList,r.left,r.top,r.right-r.left,r.bottom-r.top,0);
|
|
}
|
|
|
|
static int GetPos(playlistwin* p)
|
|
{
|
|
int n;
|
|
for (n=0;n<ListView_GetItemCount(p->WndList);++n)
|
|
if (ListView_GetItemState(p->WndList,n,LVIS_FOCUSED)==LVIS_FOCUSED)
|
|
return n;
|
|
return -1;
|
|
}
|
|
|
|
static int ListNotify(playlistwin* p,int Param,int Param2)
|
|
{
|
|
if (p->Win.Wnd)
|
|
PostMessage(p->Win.Wnd,MSG_PLAYER2,0,0);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void BeginUpdate(playlistwin* p)
|
|
{
|
|
notify Notify;
|
|
Notify.Func = NULL;
|
|
Notify.This = 0;
|
|
|
|
p->Player->Set(p->Player,PLAYER_LIST_NOTIFY,&Notify,sizeof(Notify));
|
|
|
|
p->Pos = GetPos(p);
|
|
p->InUpdate = 1;
|
|
}
|
|
|
|
static void EndUpdate(playlistwin* p)
|
|
{
|
|
int n;
|
|
notify Notify;
|
|
Notify.Func = ListNotify;
|
|
Notify.This = p;
|
|
p->Player->Set(p->Player,PLAYER_LIST_NOTIFY,&Notify,sizeof(Notify));
|
|
|
|
UpdateList(p);
|
|
|
|
for (n=0;n<ListView_GetItemCount(p->WndList);++n)
|
|
ListView_SetItemState(p->WndList,n,n==p->Pos?LVIS_FOCUSED|LVIS_SELECTED:0,LVIS_FOCUSED|LVIS_SELECTED);
|
|
|
|
if (p->Pos>=n || p->Pos<0)
|
|
{
|
|
ListView_SetItemState(p->WndList,0,LVIS_FOCUSED,LVIS_FOCUSED);
|
|
p->Pos = 0;
|
|
}
|
|
|
|
ListView_EnsureVisible(p->WndList,p->Pos,TRUE);
|
|
p->InUpdate = 0;
|
|
}
|
|
|
|
static void Play(playlistwin* p, int i)
|
|
{
|
|
bool_t b;
|
|
node* Format;
|
|
|
|
p->Player->Set(p->Player,PLAYER_LIST_CURRENT,&i,sizeof(i));
|
|
|
|
// only play when loading succeeded
|
|
if (p->Player->Get(p->Player,PLAYER_FORMAT,&Format,sizeof(Format)) == ERR_NONE && Format)
|
|
{
|
|
b = 1;
|
|
p->Player->Set(p->Player,PLAYER_PLAY,&b,sizeof(b));
|
|
}
|
|
|
|
WinClose(&p->Win);
|
|
}
|
|
|
|
static bool_t Proc(playlistwin* p,int Msg, uint32_t wParam, uint32_t lParam, int* Result)
|
|
{
|
|
LPNMLISTVIEW Notify;
|
|
int i,j,n;
|
|
int Style;
|
|
bool_t b;
|
|
node* Node;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_KEYDOWN:
|
|
if (wParam == VK_ESCAPE)
|
|
WinClose(&p->Win);
|
|
break;
|
|
|
|
case MSG_PLAYER2:
|
|
if (p->WndList)
|
|
{
|
|
p->InUpdate = 1;
|
|
UpdateList(p);
|
|
p->InUpdate = 0;
|
|
}
|
|
return 1;
|
|
|
|
case WM_COMMAND:
|
|
|
|
i = LOWORD(wParam);
|
|
|
|
switch (i)
|
|
{
|
|
case PLAYLIST_DELETE:
|
|
BeginUpdate(p);
|
|
|
|
if (p->Player->Get(p->Player,PLAYER_LIST_COUNT,&j,sizeof(j))==ERR_NONE)
|
|
{
|
|
for (n=ListView_GetItemCount(p->WndList)-1;n>=0;--n)
|
|
if (ListView_GetItemState(p->WndList,n,LVIS_SELECTED)==LVIS_SELECTED)
|
|
{
|
|
for (i=n;i<j-1;++i)
|
|
p->Player->ListSwap(p->Player,i,i+1);
|
|
--j;
|
|
if (p->Pos>n || p->Pos>=j) --p->Pos;
|
|
}
|
|
|
|
p->Player->Set(p->Player,PLAYER_LIST_COUNT,&j,sizeof(j));
|
|
}
|
|
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_UP:
|
|
BeginUpdate(p);
|
|
if (p->Pos>0)
|
|
{
|
|
p->Player->ListSwap(p->Player,p->Pos,p->Pos-1);
|
|
--p->Pos;
|
|
}
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_DOWN:
|
|
BeginUpdate(p);
|
|
if (p->Pos>=0 && p->Player->Get(p->Player,PLAYER_LIST_COUNT,&j,sizeof(j))==ERR_NONE && p->Pos<j-1)
|
|
{
|
|
p->Player->ListSwap(p->Player,p->Pos,p->Pos+1);
|
|
++p->Pos;
|
|
}
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_PLAY:
|
|
Play(p,GetPos(p));
|
|
break;
|
|
|
|
case PLAYLIST_SORTBYNAME:
|
|
BeginUpdate(p);
|
|
if (p->Player->Get(p->Player,PLAYER_LIST_COUNT,&j,sizeof(j))==ERR_NONE)
|
|
{
|
|
// bubble sort sucks :)
|
|
do
|
|
{
|
|
b = 0;
|
|
for (i=0;i<j-1;++i)
|
|
{
|
|
tchar_t URL1[MAXPATH];
|
|
tchar_t URL2[MAXPATH];
|
|
|
|
if (p->Player->Get(p->Player,PLAYER_LIST_URL+i,URL1,sizeof(URL1))==ERR_NONE &&
|
|
p->Player->Get(p->Player,PLAYER_LIST_URL+i+1,URL2,sizeof(URL2))==ERR_NONE &&
|
|
tcsicmp(URL1,URL2)>0)
|
|
{
|
|
if (p->Pos == i)
|
|
p->Pos = i+1;
|
|
else
|
|
if (p->Pos == i+1)
|
|
p->Pos = i;
|
|
|
|
p->Player->ListSwap(p->Player,i,i+1);
|
|
b = 1;
|
|
}
|
|
}
|
|
}
|
|
while (b);
|
|
}
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_DELETE_ALL:
|
|
BeginUpdate(p);
|
|
i = 0;
|
|
p->Player->Set(p->Player,PLAYER_LIST_COUNT,&i,sizeof(i));
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_SAVE:
|
|
BeginUpdate(p);
|
|
|
|
Node = NodeCreate(OPENFILE_ID);
|
|
if (Node)
|
|
{
|
|
i = OPENFLAG_SINGLE | OPENFLAG_SAVE;
|
|
Node->Set(Node,OPENFILE_FLAGS,&i,sizeof(i));
|
|
i = PLAYLIST_CLASS;
|
|
Node->Set(Node,OPENFILE_CLASS,&i,sizeof(i));
|
|
((win*)Node)->Popup((win*)Node,&p->Win);
|
|
NodeDelete(Node);
|
|
}
|
|
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_LOAD:
|
|
BeginUpdate(p);
|
|
|
|
Node = NodeCreate(OPENFILE_ID);
|
|
if (Node)
|
|
{
|
|
i = OPENFLAG_SINGLE;
|
|
Node->Set(Node,OPENFILE_FLAGS,&i,sizeof(i));
|
|
i = PLAYLIST_CLASS;
|
|
Node->Set(Node,OPENFILE_CLASS,&i,sizeof(i));
|
|
i = ((win*)Node)->Popup((win*)Node,&p->Win);
|
|
NodeDelete(Node);
|
|
if (i==2)
|
|
{
|
|
UpdateWindow(p->Win.Wnd);
|
|
i=0;
|
|
p->Player->Set(p->Player,PLAYER_LIST_CURRIDX,&i,sizeof(i));
|
|
}
|
|
}
|
|
|
|
p->Pos = -1;
|
|
p->Player->Get(p->Player,PLAYER_LIST_CURRENT,&p->Pos,sizeof(int));
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case PLAYLIST_ADD_FILES:
|
|
BeginUpdate(p);
|
|
|
|
Node = NodeCreate(OPENFILE_ID);
|
|
if (Node)
|
|
{
|
|
i = OPENFLAG_ADD;
|
|
Node->Set(Node,OPENFILE_FLAGS,&i,sizeof(i));
|
|
i = MEDIA_CLASS;
|
|
Node->Set(Node,OPENFILE_CLASS,&i,sizeof(i));
|
|
((win*)Node)->Popup((win*)Node,&p->Win);
|
|
NodeDelete(Node);
|
|
}
|
|
|
|
p->Pos = -1;
|
|
p->Player->Get(p->Player,PLAYER_LIST_CURRENT,&p->Pos,sizeof(int));
|
|
EndUpdate(p);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CREATE:
|
|
|
|
p->InUpdate = 1;
|
|
p->ThreadId = GetCurrentThreadId();
|
|
p->Player = (player*)Context()->Player;
|
|
|
|
p->Pos = -1;
|
|
p->Player->Get(p->Player,PLAYER_LIST_CURRENT,&p->Pos,sizeof(int));
|
|
|
|
Style = WS_TABSTOP|WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_HSCROLL|LVS_REPORT|LVS_SHOWSELALWAYS;
|
|
if (p->Win.ScreenWidth < 130)
|
|
Style |= LVS_NOCOLUMNHEADER;
|
|
|
|
p->WndList = CreateWindow(T("SysListView32"), NULL, Style,
|
|
0,0,20,20, p->Win.Wnd, NULL, p->Win.Module, NULL);
|
|
|
|
ListView_SetExtendedListViewStyle(p->WndList,LVS_EX_FULLROWSELECT);
|
|
|
|
AddCol(p,0,LangStr(PLAYLIST_ID,PLAYLIST_LABEL_NAME),max(15,p->DlgWidth[0]),LVCFMT_LEFT);
|
|
AddCol(p,1,LangStr(PLAYLIST_ID,PLAYLIST_LABEL_LENGTH),max(15,p->DlgWidth[1]),LVCFMT_LEFT);
|
|
AddCol(p,2,LangStr(PLAYLIST_ID,PLAYLIST_LABEL_URL),max(15,p->DlgWidth[2]),LVCFMT_LEFT);
|
|
|
|
CreateButtons(p);
|
|
Resize(p);
|
|
|
|
EndUpdate(p);
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
SetFocus(p->WndList);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
BeginUpdate(p);
|
|
p->DlgWidth[0] = GetColWidth(p,0);
|
|
p->DlgWidth[1] = GetColWidth(p,1);
|
|
p->DlgWidth[2] = GetColWidth(p,2);
|
|
p->ThreadId = 0;
|
|
p->WndList = NULL;
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
Resize(p);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
Notify = (LPNMLISTVIEW) lParam;
|
|
|
|
if (Notify->hdr.hwndFrom == p->WndList && !p->InUpdate)
|
|
{
|
|
if (Notify->hdr.code==LVN_ITEMACTIVATE)
|
|
Play(p,Notify->iItem);
|
|
|
|
if (Notify->hdr.code==LVN_KEYDOWN && ((LPNMLVKEYDOWN)lParam)->wVKey == VK_ESCAPE)
|
|
WinClose(&p->Win);
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static menudef MenuDef[] =
|
|
{
|
|
{ 0,PLATFORM_ID, PLATFORM_DONE },
|
|
{ 0,PLAYLIST_ID, PLAYLIST_FILE },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_ADD_FILES },
|
|
{ 1,-1,-1 },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_PLAY },
|
|
{ 1,-1,-1 },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_DELETE },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_DELETE_ALL },
|
|
{ 1,-1,-1 },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_SORTBYNAME },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_UP },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_DOWN },
|
|
{ 1,-1,-1 },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_LOAD },
|
|
{ 1,PLAYLIST_ID, PLAYLIST_SAVE },
|
|
|
|
MENUDEF_END
|
|
};
|
|
|
|
WINCREATE(PlayList)
|
|
|
|
static int Create(playlistwin* p)
|
|
{
|
|
PlayListCreate(&p->Win);
|
|
|
|
if (!p->Win.Smartphone)
|
|
p->DlgWidth[0] = 145;
|
|
else
|
|
p->DlgWidth[0] = 92;
|
|
p->DlgWidth[1] = 40;
|
|
p->DlgWidth[2] = 200;
|
|
|
|
p->Win.WinWidth = 180;
|
|
p->Win.WinHeight = 240;
|
|
|
|
p->Win.MenuDef = MenuDef;
|
|
p->Win.Proc = Proc;
|
|
|
|
p->Win.Node.Enum = Enum;
|
|
p->Win.Node.Get = Get;
|
|
p->Win.Node.Set = Set;
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void Delete(playlistwin* p)
|
|
{
|
|
#ifdef REGISTRY_GLOBAL
|
|
NodeRegSave(&p->Win.Node);
|
|
#endif
|
|
}
|
|
|
|
static const nodedef PlayListWin =
|
|
{
|
|
sizeof(playlistwin)|CF_GLOBAL,
|
|
PLAYLIST_ID,
|
|
WIN_CLASS,
|
|
PRI_DEFAULT,
|
|
(nodecreate)Create,
|
|
(nodedelete)Delete,
|
|
};
|
|
|
|
void PlaylistWin_Init()
|
|
{
|
|
NodeRegisterClass(&PlayListWin);
|
|
}
|
|
|
|
void PlaylistWin_Done()
|
|
{
|
|
NodeUnRegisterClass(PLAYLIST_ID);
|
|
}
|
|
|
|
#endif
|