1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
#include "main.h"
#include <bfc/dispatch.h>
#include <windowsx.h>
#include "shlobj.h"
#include "..\..\General\gen_ml\ml_ipc_0313.h"
#include "..\..\General\gen_ml\childwnd.h"
#include "../Winamp/wa_dlg.h"
#include "../xml/ifc_xmlreadercallback.h"
#include "../xml/obj_xml.h"
#include <api/service/waServiceFactory.h>
#include "resource.h"
#include "api.h"
typedef void (*ChildResizeFunc)(HWND, ChildWndResizeItem*, int);
static ChildResizeFunc ml_childresize_init=0, ml_childresize_resize=0;
typedef int (*HookDialogFunc)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static HookDialogFunc ml_hook_dialog_msg = 0;
typedef void (*DrawFunc)(HWND hwndDlg, int *tab, int tabsize);
static DrawFunc ml_draw = 0;
LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
static HWND m_hwnd;
static ChildWndResizeItem xmlwnd_rlist[]={
{IDC_LIST,0x0011},
{IDC_LOAD,0x0101},
};
//--------------------------
class ListXMLLoader : public ifc_xmlreadercallback
{
public:
ListXMLLoader(HWND _hwndList) : hwndList(_hwndList), index(0) {}
void loadSongFromXml(const wchar_t* filename, const wchar_t* artist, const wchar_t* title)
{
LVITEM lvi = {0, };
lvi.mask = LVIF_TEXT;
lvi.iItem = index;
lvi.pszText = (LPTSTR)filename;
lvi.cchTextMax = lstrlenW(filename);
SendMessage(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
lvi.iSubItem = 1;
lvi.pszText = (LPTSTR)artist;
lvi.cchTextMax = lstrlenW(artist);
SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi);
lvi.iSubItem = 2;
lvi.pszText = (LPTSTR)title;
lvi.cchTextMax = lstrlenW(title);
SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi);
index++;
}
void reset()
{
ListView_DeleteAllItems(hwndList);
index = 0;
}
void loadXML(wchar_t []);
/* XML loader callback */
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
{
//read subtags of LIBRARY
if(!wcsicmp(xmlpath, L"LIBRARY\fSONG"))
{
//getItemValue() will return the value for an attribute
loadSongFromXml(params->getItemValue(L"FILENAME"), params->getItemValue(L"ARTIST"),params->getItemValue(L"TITLE"));
}
}
private:
HWND hwndList;
int index;
protected: // this is a Wasabi object, so we need to declare a dispatch table
RECVS_DISPATCH;
};
/* Dispatch table for a Wasabi object */
#define CBCLASS ListXMLLoader
START_DISPATCH;
VCB(ONSTARTELEMENT, StartTag)
END_DISPATCH;
#undef CBCLASS
/* helper function for ListXMLLoader::loadXML */
static bool LoadFile(obj_xml *parser, const wchar_t *filename)
{
HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (file == INVALID_HANDLE_VALUE)
return false;
char data[1024];
DWORD bytesRead;
while (true)
{
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
{
parser->xmlreader_feed(data, bytesRead);
}
else
break;
}
CloseHandle(file);
parser->xmlreader_feed(0, 0);
return true;
}
void ListXMLLoader::loadXML(wchar_t xmlfile[MAX_PATH] = L"xmltest.xml")
{
// reset the listview state
reset();
// get an XML parser object from the service manager
obj_xml *parser=0;
waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
if (parserFactory)
parser = (obj_xml *)parserFactory->getInterface();
if (parser)
{
//set up a tag that we can read
//within StartTag(), we can read all subtags of this tag
parser->xmlreader_registerCallback(L"LIBRARY\f*", this);
parser->xmlreader_open();
LoadFile(parser, xmlfile);
parser->xmlreader_unregisterCallback(this);
parser->xmlreader_close();
parserFactory->releaseInterface(parser);
}
}
//--------------------------
/* This function gets called directly from gen_ml when it wants our plugin to do something
we're only handling dialog creation, but there are lots of other messages a full-featured
plugin would deal with */
INT_PTR xmlex_pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
{
if (message_type == ML_MSG_TREE_ONCREATEVIEW && param1 == xmlex_treeItem)
{
return (INT_PTR)CreateDialog(plugin.hDllInstance, MAKEINTRESOURCE(IDD_VIEW_XMLEX), (HWND)(LONG_PTR)param2, (DLGPROC)view_xmlexDialogProc);
}
return 0;
}
static BOOL xmlex_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
/* gen_ml has some helper functions to deal with skinned dialogs,
we're going to grab their function pointers.
for definition of magic numbers, see gen_ml/ml.h */
if (!ml_childresize_init)
{
/* skinning helper functions */
ml_hook_dialog_msg = (HookDialogFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)2, ML_IPC_SKIN_WADLG_GETFUNC);
ml_draw = (DrawFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)3, ML_IPC_SKIN_WADLG_GETFUNC);
/* resizing helper functions */
ml_childresize_init = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)32, ML_IPC_SKIN_WADLG_GETFUNC);
ml_childresize_resize = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)33, ML_IPC_SKIN_WADLG_GETFUNC);
}
m_hwnd=hwnd;
HWND listWnd = GetDlgItem(hwnd,IDC_LIST);
/* add listview columns */
LVCOLUMN lvc = {0, };
lvc.mask = LVCF_TEXT | LVCF_WIDTH;
lvc.pszText = (LPTSTR)L"Filename";
lvc.cx = 250;
SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)0, (LPARAM)&lvc);
lvc.pszText = (LPTSTR)L"Artist";
lvc.cx = 150;
SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)1, (LPARAM)&lvc);
lvc.pszText = (LPTSTR)L"Title";
lvc.cx = 150;
SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)2, (LPARAM)&lvc);
/* skin dialog */
MLSKINWINDOW sw;
sw.skinType = SKINNEDWND_TYPE_DIALOG;
sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT;
sw.hwndToSkin = hwnd;
MLSkinWindow(plugin.hwndLibraryParent, &sw);
/* skin listview */
sw.hwndToSkin = listWnd;
sw.skinType = SKINNEDWND_TYPE_LISTVIEW;
sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
MLSkinWindow(plugin.hwndLibraryParent, &sw);
/* skin button */
sw.skinType = SKINNEDWND_TYPE_BUTTON;
sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT;
sw.hwndToSkin = GetDlgItem(hwnd, IDC_LOAD);
MLSkinWindow(plugin.hwndLibraryParent, &sw);
ml_childresize_init(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0]));
//all other initialization is done. lets wait 20ms before we actually do anything with this plugin
//this way other (more important) things finish before this does
SetTimer(hwnd,101,20,NULL);
return FALSE;
}
static BOOL xmlex_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
if (state != SIZE_MINIMIZED)
ml_childresize_resize(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0]));
return FALSE;
}
static BOOL xmlex_OnDestroy(HWND hwnd)
{
m_hwnd=0;
return FALSE;
}
static void xmlex_OnTimer(HWND hwnd, UINT id)
{
if (id == 101)
{
KillTimer(hwnd,101);
// populate list with default local file, no pre-loaded xml file if not in working dir (really will only pre-load something in debug mode)
ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST));
loader.loadXML();
}
}
static BOOL xmlex_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id) {
case IDC_LOAD:
{
wchar_t filename[256] = L"";
//browse box supported in windows 2000+
//if this doesnt work for you (old versions of windows) just know that the file name is set in ofn.lpstrFile which is then moved to filename variable
OPENFILENAME ofn = {0};
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner=hwnd;
ofn.lpstrFilter=L"XML Files (*.xml)\0*.XML\0\0";
ofn.lpstrCustomFilter=NULL;
ofn.nFilterIndex=1;
ofn.lpstrFile=filename; //contains file name after user has selected it
ofn.nMaxFile=MAX_PATH;
ofn.lpstrFileTitle=NULL;
ofn.lpstrInitialDir=NULL;
ofn.Flags=OFN_PATHMUSTEXIST;
GetOpenFileName(&ofn);
if(*filename) //do not load on browse -> cancel
{
ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST));
loader.loadXML(filename);
}
}
break;
}
return 0;
}
LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
/* first, ask the dialog skinning system if it wants to do anything with the message
the function pointer gets set during WM_INITDIALOG so might be NULL for the first few messages
in theory we could grab it right here if we don't have it, but it's not necessary
and I wanted to put all the function pointer gathering code in the same place for this example */
if (ml_hook_dialog_msg)
{
INT_PTR a = ml_hook_dialog_msg(hwndDlg, uMsg, wParam, lParam);
if (a)
return a;
}
switch(uMsg) {
HANDLE_MSG(hwndDlg, WM_INITDIALOG, xmlex_OnInitDialog);
HANDLE_MSG(hwndDlg, WM_TIMER, xmlex_OnTimer);
HANDLE_MSG(hwndDlg, WM_COMMAND, xmlex_OnCommand);
HANDLE_MSG(hwndDlg, WM_SIZE, xmlex_OnSize);
case WM_PAINT:
{
int tab[] = { IDC_LIST|DCW_SUNKENBORDER};
ml_draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
}
return 0;
HANDLE_MSG(hwndDlg, WM_DESTROY, xmlex_OnDestroy);
}
return FALSE;
}
|