Конфигурация zsx [01.05.2010]

Список разделов Аудиоплеер foobar2000 Сборки Архив

Описание: Архив выпусков предыдущих сборок.

Сообщение #1 Максим » 23.05.2008, 17:26

Мультиконфигурация временно разбита на две части: zsx и Jnt. Для скачивания доступна только конфигурация zsx.


Конфигурация zsx


Скриншоты:

Изображение Изображение Изображение


Ссылки:

Прочитайте на досуге:

Дополнительно:

Изображение
Последний раз редактировалось Sp1ke 02.05.2010, 12:10, всего редактировалось 1 раз.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца


Сообщение #641 diefun » 11.01.2010, 21:11

Правда не дает выставить 32 бит
Последний раз редактировалось diefun 11.01.2010, 23:01, всего редактировалось 1 раз.
diefun
Репутация: 0
С нами: 13 лет 1 месяц

Сообщение #642 Максим » 13.01.2010, 23:30

Разделил конфигурацию. Теперь zsx буду выкладывать отдельно.

Сделал несколько цветовых расцветок с простым переключением. Какие цвета добавить?

Реализовал меню с помощью WSH-панели. Теперь тулбары не нужны! :)
Последний раз редактировалось Sp1ke 14.01.2010, 00:59, всего редактировалось 1 раз.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #643 Qfile68 » 14.01.2010, 22:47

2Максим
А зачем разделил?
Qfile68
Репутация: 6
С нами: 12 лет 9 месяцев

Сообщение #644 Low_Pressure » 15.01.2010, 18:42

Максим:Разделил конфигурацию. Теперь zsx буду выкладывать отдельно.
Разумно) Уж слишком разные они по интерфейсу...
Максим:Сделал несколько цветовых расцветок с простым переключением. Какие цвета добавить?
Что-то серебристо-айподистое может? Впрочем, зеленый вполне себе приятен для глаз.
Изображение
Low_Pressure M
Аватара
Возраст: 33
Откуда: Москва
Репутация: 4
С нами: 13 лет 7 месяцев

Сообщение #645 Максим » 15.01.2010, 19:42

Qfile68
Пока мне удобнее именно так. Может, потом снова соединю. Jnt нужен капитальный ремонт.

Low_Pressure
Айподистое вряд ли получится, но серая расцветка теперь есть.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #646 Qfile68 » 15.01.2010, 21:44

2Максим
А может и не нужно соединять? Пусть каждый исспользует ту сборку,которая по душе.Лично мне больше нравилась Jnt ,zsx я и не исспользовал.В интерфейсе не нравилось лишь то,что вместо кнопок управления есть черные "дырки",причем все разных размеров.А вот цветовая схема подобрана  отлично.
Qfile68
Репутация: 6
С нами: 12 лет 9 месяцев

Сообщение #647 Low_Pressure » 19.01.2010, 01:01

Максим:Айподистое вряд ли получится, но серая расцветка теперь есть.
You're the boss) Ждем, в любом случае) И серьезно, foo_jesus крайне полезная штука - автосейвы плейлистов и настроек с регулируемыми интервалами.
Изображение
Low_Pressure M
Аватара
Возраст: 33
Откуда: Москва
Репутация: 4
С нами: 13 лет 7 месяцев

Сообщение #648 VuFeRoK » 20.01.2010, 03:14

Извините у меня 2 вопроса.
1) Сборка супер но в конфигурации jnt у меня почемуто не работают 2 кнопки Spectogram и lyric(нажимаю нажимаю а в ответ ноль эмоций), как это исправить?
2) и можно ли изменить вкладку Albums на Chonflow? а то на мой взгляд его в этой конфигурации не хватает))))

P.S. Сборка мне очень понравилась, она красивая и удобная и главное что не перегружена разными плагинами(это отразилось на скорости запуска)
Автору респект
VuFeRoK
Репутация: 0
С нами: 11 лет 6 месяцев

Сообщение #649 Максим » 22.01.2010, 19:22

VuFeRoK
Спасибо за отзыв и интерес к конфигурации. Я постараюсь поскорее обновить Jnt, но пока она не поддерживается.

Выложил новую версию zsx!
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #650 Qfile68 » 23.01.2010, 17:05

Засел над тестированием новой версии zsx, конфигурация очень понравилась!Мне кажется не достает кнопки "Clear".При не развернутом окне бывает рушатся кнопки переключения цветовой схемы.А только что плеер вылетел со словами:"foobar2000 has crashed"А в остальном все отлично ,Максим, большое спасибо за кофиг!
Да, еще -поскольку foobar2000 является плеером для прослушивания качественной музыки,то почему бы не включить еще пару плагинов по умолчанию для прослушивания lossless?
Qfile68
Репутация: 6
С нами: 12 лет 9 месяцев

Сообщение #651 Максим » 23.01.2010, 17:17

Qfile68
Мне кажется не достает кнопки "Clear".
А что она должна делать?

При не развернутом окне бывает рушатся кнопки переключения цветовой схемы.
Нужно подумать о минимальном размере окна. Они могут перекрываться с панелью обновлений.

А только что плеер вылетел со словами:"foobar2000 has crashed"
Не советую использовать старые компоненты, только самые необходимые. У меня после 3 дней тестов ни одного крэша. Я могу гарантировать стабильную работу только для такого комплекта: стандартные + включенные в конфиг компоненты.

почему бы не включить еще пару плагинов по умолчанию для прослушивания lossless?
Да, обязательно включу.

Спасибо за комментарий.
Последний раз редактировалось Sp1ke 23.01.2010, 17:20, всего редактировалось 1 раз.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #652 meDveD » 23.01.2010, 17:39

Не советую использовать старые компоненты, только самые необходимые. У меня после 3 дней тестов ни одного крэша. Я могу гарантировать стабильную работу только для такого комплекта: стандартные + включенные в конфиг компоненты.
две недели пока гонял v1.0 (+ около 110 плагинов) на разных конфигах краш ловил только из-за Lyric Show Panel 2 (v0.4.5.5)
твоя тоже через минуту упала (Win7 x64) - попытка зайти в настройки лирики

но надеюсь его допилят
Последний раз редактировалось Sp1ke 23.01.2010, 17:46, всего редактировалось 1 раз.
http://www.last.fm/user/meDveD_spb
meDveD M
Возраст: 34
Откуда: SPb
Репутация: 52
С нами: 14 лет 7 месяцев

Сообщение #653 Максим » 23.01.2010, 17:45

meDveD
Да, Lyric Show 2 нестабилен, но куда без него?.. :)

Кстати, его последняя версия (v0.4.5.5) намного лучше предыдущих.
Последний раз редактировалось Sp1ke 23.01.2010, 17:46, всего редактировалось 1 раз.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #654 meDveD » 23.01.2010, 17:46

Максим:meDveD
Да, Lyric Show 2 нестабилен, но куда без него?.. :)
никуда)

Кстати Artwork view можно заменить на WSH Panel Mod (WSH Cover Panel), очень удобно.
Код: Выделить всё
//====================================================
//--------------------------------- WSH Cover Panel -------------------------------------
//-------------- v1.0 , code for foo_uie_wsh_mod v1.1.8 or higher ---------------
//--------------------- Code by Jensen (jensen-yg@163.com) ----------------------
//====================================================

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(c);
         }
      };

      // 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(c);
                     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(c);
            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(c);
         }
      };
      
      // 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(c);
                  return;
               }
            
            this.unshift(c);
            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);
}

//EOF
Последний раз редактировалось Sp1ke 23.01.2010, 17:50, всего редактировалось 1 раз.
http://www.last.fm/user/meDveD_spb
meDveD M
Возраст: 34
Откуда: SPb
Репутация: 52
С нами: 14 лет 7 месяцев

Сообщение #655 Максим » 23.01.2010, 17:55

Спасибо.

Код этой панели = 1480 строк = мой код для PSS и всех WSH-панелей :D Я лучше свою панель из Легенды сюда перенесу.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #656 Qfile68 » 23.01.2010, 20:22

2Максим
Плагины конфига+alac,monkey,cuesheet .А падала именно из-за  Lyric Show Panel 2.
А кнопка "clear" в jnt убирала плейлист
Qfile68
Репутация: 6
С нами: 12 лет 9 месяцев

Сообщение #657 Максим » 23.01.2010, 21:23

Qfile68
Я, конечно, могу заменить Lyric Show 2 другим компонентом, но он не скачивает тексты песен и не развивается, хотя и стабилен. Лучше ничего не менять и подождать. Даже сейчас плеер вполне стабилен.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Сообщение #658 Qfile68 » 23.01.2010, 22:51

2Максим
Я не предлагаю что то заменить.Я пользуюсь сборкой,а в процессе (если возникают какие то ошибки ) сообщаю.Может это поможет тебе при создании сборки :)
Qfile68
Репутация: 6
С нами: 12 лет 9 месяцев

Сообщение #659 Low_Pressure » 24.01.2010, 03:22

2Максим
Нажатие кнопки перехода в мини-режим сбрасывает расцветку на зеленую. А так, мне нравится)
Изображение
Low_Pressure M
Аватара
Возраст: 33
Откуда: Москва
Репутация: 4
С нами: 13 лет 7 месяцев

Сообщение #660 Максим » 24.01.2010, 12:20

Мини-режим я и не менял ;) Кстати, размеры окон запоминаются при переходе из одного режима в другой.

Я выложил новую версию конфига — должна загореться лампочка :) Если нажать на неё левой кнопкой мыши, откроется страница с информацией о доступных обновлениях.
Последний раз редактировалось Sp1ke 24.01.2010, 12:22, всего редактировалось 1 раз.
Максим M
Автор темы
Аватара
Возраст: 35
Репутация: 93
С нами: 14 лет 4 месяца

Пред.След.

Вернуться в Архив

cron