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 801620 times) previous topic - next topic
0 Members and 4 Guests are viewing this topic.

WSH Panel Mod

MAIN FEATURES
Scripting

Both "VBSript" and "JScript" are supported.
Draw custom images.
Add popup menu, blur, timer and more operations to images.
Add support to run main menu and context menu command.
Add various helper functions.

Editor Window
Add support to pseudo transparent, syntax highlighting for JScript and VBScript, Import/Outport scripts, customizable font style and miscellaneous UI improvements.

Shortcuts:
  • Ctrl+F: Find
  • Ctrl+H: Replace
  • Ctrl+G: Goto
  • Ctrl+S: Apply
  • F3: Find Next
  • Shift+F3: Find Previous

NOTES & HINTS
  • If anything goes wrong, check the console first.
  • gdi.Font() is fully changed: gdi.Font(name, pxSize, style);
  • Don't call repaint functions such as window.Repaint() in callback function on_size() {}, especially in pseudo transparent mode.
  • Don't try to assign parameter "gr" from function on_paint(gr) {} with other value, nor try to store "gr" in another variable.
  • CollectGarbage() is useful in JScript when you want to free memory immediately. (But please also refer to #11)
  • It's better to retrieve window width and height in callback function on_size(), because their values during startup is not reliable.
  • It's NOT recommended to create objects in callback function on_paint(), since it's called frenquently.
  • Since v1.1.0, functions /methods which use IFbFileInfo Interface is replaced with IFbMetadbHandle Inferface.
  • jsbeautifier.org is a good site for formatting your JScript files.
  • Don't forget that error handling (JScript, VBScript) helps to create more stable scripts.
  • Consider using Dispose() method instead of CollectGarbage() function.

CHANGELOG
View

DOWNLOAD
Binaries, Samples, References:
Download from here (GoogleCode)
Subscribe

Source:
You can Browse
Or, Obtain source through (using Mercurial):
Code: [Select]
hg clone https://foo-wsh-panel-mod.googlecode.com/hg/ foo_uie_wsh_panel_mod


WSH Panel Mod

Reply #2
Thank you very much

WSH Panel Mod

Reply #3
Sorry for asking: But I can't imagine what the changes do. Maybe some can explain or give examples ?

WSH Panel Mod

Reply #4
works great  and a thank you button would do great in this forum ^^

WSH Panel Mod

Reply #5
@Spirit of the ocean
The most conspicious changes are in usability.
For instance:
- Import and Export buttons instead the need of copy and paste codes
- Pseudo Transparent mode
- different colours in the code box for better overview

and of course the change in the gdi.Font() setting
instead of
var g_font = gdi.Font(-12, weight_normal, italic, uline_no, "Tahoma");

you now need to write
var g_font = gdi.Font("Tahoma",12,2);

(as "2" means "italic" according to the flags.txt included in the "Callbacks Flags and Interfaces" archive)

WSH Panel Mod

Reply #6
Awesome! I had a go at modding WSH panel last summer (semi successfully), I trust your development skills far more than my own though, is there any chance you could add a stop after current property of the fb object? So you can get and set the stop after current state? Cursor follows playback/playback follows cursor would be awesome too.

Thanks!!

WSH Panel Mod

Reply #7
I tried this version instead of the old one, this one works much better for me.

I use Curacao by Falstaff, but the WSH panel won't display the volume knob or the seek bar picture.
Couldn't find a way to change the code in the old, the configure-button is greyed and there's no where to change it, had to use Window Enabler for that.
This mod enables that button, thank you.

I had some minor problem with the code for the seek bar in this new version: txt = g_titlefmt.Eval();
It doesn't like that part somehow, removed it and it works great.

So now I can use it like it's supposed to be. =)
Windows 10 Pro x64 // foobar2000 1.3.10

WSH Panel Mod

Reply #8
// problem solved

WSH Panel Mod

Reply #9
Sure you can.
If you have a seekbar sample from the original WSH Panel you can use it in the mod too.
You only need to change the gdi.Font setting as described above.

All my old samples are working in this mod too.

WSH Panel Mod

Reply #10
ahh to late, no that wasn't the prob, But Andreas workaround works great

WSH Panel Mod

Reply #11
Hm, the "txt = g_titlefmt.Eval();" part works great here once the gdi.Font setting is changed...
I tried it with the seekbar_sample provided with the original WSH Panel.

WSH Panel Mod

Reply #12
Thanks, works now.
Windows 10 Pro x64 // foobar2000 1.3.10

WSH Panel Mod

Reply #13
@TomBarlow:
I'll add StopAfterCurrent property later in the next build.

@Andreasvb:
If error occured, wsh panel mod will send error message to the console, so check the console first is a better choice.

WSH Panel Mod

Reply #14
Thanks.
Good to know!
Windows 10 Pro x64 // foobar2000 1.3.10

WSH Panel Mod

Reply #15
1.0.2 Released, with source.

WSH Panel Mod

Reply #16
Thank you!! This is great. At last, a decent stop after current toggle!  Would it be possible to have a callback for it as well?

Another thing, I notice the PBOButtons example uses images that not everyone is going to have (I don't), which makes it look like it doesn't work (although the button still changes playback order). Could you make them text buttons?

WSH Panel Mod

Reply #17
when used "pseudo transparent".
small flashing when changing size panel and change track.

great work 


WSH Panel Mod

Reply #18
Here is my foopaint app updated for use with WSH Panel Mod:

Code: [Select]
//--------
var ForReading = 1, ForWriting = 2;

// Flags, used with GdiDrawText()
// For more information, see: [url=http://msdn.microsoft.com/en-us/library/dd162498(VS.85).aspx]http://msdn.microsoft.com/en-us/library/dd162498(VS.85).aspx[/url]
DT_TOP = 0x00000000;
DT_LEFT = 0x00000000;
DT_CENTER = 0x00000001;
DT_RIGHT = 0x00000002;
DT_VCENTER = 0x00000004;
DT_BOTTOM = 0x00000008;
DT_WORDBREAK = 0x00000010;
DT_SINGLELINE = 0x00000020;
DT_EXPANDTABS = 0x00000040;
DT_TABSTOP = 0x00000080;
DT_NOCLIP = 0x00000100;
DT_EXTERNALLEADING = 0x00000200;
DT_CALCRECT = 0x00000400;
DT_NOPREFIX = 0x00000800;
DT_INTERNAL = 0x00001000;
DT_EDITCONTROL = 0x00002000;
DT_PATH_ELLIPSIS = 0x00004000;
DT_END_ELLIPSIS = 0x00008000;
DT_MODIFYSTRING = 0x00010000;
DT_RTLREADING = 0x00020000;
DT_WORD_ELLIPSIS = 0x00040000;
DT_NOFULLWIDTHCHARBREAK = 0x00080000;
DT_HIDEPREFIX = 0x00100000;
DT_PREFIXONLY = 0x00200000;

// Flags, used by Menu
var MF_SEPARATOR = 0x00000800;
var MF_ENABLED = 0x00000000;
var MF_GRAYED = 0x00000001;
var MF_DISABLED = 0x00000002;
var MF_UNCHECKED = 0x00000000;
var MF_CHECKED = 0x00000008;
var MF_STRING = 0x00000000;
var MF_POPUP = 0x00000010;
var MF_RIGHTJUSTIFY = 0x00004000;

// This is helper function, used in DrawString()/MeasureString()
// args: h_align, v_align, trimming, flags
function StringFormat() {
var h_align = 0, v_align = 0, trimming = 0, flags = 0;
switch (arguments.length)
{
// fall-thru
case 4:
flags = arguments[3];
case 3:
trimming = arguments[2];
case 2:
v_align = arguments[1];
case 1:
h_align = arguments[0];
break;
default:
return 0;
}
return ((h_align << 28) | (v_align << 24) | (trimming << 20) | flags);
}

// h_align/v_align:
// [url=http://msdn.microsoft.com/en-us/library/ms534177(VS.85).aspx]http://msdn.microsoft.com/en-us/library/ms534177(VS.85).aspx[/url]
StringAlignment = {
Near: 0,
Center: 1,
Far: 2
};

// trimming:
// [url=http://msdn.microsoft.com/en-us/library/ms534403(VS.85).aspx]http://msdn.microsoft.com/en-us/library/ms534403(VS.85).aspx[/url]
StringTrimming = {
None: 0,
Character: 1,
Word: 2,
EllipsisCharacter: 3,
EllipsisWord: 4,
EllipsisPath: 5
};

// flags, can be combined of:
// [url=http://msdn.microsoft.com/en-us/library/ms534181(VS.85).aspx]http://msdn.microsoft.com/en-us/library/ms534181(VS.85).aspx[/url]
StringFormatFlags = {
DirectionRightToLeft: 0x00000001,
DirectionVertical: 0x00000002,
NoFitBlackBox: 0x00000004,
DisplayFormatControl: 0x00000020,
NoFontFallback: 0x00000400,
MeasureTrailingSpaces: 0x00000800,
NoWrap: 0x00001000,
LineLimit: 0x00002000,
NoClip: 0x00004000
};

//--------
function RGB(r,g,b){ return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r,g,b,a){ return ((a<<24)|(r<<16)|(g<<8)|(b)); }
//--------
function TimeFmt(t){
var zpad = function(n){
var str = n.toString();
return (str.length<2) ? "0"+str : str;
}
var h = Math.floor(t/3600); t-=h*3600;
var m = Math.floor(t/60); t-=m*60;
var s = Math.floor(t);
if(h>0) return h.toString()+":"+zpad(m)+":"+zpad(s);
return m.toString()+":"+zpad(s);
}
//----------------------------------------------------------------------------



var g_font = gdi.Font("Segoe UI", 13, 0);
//var g_titlefmt = fb.TitleFormat("%bitrate%");

var g_ctx = fb.CreateContextMenuManager();

var g_datafile = "c:\\users\\saivert\\documents\\fb2k_drawing_data.txt";
var g_drag = 0;
var g_pos = new Array();
var g_shift = {x:0, y:0};
var g_size = 5;
var g_key = null;
var g_increment = 10;
var g_bkgnd = 0;
var g_fgnd = 0;
var g_showall = false;
var g_fgnd_colors = new Array(RGB(255,10,0),
RGB(35,20,80),
RGB(90,100,10),
RGB(56,230,67)
);
function shadowtext(gr,txt,f,c,x,y,w,h,fmt){
gr.GdiDrawText(txt, f, RGB(10,10,10), x-1, y-1, w, h,fmt);
gr.GdiDrawText(txt, f, c, x, y, w, h,fmt);
}


function on_paint(gr){
var start = (new Date).getTime();

var ww = window.Width-1;
var wh = window.Height-1;
var ox = g_shift.x;
var oy = g_shift.y;

switch (g_bkgnd) {
case 0:
gr.FillSolidRect(0, 0, ww, wh, RGB(0,0,0));
break;
case 1:
gr.FillGradRect(0, 0, ww, wh, 45, RGB(0,0,0), RGB(255,255,255));
break;
case 2:
gr.FillGradRect(0, 0, ww, wh, 60, RGB(30,90,10), RGB(200,180,90));
break;

}

var img_to_blur = gdi.CreateImage(ww, wh);
var g = img_to_blur.GetGraphics();

var count = (g_showall) ? g_pos.length : fb.PlaybackTime * (g_pos.length / fb.PlaybackLength);

try {
for (var i = 1; i < count; i++) {
if (g_pos[i-1].size==0) {continue;}
g.DrawLine(ox+g_pos[i-1].x, oy+g_pos[i-1].y, ox+g_pos[i].x, oy+g_pos[i].y, g_pos[i].size,  g_pos[i].color);
}
} catch(Err) {
fb.trace(Err.message);
};

img_to_blur.ReleaseGraphics(g);
// Make box blur, radius = 2, iteration = 2
img_to_blur.BoxBlur(2, 2);

img_to_blur && gr.DrawImage(img_to_blur, 0, 0, ww, wh, 0, 0, ww, wh);


var diff = (new Date).getTime() - start;

txt = "Number of points: " + g_pos.length + "; Size: " + g_size + "; Key=" + g_key + "; Time=" + diff;
if (g_showall) txt += " [showall]";
shadowtext(gr,txt, g_font, RGB(255,255,255), 2, 0, ww, wh, DT_SINGLELINE|DT_LEFT|DT_TOP|DT_NOCLIP);

gr.FillSolidRect(5, 18, g_size, 10, g_fgnd_colors[g_fgnd]);

var help_text = "Keys: s=save, r=load, k=change bkgnd, l=change pen color, scrollwheel=change pen size, ";
shadowtext(gr,help_text, g_font, RGB(255,255,255), 2, 0, ww, wh, DT_SINGLELINE|DT_LEFT|DT_BOTTOM|DT_NOCLIP);

gr.DrawRect(ww-21,1, 20, 20, 1.0, RGB(255,0,255));

gr.DrawRect(0,0, ww, wh, 1.0, RGB(150,150,150));
}

function showmenu(){
var menu = window.CreatePopupMenu();
var colormenu = window.CreatePopupMenu();
colormenu.AppendMenuItem(MF_STRING, 3, 'Reset canvas');
menu.AppendMenuItem(MF_STRING, 1, 'Reset canvas');
menu.AppendMenuItem(MF_STRING|MF_POPUP, colormenu.id, 'Color');
g_ctx.InitNowPlaying();
g_ctx.BuildMenu(colormenu, 3, -1);

if (arguments.length==2) {
var x = arguments[0];
var y = arguments[1];
} else {
var x = window.width - 10;
var y = 20;
}
var id = menu.TrackPopupMenu(x,y);
if (id==1) {
g_pos = []; g_shift = {x:0, y:0};
} else if (id>0) g_ctx.ExecuteByID(id-3);
}

function on_size(){
}
function on_focus(focused){
}
function on_key_down(key){
g_key = key;
switch (key) {
case 66: g_pos = []; g_shift = {x:0, y:0}; break;
case 37: g_shift.x-=g_increment; break;
case 39: g_shift.x+=g_increment; break;
case 38: g_shift.y-=g_increment; break;
case 40: g_shift.y+=g_increment; break;
case 75: if (g_bkgnd++ > 1) g_bkgnd = 0; break;
case 76: if (++g_fgnd > g_fgnd_colors.length-1) g_fgnd = 0; break;
case 83: savetofile(); break;
case 82: loadfromfile(); break;
case 8: while (g_pos.length>0 && g_pos.pop().size>0); break;
case 70: g_showall = !g_showall; break;
case 93: showmenu(); break;
}
window.Repaint();
}

function on_mouse_lbtn_down(x,y){
g_drag = 1;
}
function on_mouse_lbtn_up(x,y){
//on_mouse_move(x,y);
g_pos.push({x: x-g_shift.x, y: y-g_shift.y, size: 0});
if(g_drag) g_drag = 0;
if (x > window.Width-20 && y < 20) showmenu(x,y);
}
function on_mouse_move(xpos,ypos){
if(g_drag){
g_pos.push({x: xpos-g_shift.x, y: ypos-g_shift.y, size: g_size, color: g_fgnd_colors[g_fgnd]});
window.Repaint();
}
}
function on_mouse_wheel(delta){
g_size += delta;
if (g_size <=1) g_size = 1;
window.Repaint();
}

function on_playback_starting(cmd, paused){
}
function on_playback_new_track(info){
}
function on_playback_stop(){
}
function on_playback_seek(time){
}
function on_playback_pause(state){
}
function on_playback_edited(){
}
function on_playback_dynamic_info(){
}
function on_playback_dynamic_info_track(){
}
function on_playback_time(time){
window.Repaint();
}
function on_volume_change(val){
}

function savetofile() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var a = fso.CreateTextFile(g_datafile, true);
a.WriteLine(JSON.stringify(g_pos));
a.Close();
}

function loadfromfile() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
try {
var a = fso.OpenTextFile(g_datafile, ForReading);
g_pos = JSON.parse(a.ReadAll());
a.Close();
}
catch(Err)
{
};
}

if(!this.JSON){JSON={};}
(function(){function f(n){return n<10?'0'+n:n;}
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z';};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
if(typeof rep==='function'){value=rep.call(holder,key,value);}
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
v=partial.length===0?'[]':gap?'[\n'+gap+
partial.join(',\n'+gap)+'\n'+
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
return str('',{'':value});};}
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
return reviver.call(holder,key,value);}
cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
throw new SyntaxError('JSON.parse');};}})();


loadfromfile();

I'm currently triggering this on a left button click in a special area.
Where is a event for right button clicks? or even to replace the standard context menu (with the Configure... item).

WSH Panel Mod

Reply #19
1.0.4 Released

@saivert:
You can use 1.0.4, the "on_mouse_rbtn_up(x, y, vkey)" callback function is what you need, and don't forget to return true in that function if you want to override the standard context menu. 

WSH Panel Mod

Reply #20
It would be very nice if you add support for older versions of foobar2000, if possible!
I'm using version 0.9.4.5 + Columns UI and I can not make it work with foo_uie_wsh_panel...
Thanks!

WSH Panel Mod

Reply #21
I was wondering if you are able to release a version with out the SSE2, would that be possible?

WSH Panel Mod

Reply #22
@d0ng:
No SSE2 in this release.

WSH Panel Mod

Reply #23
How can I apply a title formatting to the focused item (not the currently playing item) ?
[Note that it could be feasible if there was a way to retrieve the index in the playlist of the currently selected item]
Thanks

WSH Panel Mod

Reply #24
Nevertheless i've made those two toolbars to replace foobar's standard ones :
Volume :
Code: [Select]
function RGB(r,g,b){ return (0xff000000|(r<<16)|(g<<8)|(b)); }
var g_font = gdi.Font("Tahoma", 12, 0);
var g_drag = 0;
var ww = 100;
var hofset = 5;
var wh = 12;
function on_paint(gr){
    var vofset = (window.Height-wh)/2;
    var grad = Math.pow((100+fb.Volume)/100,2);
    var i = 0;
    while (i < ww+1) {
        var col = (grad<=0)  ? RGB(168,168,168) : (i<=grad*ww) ? RGB(32+128*i/ww,164*(1-i/ww),32*(1-i/ww)) :  RGB(168,168,168);
        gr.FillSolidRect(hofset+1+i,vofset,4,wh, col);
        i = i +5;   
    }
    gr.DrawRect(hofset,vofset, i, wh, 1.0, RGB(192,192,192));
}
function on_mouse_lbtn_down(x,y){
    g_drag = 1;
}
function on_mouse_lbtn_up(x,y){
    on_mouse_move(x,y);
    g_drag = 0;
}
function on_mouse_move(x,y){
    if(g_drag){
        var v = (x-hofset)/ww;
        v = (v<0) ? 0 : (v<1) ? v : 1;
        v = 100 * (Math.pow(v,1/2) - 1);
        fb.Volume = v;
    }   
}
function on_mouse_wheel(delta){
    if(delta>0)
        fb.VolumeUp();
    else
        fb.VolumeDown();
}
function on_volume_change(val){
    window.Repaint();
}
function on_playback_time(time){
window.Repaint();
}
//EOF


Seekbar:
Code: [Select]
function RGB(r,g,b){ return (0xff000000|(r<<16)|(g<<8)|(b)); }
var g_font = gdi.Font("Tahoma", 12, 0);
var g_drag = 0;
var ww = 270;
var hofset = 10;
var wh = 12;
function on_paint(gr){
var vofset = (window.Height-wh)/2;
var length = fb.PlaybackLength;
var grad = 0;
if (length > 0) {
grad = fb.PlaybackTime/fb.PlaybackLength;}

var i = 0;
while (i < ww+1) {

var col = (grad<=0)  ? RGB(168,168,168) : (i<=grad*ww) ? RGB(0,32+48*(1-i/ww),96+64*(1-i/ww)) :  RGB(128+48*(1-i/ww),128+48*(1-i/ww),128+48*(1-i/ww));
gr.FillSolidRect(hofset+1+i,vofset,4,wh, col);
i = i +5;
}
gr.DrawRect(hofset,vofset, i, wh, 1.0, RGB(192,192,192));
}
function on_mouse_lbtn_down(x,y){
g_drag = 1;
}
function on_mouse_lbtn_up(x,y){
on_mouse_move(x,y);
g_drag = 0;
}
function on_mouse_move(x,y){
if(g_drag){
var v = (x-hofset)/ww;
v = (v<0) ? 0 : (v<1) ? v : 1;
fb.PlaybackTime = fb.PlaybackLength * v;



}

}
function on_mouse_wheel(delta){
if(delta>0)
fb.PlaybackTime = fb.PlaybackTime + delta;
else
fb.PlaybackTime = fb.PlaybackTime + delta;
}
function on_playback_new_track(info){
window.Repaint();
}
function on_playback_stop(){
window.Repaint();
}
function on_playback_seek(time){
window.Repaint();
}
function on_playback_time(time){
window.Repaint();
}