soKindly

Damask Last.fm panel 1.0.2

Dec 25th, 2012
88
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==PREPROCESSOR==
  2. // @name "WSH Last.fm panel"
  3. // @version "1.0.2"
  4. // @author "so_kindly"
  5. // ==/PREPROCESSOR==
  6.  
  7.  
  8. // Variables {{
  9. // Text flags
  10. var DT_TOP = 0x00000000;
  11. var DT_LEFT = 0x00000000;
  12. var DT_CENTER = 0x00000001;
  13. var DT_RIGHT = 0x00000002;
  14. var DT_VCENTER = 0x00000004;
  15. var DT_BOTTOM = 0x00000008;
  16. var DT_WORDBREAK = 0x00000010;
  17. var DT_CALCRECT = 0x00000400;
  18. var DT_NOPREFIX = 0x00000800;
  19. var DT_END_ELLIPSIS = 0x00008000;
  20. var DT_NOCLIP = 0x00000100;
  21.  
  22. var IDC_HAND = 32649;
  23. var IDC_ARROW = 32512;
  24.  
  25. var FontStyle = {
  26.     Regular: 0,
  27.     Bold: 1,
  28.     Italic: 2,
  29.     BoldItalic: 3,
  30.     Underline: 4,
  31.     Strikeout: 8
  32. };
  33.  
  34. var StringAlignment = {
  35.     Near: 0,
  36.     Center: 1,
  37.     Far: 2
  38. };
  39.  
  40. var StringTrimming = {
  41.     None: 0,
  42.     Character: 1,
  43.     Word: 2,
  44.     EllipsisCharacter: 3,
  45.     EllipsisWord: 4,
  46.     EllipsisPath: 5
  47. };
  48.  
  49. var StringFormatFlags = {
  50.     DirectionRightToLeft: 0x00000001,
  51.     DirectionVertical: 0x00000002,
  52.     NoFitBlackBox: 0x00000004,
  53.     DisplayFormatControl: 0x00000020,
  54.     NoFontFallback: 0x00000400,
  55.     MeasureTrailingSpaces: 0x00000800,
  56.     NoWrap: 0x00001000,
  57.     LineLimit: 0x00002000,
  58.     NoClip: 0x00004000,
  59.     BypassGDI: 0x80000000
  60. }
  61.  
  62. // Flags of Menu
  63. var MF_SEPARATOR = 0x00000800;
  64. var MF_ENABLED = 0x00000000;
  65. var MF_GRAYED = 0x00000001;
  66. var MF_DISABLED = 0x00000002;
  67. var MF_UNCHECKED = 0x00000000;
  68. var MF_CHECKED = 0x00000008;
  69. var MF_STRING = 0x00000000;
  70. var MF_POPUP = 0x00000010;
  71.  
  72. var MK_SHIFT = 0x0004;
  73. var FOCUSFLAG;
  74.  
  75. var CursorFollowMode = {
  76.     OnlyStopped: 2,
  77.     Always: 3
  78. }
  79.  
  80. // globals
  81. var ww = 0;
  82. var wh = 0;
  83. var Properties = new GetProperties();
  84. var MetaDB;
  85.  
  86. //margins
  87. var lm = 5;
  88. var rm = 5;
  89. var tm = 5;
  90. var bm = 0;
  91.  
  92. // text vars
  93. FontStyles = {
  94.     Regular: 0,
  95.     Bold: 1,
  96.     Italic: 2,
  97.     BoldItalic: 3,
  98.     Underline: 4,
  99.     Strikeout: 8
  100. }
  101.  
  102. var font_label = gdi.Font("Segoe UI", 12, FontStyles.Bold);
  103. var font_num = gdi.Font("Segoe UI", 11, FontStyles.Bold);
  104. var font_normal = gdi.Font("Segoe UI", 13, FontStyles.Regular);
  105. var font_header = gdi.Font("Segoe UI", 15, FontStyles.Bold);
  106. var font_gui = gdi.Font("Web Symbols", 13, FontStyles.Regular);
  107.  
  108. var normal_color = RGB(180, 180, 180);
  109. var hover_color = RGB(200, 200, 200);
  110. var LineStrFmt = StringFormat(StringAlignment.Near,StringAlignment.Near,StringTrimming.None,StringFormatFlags.LineLimit);
  111.  
  112. var settings_dir = fb.ProfilePath + "Damask\\settings\\";
  113.  
  114. //img vars
  115. var images_path = fb.FoobarPath + "skins\\Damask\\images\\lastfm\\";
  116. var img_lastfm_logo_red = gdi.Image(images_path + "lastfm_logo_red.jpg");
  117. var img_lastfm_flip = gdi.Image(images_path + "scrobbleflip.png");
  118. var img_avatar = gdi.Image(settings_dir + "avatar.jpg");
  119.  
  120. var img_asterisk = gdi.Image(images_path + "asterisk_small.png");
  121. var img_heart = gdi.Image(images_path + "t2.png");
  122. var max_avatar_height = Properties.Avatar.MaxHeight;
  123.  
  124. var ava_height = img_avatar.height > max_avatar_height ? max_avatar_height : img_avatar.height;
  125. var ava_width = img_avatar.height > max_avatar_height ? max_avatar_height * img_avatar.width / img_avatar.height : img_avatar.width;
  126. var avatar_need_refresh = true;
  127.  
  128. var imgPath = fb.FoobarPath + "skins\\Damask\\images\\";
  129. var img_main_wallpaper = gdi.Image(imgPath + "DamaskBG.png").CreateRawBitmap();
  130.  
  131. var opt_username = read_option("lastfm_username", "");
  132. var username = "";
  133. var opt_api_key = read_option("lastfm_api_key", "");
  134. var WshShell = new ActiveXObject("WScript.Shell");
  135.  
  136. var lastfm_data = new Array();
  137. var lastfm_xmlhttp = new Array();
  138. var lastfm_xmlDoc = new Array();
  139.  
  140. var wait = 1;
  141. var lastfm_status = 0;
  142. var error_count = 0;
  143. var loved_track = false;
  144.  
  145. var Y_OFFSET = 0;
  146. var sum_height = 0;
  147. var text_H = 0;
  148. var text_W = 0;
  149.  
  150. var mouse_x = 0;
  151. var mouse_y = 0;
  152.  
  153. var regdate_error = false;
  154.  
  155. // scrollbar colors
  156. var vs_normal_color = RGB(50, 50, 50);
  157. var vs_hover_color = RGB(70, 70, 70);
  158. var vs_down_color = RGB(60, 60, 60);
  159. var vs_bg_color = RGB(33, 33, 33);
  160. var vs_bg_color_hover = RGB(35, 35, 35);
  161.  
  162. var text_Hs = new Array();
  163. var text_Ws = new Array();
  164. var TL_ys = new Array();
  165. var TL_xs = new Array();
  166.  
  167. var np = [fb.TitleFormat("%artist%").Eval(true), fb.TitleFormat("%album%").Eval(true), fb.TitleFormat("%title%").Eval(true)];
  168.  
  169. var spcounter = 0;
  170. var charcounter = 0;
  171. var longeststr = "";
  172. var linecounter = 1;
  173.  
  174. var WaitTimerID;
  175. var StopTimerID;
  176.  
  177. var CorrectedData = []; //artist - album - track
  178.  
  179. // text buttons array [artist, album, track, tag1, tag2, tag3, tag4, tag5, similar1, similar2, similar3, similar4, similar5]
  180. var TLs = new Array(
  181. TL1 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  182. TL2 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  183. TL3 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  184. TLtag1 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  185. TLtag2 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  186. TLtag3 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  187. TLtag4 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  188. TLtag5 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  189. TLsimilar1 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  190. TLsimilar2 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  191. TLsimilar3 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  192. TLsimilar4 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  193. TLsimilar5 = new TextLink(0, 0, 0, 0, function () {}, "", ""),
  194. TLheart = new TextLink(0, 0, 25, 25, function () {}, "N", "Loved Track"));
  195.  
  196. var Tooltip = window.CreateTooltip();
  197. var TLAnimationTimerID;
  198. var TLAnimationTimer;
  199. var EnableTooltip = true;
  200. var MaxRange;
  201. var h_link, d_link;
  202.  
  203. // Variables}}
  204.  
  205.  
  206. //===========================================================================================================
  207. //===========================================================================================================
  208. // foo_silk-lastfm engine
  209. // http://code.google.com/p/foobar-silk/
  210. // (C) 2010 by Matthijs Brobbel
  211. /*
  212. /////////////////////////////////////////////////////////////////////////
  213. //###   | lastfm_data arrays    #########################################
  214. /////////////////////////////////////////////////////////////////////////
  215. //      | 0             | 1             | 2             | 3             |
  216. //      -----------------------------------------------------------------
  217. //  id: | userinfo      | artistinfo    | albuminfo     | trackinfo     |
  218. //      -----------------------------------------------------------------
  219. //  0:  | playcount     | playcount     | playcount     | playcount     |
  220. //  1:  | avg_day       | userplaycount | userplaycount | userplaycount |
  221. //  2:  | avg_week      | listeners     | listeners     | listeners     |
  222. //  3:  | avg_month     | tags          | 0             | userloved     |
  223. //  4:  | joindate      | similar       | 0             | 0             |
  224. //  5:  | avatar        | 0             | 0             | 0             |
  225. //      -----------------------------------------------------------------
  226. /////////////////////////////////////////////////////////////////////////
  227. */
  228.  
  229. function reset_lastfm_data() {
  230.     for (id = 0; id <= 4; id++) {
  231.         lastfm_data[id] = new Array(4);
  232.     }
  233.  
  234.     for (id = 0; id <= 3; id++) {
  235.         for (n = 0; n <= 5; n++) {
  236.             lastfm_data[id][n] = 0;
  237.         }
  238.     }
  239.  
  240.     lastfm_data[1][3] = new Array();
  241.     lastfm_data[1][4] = new Array();
  242.  
  243.     for (i = 0; i < 5; i++) {
  244.         lastfm_data[1][3][i] = "0";
  245.         lastfm_data[1][4][i] = "0";
  246.     }
  247. }
  248.  
  249. function get_lastfm_data() {
  250.     if (opt_username.length == 0 || opt_api_key.length != 32) {
  251.         window.Repaint();
  252.     } else { //lastfm_status counts here
  253.         contact_lastfm("user.getinfo", 0);
  254.         contact_lastfm("artist.getinfo&artist=" + encodeURIComponent(np[0]) + "&autocorrect=1", 1);
  255.         contact_lastfm("album.getinfo&artist=" + encodeURIComponent(np[0]) + "&album=" + encodeURIComponent(np[1]), 2);
  256.         contact_lastfm("track.getinfo&artist=" + encodeURIComponent(np[0]) + "&track=" + encodeURIComponent(np[2]) + "&autocorrect=1", 3);
  257.  
  258.     }
  259. }
  260.  
  261. function contact_lastfm(method, id) {
  262.     lastfm_xmlhttp[id] = new ActiveXObject("Microsoft.XMLHTTP");
  263.     lastfm_xmlhttp[id].open("GET", "http://ws.audioscrobbler.com/2.0?api_key=" + opt_api_key + "&username=" + opt_username + "&user=" + opt_username + "&method=" + method + "&s=" + Math.random(), true);
  264.     lastfm_xmlhttp[id].setRequestHeader('User-Agent', "foo_silk_mod");
  265.     lastfm_xmlhttp[id].send();
  266.     lastfm_xmlhttp[id].onreadystatechange = function () {
  267.         if (lastfm_xmlhttp[id].readyState == 4) { // 'DONE' state
  268.             if (lastfm_xmlhttp[id].status == 200) { //success
  269.                 lastfm_status++;
  270.                 wait_lastfm_data();
  271.             }
  272.             if (lastfm_xmlhttp[id].status >= 400) { //error statuses
  273.  
  274.                 error_count++;
  275.                 lastfm_status++;
  276.                 wait_lastfm_data();
  277.             }
  278.         }
  279.     }
  280. }
  281.  
  282. function wait_lastfm_data() {
  283.     if (lastfm_status == 4 && error_count < 4) {
  284.         process_lastfm_data();
  285.         lastfm_status = wait = 0;
  286.         Y_OFFSET = 0;
  287.         error_count = 0;
  288.         return;
  289.     } else if (lastfm_status < 4) {
  290.         wait = 1;
  291.     } else if (error_count == 4) {
  292.         wait = -1;
  293.         error_count = 0;
  294.         window.Repaint();
  295.  
  296.     }
  297. }
  298.  
  299. function process_lastfm_data() {
  300.     for (id = 0; id < 4; id++) {
  301.         lastfm_xmlDoc[id] = lastfm_xmlhttp[id].responseXML;
  302.         try {
  303.             error = "last.fm API error: " + lastfm_xmlDoc[id].getElementsByTagName("error")[0].childNodes[0].nodeValue;
  304.         } catch (e) {
  305.             error = null;
  306.         }
  307.     }
  308.  
  309.     // Userinfo
  310.     try {
  311.         lastfm_data[0][0] = lastfm_xmlDoc[0].getElementsByTagName("playcount")[0].childNodes[0].nodeValue;
  312.         username = lastfm_xmlDoc[0].getElementsByTagName("name")[0].childNodes[0].nodeValue;
  313.     } catch (e) {
  314.         lastfm_data[0][0] = "0";
  315.     }
  316.     try {
  317.         lastfm_data[0][4] = lastfm_xmlDoc[0].getElementsByTagName("registered")[0].childNodes[0].nodeValue;
  318.         regdate_error = false;
  319.     } catch (e) {
  320.         regdate_error = true;
  321.         lastfm_data[0][4] = "";
  322.  
  323.     }
  324.     try {
  325.         lastfm_data[0][5] = lastfm_xmlDoc[0].getElementsByTagName("image")[2].childNodes[0].nodeValue;
  326.         if (avatar_need_refresh) {
  327.             fso = new ActiveXObject("Scripting.FileSystemObject");
  328.             img_avatar.Dispose();
  329.             img_avatar = gdi.Image(images_path + "default_avatar.png");
  330.             WshShell.Run("\"" + fb.FoobarPath + "skins\\Damask\\scripts\\" + "url2disk.exe\"" + " -i " + lastfm_data[0][5] + " -o " + "\"" + settings_dir + "\avatar.jpg\"", 0, true);
  331.             img_avatar = gdi.Image(settings_dir + "avatar.jpg");
  332.             ava_height = img_avatar.height > max_avatar_height ? max_avatar_height : img_avatar.height;
  333.             ava_width = img_avatar.height > max_avatar_height ? max_avatar_height * img_avatar.width / img_avatar.height : img_avatar.width;
  334.             avatar_need_refresh = false;
  335.         }
  336.     } catch (e) {
  337.         lastfm_data[0][5] = "";
  338.         if (avatar_need_refresh) {
  339.             img_avatar.Dispose();
  340.             img_avatar = gdi.Image(images_path + "default_avatar.png");
  341.             ava_height = img_avatar.height > max_avatar_height ? max_avatar_height : img_avatar.height;
  342.             ava_width = img_avatar.height > max_avatar_height ? max_avatar_height * img_avatar.width / img_avatar.height : img_avatar.width;
  343.             avatar_need_refresh = false;
  344.         }
  345.     }
  346.  
  347.     date = new Date().getTime() / 1;
  348.  
  349.     if (!regdate_error) {
  350.         try {
  351.             utc = Date.UTC(lastfm_data[0][4].substring(0, 4), (lastfm_data[0][4].substring(5, 7) - 1), lastfm_data[0][4].substring(8, 10), 0, 0, 0);
  352.         } catch (e) {
  353.             utc = 0;
  354.         }
  355.         try {
  356.             lastfm_data[0][1] = "" + Math.round((lastfm_data[0][0] / ((date - utc) / 86400000)) * 100) / 100;
  357.             lastfm_data[0][1] = lastfm_data[0][1].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  358.         } catch (e) {
  359.             lastfm_data[0][1] = "0";
  360.         };
  361.  
  362.         try {
  363.             lastfm_data[0][2] = "" + Math.round((lastfm_data[0][0] / ((date - utc) / 604800000)) * 10) / 10;
  364.             lastfm_data[0][2] = lastfm_data[0][2].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  365.         } catch (e) {
  366.             lastfm_data[0][2] = "0";
  367.         };
  368.  
  369.         try {
  370.             lastfm_data[0][3] = "" + Math.round((lastfm_data[0][0] / ((date - utc) / 2629743000)) * 1) / 1;
  371.             lastfm_data[0][3] = lastfm_data[0][3].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  372.         } catch (e) {
  373.             lastfm_data[0][3] = "0";
  374.         };
  375.  
  376.  
  377.     } else {
  378.         lastfm_data[0][1] = "0";
  379.         lastfm_data[0][2] = "0";
  380.         lastfm_data[0][3] = "0";
  381.     }
  382.  
  383.  
  384.     try {
  385.         lastfm_data[0][0] = lastfm_data[0][0].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  386.     } catch (e) {
  387.         lastfm_data[0][0] = "0";
  388.     }
  389.  
  390.  
  391.     // Artistinfo - Albuminfo - Trackinfo
  392.     for (id = 1; id <= 3; id++) {
  393.         try {
  394.             lastfm_data[id][0] = lastfm_xmlDoc[id].getElementsByTagName("playcount")[0].childNodes[0].nodeValue;
  395.             lastfm_data[id][0] = lastfm_data[id][0].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  396.         } catch (e) {
  397.             lastfm_data[id][0] = "0";
  398.         }
  399.  
  400.         try {
  401.             lastfm_data[id][1] = lastfm_xmlDoc[id].getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;
  402.             lastfm_data[id][1] = lastfm_data[id][1].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  403.         } catch (e) {
  404.             lastfm_data[id][1] = "0";
  405.         }
  406.  
  407.         try {
  408.             lastfm_data[id][2] = lastfm_xmlDoc[id].getElementsByTagName("listeners")[0].childNodes[0].nodeValue;
  409.             lastfm_data[id][2] = lastfm_data[id][2].replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
  410.         } catch (e) {
  411.             lastfm_data[id][2] = "0";
  412.         }
  413.  
  414.  
  415.         switch (id) {
  416.             case 1:
  417.                 try {
  418.                     CorrectedData[id] = lastfm_xmlDoc[id].getElementsByTagName("name")[0].childNodes[0].nodeValue;
  419.                     for (i = 0; i < 5; i++) {
  420.                         try {
  421.                             lastfm_data[id][3][i] = lastfm_xmlDoc[id].getElementsByTagName("tag")[i].childNodes[0].childNodes[0].nodeValue; //artist tags
  422.                         } catch (e) {
  423.                             lastfm_data[id][3][i] = "";
  424.                         }
  425.  
  426.                         try {
  427.                             lastfm_data[id][4][i] = lastfm_xmlDoc[id].getElementsByTagName("artist")[i + 1].childNodes[0].childNodes[0].nodeValue; //similar artists
  428.                         } catch (e) {
  429.                             lastfm_data[id][4][i] = "no data";
  430.                         }
  431.                     }
  432.                 } catch (e) {
  433.                     CorrectedData[id] = "~no data";
  434.                 }
  435.                 break;
  436.             case 2:
  437.                 try {
  438.                     CorrectedData[id] = lastfm_xmlDoc[id].getElementsByTagName("name")[0].childNodes[0].nodeValue;
  439.                 } catch (e) {
  440.                     CorrectedData[id] = "~no data";
  441.                 }
  442.                 break;
  443.             case 3:
  444.                 try {
  445.                     CorrectedData[id] = lastfm_xmlDoc[id].getElementsByTagName("name")[0].childNodes[0].nodeValue;
  446.                 } catch (e) {
  447.                     CorrectedData[id] = "~no data";
  448.                 }
  449.  
  450.                 try {
  451.                     lastfm_data[id][3] = lastfm_xmlDoc[id].getElementsByTagName("userloved")[0].childNodes[0].nodeValue;
  452.                 } catch (e) {
  453.                     lastfm_data[id][3] = "0";
  454.                 }
  455.                 break;
  456.         }
  457.  
  458.     }
  459.  
  460.     for (i = 0; i < TLs.length; i++) {
  461.         TLs[i].NeedReset = true;
  462.     }
  463.  
  464.     window.Repaint();
  465. }
  466.  
  467. //lfm end
  468. //===========================================================================================================
  469. //===========================================================================================================
  470.  
  471. // Tools {{
  472.  
  473. function StringFormat(h_align, v_align, trim, flag) {
  474.     return ((h_align << 28) | (v_align << 24) | (trim << 20) | flag);
  475. }
  476.  
  477. function RGB(r, g, b) {
  478.     return (0xff000000 | (r << 16) | (g << 8) | (b));
  479. }
  480.  
  481. function RGBA(r, g, b, a) {
  482.     return ((a << 24) | (r << 16) | (g << 8) | (b));
  483. }
  484.  
  485. //Properties
  486. function GetProperties() {
  487.     this.Avatar = {
  488.         MaxHeight: window.GetProperty("A01.Avatar.MaxHeight", 100)
  489.     }
  490.  
  491.     this.Avatar.MaxHeight = Math.min(Math.max(this.Avatar.MaxHeight, 30), 252);
  492.    
  493.     this.Panel = {
  494.         CursorFollowMode: window.GetProperty("B01.Panel.CursorFollowMode", CursorFollowMode.OnlyStopped),
  495.     }
  496.    
  497.     this.Panel.CursorFollowMode = Math.max(this.Panel.CursorFollowMode, CursorFollowMode.OnlyStopped);
  498.     this.Panel.CursorFollowMode = Math.min(this.Panel.CursorFollowMode, CursorFollowMode.Always);
  499.     window.SetProperty("B01.Panel.CursorFollowMode", this.Panel.CursorFollowMode);
  500. }
  501.  
  502. // Generate background image.
  503. function GenerateBG() {
  504.     var img_bg = gdi.CreateImage(ww, wh);
  505.     var g = img_bg.GetGraphics();
  506.     // wallpaper
  507.     g.GdiDrawBitmap(img_main_wallpaper, 0, 0, img_bg.width, img_bg.height, 0, 0, img_bg.width, img_bg.height);
  508.  
  509.     img_bg_bmp = img_bg.CreateRawBitmap();
  510.     img_bg.ReleaseGraphics(g);
  511. }
  512.  
  513. // Tools }}
  514. //===================================================================================================================================================
  515.  
  516. //timers
  517. function c_WaitTimer() {
  518.     this.Stop = function () {
  519.         if (WaitTimerID) {
  520.             window.ClearTimeout(WaitTimerID);
  521.             WaitTimerID = null;
  522.             //window.Repaint();
  523.         }
  524.     }
  525.  
  526.     this.Start = function () {
  527.         WaitTimerID = window.SetTimeout(function () {
  528.             WaitTimerID = null;
  529.             lastfm_status = 0;
  530.             wait = 1;
  531.  
  532.             MetaDB = fb.GetFocusItem();
  533.             FOCUSFLAG = true;
  534.             if (MetaDB){
  535.                 np = [fb.TitleFormat("%artist%").EvalWithMetadb(MetaDB), fb.TitleFormat("%album%").EvalWithMetadb(MetaDB), fb.TitleFormat("%title%").EvalWithMetadb(MetaDB)]
  536.                 if (np[0] == "?" && np[1] == "?") {
  537.                     wait = -2;
  538.                     window.Repaint();
  539.                     return;
  540.                 }
  541.                 lastfm_status = 0;
  542.                 wait = 1;
  543.                 window.Repaint();
  544.                 get_lastfm_data();
  545.             } else {
  546.                 wait = -2;
  547.                 window.Repaint();
  548.             }
  549.         }, 400);
  550.     }
  551. }
  552.  
  553.  
  554. function c_ButtonAnimationTimer() {
  555.     this.Stop = function () {
  556.         if (TLAnimationTimerID) {
  557.             window.ClearInterval(TLAnimationTimerID);
  558.             TLAnimationTimerID = null;
  559.         }
  560.     }
  561.  
  562.     this.Start = function () {
  563.         TLAnimationTimerID = window.SetInterval(function () {
  564.             var NeedRepaint = 0;
  565.             for (var i = 0; i < TLs.length; i++) {
  566.                 if (TLs[i].NeedRefresh) {
  567.                     TLs[i].RefreshOpacity();
  568.                     NeedRepaint += 1;
  569.                     Onlybtn = TLs[i]; // If only one button need to be repainted.
  570.                 }
  571.             }
  572.  
  573.             if (NeedRepaint) {
  574.                 if (NeedRepaint == 1) window.RepaintRect(Onlybtn.x, Onlybtn.y + Y_OFFSET, Onlybtn.width, Onlybtn.height);
  575.                 else window.RepaintRect(MaxRange.x, MaxRange.y, MaxRange.width, MaxRange.height); // This is range of buttons.
  576.             } else {
  577.                 TLAnimationTimer.Stop();
  578.             }
  579.         }, 50)
  580.     }
  581. }
  582.  
  583. // VB wrapper {{
  584. var vb = {};
  585. vb.Function = function (func) {
  586.     return function () {
  587.         return vb.Function.eval.call(this, func, arguments);
  588.     }
  589. };
  590. vb.Function.eval = function (func) {
  591.     var args = Array.prototype.slice.call(arguments[1]);
  592.     for (var i = 0; i < args.length; i++) {
  593.         if (typeof args[i] != 'string') continue;
  594.         args[i] = '"' + args[i].replace(/"/g, '" + Chr(34) + "') + '"';
  595.     }
  596.     var vbe;
  597.     vbe = new ActiveXObject('ScriptControl');
  598.     vbe.Language = 'VBScript';
  599.     return vbe.eval(func + '(' + args.join(', ') + ')');
  600. };
  601. var InputBox = vb.Function('InputBox');
  602. var MsgBox = vb.Function('MsgBox');
  603. // VB wrapper}}
  604.  
  605. //===================================================================================================================================================
  606. // Options engine {{
  607.  
  608. function update_option(optname, optvalue) {
  609.     var fso, f1, ts, s;
  610.     var ForReading = 1;
  611.     var ForWriting = 2;
  612.     fso = new ActiveXObject("Scripting.FileSystemObject");
  613.  
  614.     // Read the contents of the txt file
  615.     ts = fso.OpenTextFile(settings_dir + optname + ".txt", ForReading);
  616.     s = ts.ReadLine();
  617.     ts.Close();
  618.     // renaming the empty file used after in the PSS with the new value
  619.     f1 = fso.MoveFile(settings_dir + optname + "_" + s, settings_dir + optname + "_" + optvalue);
  620.  
  621.     // updating the txt file with the new value
  622.     ts = fso.OpenTextFile(settings_dir + optname + ".txt", ForWriting);
  623.     ts.WriteLine(optvalue);
  624.     ts.Close();
  625.     return optvalue;
  626. }
  627.  
  628. function read_option(optname, initvalue) {
  629.     var fso, ts, ts2, s;
  630.     var ForReading = 1;
  631.     var ForWriting = 2;
  632.     fso = new ActiveXObject("Scripting.FileSystemObject");
  633.  
  634.     if (file_exists(settings_dir + optname + ".txt")) {
  635.         ts = fso.OpenTextFile(settings_dir + optname + ".txt", ForReading);
  636.         s = ts.ReadLine();
  637.         ts.Close();
  638.         return s;
  639.     } else {
  640.         ts = fso.CreateTextFile(settings_dir + optname + ".txt", ForWriting);
  641.         ts.WriteLine(initvalue);
  642.         ts.Close();
  643.         ts2 = fso.CreateTextFile(settings_dir + optname + "_" + initvalue, ForWriting);
  644.         ts2.Close();
  645.         return initvalue;
  646.     }
  647. }
  648.  
  649. function folder_exists(chemin) {
  650.     var fso, bool;
  651.     fso = new ActiveXObject("Scripting.FileSystemObject");
  652.     bool = fso.FolderExists(chemin);
  653.     return bool;
  654. }
  655.  
  656. function file_exists(chemin) {
  657.     var fso, bool;
  658.     fso = new ActiveXObject("Scripting.FileSystemObject");
  659.     bool = fso.Fileexists(chemin);
  660.     return bool;
  661. }
  662.  
  663. // Options engine }}
  664.  
  665. // Cursor follow tools {{
  666. function SetCursorFollowMode(FollowMode) {
  667.     if (FollowMode != Properties.Panel.CursorFollowMode) {
  668.         Properties.Panel.CursorFollowMode = FollowMode;
  669.         window.SetProperty("B01.Panel.CursorFollowMode", FollowMode);
  670.         CursorFollow(FollowMode);
  671.     }
  672. }
  673.  
  674. function CursorFollow(FollowMode) {
  675.     switch (FollowMode) {
  676.         case CursorFollowMode.OnlyStopped:
  677.             if (fb.IsPlaying) on_playback_new_track();
  678.             else on_item_focus_change();
  679.             break;
  680.         case CursorFollowMode.Always:
  681.             on_item_focus_change();
  682.             break;
  683.     }
  684. }
  685.  
  686. // Cursor follow tools }}
  687.  
  688.  
  689. //context menu
  690. function show_context_menu(x, y) {
  691.     var _menu = window.CreatePopupMenu();
  692.     var _avatar = window.CreatePopupMenu();
  693.     var _followMode = window.CreatePopupMenu();
  694.     var ret;
  695.  
  696.     if (opt_username.length == 0 || opt_api_key.length != 32) {
  697.         _menu.AppendMenuItem(MF_STRING, 10, "Set your Last.fm username...");
  698.         //_menu.AppendMenuItem(MF_STRING, 11, "Set your API KEY...");
  699.     } else {
  700.         _menu.AppendMenuItem(opt_username.length > 0 && opt_api_key.length == 32 ? MF_STRING : MF_GRAYED, 1, "Update Last.fm Data");
  701.         _menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
  702.        
  703.         _followMode.AppendMenuItem(MF_STRING, 2, "Only Stopped");
  704.         _followMode.AppendMenuItem(MF_STRING, 3, "Always");
  705.         _followMode.CheckMenuRadioItem(2, 3, Properties.Panel.CursorFollowMode);
  706.         _followMode.AppendTo(_menu, MF_STRING, "Cursor follow mode");
  707.        
  708.         _avatar.AppendMenuItem(MF_STRING, 4, "Download avatar");
  709.         _avatar.AppendMenuItem(MF_STRING, 5, "Restore default avatar");
  710.         _avatar.AppendTo(_menu, MF_STRING, "Avatar");
  711.  
  712.         _menu.AppendMenuItem(MF_STRING, 6, "Change username");
  713.         //_menu.AppendMenuItem(MF_STRING, 7, "Change API Key");
  714.         _menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
  715.         _menu.AppendMenuItem(MF_STRING, 8, "Properties");
  716.     }
  717.  
  718.     ret = _menu.TrackPopupMenu(x, y);
  719.     switch (ret) {
  720.         case 1:
  721.             lastfm_status = 0;
  722.             wait = 1;
  723.             window.Repaint();
  724.             CursorFollow(Properties.Panel.CursorFollowMode);
  725.             break;
  726.         case 2:
  727.             SetCursorFollowMode(CursorFollowMode.OnlyStopped);
  728.             break;
  729.         case 3:
  730.             SetCursorFollowMode(CursorFollowMode.Always);
  731.             break;
  732.         case 4:
  733.             fso = new ActiveXObject("Scripting.FileSystemObject");
  734.             img_avatar.Dispose();
  735.             img_avatar = gdi.Image(images_path + "default_avatar.png")
  736.             window.Repaint();
  737.             fb.trace("\"" + fb.FoobarPath + "skins\\Damask\\scripts\\" + "url2disk.exe\"" + " -i " + lastfm_data[0][5] + " -o " + "\"" + settings_dir + "\avatar.jpg\"");
  738.             WshShell.Run("\"" + fb.FoobarPath + "skins\\Damask\\scripts\\" + "url2disk.exe\"" + " -i " + lastfm_data[0][5] + " -o " + "\"" + settings_dir + "\avatar.jpg\"", 0, true);
  739.             img_avatar = gdi.Image(settings_dir + "avatar.jpg");
  740.             ava_height = img_avatar.height > max_avatar_height ? max_avatar_height : img_avatar.height;
  741.             ava_width = img_avatar.height > max_avatar_height ? max_avatar_height * img_avatar.width / img_avatar.height : img_avatar.width;
  742.             window.Repaint();
  743.             break;
  744.         case 5:
  745.             img_avatar.Dispose();
  746.             img_avatar = gdi.Image(images_path + "default_avatar.png");
  747.             ava_height = img_avatar.height > max_avatar_height ? max_avatar_height : img_avatar.height;
  748.             ava_width = img_avatar.height > max_avatar_height ? max_avatar_height * img_avatar.width / img_avatar.height : img_avatar.width;
  749.             window.Repaint();
  750.             break;
  751.         case 6:
  752.             opt_username = InputBox("Please enter your Last.fm username", "Last.fm panel", opt_username);
  753.             if (!opt_username) opt_username = "";
  754.             update_option("lastfm_username", opt_username);
  755.  
  756.             avatar_need_refresh = true;
  757.  
  758.             CursorFollow(Properties.Panel.CursorFollowMode);
  759.             break;
  760.         case 7:
  761.             opt_api_key = InputBox("Please enter your Last.fm API KEY (http://www.last.fm/api/account)", "Last.fm panel", opt_api_key);
  762.             if (!opt_api_key) opt_api_key = "";
  763.             update_option("lastfm_api_key", opt_api_key);
  764.             CursorFollow(Properties.Panel.CursorFollowMode);
  765.             break;
  766.         case 8:
  767.             window.ShowProperties();
  768.             break;
  769.         case 10:
  770.             opt_username = InputBox("Please enter your Last.fm username", "Last.fm panel", opt_username);
  771.             if (!opt_username) opt_username = "";
  772.             update_option("lastfm_username", opt_username);
  773.  
  774.             avatar_need_refresh = true;
  775.  
  776.             CursorFollow(Properties.Panel.CursorFollowMode);
  777.             break;
  778.         case 11:
  779.             opt_api_key = InputBox("Please enter your Last.fm API KEY (http://www.last.fm/api/account)", "Last.fm panel", opt_api_key);
  780.             if (!opt_api_key) opt_api_key = "";
  781.             update_option("lastfm_api_key", opt_api_key);
  782.             CursorFollow(Properties.Panel.CursorFollowMode);
  783.             break;
  784.     }
  785.     _menu.Dispose();
  786.     _avatar.Dispose();
  787.     _followMode.Dispose();
  788.     return true;
  789. }
  790.  
  791. // button class
  792. function TextLink(x, y, width, height, fn_onclick, label, tiptext) {
  793.     this.x = x;
  794.     this.y = y;
  795.     this.width = width;
  796.     this.height = height;
  797.     this.label = label;
  798.     this.tiptext = tiptext;
  799.     this.TestProp = "";
  800.     this.NeedRefresh = 0;
  801.     this.oldstate = 0; // 0=normal, 1=hover, 2=down.
  802.     this.state = 0;
  803.     this.opacity = 0; // Opacity of new state image.
  804.     this.step = 0;
  805.     this.show = true;
  806.     this.NeedReset = false;
  807.  
  808.     this.OnClick = fn_onclick;
  809.  
  810.     this.ChangeState = function (s) {
  811.         this.oldstate = this.state;
  812.         this.state = s;
  813.         this.opacity = 0;
  814.         this.NeedRefresh = 1;
  815.         switch (s) {
  816.             case 0:
  817.                 this.step = 40; // Step of changing to normal state.
  818.                 Tooltip.Deactivate();
  819.                 Tooltip.Text = "";
  820.                 break;
  821.             case 1:
  822.                 this.step = 75; // hover state.
  823.                 if (EnableTooltip) {
  824.                     Tooltip.Text = this.tiptext;
  825.                     Tooltip.Activate();
  826.                 }
  827.                 break;
  828.             case 2:
  829.                 this.step = 85; // down state.
  830.                 Tooltip.Deactivate();
  831.                 Tooltip.Text = "";
  832.                 break;
  833.         }
  834.  
  835.         if (!TLAnimationTimerID) // start animation
  836.         TLAnimationTimer.Start();
  837.     }
  838.  
  839.     this.isXYok = function (x2, y2) {
  840.         return (x2 >= this.x && y2 >= this.y + Y_OFFSET && x2 <= this.x + this.width && y2 <= this.y + Y_OFFSET + this.height) ? true : false;
  841.     }
  842.  
  843.     this.Draw = function (x2, y2, gr) {
  844.         x2 = this.x; //disabled
  845.         y2 = this.y; //disabled
  846.         if (this.opacity < 255) {
  847.             switch (this.oldstate) {
  848.                 case 0:
  849.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(20, 20, 20, 255));
  850.                     gr.DrawString(this.label, font_normal, normal_color, this.x + 4, this.y + Y_OFFSET, this.width - 4, this.height, LineStrFmt);
  851.                     break;
  852.                 case 1:
  853.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(30, 30, 30, 255));
  854.                     gr.DrawString(this.label, font_normal, hover_color, this.x + 4, this.y + Y_OFFSET, this.width - 4, this.height, LineStrFmt);
  855.                     break;
  856.                 case 2:
  857.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(36, 36, 36, 255));
  858.                     gr.DrawString(this.label, font_normal, hover_color, this.x + 4, this.y + Y_OFFSET, this.width - 4, this.height, LineStrFmt);
  859.                     break;
  860.                 default:
  861.                     break;
  862.             }
  863.         }
  864.  
  865.         if (this.opacity) {
  866.             switch (this.state) {
  867.                 case 0:
  868.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(20, 20, 20, this.opacity));
  869.                     gr.DrawString(this.label, font_normal, normal_color, this.x + 4, this.y + Y_OFFSET, this.width, this.height, LineStrFmt);
  870.                     break;
  871.                 case 1:
  872.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(30, 30, 30, this.opacity));
  873.                     gr.DrawString(this.label, font_normal, hover_color, this.x + 4, this.y + Y_OFFSET, this.width, this.height, LineStrFmt);
  874.                     break;
  875.                 case 2:
  876.                     gr.FillSolidRect(this.x, this.y + Y_OFFSET, this.width, this.height, RGBA(36, 36, 36, this.opacity));
  877.                     gr.DrawString(this.label, font_normal, hover_color, this.x + 4, this.y + Y_OFFSET, this.width, this.height, LineStrFmt);
  878.                     break;
  879.             }
  880.         }
  881.     }
  882.  
  883.     this.RefreshOpacity = function (fn) {
  884.         if (this.opacity < 255) this.opacity = Math.min(this.opacity + this.step, 255);
  885.         else {
  886.             this.oldstate = this.state;
  887.             this.opacity = 0;
  888.             this.NeedRefresh = 0;
  889.         }
  890.     }
  891. }
  892.  
  893. function GetCoordinates() {
  894.  
  895.     // Calculate the max range of buttons, for increasing refresh speed.
  896.     MaxRange = {
  897.         x: TLs[0].x,
  898.         y: TLs[0].y + Y_OFFSET,
  899.         width: TLs[0].width,
  900.         height: TLs[0].height
  901.     }
  902.  
  903.     for (var i = 1; i < TLs.length - 1; i++) {
  904.         if (TLs[i].show) {
  905.             MaxRange.x = Math.min(TLs[i].x, MaxRange.x);
  906.             MaxRange.y = Math.min(TLs[i].y + Y_OFFSET, MaxRange.y);
  907.             MaxRange.width = Math.max(TLs[i].x + TLs[i].width - MaxRange.x, MaxRange.width);
  908.             MaxRange.height = Math.max(TLs[i].y + Y_OFFSET + TLs[i].height - MaxRange.y, MaxRange.height);
  909.         }
  910.     }
  911.  
  912. }
  913.  
  914. // Scrollbar tools {{
  915. var scrollpos;
  916. var scrollmax;
  917. var ratio;
  918. var NeedScrollbar;
  919.  
  920. var slider_hover;
  921. var slider_y_rel;
  922. var slider_drag;
  923.  
  924. function SetSlider() {
  925.     if (sum_height < wh) {
  926.  
  927.         if (Y_OFFSET != 0) {
  928.             Y_OFFSET = 0;
  929.         }
  930.         NeedScrollbar = false;
  931.         return;
  932.     } else {
  933.         NeedScrollbar = true;
  934.         scrollmax = sum_height + tm - wh;
  935.         scrollpos = -1 * Y_OFFSET;
  936.  
  937.         ratio = wh / (sum_height + tm); // какая часть = страница от всего док.
  938.         if (ratio > 1) ratio = 1;
  939.  
  940.         Scrollbar.step = 1 / ratio;
  941.         Scrollbar.slider.height = Math.round(ratio * wh);
  942.         if (Scrollbar.slider.height < Scrollbar.min_height) {
  943.             Scrollbar.slider.height = Scrollbar.min_height;
  944.         }
  945.  
  946.         Scrollbar.slider.y = Math.round((wh - Scrollbar.slider.height) * scrollpos / scrollmax);
  947.         Scrollbar.slider.x = ww - 18;
  948.         Scrollbar.slider.width = 16;
  949.  
  950.         if (Y_OFFSET < -1 * (sum_height - wh + tm)) {
  951.             Y_OFFSET = -1 * (sum_height - wh + tm);
  952.         }
  953.     }
  954. }
  955.  
  956. function V_SCROLLBAR(width, min_h) {
  957.     this.width = width;
  958.     this.step = 0;
  959.     this.state = 0;
  960.     this.slider = {
  961.         x: 0,
  962.         y: 0,
  963.         width: 0,
  964.         height: 0,
  965.         min_height: min_h
  966.     }
  967.  
  968.     this.isXYok = function (x, y) {
  969.         return (x >= ww - 20 && y >= 0 && x <= ww && y <= wh) ? true : false;
  970.     }
  971.  
  972.     this.slider_isXYok = function (x, y) {
  973.         return (x >= this.slider.x && y >= this.slider.y && x <= this.slider.x + this.slider.width && y <= this.slider.y + this.slider.height) ? true : false;
  974.     }
  975.  
  976.     this.Draw = function (gr) {
  977.         if (NeedScrollbar) {
  978.             //bg
  979.             gr.DrawRect(ww - 20, 0, 19, wh - 1, 1, RGB(20, 20, 20));
  980.             gr.FillSolidRect(ww - 19, 1, 18, wh - 2, vs_bg_color);
  981.  
  982.             //slider
  983.             gr.FillSolidRect(this.slider.x, this.slider.y, this.slider.width, this.slider.height, (slider_drag) ? vs_down_color : (slider_hover ? vs_hover_color : vs_normal_color));
  984.             gr.DrawRect(this.slider.x, this.slider.y, this.slider.width - 1, this.slider.height - 1, 1, RGB(25, 25, 25));
  985.  
  986.         }
  987.     }
  988.  
  989. }
  990. // Scrollbar tools }}
  991.  
  992. //===================================================================================================================================================
  993. //===================================================================================================================================================
  994.  
  995.  
  996. function on_init() {
  997.     Scrollbar = new V_SCROLLBAR(20, 45);
  998.     WaitTimer = new c_WaitTimer();
  999.     TLAnimationTimer = new c_ButtonAnimationTimer();
  1000.     update_option("lastfm_api_key", "179b25d95e633097ec682c58b4a993ec");
  1001.     reset_lastfm_data();
  1002.     //WaitTimer.Start();
  1003. }
  1004. on_init();
  1005.  
  1006.  
  1007. function on_size() {
  1008.     if (!window.Width || !window.Height) return;
  1009.     ww = window.Width;
  1010.     wh = window.Height;
  1011.    
  1012.     SetSlider();
  1013.     GetCoordinates();
  1014.     CursorFollow(Properties.Panel.CursorFollowMode);
  1015.     GenerateBG();
  1016. }
  1017.  
  1018. function on_paint(gr) {
  1019.     //don't draw if panel sizes are less than min values
  1020.     if (window.Width < 185 || window.Height < 100) {
  1021.         if (img_bg_bmp) gr.GdiDrawBitmap(img_bg_bmp, 0, 0, ww, wh, 0, 0, img_bg_bmp.width, img_bg_bmp.height);
  1022.         return;
  1023.     }
  1024.  
  1025.     sum_height = 0;
  1026.     gr.SetTextRenderingHint(5);
  1027.     // Draw background image.
  1028.     if (img_bg_bmp) gr.GdiDrawBitmap(img_bg_bmp, 0, 0, ww, wh, 0, 0, img_bg_bmp.width, img_bg_bmp.height);
  1029.  
  1030.  
  1031.     if (opt_username.length == 0 || opt_api_key.length != 32) {
  1032.         gr.GdiDrawText("Last.fm panel \n Please enter your username with context menu", font_normal, normal_color, 0, 0, ww, wh, DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
  1033.         return;
  1034.     }
  1035.     if (wait == 0) {
  1036.         //draw last.fm logo
  1037.         gr.FillSolidRect(0, tm + Y_OFFSET, ww, 30, RGBA(210, 19, 9, 255));
  1038.         gr.DrawImage(img_lastfm_logo_red, (ww - 100) / 2, tm + Y_OFFSET, 100, 30, 0, 0, 900, 269);
  1039.         //draw user avatar
  1040.         gr.DrawImage(img_avatar, lm, tm + 30 + tm + Y_OFFSET, ava_width, ava_height, 0, 0, img_avatar.width, img_avatar.height);
  1041.         sum_height += ava_height < 100 ? tm + 30 + tm + 100 : tm + 30 + tm + ava_height;
  1042.         gr.DrawRect(lm, tm + 30 + tm + Y_OFFSET, ava_width, ava_height, 2, normal_color);
  1043.         //draw username
  1044.         if (ww >= 175 + ava_width) {
  1045.             gr.GdiDrawText(username != "" ? username : opt_username, font_header, normal_color, lm + ava_width + 15, 45 + Y_OFFSET, ww, wh);
  1046.         } else {
  1047.             gr.GdiDrawText(username != "" ? username : opt_username, font_header, normal_color, lm, sum_height + 5 + Y_OFFSET, ww, wh);
  1048.             sum_height += font_header.height + 9;
  1049.         }
  1050.  
  1051.  
  1052.         // plays ========================================================================================================================================================================================
  1053.  
  1054.         for (i = 0; i <= 3; i++) {
  1055.             charcounter = 0;
  1056.             spcounter = 0;
  1057.  
  1058.             switch (i) {
  1059.                 case 0:
  1060.                     txt_plays = " plays";
  1061.                     break;
  1062.                 case 1:
  1063.                     txt_plays = " per day";
  1064.                     break;
  1065.                 case 2:
  1066.                     txt_plays = " per week";
  1067.                     break;
  1068.                 case 3:
  1069.                     txt_plays = " per month";
  1070.                     break;
  1071.             }
  1072.  
  1073.             if (longeststr.length < lastfm_data[0][i].length) longeststr = lastfm_data[0][i];
  1074.  
  1075.             if (ww >= 175 + ava_width) {
  1076.                 for (j = 0; j < lastfm_data[0][i].length; j++) {
  1077.                     if (lastfm_data[0][i].substring((j), j + 1) != " ") {
  1078.                         gr.DrawImage(img_lastfm_flip, lm + ava_width + 15 + charcounter * 11 + spcounter * 5, 70 + (i * 15) + Y_OFFSET, img_lastfm_flip.width, img_lastfm_flip.height, 0, 0, img_lastfm_flip.width, img_lastfm_flip.height);
  1079.                         charcounter++;
  1080.                     } else {
  1081.                         spcounter++;
  1082.                     }
  1083.                     gr.GdiDrawText(lastfm_data[0][i].substring((j), j + 1), font_num, RGB(255, 255, 255), lm + ava_width + 17 + (charcounter - 1) * 11 + spcounter * 5, 69 + (i * 15) + Y_OFFSET, ww, wh, DT_TOP | DT_LEFT);
  1084.                 }
  1085.                 gr.GdiDrawText(txt_plays, font_num, normal_color, lm + ava_width + 15 + charcounter * 11 + spcounter * 5 + 3, 69 + (i * 15) + Y_OFFSET, ww, wh, DT_TOP | DT_LEFT);
  1086.             } else {
  1087.                 for (j = 0; j < lastfm_data[0][i].length; j++) {
  1088.                     if (lastfm_data[0][i].substring((j), j + 1) != " ") {
  1089.                         gr.DrawImage(img_lastfm_flip, lm + charcounter * 11 + spcounter * 5, sum_height + Y_OFFSET, img_lastfm_flip.width, img_lastfm_flip.height, 0, 0, img_lastfm_flip.width, img_lastfm_flip.height);
  1090.                         charcounter++;
  1091.                     } else {
  1092.                         spcounter++;
  1093.                     }
  1094.                     gr.GdiDrawText(lastfm_data[0][i].substring((j), j + 1), font_num, RGB(255, 255, 255), lm + 2 + (charcounter - 1) * 11 + spcounter * 5, sum_height - 1 + Y_OFFSET, ww, wh, DT_TOP | DT_LEFT);
  1095.                 }
  1096.                 gr.GdiDrawText(txt_plays, font_num, normal_color, lm + charcounter * 11 + spcounter * 5 + 3, sum_height - 1 + Y_OFFSET, ww, wh, DT_TOP | DT_LEFT);
  1097.                 sum_height += img_lastfm_flip.height + 3;
  1098.             }
  1099.  
  1100.         }
  1101.  
  1102.  
  1103.         //========================================================================================================================================================================================
  1104.         gr.GdiDrawText("Current track", font_header, normal_color, lm, sum_height + 6 + Y_OFFSET, ww, wh);
  1105.         // artist - album - track ========================================================================================================================================================================================
  1106.  
  1107.         if (lastfm_data[3][3] == "1") { //userloved
  1108.             TLs[13].x = 105;
  1109.             TLs[13].y = sum_height + 6;
  1110.  
  1111.             TLs[13].Draw = function (gr) {
  1112.                 gr.GdiDrawText(TLs[13].label, font_gui, normal_color, TLs[13].x, TLs[13].y + Y_OFFSET, TLs[13].width, TLs[13].height);
  1113.             }
  1114.             TLs[13].Draw(gr);
  1115.         } else {
  1116.             TLs[13].x = ww + 10;
  1117.         }
  1118.  
  1119.         sum_height += font_header.height + 17;
  1120.  
  1121.  
  1122.         for (i = 0; i < 3; i++) {
  1123.             TLs[i].y = sum_height;
  1124.  
  1125.             if (TLs[i].NeedReset) {
  1126.                 if (CorrectedData[i + 1] != "~no data") {
  1127.                     text_Ws[i] = Math.ceil(gr.MeasureString(CorrectedData[i + 1] == np[i] ? np[i] : CorrectedData[i + 1] + " [*]", font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Width);
  1128.                     text_Hs[i] = Math.ceil(gr.MeasureString(CorrectedData[i + 1] == np[i] ? np[i] : CorrectedData[i + 1] + " [*]", font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Height);
  1129.  
  1130.                     switch (i) {
  1131.                         case 0:
  1132.                             TLs[i].OnClick = function () {
  1133.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(CorrectedData[1]))
  1134.                             };
  1135.                             break;
  1136.                         case 1:
  1137.                             TLs[i].OnClick = function () {
  1138.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(CorrectedData[1]) + "/" + encodeURIComponent(CorrectedData[2]))
  1139.                             };
  1140.                             break;
  1141.                         case 2:
  1142.                             TLs[i].OnClick = function () {
  1143.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(CorrectedData[1]) + "/" + encodeURIComponent(CorrectedData[2]) + "/" + encodeURIComponent(CorrectedData[3]))
  1144.                             };
  1145.                             break;
  1146.                     }
  1147.  
  1148.                     TLs[i].x = 50 + lm;
  1149.                     TLs[i].width = text_Ws[i] + 8;
  1150.                     TLs[i].height = text_Hs[i];
  1151.                     TLs[i].label = CorrectedData[i + 1] == np[i] ? np[i] : CorrectedData[i + 1] + " [*]";
  1152.                     TLs[i].tiptext = CorrectedData[i + 1] == np[i] ? "" : "Auto-corrected from: " + "'" + np[i] + "'";
  1153.                     TLs[i].NeedReset = false;
  1154.                 } else {
  1155.                     text_Ws[i] = Math.ceil(gr.MeasureString(np[i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Width);
  1156.                     text_Hs[i] = Math.ceil(gr.MeasureString(np[i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Height);
  1157.  
  1158.                     switch (i) {
  1159.                         case 0:
  1160.                             TLs[i].OnClick = function () {
  1161.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(np[0]))
  1162.                             };
  1163.                             break;
  1164.                         case 1:
  1165.                             TLs[i].OnClick = function () {
  1166.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(np[0]) + "/" + encodeURIComponent(np[1]))
  1167.                             };
  1168.                             break;
  1169.                         case 2:
  1170.                             TLs[i].OnClick = function () {
  1171.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(np[0]) + "/" + encodeURIComponent(np[1]) + "/" + encodeURIComponent(np[2]))
  1172.                             };
  1173.                             break;
  1174.                     }
  1175.  
  1176.                     TLs[i].x = 50 + lm;
  1177.                     TLs[i].width = text_Ws[i] + 8;
  1178.                     TLs[i].height = text_Hs[i];
  1179.                     TLs[i].label = np[i];
  1180.                     TLs[i].tiptext = "";
  1181.                     TLs[i].NeedReset = false;
  1182.                 }
  1183.  
  1184.  
  1185.             }
  1186.             TLs[i].Draw(this.x, this.y, gr);
  1187.  
  1188.  
  1189.             switch (i) {
  1190.                 case 0:
  1191.                     txt_t = "Artist:";
  1192.                     break;
  1193.                 case 1:
  1194.                     txt_t = "Album:";
  1195.                     break;
  1196.                 case 2:
  1197.                     txt_t = "Track:";
  1198.                     break;
  1199.             }
  1200.             gr.GdiDrawText(txt_t, font_label, normal_color, lm, sum_height + 2 + Y_OFFSET, 50, wh);
  1201.             sum_height += text_Hs[i] + 3;
  1202.         }
  1203.  
  1204.         sum_height += 3;
  1205.  
  1206.         // tags ========================================================================================================================================================================================
  1207.  
  1208.         gr.GdiDrawText("Artist", font_label, normal_color, lm, sum_height + 2 + Y_OFFSET, 50, wh);
  1209.         gr.GdiDrawText("tags:", font_label, normal_color, lm, sum_height + 2 + font_label.height + Y_OFFSET, 50, wh);
  1210.         linecounter = 1;
  1211.  
  1212.         if (lastfm_data[1][3][0] != "no data") {
  1213.             for (i = 0; i < 5; i++) {
  1214.                 text_Ws[i + 3] = Math.ceil(gr.MeasureString(lastfm_data[1][3][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Width);
  1215.                 text_Hs[i + 3] = Math.ceil(gr.MeasureString(lastfm_data[1][3][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Height);
  1216.  
  1217.  
  1218.                 TLs[i + 3].x = i == 0 ? 50 + lm : (TLs[i + 2].x + text_Ws[i + 2] + 8 + text_Ws[i + 3] + 8 + 1 < ww - rm - 20 ? TLs[i + 2].x + text_Ws[i + 2] + 11 : 50 + lm);
  1219.                 TLs[i + 3].y = i == 0 ? sum_height : (TLs[i + 2].x + text_Ws[i + 2] + 8 + text_Ws[i + 3] + 8 + 1 < ww - rm - 20 ? TLs[i + 2].y : sum_height + font_normal.height + 3);
  1220.                 linecounter += (TLs[i + 2].x + text_Ws[i + 2] + 8 + text_Ws[i + 3] + 8 + 1 < ww - rm - 20) || i == 0 ? 0 : 1;
  1221.  
  1222.  
  1223.                 if (TLs[i + 3].NeedReset) {
  1224.                     switch (i) {
  1225.                         case 0:
  1226.                             TLs[i + 3].OnClick = function () {
  1227.                                 WshShell.run("http://www.last.fm/tag/" + encodeURIComponent(lastfm_data[1][3][0]))
  1228.                             };
  1229.                             break;
  1230.                         case 1:
  1231.                             TLs[i + 3].OnClick = function () {
  1232.                                 WshShell.run("http://www.last.fm/tag/" + encodeURIComponent(lastfm_data[1][3][1]))
  1233.                             };
  1234.                             break;
  1235.                         case 2:
  1236.                             TLs[i + 3].OnClick = function () {
  1237.                                 WshShell.run("http://www.last.fm/tag/" + encodeURIComponent(lastfm_data[1][3][2]))
  1238.                             };
  1239.                             break;
  1240.                         case 3:
  1241.                             TLs[i + 3].OnClick = function () {
  1242.                                 WshShell.run("http://www.last.fm/tag/" + encodeURIComponent(lastfm_data[1][3][3]))
  1243.                             };
  1244.                             break;
  1245.                         case 4:
  1246.                             TLs[i + 3].OnClick = function () {
  1247.                                 WshShell.run("http://www.last.fm/tag/" + encodeURIComponent(lastfm_data[1][3][4]))
  1248.                             };
  1249.                             break;
  1250.                     }
  1251.  
  1252.  
  1253.                     TLs[i + 3].width = text_Ws[i + 3] + 8;
  1254.                     TLs[i + 3].height = text_Hs[i + 3];
  1255.                     TLs[i + 3].label = lastfm_data[1][3][i];
  1256.                     TLs[i + 3].tiptext = "";
  1257.                     TLs[i + 3].NeedReset = false;
  1258.  
  1259.                 }
  1260.                 TLs[i + 3].Draw(0, 0, gr);
  1261.  
  1262.                 if (i == 0) sum_height += gr.MeasureString(lastfm_data[1][3][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).lines > 1 ? text_Hs[i + 3] - font_normal.height : 0;
  1263.                 else sum_height += (TLs[i + 2].x + text_Ws[i + 2] + 8 + text_Ws[i + 3] + 8 + 1 < ww - rm - 20) ? 0 : text_Hs[i + 3] + 3;
  1264.             }
  1265.         } else {
  1266.             for (i = 0; i < 5; i++) {
  1267.                 TLs[i + 3].show = false;
  1268.             }
  1269.             gr.GdiDrawText("Tags did not recieved", font_normal, normal_color, lm + 50, sum_height + 2 + Y_OFFSET, ww, wh);
  1270.         }
  1271.  
  1272.         sum_height += linecounter == 1 ? font_normal.height * 2 + 6 : font_normal.height + 6;
  1273.         // similar ========================================================================================================================================================================================
  1274.  
  1275.         gr.GdiDrawText("Similar", font_label, normal_color, lm, sum_height + 2 + Y_OFFSET, 50, wh);
  1276.         gr.GdiDrawText("artists:", font_label, normal_color, lm, sum_height + 2 + font_label.height + Y_OFFSET, 50, wh);
  1277.         linecounter = 1;
  1278.  
  1279.         if (lastfm_data[1][4][0] != "no data") {
  1280.             for (i = 0; i < 5; i++) {
  1281.                 text_Ws[i + 8] = Math.ceil(gr.MeasureString(lastfm_data[1][4][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Width);
  1282.                 text_Hs[i + 8] = Math.ceil(gr.MeasureString(lastfm_data[1][4][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).Height);
  1283.  
  1284.  
  1285.                 TLs[i + 8].x = i == 0 ? 50 + lm : (TLs[i + 7].x + text_Ws[i + 7] + 8 + text_Ws[i + 8] + 8 + 1 < ww - rm - 20 ? TLs[i + 7].x + text_Ws[i + 7] + 11 : 50 + lm);
  1286.                 TLs[i + 8].y = i == 0 ? sum_height : (TLs[i + 7].x + text_Ws[i + 7] + 8 + text_Ws[i + 8] + 8 + 1 < ww - rm - 20 ? TLs[i + 7].y : sum_height + font_normal.height + 3);
  1287.                 linecounter += (TLs[i + 7].x + text_Ws[i + 7] + 8 + text_Ws[i + 8] + 8 + 1 < ww - rm - 20) || i == 0 ? 0 : 1;
  1288.  
  1289.                 if (TLs[i + 8].NeedReset) {
  1290.                     switch (i) {
  1291.                         case 0:
  1292.                             TLs[i + 8].OnClick = function () {
  1293.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(lastfm_data[1][4][0]))
  1294.                             };
  1295.                             break;
  1296.                         case 1:
  1297.                             TLs[i + 8].OnClick = function () {
  1298.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(lastfm_data[1][4][1]))
  1299.                             };
  1300.                             break;
  1301.                         case 2:
  1302.                             TLs[i + 8].OnClick = function () {
  1303.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(lastfm_data[1][4][2]))
  1304.                             };
  1305.                             break;
  1306.                         case 3:
  1307.                             TLs[i + 8].OnClick = function () {
  1308.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(lastfm_data[1][4][3]))
  1309.                             };
  1310.                             break;
  1311.                         case 4:
  1312.                             TLs[i + 8].OnClick = function () {
  1313.                                 WshShell.run("http://www.last.fm/music/" + encodeURIComponent(lastfm_data[1][4][4]))
  1314.                             };
  1315.                             break;
  1316.                     }
  1317.  
  1318.  
  1319.                     TLs[i + 8].width = text_Ws[i + 8] + 8;
  1320.                     TLs[i + 8].height = text_Hs[i + 8];
  1321.                     TLs[i + 8].label = lastfm_data[1][4][i];
  1322.                     TLs[i + 8].tiptext = "";
  1323.                     TLs[i + 8].NeedReset = false;
  1324.  
  1325.                 }
  1326.                 TLs[i + 8].Draw(0, 0, gr);
  1327.  
  1328.                 if (i == 0) sum_height += gr.MeasureString(lastfm_data[1][4][i], font_normal, 0, 0, ww - 50 - lm - rm - 20, wh, LineStrFmt).lines > 1 ? text_Hs[i + 8] - font_normal.height : 0;
  1329.                 else sum_height += (TLs[i + 7].x + text_Ws[i + 7] + 8 + text_Ws[i + 8] + 8 + 1 < ww - rm - 20) ? 0 : text_Hs[i + 8] + 3;
  1330.             }
  1331.         } else {
  1332.             for (i = 0; i < 5; i++) {
  1333.                 TLs[i + 8].show = false;
  1334.             }
  1335.             gr.GdiDrawText("Artists did not recieved", font_normal, normal_color, lm + 50, sum_height + 2 + Y_OFFSET, ww, wh);
  1336.         }
  1337.  
  1338.         sum_height += linecounter == 1 ? font_normal.height * 2 + 2 : font_normal.height + 2;
  1339.         GetCoordinates(); //run this when all buttons are resetted
  1340.  
  1341.         // listeners ========================================================================================================================================================================================
  1342.         gr.GdiDrawText("Listeners", font_header, normal_color, lm, sum_height + Y_OFFSET, ww, wh);
  1343.         sum_height += font_header.height + 5;
  1344.  
  1345.         for (id = 1; id <= 3; id++) {
  1346.             charcounter = 0;
  1347.             spcounter = 0;
  1348.  
  1349.             for (j = 0; j < lastfm_data[id][2].length; j++) {
  1350.                 if (lastfm_data[id][2].substring((j), j + 1) != " ") {
  1351.                     gr.DrawImage(img_lastfm_flip, lm + 50 + charcounter * 11 + spcounter * 5, sum_height + Y_OFFSET, img_lastfm_flip.width, img_lastfm_flip.height, 0, 0, img_lastfm_flip.width, img_lastfm_flip.height);
  1352.                     charcounter++;
  1353.                 } else {
  1354.                     spcounter++;
  1355.                 }
  1356.                 gr.GdiDrawText(lastfm_data[id][2].substring((j), j + 1), font_num, RGB(255, 255, 255), lm + (charcounter - 1) * 11 + spcounter * 5 + 2 + 50, sum_height - 1 + Y_OFFSET, ww, wh);
  1357.             }
  1358.  
  1359.             switch (id) {
  1360.                 case 1:
  1361.                     txt_t = "Artist:";
  1362.                     break;
  1363.                 case 2:
  1364.                     txt_t = "Album:";
  1365.                     break;
  1366.                 case 3:
  1367.                     txt_t = "Track:";
  1368.                     break;
  1369.             }
  1370.             gr.GdiDrawText(txt_t, font_label, normal_color, lm, sum_height - 1 + Y_OFFSET, ww, wh);
  1371.             sum_height += 18;
  1372.         }
  1373.  
  1374.  
  1375.         // plays ========================================================================================================================================================================================
  1376.         gr.GdiDrawText("Plays", font_header, normal_color, lm, sum_height + Y_OFFSET, ww, wh);
  1377.         sum_height += font_header.height + 5;
  1378.  
  1379.         for (id = 1; id <= 3; id++) {
  1380.             charcounter = 0;
  1381.             spcounter = 0;
  1382.             for (j = 0; j < lastfm_data[id][0].length; j++) {
  1383.                 if (lastfm_data[id][0].substring((j), j + 1) != " ") {
  1384.                     gr.DrawImage(img_lastfm_flip, lm + 50 + charcounter * 11 + spcounter * 5, sum_height + Y_OFFSET, img_lastfm_flip.width, img_lastfm_flip.height, 0, 0, img_lastfm_flip.width, img_lastfm_flip.height);
  1385.                     charcounter++;
  1386.                 } else {
  1387.                     spcounter++;
  1388.                 }
  1389.                 gr.GdiDrawText(lastfm_data[id][0].substring((j), j + 1), font_num, RGB(255, 255, 255), lm + (charcounter - 1) * 11 + spcounter * 5 + 2 + 50, sum_height - 1 + Y_OFFSET, ww, wh);
  1390.             }
  1391.  
  1392.             switch (id) {
  1393.                 case 1:
  1394.                     txt_tt = "Artist:";
  1395.                     break;
  1396.                 case 2:
  1397.                     txt_tt = "Album:";
  1398.                     break;
  1399.                 case 3:
  1400.                     txt_tt = "Track:";
  1401.                     break;
  1402.             }
  1403.  
  1404.             gr.GdiDrawText(txt_tt, font_label, normal_color, lm, sum_height - 1 + Y_OFFSET, ww, wh);
  1405.             sum_height += 18;
  1406.         }
  1407.  
  1408.         // by user ========================================================================================================================================================================================
  1409.         gr.GdiDrawText(username != "" ? "Plays by " + username : "Plays by " + opt_username, font_header, normal_color, lm, sum_height + Y_OFFSET, ww, wh);
  1410.  
  1411.         sum_height += font_header.height + 5;
  1412.  
  1413.         for (id = 1; id <= 3; id++) {
  1414.             charcounter = 0;
  1415.             spcounter = 0;
  1416.             for (j = 0; j < lastfm_data[id][1].length; j++) {
  1417.                 if (lastfm_data[id][1].substring((j), j + 1) != " ") {
  1418.                     gr.DrawImage(img_lastfm_flip, lm + 50 + charcounter * 11 + spcounter * 5, sum_height + Y_OFFSET, img_lastfm_flip.width, img_lastfm_flip.height, 0, 0, img_lastfm_flip.width, img_lastfm_flip.height);
  1419.                     charcounter++;
  1420.                 } else {
  1421.                     spcounter++;
  1422.                 }
  1423.                 gr.GdiDrawText(lastfm_data[id][1].substring((j), j + 1), font_num, RGB(255, 255, 255), lm + (charcounter - 1) * 11 + spcounter * 5 + 2 + 50, sum_height - 1 + Y_OFFSET, ww, wh);
  1424.             }
  1425.  
  1426.             switch (id) {
  1427.                 case 1:
  1428.                     txt_tt = "Artist:";
  1429.                     break;
  1430.                 case 2:
  1431.                     txt_tt = "Album:";
  1432.                     break;
  1433.                 case 3:
  1434.                     txt_tt = "Track:";
  1435.                     break;
  1436.             }
  1437.  
  1438.             gr.GdiDrawText(txt_tt, font_label, normal_color, lm, sum_height - 1 + Y_OFFSET, ww, wh);
  1439.             sum_height += 18;
  1440.         }
  1441.  
  1442.     } else if (wait == 1) {
  1443.         gr.GdiDrawText("Grabbing last.fm data.\n Hold on!", font_normal, normal_color, 0, 0, ww, wh, DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
  1444.         return;
  1445.     } else if (wait == -1) {
  1446.         gr.GdiDrawText("Artist: " + np[0] + "\n Album: " + np[1] + "\n Track: " + np[2] + "\n \n Something went wrong :( \n Data did not recieved.", font_normal, normal_color, 0, 0, ww, wh, DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
  1447.     } else if (wait == -2) {
  1448.         gr.GdiDrawText("No track specified", font_normal, normal_color, 0, 0, ww, wh, DT_CENTER | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
  1449.     }
  1450.  
  1451.     //draw vscrollbar
  1452.     SetSlider();
  1453.     Scrollbar.Draw(gr);
  1454. }
  1455.  
  1456. function on_playback_new_track() {
  1457.     if(Properties.Panel.CursorFollowMode == CursorFollowMode.OnlyStopped){
  1458.         WaitTimer.Stop();
  1459.         MetaDB = fb.GetNowPlaying();
  1460.         FOCUSFLAG = false;
  1461.         np = [fb.TitleFormat("%artist%").EvalWithMetadb(MetaDB), fb.TitleFormat("%album%").EvalWithMetadb(MetaDB), fb.TitleFormat("%title%").EvalWithMetadb(MetaDB)]
  1462.         if (np[0] == "?" && np[1] == "?") {
  1463.             wait = -2;
  1464.             window.Repaint();
  1465.             return;
  1466.         }
  1467.         lastfm_status = 0;
  1468.         wait = 1;
  1469.         window.Repaint();
  1470.         get_lastfm_data();
  1471.     }
  1472. }
  1473.  
  1474.  
  1475. function on_item_focus_change() {
  1476.     if(Properties.Panel.CursorFollowMode == CursorFollowMode.Always || (Properties.Panel.CursorFollowMode == CursorFollowMode.OnlyStopped && !fb.IsPlaying && !fb.IsPaused)){
  1477.         WaitTimer.Stop();
  1478.         WaitTimer.Start();
  1479.     }
  1480. }
  1481.  
  1482. function on_playback_stop(reason) {
  1483.     if (!reason || reason == 1) {
  1484.         if(Properties.Panel.CursorFollowMode == CursorFollowMode.OnlyStopped && !FOCUSFLAG){
  1485.             WaitTimer.Stop();
  1486.             WaitTimer.Start();
  1487.         }
  1488.     }
  1489. }
  1490.  
  1491. function on_mouse_move(x, y) {
  1492.     if (window.Width < 185 || window.Height < 100) return;
  1493.     if (wait != 0) return;
  1494.  
  1495.     if (slider_drag) {
  1496.         Scrollbar.slider.y = Math.min(Math.max(y - slider_y_rel, 0), wh - Scrollbar.slider.height);
  1497.         Y_OFFSET = Math.round(Math.min(Math.max(-1 * Scrollbar.step * Scrollbar.slider.y, -1 * scrollmax), 0));
  1498.         window.Repaint();
  1499.     } else {
  1500.         if (Scrollbar.slider_isXYok(x, y)) {
  1501.             if (!slider_hover && !d_link) slider_hover = true;
  1502.             window.RepaintRect(ww - 20, 0, ww, wh);
  1503.         } else if (slider_hover) {
  1504.             slider_hover = false;
  1505.             window.RepaintRect(ww - 20, 0, ww, wh);
  1506.         }
  1507.     }
  1508.  
  1509.     if (d_link) {
  1510.         if (d_link.isXYok(x, y)) {
  1511.             if (d_link.state != 2) d_link.ChangeState(2);
  1512.         } else if (d_link.state != 1) d_link.ChangeState(1);
  1513.     } else {
  1514.         for (var i = 0; i < TLs.length; i++)
  1515.         if (TLs[i].isXYok(x, y) && TLs[i].show) {
  1516.             if (h_link != TLs[i]) {
  1517.                 if (h_link) h_link.ChangeState(0);
  1518.                 h_link = TLs[i];
  1519.                 if (h_link != TLs[13]) window.SetCursor(IDC_HAND);
  1520.                 h_link.ChangeState(1);
  1521.             }
  1522.             break;
  1523.         }
  1524.         if (i == TLs.length) {
  1525.  
  1526.             if (h_link) {
  1527.                 if (h_link) h_link.ChangeState(0);
  1528.                 h_link = undefined;
  1529.                 window.SetCursor(IDC_ARROW);
  1530.             }
  1531.         }
  1532.     }
  1533.  
  1534. }
  1535.  
  1536. function on_mouse_lbtn_down(x, y) {
  1537.     if (window.Width < 185 || window.Height < 100) return;
  1538.     if (h_link && !d_link) {
  1539.         d_link = h_link;
  1540.         d_link.ChangeState(2);
  1541.     }
  1542.  
  1543.     if (NeedScrollbar) {
  1544.         if (slider_hover && !slider_drag && !d_link) {
  1545.             slider_drag = true;
  1546.             slider_y_rel = y - Scrollbar.slider.y;
  1547.         } else if (!slider_hover && !slider_drag && !d_link && Scrollbar.isXYok(x, y)) {
  1548.             slider_drag = true;
  1549.             slider_y_rel = Scrollbar.slider.height / 2;
  1550.             on_mouse_move(x, y);
  1551.         }
  1552.     }
  1553.  
  1554. }
  1555.  
  1556. function on_mouse_lbtn_up(x, y) {
  1557.     if (window.Width < 185 || window.Height < 100) return;
  1558.     if (d_link) {
  1559.         if (d_link.state == 2) {
  1560.             d_link.OnClick();
  1561.         }
  1562.         d_link = undefined;
  1563.         on_mouse_move(x, y);
  1564.     }
  1565.  
  1566.     if (slider_drag) {
  1567.         slider_drag = false;
  1568.     }
  1569. }
  1570.  
  1571. function on_mouse_leave() {
  1572.     if (window.Width < 185 || window.Height < 100) return;
  1573.     if (h_link) {
  1574.         h_link.ChangeState(0);
  1575.         h_link = undefined;
  1576.         window.SetCursor(IDC_ARROW);
  1577.     }
  1578.     Tooltip.Text = "";
  1579.  
  1580.     if (slider_hover) {
  1581.         slider_hover = false;
  1582.         window.RepaintRect(ww - 20, 0, ww, wh);
  1583.     }
  1584. }
  1585.  
  1586. function on_mouse_wheel(delta) {
  1587.     if (window.Width < 185 || window.Height < 100) return;
  1588.     if (NeedScrollbar && !d_link && !slider_drag) {
  1589.         Y_OFFSET = Math.min(Math.max(Y_OFFSET + delta * 35, -1 * scrollmax), 0);
  1590.         on_mouse_move();
  1591.         window.Repaint();
  1592.     }
  1593. }
  1594.  
  1595. function on_mouse_rbtn_down(x, y, vkey) {
  1596.     rbtnDown = true;
  1597. }
  1598.  
  1599. function on_mouse_rbtn_up(x, y, vkey) {
  1600.     if (window.Width < 185 || window.Height < 100) return false;
  1601.     if (rbtnDown) {
  1602.         rbtnDown = false;
  1603.         if (vkey == MK_SHIFT) {
  1604.             return false; // if shift button pressed, show default context menu.
  1605.         } else {
  1606.             show_context_menu(x, y);
  1607.             return true;
  1608.         }
  1609.     }
  1610. }
  1611.  
  1612. function on_playlist_items_removed(playlist, new_count) {
  1613.     on_playlists_changed();
  1614. }
  1615.  
  1616. function on_playlist_switch() {
  1617.     on_playlists_changed();
  1618. }
  1619.  
  1620. function on_playlists_changed() {
  1621.     on_item_focus_change();
  1622. }
  1623.  
  1624. //EOF
RAW Paste Data