Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: WSH Panel Mod (Read 815422 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

WSH Panel Mod

Reply #950
i have a very stupid question. is there some sort of introduction/tutorial/... available to get started with all this? i know how to code js/vbscript but i just have no clue how to even invoke the editor to edit something =)


When  you have read this topic and this link thru, then you know almost all about how to code in wsh, you have already big benefit, like you said you know how to code in js. I had to learn all of this from scratch.  But now i laugh how stupid i was six months ago


aha, it's all about the panel. i could have guessed that from the components name. well, thanks.

WSH Panel Mod

Reply #951
Maybe i found a bug:
Code: [Select]
window.MinWidth = window.Height;
window.MaxWidth = window.Height;

When I use this, window.Width is always 2 pixels smaller then window.Height. But i think they should be the same.
I noticed that this has to do with DUI border style: If you set border style to "none", then window.Width and window.Height have the same value. But if you set border style to "grey", then window.Width is 2 pixels smaller.

WSH Panel Mod

Reply #952
MeasureString bug

Apparently, the X and Height values of the rectangle computed by MeasureString() are wrong when the specified width of the rectangle has some specific values.  It is difficult to understand and explain exactly the problem, but this script demonstrates the bug:

Code: [Select]
DT_TOP = 0x00000000;
DT_LEFT = 0x00000000;
DT_CENTER = 0x00000001;
DT_RIGHT = 0x00000002;
DT_VCENTER = 0x00000004;
DT_BOTTOM = 0x00000008;
DT_WORDBREAK = 0x00000010;
DT_CALCRECT = 0x00000400;
DT_NOPREFIX = 0x00000800;
DT_END_ELLIPSIS = 0x00008000;

function RGB(r,g,b) {
    return (0xff000000|(r<<16)|(g<<8)|(b));
}

s = "The Plymouth Guildhall recording is sourced from an original soundboard tape. An audience bootleg recording of the show has been used to add ambience and to repair a missing intro section from Get Thy Bearings."
font = gdi.Font("Tahoma", 12, 0);
flags = DT_CENTER | DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX;
window.Repaint();

function print(gr, string, x, y, w, font, color, flags)
{
    rect = gr.MeasureString(string, font, x, y, w, 9999999999, flags);
    gr.DrawRect(rect.X, rect.Y, rect.Width, rect.Height, 1, RGB(255,0,0));
    gr.GdiDrawText(string, font, color, x, y, w, rect.Height+50, flags);
}
function on_paint(gr)
{
    ww = window.Width;
    print(gr, s, 4, 4, ww-8, font, RGB(0,0,0), flags);
    fb.trace(ww-8);
}

The red rectangle *should* be around the text, as it is drawn using the IMeasureStringInfo properties, but as you can see below, it's not the case.

The bug happens only when the window width has some specific values.  So, to reproduce it, you have to slowly resize the WSH window horizontally.

I'm running foobar 1.1 with CUI 0.3.8.6 and WSH 1.3.6, under Win7 X64.

Is it a known bug?  Is it a workaround to avoid it?

[EDIT] I forgot to write that the X bug happens only with DT_CENTER, but the Height bug happens also with DT_LEFT.

[EDIT2] I've found the problem.  MeasureString() works fine when the string is drawn using DrawString(), but it is not suitable for GdiDrawText().  Pity, as GdiDrawText() is faster, and DrawString() doesn't support the DT_CENTER flag.

So, my bug report is now a simple question: is it a way to accurately measure a string drawn with GdiDrawText()?  (I need to know only the height of the string).

WSH Panel Mod

Reply #953
CalcTextHeight(str, IGdiFont)

WSH Panel Mod

Reply #954
CalcTextHeight(str, IGdiFont)

Thanks, but that doesn't work for me.  I use DT_WORDBREAK with a specific maximum width, and CalcTextHeight doesn't take that into account.  OK, I know that it is theoretically possible to evaluate the number of lines produced by GdiDrawText, and multiply it by the height of a single line, but it's a complex operation.

But this is the correct way to compute the height.  (This function returns the Y position at the bottom of the string, but if you just need to compute the height of the string, just pass 0 for the y argument.)
Code: [Select]
var temp_bmp = gdi.CreateImage(1, 1);
var temp_gr = temp_bmp.GetGraphics();
function stringHeight(text, font, y, width, flags)
{
    var arr = temp_gr.GdiDrawText(text, font, 0xFFFFFFFF, 0, y, width, 1, DT_VCENTER|DT_CALCRECT|flags).toArray();
    return(y + arr[3] - arr[1]);
}

Unfortunately, the array returned by GdiDrawText() is correct only when DT_VCENTER (and DT_CALCRECT of course) are included in the font flags.  The fact that DT_VCENTER is mandatory is a pity, as it is necessary to write the string twice: the first time in a temp bitmap just to compute its height, and then in the window itself, without the flag.  Due to this restriction, I'm not sure GdiDrawText() is really faster than DrawString().  Anyway, I need GdiDrawText() as DrawString() ignores the DT_CENTER flag.

BTW, I wonder if it is necessary to release the resources (like temp_bmp, temp_gr and the font in my example) in the on_script_unload() callback, or if they are released automatically.  I suppose that they are released anyway when foobar is closed, but is it also the case when, for example, the script is edited, and therefore restarted?

WSH Panel Mod

Reply #955
I can't compile this under VS2010.

I patched the Columns UI SDK so that compiles fine now.

But I still got this issue:
MIDL2335: illegal expression type in constant FillGradRect

from script_interface.h:
Code: [Select]
[
    object,
    dual,
    pointer_default(unique),
    library_block,
    uuid("9d6e404f-5ba7-4470-88d5-eb5980dffc07")
]
__interface IGdiGraphics: IGdiObj
{
[propput] STDMETHOD(_ptr)(void * p);
STDMETHOD(FillSolidRect)(float x, float y, float w, float h, DWORD color);
STDMETHOD(FillGradRect)(float x, float y, float w, float h, float angle, DWORD color1,
DWORD color2, [defaultvalue(1.0)] float focus);
STDMETHOD(FillRoundRect)(float x, float y, float w, float h, float arc_width, float arc_height, DWORD color);
STDMETHOD(FillEllipse)(float x, float y, float w, float h, DWORD color);
STDMETHOD(FillPolygon)(DWORD color, [range(0, 1)]INT fillmode, VARIANT points);

STDMETHOD(DrawLine)(float x1, float y1, float x2, float y2, float line_width, DWORD color);
STDMETHOD(DrawRect)(float x, float y, float w, float h, float line_width, DWORD color);
STDMETHOD(DrawRoundRect)(float x, float y, float w, float h, float arc_width,
float arc_height, float line_width, DWORD color);
STDMETHOD(DrawEllipse)(float x, float y, float w, float h, float line_width, DWORD color);
STDMETHOD(DrawPolygon)(DWORD color, float line_width, VARIANT points);

STDMETHOD(DrawString)(BSTR str, IGdiFont* font, DWORD color, float x,
float y, float w, float h, [defaultvalue(0)] DWORD flags);
STDMETHOD(GdiDrawText)(BSTR str, IGdiFont * font, DWORD color, int x, int y, int w, int h,
[defaultvalue(0)] DWORD format, [out,retval] VARIANT * p);
STDMETHOD(DrawImage)(IGdiBitmap* image, float dstX, float dstY, float dstW, float dstH, float srcX, float srcY,
float srcW, float srcH, [defaultvalue(0)]float angle, [defaultvalue(255)]BYTE alpha);
STDMETHOD(GdiDrawBitmap)(IGdiRawBitmap * bitmap, int dstX, int dstY, int dstW,
int dstH, int srcX, int srcY, int srcW, int srcH);
STDMETHOD(GdiAlphaBlend)(IGdiRawBitmap * bitmap, int dstX, int dstY, int dstW, int dstH, int srcX,
int srcY, int srcW, int srcH, [defaultvalue(255)]BYTE alpha);
//STDMETHOD(GdiTransparentBlt)(IGdiRawBitmap * bitmap, int dstX, int dstY, int dstW, int dstH,
// int srcX, int srcY, int srcW, int srcH, DWORD color);
STDMETHOD(MeasureString)(BSTR str, IGdiFont * font, float x, float y, float w, float h,
[defaultvalue(0)] DWORD flags, [out,retval] IMeasureStringInfo ** pp);
STDMETHOD(CalcTextWidth)(BSTR str, IGdiFont * font, [out,retval] UINT * p);
STDMETHOD(CalcTextHeight)(BSTR str, IGdiFont * font, [out,retval] UINT * p);
STDMETHOD(EstimateLineWrap)(BSTR str, IGdiFont * font, int max_width, [out,retval] VARIANT * p);
STDMETHOD(SetTextRenderingHint)([range(Gdiplus::TextRenderingHintSystemDefault,
Gdiplus::TextRenderingHintClearTypeGridFit)] UINT mode);
STDMETHOD(SetSmoothingMode)([range(Gdiplus::SmoothingModeInvalid,
Gdiplus::SmoothingModeAntiAlias)] int mode);
STDMETHOD(SetInterpolationMode)([range(Gdiplus::InterpolationModeInvalid,
Gdiplus::InterpolationModeHighQualityBicubic)] int mode);
//STDMETHOD(SetCompositingMode)([range(Gdiplus::CompositingModeSourceOver,
// Gdiplus::CompositingModeSourceCopy)] UINT mode);
//STDMETHOD(SetCompositingQuality)([range(Gdiplus::CompositingQualityInvalid,
// Gdiplus::CompositingQualityAssumeLinear)] int mode);
};
_COM_SMARTPTR_TYPEDEF(IGdiGraphics, __uuidof(IGdiGraphics));

generated vc100.idl:
Code: [Select]

[
object,
dual,
pointer_default(unique),
custom(8AFCDA7F-33B7-3120-86A8-754D2C0C0578, "library_block"),
uuid(9d6e404f-5ba7-4470-88d5-eb5980dffc07)
]
#line 111 "h:\\fb2k-sdk\\foobar2000\\foo-wsh-panel-mod\\foo_uie_wsh_panel_mod\\script_interface.h"
interface IGdiGraphics : IGdiObj {
#line 113 "h:\\fb2k-sdk\\foobar2000\\foo-wsh-panel-mod\\foo_uie_wsh_panel_mod\\script_interface.h"
[propput] HRESULT  _ptr([in]void *p);
HRESULT  FillSolidRect([in]float x, [in]float y, [in]float w, [in]float h, [in]DWORD color);
HRESULT  FillGradRect([in]float x, [in]float y, [in]float w, [in]float h, [in]float angle,
[in]DWORD color1, [in]DWORD color2, [defaultvalue("1.000000")] float focus);
HRESULT  FillRoundRect([in]float x, [in]float y, [in]float w, [in]float h, [in]float arc_width,
[in]float arc_height, [in]DWORD color);
HRESULT  FillEllipse([in]float x, [in]float y, [in]float w, [in]float h, [in]DWORD color);
HRESULT  FillPolygon([in]DWORD color, [range(0, 1)] INT fillmode, [in]VARIANT points);
#line 120 "h:\\fb2k-sdk\\foobar2000\\foo-wsh-panel-mod\\foo_uie_wsh_panel_mod\\script_interface.h"
HRESULT  DrawLine([in]float x1, [in]float y1, [in]float x2, [in]float y2, [in]float line_width,
[in]DWORD color);
HRESULT  DrawRect([in]float x, [in]float y, [in]float w, [in]float h, [in]float line_width,
[in]DWORD color);
HRESULT  DrawRoundRect([in]float x, [in]float y, [in]float w, [in]float h, [in]float arc_width,
[in]float arc_height, [in]float line_width, [in]DWORD color);
HRESULT  DrawEllipse([in]float x, [in]float y, [in]float w, [in]float h, [in]float line_width,
[in]DWORD color);
HRESULT  DrawPolygon([in]DWORD color, [in]float line_width, [in]VARIANT points);
#line 126 "h:\\fb2k-sdk\\foobar2000\\foo-wsh-panel-mod\\foo_uie_wsh_panel_mod\\script_interface.h"
HRESULT  DrawString([in]BSTR str, [in]IGdiFont *font, [in]DWORD color, [in]float x,
[in]float y, [in]float w, [in]float h, [defaultvalue(0)] DWORD flags);
HRESULT  GdiDrawText([in]BSTR str, [in]IGdiFont *font, [in]DWORD color, [in]int x,
[in]int y, [in]int w, [in]int h, [defaultvalue(0)] DWORD format,
[out,retval] VARIANT *p);
HRESULT  DrawImage([in]IGdiBitmap *image, [in]float dstX, [in]float dstY,
[in]float dstW, [in]float dstH, [in]float srcX, [in]float srcY, [in]float srcW,
[in]float srcH, [defaultvalue(0)] float angle, [defaultvalue(255)] BYTE alpha);
HRESULT  GdiDrawBitmap([in]IGdiRawBitmap *bitmap, [in]int dstX, [in]int dstY,
[in]int dstW, [in]int dstH, [in]int srcX, [in]int srcY, [in]int srcW, [in]int srcH);
HRESULT  GdiAlphaBlend([in]IGdiRawBitmap *bitmap, [in]int dstX, [in]int dstY,
[in]int dstW, [in]int dstH, [in]int srcX, [in]int srcY, [in]int srcW,
[in]int srcH, [defaultvalue(255)] BYTE alpha);
#line 132 "h:\\fb2k-sdk\\foobar2000\\foo-wsh-panel-mod\\foo_uie_wsh_panel_mod\\script_interface.h"
HRESULT  MeasureString([in]BSTR str, [in]IGdiFont *font, [in]float x, [in]float y, [in]float w,
[in]float h, [defaultvalue(0)] DWORD flags, [out,retval] IMeasureStringInfo **pp);
HRESULT  CalcTextWidth([in]BSTR str, [in]IGdiFont *font, [out,retval] UINT *p);
HRESULT  CalcTextHeight([in]BSTR str, [in]IGdiFont *font, [out,retval] UINT *p);
HRESULT  EstimateLineWrap([in]BSTR str, [in]IGdiFont *font, [in]int max_width, [out,retval] VARIANT *p);
HRESULT  SetTextRenderingHint([range(0, 5)] UINT mode);
HRESULT  SetSmoothingMode([range(-1, 4)] int mode);
HRESULT  SetInterpolationMode([range(-1, 7)] int mode);
};


wish the CODEBOX tag automatically wrapped lines. I had to manually wrap them in order to not mess up the forum layout.

 

WSH Panel Mod

Reply #956
@saivert:
I've no idea, I've built several revisions using MSVC10, maybe rebuild full solution fix that?

@r0lZ:
Quote
is it a way to accurately measure a string drawn with GdiDrawText()? (I need to know only the height of the string).

No simple way, you have to write some functions to calculate them on your own. (use a temp IGraphics is a fine trick anyway)
FYI, if you want a different line length, the simple way is make use of EstimateLineWrap() method.


@durch:
Actually, window.Width and window.Height return client window size (border size excluded), but MINMAXINFO of window tracks full window size (border size included). Anyway, I'll find workaround for that later.

WSH Panel Mod

Reply #957
@r0lZ:
Quote
is it a way to accurately measure a string drawn with GdiDrawText()? (I need to know only the height of the string).

No simple way, you have to write some functions to calculate them on your own. (use a temp IGraphics is a fine trick anyway)
FYI, if you want a different line length, the simple way is make use of EstimateLineWrap() method.

Thanks for the tip.  I have understood now that there are two completely different ways to draw strings, and they require different methods.  Now, things are much more simple for me.  (BTW, maybe a short explanation should be added in the manual, as this is confusing for newbie like me.)

The most important thing I still need to know is how the script can be notified when the window is made invisible, because another tab is selected.  I have noticed that on_paint() is called when the tab containing the window is selected, so it is possible to set a flag telling that the window is visible, but as far as I know, there is no way to clear that flag when the window is made invisible.  Could you consider to add a new callback or a window property to reflect the visible/invisible state of the window?  (Ideally, the flag should also reflect the state of the entire foobar window, and be off when, for example, foobar is minimized.)  It is a pity to have to refresh graphics that are not visible anyway.  Thanks in advance.

WSH Panel Mod

Reply #958
Rebuild of solution does not fix the problem. The midl compiler is still throwing a error.

Could you provide the solution and project files you are using since I basically had to convert the entire fb2k SDK to the new .vcxproj format and had to do the same to the Columns UI SDK as well. Maybe something got screwed up during the project conversion and you had to fix something in the build settings to be compatible with your code. I'm a total newbie when it comes to this.

VS2010 is a total bitch because you can't just load anything built with an earlier version into it and click Build. Something is always broken.
Maybe I should just bite the bullet and downgrade to VS2008.


WSH Panel Mod

Reply #959
@saivert:
It's ok to use converted projects directly, can you provide full build log(foo_uie_wsh_panel_mod.log)? I'm wondering if it caused by a wrong midl.exe version. (version string of midl.exe should be "Microsoft ® 32b/64b MIDL Compiler Version 7.00.0555")

@r0lZ:
Quote
Could you consider to add a new callback or a window property to reflect the visible/invisible state of the window? (Ideally, the flag should also reflect the state of the entire foobar window, and be off when, for example, foobar is minimized.) It is a pity to have to refresh graphics that are not visible anyway. Thanks in advance.
I'll consider that. However, if you want to refresh graphics even it's not visible, why not providing a background buffer and draws on it?
Code: [Select]
var back_buffer = null, back_buffer_gr = null;
var ww = 0, wh = 0;
// Draw some stuff on the background buffer every 500ms
var timer = window.CreateTimerInterval(500);

function RGB(r, g, b) {
    return (0xff000000 | (r << 16) | (g << 8) | (b));
}


function on_size() {
    ww = window.Width;
    wh = window.Height;
   
    // Create a background buffer, but first remember to clean previous one
    if (back_buffer) {
        back_buffer.ReleaseGraphics(back_buffer_gr);
        back_buffer.Dispose();
    }
    back_buffer = gdi.CreateImage(ww, wh);
    // Get IGraphics interface of this background buffer
    back_buffer_gr = back_buffer.GetGraphics();
}

function on_paint(gr) {
    draw_on_background();
    gr.DrawImage(back_buffer, 0, 0, ww, wh, 0, 0, ww, wh);
}

function on_timer() {
    draw_on_background();
}

function draw_on_background() {
    // Refresh your background image here.
    if (back_buffer_gr) {
        back_buffer_gr.FillGradRect(0, 0, ww, wh, 90, RGB(240, 240, 240), RGB(190, 190, 190));
    }
}

WSH Panel Mod

Reply #960
I'll consider that. However, if you want to refresh graphics even it's not visible, why not providing a background buffer and draws on it?

I use graphics buffers already (for other reasons), but I want to be able to do exactly the opposite than what you suggest.  I have many scripts running whenever the current title changes and when the metadb is updated, and some of them are really useless.  For example, I think it is useless to download the artist or track information from last.fm or any online site when the window that displays that information is not visible.  So, I need to know for sure if the window is visible or not.

The problem of the graphics is another thing.  Your solution is elegant, but for me, since I want to do the opposite, drawing in a buffer doesn't solve the problem.  It's even worse, as I will spend time and resources in drawing in useless buffers.

Anyway, thanks for considering my proposition.  :-)

WSH Panel Mod

Reply #961
Hi T.P Wang!
Thank you very much for this great component. I want ask you about some features:
1. Now we can use fb.GetNowPlaying() and fb.GetFocusItem() to apply context commands to playlist elements. But we can't apply commands to the groups of selected files. fb.GetSelection() does something different.
2. Can you please add functions to support main window transparency, resizing, moving and ect. like in WSH Panel Mod Mod?

WSH Panel Mod

Reply #962
hey T.P, is there a way to stop your SimpleThemedButton script from giving script errors when changing windows themes. the console points to this line of code....

Code: [Select]
g_theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);


obviously, i don't change my theme that often but it would be nice if the script could handle it gracefully.

and thanks for the new preprocessor stuff in 1.37. very handy.

WSH Panel Mod

Reply #963
marc2003.

Move the

var g_theme = window.CreateThemeManager("Button");

inside the

this.draw = function (gr) {}

this should fix it.





WSH Panel Mod

Reply #964
@Zin-Uru:
1. I'll add multiple selection support for applying context menu commands in the near future (but only in context menu).
2. No.

@marc2003:
Confirmed, will be fixed later, thanks for reporting.

WSH Panel Mod

Reply #965
Thanks for the update, and especially for window.IsVisible and for the support for the new component folder location.  :-)

WSH Panel Mod

Reply #966
Quote
1. I'll add multiple selection support for applying context menu commands in the near future (but only in context menu).

Great! Thank you.

WSH Panel Mod

Reply #967
There's one thing I'd like to request, which is the ability to set a flag in TrackPopupMenu that lets you determine whether the menu appears from the left/right/top/bottom of the x,y coordinates you specify. Is it possible? It would be great to have. Thanks!

WSH Panel Mod

Reply #968
New idea: can you add please a function to get all current playlist tracks as array or collection of metadb handles? It would be very useful.

WSH Panel Mod

Reply #969
@T.P Wang

Is it possible (if yes i make it as a request...) to add more functions to playlists ... here are some ideas:

- function that give us the kind of a playlist : normal or autoplaylist
- function that allow to create an autoplaylist, i.e: CreateAutoPlaylist(idx, name, query) ?
- in the same way as the previous request, a function for changing the query of an existing autoplaylist, i.e: UpdateAutoPlaylist(idx, name, query) ?

such functions would be really awesome and could let us to script filters according an album/artist or what you want ! scripting a quicksearch panel in WSH would be so easy with these 3 NEW tools.

what about this?

Thanx by advance for your feedback

WSH Panel Mod

Reply #970
I second that suggestions!  Very good idea.  Without a way to populate the playlists, the other playlist functions are not very useful.
T.P Wang Pleeease do it!

WSH Panel Mod

Reply #971
Hi,
I'm discovering this mod and trying to make a seekbar.
Here is the code I am using, it works well except the bar is kinda green like Windows 7 status bar and I'd prefer it white.
What am I supposed to change to do so ?
Thanks in advance for your support.


Code: [Select]
var g_theme = window.CreateThemeManager("PROGRESS");
var g_bar_height = 4;
var g_cycles = 0;
var ww = 0,
wh = 0;
var top = 0;
var g_pos = 0;
var g_drag = false;
var g_length = 1;

function clamp(x, l, h) {
return (x < l) ? l : ((x > h) ? h : x);
}


function on_size() {
ww = window.Width;
wh = window.Height;
top = (wh - g_bar_height) >> 1;
}

function on_paint(gr) {
g_theme.SetPartAndStateID(1, 0);
g_theme.DrawThemeBackground(gr, 0, top, ww, g_bar_height);

if (fb.IsPlaying && g_length > 0) {
g_theme.SetPartAndStateID(5, fb.IsPaused ? 3 : 1);
g_theme.DrawThemeBackground(gr, 0, top, g_pos, g_bar_height);
}
}

function on_mouse_lbtn_down(x, y) {
if (g_length > 0) {
g_drag = true;
on_mouse_move(x, y);
}
}

function on_mouse_lbtn_up(x, y) {
if (g_length > 0 && g_drag) {
g_drag = false;
fb.PlaybackTime = g_length * g_pos / ww;
on_mouse_move(x, y);
}
}

function on_mouse_move(x, y) {
if (g_drag) {
g_pos = clamp(x, 0, ww);
window.Repaint();
}
}

function on_mouse_wheel(delta) {
fb.PlaybackTime = fb.PlaybackTime + delta * 2;
}

function on_playback_time(time) {
if (!g_drag) {
if (g_length > 0) g_pos = ww * time / g_length;
window.Repaint();
}
}

function on_playback_seek() {
if (!g_drag && g_length > 0) window.Repaint();
}

function on_playback_pause() {
window.Repaint();
}

function on_playback_stop() {
g_length = 0;
g_pos = 0;
g_drag = false;
window.Repaint();
}

function on_playback_new_track() {
g_length = fb.PlaybackLength;
g_pos = 0;
g_drag = false;
window.Repaint();
}

if (fb.IsPlaying) on_playback_new_track();


WSH Panel Mod

Reply #973
Thanks for the advice, I'll do so

WSH Panel Mod

Reply #974
WSH Panel Mod 1.4.0 Beta released.
Changelog:
Quote
v1.4.0 Beta 1
- ADD: New IFbMetadbHandleList interface for a list of metadb handles.
- ADD: fb.GetSelections() method.
- CHG: fb.RunContextCommandWithMetadb() now accept IFbMetadbHandleList.
- ADD: Autoplaylist functions: fb.IsAutoPlaylist(), fb.CreateAutoPlaylist() and fb.ShowAutoPlaylistUI().
- FIX: Script crashes with themes API while changing Windows themes.
- ADD: UI improvements.