Thanks, yours looks excellent, and I love the concept. Here are my scripts, the first is the left hand buttons:
var bg = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btn_m.png");
var bgL = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btnbg_l.png");
var bgR = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btnbg_r.png");
var button_bg_hov = gdi.Image(fb.FoobarPath + "\\themes\\Averia\\images\\btn_bg.png");
var button_bg_down = gdi.Image(fb.FoobarPath + "\\themes\\Averia\\images\\btn_bg_d.png");
var cur_btn = null;
var act_btn = null;
ButtonStates = {
normal: 0,
hover: 1,
down: 2
}
ShowButton = {
hide: 0,
show: 1
}
var ww = window.Width;
var wh = window.Height;
//button function
function button(icon,func_onClick,x,state,show)
{
this.icon=gdi.Image(fb.FoobarPath + "\\images\\black indented\\pngs\\"+icon+".png");
this.state=state ? state : ButtonStates.normal;
this.show=show ? show : ShowButton.show;
this.x=x;
this.func_onClick = func_onClick;
this.containXY = function (x, y)
{
return (this.x <= x) && (x <= this.x + 23) && (0 <= y) && (y <= 20);
}
this.draw = function (gr)
{
if (this.show == ShowButton.hide){return;}
else
{
if(this.state == ButtonStates.normal)
{
gr.DrawImage(this.icon, this.x+3, 2, 16, 16, 0, 0, 16, 16);
}
else if(this.state == ButtonStates.hover)
{
gr.DrawImage(button_bg_hov, this.x, 0, 23, 20, 0, 0, 23, 20);
gr.DrawImage(this.icon, this.x+3, 2, 16, 16, 0, 0, 16, 16);
}
else if(this.state == ButtonStates.down)
{
gr.DrawImage(button_bg_down, this.x, 0, 23, 20, 0, 0, 23, 20);
gr.DrawImage(this.icon, this.x+3, 2, 16, 16, 0, 0, 16, 16);
}
}
}
this.onClick = function ()
{
this.func_onClick && this.func_onClick();
}
}
function showhidebuttons()
{
if(fb.IsPlaying && !fb.IsPaused)
{
$buttons.play.show = ShowButton.hide;
$buttons.pause.show = ShowButton.show;
}
else
{
$buttons.pause.show = ShowButton.hide;
$buttons.play.show = ShowButton.show;
}
if(fb.StopAfterCurrent)
{
$buttons.sac.show = ShowButton.hide;
$buttons.sac_on.show = ShowButton.show;
}
else
{
$buttons.sac_on.show = ShowButton.hide;
$buttons.sac.show = ShowButton.show;
}
}
function drawAllButtons(gr)
{
showhidebuttons();
for (var i in $buttons)
{
$buttons[i].draw(gr);
}
}
function chooseButton(x, y)
{
for (var i in $buttons)
{
if ($buttons[i].containXY(x, y) && $buttons[i].show != ShowButton.hide)
return $buttons[i];
}
return null;
}
$buttons = {
back: new button('back' ,function(){fb.Prev();},0),
stop: new button('stop' ,function(){fb.Stop();},23),
play: new button('play' ,function(){fb.PlayOrPause();},46),
pause: new button('pause' ,function(){fb.PlayOrPause();},46),
sac: new button('sac' ,function(){fb.StopAfterCurrent=true;},69),
sac_on:new button('sac_on',function(){fb.StopAfterCurrent=false;},69),
next: new button('fwd' ,function(){fb.Next();},92)
}
function on_paint(gr)
{
gr.FillSolidRect(0,0,window.Width,window.Height,0xfffcfcfc);
gr.DrawImage( bg, bgL.Width, 0, window.Width-bgL.Width, bg.Height, 0, 0, bg.Width, bg.Height);
gr.DrawImage( bgL, 0, 0, bgL.Width, bgL.Height, 0, 0, bgL.Width, bgL.Height);
drawAllButtons(gr);
}
function on_size()
{
ww = window.Width;
wh = window.Height;
}
function on_mouse_lbtn_down(x,y)
{
cur_btn = chooseButton(x, y);
if(cur_btn)
{
cur_btn.state=ButtonStates.down;
}
act_btn = cur_btn;
window.Repaint();
}
function on_mouse_move(x, y)
{
cur_btn = chooseButton(x, y);
if(cur_btn)
{
if(cur_btn.state!=ButtonStates.down&&!act_btn)
{
cur_btn.state=ButtonStates.hover;
}
for(var i in $buttons)
{
if($buttons[i] != cur_btn)
{
$buttons[i].state=ButtonStates.normal;
}
}
if(cur_btn==act_btn)
{
cur_btn.state=ButtonStates.down;
}
}
else
{
for(var i in $buttons)
{
$buttons[i].state=ButtonStates.normal;
}
}
window.Repaint();
}
function on_mouse_lbtn_up(x, y)
{
if (cur_btn&&act_btn==cur_btn)
{
cur_btn.onClick();
cur_btn = chooseButton(x, y);
showhidebuttons();
cur_btn.state=ButtonStates.hover;
}
act_btn = null;
window.Repaint();
}
function on_mouse_leave()
{
for (var i in $buttons)
{
$buttons[i].state=ButtonStates.normal;
}
window.Repaint();
}
function on_playback_stop()
{
window.Repaint();
}
function on_playback_pause(state)
{
window.Repaint();
}
function on_playback_starting(cmd, is_paused)
{
window.Repaint();
}
function on_playlist_stop_after_current_changed(state)
{
window.Repaint();
}
The right hand buttons are basically the same, but with a different $buttons array:
$buttons = {
cfp: new button('cfp' ,function() {fb.CursorFollowPlayback=true;},0),
cfp_on: new button('cfp_on' ,function() {fb.CursorFollowPlayback=false;},0),
pfc: new button('pfc' ,function() {fb.PlaybackFollowCursor=true;},23),
pfc_on: new button('pfc_on' ,function() {fb.PlaybackFollowCursor=false;},23),
shuf: new button('shuff' ,function() {fb.PlaybackOrder=4;},46),
shuf_on:new button('shuff_on' ,function() {fb.PlaybackOrder=0;},46),
rtrk: new button('rep_trk' ,function() {fb.PlaybackOrder=2;},69),
rtrk_on:new button('rep_trk_on',function() {fb.PlaybackOrder=0;},69),
rall: new button('rep_all' ,function() {fb.PlaybackOrder=1;},92),
rall_on:new button('rep_all_on',function() {fb.PlaybackOrder=0},92)
}
and different showhidebuttons function:
function showhidebuttons()
{
if(fb.CursorFollowPlayback)
{
$buttons.cfp.show = ShowButton.hide;
$buttons.cfp_on.show = ShowButton.show;
}
else
{
$buttons.cfp_on.show = ShowButton.hide;
$buttons.cfp.show = ShowButton.show;
}
if(fb.PlaybackFollowCursor)
{
$buttons.pfc.show = ShowButton.hide;
$buttons.pfc_on.show = ShowButton.show;
}
else
{
$buttons.pfc_on.show = ShowButton.hide;
$buttons.pfc.show = ShowButton.show;
}
if(fb.PlaybackOrder==0)
{
$buttons.shuf_on.show = ShowButton.hide;
$buttons.rtrk_on.show = ShowButton.hide;
$buttons.rall_on.show = ShowButton.hide;
$buttons.shuf.show = ShowButton.show;
$buttons.rtrk.show = ShowButton.show;
$buttons.rall.show = ShowButton.show;
}
else if(fb.PlaybackOrder==1)
{
$buttons.shuf_on.show = ShowButton.hide;
$buttons.rtrk_on.show = ShowButton.hide;
$buttons.rall_on.show = ShowButton.show;
$buttons.shuf.show = ShowButton.show;
$buttons.rtrk.show = ShowButton.show;
$buttons.rall.show = ShowButton.hide;
}
else if(fb.PlaybackOrder==2)
{
$buttons.shuf_on.show = ShowButton.hide;
$buttons.rtrk_on.show = ShowButton.show;
$buttons.rall_on.show = ShowButton.hide;
$buttons.shuf.show = ShowButton.show;
$buttons.rtrk.show = ShowButton.hide;
$buttons.rall.show = ShowButton.show;
}
else if(fb.PlaybackOrder==4)
{
$buttons.shuf_on.show = ShowButton.show;
$buttons.rtrk_on.show = ShowButton.hide;
$buttons.rall_on.show = ShowButton.hide;
$buttons.shuf.show = ShowButton.hide;
$buttons.rtrk.show = ShowButton.show;
$buttons.rall.show = ShowButton.show;
}
}
As well as different callbacks, the relevant ones from the callbacks.txt.
Then there's the seekbar, features include tooltip, seeking with mouse scroll, redraw more than once per sec, and it also only shows anything while it's playing, and has a different display for streams.
//Text formatting function
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);
}
//Time formatting
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);
}
StringAlignment = {
Near: 0,
Centre: 1,
Far: 2
};
var font = gdi.Font("Calibri", 10, 1);
var l_stringformat = StringFormat(StringAlignment.Near, StringAlignment.Centre);
var c_stringformat = StringFormat(StringAlignment.Centre, StringAlignment.Centre);
var r_stringformat = StringFormat(StringAlignment.Far, StringAlignment.Centre);
var g_drag = 0;
var g_drag_seek = 0;
var g_drag_hov = 0;
//The seekbar
var L = gdi.Image(fb.FoobarPath + "\\images\\black indented\\seekbar\\L.png");
var R = gdi.Image(fb.FoobarPath + "\\images\\black indented\\seekbar\\R.png");
var seeker = gdi.Image(fb.FoobarPath + "\\images\\black indented\\seekbar\\seeker2.png");
//background
var bg = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btn_m.png");
var bgL = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btnbg_l.png");
var bgR = gdi.Image(fb.FoobarPath+ "\\themes\\Averia\\images\\btnbg_r.png");
var ww = window.Width;
var wh = window.Height;
//Titleformatting
var len = fb.Titleformat("%length%");
var elap = fb.TitleFormat("%playback_time%");
var remain = fb.TitleFormat("[%playback_time_remaining%]");
var tooltip = window.CreateTooltip();
var pos = 0;
var seekstart = 0;
var seekend = 0;
var seekpad = 6;
var seekerwidth = seeker.Width/2;
var g_timer;
function on_paint(gr)
{
gr.SetTextRenderingHint(5);
gr.FillSolidRect(0,0,window.Width,window.Height,0xfffcfcfc);
gr.DrawImage( bg, 0, 0, window.Width, bg.Height, 0, 0, bg.Width, bg.Height);
//For normal playback
if(fb.PlaybackLength>0)
{
seekstart = gr.CalcTextWidth(len.Eval(),font);
seekend = gr.CalcTextWidth(len.Eval(),font);
gr.DrawImage( L, seekstart+seekpad, 2, window.Width-(seekstart+seekend+2*seekpad)-R.Width, 16, 0, 0, window.Width-(seekstart+seekend+2*seekpad)-R.Width, 16);
gr.DrawImage( R, window.Width-(seekend+seekpad)-R.Width, 2, 2, 16, 0, 0, 2, 16);
gr.DrawString(elap.Eval(), font, 0xff000000, 3, 0, seekstart+seekpad, 18, l_stringformat);
gr.DrawString(remain.Eval(), font, 0xff000000, ww-seekend-3-seekpad, 0, seekend+seekpad, 18, r_stringformat);
if(g_drag)
{
pos = seekstart+seekpad+seekerwidth+(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))) * g_drag_seek;
}
else
{
pos = seekstart+seekpad+seekerwidth+(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))) * (fb.PlaybackTime / fb.PlaybackLength);
}
gr.DrawImage( seeker, pos-seekerwidth, 2, 12, 16, 0, 0, 12, 16);
if(g_drag_hov)
{
gr.DrawImage(bgL, 0, 0, bgL.Width, bgL.Height, 0, 0, bgL.Width, bgL.Height);
gr.DrawImage(bgR, window.Width-bgR.Width, 0, bgR.Width, bgR.Height, 0, 0, bgR.Width, bgR.Height);
}
}
//For streams
else if(fb.IsPlaying && fb.PlaybackLength)
{
seekstart = 0;
seekend = 0;
gr.DrawString(elap.Eval()+" / continuous", font, 0xff000000, 0, 0, window.Width, 18, c_stringformat);
if(g_drag_hov)
{
gr.DrawImage(bgL, 0, 0, bgL.Width, bgL.Height, 0, 0, bgL.Width, bgL.Height);
gr.DrawImage(bgR, window.Width-bgR.Width, 0, bgR.Width, bgR.Height, 0, 0, bgR.Width, bgR.Height);
}
}
}
function on_size()
{
ww = window.Width;
wh = window.Height;
}
function on_mouse_lbtn_down(x,y)
{
if(x>seekstart+seekpad&&x<window.Width-(seekend+seekpad))
{
if(fb.PlaybackLength){g_drag = 1;}
g_drag_seek = (x>seekstart+seekpad+seekerwidth)?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):(x<(window.Width-(seekend+seekpad+seekerwidth)))?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):1;
g_drag_seek = (g_drag_seek<0) ? 0 : (g_drag_seek<1) ? g_drag_seek : 1;
}
window.Repaint();
}
function on_mouse_move(x, y)
{
g_drag_hov = true;
if(fb.IsPlaying&&fb.PlaybackLength>0&&x>seekstart&&x<window.Width-seekend)
{
g_drag_seek = (x>seekstart+seekpad+seekerwidth)?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):(x<(window.Width-(seekend+seekpad+seekerwidth)))?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):1;
g_drag_seek = (g_drag_seek<0) ? 0 : (g_drag_seek<1) ? g_drag_seek : 1;
tooltip.Text = TimeFmt(fb.PlaybackLength * g_drag_seek);
tooltip.Activate();
}
else
{
tooltip.Deactivate();
}
window.Repaint();
}
function on_mouse_lbtn_up(x, y)
{
if(g_drag)
{
g_drag = 0;
g_drag_seek = (x>seekstart+seekpad+seekerwidth)?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):(x<(window.Width-(seekend+seekpad+seekerwidth)))?(x-(seekstart+seekpad+seekerwidth))/(window.Width-(seekstart+seekend+2*(seekpad+seekerwidth))):1;
g_drag_seek = (g_drag_seek<0) ? 0 : (g_drag_seek<1) ? g_drag_seek : 1;
fb.PlaybackTime = fb.PlaybackLength * g_drag_seek;
}
window.Repaint();
}
function on_mouse_leave()
{
g_drag_hov = false;
tooltip.Deactivate();
window.Repaint();
}
function on_playback_seek(time)
{
window.Repaint();
}
function on_playback_time(time)
{
if(g_timer){window.KillTimer(g_timer);}
if(fb.PlaybackLength<500&&fb.PlaybackLength>0){g_timer = window.CreateTimerInterval(100);}
window.Repaint();
}
function on_playback_stop()
{
if(g_timer){window.KillTimer(g_timer);}
window.Repaint();
}
function on_playback_pause(state)
{
window.Repaint();
}
function on_playback_starting(cmd, is_paused)
{
g_timer = window.CreateTimerInterval(100);
window.Repaint();
}
//Redraw more than once per sec
function on_timer(id)
{
window.Repaint();
}
//Seek using mouse wheel
function on_mouse_wheel(delta){
if(delta>0)
fb.RunMainMenuCommand("Seek Ahead by 10 Seconds");
else
fb.RunMainMenuCommand("Seek Back by 10 Seconds");
}
Feel free to use/abuse. I hope this all fits, it's quite a long post!