Here is my foopaint app updated for use with WSH Panel Mod:
//--------
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).