Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,144 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_VIEW_EX DIALOG DISCARDABLE 0, 0, 291, 274
STYLE DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "List4",IDC_LIST,"SysListView32",LVS_REPORT |
LVS_SHOWSELALWAYS | LVS_OWNERDATA | WS_TABSTOP,0,13,289,
246
LTEXT "",IDC_STATUS,41,262,248,8
LTEXT "Search:",IDC_STATIC,0,1,26,8
EDITTEXT IDC_QUICKSEARCH,26,1,263,10,ES_AUTOHSCROLL | NOT
WS_BORDER
CONTROL "Config",IDC_BUTTON_CONFIG,"Button",BS_OWNERDRAW |
WS_TABSTOP,2,261,35,11
END
IDD_CONFIG DIALOG DISCARDABLE 0, 0, 200, 97
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Ex Configuration"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,76,50,14
PUSHBUTTON "Cancel",IDCANCEL,143,76,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_VIEW_EX, DIALOG
BEGIN
RIGHTMARGIN, 289
END
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 193
TOPMARGIN, 7
BOTTOMMARGIN, 90
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// French (France) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
#ifdef _WIN32
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_CONTEXTMENUS MENU DISCARDABLE
BEGIN
POPUP "TreeItemContext"
BEGIN
MENUITEM "About Ex..", ID_ABOUT
MENUITEM "Ex Configuration...", ID_CONFIG
END
END
#endif // French (France) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,152 @@
# Microsoft Developer Studio Project File - Name="ml_ex" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=ml_ex - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ml_ex.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ml_ex.mak" CFG="ml_ex - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ml_ex - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "ml_ex - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "ml_ex - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ML_ex_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ML_ex_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "NDEBUG"
# ADD RSC /l 0x40c /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /machine:I386 /out:"c:\progra~1\winamp\plugins\ml_ex.dll" /opt:nowin98
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "ml_ex - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ML_ex_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ML_ex_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "_DEBUG"
# ADD RSC /l 0x40c /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /debug /machine:I386 /out:"c:\progra~1\winamp\plugins\ml_ex.dll" /pdbtype:sept
!ENDIF
# Begin Target
# Name "ml_ex - Win32 Release"
# Name "ml_ex - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\itemlist.cpp
# End Source File
# Begin Source File
SOURCE=..\listview.cpp
# End Source File
# Begin Source File
SOURCE=..\ml_lib.cpp
# End Source File
# Begin Source File
SOURCE=.\view_ex.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\childwnd.h
# End Source File
# Begin Source File
SOURCE=..\..\winamp\ipc_pe.h
# End Source File
# Begin Source File
SOURCE=..\itemlist.h
# End Source File
# Begin Source File
SOURCE=..\listview.h
# End Source File
# Begin Source File
SOURCE=..\ml.h
# End Source File
# Begin Source File
SOURCE=..\..\winamp\wa_dlg.h
# End Source File
# Begin Source File
SOURCE=..\..\winamp\wa_ipc.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\ex.rc
# End Source File
# End Group
# End Target
# End Project

View file

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "ml_ex"=.\ml_ex.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View file

@ -0,0 +1,62 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by ex.rc
//
#define IDD_DIALOG1 101
#define IDR_CONTEXTMENUS 102
#define IDD_SEND_FILES 103
#define IDD_CONFIG 104
#define IDD_EDIT_INFO 105
#define IDD_VIEW_IPOD 221
#define IDD_VIEW_NJB 221
#define IDD_VIEW_EX 221
#define IDD_INIT 222
#define IDC_PROGRESS1 1000
#define IDC_STATUS 1001
#define IDC_EDIT_ARTIST 1002
#define IDC_PROGRESS2 1002
#define IDC_CHECK_ARTIST 1003
#define IDC_CHECK_TITLE 1004
#define IDC_CHECK_ALBUM 1005
#define IDC_QUICKSEARCH 1006
#define IDC_CHECK_TRACK 1006
#define IDC_CHECK_GENRE 1007
#define IDC_CHECK_YEAR 1008
#define IDC_EDIT_TITLE 1009
#define IDC_EDIT_ALBUM 1010
#define IDC_BUTTON_AUTODETECT 1010
#define IDC_EDIT_TRACK 1011
#define IDC_CHECK1 1011
#define IDC_EDIT_GENRE 1012
#define IDC_DETECTDUPS 1012
#define IDC_EDIT_YEAR 1013
#define IDC_CURTRACKNAME 1013
#define IDC_BUTTON_PLAY 1016
#define IDC_BUTTON_ENQUEUE 1017
#define IDC_BUTTON_REFRESH 1018
#define IDC_BUTTON_CONFIG 1018
#define IDC_IPODSTATUS 1030
#define IDC_LIST 1031
#define IDC_COMBO1 1032
#define IDC_COMBO2 1033
#define IDC_TEXT_GENRE 1039
#define IDC_TEXT_BITRATE 1040
#define ID_IPODWND_REMOVEFROMIPOD 40001
#define ID_IPODTREEITEMCONTEXT_ABOUTIPOD 40002
#define ID_ABOUT 40002
#define ID_IPODTREEITEMCONTEXT_IPODCONFIGURATION 40003
#define ID_CONFIG 40003
#define ID_IPODWND_EDITITEMSINFORMATIONS 40004
#define ID_IPODWND_PLAYSELECTEDFILES 40013
#define ID_IPODWND_ENQUEUESELECTEDFILES 40014
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_COMMAND_VALUE 40005
#define _APS_NEXT_CONTROL_VALUE 1014
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,888 @@
/*
** Copyright (C) 2003 Nullsoft, Inc.
**
** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
** liable for any damages arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
** alter it and redistribute it freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
**
** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
**
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include "../ml.h"
#include "resource.h"
#include "../listview.h"
#include "../childwnd.h"
#include "../../winamp/wa_dlg.h"
#include "../itemlist.h"
// configuration section in winamp.ini
#define CONFIG_SEC "ml_ex"
// columns in our big treeview
#define COL_ARTIST 0
#define COL_TITLE 1
#define COL_ALBUM 2
#define COL_LENGTH 3
#define COL_TRACK 4
#define COL_GENRE 5
#define COL_YEAR 6
#define COL_FILENAME 7
// makes a NULL char * an empty string
#define MAKESAFE(x) ((x)?(x):"")
// yes, we could easily use an itemRecord / itemRecordList here instead of 'Song's, but the point of this example
// is to show how to integrate with some other native structure
typedef struct
{
char *artist;
char *title;
char *album;
int songlen; // seconds?
int track_nr;
char *genre;
int year;
char *filename;
} Song;
// our leading crap reduction agent for use with sorting/etc
#define SKIP_THE_AND_WHITESPACE(x) { while (!isalnum(*x) && *x) x++; if (!_strnicmp(x,"the ",4)) x+=4; while (*x == ' ') x++; }
extern winampMediaLibraryPlugin plugin;
static int myParam; // param of our tree item
static C_ItemList m_songs, *m_songs_sorted;
static W_ListView m_list;
static HWND m_hwnd;
static HMENU m_context_menus;
static int m_skinlistview_handle;
void config(HWND parent);
void sortResults();
static void deleteSongPtr(Song *song)
{
free(song->album);
free(song->artist);
free(song->title);
free(song->genre);
free(song->filename);
free(song);
}
static void clearSongList()
{
int i=m_songs.GetSize();
while (i>0)
{
Song *song=(Song *)m_songs.Get(--i);
deleteSongPtr(song);
m_songs.Del(i);
}
}
// this doesnt actually alloc the memory for all the strings, just references them (so it is only temporarily valid at best)
void SongsToItemList(itemRecordList *p, int all)
{
if (!m_hwnd) all=1;
p->Alloc=p->Size=0;
p->Items=0;
C_ItemList *list=(C_ItemList *)m_songs_sorted;
if (!list) { list=&m_songs; all=1; }
int x,l=list->GetSize();
for (x = 0 ; x < l; x ++)
{
if (!all && !m_list.GetSelected(x)) continue;
allocRecordList(p,p->Size+1,256);
if (!p->Items) break;
Song *s=(Song *)list->Get(x);
memset(&p->Items[p->Size],0,sizeof(itemRecord));
p->Items[p->Size].album=s->album;
p->Items[p->Size].artist=s->artist;
p->Items[p->Size].title=s->title;
p->Items[p->Size].genre=s->genre;
p->Items[p->Size].filename=s->filename;
p->Items[p->Size].track=s->track_nr;
p->Items[p->Size].year=s->year;
p->Items[p->Size].length=s->songlen;
p->Size++;
}
}
static void playFiles(int enqueue, int all)
{
if (!m_songs_sorted) return;
if (!m_hwnd && !all) return;
itemRecordList obj={0,};
SongsToItemList(&obj,all);
if (obj.Size)
{
mlSendToWinampStruct s={ML_TYPE_ITEMRECORDLIST,(void*)&obj,!!enqueue};
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_SENDTOWINAMP);
}
free(obj.Items);
}
void addItemListToSongs(itemRecordList *p)
{
if (p) for (int x = 0 ; x < p->Size; x ++)
{
Song *s=(Song *)calloc(1,sizeof(Song));
if (p->Items[x].album) s->album=_strdup(p->Items[x].album);
if (p->Items[x].artist) s->artist=_strdup(p->Items[x].artist);
if (p->Items[x].title) s->title=_strdup(p->Items[x].title);
if (p->Items[x].genre) s->genre=_strdup(p->Items[x].genre);
if (p->Items[x].filename) s->filename=_strdup(p->Items[x].filename);
s->track_nr=p->Items[x].track;
s->year=p->Items[x].year;
s->songlen=p->Items[x].length;
m_songs.Add((void*)s);
}
}
char *conf_file;
int init() {
mlAddTreeItemStruct mla={
0, // if you used 0, it would put it on top level, or ML_TREEVIEW_ID_DEVICES
"Item Cache Example",
1,
};
conf_file=(char*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILE); // get winamp.ini name :)
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&mla,ML_IPC_ADDTREEITEM);
myParam=mla.this_id;
m_context_menus=LoadMenu(plugin.hDllInstance,MAKEINTRESOURCE(IDR_CONTEXTMENUS));
return 0;
}
void quit()
{
clearSongList();
}
void loadSongList()
{
clearSongList();
// populate m_songs from whatever source we have
Song *p=(Song *)calloc(sizeof(Song),1);
p->filename = _strdup("http://www.firehose.net/~deadbeef/media/Misc/music/030223%20-%20pervert-in-a-satellite.mp3");
p->album=_strdup("SEP");
p->artist=_strdup("Nullsoft Band");
p->genre=_strdup("Shit");
p->songlen = 666;
p->track_nr=1;
p->title=_strdup("Pervert In A Satellite");
p->year=2003;
m_songs.Add((void*)p);
}
// this is uberadvancedsearchtechnology[tm]
static void parsequicksearch(char *out, char *in) // parses a list into a list of terms that we are searching for
{
int inquotes=0, neednull=0;
while (*in)
{
char c=*in++;
if (c != ' ' && c != '\t' && c != '\"')
{
neednull=1;
*out++=c;
}
else if (c == '\"')
{
inquotes=!inquotes;
if (!inquotes)
{
*out++=0;
neednull=0;
}
}
else
{
if (inquotes) *out++=c;
else if (neednull)
{
*out++=0;
neednull=0;
}
}
}
*out++=0;
*out++=0;
}
static int in_string(char *string, char *substring)
{
if (!string) return 0;
if (!*substring) return 1;
int l=strlen(substring);
while (string[0]) if (!_strnicmp(string++,substring,l)) return 1;
return 0;
}
static void updateList()
{
if(!m_hwnd) return;
char filterstr[256],filteritems[300];
GetDlgItemText(m_hwnd,IDC_QUICKSEARCH,filterstr,sizeof(filterstr)-1);
parsequicksearch(filteritems,filterstr);
delete m_songs_sorted;
m_songs_sorted=new C_ItemList;
unsigned int totallen=0,filterlen=0,filterval=0;
for(int i=0;i<m_songs.GetSize();i++)
{
Song *s=(Song *)m_songs.Get(i);
totallen+=s->songlen;
char year[32]="";
if (s->year < 5000 && s->year > 0) sprintf(year,"%d",s->year);
char *p=filteritems;
if (*p)
{
while (*p)
{
// search for 'p' in the song
if (!in_string(s->album,p) && !in_string(s->artist,p) && !in_string(s->title,p) && !in_string(s->genre,p) && !in_string(year,p))
break;
p+=strlen(p)+1;
}
if (*p) continue;
}
filterval++;
filterlen+=s->songlen;
m_songs_sorted->Add((void *)s);
}
sortResults();
char tmp[512];
if (m_songs.GetSize() != m_songs_sorted->GetSize())
wsprintf(tmp,"Found: %d items [%d:%02d:%02d]",
m_songs_sorted->GetSize(),filterval,
filterlen/3600,(filterlen/60)%60,filterlen%60);
else
wsprintf(tmp,"%d items [%d:%02d:%02d]",m_songs.GetSize(),totallen/3600,(totallen/60)%60,totallen%60);
SetDlgItemText(m_hwnd,IDC_STATUS,tmp);
}
static ChildWndResizeItem resize_rlist[]={
{IDC_QUICKSEARCH,0x0010},
{IDC_LIST,0x0011},
{IDC_BUTTON_CONFIG,0x0101},
{IDC_STATUS,0x0111}
};
int g_sortcol, g_sortdir;
static int STRCMP_NULLOK(const char *pa, const char *pb)
{
if (!pa) pa="";
else SKIP_THE_AND_WHITESPACE(pa)
if (!pb) pb="";
else SKIP_THE_AND_WHITESPACE(pb)
return _stricmp(pa,pb);
}
static int sortFunc(const void *elem1, const void *elem2)
{
Song *a=(Song *)*(void **)elem1;
Song *b=(Song *)*(void **)elem2;
int use_by=g_sortcol;
int use_dir=g_sortdir;
#define RETIFNZ(v) if ((v)<0) return use_dir?1:-1; if ((v)>0) return use_dir?-1:1;
// this might be too slow, but it'd be nice
int x;
for (x = 0; x < 4; x ++)
{
if (use_by == COL_YEAR) // year -> artist -> album -> track
{
int v1=a->year;
int v2=b->year;
if (v1<0)v1=0;
if (v2<0)v2=0;
RETIFNZ(v1-v2)
use_by=COL_ARTIST;
}
else if (use_by == COL_TITLE) // title -> artist -> album -> track
{
int v=STRCMP_NULLOK(a->title,b->title);
RETIFNZ(v)
use_by=COL_ARTIST;
}
else if (use_by == COL_ARTIST) // artist -> album -> track -> title
{
int v=STRCMP_NULLOK(a->artist,b->artist);
RETIFNZ(v)
use_by=COL_ALBUM;
}
else if (use_by == COL_ALBUM) // album -> track -> title -> artist
{
int v=STRCMP_NULLOK(a->album,b->album);
RETIFNZ(v)
use_dir=0;
use_by=COL_TRACK;
}
else if (use_by == COL_GENRE) // genre -> artist -> album -> track
{
int v=STRCMP_NULLOK(a->genre,b->genre);
RETIFNZ(v)
use_by=COL_ARTIST;
}
else if (use_by == COL_TRACK) // track -> title -> artist -> album
{
int v1=a->track_nr;
int v2=b->track_nr;
if (v1<0)v1=0;
if (v2<0)v2=0;
RETIFNZ(v1-v2)
use_by=COL_TITLE;
}
else if (use_by == COL_LENGTH) // length -> artist -> album -> track
{
int v1=a->songlen;
int v2=b->songlen;
if (v1<0)v1=0;
if (v2<0)v2=0;
RETIFNZ(v1-v2)
use_by=COL_ARTIST;
}
else break; // no sort order?
}
#undef RETIFNZ
return 0;
}
void sortResults()
{
if (!m_songs_sorted) return;
qsort(m_songs_sorted->GetAll(),m_songs_sorted->GetSize(),sizeof(void*),sortFunc);
ListView_SetItemCount(m_list.getwnd(),0);
ListView_SetItemCount(m_list.getwnd(),m_songs_sorted->GetSize());
ListView_RedrawItems(m_list.getwnd(),0,m_songs_sorted->GetSize()-1);
}
int (*wad_getColor)(int idx);
int (*wad_handleDialogMsgs)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void (*wad_DrawChildWindowBorders)(HWND hwndDlg, int *tab, int tabsize);
void (*cr_init)(HWND hwndDlg, ChildWndResizeItem *list, int num);
void (*cr_resize)(HWND hwndDlg, ChildWndResizeItem *list, int num);
static BOOL CALLBACK dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
if (wad_handleDialogMsgs)
{
BOOL a=wad_handleDialogMsgs(hwndDlg,uMsg,wParam,lParam); if (a) return a;
}
switch (uMsg)
{
case WM_DISPLAYCHANGE:
ListView_SetTextColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMFG):RGB(0xff,0xff,0xff));
ListView_SetBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
ListView_SetTextBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
m_list.refreshFont();
return 0;
case WM_INITDIALOG:
m_hwnd=hwndDlg;
*(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
*(void **)&wad_handleDialogMsgs=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,2,ML_IPC_SKIN_WADLG_GETFUNC);
*(void **)&wad_DrawChildWindowBorders=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,3,ML_IPC_SKIN_WADLG_GETFUNC);
*(void **)&cr_init=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,32,ML_IPC_SKIN_WADLG_GETFUNC);
// woof: *(void **)&cr_resize=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,33,ML_IPC_SKIN_WADLG_GETFUNC);
if (cr_init) cr_init(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0]));
m_list.setLibraryParentWnd(plugin.hwndLibraryParent);
m_list.setwnd(GetDlgItem(hwndDlg,IDC_LIST));
m_list.AddCol("Artist",200);
m_list.AddCol("Title",200);
m_list.AddCol("Album",200);
m_list.AddCol("Length",64);
m_list.AddCol("Track #",64);
m_list.AddCol("Genre",100);
m_list.AddCol("Year",64);
m_list.AddCol("Filename",80);
ListView_SetTextColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMFG):RGB(0xff,0xff,0xff));
ListView_SetBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
ListView_SetTextBkColor(m_list.getwnd(),wad_getColor?wad_getColor(WADLG_ITEMBG):RGB(0x00,0x00,0x00));
g_sortdir=GetPrivateProfileInt(CONFIG_SEC,"sortdir",0,conf_file);
g_sortcol=GetPrivateProfileInt(CONFIG_SEC,"sortcol",g_sortcol,conf_file);
m_skinlistview_handle=SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(int)m_list.getwnd(),ML_IPC_SKIN_LISTVIEW);
SetTimer(hwndDlg,32,50,NULL);
return 0;
case WM_NOTIFY:
{
LPNMHDR l=(LPNMHDR)lParam;
if (l->idFrom==IDC_LIST)
{
if (l->code == NM_DBLCLK)
{
playFiles(!!(GetAsyncKeyState(VK_SHIFT)&0x8000),0);
}
else if (l->code == LVN_BEGINDRAG)
{
SetCapture(hwndDlg);
}
else if (l->code == LVN_ODFINDITEM) // yay we find an item (for kb shortcuts)
{
NMLVFINDITEM *t = (NMLVFINDITEM *)lParam;
int i=t->iStart;
if (i >= m_songs_sorted->GetSize()) i=0;
int cnt=m_songs_sorted->GetSize()-i;
if (t->lvfi.flags & LVFI_WRAP) cnt+=i;
while (cnt-->0)
{
Song *thissong = (Song *)m_songs_sorted->Get(i);
char tmp[128];
char *name=0;
switch (g_sortcol)
{
case COL_ARTIST: name=thissong->artist; break;
case COL_TITLE: name=thissong->title; break;
case COL_ALBUM: name=thissong->album; break;
case COL_LENGTH:
wsprintf(tmp,"%d:%02d",thissong->songlen/60,(thissong->songlen)%60); name=tmp;
break;
case COL_TRACK: if (thissong->track_nr > 0 && thissong->track_nr < 1000) { wsprintf(tmp,"%d",thissong->track_nr); name=tmp; } break;
case COL_GENRE: name=thissong->genre; break;
case COL_YEAR: if (thissong->year < 5000 && thissong->year > 0) { wsprintf(tmp,"%d",thissong->year); name=tmp; } break;
case COL_FILENAME: name=thissong->filename; break;
}
if (!name) name="";
else SKIP_THE_AND_WHITESPACE(name)
if (t->lvfi.flags & (4|LVFI_PARTIAL))
{
if (!_strnicmp(name,t->lvfi.psz,strlen(t->lvfi.psz)))
{
SetWindowLong(hwndDlg,DWL_MSGRESULT,i);
return 1;
}
}
else if (t->lvfi.flags & LVFI_STRING)
{
if (!_stricmp(name,t->lvfi.psz))
{
SetWindowLong(hwndDlg,DWL_MSGRESULT,i);
return 1;
}
}
else
{
SetWindowLong(hwndDlg,DWL_MSGRESULT,-1);
return 1;
}
if (++i == m_songs_sorted->GetSize()) i=0;
}
SetWindowLong(hwndDlg,DWL_MSGRESULT,-1);
return 1;
}
else if (l->code == LVN_GETDISPINFO)
{
NMLVDISPINFO *lpdi = (NMLVDISPINFO*) lParam;
int item=lpdi->item.iItem;
if (item < 0 || item >= m_songs_sorted->GetSize()) return 0;
Song *thissong = (Song *)m_songs_sorted->Get(item);
if (lpdi->item.mask & (LVIF_TEXT|/*LVIF_IMAGE*/0)) // we can always do images too :)
{
if (lpdi->item.mask & LVIF_TEXT)
{
char tmpbuf[128];
char *nameptr=0;
switch (lpdi->item.iSubItem)
{
case COL_ARTIST: nameptr=thissong->artist; break;
case COL_TITLE: nameptr=thissong->title; break;
case COL_ALBUM: nameptr=thissong->album; break;
case COL_LENGTH:
wsprintf(tmpbuf,"%d:%02d",thissong->songlen/60,(thissong->songlen)%60); nameptr=tmpbuf;
break;
case COL_TRACK: if (thissong->track_nr > 0 && thissong->track_nr < 1000) { wsprintf(tmpbuf,"%d",thissong->track_nr); nameptr=tmpbuf; } break;
case COL_GENRE: nameptr=thissong->genre; break;
case COL_YEAR: if (thissong->year>0 && thissong->year<5000) { wsprintf(tmpbuf,"%d",thissong->year); nameptr=tmpbuf; } break;
case COL_FILENAME: nameptr=thissong->filename; break;
}
if (nameptr) lstrcpyn(lpdi->item.pszText,nameptr,lpdi->item.cchTextMax);
else lpdi->item.pszText[0]=0;
}
// if(lpdi->item.mask & LVIF_IMAGE)
} // bother
return 0;
} // LVN_GETDISPINFO
else if (l->code == LVN_COLUMNCLICK)
{
NMLISTVIEW *p=(NMLISTVIEW*)lParam;
if (p->iSubItem == g_sortcol) g_sortdir=!g_sortdir;
else g_sortcol=p->iSubItem;
char str[32];
sprintf(str,"%d",g_sortdir);
WritePrivateProfileString(CONFIG_SEC,"sortdir",str,conf_file);
sprintf(str,"%d",g_sortcol);
WritePrivateProfileString(CONFIG_SEC,"sortcol",str,conf_file);
sortResults();
}
}
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BUTTON_CONFIG:
config(hwndDlg);
break;
case IDC_QUICKSEARCH:
if (HIWORD(wParam) == EN_CHANGE)
{
KillTimer(hwndDlg,500);
SetTimer(hwndDlg,500,150,NULL);
}
break;
}
break;
case WM_TIMER:
if (wParam == 500)
{
KillTimer(hwndDlg,500);
char buf[256];
GetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf,sizeof(buf));
buf[255]=0;
WritePrivateProfileString(CONFIG_SEC,"lastfilter",buf,conf_file);
updateList();
}
else if (wParam == 32)
{
KillTimer(hwndDlg,32);
if (!m_songs.GetSize()) loadSongList();
char buf[256];
GetPrivateProfileString(CONFIG_SEC,"lastfilter","",buf,sizeof(buf),conf_file);
SetDlgItemText(hwndDlg,IDC_QUICKSEARCH,buf); // automatically updates the list via EN_CHANGE
}
break;
case WM_SIZE:
#if 0 // BP:
if (wParam != SIZE_MINIMIZED)
{
if (cr_resize) cr_resize(hwndDlg,resize_rlist,sizeof(resize_rlist)/sizeof(resize_rlist[0]));
}
#endif
break;
case WM_PAINT:
{
if (wad_DrawChildWindowBorders)
{
int tab[] = { IDC_QUICKSEARCH|DCW_SUNKENBORDER, IDC_LIST|DCW_SUNKENBORDER};
wad_DrawChildWindowBorders(hwndDlg,tab,2);
}
}
return 0;
case WM_DESTROY:
//clearSongList();
m_hwnd=NULL;
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,m_skinlistview_handle,ML_IPC_UNSKIN_LISTVIEW);
return 0;
case WM_ML_CHILDIPC:
if (lParam == ML_CHILDIPC_DROPITEM && wParam)
{
mlDropItemStruct *t=(mlDropItemStruct*)wParam;
if (t->type == ML_TYPE_ITEMRECORDLIST) t->result=1;
if (t->data)
{
if (t->type == ML_TYPE_ITEMRECORDLIST) // we got a drag&drop to our window, hot!
{
addItemListToSongs((itemRecordList*)t->data);
updateList();
}
}
}
return 0;
case WM_LBUTTONUP:
if (GetCapture() == hwndDlg)
{
ReleaseCapture();
POINT p;
p.x=GET_X_LPARAM(lParam);
p.y=GET_Y_LPARAM(lParam);
ClientToScreen(hwndDlg,&p);
HWND h=WindowFromPoint(p);
if (h != hwndDlg && !IsChild(hwndDlg,h))
{
mlDropItemStruct m={ML_TYPE_ITEMRECORDLIST,NULL,0};
m.p=p;
m.flags=ML_HANDLEDRAG_FLAG_NOCURSOR;
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
if (m.result>0)
{
itemRecordList o={0,};
SongsToItemList(&o,0);
if (o.Size)
{
//fill in this itemCacheObject if you want to provide drag&drop out of the window
m.flags=0;
m.result=0;
m.data=(void*)&o;
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
}
free(o.Items);
}
}
}
break;
case WM_MOUSEMOVE:
if (GetCapture()==hwndDlg)
{
POINT p;
p.x=GET_X_LPARAM(lParam);
p.y=GET_Y_LPARAM(lParam);
ClientToScreen(hwndDlg,&p);
mlDropItemStruct m={ML_TYPE_ITEMRECORDLIST,NULL,0};
m.p=p;
HWND h=WindowFromPoint(p);
if (!h || h == hwndDlg || IsChild(hwndDlg,h))
{
SetCursor(LoadCursor(NULL,IDC_NO));
}
else
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDRAG);
}
break;
}
return 0;
}
static BOOL CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
// save combo box
case IDCANCEL:
EndDialog(hwndDlg,LOWORD(wParam) == IDOK);
break;
}
return 0;
}
return 0;
}
static void config(HWND parent)
{
DialogBox(plugin.hDllInstance,MAKEINTRESOURCE(IDD_CONFIG),parent,config_dlgproc);
}
int onTreeItemClick(int param, int action, HWND hwndParent) // if param is not yours, return 0
{
if (action == ML_ACTION_RCLICK)
{
POINT p;
GetCursorPos(&p);
int r=TrackPopupMenu(GetSubMenu(m_context_menus,0),TPM_RETURNCMD|TPM_RIGHTBUTTON|TPM_LEFTBUTTON|TPM_NONOTIFY,p.x,p.y,0,hwndParent,NULL);
switch (r)
{
case ID_ABOUT:
MessageBox(hwndParent,"ml_ex!!!","About ml_ex!!!",MB_OK);
break;
case ID_CONFIG:
config(hwndParent);
break;
}
}
return 1;
}
int onTreeItemDropTarget(int param, int type, void *obj)
{
if (type != ML_TYPE_ITEMRECORDLIST) return -1;
if (!obj) return 1;
// do somethihng with the itemCache object. do not free it however, since the caller owns it
addItemListToSongs((itemRecordList*)obj);
updateList();
return 1;
}
int onTreeItemDrag(int param, POINT p, int *type)
{
HWND h=WindowFromPoint(p);
if (h && (h == m_hwnd || IsChild(m_hwnd,h))) return -1; // prevent from dropping into ourselves
// if we wanted to be able to drag&drop our tree item to other people, we'd
// return 1 and set type to ML_TYPE_ITEMRECORDLIST or ML_TYPE_FILENAMES etc.
// *type = ML_TYPE_ITEMRECORDLIST;
return -1;
}
int onTreeItemDrop(int param, POINT p) // you should send the appropriate ML_IPC_HANDLEDROP if you support it
{
HWND h=WindowFromPoint(p);
if (h && (h == m_hwnd || IsChild(m_hwnd,h))) return -1; // prevent from dropping into ourselves
// if we wanted to be able to drag&drop our tree item to other people, we'd
// create an itemCacheObject or a doublenull terminated list (depending on what we want),
// and send it back to the media library so it can route it to the appropriate destination:
//
// itemCacheObject o={0,};
// fillInMyObject(&o);
// mlDropItemStruct m={0,};
// m.type = ML_TYPE_ITEMRECORDLIST;
// m.data = (void*)&o;
// m.p=p;
// SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
// freeMyObject(&o);
// or this:
itemRecordList o={0,};
SongsToItemList(&o,1);
if (o.Size)
{
mlDropItemStruct m={0,};
m.type = ML_TYPE_ITEMRECORDLIST;
m.data = (void*)&o;
m.p=p;
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&m,ML_IPC_HANDLEDROP);
}
free(o.Items);
return 1;
}
int PluginMessageProc(int message_type, int param1, int param2, int param3)
{
// check for any global messages here
if (message_type >= ML_MSG_TREE_BEGIN && message_type <= ML_MSG_TREE_END)
{
if (param1 != myParam) return 0;
// local messages for a tree item
switch (message_type)
{
case ML_MSG_TREE_ONCREATEVIEW:
return (int)CreateDialog(plugin.hDllInstance,MAKEINTRESOURCE(IDD_VIEW_EX),(HWND)param2,dlgproc);
case ML_MSG_TREE_ONCLICK:
return onTreeItemClick(param1,param2,(HWND)param3);
case ML_MSG_TREE_ONDROPTARGET:
return onTreeItemDropTarget(param1,param2,(void*)param3);
case ML_MSG_TREE_ONDRAG:
return onTreeItemDrag(param1,*(POINT*)param2,(int*)param3);
case ML_MSG_TREE_ONDROP:
return onTreeItemDrop(param1,*(POINT*)param2);
}
}
else if (message_type == ML_MSG_ONSENDTOBUILD)
{
if (param1 == ML_TYPE_ITEMRECORDLIST)
{
mlAddToSendToStruct s;
s.context=param2;
s.desc="ItemCacheEx";
s.user32=(int)PluginMessageProc;
SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_ADDTOSENDTO);
}
}
else if (message_type == ML_MSG_ONSENDTOSELECT)
{
if (param1 == ML_TYPE_ITEMRECORDLIST && param2 && param3 == (int)PluginMessageProc)
{
addItemListToSongs((itemRecordList*)param2);
updateList();
return 1;
}
}
return 0;
}
winampMediaLibraryPlugin plugin =
{
MLHDR_VER,
"ml_ex v0.1",
init,
quit,
PluginMessageProc,
};
extern "C" {
__declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
{
return &plugin;
}
};