There is a script for viewing album covers on the panel has buttons to switch Folder\CD\Artist\etc. Please help make switch tracks for this buttons Previous\Play\Pause\Next.
function RGBA(r,g,b,a){
var res = 0xff000000|(r<<16)|(g<<8)|(b);
if (a!=undefined) res = (res & 0x00ffffff) | (a << 24)
return res;
}
//====================================================
// Properties Object =======================================
/* All settings store here */
var Properties = new function (){
this.Panel = {
// 0: Never, 1: When not playing, 2: Always.
FollowCursor: window.GetProperty("Panel.FollowCursor", 1),
// Where the images folders in.
WorkDirectory: fb.FoobarPath+fb.TitleFormat(window.GetProperty("Panel.WorkDirectory", "Images\\EIKO\\WSH Cover\\")).Eval(true),
// "cn": Chinese, "en": English, "auto": Auto choose, base on foobar2000 core language.
lang: window.GetProperty("Panel.Language", "auto").toLowerCase(), // Language
// Separate with comma, like "255,255,255"
BackGroundColor: window.GetProperty("Panel.BackGroundColor", ""),
Tooltip: window.CreateTooltip() // Create button's tooltip
};
if (typeof(this.Panel.FollowCursor)!="number")
this.Panel.FollowCursor = 1;
else if (this.Panel.FollowCursor<0)
this.Panel.FollowCursor = 0;
else if (this.Panel.FollowCursor>2)
this.Panel.FollowCursor = 2;
if (this.Panel.lang != "cn" && this.Panel.lang != "en")
this.Panel.lang = (fb.TitleFormat("$meta()").Eval(true)=="[未知函数]") ? "cn" : "en";
try {
this.Panel.FSO = new ActiveXObject("Scripting.FileSystemObject");
} catch(e) {
// Impossible to work without FSO.
fb.ShowPopupMessage(this.Panel.lang=="cn" ? "无法创建FSO对象, WSH Cover面板无法工作." : "Can not create File System Object (FSO), WSH Cover Panel can't work.", "WSH Cover Panel", 1);
new ActiveXObject("Scripting.FileSystemObject"); // End scripts running.
}
if (!this.Panel.FSO.FolderExists(this.Panel.WorkDirectory))
fb.ShowPopupMessage(this.Panel.lang=="cn" ? "无效的工作路径." : "Invalid work directory.", "WSH Cover Panel", 1);
if (this.Panel.BackGroundColor) {
this.Panel.BackGroundColor = this.Panel.BackGroundColor.replace(/ | /g, "");
this.Panel.BackGroundColor = this.Panel.BackGroundColor.split(",");
for (var i in this.Panel.BackGroundColor) {
if (this.Panel.BackGroundColor[i]<0)
this.Panel.BackGroundColor[i] = 0;
else if (this.Panel.BackGroundColor[i]>255)
this.Panel.BackGroundColor[i] = 255;
}
if (this.Panel.BackGroundColor.length<4)
this.Panel.BackGroundColor.length = 4;
}
//---------------------------------------------------------------------
this.Cycle = {
// Enable image cycle.
Enable: window.GetProperty("Cycle.Enable", true),
// Interval period.
Period: window.GetProperty("Cycle.Period", 10000),
// Cycle all the wildcard match files in image SourceFormat.
CycleInWildCard: window.GetProperty("Cycle.CycleInWildCard", true),
// Pause images cycle automatic when following cursor.
AutoPauseWhenFollowCursor: window.GetProperty("Cycle.AutoPauseWhenFollowCursor", true),
// Animations on image's changing. Not only in image cycle, but also in track switching.
Animation: {
Enable: window.GetProperty("Cycle.Animation.Enable", true),
RefreshInterval: window.GetProperty("Cycle.Animation.RefreshInterval", 50),
Duration: window.GetProperty("Cycle.Animation.Duration", 400)
}
};
if (typeof(this.Cycle.Period)!="number")
this.Cycle.Period = 7000;
else if (this.Cycle.Period<100)
this.Cycle.Period = 100;
if (typeof(this.Cycle.Animation.RefreshInterval)!="number")
this.Cycle.Animation.RefreshInterval = 50;
else if (this.Cycle.Animation.RefreshInterval<10)
this.Cycle.Animation.RefreshInterval = 10;
if (typeof(this.Cycle.Animation.Duration)!="number")
this.Cycle.Animation.Duration = 300;
else if (this.Cycle.Animation.Duration<10)
this.Cycle.Animation.Duration = 10;
//---------------------------------------------------------------------
this.Image = {
// Separate paths by "||"; use "|||" to separate default images and other images, only can be used once; "<embed>" means embed cover, must be a individual path in sourceformat.
SourceFormat: window.GetProperty("Image.SourceFormat", "<embed>||$directory_path(%path%)\\cover.*||$directory_path(%path%)\\folder.*"),
// In same group, if SourceFormat not changed, panel will not check any new files, and the images cycle will not be reset.
GroupFormat: window.GetProperty("Image.GroupFormat", "%album%"),
// Default image path.
DefaultImagePath: fb.TitleFormat(window.GetProperty("Image.DefaultImagePath", "Images\\EIKO\\Default.jpg")).Eval(true),
// File larger than this value will not be loaded. <=0 means no limit.
MaxFileSize: window.GetProperty("Image.MaxFileSize", 2097152),
// Keep images aspect ratio.
KeepAspectRatio: window.GetProperty("Image.KeepAspectRatio", true),
// Stretch images to fit panel.
Stretch: window.GetProperty("Image.Stretch", false),
// Images is stored after resize, so you can set this value larger if your panel size is not very large.
ImageCacheCapacity: window.GetProperty("Image.ImageCacheCapacity", 10),
// This panel also stores path search result, only stores the strings.
PathCacheCapacity: window.GetProperty("Image.PathCacheCapacity", 20),
// Only these types of files can be displayed. Not necessary to modify this at most times.
SupportTypes: new Array("jpg", "jpeg", "png", "gif", "bmp"),
// Image smoothing mode.
SmoothingMode: window.GetProperty("Image.SmoothingMode", 0),
// Image interpolation mode in resizing.
InterpolationMode: window.GetProperty("Image.InterpolationMode", 0)
};
if (typeof(this.Image.MaxFileSize)!="number")
this.Image.MaxFileSize = 2097152;
else if (this.Image.MaxFileSize<0)
this.Image.MaxFileSize = 0;
if (typeof(this.Image.ImageCacheCapacity)!="number")
this.Image.ImageCacheCapacity = 10;
else if (this.Image.ImageCacheCapacity<0)
this.Image.ImageCacheCapacity = 0;
if (typeof(this.Image.PathCacheCapacity)!="number")
this.Image.PathCacheCapacity = 20;
else if (this.Image.PathCacheCapacity<0)
this.Image.PathCacheCapacity = 0;
if (typeof(this.Image.SmoothingMode)!="number")
this.Image.SmoothingMode = 0;
else if (this.Image.SmoothingMode<-1)
this.Image.SmoothingMode = -1;
else if (this.Image.SmoothingMode>4)
this.Image.SmoothingMode = 4;
if (typeof(this.Image.InterpolationMode)!="number")
this.Image.InterpolationMode = 0;
else if (this.Image.InterpolationMode<-1)
this.Image.InterpolationMode = -1;
else if (this.Image.InterpolationMode>7)
this.Image.InterpolationMode = 7;
//---------------------------------------------------------------------
this.Buttons = {
// Whether display the control buttons.
Display: window.GetProperty("Buttons.Display", true),
// 0: topleft, 1:topright, 2:bottomleft, 3:bottomright
Position: window.GetProperty("Buttons.Position", "4")
};
if (typeof(this.Buttons.Position)!="number")
this.Buttons.Position = 4;
else if (this.Buttons.Position<0)
this.Buttons.Position = 0;
else if (this.Buttons.Position>5)
this.Buttons.Position = 5;
}();
//====================================================
// Three funtions ==========================================
//---------------------------------------------------------------------------------------------
/* Calculate image's new size and offsets in new width and height range.
Use panel's default settings of stretch and ratio if they are not specified */
function CalcNewImgSize (img, dstW, dstH, srcW,srcH, strch, kar) {
if (!img) return;
if (!srcW) srcW = img.width;
if (!srcH) srcH = img.height;
if (strch==undefined) strch = Properties.Image.Stretch;
if (kar==undefined) kar = Properties.Image.KeepAspectRatio;
var size;
if (strch) {
size = {x:0, y:0, width:dstW, height:dstH};
if (kar) {
size.width = Math.ceil(srcW*dstH/srcH);
if (size.width>dstW) {
size.width = dstW;
size.height = Math.ceil(srcH*dstW/srcW);
}
}
} else {
size = {x:0, y:0, width:srcW, height:srcH};
if (kar) {
if (srcH>dstH) {
size.height = dstH;
size.width = Math.ceil(srcW*dstH/srcH);
}
if (size.width>dstW) {
size.width = dstW;
size.height = Math.ceil(srcH*dstW/srcW);
}
} else {
size.width = Math.min(srcW, dstW);
size.height = Math.min(srcH, dstH);
}
}
size.x = Math.floor((dstW-size.width)/2);
size.y = Math.floor((dstH-size.height)/2);
return size;
}
//---------------------------------------------------------------------------------------------
/* Reisze image to new width and height */
function ResizeImg (img, dstW, dstH) {
if (!img || !dstW || !dstH) return img;
if (img.width==dstW && img.height==dstH) return img;
var newimg = gdi.CreateImage(dstW, dstH);
var g = newimg.GetGraphics();
g.DrawImage(img, 0, 0, dstW, dstH, 0, 0, img.width, img.height);
newimg.ReleaseGraphics(g);
CollectGarbage(); // Release memory.
return newimg;
}
//---------------------------------------------------------------------------------------------
/* Remove an element from "this" array, return the removed element */
function RemoveFromArray (index) {
if (index==0)
return this.shift();
else if (index==this.length-1)
return this.pop();
var c = this[index];
var rest = this.slice(index+1);
this.length = index;
this.push.apply(this, rest);
return c;
}
//====================================================
// Define Image Loader ====================================
/* Loader image file from specified path. It contains a image cache.
Primarily provides the "GetImg()" method */
var ImageLoader = new function (Prop) {
var ImgCacheCapacity = Prop.Image.ImageCacheCapacity;
if (ImgCacheCapacity) {
// Cache array is always sorted, sort by last accessed.
// Array's length never change.
// No empty element, only empty "cacheitem".
// No item will really be deleted, only be deassigned.
var ImgsCache = new Array;
// Admissible size error in cache reading.
ImgsCache.ImgSizeError1 = 10; // For enlarge.
ImgsCache.ImgSizeError2 = 50; // For shrink.
// Class of the items in cache.
ImgsCache.cacheItem = function (path, imgobj) {
this.Path = path; // String.
this.ImgObj = imgobj; // Object, gdi.image() object, or empty.
this.srcW = 0; // Source width.
this.srcH = 0; // Source height
};
// Fill the cache array with empty cacheitems.
for (var i=0; i<ImgCacheCapacity-1; i++)
ImgsCache.push(new ImgsCache.cacheItem(null, null));
// Remove element from cache array, return the removed element.
ImgsCache.remove = RemoveFromArray;
// Store item in the beginning of the cache array. Duplicate item's "ImgObj" will be overwritten.
ImgsCache.Store = function (path, imgobj, srcW, srcH) {
var c;
if (this.SearchFor(path)) {
c = this[0]; // This is the one just found.
c.ImgObj = imgobj;
if (srcW) c.srcW = srcW;
if (srcH) c.srcH = srcH;
} else if (c = this.pop()) {
c.Path = path;
c.ImgObj = imgobj;
c.srcW = srcW ? srcW : (imgobj ? imgobj.width : 0); // Store source width.
c.srcH = srcH ? srcH : (imgobj ? imgobj.height : 0); // Store source height.
this.unshift©;
}
};
// Search in cache, find the image object.
// Resize "ImgObj" to "dst" size, if current size is not enough, and the source size is closer, remove this item and return nothing.
// Or, move it to the beginning of the cache array, then resize image, then return this cache item.
// If no result found, return nothing.
ImgsCache.SearchFor = function (path, dstW, dstH) {
var i = 0;
for (i; i<this.length; i++) // Find it.
if (this[i].Path==path)
break;
if (i<this.length) {
var c = this.remove(i);
var img = c.ImgObj;
// For resizing------------------------
if (img && dstW && dstH) {
var size = CalcNewImgSize(img, dstW, dstH, c.srcW, c.srcH);
// If image should be enlarged and it still can be enlarged...
if ((size.width>img.width && img.width<c.srcW) || (size.height>img.height && img.height<c.srcH)) {
// If the dst size is not too large...
if (size.width-img.width<this.ImgSizeError1 && size.width<c.srcW && size.height-img.height<this.ImgSizeError1 && size.height<c.srcH)
img = ResizeImg(img, size.width, size.height); // Only resize, no cache.
else {
// Return to reload image file.
this.push©;
return;
}
// If it's shrinking...
} else if (size.width<img.width || size.height<img.height) {
// If the dst size is too small...
if (img.width-size.width>this.ImgSizeError2 || img.height-size.height>this.ImgSizeError2) {
img = ResizeImg(img, size.width, size.height); // Resize and cache.
c.ImgObj = img;
} else
img = ResizeImg(img, size.width, size.height); // Resize and don't cache.
} else {
size = CalcNewImgSize(img, dstW, dstH);
img = ResizeImg(img, size.width, size.height);
c.ImgObj = img;
}
}
//------------------------------------
this.unshift©;
return (img || true); // If path was found, return something "true" at all times.
}
};
// Clear cache, only reset all cache items indeed.
ImgsCache.Clear = function () {
for (var i=0; i<this.length-1; i++) {
this[i].Path = null;
this[i].ImgObj = null;
this[i].srcW = 0;
this[i].srcH = 0;
}
};
}
// Load image file from specified path, generate gdi.image() object, resize it, cache it, then return it.
// If path invalid or file corrupt, return nothing.
this.GetImg = function (path, dstW, dstH, NoCache) {
if (!path) return;
var imgobj;
if (!NoCache && ImgsCache)
imgobj = ImgsCache.SearchFor(path, dstW, dstH);
if (imgobj) {
if (typeof(imgobj)!="object") imgobj = null; // Maybe it's a boolean value.
} else {
if (path.charAt(0)=="<") // Embed image.
imgobj = utils.GetAlbumArtEmbedded(path.substring(1, path.length-1), 0);
else
imgobj = gdi.image(path);
var srcW, srcH;
if (imgobj) {
srcW = imgobj.width;
srcH = imgobj.height;
if (dstW && dstH) {
var size = CalcNewImgSize(imgobj, dstW, dstH);
imgobj = ResizeImg(imgobj, size.width, size.height);
}
}
// Store every path, even no valid image exists.
ImgsCache && ImgsCache.Store(path, imgobj, srcW, srcH);
}
if (imgobj)
return imgobj;
};
this.ClearCache = function () {
ImgsCache && ImgsCache.Clear();
};
} (Properties);
var GetImg = ImageLoader.GetImg;
//====================================================
// Define Path Checker =====================================
/* Find matches image files in directorys. It contains a paths cache.
Primarily provides the "GetImgPaths()" method */
var PathChecker = new function (Prop, ImgLoader) {
var FSO = Prop.Panel.FSO;
var ImgSrcFmt = Prop.Image.SourceFormat;
var ImgSrcStr = "";
var SupportTypes = Prop.Image.SupportTypes;
var MaxFileSize = Prop.Image.MaxFileSize;
var CycleInWildCard = Prop.Cycle.CycleInWildCard;
var GetEmbedImg = ImgLoader;
var FoundFiles = new Array;
var PathsArray;
var PathCacheCapacity = Prop.Image.PathCacheCapacity;
if (PathCacheCapacity) {
// This cache array is similar to the images cache array.
var PathsCache = new Array;
PathsCache.FSO = FSO;
PathsCache.cacheItem = function (path, files) {
this.Path = path; // String.
this.MatchFiles = files; // Must an array, path array.
};
for (var i=0; i<PathCacheCapacity-1; i++)
PathsCache.push(new PathsCache.cacheItem(null, null))
PathsCache.remove = RemoveFromArray;
// Duplicate item will be overwritten.
PathsCache.Store = function (path, files) {
var c;
if (this.SearchFor(path))
this[0].MatchFiles = files;
else if (c = this.pop()) {
c.Path = path;
c.MatchFiles = files;
this.unshift©;
}
};
// Search in cache, returns the search result, and move it to the beginning of the cache array.
// All files in result array will be checked before return, if one or more files doesn't exist, remove this item and return nothing.
// If no result found, return nothing.
PathsCache.SearchFor = function (path) {
var i = 0;
for (i; i<this.length; i++)
if (this[i].Path==path)
break;
if (i<this.length) {
var c = this.remove(i);
var rslt = c.MatchFiles;
for (var j=0; j<rslt.length; j++) // Check whether all the files are exist.
if (!this.FSO.FileExists(rslt[j])) {
c.Path = null;
this.push©;
return;
}
this.unshift©;
return rslt;
}
};
PathsCache.Clear = function () {
for (var i=0; i<this.length-1; i++) {
this[i].Path = null;
this[i].MatchFiles = null;
}
};
}
// Union Array2 into Array1.
var unionArray = function (Array1, Array2 ) {
var seen = {};
for (var i=0; i<Array1.length; i++)
seen[Array1[i]] = true;
for (var i=0; i<Array2.length; i++)
if (!seen[Array2[i]])
Array1.push(Array2[i]);
};
// Calculate ImageSourceFormat, and replace <embed> with <rawpath>.
var CalcPathFmt = function (pathfmt, metadb) {
if (metadb)
var paths = fb.TitleFormat(ImgSrcFmt).EvalWithMetadb(metadb)
else
var paths = fb.TitleFormat(ImgSrcFmt).Eval();
paths = paths.replace(/<embed>/gi, "<"+metadb.RawPath+">");
return paths;
};
// Check file type and file size.
var IsFilePropOK = function (file) {
var ext = FSO.GetExtensionName(file).toLowerCase();
for (var i=0; i<SupportTypes.length; i++) {
if (ext==SupportTypes[i] && (MaxFileSize<=0 || file.Size<=MaxFileSize))
return true;
}
return false;
};
// Find matches image files in "ImgSrc", cache relational paths, return the valid paths array.
// If "ImgSrc" has nothing changed, return the previous array directly.
// If no valid path found, return an empty array.
this.GetImgPaths = function (metadb) {
var newsrc = CalcPathFmt(ImgSrcFmt, metadb);
if (newsrc==ImgSrcStr)
return FoundFiles; // If the source format has nothing changed, return the previous results directly.
else
ImgSrcStr = newsrc;
PathsArray = ImgSrcStr.split("||");
var NewFoundFiles = new Array;
for (var i=0; i<PathsArray.length; i++) {
var Path = PathsArray[i];
var SearchResults = PathsCache ? PathsCache.SearchFor(Path) : null;
if (!SearchResults) {
SearchResults = new Array;
var EmbedPath = Path.match(/<.*>/);
if (EmbedPath) { // Check embed cover.
EmbedPath = EmbedPath.toString();
if (GetEmbedImg(EmbedPath))
SearchResults.push(EmbedPath);
} else if (Path.indexOf("*")==-1 && Path.indexOf("?")==-1) { // If not wildcard exist.
if (!FSO.FileExists(Path)) continue;
SearchResults.push(Path);
} else { // Search in wildcard.
var foldername = FSO.GetParentFolderName(Path);
if (!FSO.FolderExists(foldername)) continue;
if (CycleInWildCard) {
// Check file type and size first -----------------
var ValidFiles = PathsCache ? PathsCache.SearchFor(foldername+"\\*") : null; // Search in cache first.
if (!ValidFiles) {
ValidFiles = new Array;
var e = new Enumerator(FSO.GetFolder(foldername).Files);
for (; !e.atEnd(); e.moveNext()) {
var file = e.item();
if (IsFilePropOK(file))
ValidFiles.push(file.Path);
}
PathsCache && PathsCache.Store(foldername+"\\*", ValidFiles); // Store this step's result in cache.
}
// Then match wildcard ------------------
var exp = FSO.GetFileName(Path);
if (exp!="*" && exp!="*.*") {
for (var j=0; j<ValidFiles.length; j++) {
if (utils.PathWildcardMatch(exp, FSO.GetFileName(ValidFiles[j])))
SearchResults.push(ValidFiles[j]);
}
} else
SearchResults = ValidFiles;
} else {
var exp = FSO.GetFileName(Path);
var e = new Enumerator(FSO.GetFolder(foldername).Files);
for (; !e.atEnd(); e.moveNext()) {
var file = e.item();
if (IsFilePropOK(file) && utils.PathWildcardMatch(exp, file.Name)) {
SearchResults.push(file.Path);
break; // One file per path is enough.
}
}
}
}
PathsCache && PathsCache.Store(Path, SearchResults); // Store search results for this path.
}
// Merge these files of this path into the final results, duplicate files will only keep one.
unionArray(NewFoundFiles, SearchResults);
}
if (NewFoundFiles.join()!=FoundFiles.join()) // If the result has nothing changed, return the previous results directly.
FoundFiles = NewFoundFiles;
CollectGarbage(); // Release memory.
return FoundFiles;
};
this.ClearCache = function () {
PathsCache && PathsCache.Clear();
ImgSrcStr = "";
};
} (Properties, GetImg);
var GetImgPaths = PathChecker.GetImgPaths;
//====================================================
// Define Display Style =====================================
/* Define style, display image and animation.
Primarily provides the "ChangeImage()" method */
var Display = new function (Prop, ImgLoader) {
this.margin = {top: 0, left: 0, bottom: 0, right: 0};
this.x = this.margin.left;
this.y = this.margin.top;
this.width;
this.height;
var FSO = Prop.Panel.FSO;
var EnableFading = Prop.Cycle.Animation.Enable;
var RefreshInterval = Prop.Cycle.Animation.RefreshInterval;
var step = Math.min(Math.ceil(255*RefreshInterval/Prop.Cycle.Animation.Duration),255);
var DefaultImg = gdi.image(Prop.Image.DefaultImagePath);
var ext = FSO.GetExtensionName(Prop.Image.DefaultImagePath).toLowerCase();
var DefaultRaw = null;
if (DefaultImg && ext!="png" && ext!="gif")
DefaultRaw = DefaultImg.CreateRawBitmap();
var ImgPath = null;
var CurImage = DefaultImg;
var CurRaw = DefaultRaw;
var CurSize = null;
var NewImage = null;
var NewSize = null;
var CanBeCreateRaw = true;
var opacity = 255;
var timer = null;
if (ImgLoader)
var GetImg = ImgLoader;
else
var GetImg = function () {
return gdi.image(path);
};
// Change now displaying image to the new one.
// "path" is a string object, or empty.
// When "path" is empty, means change to style default image (DefaultImg).
// "GroupChanged" means "GroupFormat" calculate result changes.
this.ChangeImage = function (path, GroupChanged) {
if (path==ImgPath) return;
ImgPath = path;
var newimg;
if (ImgPath) {
newimg = GetImg(ImgPath, this.width, this.height);
var ext = FSO.GetExtensionName(ImgPath).toLowerCase();
CanBeCreateRaw = ext!="png" && ext!="gif";
} else
newimg = DefaultImg;
if (EnableFading) {
if (NewImage) {
CurImage = NewImage;
//CurRaw = NewImage==DefaultImg ? DefaultRaw : (CanBeCreateRaw ? CurImage.CreateRawBitmap() : null);
CurSize = NewSize;
opacity = 255;
}
NewImage = newimg;
NewSize = CalcNewImgSize(NewImage, this.width, this.height);
if (!timer) timer = window.CreateTimerInterval(RefreshInterval);
} else {
CurImage = newimg;
CurRaw = ImgPath ? (CanBeCreateRaw ? CurImage.CreateRawBitmap() : null) : DefaultRaw;
CurSize = CalcNewImgSize(CurImage, this.width, this.height);
window.RepaintRect(this.x, this.y, this.width, this.height);
}
};
this.Refresh = function () {
if (ImgPath) {
CurImage = GetImg(ImgPath, this.width, this.height, true); // Get image bypass cache.
if (CurRaw) CurRaw = CurImage.CreateRawBitmap();
} else {
DefaultImg = gdi.image(Prop.Image.DefaultImagePath);
DefaultRaw = DefaultImg.CreateRawBitmap();
CurImage = DefaultImg;
CurRaw = DefaultRaw;
}
if (CurImage)
CurSize = CalcNewImgSize(CurImage, this.width, this.height);
if (NewImage)
NewSize = CalcNewImgSize(NewImage, this.width, this.height);
window.Repaint();
};
this.OnPaint = function (gr) {
var Img, size;
if (Img = CurImage) {
size = CurSize;
if (opacity==255 && CurRaw)
// This funtion is much more faster.
gr.GdiDrawBitmap(CurRaw, this.x+size.x, this.y+size.y, size.width, size.height, 0, 0, Img.width, Img.height);
else
gr.DrawImage(Img, this.x+size.x, this.y+size.y, size.width, size.height, 0, 0, Img.width, Img.height, 0, opacity);
}
if (Img = NewImage) {
size = NewSize;
gr.DrawImage(Img, this.x+size.x, this.y+size.y, size.width, size.height, 0, 0, Img.width, Img.height, 0, 255-opacity);
}
};
this.OnTimer = function (id) {
if (timer && id==timer.ID) {
if (opacity>0) {
opacity = Math.max(opacity-step,0);
window.RepaintRect(this.x, this.y, this.width, this.height);
} else {
CurImage = NewImage;
CurRaw = ImgPath ? (CanBeCreateRaw ? CurImage.CreateRawBitmap() : null) : DefaultRaw;
CurSize = NewSize;
NewImage = null;
NewSize = null;
opacity = 255;
timer && window.KillTimer(timer);
timer = null;
CollectGarbage(); // Release memory.
//window.RepaintRect(this.x, this.y, this.width, this.height);
}
}
};
this.OnResize = function (ww, wh) {
this.width = ww-this.margin.left-this.margin.right;
this.height = wh-this.margin.top-this.margin.bottom;
if (ImgPath) {
CurImage = GetImg(ImgPath, this.width, this.height);
if (CurRaw) CurRaw = CurImage.CreateRawBitmap();
}
if (CurImage)
CurSize = CalcNewImgSize(CurImage, this.width, this.height);
if (NewImage)
NewSize = CalcNewImgSize(NewImage, this.width, this.height);
};
} (Properties, GetImg);
//====================================================
// Define Main Controler ====================================
/* Main controler of the panel,
controls images loading, changing, cycle, and paths checking */
var Controler = new function (Prop, GetImgPaths, Dsp) {
var CycleEnabled = Prop.Cycle.Enable;
this.CycleActivated = false;
var CyclePeriod = Prop.Cycle.Period;
var GroupFmt = Prop.Image.GroupFormat;
var GroupStr = null;
var ImgPaths = null;
this.CurImgPath = null;
var CurImgIdx = 0;
this.Paused = window.GetProperty("Cycle.Paused", !CycleEnabled);
var timer = null;
var _this = this;
var ChangeImg = function (arg, GroupChanged) {
switch (arg) {
case 2: // Last
CurImgIdx = ImgPaths.length-1;
break;
case 1: // Next
CurImgIdx = CurImgIdx+1<ImgPaths.length ? CurImgIdx+1 : 0;
break;
case -1: // Previous
CurImgIdx = CurImgIdx-1>=0 ? CurImgIdx-1 : ImgPaths.length-1;
break;
case -2: // First
CurImgIdx = 0;
break;
default: // Default
arg = 0;
}
var path = arg ? ImgPaths[CurImgIdx] : null;
toDefault(path ? false : true);
if (!GroupChanged && path==_this.CurImgPath)
return;
else
_this.CurImgPath = path;
Dsp.ChangeImage(_this.CurImgPath, GroupChanged);
};
var ResetTimer = function () {
if (!timer) return;
window.KillTimer(timer);
timer = window.CreateTimerInterval(CyclePeriod);
CollectGarbage(); // Release memory.
};
this.Play = function () {
this.Paused = false;
window.SetProperty("Cycle.Paused", this.Paused);
if (!this.CycleActivated) return;
if (!timer) timer = window.CreateTimerInterval(CyclePeriod);
};
this.Pause = function (p) {
if (!p) {
this.Paused = true;
window.SetProperty("Cycle.Paused", this.Paused);
}
if (!this.CycleActivated) return;
if (timer) {
window.KillTimer(timer);
timer = null;
CollectGarbage(); // Release memory.
}
};
this.Next = function () {
if (!this.CycleActivated) return;
ResetTimer();
ChangeImg(1);
};
this.Previous = function () {
if (!this.CycleActivated) return;
ResetTimer();
ChangeImg(-1);
};
this.First = function () {
if (!this.CycleActivated) return;
ResetTimer();
ChangeImg(-2);
};
this.Last = function () {
if (!this.CycleActivated) return;
ResetTimer();
ChangeImg(2);
};
this.OnNewTrack = function (metadb, followcur) {
var NewImgPaths = GetImgPaths(metadb);
if (metadb)
var groupstr = fb.TitleFormat(GroupFmt).EvalWithMetadb(metadb)
else
var groupstr = fb.TitleFormat(GroupFmt).Eval();
if (GroupStr!=groupstr) {
GroupStr = groupstr;
var IsNewGroup = true;
} else
var IsNewGroup = false;
if (ImgPaths!=NewImgPaths || IsNewGroup) {
ImgPaths = NewImgPaths;
if (ImgPaths.length<=1)
SetCycleStatus(false);
else
SetCycleStatus(CycleEnabled);
ResetTimer();
ChangeImg(-2, IsNewGroup);
}
if (followcur && Prop.Cycle.AutoPauseWhenFollowCursor) {
this.Pause(true);
if (CurImgIdx!=0)
ChangeImg(-2);
} else
!this.Paused && this.Play();
};
this.OnStop = function (reason) {
timer && window.KillTimer(timer);
if (reason<=1)
ChangeImg();
if (reason!=2) {
this.Pause(true);
SetCycleStatus(false);
ImgPaths = null;
this.CurImgPath = null;
CurImgIdx = 0;
GroupStr = null;
}
};
this.OnTimer = function (id) {
if (timer && id==timer.ID)
this.Next();
};
} (Properties, GetImgPaths, Display);
//====================================================
// Define Control Buttons ===================================
/* All button's funtions are calls of Controler's method */
if (Properties.Buttons.Display && Properties.Cycle.Enable) {
var Buttons = new function (Prop, Ctrl) {
var BtnDir = Prop.Panel.WorkDirectory + "Buttons\\";
var lang = Prop.Panel.lang;
var Position = Prop.Buttons.Position;
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
var opacity = 0;
var defaultOp = 150;
var hbtn = null;
var dbtn = null;
var timer = null;
var RefreshInterval = 50;
var step = 40;
var dstOp = 0;
var _this = this;
this.BtnsArray = new Array();
// Define button class ------------------------------------------------
var Button = function (x, y, img, OnClick, tiptext) {
this.x = x;
this.y = y;
this.width = img.width/4;
this.height = img.height;
this.Img = img;
this.tiptext = tiptext;
this.state = 3; // 0=normal, 1=hover, 2=down, 3=disabled
this.enabled = false;
this.OnClick = OnClick;
var Tooltip = Prop.Panel.Tooltip;
this.isXYinBtn = function (x, y) {
if (!this.enabled) return false;
return (x >= this.x && y >= this.y && x<= this.x + this.width && y <= this.y + this.height) ? true : false;
};
this.Draw = function (gr, op) {
if (!opacity) return;
gr.DrawImage(this.Img, this.x, this.y, this.width, this.height, this.state*this.Img.width/4, 0, this.width, this.height, 0, opacity);
};
this.ChangeState = function (s, enabled) {
//if (!this.enabled && !enabled) return;
if (enabled===undefined) {
if (s==this.state)
return;
else
this.state = s;
} else {
this.enabled = enabled;
this.state = enabled ? 0 : 3;
}
if (s==1) {
Tooltip.Text = this.tiptext;
Tooltip.Activate();
} else
Tooltip.Deactivate();
if (opacity)
window.RepaintRect(this.x, this.y, this.width, this.height);
};
};
// Create buttons --------------------------------
var img_play = gdi.image(BtnDir+"Play.png");
var img_pause = gdi.image(BtnDir+"Pause.png");
var img_next = gdi.image(BtnDir+"Next.png");
var img_prev = gdi.image(BtnDir+"Prev.png");
var xOffset = this.x;
this.BtnsArray.push(new Button(xOffset, this.y, img_prev, function(){Ctrl.Previous();}, lang=="cn" ? "上一张图片" : "Previous Image"));
xOffset += this.BtnsArray[this.BtnsArray.length-1].width;
this.BtnsArray.push(PlayBtn = new Button(xOffset, this.y, img_play, function(){SetPauseStatus(Ctrl.Paused)}, ""));
xOffset += this.BtnsArray[this.BtnsArray.length-1].width;
this.BtnsArray.push(new Button(xOffset, this.y, img_next, function(){Ctrl.Next();}, lang=="cn" ? "下一张图片" : "Next Image"));
xOffset += this.BtnsArray[this.BtnsArray.length-1].width;
PlayBtn.tiptext_play = lang=="cn" ? "循环封面" : "Cycle Covers";
PlayBtn.tiptext_pause = lang=="cn" ? "暂停循环" : "Pause Cycle";
PlayBtn.tiptext = Ctrl.Paused ? PlayBtn.tiptext_play : PlayBtn.tiptext_pause;
PlayBtn.img_pause = img_pause;
PlayBtn.img_play = img_play;
PlayBtn.Img = Ctrl.Paused ? PlayBtn.img_play : PlayBtn.img_pause;
PlayBtn.ChangeState(null, true);
this.PlayBtn = PlayBtn;
this.width = xOffset-this.x;
this.height = PlayBtn.height;
//---------------------------------------
this.SetCycleStatus = function (s) {
this.BtnsArray[0].ChangeState(null, s);
this.BtnsArray[2].ChangeState(null, s);
};
this.SetPauseStatus = function (s) {
if (s) {
PlayBtn.Img = PlayBtn.img_pause;
PlayBtn.tiptext = PlayBtn.tiptext_pause;
} else {
PlayBtn.Img = PlayBtn.img_play;
PlayBtn.tiptext = PlayBtn.tiptext_play;
}
};
var isXYinBtns = function (x, y) {
return (x >= _this.x && y >= _this.y && x<= _this.x + _this.width && y <= _this.y + _this.height) ? true : false;
};
var Fading = function (dstop) {
if (dstOp==dstop) return;
dstOp = dstop;
if (!timer) timer = window.CreateTimerInterval(RefreshInterval);
};
this.OnPaint = function (gr) {
if (!opacity) return;
for (var i=0; i<this.BtnsArray.length; i++)
this.BtnsArray[i].Draw(gr, opacity);
};
this.OnMouseMove = function (x, y) {
if (isXYinBtns(x, y)) {
if (opacity!=255) {
dstOp = 255;
opacity = 255;
window.RepaintRect(this.x, this.y, this.width, this.height);
}
} else if (opacity!=defaultOp)
Fading(defaultOp);
if (dbtn) {
if (dbtn.isXYinBtn(x, y))
dbtn.ChangeState(2);
else
dbtn.ChangeState(1);
} else {
for (var i=0; i < this.BtnsArray.length ; i++)
if (this.BtnsArray[i].isXYinBtn(x,y)) {
if (hbtn!=this.BtnsArray[i]) {
if(hbtn) hbtn.ChangeState(0);
hbtn = this.BtnsArray[i];
hbtn.ChangeState(1);
}
break;
}
if (i==this.BtnsArray.length) {
if (hbtn) {
hbtn.ChangeState(0);
hbtn = null;
}
}
}
};
this.OnLbtnDown = function (x, y) {
if (hbtn) {
dbtn = hbtn;
dbtn.ChangeState(2);
}
};
this.OnLbtnUp = function (x, y) {
if (dbtn) {
if (dbtn.state==2) {
dbtn.OnClick();
dbtn.ChangeState(1);
}
dbtn = null;
this.OnMouseMove(x, y);
}
};
this.OnMouseLeave = function () {
Fading(0);
if (hbtn) {
hbtn.ChangeState(0);
hbtn = null;
}
};
this.OnTimer = function (id) {
if (timer && id==timer.ID) {
if (opacity==dstOp) {
timer && window.KillTimer(timer);
timer = null;
CollectGarbage(); // Release memory.
//window.RepaintRect(this.x, this.y, this.width, this.height);
} else {
if (opacity<dstOp)
opacity = Math.min(opacity+step, dstOp);
else
opacity = Math.max(opacity-step, dstOp);
window.RepaintRect(this.x, this.y, this.width, this.height);
}
}
};
this.OnResize = function (ww, wh) {
if (Position==1 || Position==4)
this.x = (ww-this.width)/2;
else if (Position==2 || Position==5)
this.x = ww-this.width;
if (Position>2)
this.y = wh-this.height;
var x = this.x;
for (var i=0; i<this.BtnsArray.length; i++) {
this.BtnsArray[i].x = x;
x += this.BtnsArray[i].width;
this.BtnsArray[i].y = this.y;
};
this.width = x-this.x;
};
} (Properties, Controler);
} else
var Buttons = {};
//====================================================
// Functions Menu ========================================
var FuncMenu = new function (Prop, Ctrl, Dsp, Btns, ImgLoader, ImgFinder) {
// Flags ----------
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;
var lang = Prop.Panel.lang;
var ItemList = {};
var ItemID = 1;
var BuildMenu = function (items) {
var menu = window.CreatePopupMenu();
var mf, id, radio;
for (var i=0; i<items.length; i++) {
mf = items[i].Flag || MF_STRING;
id = items[i].ID || ItemID++;
menu.AppendMenuItem(mf, id, items[i].Caption);
if (i==items.Radio)
radio = id;
ItemList[id] = items[i];
}
radio && menu.CheckMenuRadioItem(1, items.length, radio);
return menu;
};
// Submenu: Follow Cursor -------------------------
var Menu_FC_Items = new Array(
{
Caption: lang=="cn" ? "仅在非播放时" : "Only when not playing",
Func: function(){
if (Prop.Panel.FollowCursor==1) return;
Prop.Panel.FollowCursor = 1;
window.SetProperty("Panel.FollowCursor", 1);
Menu_FC_Items.Radio = 0;
if (fb.IsPlaying)
on_playback_new_track(fb.GetNowPlaying());
else
on_item_focus_change(fb.GetFocusItem());
RebuildMenu();
}
},
{
Caption: lang=="cn" ? "总是" : "Always",
Func: function(){
if (Prop.Panel.FollowCursor==2) return;
Prop.Panel.FollowCursor = 2;
window.SetProperty("Panel.FollowCursor", 2);
Menu_FC_Items.Radio = 1;
on_item_focus_change(fb.GetFocusItem());
RebuildMenu();
}
},
{
Caption: lang=="cn" ? "从不" : "Never",
Func: function(){
if (Prop.Panel.FollowCursor==0) return;
Prop.Panel.FollowCursor = 0;
window.SetProperty("Panel.FollowCursor", 0);
Menu_FC_Items.Radio = 2;
if (fb.IsPlaying)
on_playback_new_track(fb.GetNowPlaying());
else
on_playback_stop(0);
RebuildMenu();
}
}
);
var fc = Prop.Panel.FollowCursor;
Menu_FC_Items.Radio = fc==1 ? 0 : fc==2 ? 1 : fc==0 ? 2 : null;
var Menu_SubItem_FC = {
Flag: MF_POPUP,
Caption: lang=="cn" ? "光标跟随模式" : "Follow Cursor",
ID: null
}
// Submenu: Image Stretching ----------------------
var Menu_IS_Items = new Array(
{
Flag: Prop.Image.Stretch ? MF_CHECKED : MF_UNCHECKED,
Caption: lang=="cn" ? "拉伸图像" : "Stretch Image",
Func: function(){
Prop.Image.Stretch = !Prop.Image.Stretch;
window.SetProperty("Image.Stretch", Prop.Image.Stretch);
this.Flag = Prop.Image.Stretch ? MF_CHECKED : MF_UNCHECKED;
Dsp && Dsp.Refresh();
RebuildMenu();
}
},
{
Flag: Prop.Image.KeepAspectRatio ? MF_CHECKED : MF_UNCHECKED,
Caption: lang=="cn" ? "保持比例" : "Keep Aspect Ratio",
Func: function(){
Prop.Image.KeepAspectRatio = !Prop.Image.KeepAspectRatio;
window.SetProperty("Image.KeepAspectRatio", Prop.Image.KeepAspectRatio);
this.Flag = Prop.Image.KeepAspectRatio ? MF_CHECKED : MF_UNCHECKED;
Dsp && Dsp.Refresh();
RebuildMenu();
}
}
);
var Menu_SubItem_IS = {
Flag: MF_POPUP,
Caption: lang=="cn" ? "图像拉伸" : "Image Stretching",
ID: null
}
// Main menu --------------------------------
var Item_cycle = {
Flag: MF_ENABLED,
cap_play: lang=="cn" ? "继续循环" : "Resume Cycle",
cap_pause: lang=="cn" ? "暂停循环" : "Pause Cycle",
Caption: null,
Func: function () {Ctrl && SetPauseStatus(Ctrl.Paused);}
};
Item_cycle.Caption = Ctrl.Paused ? Item_cycle.cap_play : Item_cycle.cap_pause;
var Item_VWEV, Item_OIF;
var Menu_Items = new Array (
Item_cycle,
{
Flag: MF_GRAYED,
Caption: lang=="cn" ? "上一张图片" : "Previous Image",
Func: function(){Ctrl & Ctrl.Previous();}
},
{
Flag: MF_GRAYED,
Caption: lang=="cn" ? "下一张图片" : "Next Image",
Func: function(){Ctrl && Ctrl.Next();}
},
{
Flag: MF_GRAYED,
Caption: lang=="cn" ? "第一张图片" : "First Image",
Func: function(){Ctrl && Ctrl.First();}
},
{
Flag: MF_GRAYED,
Caption: lang=="cn" ? "最后一张图片" : "Last Image",
Func: function(){Ctrl && Ctrl.Last();}
},
//--------------------------------------------------------------
Item_VWEV = {
Flag: MF_GRAYED,
Caption: lang=="cn" ? "在外部查看器中查看" : "View With External Viewer",
Func: function(){
var path = Ctrl.CurImgPath;
if (!path) return;
if (path.charAt(0)=="<") {
fb.ShowPopupMessage(lang=="cn" ? "当前图片为内嵌图片,无法用外部查看器显示" : "This image is embed image, can't be displayed in external viewer", "WSH Cover Panel", 1);
return;
}
if (!Prop.Panel.ShellObj)
Prop.Panel.ShellObj= new ActiveXObject("Shell.Application");
Prop.Panel.ShellObj.ShellExecute('"' + path + '"', "", "", "open", 1);
}
},
Item_OIF = {
Flag: MF_GRAYED,
Caption: lang=="cn" ? "打开图片所在目录" : "Open Containing Folder",
Func: function(){
var path = Ctrl.CurImgPath;
if (!path) return;
if (path.charAt(0)=="<")
path = path.substring(1, path.length-1);
if (!Prop.Panel.ShellObj)
Prop.Panel.ShellObj= new ActiveXObject("Shell.Application");
Prop.Panel.ShellObj.ShellExecute("explorer", '/select,\"' + path + '"', "", "open", 1);
}
},
{
Flag: MF_SEPARATOR // Insert separator.
},
Menu_SubItem_IS // Insert "Image Stretching" submenu.
,
Menu_SubItem_FC // Insert "Follow Cursor" submenu.
,
{
Flag: MF_SEPARATOR
},
{
Caption: lang=="cn" ? "刷新图片" : "Refresh Image",
Func: function(){Dsp && Dsp.Refresh();}
},
{
Flag: (Prop.Image.ImageCacheCapacity || Prop.Image.PathCacheCapacity) ? MF_ENABLED : MF_GRAYED,
Caption: lang=="cn" ? "清除缓存" : "Clear Cache",
Func: function () {
ImgLoader && ImgLoader.ClearCache();
ImgFinder && ImgFinder.ClearCache();
CollectGarbage(); // Release memory.
}
},
{
Flag: MF_SEPARATOR
},
{
Caption: lang=="cn" ? "WSH Cover 参数设置..." : "WSH Cover Properties...",
Func: function(){window.ShowProperties();}
},
{
Caption: lang=="cn" ? "帮助..." : "Help...",
Func: function(){
var HelpFile = Prop.Panel.WorkDirectory + "WSH_Cover_Properties_Help.txt";
if (!Prop.Panel.FSO.FileExists(HelpFile)) {
fb.ShowPopupMessage(Prop.Panel.lang=="cn" ? "找不到 "+HelpFile+" 文件." : "Can not find file "+HelpFile+" .", "WSH Cover Panel", 1);
return;
}
var file = Prop.Panel.FSO.OpenTextFile(HelpFile, 1);
var txt = file.ReadAll();
fb.ShowPopupMessage(txt, "WSH Cover Panel", 2);
file.Close();
}
}
);
this.ViewWithExternalViewer = Item_VWEV.Func;
this.Menu_Items = Menu_Items;
var Menu, Menu_FC;
var RebuildMenu = function(){
ItemList = {};
ItemID = 1;
Menu_FC = BuildMenu(Menu_FC_Items);
Menu_SubItem_FC.ID = Menu_FC.ID;
Menu_IS = BuildMenu(Menu_IS_Items);
Menu_SubItem_IS.ID = Menu_IS.ID;
Menu = BuildMenu(Menu_Items);
};
this.RebuildMenu = RebuildMenu;
RebuildMenu();
this.Show = function (x, y) {
var ret = Menu.TrackPopupMenu(x, y);
if (ret!=0)
ItemList[ret].Func();
};
this.SetCycleStatus = function (s) {
for (var i=1; i<5; i++)
Menu_Items[i].Flag = s ? MF_ENABLED : MF_GRAYED;
RebuildMenu();
};
this.SetPauseStatus = function (s) {
if (s)
Item_cycle.Caption = Item_cycle.cap_pause;
else
Item_cycle.Caption = Item_cycle.cap_play;
RebuildMenu();
};
var IsDefaultImg = true;
this.toDefault = function (s) {
if (s==IsDefaultImg) return;
IsDefaultImg = s;
Item_VWEV.Flag = s ? MF_GRAYED : MF_ENABLED;
Item_OIF.Flag = s ? MF_GRAYED : MF_ENABLED;
RebuildMenu();
};
} (Properties, Controler, Display, Buttons, ImageLoader, PathChecker);
//====================================================
function SetCycleStatus (s) {
Controler.CycleActivated = s;
Buttons.SetCycleStatus && Buttons.SetCycleStatus(s);
FuncMenu && FuncMenu.SetCycleStatus(s);
};
function SetPauseStatus (s) {
if (s)
Controler.Play();
else
Controler.Pause();
Buttons.SetPauseStatus && Buttons.SetPauseStatus(s);
FuncMenu && FuncMenu.SetPauseStatus(s);
};
function toDefault (s) {
FuncMenu && FuncMenu.toDefault(s);
};
//====================================================
// BackGround ===========================================
var bgcolor = Properties.Panel.BackGroundColor;
if (bgcolor)
bgcolor = RGBA(bgcolor[0], bgcolor[1], bgcolor[2], bgcolor[3]);
//====================================================
//====================================================
function on_paint(gr){
gr.SetSmoothingMode(Properties.Image.SmoothingMode);
gr.SetInterpolationMode(Properties.Image.InterpolationMode);
if (bgcolor)
gr.FillSolidRect(0, 0, ww, wh, bgcolor);
Display.OnPaint && Display.OnPaint(gr);
Buttons.OnPaint && Buttons.OnPaint(gr);
}
function on_size(){
if (!window.Width || !window.Height) return;
ww = window.Width;
wh = window.Height;
Display.OnResize && Display.OnResize(ww, wh);
Buttons.OnResize && Buttons.OnResize(ww, wh);
}
// Track events ---------------------------------------------
function on_item_focus_change(){
if (fb.GetFocusItem() && (Properties.Panel.FollowCursor==2 || (Properties.Panel.FollowCursor==1 && !fb.IsPlaying)))
Controler.OnNewTrack && Controler.OnNewTrack(fb.GetFocusItem(), true);
}
function on_playback_new_track(metadb){
if (Properties.Panel.FollowCursor<=1)
Controler.OnNewTrack && Controler.OnNewTrack(metadb);
}
function on_playback_stop(reason){
var metadb = fb.GetFocusItem();
if (Properties.Panel.FollowCursor==0 || !metadb)
Controler.OnStop && Controler.OnStop(reason);
else if (Properties.Panel.FollowCursor==1 && reason!=2)
Controler.OnNewTrack && Controler.OnNewTrack(metadb, true);
}
// Mouse events --------------------------------------------
var rbtnDown, ShiftDown, mbtnDown;
function on_mouse_move(x,y){
Buttons.OnMouseMove && Buttons.OnMouseMove(x, y);
}
function on_mouse_lbtn_down(x,y){
Buttons.OnLbtnDown && Buttons.OnLbtnDown(x, y);
}
function on_mouse_lbtn_up(x,y){
Buttons.OnLbtnUp && Buttons.OnLbtnUp(x, y);
}
function on_mouse_leave(){
Buttons.OnMouseLeave && Buttons.OnMouseLeave();
}
function on_mouse_rbtn_down(x, y, vkey){
rbtnDown = true;
ShiftDown = vkey==6 ? true : false;
}
function on_mouse_rbtn_up(x, y, vkey){
if (!rbtnDown) return true;
rbtnDown = false;
if (ShiftDown)
return; // If shift key was pressed down, show default right click menu.
else {
FuncMenu.Show(x,y); // Show customize menu.
return true; // Disable default right click menu.
}
}
function on_mouse_mbtn_down(x, y, mask) {
mbtnDown = true;
}
function on_mouse_mbtn_up(x, y, mask) {
if (!mbtnDown) return;
FuncMenu.ViewWithExternalViewer();
mbtnDown = false;
}
function on_mouse_wheel(delta){
if (delta>0)
Controler && Controler.Previous();
else
Controler && Controler.Next();
}
//---------------------------------------------------------
function on_timer(id){
Controler.OnTimer && Controler.OnTimer(id);
Display.OnTimer && Display.OnTimer(id);
Buttons.OnTimer && Buttons.OnTimer(id);
}
http://maf.freedom-vrn.ru/Images.zip