Advertisement
Guest User

Untitled

a guest
Jan 30th, 2015
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // *****************************************************************************************************************************************
  2. // Playlist object by Br3tt aka Falstaff (c)2015
  3. // *****************************************************************************************************************************************
  4.  
  5. oScrollbar = function(themed) {
  6.     this.themed = themed;
  7.     if(themed) {
  8.         this.theme = window.CreateThemeManager("scrollbar");
  9.     }; else {
  10.         this.theme = false;
  11.     };
  12.     this.cursorScrollTimer = false;
  13.     this.buttons = Array(null, null, null);
  14.  
  15.     this.draw = function(gr, x, y) {
  16.         // draw background and buttons up & down
  17.         if(this.themed) {
  18.             try {
  19.                 this.theme.SetPartAndStateId(6, 1);
  20.                 this.theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);
  21.                 gr.FillSolidRect(this.x - 1, this.y, 1, this.h, g_color_normal_bg);
  22.                 gr.FillSolidRect(this.x - 1, this.y, 1, this.h, RGBA(0,0,0,60));
  23.             }; catch(e) {
  24.                 gr.FillSolidRect(this.x, this.y, this.w, this.h, g_color_normal_txt & 0x15ffffff);
  25.             };
  26.         }; else {
  27.             gr.FillSolidRect(this.x, this.y, this.w, this.h, g_color_normal_txt & 0x15ffffff);
  28.         };
  29.         // draw up & down buttons
  30.         this.buttons[cScrollBar.buttonType.up].draw(gr, this.x, this.y, 255);
  31.         this.buttons[cScrollBar.buttonType.down].draw(gr, this.x, this.y + this.h - this.w, 255);
  32.        
  33.         // draw cursor
  34.         this.buttons[cScrollBar.buttonType.cursor].draw(gr, this.x, this.cursorPos, 255);
  35.     };
  36.          
  37.     this.setCursor = function(totalRowVisible, totalRows, offset) {
  38.         if(totalRows > 0 && totalRows > totalRowVisible && this.w > 2) {
  39.             this.cursorWidth = this.w - 0;
  40.             // calc cursor height
  41.             this.cursorHeight = Math.round((totalRowVisible / totalRows) * this.area_h);
  42.             if(this.cursorHeight < this.w - 2) this.cursorHeight = this.w - 2;
  43.             // cursor pos
  44.             var ratio = offset / (totalRows - totalRowVisible);
  45.             this.cursorPos = this.area_y + Math.round((this.area_h - this.cursorHeight) * ratio);
  46.             this.setCursorButton();
  47.         };
  48.     };
  49.    
  50.     this.setCursorButton = function() {
  51.         // normal cursor Image
  52.         this.cursorImage_normal = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
  53.         var gb = this.cursorImage_normal.GetGraphics();
  54.         // Draw Themed Scrollbar (lg/col)
  55.         try {
  56.             this.theme.SetPartAndStateId(3, 1);
  57.             this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  58.             if(this.cursorHeight >= 16) {
  59.                 this.theme.SetPartAndStateId(9, 1);
  60.                 this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  61.             };
  62.         }; catch(e) {
  63.             gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x33ffffff);
  64.         };
  65.         this.cursorImage_normal.ReleaseGraphics(gb);
  66.        
  67.         // hover cursor Image
  68.         this.cursorImage_hover = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
  69.         gb = this.cursorImage_hover.GetGraphics();
  70.         // Draw Themed Scrollbar (lg/col)
  71.         try {
  72.             this.theme.SetPartAndStateId(3, 2);
  73.             this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  74.             if(this.cursorHeight >= 16) {
  75.                 this.theme.SetPartAndStateId(9, 1);
  76.                 this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  77.             };
  78.         }; catch(e) {
  79.             gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x55ffffff);
  80.         };
  81.         this.cursorImage_hover.ReleaseGraphics(gb);
  82.        
  83.         // down cursor Image
  84.         this.cursorImage_down = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
  85.         gb = this.cursorImage_down.GetGraphics();
  86.         // Draw Themed Scrollbar (lg/col)
  87.         try {
  88.             this.theme.SetPartAndStateId(3, 3);
  89.             this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  90.             if(this.cursorHeight >= 16) {
  91.                 this.theme.SetPartAndStateId(9, 1);
  92.                 this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
  93.             };
  94.         }; catch(e) {
  95.             gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x99ffffff);
  96.         };
  97.         this.cursorImage_down.ReleaseGraphics(gb);
  98.        
  99.         // create/refresh cursor Button in buttons array
  100.         this.buttons[cScrollBar.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
  101.     };
  102.    
  103.     this.setButtons = function() {
  104.  
  105.         // normal scroll_up Image
  106.         this.upImage_normal = gdi.CreateImage(this.w, this.w);
  107.         var gb = this.upImage_normal.GetGraphics();
  108.         // Draw Themed Scrollbar (lg/col)
  109.         try {
  110.             this.theme.SetPartAndStateId(1, 1);
  111.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  112.         }; catch(e) {
  113.             gb.SetTextRenderingHint(4);
  114.             gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
  115.         };
  116.         this.upImage_normal.ReleaseGraphics(gb);
  117.  
  118.         // hover scroll_up Image
  119.         this.upImage_hover = gdi.CreateImage(this.w, this.w);
  120.         gb = this.upImage_hover.GetGraphics();
  121.         // Draw Themed Scrollbar (lg/col)
  122.         try {
  123.             this.theme.SetPartAndStateId(1, 2);
  124.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  125.         }; catch(e) {
  126.             gb.SetTextRenderingHint(4);
  127.             gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
  128.         };
  129.         this.upImage_hover.ReleaseGraphics(gb);
  130.  
  131.         // down scroll_up Image
  132.         this.upImage_down = gdi.CreateImage(this.w, this.w);
  133.         gb = this.upImage_down.GetGraphics();
  134.         // Draw Themed Scrollbar (lg/col)
  135.         try {
  136.             this.theme.SetPartAndStateId(1, 3);
  137.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  138.         }; catch(e) {
  139.             gb.SetTextRenderingHint(4);
  140.             gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt, 0, 0, this.w, this.w, cc_stringformat);
  141.         };
  142.         this.upImage_down.ReleaseGraphics(gb);
  143.  
  144.         // normal scroll_down Image
  145.         this.downImage_normal = gdi.CreateImage(this.w, this.w);
  146.         gb = this.downImage_normal.GetGraphics();
  147.         // Draw Themed Scrollbar (lg/col)
  148.         try {
  149.             this.theme.SetPartAndStateId(1, 5);
  150.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  151.         }; catch(e) {
  152.             gb.SetTextRenderingHint(4);
  153.             gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
  154.         };
  155.         this.downImage_normal.ReleaseGraphics(gb);
  156.  
  157.         // hover scroll_down Image
  158.         this.downImage_hover = gdi.CreateImage(this.w, this.w);
  159.         gb = this.downImage_hover.GetGraphics();
  160.         // Draw Themed Scrollbar (lg/col)
  161.         try {
  162.             this.theme.SetPartAndStateId(1, 6);
  163.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  164.         }; catch(e) {
  165.             gb.SetTextRenderingHint(4);
  166.             gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
  167.         };
  168.         this.downImage_hover.ReleaseGraphics(gb);
  169.  
  170.         // down scroll_down Image
  171.         this.downImage_down = gdi.CreateImage(this.w, this.w);
  172.         gb = this.downImage_down.GetGraphics();
  173.         // Draw Themed Scrollbar (lg/col)
  174.         try {
  175.             this.theme.SetPartAndStateId(1, 7);
  176.             this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
  177.         }; catch(e) {
  178.             gb.SetTextRenderingHint(4);
  179.             gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt, 0, 0, this.w, this.w, cc_stringformat);
  180.         };
  181.         this.downImage_down.ReleaseGraphics(gb);
  182.  
  183.         for(i = 1; i < this.buttons.length; i++) {
  184.             switch(i) {
  185.             case cScrollBar.buttonType.cursor:
  186.                 this.buttons[cScrollBar.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
  187.                 break;
  188.             case cScrollBar.buttonType.up:
  189.                 this.buttons[cScrollBar.buttonType.up] = new button(this.upImage_normal, this.upImage_hover, this.upImage_down);
  190.                 break;
  191.             case cScrollBar.buttonType.down:
  192.                 this.buttons[cScrollBar.buttonType.down] = new button(this.downImage_normal, this.downImage_hover, this.downImage_down);
  193.                 break;
  194.             };
  195.         };
  196.     };
  197.    
  198.     this.setSize = function(x, y, w, h) {
  199.         this.x = x;
  200.         this.y = y;
  201.         this.w = w;
  202.         this.h = h;
  203.         // scrollbar area for the cursor (<=> scrollbar height minus up & down buttons height)
  204.         this.area_y = y + w;
  205.         this.area_h = h - (w * 2);
  206.         this.setButtons();
  207.     };
  208.    
  209.     this.setOffsetFromCursorPos = function() {
  210.         // calc ratio of the scroll cursor to calc the equivalent item for the full playlist (with gh)
  211.         var ratio = (this.cursorPos - this.area_y) / (this.area_h - this.cursorHeight);
  212.         // calc idx of the item (of the full playlist with gh) to display at top of the panel list (visible)
  213.         var newOffset = Math.round((p.list.totalRows - p.list.totalRowVisible) * ratio);
  214.         return newOffset;
  215.     };
  216.    
  217.     this.cursorCheck = function(event, x, y) {
  218.         this.ishover = (x >= this.x && x <= this.x + this.w && y >= this.cursorPos && y <= (this.cursorPos + this.cursorHeight));
  219.  
  220.         switch(event) {
  221.         case "down":
  222.             this.buttons[0].checkstate(event, x, y);
  223.             if(this.ishover) {
  224.                 this.cursorClickX = x;
  225.                 this.cursorClickY = y;
  226.                 this.cursorDrag = true;
  227.                 this.cursorDragDelta = y - this.cursorPos;
  228.                 this.clicked = true;
  229.             };
  230.             break;
  231.         case "up":
  232.             this.buttons[0].checkstate(event, x, y);
  233.             if(this.cursorDrag) {
  234.                 p.list.offset = this.setOffsetFromCursorPos();
  235.                 p.list.setItems(false);
  236.                 full_repaint();
  237.             };
  238.             this.cursorClickX = 0;
  239.             this.cursorClickY = 0;
  240.             this.cursorDrag = false;
  241.             this.clicked = false;
  242.             break;
  243.         case "move":
  244.             this.buttons[0].checkstate(event, x, y);
  245.             if(this.cursorDrag) {
  246.                 this.cursorPos = y - this.cursorDragDelta;
  247.                 if(this.cursorPos + this.cursorHeight > this.area_y + this.area_h) {
  248.                     this.cursorPos = (this.area_y + this.area_h) - this.cursorHeight;
  249.                 };
  250.                 if(this.cursorPos < this.area_y) {
  251.                     this.cursorPos = this.area_y;
  252.                 };
  253.                
  254.                 p.list.offset = this.setOffsetFromCursorPos();
  255.                 if(!g_mouse_wheel_timer) {
  256.                     g_mouse_wheel_timer = window.SetTimeout(function() {
  257.                         p.list.setItems(false);
  258.                         full_repaint();
  259.                         g_mouse_wheel_timer && window.ClearTimeout(g_mouse_wheel_timer);
  260.                         g_mouse_wheel_timer = false;
  261.                     }, 30);
  262.                 };
  263.             };
  264.             break;
  265.         case "leave":
  266.             this.buttons[0].checkstate(event, x, y);
  267.             break;
  268.         };
  269.     };
  270.  
  271.     this.check = function(event, x, y) {
  272.         this.hover = (x >= this.x && x <= this.x + this.w && y > this.area_y && y < this.area_y + this.area_h);
  273.  
  274.         // check cursor
  275.         this.cursorCheck(event, x, y);
  276.        
  277.         // check other buttons
  278.         for(var i = 1; i < this.buttons.length; i++) {
  279.             switch(event) {
  280.                 case "dblclk":
  281.                     switch(i) {
  282.                         case 1: // up button
  283.                             if(this.buttons[i].checkstate(event, x, y) == ButtonStates.hover) {
  284.                                 this.clicked = true;
  285.                                 p.list.buttonclicked = true;
  286.                                 this.buttons[i].checkstate("down", x, y);
  287.  
  288.                                 p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
  289.                                 p.list.setItems(false);
  290.                                 p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  291.                                 if(properties.smoothscrolling) {
  292.                                     cList.scroll_direction = 1;
  293.                                     set_scroll_delta();
  294.                                 };
  295.                                 full_repaint();
  296.                                 if(!cScrollBar.timerID2) {
  297.                                     cScrollBar.timerID2 = window.SetInterval(function() {
  298.                                         cScrollBar.timer_counter++;
  299.                                         if(cScrollBar.timer_counter > 7) {
  300.                                             p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
  301.                                             p.list.setItems(false);
  302.                                             p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  303.                                             full_repaint();
  304.                                         };
  305.                                     }, 60);
  306.                                 };
  307.                             };
  308.                             break;
  309.                         case 2: // down button
  310.                             if(this.buttons[i].checkstate(event, x, y) == ButtonStates.hover) {
  311.                                 this.clicked = true;
  312.                                 p.list.buttonclicked = true;
  313.                                 this.buttons[i].checkstate("down", x, y);
  314.  
  315.                                 p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
  316.                                 p.list.setItems(false);
  317.                                 p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  318.                                 if(properties.smoothscrolling) {
  319.                                     cList.scroll_direction = -1;
  320.                                     set_scroll_delta();
  321.                                 };
  322.                                 full_repaint();
  323.                                 if(!cScrollBar.timerID2) {
  324.                                     cScrollBar.timerID2 = window.SetInterval(function() {
  325.                                         cScrollBar.timer_counter++;
  326.                                         if(cScrollBar.timer_counter > 7) {
  327.                                             p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
  328.                                             p.list.setItems(false);
  329.                                             p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  330.                                             full_repaint();
  331.                                         };
  332.                                     }, 60);
  333.                                 };
  334.                             };
  335.                             break;
  336.                     };
  337.                     break;
  338.                 case "down":
  339.                     switch(i) {
  340.                         case 1: // up button
  341.                             if(this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
  342.                                 this.clicked = true;
  343.                                 p.list.buttonclicked = true;
  344.                                 cScrollBar.timer_counter = 0;
  345.                                 p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
  346.                                 p.list.setItems(false);
  347.                                 p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  348.                                 if(properties.smoothscrolling) {
  349.                                     cList.scroll_direction = 1;
  350.                                     set_scroll_delta();
  351.                                 };
  352.                                 full_repaint();
  353.                                 if(!cScrollBar.timerID2) {
  354.                                     cScrollBar.timerID2 = window.SetInterval(function() {
  355.                                         cScrollBar.timer_counter++;
  356.                                         if(cScrollBar.timer_counter > 7) {
  357.                                             p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
  358.                                             p.list.setItems(false);
  359.                                             p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  360.                                             full_repaint();
  361.                                         };
  362.                                     }, 60);
  363.                                 };
  364.                             };
  365.                             break;
  366.                         case 2: // down button
  367.                             if(this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
  368.                                 this.clicked = true;
  369.                                 p.list.buttonclicked = true;
  370.                                 cScrollBar.timer_counter = 0;
  371.                                 p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
  372.                                 p.list.setItems(false);
  373.                                 p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  374.                                 if(properties.smoothscrolling) {
  375.                                     cList.scroll_direction = -1;
  376.                                     set_scroll_delta();
  377.                                 };
  378.                                 full_repaint();
  379.                                 if(!cScrollBar.timerID2) {
  380.                                     cScrollBar.timerID2 = window.SetInterval(function() {
  381.                                         cScrollBar.timer_counter++;
  382.                                         if(cScrollBar.timer_counter > 7) {
  383.                                             p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
  384.                                             p.list.setItems(false);
  385.                                             p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  386.                                             full_repaint();
  387.                                         };
  388.                                     }, 60);
  389.                                 };
  390.                             };
  391.                             break;
  392.                     };
  393.                     break;
  394.                 case "up":
  395.                     if(cScrollBar.timerID2) {
  396.                         window.ClearInterval(cScrollBar.timerID2);
  397.                         cScrollBar.timerID2 = false;
  398.                     };
  399.                     cScrollBar.timer_counter = 0;
  400.                     this.buttons[i].checkstate(event, x, y);
  401.                     this.clicked = false;
  402.                     break;
  403.                 default:
  404.                     this.buttons[i].checkstate(event, x, y);
  405.             };
  406.         };
  407.     };
  408.  
  409.     this.repaint = function() {
  410.         window.RepaintRect(this.x, this.y, this.w, this.h);
  411.     };
  412. };
  413.  
  414. oGroup = function(index, start, count, total_time_length, focusedTrackId) {
  415.     this.index = index;
  416.     this.start = start;
  417.     this.count = count;
  418.     this.total_time_length = total_time_length;
  419.     this.total_group_duration_txt = formatPlaylistTotalDurationText(total_time_length);
  420.  
  421.     if(count < cGroup.count_minimum) {
  422.         this.rowsToAdd = cGroup.count_minimum - count;
  423.     }; else {
  424.         this.rowsToAdd = 0;
  425.     };
  426.     // Add extra rows to the total rows of the group
  427.     this.rowsToAdd += cGroup.extra_rows;
  428.  
  429.     if(properties.autocollapse) {
  430.         if(focusedTrackId >= this.start && focusedTrackId < this.start + this.count) { // focused track is in this group!
  431.             this.collapsed = false;
  432.             // save in globals the current group id of the focused track (used for autocollapse option)
  433.             g_group_id_focused = this.index;
  434.         }; else {
  435.             this.collapsed = true;
  436.         };
  437.     }; else {
  438.         this.collapsed = false;
  439.     };
  440.    
  441.     this.totalPreviousRows = 0;
  442.  
  443.     this.collapse = function() {
  444.         this.collapse = true;
  445.     };
  446.  
  447.     this.expand = function() {
  448.         this.collapse = false;
  449.     };
  450. };
  451.  
  452. oItem = function (playlist, row_index, type, handle, track_index, group_index, track_index_in_group, heightInRow, groupRowDelta, obj, empty_row_index) {
  453.     // type 1 = group
  454.     // type 0 = track
  455.     this.type = type;
  456.     this.playlist = playlist;
  457.     this.row_index = row_index;
  458.     this.metadb = handle;
  459.     this.track_index = track_index;
  460.     this.track_index_in_group = track_index_in_group;
  461.     this.group_index = group_index;
  462.     this.heightInRow = heightInRow;
  463.     this.groupRowDelta = groupRowDelta;
  464.     this.obj = obj;
  465.     this.empty_row_index = empty_row_index;
  466.     this.tracktype = TrackType(this.metadb.rawpath.substring(0, 4));
  467.     this.l_rating = 0;
  468.     this.l_mood = 0;
  469.  
  470.     this.setGroupMeta = function () {
  471.         if (this.type == 1) {
  472.             if (this.metadb) {
  473.                 this.l1 = fb.TitleFormat(p.list.groupby[cGroup.pattern_idx].l1).EvalWithMetadb(this.metadb);
  474.                 this.r1 = fb.TitleFormat(p.list.groupby[cGroup.pattern_idx].r1).EvalWithMetadb(this.metadb);
  475.                 this.l2 = fb.TitleFormat(p.list.groupby[cGroup.pattern_idx].l2).EvalWithMetadb(this.metadb);
  476.                 this.r2 = fb.TitleFormat(p.list.groupby[cGroup.pattern_idx].r2).EvalWithMetadb(this.metadb);
  477.             };
  478.         };
  479.     };
  480.     this.setGroupMeta();
  481.  
  482.     this.drawRowContents = function (gr) {
  483.         // Draw columns content
  484.         var cx, cw;
  485.    
  486.         for (var j = 0; j < p.headerBar.columns.length; j++) {
  487.             if (p.headerBar.columns[j].w > 0) {
  488.                 cx = p.headerBar.columns[j].x + zoom(5, g_dpi);
  489.                 cw = (Math.abs(p.headerBar.w * p.headerBar.columns[j].percent / 100000)) - zoom(10, g_dpi);
  490.                 switch (p.headerBar.columns[j].ref) {
  491.                 case "State":
  492.                     var queue_w = Math.round(gr.CalcTextWidth("00", g_font_queue_idx) + 1);
  493.                     var icon_w = queue_w + zoom(6, g_dpi);
  494.                     switch (p.headerBar.columns[j].align) {
  495.                     case 0:
  496.                         var icon_x = cx + zoom(2, g_dpi);
  497.                         break;
  498.                     case 1:
  499.                         var icon_x = cx + Math.round((cw / 2) - (queue_w / 2)) - zoom(5, g_dpi);
  500.                         break;
  501.                     case 2:
  502.                         var icon_x = Math.floor(cx + cw - queue_w - zoom(10, g_dpi));
  503.                         break;
  504.                     };
  505.                     if(fb.IsPlaying) {
  506.                         if (plman.PlayingPlaylist == this.playlist) {
  507.                             if (this.track_index == p.list.nowplaying.PlaylistItemIndex) {
  508.                                 if (fb.isPaused) {
  509.                                     gr.DrawString(String.fromCharCode(127).repeat(2), g_font_pauseicon, this.text_colour, icon_x, this.y, icon_w, cTrack.height + cTrack.parity, cc_stringformat);
  510.                                 }; else {
  511.                                     gr.SetTextRenderingHint(4);
  512.                                     if (g_seconds / 2 == Math.floor(g_seconds / 2)) {
  513.                                         gr.DrawString(String.fromCharCode(117), g_font_playicon, this.text_colour, icon_x, this.y, icon_w, cTrack.height + cTrack.parity, cc_stringformat);
  514.                                     }; else {
  515.                                         gr.DrawString(String.fromCharCode(119), g_font_playicon, this.text_colour, icon_x, this.y, icon_w, cTrack.height + cTrack.parity, cc_stringformat);
  516.                                     };
  517.                                 };
  518.                             };
  519.                         };
  520.                     };
  521.                     break;
  522.                 case "Index":
  523.                     try {
  524.                         gr.GdiDrawText(num(this.track_index + 1, p.list.count.toString().length), this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  525.                     }; catch (e) {};
  526.                     break;
  527.                 case "Tracknumber":
  528.                     if (typeof (this.tracknumber) == "undefined") this.tracknumber = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  529.                     try {
  530.                         gr.GdiDrawText(this.tracknumber, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  531.                     }; catch (e) {};
  532.                     break;
  533.                 case "Title":
  534.                     if(typeof(this.title) == "undefined") this.title = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  535.                     var ref_w = gr.CalcTextWidth(this.title, this.font);
  536.                     this.tooltip = (ref_w > cw);
  537.                     try {
  538.                         gr.GdiDrawText(this.title, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  539.                     }; catch (e) {};
  540.                     break;
  541.                 case "Date":
  542.                     if(typeof (this.date) == "undefined") this.date = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  543.                     try {
  544.                         gr.GdiDrawText(this.date, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  545.                     }; catch (e) {};
  546.                     break;
  547.                 case "Playcount":
  548.                     if (typeof (this.playcount) == "undefined") this.playcount = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  549.                     gr.GdiDrawText(this.playcount, this.font, blendColors(this.text_colour, g_color_normal_bg, ((this.playcount==0 || this.playcount=="-") ? 0.35 : 0.0)), cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  550.                     break;
  551.                 case "Bitrate":
  552.                     if(typeof (this.bitrate) == "undefined") this.bitrate = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  553.                     if (fb.IsPlaying) {
  554.                         if (plman.PlayingPlaylist == this.playlist) {
  555.                             if (this.track_index != p.list.nowplaying.PlaylistItemIndex) {
  556.                                 var tmp_bitrate = this.bitrate;
  557.                             }; else {
  558.                                 var tmp_bitrate = this.playing_bitrate;
  559.                             };
  560.                         };
  561.                     }; else {
  562.                         var tmp_bitrate = this.bitrate;
  563.                     };
  564.                     if (typeof (tmp_bitrate) == "undefined") tmp_bitrate = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  565.                     try {
  566.                         gr.GdiDrawText(tmp_bitrate, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  567.                     }; catch (e) {};
  568.                     break;
  569.                 case "Artist":
  570.                     if(typeof (this.artist) == "undefined") this.artist = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  571.                     try {
  572.                         gr.GdiDrawText(this.artist, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  573.                     }; catch (e) {};
  574.                     break;
  575.                 case "Album":
  576.                     if(typeof (this.album) == "undefined") this.album = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  577.                     try {
  578.                         gr.GdiDrawText(this.album, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  579.                     }; catch (e) {};
  580.                     break;
  581.                 case "Genre":
  582.                     if (typeof (this.genre) == "undefined") this.genre = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  583.                     try {
  584.                         gr.GdiDrawText(this.genre, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  585.                     }; catch (e) {};
  586.                     break;
  587.                 case "Mood":
  588.                     if (typeof (this.mood) == "undefined") this.mood = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  589.                     columns.mood = true;
  590.                     // column width
  591.                     if (g_font_guifx_found) {
  592.                         columns.mood_w = gr.CalcTextWidth("v", g_font_mood) + 3;
  593.                     }; else {
  594.                         columns.mood_w = gr.CalcTextWidth(String.fromCharCode(252), g_font_mood) + 3;
  595.                     };
  596.                     // column x
  597.                     switch (p.headerBar.columns[j].align) {
  598.                     case 0:
  599.                         columns.mood_x = cx - 2;
  600.                         break;
  601.                     case 1:
  602.                         columns.mood_x = cx + Math.floor((cw - columns.mood_w) / 2) + 1;
  603.                         break;
  604.                     case 2:
  605.                         columns.mood_x = cx + cw - columns.mood_w + 6;
  606.                         break;
  607.                     };
  608.                     if (this.tracktype < 2) {
  609.                         var m_color = (this.mood != 0 ? (columns.mood_colored ? RGB(255, 120, 160) : this.text_colour) : g_color_normal_txt & 0x16ffffff);
  610.                     }; else {
  611.                         var m_color = g_color_normal_txt & 0x16ffffff;
  612.                     };
  613.                     if (g_font_guifx_found) {
  614.                         gr.SetTextRenderingHint(4);
  615.                         if(this.mood != 0 && columns.mood_colored) {
  616.                             gr.DrawString("v", g_font_mood, RGBA(0,0,0,40), columns.mood_x-1, this.y+1, columns.mood_w, cTrack.height + cTrack.parity-1, lc_stringformat);
  617.                             gr.DrawString("v", g_font_mood, RGBA(0,0,0,60), columns.mood_x+1, this.y+2, columns.mood_w, cTrack.height + cTrack.parity-1, lc_stringformat);
  618.                         };
  619.                         gr.DrawString("v", g_font_mood, m_color, columns.mood_x, this.y+1, columns.mood_w, cTrack.height + cTrack.parity-1, lc_stringformat);
  620.                     }; else {
  621.                         gr.SetTextRenderingHint(4);
  622.                         if(this.mood != 0 && columns.mood_colored) {
  623.                             gr.DrawString(String.fromCharCode(60), g_font_mood, RGBA(0,0,0,60), columns.mood_x+1, this.y+3+1, columns.mood_w, cTrack.height + cTrack.parity-1, lc_stringformat);
  624.                         };
  625.                         gr.DrawString(String.fromCharCode(60), g_font_mood, m_color, columns.mood_x, this.y+3, columns.mood_w, cTrack.height + cTrack.parity-1, lc_stringformat);
  626.                     };
  627.                     break;
  628.                 case "Rating":
  629.                     cw = p.headerBar.columns[j].w - zoom(6, g_dpi);
  630.                     if (typeof (this.rating) == "undefined") this.rating = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  631.                     columns.rating = true;
  632.                     // column width
  633.                     if (g_font_guifx_found) {
  634.                         columns.rating_w = gr.CalcTextWidth("bbbbb", g_font_rating);
  635.                     }; else {
  636.                         columns.rating_w = gr.CalcTextWidth(String.fromCharCode(234).repeat(5), g_font_rating);
  637.                     };
  638.                     var one_star_w = Math.round(columns.rating_w / 5);
  639.                     var total_stars_drawable = Math.floor((cw-2) / one_star_w);
  640.                     if (total_stars_drawable > 5) total_stars_drawable = 5;
  641.                     // column x
  642.                     switch (p.headerBar.columns[j].align) {
  643.                     case 0:
  644.                         columns.rating_x = cx - 2 + 3;
  645.                         break;
  646.                     case 1:
  647.                         columns.rating_x = cx + 3 + Math.round((cw - 6 - one_star_w * total_stars_drawable) / 2) - 1;
  648.                         break;
  649.                     case 2:
  650.                         columns.rating_x = cx + 3 + cw - 6 - one_star_w * total_stars_drawable;
  651.                         break;
  652.                     };
  653.                     var rating_text_colour = this.state > 0 ? g_color_highlight : blendColors(g_color_normal_txt, g_color_normal_bg, 0.5);
  654.                     var r_color = (columns.rating_colored ? RGB(255,255,100) : this.text_colour);
  655.                     if (g_font_guifx_found) {
  656.                         gr.SetTextRenderingHint(3);
  657.                         gr.DrawString(". ".repeat(total_stars_drawable), gdi.Font("lucida console", zoom(12, g_dpi), 2), this.text_colour & 0x40ffffff, columns.rating_x - 3 + 03, this.y - 1 - 02, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  658.                         if(columns.rating_colored) {
  659.                             gr.DrawString("b".repeat(Math.round(this.rating > total_stars_drawable ? total_stars_drawable : this.rating)), g_font_rating, RGBA(0,0,0,40), columns.rating_x - 3-1, this.y - 1, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  660.                             gr.DrawString("b".repeat(Math.round(this.rating > total_stars_drawable ? total_stars_drawable : this.rating)), g_font_rating, RGBA(0,0,0,60), columns.rating_x - 3+1, this.y - 1+1, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  661.                         };
  662.                         gr.DrawString("b".repeat(Math.round(this.rating > total_stars_drawable ? total_stars_drawable : this.rating)), g_font_rating, r_color, columns.rating_x - 3, this.y - 1, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  663.                         if (total_stars_drawable < 5) {
  664.                             var drawn_star_w = gr.CalcTextWidth("b".repeat(total_stars_drawable), g_font_rating) - 1;
  665.                             gr.gdiDrawText("...", this.font, this.text_colour, columns.rating_x - 6 + drawn_star_w, this.y - 1, columns.rating_w + 1, cTrack.height + cTrack.parity, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS);
  666.                         };
  667.                     }; else {
  668.                         gr.SetTextRenderingHint(3);
  669.                         gr.DrawString(String.fromCharCode(234).repeat(total_stars_drawable), g_font_rating, this.text_colour & 0x20ffffff, columns.rating_x - 4, this.y + 2, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  670.                         if(columns.rating_colored) {
  671.                             gr.DrawString(String.fromCharCode(234).repeat(Math.round(this.rating > total_stars_drawable ? total_stars_drawable : this.rating)), g_font_rating, RGBA(0,0,0,60), columns.rating_x - 4+1, this.y + 2+1, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  672.                         };
  673.                         gr.DrawString(String.fromCharCode(234).repeat(Math.round(this.rating > total_stars_drawable ? total_stars_drawable : this.rating)), g_font_rating, r_color, columns.rating_x - 4, this.y + 2, cw + 1, cTrack.height + cTrack.parity, lc_stringformat);
  674.                         if (total_stars_drawable < 5) {
  675.                             var drawn_star_w = gr.CalcTextWidth(String.fromCharCode(234).repeat(total_stars_drawable), g_font_rating);
  676.                             gr.gdiDrawText("...", this.font, this.text_colour, columns.rating_x - 6 + drawn_star_w, this.y, cw + 1, cTrack.height + cTrack.parity, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_END_ELLIPSIS);
  677.                         };
  678.                     };
  679.                     break;
  680.                 case "Duration":
  681.                     if (typeof (this.duration) == "undefined") this.duration = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  682.                     if (fb.IsPlaying) {
  683.                         if (plman.PlayingPlaylist == this.playlist) {
  684.                             if (this.track_index != p.list.nowplaying.PlaylistItemIndex) {
  685.                                 var tmp_duration = this.duration;
  686.                             }; else {
  687.                                 var tmp_duration = this.playing_duration;
  688.                             };
  689.                         };
  690.                     }; else {
  691.                         var tmp_duration = this.duration;
  692.                     };
  693.                     if (typeof (tmp_duration) == "undefined") tmp_duration = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  694.                     try {
  695.                         gr.GdiDrawText(tmp_duration + ' ', this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  696.                     }; catch (e) {};
  697.                     break;
  698.                 default:
  699.                     // Custom columns TF
  700.                     this.user_column = fb.TitleFormat(p.headerBar.columns[j].tf).EvalWithMetadb(this.metadb);
  701.                     gr.GdiDrawText(this.user_column, this.font, this.text_colour, cx, this.y, cw, this.h + cTrack.parity, p.headerBar.columns[j].DT_align | DT_CALCRECT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX);
  702.                     break;
  703.                 };
  704.             }; else {
  705.                 switch (p.headerBar.columns[j].ref) {
  706.                 case "Mood":
  707.                     columns.mood = false;
  708.                     break;
  709.                 case "Rating":
  710.                     columns.rating = false;
  711.                     break;
  712.                 };
  713.             };
  714.         };
  715.     };
  716.  
  717.     this.draw = function (gr, x, y, w, h) {
  718.         this.x = x + 1;
  719.         this.y = y;
  720.         this.w = w - 2;
  721.         this.h = h;
  722.         switch (this.type) {
  723.         case 0:
  724.             // ===============
  725.             // draw track item
  726.             // ===============
  727.             if (cover.column) {
  728.                 cover.w = p.headerBar.columns[0].w;
  729.                 cover.h = cover.w;
  730.             }; else {
  731.                 cover.w = 0;
  732.                 cover.h = 0;
  733.             };
  734.             if (this.empty_row_index == 0) {
  735.                     this.queue_idx = isTrackQueued(this.metadb);
  736.                     if(this.queue_idx > -1) {
  737.                         if(p.list.focusedTrackId == this.track_index) {
  738.                             //gr.FillSolidRect(this.x + cover.w + 2, this.y + 2, this.w - cover.w - 4, this.h - 4, g_color_highlight & 0x20ffffff);
  739.                         }; else {
  740.                             //gr.FillSolidRect(this.x + cover.w, this.y + 1, this.w - cover.w, this.h - 2, g_color_highlight & 0x20ffffff);
  741.                         };
  742.                     };
  743.                     if (fb.IsPlaying && plman.PlayingPlaylist == this.playlist && this.track_index == p.list.nowplaying.PlaylistItemIndex) {
  744.                         this.font = gdi.Font(g_fname, g_fsize, 1);
  745.                         // playing track bg
  746.                         if (plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  747.                             if (p.list.focusedTrackId == this.track_index) {
  748.                                 //**
  749.                                 gr.FillSolidRect(this.x + cover.w + 2, this.y + 2, this.w - cover.w - 4, this.h - 4, g_color_selected_bg & 0x30ffffff);
  750.                                
  751.                                 this.state = 2;
  752.                                 this.text_colour = blendColors(g_color_highlight, g_color_normal_bg, 0.1); //blendColors(g_color_normal_txt, g_color_normal_txt, 0.30);
  753.                                 // frame on focused item
  754.                                 gr.DrawRect(this.x + cover.w + 1, this.y + 2, this.w - cover.w - 2, this.h - 4, 2.0, g_color_normal_txt & 0xaaffffff);
  755.                             }; else {
  756.                                 //**
  757.                                 gr.FillSolidRect(this.x + cover.w, this.y + 1, this.w - cover.w, this.h - 2, g_color_selected_bg & 0x30ffffff);
  758.                                 this.state = 1;
  759.                                 this.text_colour = blendColors(g_color_highlight, g_color_normal_bg, 0.1); //blendColors(g_color_normal_txt, g_color_normal_txt, 0.30);
  760.                             };
  761.                         }; else {
  762.                             // if row is focused, draw focused colors & style ELSE draw with normal colors
  763.                             if (p.list.focusedTrackId == this.track_index) {
  764.                                 this.state = 2;
  765.                                 this.text_colour = blendColors(g_color_highlight, g_color_normal_bg, 0.1); //blendColors(g_color_normal_txt, g_color_normal_txt, 0.30);
  766.                                 // frame on focused item
  767.                                 gr.DrawRect(this.x + cover.w + 1, this.y + 2, this.w - cover.w - 2, this.h - 4, 2.0, g_color_normal_txt & 0xaaffffff);
  768.                             }; else {
  769.                                 // draw stripes of the normal row background
  770.                                 if (properties.oddevenrowshighlight) {
  771.                                     var parity = ((this.track_index_in_group / 2) == Math.floor(this.track_index_in_group / 2) ? 1 : 0);
  772.                                     if (parity == 1) {
  773.                                     }; else {
  774.                                         gr.FillSolidRect(this.x + cover.w, this.y, this.w - cover.w, this.h, g_color_normal_txt & 0x05ffffff);
  775.                                     };
  776.                                 };
  777.                                 this.state = 0;
  778.                                 this.text_colour = blendColors(g_color_highlight, g_color_normal_bg, 0.1); //blendColors(g_color_normal_txt, g_color_normal_txt, 0.30);
  779.                             };
  780.                         };
  781.                     }; else {
  782.                         this.font = g_font;
  783.                         // no playing track bg
  784.                         if (plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  785.                             //**
  786.                             gr.FillSolidRect(this.x + cover.w, this.y + 1, this.w - cover.w, this.h - 2, g_color_selected_bg & 0x30ffffff);
  787.                            
  788.                             if (p.list.focusedTrackId == this.track_index) {
  789.                                 this.state = 2;
  790.                                 this.text_colour = blendColors(g_color_selected_txt, g_color_normal_bg, 0.1);
  791.                                 // frame on focused item
  792.                                 gr.DrawRect(this.x + cover.w + 1, this.y + 2, this.w - cover.w - 2, this.h - 4, 2.0, g_color_normal_txt & 0xaaffffff);
  793.                             }; else {
  794.                                 this.state = 1;
  795.                                 this.text_colour = blendColors(g_color_selected_txt, g_color_normal_bg, 0.1);
  796.                             };
  797.                         }; else {
  798.                             // if row is focused, draw focused colors & style ELSE draw with normal colors
  799.                             if (p.list.focusedTrackId == this.track_index) {
  800.                                 this.state = 2;
  801.                                 this.text_colour = g_color_normal_txt;
  802.                                 // frame on focused item
  803.                                 gr.DrawRect(this.x + cover.w + 1, this.y + 2, this.w - cover.w - 2, this.h - 4, 2.0, g_color_normal_txt & 0xaaffffff);
  804.                             }; else {
  805.                                 // draw stripes of the normal row background
  806.                                 if (properties.oddevenrowshighlight) {
  807.                                     var parity = ((this.track_index_in_group / 2) == Math.floor(this.track_index_in_group / 2) ? 1 : 0);
  808.                                     if (parity == 1) {
  809.                                     }; else {
  810.                                         gr.FillSolidRect(this.x + cover.w, this.y, this.w - cover.w, this.h, g_color_normal_txt & 0x05ffffff);
  811.                                     };
  812.                                 };
  813.                                 this.state = 0;
  814.                                 this.text_colour = g_color_normal_txt;
  815.                                 this.search_colour_bg = RGBA(255, 255, 75, 255);
  816.                                 this.search_colour_bd = RGBA(0, 0, 0, 20);
  817.                             };
  818.                         };
  819.                     };
  820.  
  821.             }; else {
  822.                 /*
  823.                 // draw stripes for the empty rows
  824.                 var parity = ((this.track_index_in_group / 2) == Math.floor(this.track_index_in_group / 2)? 1 : 0);
  825.                 if(parity == 0) {
  826.                     gr.FillSolidRect(this.x + cover.w, this.y, this.w - cover.w, this.h, RGBA(000,000,000,5));
  827.                 }; else {
  828.                     gr.FillSolidRect(this.x + cover.w, this.y, this.w - cover.w, this.h, RGBA(255,255,255,5));
  829.                 };
  830.                 */
  831.                 // if last empty track of the group, draw group length info
  832.                 /*
  833.                 if (cGroup.extra_rows > 0 && this.track_index_in_group == p.list.groups[this.group_index].count) {
  834.                     gr.gdiDrawText("Total Group Length = " + TimeFromSeconds(Math.round(p.list.groups[this.group_index].total_time_length)), gdi.Font("Arial", 10, 0), g_color_normal_txt, this.x, this.y, this.w - 010, this.h, DT_RIGHT | DT_TOP | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  835.                 };
  836.                 */
  837.             };
  838.  
  839.             // now playing track
  840.             if (this.empty_row_index == 0) {
  841.                 if (fb.IsPlaying) {
  842.                     if (plman.PlayingPlaylist == this.playlist) {
  843.                         //this.nowplaying = plman.GetPlayingItemLocation();
  844.                         if (this.track_index == p.list.nowplaying.PlaylistItemIndex) {
  845.                             p.list.nowplaying_y = this.y;
  846.                             this.playing_duration = tf_playback_time_remaining.Eval(true);
  847.                             this.playing_bitrate = tf_bitrate_playing.Eval(true);
  848.                         };
  849.                     };
  850.                 };
  851.             };
  852.  
  853.             // if no group header draw a thin line on the top of the 1st track of the group
  854.             if (!properties.showgroupheaders && this.track_index_in_group == 0) {
  855.                 gr.FillSolidRect(this.x, this.y, this.w, 1, g_color_normal_txt & 0x10ffffff);
  856.             };
  857.  
  858.             // Draw Track content
  859.             // ==================
  860.             if (this.empty_row_index == 0) {
  861.                 this.drawRowContents(gr);
  862.             };
  863.            
  864.             // Draw cover art
  865.             // ==============
  866.             if (cover.column) {
  867.                 if (this.row_index == 0 && this.track_index_in_group > 0 && this.track_index_in_group <= Math.ceil(cover.h / cTrack.height)) {
  868.                     var cover_draw_delta = this.track_index_in_group * cTrack.height;
  869.                 }; else {
  870.                     var cover_draw_delta = 0;
  871.                 };
  872.                 if ((this.track_index_in_group == 0 || (this.row_index == 0 && cover_draw_delta > 0))) {
  873.                     // cover bg
  874.                     var cv_x = this.x + cover.margin;
  875.                     var cv_y = (this.y - cover_draw_delta) + cover.margin;
  876.                     var cv_w = cover.w - cover.margin * 2;
  877.                     var cv_h = cover.h - cover.margin * 2;
  878.  
  879.                     var groupmetadb = p.list.handleList.Item(p.list.groups[this.group_index].start);
  880.                     this.cover_img = g_image_cache.hit(groupmetadb);
  881.                     //
  882.                     if(typeof this.cover_img != "undefined") {
  883.                         if(this.cover_img == null) {
  884.                             this.cover_img = images.nocover;
  885.                         };
  886.                         if(this.cover_img) {
  887.                             if (cover.keepaspectratio) {
  888.                                 // *** check aspect ratio *** //
  889.                                 if (this.cover_img.Height >= this.cover_img.Width) {
  890.                                     var ratio = this.cover_img.Width / this.cover_img.Height;
  891.                                     var pw = cv_w * ratio;
  892.                                     var ph = cv_h;
  893.                                     this.left = Math.floor((ph - pw) / 2);
  894.                                     this.top = 0;
  895.                                     cv_x += this.left;
  896.                                     cv_y += this.top;
  897.                                     cv_w = cv_w - this.left * 2 - 1;
  898.                                     cv_h = cv_h - this.top * 2 - 1;
  899.                                 }; else {
  900.                                     var ratio = this.cover_img.Height / this.cover_img.Width;
  901.                                     var pw = cv_w;
  902.                                     var ph = cv_h * ratio;
  903.                                     this.top = Math.floor((pw - ph) / 2);
  904.                                     this.left = 0;
  905.                                     cv_x += this.left;
  906.                                     cv_y += this.top;
  907.                                     cv_w = cv_w - this.left * 2 - 1;
  908.                                     cv_h = cv_h - this.top * 2 - 1;
  909.                                 };
  910.                                 // *** check aspect ratio *** //
  911.                             };
  912.  
  913.                             if (cover.keepaspectratio) {
  914.                                 gr.DrawRect(cv_x + 1, cv_y + 1, cv_w - 1, cv_h - 1, 4.0, RGBA(0, 0, 10, 50));
  915.                                 gr.DrawImage(this.cover_img, cv_x, cv_y, cv_w, cv_h, 0, 0, this.cover_img.Width, this.cover_img.Height);
  916.                                 gr.DrawRect(cv_x, cv_y, cv_w, cv_h, 2.0, RGB(255, 255, 255));
  917.                             }; else {
  918.                                 gr.DrawRect(cv_x + 1, cv_y + 1, cv_w - 1, cv_h - 1, 4.0, RGBA(0, 0, 10, 50));
  919.                                 gr.DrawImage(this.cover_img, cv_x, cv_y, cv_w, cv_h, 0, 0, this.cover_img.Width, this.cover_img.Height);
  920.                                 gr.DrawRect(cv_x, cv_y, cv_w - 1, cv_h - 1, 2.0, RGB(255, 255, 255));
  921.                             };
  922.                         };
  923.                     }; else {
  924.                         gr.DrawImage(images.loading, cv_x-2, cv_y-2, cv_w, cv_h, 0, 0, images.loading.Width, images.loading.Height, images.loading_angle, 225);
  925.                     };
  926.                 };
  927.             };
  928.  
  929.             // if dragging items, draw line at top of the hover items to show where dragged items will be inserted on mouse button up
  930.             if(!cPlaylistManager.hscroll_timer && mouse_x < (p.playlistManager.x - p.playlistManager.woffset) - 30) {
  931.                 if (this.empty_row_index == 0) {
  932.                     if (dragndrop.drag_in && this.ishover && p.list.ishover) {
  933.                         if(p.playlistManager.woffset == 0 || cPlaylistManager.visible) {
  934.                             if (!plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  935.                                 if (this.track_index > dragndrop.drag_id) {
  936.                                     gr.FillSolidRect(this.x + cover.w, this.y + this.h - Math.floor(cList.borderWidth / 2), this.w - cover.w, cList.borderWidth, g_color_selected_bg);
  937.                                     gr.FillSolidRect(this.x + cover.w, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  938.                                     gr.FillSolidRect(this.x + this.w - cList.borderWidth, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  939.                                     dragndrop.drop_id = this.track_index;
  940.                                 }; else if (this.track_index < dragndrop.drag_id) {
  941.                                     gr.FillSolidRect(this.x + cover.w, this.y - Math.floor(cList.borderWidth / 2), this.w - cover.w, cList.borderWidth, g_color_selected_bg);
  942.                                     gr.FillSolidRect(this.x + cover.w, this.y - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  943.                                     gr.FillSolidRect(this.x + this.w - cList.borderWidth, this.y - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  944.                                     dragndrop.drop_id = this.track_index;
  945.                                 };
  946.                             };
  947.                         };
  948.                     };
  949.                 };
  950.             };
  951.             break;
  952.         case 1:
  953.             // ===============
  954.             // draw group item
  955.             // ===============
  956.             if (!cover.column || (cover.column && this.obj.collapsed)) {
  957.                 if (this.heightInRow > 1 && cover.show) {
  958.                     cover.h = this.heightInRow * cTrack.height;
  959.                     cover.w = cover.h;
  960.                 }; else {
  961.                     cover.h = zoom(5, g_dpi);
  962.                     cover.w = cover.h;
  963.                 };
  964.             }; else {
  965.                 cover.h = zoom(4, g_dpi);
  966.                 cover.w = cover.h;
  967.             };
  968.             var groupDelta = this.groupRowDelta * cTrack.height;
  969.            
  970.             // group header bg
  971.             //gr.FillGradRect(this.x, (this.y - groupDelta) + 1, this.w, this.h - 2, 88, RGBA(0,0,5,8), RGBA(255,255,255,10), 1.0);
  972.             gr.FillSolidRect(this.x, (this.y - groupDelta) + 0, this.w, 1, g_color_normal_txt & 0x10ffffff);
  973.             gr.FillSolidRect(this.x, (this.y - groupDelta) + 1, this.w, this.h - 2, g_color_normal_txt & 0x04ffffff);
  974.             //gr.FillGradRect(this.x, (this.y - groupDelta) + 1, this.w, cTrack.height, 88, g_color_normal_txt & 0x05ffffff, 0, 1.0);
  975.            
  976.             // draw group text infos
  977.             var text_left_padding = zoom(2, g_dpi);
  978.             var scrollbar_gape = (p.scrollbar.visible && (p.list.totalRows > p.list.totalRowVisible)) ? 0 : cScrollBar.width;
  979.            
  980.             var color_txt = g_color_selected_bg;
  981.             if(fb.IsPlaying) {
  982.                 if (plman.PlayingPlaylist == this.playlist) {
  983.                     if (p.list.nowplaying.PlaylistItemIndex >= this.obj.start && p.list.nowplaying.PlaylistItemIndex < this.obj.start + this.obj.count) {
  984.                         color_txt = g_color_highlight;
  985.                     };
  986.                 };
  987.             };
  988.            
  989.             // Draw Header content
  990.             // ===================
  991.             switch (this.heightInRow) {
  992.             case 1:
  993.                 var lg1_right_field_w = gr.CalcTextWidth(this.r1, g_font_group1_bold) + cList.borderWidth*2;
  994.                 gr.gdiDrawText(this.l1 + " / " + this.l2, g_font_group1, blendColors(g_color_normal_txt, color_txt, 0.80), this.x + cover.w + text_left_padding, (this.y - groupDelta)-1, this.w - cover.w - text_left_padding*4 - lg1_right_field_w - scrollbar_gape, this.h, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  995.                 gr.gdiDrawText(this.r1, g_font_group1_bold, blendColors(g_color_normal_txt, color_txt, 0.80), this.x + cover.w + text_left_padding, (this.y - groupDelta)-1, this.w - cover.w - text_left_padding*5 + 02 - scrollbar_gape, this.h, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
  996.                 gr.FillSolidRect(this.x + cover.w + text_left_padding, Math.round(this.y + cTrack.height * 1 - groupDelta - 5), this.w - cover.w - text_left_padding*5 + 02, 1.0, blendColors(g_color_normal_txt, g_color_normal_bg, 0.60));                
  997.                 break;
  998.             case 2:
  999.                 var lg1_right_field_w = gr.CalcTextWidth(this.r1, g_font_group1_bold) + cList.borderWidth*2;
  1000.                 var lg2_right_field_w = gr.CalcTextWidth(this.r2, g_font_group2) + cList.borderWidth*2;
  1001.                 gr.gdiDrawText(this.l1, g_font_group1_bold, blendColors(g_color_normal_txt, color_txt, 0.90), this.x + cover.w + text_left_padding, (this.y - groupDelta) + 3, this.w - cover.w - text_left_padding*4 - lg1_right_field_w - scrollbar_gape, cTrack.height, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1002.                 gr.gdiDrawText(this.l2, g_font_group2, blendColors(g_color_normal_txt, color_txt, 0.70), this.x + cover.w + text_left_padding, (this.y + cTrack.height - groupDelta) - 6, this.w - cover.w - text_left_padding*4 - lg2_right_field_w - scrollbar_gape, cTrack.height, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1003.                 gr.gdiDrawText(this.r1, g_font_group1_bold, blendColors(g_color_normal_txt, color_txt, 0.90), this.x + cover.w + text_left_padding, (this.y - groupDelta) + 3, this.w - cover.w - text_left_padding*5 + 02 - scrollbar_gape, cTrack.height, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1004.                 gr.gdiDrawText(this.r2, g_font_group2, blendColors(g_color_normal_txt, color_txt, 0.70), this.x + cover.w + text_left_padding, (this.y + cTrack.height - groupDelta) - 6, this.w - cover.w - text_left_padding*5 + 01 - scrollbar_gape, cTrack.height, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1005.                 gr.FillSolidRect(this.x + cover.w + text_left_padding, (this.y + cTrack.height * 2 - groupDelta) - 8, this.w - cover.w - text_left_padding*5 + 02, 1.0, blendColors(g_color_normal_txt, g_color_normal_bg, 0.60));                
  1006.                 break;
  1007.             default:
  1008.                 var lg1_right_field_w = gr.CalcTextWidth(this.r1, g_font_group1_bold) + cList.borderWidth*2;
  1009.                 var lg2_right_field_w = gr.CalcTextWidth(this.r2, g_font_group2) + cList.borderWidth*2;
  1010.                 gr.gdiDrawText(this.l1, g_font_group1_bold, blendColors(g_color_normal_txt, color_txt, 0.90), this.x + cover.w + text_left_padding, (this.y - groupDelta) + 3, this.w - cover.w - text_left_padding*4 - lg1_right_field_w - scrollbar_gape, cTrack.height, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1011.                 gr.gdiDrawText(this.l2, g_font_group2, blendColors(g_color_normal_txt, color_txt, 0.70), this.x + cover.w + text_left_padding, (this.y + cTrack.height - groupDelta) - 4, this.w - cover.w - text_left_padding*4 - lg2_right_field_w - scrollbar_gape, cTrack.height, DT_LEFT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1012.                 gr.gdiDrawText(this.r1, g_font_group1_bold, blendColors(g_color_normal_txt, color_txt, 0.90), this.x + cover.w + text_left_padding, (this.y - groupDelta) + 3, this.w - cover.w - text_left_padding*5 + 02 - scrollbar_gape, cTrack.height, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1013.                 gr.gdiDrawText(this.r2, g_font_group2, blendColors(g_color_normal_txt, color_txt, 0.70), this.x + cover.w + text_left_padding, (this.y + cTrack.height - groupDelta) - 4, this.w - cover.w - text_left_padding*5 + 01 - scrollbar_gape, cTrack.height, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1014.                 // lg 3 (not customizable)
  1015.                 gr.FillSolidRect(this.x + cover.w + text_left_padding, (this.y + cTrack.height * 2 - groupDelta) - 1, this.w - cover.w - text_left_padding*5 + 02, 1.0, blendColors(g_color_normal_txt, g_color_normal_bg, 0.50));
  1016.                 var lg3_left_field = this.obj.count + (this.obj.count > 1 ? " tracks, " : " track, ") + this.obj.total_group_duration_txt;
  1017.                 var lg3_right_field = (this.group_index+1) + " / " + p.list.groups.length;
  1018.                 var lg3_right_field_w = gr.CalcTextWidth(lg3_right_field, g_font) + cList.borderWidth*2;
  1019.                 gr.gdiDrawText(lg3_left_field, g_font, blendColors(g_color_normal_txt, g_color_normal_bg, 0.40), this.x + cover.w + text_left_padding, (this.y + cTrack.height * 2 - groupDelta) - 2, this.w - cover.w - text_left_padding*4 - lg3_right_field_w - scrollbar_gape, cTrack.height, DT_LEFT | DT_TOP | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1020.                 gr.gdiDrawText(lg3_right_field, g_font, blendColors(g_color_normal_txt, g_color_normal_bg, 0.40), this.x + cover.w + text_left_padding, (this.y + cTrack.height * 2 - groupDelta) - 2, this.w - cover.w - text_left_padding*5 + 01 - scrollbar_gape, cTrack.height, DT_RIGHT | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS);
  1021.             };
  1022.  
  1023.             // highlight group that contains a selected track
  1024.             var now_playing_found = false;
  1025.             for(var k = 0; k < this.obj.count; k++) {
  1026.                 if (plman.IsPlaylistItemSelected(p.list.playlist, this.obj.start + k) && this.obj.collapsed) {
  1027.                     gr.FillSolidRect(this.x, (this.y - groupDelta) + 1, this.w, this.h - 2, g_color_selected_bg & 0x20ffffff);
  1028.                     break;
  1029.                 }; else {
  1030.                     // highlight the now playing group header
  1031.                     if(fb.IsPlaying) {
  1032.                         if(plman.PlayingPlaylist == this.playlist) {
  1033.                             if(!now_playing_found && p.list.nowplaying.PlaylistItemIndex >= this.obj.start && p.list.nowplaying.PlaylistItemIndex < this.obj.start + this.obj.count && this.obj.collapsed) {
  1034.                                 gr.FillSolidRect(this.x, (this.y - groupDelta) + 1, this.w, this.h - 2, g_color_highlight & 0x16ffffff);
  1035.                                 now_playing_found = true;
  1036.                             };
  1037.                         };
  1038.                     };
  1039.                 };
  1040.             };
  1041.  
  1042.  
  1043.             // Draw cover art
  1044.             // ==============
  1045.             if(!cover.column || (cover.column && this.obj.collapsed)) {
  1046.                 if(this.heightInRow > 1 && cover.show) {
  1047.                     // cover bg
  1048.                     var cv_x = this.x + cover.margin + 1;
  1049.                     var cv_y = (this.y - groupDelta) + cover.margin;
  1050.                     var cv_w = cover.w - cover.margin * 2;
  1051.                     var cv_h = cover.h - cover.margin * 2;
  1052.                     //
  1053.                     this.cover_img = g_image_cache.hit(this.metadb);
  1054.                     //
  1055.                     if(typeof this.cover_img != "undefined") {
  1056.                         if(this.cover_img == null) {
  1057.                             this.cover_img = images.nocover;
  1058.                         };
  1059.                         if(this.cover_img) {
  1060.                             if (cover.keepaspectratio) {
  1061.                                 // *** check aspect ratio *** //
  1062.                                 if (this.cover_img.Height >= this.cover_img.Width) {
  1063.                                     var ratio = this.cover_img.Width / this.cover_img.Height;
  1064.                                     var pw = cv_w * ratio;
  1065.                                     var ph = cv_h;
  1066.                                     this.left = Math.floor((ph - pw) / 2);
  1067.                                     this.top = 0;
  1068.                                     cv_x += this.left;
  1069.                                     cv_y += this.top;
  1070.                                     cv_w = cv_w - this.left * 2 - 1;
  1071.                                     cv_h = cv_h - this.top * 2 - 1;
  1072.                                 }; else {
  1073.                                     var ratio = this.cover_img.Height / this.cover_img.Width;
  1074.                                     var pw = cv_w;
  1075.                                     var ph = cv_h * ratio;
  1076.                                     this.top = Math.floor((pw - ph) / 2);
  1077.                                     this.left = 0;
  1078.                                     cv_x += this.left;
  1079.                                     cv_y += this.top;
  1080.                                     cv_w = cv_w - this.left * 2 - 1;
  1081.                                     cv_h = cv_h - this.top * 2 - 1;
  1082.                                 };
  1083.                                 // *** check aspect ratio *** //
  1084.                             };
  1085.  
  1086.                             if(cover.keepaspectratio) {
  1087.                                 gr.DrawRect(cv_x + 1, cv_y + 1, cv_w - 1, cv_h - 1, 4.0, RGBA(0, 0, 10, 50));
  1088.                                 gr.DrawImage(this.cover_img, cv_x, cv_y, cv_w, cv_h, 0, 0, this.cover_img.Width, this.cover_img.Height);
  1089.                                 gr.DrawRect(cv_x, cv_y, cv_w, cv_h, 2.0, RGB(255, 255, 255));
  1090.                             }; else {
  1091.                                 gr.DrawRect(cv_x + 1, cv_y + 1, cv_w - 1, cv_h - 1, 4.0, RGBA(0, 0, 10, 50));
  1092.                                 gr.DrawImage(this.cover_img, cv_x, cv_y, cv_w, cv_h, 0, 0, this.cover_img.Width, this.cover_img.Height);
  1093.                                 gr.DrawRect(cv_x, cv_y, cv_w - 1, cv_h - 1, 2.0, RGB(255, 255, 255));
  1094.                             };
  1095.                         };
  1096.                     }; else {
  1097.                         gr.DrawImage(images.loading, cv_x-2, cv_y-2, cv_w, cv_h, 0, 0, images.loading.Width, images.loading.Height, images.loading_angle, 225);
  1098.                     };
  1099.                 };
  1100.             };
  1101.  
  1102.             // if dragging items, draw line at top of the hover items to show where dragged items will be inserted on mouse button up
  1103.             if(!cPlaylistManager.hscroll_timer && mouse_x < (p.playlistManager.x - p.playlistManager.woffset) - 30) {
  1104.                 if (dragndrop.drag_in && this.ishover && p.list.ishover) {
  1105.                     if(p.playlistManager.woffset == 0 || cPlaylistManager.visible) {
  1106.                         if(!plman.IsPlaylistItemSelected(plman.ActivePlaylist, this.track_index)) {
  1107.                             var cover_w = (p.headerBar.columns[0].percent > 0 ? p.headerBar.columns[0].w : 0);
  1108.                             if(this.track_index <= dragndrop.drag_id) {
  1109.                                 if(this.groupRowDelta==0) {
  1110.                                     gr.FillSolidRect(this.x + cover_w, this.y - Math.floor(cList.borderWidth / 2), this.w - cover_w, cList.borderWidth, g_color_selected_bg);
  1111.                                     gr.FillSolidRect(this.x + cover_w, this.y - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1112.                                     gr.FillSolidRect(this.x + this.w - cList.borderWidth, this.y - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1113.                                 }
  1114.                                 if(this.obj.collapsed) {
  1115.                                     dragndrop.drop_id = this.track_index;
  1116.                                 }; else {
  1117.                                     dragndrop.drop_id = this.track_index;
  1118.                                 };
  1119.                             }; else {
  1120.                                 if(this.obj.collapsed) {
  1121.                                     gr.FillSolidRect(this.x + cover_w, this.y + this.h - Math.floor(cList.borderWidth / 2), this.w - cover_w, cList.borderWidth, g_color_selected_bg);
  1122.                                     gr.FillSolidRect(this.x + cover_w, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1123.                                     gr.FillSolidRect(this.x + this.w - cList.borderWidth, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1124.                                     dragndrop.drop_id = this.track_index + this.obj.count - 1;
  1125.                                 }; else {
  1126.                                     gr.FillSolidRect(this.x + cover_w, this.y + this.h - Math.floor(cList.borderWidth / 2), this.w - cover_w, cList.borderWidth, g_color_selected_bg);
  1127.                                     gr.FillSolidRect(this.x + cover_w, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1128.                                     gr.FillSolidRect(this.x + this.w - cList.borderWidth, this.y + this.h - Math.floor(cList.borderWidth / 2) - 4*cList.borderWidth, cList.borderWidth, 9*cList.borderWidth, g_color_selected_bg);
  1129.                                     dragndrop.drop_id = this.track_index - 1;
  1130.                                 };
  1131.                             };
  1132.                         };
  1133.                     };
  1134.                 };
  1135.             };
  1136.             break;
  1137.         };
  1138.     };
  1139.  
  1140.     this.check = function (event, x, y) {
  1141.         var groupDelta = this.groupRowDelta * cTrack.height;
  1142.         var col_cover_w = (p.headerBar.columns[0].percent > 0 ? p.headerBar.columns[0].w : 0);
  1143.         this.ishover = (x >= this.x + col_cover_w && x < this.x + this.w && y >= this.y && y < this.y + this.h - groupDelta);
  1144.  
  1145.         var prev_rating_hover = this.rating_hover;
  1146.         var prev_l_rating = this.l_rating;
  1147.         var prev_mood_hover = this.mood_hover;
  1148.         var prev_l_mood = this.l_mood;
  1149.         this.rating_hover = (this.type == 0 && this.empty_row_index == 0 && x >= columns.rating_x && x <= columns.rating_x + columns.rating_w && y > this.y + 2 && y < this.y + this.h - 2);
  1150.         this.mood_hover = (this.type == 0 && this.empty_row_index == 0 && x >= columns.mood_x && x <= columns.mood_x + columns.mood_w - 3 && y > this.y + 2 && y < this.y + this.h - 2);
  1151.  
  1152.         switch (event) {
  1153.         case "down":
  1154.             if(this.ishover) {
  1155.                 if (this.type == 1) { // group header
  1156.                     if(utils.IsKeyPressed(VK_SHIFT)) {
  1157.                         if (p.list.focusedTrackId != this.track_index) {
  1158.                             if (p.list.SHIFT_start_id != null) {
  1159.                                 p.list.selectAtoB(p.list.SHIFT_start_id, this.track_index + this.obj.count - 1);
  1160.                             }; else {
  1161.                                 p.list.selectAtoB(p.list.focusedTrackId, this.track_index + this.obj.count - 1);
  1162.                             };
  1163.                         };
  1164.                     }; else if (utils.IsKeyPressed(VK_CONTROL)) {
  1165.                         plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1166.                         p.list.selectGroupTracks(this.group_index, true);
  1167.                         p.list.SHIFT_start_id = null;
  1168.                     }; else {
  1169.                         plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1170.                         plman.ClearPlaylistSelection(p.list.playlist);
  1171.                         if ((properties.autocollapse && !this.obj.collapsed) || !properties.autocollapse) {
  1172.                             p.list.selectGroupTracks(this.group_index, true);
  1173.                         };
  1174.                         p.list.SHIFT_start_id = null;
  1175.                         if(p.list.metadblist_selection.Count >= 1) {
  1176.                             dragndrop.clicked = true;
  1177.                             dragndrop.moved = false;
  1178.                             dragndrop.x = x;
  1179.                             dragndrop.y = y;
  1180.                             dragndrop.drag_id = this.track_index;
  1181.                             if (!isQueuePlaylistActive()) {
  1182.                                 dragndrop.timerID = window.SetTimeout(function () {
  1183.                                     dragndrop.drag_in = true;
  1184.                                     dragndrop.timerID && window.ClearTimeout(dragndrop.timerID);
  1185.                                     dragndrop.timerID = false;
  1186.                                 }, 250);
  1187.                             };
  1188.                         };
  1189.                     };
  1190.                     if(properties.autocollapse) {
  1191.                         if (this.obj.collapsed) {
  1192.                             p.list.updateGroupStatus(this.group_index);
  1193.                         };
  1194.                     };
  1195.                     p.list.metadblist_selection = plman.GetPlaylistSelectedItems(p.list.playlist);
  1196.                 }; else { // track
  1197.                     if(this.rating_hover) {
  1198.                         columns.rating_drag = true;
  1199.                     }; else if (this.mood_hover) {
  1200.                         columns.mood_drag = true;
  1201.                     }; else {
  1202.                         if(plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  1203.                             if (p.list.metadblist_selection.Count >= 1) {
  1204.                                 dragndrop.clicked = true;
  1205.                                 dragndrop.moved = false;
  1206.                                 dragndrop.x = x;
  1207.                                 dragndrop.y = y;
  1208.                                 if (p.list.metadblist_selection.Count > 1) {
  1209.                                     // test if selection is contigus, if not, drag'n drop disable
  1210.                                     var first_item_selected_id = p.list.handleList.Find(p.list.metadblist_selection.item(0));
  1211.                                     var last_item_selected_id = p.list.handleList.Find(p.list.metadblist_selection.item(p.list.metadblist_selection.Count - 1));
  1212.                                     var contigus_count = (last_item_selected_id - first_item_selected_id) + 1;
  1213.                                 }; else {
  1214.                                     var contigus_count = 0;
  1215.                                 };
  1216.                                 if(p.list.metadblist_selection.Count == 1 || (p.list.metadblist_selection.Count > 1 && p.list.metadblist_selection.Count == contigus_count)) {
  1217.                                     dragndrop.contigus_sel = true;
  1218.                                     dragndrop.drag_id = this.track_index;
  1219.                                     if (!isQueuePlaylistActive()) {
  1220.                                         dragndrop.timerID = window.SetTimeout(function () {
  1221.                                             dragndrop.drag_in = true;
  1222.                                             dragndrop.timerID && window.ClearTimeout(dragndrop.timerID);
  1223.                                             dragndrop.timerID = false;
  1224.                                         }, 250);
  1225.                                     };
  1226.                                 }; else if(p.list.metadblist_selection.Count > 1) {
  1227.                                     dragndrop.contigus_sel = false;
  1228.                                     dragndrop.drag_id = this.track_index;
  1229.                                     if (!isQueuePlaylistActive()) {
  1230.                                         dragndrop.timerID = window.SetTimeout(function () {
  1231.                                             dragndrop.drag_in = true;
  1232.                                             dragndrop.timerID && window.ClearTimeout(dragndrop.timerID);
  1233.                                             dragndrop.timerID = false;
  1234.                                         }, 250);
  1235.                                     };
  1236.                                 };
  1237.                             };
  1238.                             if(utils.IsKeyPressed(VK_SHIFT)) {
  1239.                                 if(p.list.focusedTrackId != this.track_index) {
  1240.                                     if (p.list.SHIFT_start_id != null) {
  1241.                                         p.list.selectAtoB(p.list.SHIFT_start_id, this.track_index);
  1242.                                     }; else {
  1243.                                         p.list.selectAtoB(p.list.focusedTrackId, this.track_index);
  1244.                                     };
  1245.                                 };
  1246.                             }; else if(utils.IsKeyPressed(VK_CONTROL)) {
  1247.                                 plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, false);
  1248.                                 //};
  1249.                             }; else if(p.list.metadblist_selection.Count == 1) {
  1250.                                 plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1251.                                 plman.ClearPlaylistSelection(p.list.playlist);
  1252.                                 plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, true);
  1253.                             };
  1254.                         }; else { // click on a not selected track
  1255.                             if(utils.IsKeyPressed(VK_SHIFT)) {
  1256.                                 if(p.list.focusedTrackId != this.track_index) {
  1257.                                     if (p.list.SHIFT_start_id != null) {
  1258.                                         p.list.selectAtoB(p.list.SHIFT_start_id, this.track_index);
  1259.                                     }; else {
  1260.                                         p.list.selectAtoB(p.list.focusedTrackId, this.track_index);
  1261.                                     };
  1262.                                 };
  1263.                             }; else if(utils.IsKeyPressed(VK_CONTROL)) {
  1264.                                 p.list.selX = x;
  1265.                                 p.list.selY = y;
  1266.                                 p.list.drawRectSel = true;
  1267.                                 p.list.selStartId = this.track_index;
  1268.                                 p.list.selStartOffset = p.list.offset;
  1269.                                 p.list.selEndOffset = p.list.offset;
  1270.                                 p.list.selDeltaRows = 0;
  1271.                                 p.list.selAffected.splice(0, p.list.selAffected.length);
  1272.                                 plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1273.                                 plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, true);
  1274.                                 p.list.SHIFT_start_id = null;
  1275.                             }; else {
  1276.                                 p.list.selX = x;
  1277.                                 p.list.selY = y;
  1278.                                 p.list.drawRectSel = true;
  1279.                                 p.list.selStartId = this.track_index;
  1280.                                 p.list.selStartOffset = p.list.offset;
  1281.                                 p.list.selEndOffset = p.list.offset;
  1282.                                 p.list.selDeltaRows = 0;
  1283.                                 p.list.selAffected.splice(0, p.list.selAffected.length);
  1284.                                
  1285.                                 plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1286.                                 plman.ClearPlaylistSelection(p.list.playlist);
  1287.                                 plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, true);
  1288.                                
  1289.                                 p.list.SHIFT_start_id = null;
  1290.                             };
  1291.                         };
  1292.                         p.list.metadblist_selection = plman.GetPlaylistSelectedItems(p.list.playlist);
  1293.                     };
  1294.                 };
  1295.             };
  1296.             break;
  1297.         case "dblclk":
  1298.             if (this.ishover) {
  1299.                 if (this.type == 1) { // group header
  1300.                     if (properties.autocollapse) {
  1301.                         /*
  1302.                         if(this.obj.collapsed) {
  1303.                             p.list.updateGroupStatus(this.group_index);
  1304.                         }; else {
  1305.                             p.list.updateGroupsOnCollapse(this.group_index);
  1306.                         };
  1307.                         */
  1308.                     }; else {
  1309.                         if (this.obj.collapsed) {
  1310.                             p.list.updateGroupsOnExpand(this.group_index);
  1311.                         }; else {
  1312.                             p.list.updateGroupsOnCollapse(this.group_index);
  1313.                         };
  1314.                     };
  1315.                     p.list.setItems(false);
  1316.                     full_repaint();
  1317.                 }; else { // track
  1318.                     var cmd = properties.defaultPlaylistItemAction;
  1319.                     if(cmd == "Play") {
  1320.                         plman.ExecutePlaylistDefaultAction(p.list.playlist, this.track_index);
  1321.                     }; else {
  1322.                         fb.RunContextCommandWithMetadb(cmd, this.metadb, 0);
  1323.                     };
  1324.                 };
  1325.             };
  1326.             break;
  1327.         case "up":
  1328.             if (this.ishover) {
  1329.                 if (this.rating_hover) {
  1330.                     // Rating
  1331.                     if (this.tracktype < 2) {
  1332.                         if (foo_playcount) {
  1333.                             // Rate to database statistics brought by foo_playcount.dll
  1334.                             if (this.l_rating != this.rating) {
  1335.                                 if (this.metadb) {
  1336.                                     var bool = fb.RunContextCommandWithMetadb("Rating/" + ((this.l_rating == 0) ? "<not set>" : this.l_rating), this.metadb);
  1337.                                     this.rating = this.l_rating;
  1338.                                 };
  1339.                             }; else {
  1340.                                 var bool = fb.RunContextCommandWithMetadb("Rating/<not set>", this.metadb);
  1341.                                 this.rating = 0;
  1342.                             };
  1343.                         }; else {
  1344.                             // Rate to file
  1345.                             if (this.l_rating != this.rating) {
  1346.                                 if (this.metadb) {
  1347.                                     var bool = this.metadb.UpdateFileInfoSimple("RATING", this.l_rating);
  1348.                                     this.rating = this.l_rating;
  1349.                                 };
  1350.                             }; else {
  1351.                                 var bool = this.metadb.UpdateFileInfoSimple("RATING", "");
  1352.                                 this.rating = 0;
  1353.                             };
  1354.                         };
  1355.                     };
  1356.                 }; else if (this.mood_hover) {
  1357.                     // Mood
  1358.                     if (this.tracktype < 2) {
  1359.                         // tag to file
  1360.                         if (this.l_mood != this.mood) {
  1361.                             if (this.metadb) {
  1362.                                 var bool = this.metadb.UpdateFileInfoSimple("MOOD", getTimestamp());
  1363.                                 this.mood = this.l_mood;
  1364.                             };
  1365.                         }; else {
  1366.                             var bool = this.metadb.UpdateFileInfoSimple("MOOD", "");
  1367.                             this.mood = 0;
  1368.                         };
  1369.                     };
  1370.                 }; else {
  1371.                     if (!p.list.drawRectSel && plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  1372.                         if (!utils.IsKeyPressed(VK_SHIFT) && !utils.IsKeyPressed(VK_CONTROL)) {
  1373.                             if (!dragndrop.drag_in) {
  1374.                                 if (this.type == 0) { // track
  1375.                                     plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1376.                                     plman.ClearPlaylistSelection(p.list.playlist);
  1377.                                     plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, true);
  1378.                                 };
  1379.                             };
  1380.                         };
  1381.                     };
  1382.                 };
  1383.             };
  1384.             dragndrop.clicked = false;
  1385.             dragndrop.moved = false;
  1386.             columns.rating_drag = false;
  1387.             columns.mood_drag = false;
  1388.             break;
  1389.         case "right":
  1390.             if (this.ishover) {
  1391.                 if (this.type == 1) { // group header
  1392.                     if (!plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  1393.                         plman.ClearPlaylistSelection(p.list.playlist);
  1394.                         plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1395.                         p.list.selectGroupTracks(this.group_index, true);
  1396.                         p.list.SHIFT_start_id = null;
  1397.                     };
  1398.                     p.list.context_menu(x, y, this.track_index, this.row_index);
  1399.                 }; else { // track
  1400.                     if (this.rating_hover) {
  1401.  
  1402.                     }; else if (this.mood_hover) {
  1403.  
  1404.                     }; else {
  1405.                         if (plman.IsPlaylistItemSelected(p.list.playlist, this.track_index)) {
  1406.  
  1407.                         }; else {
  1408.                             plman.SetPlaylistFocusItem(p.list.playlist, this.track_index);
  1409.                             plman.ClearPlaylistSelection(p.list.playlist);
  1410.                             plman.SetPlaylistSelectionSingle(p.list.playlist, this.track_index, true);
  1411.                         };
  1412.                         p.list.context_menu(x, y, this.track_index, this.row_index);
  1413.                     };
  1414.                 };
  1415.             };
  1416.             break;
  1417.         case "move":
  1418.             if(columns.rating && !columns.rating_drag) {
  1419.                 if(this.rating_hover) {
  1420.                     var one_star_w = Math.round(columns.rating_w / 5);
  1421.                     this.l_rating = Math.floor((x - columns.rating_x) / one_star_w) + 1;
  1422.                     if(this.l_rating>5) this.l_rating = 5;
  1423.                 }; else {
  1424.                     this.l_rating = 0;
  1425.                 };
  1426.             };
  1427.             if(columns.mood && !columns.mood_drag) {
  1428.                 if(this.mood_hover) {
  1429.                     this.l_mood = 1;
  1430.                 }; else {
  1431.                     this.l_mood = 0;
  1432.                 };
  1433.             };
  1434.             // update tooltip text
  1435.             if(this.tooltip && this.ishover) {
  1436.                 g_tooltip_txt = this.title;
  1437.             };
  1438.            
  1439.             // update on mouse move to draw rect selection zone
  1440.             if(p.list.drawRectSel) {       
  1441.                 if(this.ishover) {
  1442.                     if(this.type == 0) { // track
  1443.                         p.list.selEndId = this.track_index;
  1444.                     }; else { // group header
  1445.                         if(this.track_index > 0) {
  1446.                             if(y > p.list.selY) {
  1447.                                 if(p.list.selStartId <= p.list.selEndId) {
  1448.                                     if(this.track_index == this.track_index + 1) {
  1449.                                         p.list.selEndId = this.track_index - 0;
  1450.                                     }; else {
  1451.                                         p.list.selEndId = this.track_index - 1;
  1452.                                     };
  1453.                                 }; else {
  1454.                                     if(this.track_index == this.track_index + 1) {
  1455.                                         p.list.selEndId = this.track_index - 1;
  1456.                                     }; else {
  1457.                                         p.list.selEndId = this.track_index - 0;
  1458.                                     };
  1459.                                 };
  1460.                             }; else {
  1461.                                 if(p.list.selStartId < p.list.selEndId) {
  1462.                                     if(this.track_index == this.track_index + 1) {
  1463.                                         p.list.selEndId = this.track_index - 0;
  1464.                                     }; else {
  1465.                                         p.list.selEndId = this.track_index - 1;
  1466.                                     };
  1467.                                 }; else {
  1468.                                     if(this.track_index == this.track_index + 1) {
  1469.                                         p.list.selEndId = this.track_index - 1;
  1470.                                     }; else {
  1471.                                         p.list.selEndId = this.track_index - 0;
  1472.                                     };
  1473.                                 };
  1474.                             };
  1475.                         };
  1476.                     };
  1477.                
  1478.                     if(!cList.repaint_timer) {
  1479.                         window.SetCursor(IDC_HAND);
  1480.                         cList.repaint_timer = window.SetInterval(function() {
  1481.                             if(mouse_y < p.list.y + cTrack.height * 0) {
  1482.                                 p.list.selEndId = p.list.selEndId > 0 ? p.list.items[0].track_index : 0;
  1483.                                 if(p.scrollbar.visible) on_mouse_wheel(1);
  1484.                             }; else if(mouse_y > p.list.y + p.list.h - cTrack.height * 0) {
  1485.                                 p.list.selEndId = p.list.selEndId < p.list.count - 1 ? p.list.items[p.list.items.length - 1].track_index : p.list.count - 1;
  1486.                                 if(p.scrollbar.visible) on_mouse_wheel(-1);
  1487.                             };
  1488.                             // set selection on items in the rect area drawn
  1489.                             plman.SetPlaylistSelection(p.list.playlist, p.list.selAffected, false);
  1490.                             p.list.selAffected.splice(0, p.list.selAffected.length);
  1491.                             var deb = p.list.selStartId <= p.list.selEndId ? p.list.selStartId : p.list.selEndId;
  1492.                             var fin = p.list.selStartId <= p.list.selEndId ? p.list.selEndId : p.list.selStartId;
  1493.                             for(var i = deb; i <= fin ;i++) {
  1494.                                 p.list.selAffected.push(i);
  1495.                             };
  1496.                             plman.SetPlaylistSelection(p.list.playlist, p.list.selAffected, true);
  1497.                             p.list.metadblist_selection = plman.GetPlaylistSelectedItems(p.list.playlist);
  1498.                             plman.SetPlaylistFocusItem(p.list.playlist, p.list.selEndId);
  1499.                             //
  1500.                             p.list.selEndOffset = p.list.offset;
  1501.                         }, 100);
  1502.                     }; else {
  1503.                         window.SetCursor(IDC_ARROW);
  1504.                     };
  1505.                 };
  1506.             };
  1507.             if(dragndrop.clicked) {
  1508.                 dragndrop.moved = true;
  1509.             };
  1510.             break;
  1511.         };
  1512.     };
  1513. };
  1514.  
  1515. oGroupBy = function(label, tf, sortOrder, ref, l1, r1, l2, r2) {
  1516.     this.label = label;
  1517.     this.tf = tf;
  1518.     this.sortOrder = sortOrder;
  1519.     this.ref = ref;
  1520.     this.l1 = l1;
  1521.     this.r1 = r1;
  1522.     this.l2 = l2;
  1523.     this.r2 = r2;
  1524. };
  1525.  
  1526. oList = function(object_name, playlist) {
  1527.     this.objectName = object_name;
  1528.     this.playlist = playlist;
  1529.     this.focusedTrackId = plman.GetPlaylistFocusItemIndex(this.playlist);
  1530.     this.handleList = plman.GetPlaylistItems(this.playlist);
  1531.     this.count = this.handleList.Count;
  1532.     this.groups = [];
  1533.     this.items = [];
  1534.     this.groupby = [];
  1535.     this.totalGroupBy = window.GetProperty("SYSTEM.Groups.TotalGroupBy", 0);
  1536.     this.metadblist_selection = plman.GetPlaylistSelectedItems(this.playlist);
  1537.     this.SHIFT_start_id = null;
  1538.     this.SHIFT_count = 0;
  1539.     this.ishover = false;
  1540.     this.buttonclicked = false;
  1541.     this.selAffected = [];
  1542.     this.drawRectSel = false;
  1543.     this.beam = 0;
  1544.        
  1545.     this.saveGroupBy = function() {
  1546.         var tmp;
  1547.         for(var j = 0; j < 8; j++) {
  1548.             tmp = "";
  1549.             for(var i = 0; i < this.groupby.length; i++) {
  1550.                 switch(j) {
  1551.                     case 0:
  1552.                         tmp = tmp + this.groupby[i].label;
  1553.                         break;
  1554.                     case 1:
  1555.                         tmp = tmp + this.groupby[i].tf;
  1556.                         break;
  1557.                     case 2:
  1558.                         tmp = tmp + this.groupby[i].sortOrder;
  1559.                         break;
  1560.                     case 3:
  1561.                         tmp = tmp + this.groupby[i].ref;
  1562.                         break;
  1563.                     case 4:
  1564.                         tmp = tmp + this.groupby[i].l1;
  1565.                         break;
  1566.                     case 5:
  1567.                         tmp = tmp + this.groupby[i].r1;
  1568.                         break;
  1569.                     case 6:
  1570.                         tmp = tmp + this.groupby[i].l2;
  1571.                         break;
  1572.                     case 7:
  1573.                         tmp = tmp + this.groupby[i].r2;
  1574.                         break;
  1575.                 };
  1576.                 // add separator ';'
  1577.                 if(i < this.groupby.length - 1) {
  1578.                     tmp = tmp + ";";
  1579.                 };
  1580.             };
  1581.             switch(j) {
  1582.                 case 0:
  1583.                     window.SetProperty("SYSTEM.GroupBy.label", tmp);
  1584.                     break;
  1585.                 case 1:
  1586.                     window.SetProperty("SYSTEM.GroupBy.tf", tmp);
  1587.                     break;
  1588.                 case 2:
  1589.                     window.SetProperty("SYSTEM.GroupBy.sortOrder", tmp);
  1590.                     break;
  1591.                 case 3:
  1592.                     window.SetProperty("SYSTEM.GroupBy.ref", tmp);
  1593.                     break;
  1594.                 case 4:
  1595.                     window.SetProperty("SYSTEM.GroupBy.l1", tmp);
  1596.                     break;
  1597.                 case 5:
  1598.                     window.SetProperty("SYSTEM.GroupBy.r1", tmp);
  1599.                     break;
  1600.                 case 6:
  1601.                     window.SetProperty("SYSTEM.GroupBy.l2", tmp);
  1602.                     break;
  1603.                 case 7:
  1604.                     window.SetProperty("SYSTEM.GroupBy.r2", tmp);
  1605.                     break;
  1606.             };
  1607.         };
  1608.         this.initGroupBy();
  1609.     };
  1610.  
  1611.     this.initGroupBy = function() {
  1612.         this.groupby.splice(0, this.groupby.length);
  1613.         if(this.totalGroupBy == 0) {
  1614.             // INITIALIZE GroupBy patterns
  1615.             var fields = [];
  1616.             var tmp;
  1617.  
  1618.             for(var i = 0; i < 8; i++) {
  1619.                 switch(i) {
  1620.                     case 0:
  1621.                         fields.push(new Array("Album Artist | Album | Disc", "Folder Structure"));
  1622.                         break;
  1623.                     case 1:
  1624.                         fields.push(new Array("%album artist%%album%%discnumber%","$replace(%path%,%filename_ext%,)"));
  1625.                         break;
  1626.                     case 2:
  1627.                         fields.push(new Array("%album artist% | $if(%album%,%date%,'9999') | %album% | %discnumber% | %tracknumber% | %title%","%path%"));
  1628.                         break;
  1629.                     case 3:
  1630.                         fields.push(new Array("Album","Path"));
  1631.                         break;
  1632.                     case 4: // l1
  1633.                         fields.push(new Array("$if(%album%,%album%$if(%discnumber%,$ifgreater(%totaldiscs%,1,' - [disc '%discnumber%$if(%totaldiscs%,'/'%totaldiscs%']',']'),),),$if(%length%,'Single(s)','Web radios'))","$directory(%path%,1)"));
  1634.                         break;
  1635.                     case 5: // r1
  1636.                         fields.push(new Array("$if(%date%,$year($replace(%date%,/,-,.,-)),'-')","$if(%date%,$year($replace(%date%,/,-,.,-)),'-')"));
  1637.                         break;
  1638.                     case 6: // l2
  1639.                         fields.push(new Array("$if(%length%,%album artist%,'Stream')","$directory(%path%,2)"));
  1640.                         break;
  1641.                     case 7: // r2
  1642.                         fields.push(new Array("$if2(%genre%,'Other')","$if2(%genre%,'Other')"));
  1643.                         break;
  1644.                 };
  1645.                 // convert array to csv string
  1646.                 tmp = "";
  1647.                 for(var j = 0; j < fields[i].length; j++) {
  1648.                     tmp = tmp + fields[i][j];
  1649.                     if(j < fields[i].length - 1) {
  1650.                         tmp = tmp + ";";
  1651.                     };
  1652.                 };
  1653.                 // save CSV string into window Properties
  1654.                 switch(i) {
  1655.                     case 0:
  1656.                         window.SetProperty("SYSTEM.GroupBy.label", tmp);
  1657.                         break;
  1658.                     case 1:
  1659.                         window.SetProperty("SYSTEM.GroupBy.tf", tmp);
  1660.                         break;
  1661.                     case 2:
  1662.                         window.SetProperty("SYSTEM.GroupBy.sortOrder", tmp);
  1663.                         break;
  1664.                     case 3:
  1665.                         window.SetProperty("SYSTEM.GroupBy.ref", tmp);
  1666.                         break;
  1667.                     case 4:
  1668.                         window.SetProperty("SYSTEM.GroupBy.l1", tmp);
  1669.                         break;
  1670.                     case 5:
  1671.                         window.SetProperty("SYSTEM.GroupBy.r1", tmp);
  1672.                         break;
  1673.                     case 6:
  1674.                         window.SetProperty("SYSTEM.GroupBy.l2", tmp);
  1675.                         break;
  1676.                     case 7:
  1677.                         window.SetProperty("SYSTEM.GroupBy.r2", tmp);
  1678.                         break;
  1679.                 };
  1680.             };
  1681.             // create GroupBy Objects
  1682.             this.totalGroupBy = fields[0].length;
  1683.             window.SetProperty("SYSTEM.Groups.TotalGroupBy", this.totalGroupBy);
  1684.             for(var k = 0; k < this.totalGroupBy; k++) {
  1685.                 this.groupby.push(new oGroupBy(fields[0][k],fields[1][k],fields[2][k],fields[3][k],fields[4][k],fields[5][k],fields[6][k],fields[7][k]));
  1686.             };
  1687.            
  1688.         }; else {
  1689.             var fields = [];
  1690.             var tmp;
  1691.             // LOAD GroupBy patterns from Properties
  1692.             for(var i = 0; i < 8; i++) {
  1693.                 switch(i) {
  1694.                     case 0:
  1695.                         tmp = window.GetProperty("SYSTEM.GroupBy.label", "?;?");
  1696.                         break;
  1697.                     case 1:
  1698.                         tmp = window.GetProperty("SYSTEM.GroupBy.tf", "?;?");
  1699.                         break;
  1700.                     case 2:
  1701.                         tmp = window.GetProperty("SYSTEM.GroupBy.sortOrder", "?;?");
  1702.                         break;
  1703.                     case 3:
  1704.                         tmp = window.GetProperty("SYSTEM.GroupBy.ref", "?;?");
  1705.                         break;
  1706.                     case 4:
  1707.                         tmp = window.GetProperty("SYSTEM.GroupBy.l1", "?;?");
  1708.                         break;
  1709.                     case 5:
  1710.                         tmp = window.GetProperty("SYSTEM.GroupBy.r1", "?;?");
  1711.                         break;
  1712.                     case 6:
  1713.                         tmp = window.GetProperty("SYSTEM.GroupBy.l2", "?;?");
  1714.                         break;
  1715.                     case 7:
  1716.                         tmp = window.GetProperty("SYSTEM.GroupBy.r2", "?;?");
  1717.                         break;
  1718.                 };
  1719.                 fields.push(tmp.split(";"));
  1720.             };
  1721.             for(var k = 0; k < this.totalGroupBy; k++) {
  1722.                 this.groupby.push(new oGroupBy(fields[0][k],fields[1][k],fields[2][k],fields[3][k],fields[4][k],fields[5][k],fields[6][k],fields[7][k]));
  1723.             };
  1724.         };
  1725.     };
  1726.     this.initGroupBy();
  1727.    
  1728.     this.getTotalRows = function() {
  1729.         var ct = 0;
  1730.         var cv = 0;
  1731.         for(var i = 0; i < this.groups.length; i++) {
  1732.             this.groups[i].totalPreviousRows += ct;
  1733.             this.groups[i].totalPreviousTracks += cv;
  1734.             if(this.groups[i].collapsed) {
  1735.                 ct += cGroup.collapsed_height;
  1736.             }; else {
  1737.                 ct += this.groups[i].count + cGroup.expanded_height;
  1738.                 ct += this.groups[i].rowsToAdd;
  1739.             };
  1740.             cv += this.groups[i].count;
  1741.             cv += this.groups[i].rowsToAdd;
  1742.         };
  1743.         return ct;
  1744.     };
  1745.    
  1746.     this.updateGroupsOnCollapse = function(group_id) {
  1747.         if(!this.groups[group_id].collapsed) {
  1748.             var delta = (this.groups[group_id].count + this.groups[group_id].rowsToAdd) + (cGroup.expanded_height - cGroup.collapsed_height);
  1749.             for(var i = group_id + 1; i < this.groups.length; i++) {
  1750.                 this.groups[i].totalPreviousRows -= delta;
  1751.             };
  1752.             this.totalRows -= delta;
  1753.             if(this.totalRows <= this.totalRowVisible) {
  1754.                 this.offset = 0;
  1755.             }; else {
  1756.                 if(this.totalRows - this.offset < this.totalRowVisible) {
  1757.                     this.offset = this.totalRows - this.totalRowVisible;
  1758.                 };
  1759.             };
  1760.             this.groups[group_id].collapsed = true;
  1761.         };
  1762.     };
  1763.    
  1764.     this.updateGroupsOnExpand = function(group_id) {
  1765.         if(this.groups[group_id].collapsed) {
  1766.             var delta = (this.groups[group_id].count + this.groups[group_id].rowsToAdd) + (cGroup.expanded_height - cGroup.collapsed_height);
  1767.             for(var i = group_id + 1; i < this.groups.length; i++) {
  1768.                 this.groups[i].totalPreviousRows += delta;
  1769.             };
  1770.             this.totalRows += delta;
  1771.             this.groups[group_id].collapsed = false;
  1772.         };
  1773.     };
  1774.    
  1775.     this.updateGroupStatus = function(group_id) {
  1776.         // collapse previous group of focused track
  1777.         if(properties.autocollapse) {
  1778.             this.updateGroupsOnCollapse(g_group_id_focused);
  1779.         };
  1780.         // expand new group of the current focused track (new one)
  1781.         this.updateGroupsOnExpand(group_id);
  1782.         // update current group id of focused track
  1783.         g_group_id_focused = group_id;
  1784.     };
  1785.    
  1786.     this.init_groups = function() {
  1787.         var handle;
  1788.         var current;
  1789.         var previous;
  1790.         var count = 0;
  1791.         var start = 0;
  1792.         var total_time_length = 0;
  1793.         var global_time = 0;
  1794.        
  1795.         //var t1 = fb.CreateProfiler("Init Groups");
  1796.        
  1797.         // update group key TF pattern
  1798.         if(properties.showgroupheaders) {
  1799.             tf_group_key = fb.TitleFormat(this.groupby[cGroup.pattern_idx].tf);
  1800.         }; else {
  1801.             tf_group_key = fb.TitleFormat(1);
  1802.         };
  1803.  
  1804.         this.groups.splice(0, this.groups.length);
  1805.         for(var i = 0; i < this.count; i++) {
  1806.             handle = this.handleList.Item(i);
  1807.             current = tf_group_key.EvalWithMetadb(handle);
  1808.             if(i == 0) {
  1809.                 if(this.count == 1) {
  1810.                     count++;
  1811.                     total_time_length += handle.Length;
  1812.                     global_time += handle.Length;
  1813.                     this.groups.push(new oGroup(this.groups.length, start, count, total_time_length, this.focusedTrackId));
  1814.                 }; else {
  1815.                     previous = current;
  1816.                 };
  1817.             }; else {
  1818.                 if(current != previous || i == this.count - 1) {
  1819.                     if(current != previous) {
  1820.                         if(i == this.count - 1) {
  1821.                             this.groups.push(new oGroup(this.groups.length, start, count, total_time_length, this.focusedTrackId));
  1822.                             start = i;
  1823.                             count = 1;
  1824.                             total_time_length = handle.Length;
  1825.                             //global_time += handle.Length;
  1826.                             this.groups.push(new oGroup(this.groups.length, start, count, total_time_length, this.focusedTrackId));
  1827.                         }; else {
  1828.                             this.groups.push(new oGroup(this.groups.length, start, count, total_time_length, this.focusedTrackId));
  1829.                         };
  1830.                     }; else {
  1831.                         total_time_length += handle.Length;
  1832.                         count++;
  1833.                         this.groups.push(new oGroup(this.groups.length, start, count, total_time_length, this.focusedTrackId));
  1834.                     };
  1835.                     count = 0;
  1836.                     total_time_length = 0;
  1837.                     start = i;
  1838.                     previous = current;
  1839.                 };
  1840.             };
  1841.             if(this.count > 1) {
  1842.                 count++;
  1843.                 total_time_length += handle.Length;
  1844.                 global_time += handle.Length;
  1845.             };
  1846.         };
  1847.         // calc total rows for this total handles + groups
  1848.         this.totalRows = this.getTotalRows();
  1849.        
  1850.         // total seconds playlist for playlist header panel
  1851.         g_total_duration_text = formatPlaylistTotalDurationText(global_time);
  1852.        
  1853.         //fb.trace("init groups delay = "+t1.Time+" ms /handleList count="+this.count);
  1854.     };
  1855.  
  1856.     this.updateHandleList = function(playlist) {
  1857.         this.playlist = playlist;
  1858.         if(plman.PlaylistItemCount(this.playlist) > 0) {
  1859.             this.focusedTrackId = plman.GetPlaylistFocusItemIndex(this.playlist);
  1860.         }; else {
  1861.             this.focusedTrackId = -1;
  1862.         };
  1863.         if(this.handleList) this.handleList.Dispose();
  1864.         this.handleList = plman.GetPlaylistItems(this.playlist);
  1865.         this.count = this.handleList.Count;
  1866.         this.init_groups();
  1867.         this.getStartOffsetFromFocusId();
  1868.     };
  1869.    
  1870.     this.setSize = function(x, y, w, h) {
  1871.         this.x = x;
  1872.         this.y = y;
  1873.         this.w = w;
  1874.         this.h = h;
  1875.         this.totalRowVisible = Math.floor(this.h / cTrack.height);
  1876.         this.totalRowToLoad = this.totalRowVisible + 1;
  1877.     };
  1878.    
  1879.     this.selectAtoB = function(start_id, end_id) {
  1880.  
  1881.         var affectedItems = Array();
  1882.        
  1883.         if(this.SHIFT_start_id == null) {
  1884.             this.SHIFT_start_id = start_id;
  1885.         };
  1886.        
  1887.         plman.ClearPlaylistSelection(this.playlist);
  1888.        
  1889.         var previous_focus_id = this.focusedTrackId;
  1890.        
  1891.         if(start_id < end_id) {
  1892.             var deb = start_id;
  1893.             var fin = end_id;
  1894.         }; else {
  1895.             var deb = end_id;
  1896.             var fin = start_id;        
  1897.         };
  1898.  
  1899.         for(var i = deb; i <= fin ;i++) {
  1900.             affectedItems.push(i);
  1901.         };
  1902.         plman.SetPlaylistSelection(this.playlist, affectedItems, true);
  1903.        
  1904.         plman.SetPlaylistFocusItem(this.playlist, end_id);
  1905.        
  1906.         if(affectedItems.length > 1) {
  1907.             if(end_id > previous_focus_id) {
  1908.                 var delta = end_id - previous_focus_id;
  1909.                 this.SHIFT_count += delta;
  1910.             }; else {
  1911.                 var delta = previous_focus_id - end_id;
  1912.                 this.SHIFT_count -= delta;
  1913.             };
  1914.         };
  1915.     };
  1916.  
  1917.     this.selectGroupTracks = function(gp_id, state) {
  1918.         var affectedItems = Array();
  1919.         var first_trk = this.groups[gp_id].start;
  1920.         var total_trks = this.groups[gp_id].count;
  1921.         for(var i = first_trk; i < first_trk + total_trks; i++) {
  1922.             affectedItems.push(i);
  1923.         };
  1924.         plman.SetPlaylistSelection(this.playlist, affectedItems, state);
  1925.     };
  1926.    
  1927.     this.showNowPlaying = function() {
  1928.         if(fb.IsPlaying) {
  1929.             if(plman.PlayingPlaylist != this.playlist) {
  1930.                 plman.ActivePlaylist = plman.PlayingPlaylist;
  1931.                 this.playlist = plman.ActivePlaylist;
  1932.                 this.nowplaying = plman.GetPlayingItemLocation();
  1933.                 // set focus on the now playing item
  1934.                 plman.SetPlaylistFocusItem(this.playlist, this.nowplaying.PlaylistItemIndex);
  1935.             }; else {
  1936.                 this.nowplaying = plman.GetPlayingItemLocation();
  1937.                 // set focus on the now playing item
  1938.                 plman.SetPlaylistFocusItem(this.playlist, this.nowplaying.PlaylistItemIndex);
  1939.                 this.setItems(!p.list.isFocusedItemVisible());
  1940.                 full_repaint();
  1941.             };
  1942.         };
  1943.     };
  1944.    
  1945.     this.showFocusedItem = function() {
  1946.         this.setItems(true);
  1947.         full_repaint();
  1948.     };
  1949.    
  1950.     this.getStartOffsetFromFocusId = function() {
  1951.         var mid = Math.floor(this.totalRowToLoad / 2) - 1;
  1952.         if(plman.PlaylistItemCount(this.playlist) > 0) {
  1953.             this.focusedTrackId = plman.GetPlaylistFocusItemIndex(this.playlist);
  1954.         }; else {
  1955.             this.focusedTrackId = -1;
  1956.         };
  1957.         if(this.focusedTrackId < 0) {
  1958.             this.offset = 0;
  1959.             return this.offset;
  1960.         }; 
  1961.        
  1962.         this.focusedRowId = this.getRowId(this.focusedTrackId);
  1963.            
  1964.         if(this.totalRows > this.totalRowVisible) {
  1965.             if(this.focusedRowId <= mid) {
  1966.                 this.offset = 0;
  1967.             }; else {
  1968.                 var d = this.totalRows - (this.focusedRowId + 1);
  1969.                 if(d >= Math.floor(this.totalRowToLoad / 2)) {
  1970.                     this.offset = this.focusedRowId - mid;
  1971.                 }; else {              
  1972.                     this.offset = this.totalRows - this.totalRowVisible;
  1973.                 };
  1974.             };
  1975.             if(this.offset < 0) this.offset = 0;
  1976.         }; else {
  1977.             this.offset = 0;
  1978.         };
  1979.         return this.offset;
  1980.     };
  1981.    
  1982.     this.getGroupIdfromTrackId = function(valeur) {
  1983.         var mediane = 0; var deb = 0; var fin = this.groups.length - 1;
  1984.         while(deb <= fin){
  1985.             mediane = Math.floor((fin + deb)/2);
  1986.             if(valeur >= this.groups[mediane].start && valeur < this.groups[mediane].start + this.groups[mediane].count) {
  1987.                 return mediane;
  1988.             }; else if(valeur < this.groups[mediane].start) {
  1989.                 fin = mediane - 1;
  1990.             }; else {
  1991.                 deb = mediane + 1;
  1992.             };
  1993.         };
  1994.         return -1;
  1995.     };
  1996.    
  1997.     this.getGroupIdFromRowId = function(valeur) {
  1998.         var mediane = 0; var deb = 0; var fin = this.groups.length - 1;
  1999.         while(deb <= fin){
  2000.             mediane = Math.floor((fin + deb)/2);
  2001.             grp_height = this.groups[mediane].collapsed ? cGroup.collapsed_height : cGroup.expanded_height;
  2002.             grp_size = this.groups[mediane].collapsed ? grp_height : grp_height + this.groups[mediane].count + this.groups[mediane].rowsToAdd;
  2003.             if(valeur >= this.groups[mediane].totalPreviousRows && valeur < this.groups[mediane].totalPreviousRows + grp_size) {
  2004.                 return mediane;
  2005.             }; else if(valeur < this.groups[mediane].totalPreviousRows) {
  2006.                 fin = mediane - 1;
  2007.             }; else {
  2008.                 deb = mediane + 1;
  2009.             };
  2010.         };
  2011.         return -1;
  2012.     };
  2013.    
  2014.     this.getRowId = function(trackId) {
  2015.         var grp_id = this.getGroupIdfromTrackId(trackId);
  2016.         if(this.groups[grp_id].collapsed) { // track hidden in the collapsed group so return = -1 or we return the row id of the group it belongs to ?
  2017.             //var row_index = -1;
  2018.             var row_index = this.groups[grp_id].totalPreviousRows + 1;
  2019.         }; else { // group expanded so we can return a valid row_id for the track searched
  2020.             var row_index = this.groups[grp_id].totalPreviousRows + cGroup.expanded_height + (trackId - this.groups[grp_id].start);
  2021.         };
  2022.         return row_index;
  2023.     };
  2024.  
  2025.     this.getTrackId = function(rowId) {
  2026.         this.s_group_id = this.getGroupIdFromRowId(rowId);
  2027.         if(this.s_group_id >= 0) {
  2028.             this.s_group_height = this.groups[this.s_group_id].collapsed ? cGroup.collapsed_height : cGroup.expanded_height;
  2029.             if(this.groups[this.s_group_id].collapsed) {
  2030.                 var a = rowId - this.groups[this.s_group_id].totalPreviousRows;
  2031.                 this.s_groupheader_line_id = a;
  2032.                 this.s_track_id = this.groups[this.s_group_id].start;
  2033.             }; else {
  2034.                 var a = rowId - this.groups[this.s_group_id].totalPreviousRows;
  2035.                 if(a < this.s_group_height) { // row is in the group header
  2036.                     this.s_groupheader_line_id = a;
  2037.                     this.s_track_id = this.groups[this.s_group_id].start;
  2038.                 }; else { // row is a track
  2039.                     this.s_groupheader_line_id = -1;
  2040.                     this.s_track_id = (a - this.s_group_height) + this.groups[this.s_group_id].start;
  2041.                     var track_index_in_group = this.s_track_id - this.groups[this.s_group_id].start;
  2042.                     if(track_index_in_group >= this.groups[this.s_group_id].count) { // track is a copy of the last track of the group to fill the group with minimum track count in group feature!
  2043.                         this.s_delta = (track_index_in_group - this.groups[this.s_group_id].count) + 1;
  2044.                         this.s_track_id -= this.s_delta;
  2045.                     }; else {
  2046.                         this.s_delta = 0;
  2047.                     };
  2048.                 };
  2049.             };
  2050.             return this.s_track_id;
  2051.         }; else {
  2052.             return 0;
  2053.         };
  2054.     };
  2055.    
  2056.     this.scrollItems = function(delta, scrollstep) {
  2057.         cList.scroll_direction = (delta < 0 ? -1 : 1);
  2058.         if(delta > 0) { // scroll up
  2059.             this.offset -= scrollstep;
  2060.             if(this.offset < 0) this.offset = 0;   
  2061.         }; else { // scroll down
  2062.             this.offset += scrollstep;
  2063.             if(this.offset > this.totalRows - this.totalRowVisible) {
  2064.                 this.offset = this.totalRows - this.totalRowVisible;
  2065.             };
  2066.         };
  2067.         this.setItems(false);
  2068.         p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
  2069.        
  2070.         if(properties.smoothscrolling) set_scroll_delta();
  2071.        
  2072.         if(!p.list.drawRectSel) full_repaint();
  2073.     };
  2074.    
  2075.        
  2076.     this.setItems = function(forceFocus) {
  2077.         var track_index_in_group = 0;
  2078.         var row_index = 0;
  2079.         if(forceFocus) { // from focus item centered in panel
  2080.             if(this.totalRows > this.totalRowVisible) {        
  2081.                 var i = this.getStartOffsetFromFocusId();
  2082.                 if(this.totalRows - this.offset <= this.totalRowVisible) {
  2083.                     var total_rows_to_draw = this.totalRows < this.totalRowVisible ? this.totalRows : this.totalRowVisible;
  2084.                 }; else {
  2085.                     var total_rows_to_draw = this.totalRows < this.totalRowToLoad ? this.totalRows : this.totalRowToLoad;
  2086.                 };
  2087.                 this.items.splice(0, this.items.length);
  2088.                                
  2089.                 while(i < this.offset + total_rows_to_draw) {
  2090.                     this.getTrackId(i);
  2091.                     if(this.s_groupheader_line_id >= 0) { // group header
  2092.                         this.items.push(new oItem(this.playlist, row_index, 1, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, 0, this.s_group_height, this.s_groupheader_line_id, this.groups[this.s_group_id], 0));
  2093.                         i += this.s_group_height - this.s_groupheader_line_id;
  2094.                         row_index += this.s_group_height - this.s_groupheader_line_id;
  2095.                     }; else { // track row
  2096.                         track_index_in_group = this.s_track_id - this.groups[this.s_group_id].start + this.s_delta;
  2097.                         this.items.push(new oItem(this.playlist, row_index, 0, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, track_index_in_group, 1, 0, null, this.s_delta));
  2098.                         i++;
  2099.                         row_index++;
  2100.                     };
  2101.                 };
  2102.             }; else {
  2103.                 this.offset = 0;
  2104.                 var i = 0;  // offset = 0  
  2105.                 this.items.splice(0, this.items.length);
  2106.                 while(i < this.totalRows) {
  2107.                     this.getTrackId(i);
  2108.                     if(this.s_groupheader_line_id >= 0) { // group header
  2109.                         this.items.push(new oItem(this.playlist, row_index, 1, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, 0, this.s_group_height, this.s_groupheader_line_id, this.groups[this.s_group_id], 0));
  2110.                         i += this.s_group_height - this.s_groupheader_line_id;
  2111.                         row_index += this.s_group_height - this.s_groupheader_line_id;
  2112.                     }; else { // track row
  2113.                         track_index_in_group = this.s_track_id - this.groups[this.s_group_id].start + this.s_delta;
  2114.                         this.items.push(new oItem(this.playlist, row_index, 0, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, track_index_in_group, 1, 0, null, this.s_delta));
  2115.                         i++;
  2116.                         row_index++;
  2117.                     };
  2118.                 };
  2119.             };  
  2120.         }; else { // fill items from current offset
  2121.             if(this.totalRows > this.totalRowVisible) {
  2122.                 if(typeof(this.offset)=="undefined") {
  2123.                     this.getStartOffsetFromFocusId();
  2124.                     fb.trace("... undefined");
  2125.                 };
  2126.                 var i = this.offset;           
  2127.                 if(this.totalRows - this.offset <= this.totalRowVisible) {
  2128.                     var total_rows_to_draw = this.totalRows < this.totalRowVisible ? this.totalRows : this.totalRowVisible;
  2129.                 }; else {
  2130.                     var total_rows_to_draw = this.totalRows < this.totalRowToLoad ? this.totalRows : this.totalRowToLoad;
  2131.                 };
  2132.                 this.items.splice(0, this.items.length);
  2133.                 while(i < this.offset + total_rows_to_draw) {
  2134.                     this.getTrackId(i);
  2135.                     if(this.s_groupheader_line_id >= 0) { // group header
  2136.                         this.items.push(new oItem(this.playlist, row_index, 1, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, 0, this.s_group_height, this.s_groupheader_line_id, this.groups[this.s_group_id], 0));
  2137.                         i += this.s_group_height - this.s_groupheader_line_id;
  2138.                         row_index += this.s_group_height - this.s_groupheader_line_id;
  2139.                     }; else { // track row
  2140.                         track_index_in_group = this.s_track_id - this.groups[this.s_group_id].start + this.s_delta;
  2141.                         this.items.push(new oItem(this.playlist, row_index, 0, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, track_index_in_group, 1, 0, null, this.s_delta));
  2142.                         i++;
  2143.                         row_index++;
  2144.                     };
  2145.                 };
  2146.             }; else {
  2147.                 var i = 0;  // offset = 0  
  2148.                 this.items.splice(0, this.items.length);
  2149.                 while(i < this.totalRows) {
  2150.                     this.getTrackId(i);
  2151.                     if(this.s_groupheader_line_id >= 0) { // group header
  2152.                         this.items.push(new oItem(this.playlist, row_index, 1, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, 0, this.s_group_height, this.s_groupheader_line_id, this.groups[this.s_group_id], 0));
  2153.                         i += this.s_group_height - this.s_groupheader_line_id;
  2154.                         row_index += this.s_group_height - this.s_groupheader_line_id;
  2155.                     }; else { // track row
  2156.                         track_index_in_group = this.s_track_id - this.groups[this.s_group_id].start + this.s_delta;
  2157.                         this.items.push(new oItem(this.playlist, row_index, 0, this.handleList.Item(this.s_track_id), this.s_track_id, this.s_group_id, track_index_in_group, 1, 0, null, this.s_delta));
  2158.                         i++;
  2159.                         row_index++;
  2160.                     };
  2161.                 };
  2162.             };
  2163.         };
  2164.     };
  2165.        
  2166.     this.getOffsetFromCursorPos = function() {
  2167.         var r = (this.cursorPos / this.h);
  2168.         this.offset = Math.round(r * this.totalRows);
  2169.     };
  2170.    
  2171.     this.isFocusedItemVisible = function() {
  2172.         if(this.totalRows <= this.totalRowVisible) {
  2173.             return true;
  2174.         }; else {
  2175.             for(var i = 0; i < this.items.length - 1; i++) {
  2176.                 if((this.items[i].type == 0 && this.items[i].empty_row_index == 0) || this.groups[this.items[i].group_index].collapsed) {
  2177.                     if(this.groups[this.items[i].group_index].collapsed) {
  2178.                         if(this.focusedTrackId >= this.groups[this.items[i].group_index].start && this.focusedTrackId < this.groups[this.items[i].group_index].start + this.groups[this.items[i].group_index].count) {
  2179.                             return true;
  2180.                         };
  2181.                     }; else if(this.focusedTrackId == this.items[i].track_index) {
  2182.                         return true;
  2183.                     };
  2184.                 };
  2185.             };
  2186.         };
  2187.         return false;
  2188.     };
  2189.    
  2190.     this.draw = function(gr) {
  2191.         var item_h = 0;
  2192.  
  2193.         if(cList.scroll_timer) {
  2194.             var row_top_y = this.y - (cList.scroll_delta * cList.scroll_direction);
  2195.         }; else {
  2196.             var row_top_y = this.y;
  2197.         };
  2198.         var width = 0;
  2199.        
  2200.         if(fb.IsPlaying && plman.PlayingPlaylist == this.playlist) {
  2201.             this.nowplaying = plman.GetPlayingItemLocation();
  2202.         };
  2203.                
  2204.         // Draw items (tracks and group headers)
  2205.         for(var i = 0; i < this.items.length; i++) {
  2206.             item_h = this.items[i].heightInRow * cTrack.height;
  2207.             // test if scrollbar displayed or not for the items width to draw
  2208.             if(this.totalRows <= this.totalRowVisible || !properties.showscrollbar) {
  2209.                 width = this.w;
  2210.             }; else {
  2211.                 width = this.w - cScrollBar.width;
  2212.             };
  2213.             this.items[i].draw(gr, this.x, row_top_y, width, item_h);
  2214.             row_top_y += item_h - (this.items[i].groupRowDelta * cTrack.height);
  2215.         };
  2216.        
  2217.         // Draw rect selection
  2218.         if (this.drawRectSel) {
  2219.             var rectSelColor = g_color_selected_bg;
  2220.             this.selDeltaRows = this.selEndOffset - this.selStartOffset;
  2221.             if (this.selX <= mouse_x) {
  2222.                 if (this.selY - this.selDeltaRows*cTrack.height <= mouse_y) {
  2223.                     gr.FillSolidRect(this.selX, (this.selY - this.selDeltaRows*cTrack.height), mouse_x - this.selX, mouse_y - (this.selY - this.selDeltaRows*cTrack.height), rectSelColor & 0x33ffffff);
  2224.                     gr.DrawRect(this.selX, (this.selY - this.selDeltaRows*cTrack.height), mouse_x - this.selX - 1, mouse_y - (this.selY - this.selDeltaRows*cTrack.height) - 1, 1.0, rectSelColor & 0x66ffffff);
  2225.                 }; else {
  2226.                     gr.FillSolidRect(this.selX, mouse_y, mouse_x - this.selX, this.selY - mouse_y - this.selDeltaRows*cTrack.height, rectSelColor & 0x33ffffff);
  2227.                     gr.DrawRect(this.selX, mouse_y, mouse_x - this.selX - 1, this.selY - mouse_y - this.selDeltaRows*cTrack.height - 1, 1.0, rectSelColor & 0x66ffffff);
  2228.                 };
  2229.             }; else {
  2230.                 if (this.selY - this.selDeltaRows*cTrack.height <= mouse_y) {
  2231.                     gr.FillSolidRect(mouse_x, (this.selY - this.selDeltaRows*cTrack.height), this.selX - mouse_x, mouse_y - (this.selY - this.selDeltaRows*cTrack.height), rectSelColor & 0x33ffffff);
  2232.                     gr.DrawRect(mouse_x, (this.selY - this.selDeltaRows*cTrack.height), this.selX - mouse_x - 1, mouse_y - (this.selY - this.selDeltaRows*cTrack.height) - 1, 1.0, rectSelColor & 0x66ffffff);
  2233.                 }; else {
  2234.                     gr.FillSolidRect(mouse_x, mouse_y, this.selX - mouse_x, this.selY - mouse_y - this.selDeltaRows*cTrack.height, rectSelColor & 0x33ffffff);
  2235.                     gr.DrawRect(mouse_x, mouse_y, this.selX - mouse_x - 1, this.selY - mouse_y - this.selDeltaRows*cTrack.height - 1, 1.0, rectSelColor & 0x66ffffff);
  2236.                 };
  2237.             };
  2238.         };
  2239.     };
  2240.    
  2241.     this.repaint = function() {
  2242.         window.RepaintRect(this.x, this.y, this.w, this.h);
  2243.     };
  2244.    
  2245.     this.check = function(event, x, y, delta) {
  2246.         this.ishover = (x > this.x && x < this.x + this.w - p.playlistManager.woffset && y > this.y && y < this.y + this.h);
  2247.         switch(event) {
  2248.             case "down":
  2249.                 this.mclicked = this.ishover;
  2250.                 if(this.ishover) {
  2251.                     for(var i = 0; i < this.items.length; i++) {
  2252.                         this.items[i].check(event, x, y);
  2253.                     };
  2254.                 };
  2255.                 break;
  2256.             case "up":
  2257.                 if(this.ishover) {
  2258.                     for(var i = 0; i < this.items.length; i++) {
  2259.                         this.items[i].check(event, x, y);
  2260.                     };
  2261.                 };
  2262.                 p.list.drawRectSel = false;
  2263.                 // kill timer on rect area refresh for "drawRectSel"
  2264.                 cList.repaint_timer && window.ClearInterval(cList.repaint_timer);
  2265.                 cList.repaint_timer = false;
  2266.                 // kill drag move playlist item timers (vscroll)
  2267.                 cPlaylistManager.vscroll_timer_loop && window.ClearTimeout(cPlaylistManager.vscroll_timer_loop);
  2268.                 cPlaylistManager.vscroll_timer_loop = false;
  2269.                 cPlaylistManager.vscroll_timer && window.ClearTimeout(cPlaylistManager.vscroll_timer);
  2270.                 cPlaylistManager.vscroll_timer = false;
  2271.                 this.mclicked = false;
  2272.                 break;
  2273.             case "move":
  2274.                 for(var i = 0; i < this.items.length; i++) {
  2275.                     this.items[i].check(event, x, y);
  2276.                 };
  2277.                 if(!this.drawRectSel) {
  2278.                     // hscroll playlist manager panel when dragging tracks if not visible by default
  2279.                     if(dragndrop.moved || cPlaylistManager.drag_moved) {
  2280.                         if(!cPlaylistManager.hscroll_timer) {
  2281.                             if(!cPlaylistManager.visible) {
  2282.                                 if((p.playlistManager.woffset == 0 && mouse_x > p.list.w / 1.5) || (p.playlistManager.woffset >= cPlaylistManager.width && (mouse_x <= p.list.w / 1.5))) {
  2283.                                     p.playlistManager.refresh("", true, true);
  2284.                                     cPlaylistManager.hscroll_timer = window.SetInterval(function () {
  2285.                                         if(mouse_x > p.list.w / 1.5) {
  2286.                                             p.playlistManager.woffset += cPlaylistManager.step;
  2287.                                             if(p.playlistManager.woffset >= cPlaylistManager.width) {
  2288.                                                 p.playlistManager.woffset = cPlaylistManager.width;
  2289.                                                 cPlaylistManager.hscroll_timer && window.ClearTimeout(cPlaylistManager.hscroll_timer);
  2290.                                                 cPlaylistManager.hscroll_timer = false;
  2291.                                             };
  2292.                                             full_repaint();
  2293.                                         }; else {
  2294.                                             full_repaint();
  2295.                                             p.playlistManager.woffset -= cPlaylistManager.step;
  2296.                                             if(p.playlistManager.woffset <= 0) {
  2297.                                                 p.playlistManager.woffset = 0;
  2298.                                                 cPlaylistManager.hscroll_timer && window.ClearTimeout(cPlaylistManager.hscroll_timer);
  2299.                                                 cPlaylistManager.hscroll_timer = false;
  2300.                                                 full_repaint();
  2301.                                             };
  2302.                                         };
  2303.                                     }, 16);
  2304.                                 };
  2305.                             };
  2306.                             if(p.playlistManager.woffset >= cPlaylistManager.width) { // if playlist manager panel opened
  2307.                                 // vscroll playlist manager on dragging
  2308.                                 // ************************************
  2309.                                 var inner_padding = 0;
  2310.                                 var area_h = Math.floor(p.playlistManager.h / cPlaylistManager.rowHeight) * cPlaylistManager.rowHeight;
  2311.                                 if(x > p.playlistManager.x - p.playlistManager.woffset && x < p.playlistManager.x - p.playlistManager.woffset + p.playlistManager.w) {
  2312.                                     if(p.playlistManager.offset > 0 && y < p.playlistManager.y + cPlaylistManager.rowHeight + inner_padding) {
  2313.                                         if(p.playlistManager.scrollbarWidth > 0 && !cPlaylistManager.vscroll_timer_loop) {
  2314.                                             cPlaylistManager.vscroll_timer_loop = window.SetInterval(function(){
  2315.                                                 //
  2316.                                                 var s = Math.abs(mouse_y - (p.playlistManager.y + cPlaylistManager.rowHeight));
  2317.                                                 var h = Math.ceil(cPlaylistManager.rowHeight / 2);
  2318.                                                 if(s > h) s = h;
  2319.                                                 var t = h - s + 1;
  2320.                                                 var r = Math.round(500 / h);
  2321.                                                 var scroll_speed_ms = ((t * r) < 10 ? 10 : (t * r));
  2322.                                                 //
  2323.                                                 if(!cPlaylistManager.vscroll_timer) {
  2324.                                                     cPlaylistManager.vscroll_timer = window.SetTimeout(function(){
  2325.                                                         p.playlistManager.offset = p.playlistManager.offset > 0 ? p.playlistManager.offset - 1 : 0;
  2326.                                                         p.playlistManager.scrollbar.reSet(p.playlistManager.rowTotal, cPlaylistManager.rowHeight, p.playlistManager.offset);
  2327.                                                         full_repaint();
  2328.                                                         if(p.playlistManager.offset==0 || p.playlistManager.woffset < cPlaylistManager.width) { // kill interval timer!
  2329.                                                             window.ClearTimeout(cPlaylistManager.vscroll_timer_loop);
  2330.                                                             cPlaylistManager.vscroll_timer_loop = false;
  2331.                                                         };
  2332.                                                         window.ClearTimeout(cPlaylistManager.vscroll_timer);
  2333.                                                         cPlaylistManager.vscroll_timer = false;
  2334.                                                     }, scroll_speed_ms);
  2335.                                                 };
  2336.                                             }, 5);
  2337.                                         };
  2338.                                     }; else if(p.playlistManager.offset < p.playlistManager.rowTotal - p.playlistManager.totalRows && y > p.playlistManager.y + area_h - inner_padding) {
  2339.                                         if(p.playlistManager.scrollbarWidth > 0 && !cPlaylistManager.vscroll_timer_loop) {
  2340.                                             cPlaylistManager.vscroll_timer_loop = window.SetInterval(function(){
  2341.                                                 //
  2342.                                                 var s = Math.abs(mouse_y - (p.playlistManager.y + area_h));
  2343.                                                 var h = Math.ceil(cPlaylistManager.rowHeight / 2);
  2344.                                                 if(s > h) s = h;
  2345.                                                 var t = h - s + 1;
  2346.                                                 var r = Math.round(500 / h);
  2347.                                                 var scroll_speed_ms = ((t * r) < 10 ? 10 : (t * r));
  2348.                                                 //
  2349.                                                 if(!cPlaylistManager.vscroll_timer) {
  2350.                                                     cPlaylistManager.vscroll_timer = window.SetTimeout(function(){
  2351.                                                         p.playlistManager.offset = p.playlistManager.offset < p.playlistManager.rowTotal - p.playlistManager.totalRows ? p.playlistManager.offset + 1 : p.playlistManager.rowTotal - p.playlistManager.totalRows;
  2352.                                                         p.playlistManager.scrollbar.reSet(p.playlistManager.rowTotal, cPlaylistManager.rowHeight, p.playlistManager.offset);
  2353.                                                         on_mouse_move(mouse_x+1, mouse_y); // call mouse_move to set mouse cursor to right image (IDC_NO if not on a playlist item)
  2354.                                                         full_repaint();
  2355.                                                         if(p.playlistManager.offset == p.playlistManager.rowTotal - p.playlistManager.totalRows || p.playlistManager.woffset < cPlaylistManager.width) { // kill interval timer!
  2356.                                                             window.ClearTimeout(cPlaylistManager.vscroll_timer_loop);
  2357.                                                             cPlaylistManager.vscroll_timer_loop = false;
  2358.                                                         };
  2359.                                                         window.ClearTimeout(cPlaylistManager.vscroll_timer);
  2360.                                                         cPlaylistManager.vscroll_timer = false;
  2361.                                                     }, scroll_speed_ms);
  2362.                                                 };
  2363.                                             }, 5);
  2364.                                         };
  2365.                                     }; else {
  2366.                                         if(cPlaylistManager.vscroll_timer) {
  2367.                                             window.ClearInterval(cPlaylistManager.vscroll_timer_loop);
  2368.                                             cPlaylistManager.vscroll_timer_loop = false;
  2369.                                         };
  2370.                                         if(!cPlaylistManager.drag_move_timer) {
  2371.                                             cPlaylistManager.drag_move_timer = window.SetTimeout(function() {
  2372.                                                 if(p.playlistManager.hoverId != p.playlistManager.hoverId_previous) {
  2373.                                                     full_repaint();
  2374.                                                     p.playlistManager.hoverId_previous = p.playlistManager.hoverId;
  2375.                                                 };
  2376.                                                 window.ClearInterval(cPlaylistManager.drag_move_timer);
  2377.                                                 cPlaylistManager.drag_move_timer = false;
  2378.                                             }, 50);
  2379.                                         };
  2380.                                     };
  2381.                                 }; else {
  2382.                                     if(cPlaylistManager.vscroll_timer_loop) {
  2383.                                         window.ClearInterval(cPlaylistManager.vscroll_timer_loop);
  2384.                                         cPlaylistManager.vscroll_timer_loop = false;
  2385.                                     };
  2386.                                 };
  2387.                             };
  2388.                         };
  2389.                     }; else {
  2390.                         // kill timers
  2391.                         if(cPlaylistManager.vscroll_timer_loop) {
  2392.                             window.ClearInterval(cPlaylistManager.vscroll_timer_loop);
  2393.                             cPlaylistManager.vscroll_timer_loop = false;
  2394.                         };
  2395.                     };
  2396.                 };
  2397.                 break;
  2398.             default:
  2399.                 if(this.ishover) {
  2400.                     for(var i = 0; i < this.items.length; i++) {
  2401.                         this.items[i].check(event, x, y);
  2402.                     };
  2403.                 };
  2404.         };
  2405.     };
  2406.    
  2407.     this.incrementalSearch = function() {
  2408.         var count = 0;
  2409.         var albumartist, artist;
  2410.         var chr;
  2411.         var gstart;
  2412.         var pid = -1;
  2413.        
  2414.         // exit if no search string in cache
  2415.         if(cList.search_string.length <= 0) return true;
  2416.        
  2417.         // 1st char of the search string
  2418.         var first_chr = cList.search_string.substring(0,1);  
  2419.         var len = cList.search_string.length;
  2420.        
  2421.         // which start point for the search
  2422.         if(this.count > 1000) {
  2423.             albumartist = tf_albumartist.EvalWithMetadb(this.handleList.Item(Math.floor(this.count / 2)));
  2424.             chr = albumartist.substring(0,1);
  2425.             if(first_chr.charCodeAt(first_chr) > chr.charCodeAt(chr)) {
  2426.                 gstart = Math.floor(this.count / 2);
  2427.             }; else {
  2428.                 gstart = 0;
  2429.             };
  2430.         }; else {
  2431.             gstart = 0;
  2432.         };
  2433.  
  2434.         // 1st search on "album artist" TAG
  2435.         var format_str = "";
  2436.         for(var i=gstart; i < this.count; i++) {
  2437.             albumartist = tf_albumartist.EvalWithMetadb(this.handleList.Item(i));
  2438.             format_str = albumartist.substring(0,len).toUpperCase();
  2439.             if(format_str == cList.search_string) {
  2440.                 pid = i;
  2441.                 break;
  2442.             };
  2443.         };
  2444.        
  2445.         // if not found, search in the first part (from 0 to gstart)
  2446.         if(pid < 0) {
  2447.             var format_str = "";
  2448.             for(var i=0; i < gstart; i++) {
  2449.                 albumartist = tf_albumartist.EvalWithMetadb(this.handleList.Item(i));
  2450.                 format_str = albumartist.substring(0,len).toUpperCase();
  2451.                 if(format_str == cList.search_string) {
  2452.                     pid = i;
  2453.                     break;
  2454.                 };
  2455.             };
  2456.         };
  2457.        
  2458.         if(pid < 0) {
  2459.             // 2nd search on "artist" TAG
  2460.             var format_str = "";
  2461.             for(var i=0; i < this.count; i++) {
  2462.                 artist = tf_artist.EvalWithMetadb(this.handleList.Item(i));
  2463.                 format_str = artist.substring(0,len).toUpperCase();
  2464.                 if(format_str == cList.search_string) {
  2465.                     pid = i;
  2466.                     break;
  2467.                 };
  2468.             };
  2469.         };
  2470.        
  2471.         if(pid >= 0) { // found
  2472.             this.focusedTrackId = pid;
  2473.             plman.ClearPlaylistSelection(this.playlist);
  2474.             plman.SetPlaylistSelectionSingle(this.playlist, this.focusedTrackId, true);
  2475.             plman.SetPlaylistFocusItem(this.playlist, this.focusedTrackId);
  2476.             this.showFocusedItem();
  2477.         }; else { // not found on "album artist" TAG, new search on "artist" TAG
  2478.             cList.inc_search_noresult = true;
  2479.             full_repaint();
  2480.         };
  2481.        
  2482.         cList.clear_incsearch_timer && window.ClearTimeout(cList.clear_incsearch_timer);
  2483.         cList.clear_incsearch_timer = window.SetTimeout(function () {
  2484.             // reset incremental search string after 1 seconds without any key pressed
  2485.             cList.search_string = "";
  2486.             cList.inc_search_noresult = false;
  2487.             full_repaint();
  2488.             window.ClearInterval(cList.clear_incsearch_timer);
  2489.             cList.clear_incsearch_timer = false;
  2490.         }, 1000);
  2491.     };
  2492.  
  2493.     this.context_menu = function(x, y, id, row_id) {
  2494.         var _menu = window.CreatePopupMenu();
  2495.         var Context = fb.CreateContextMenuManager();
  2496.         var _child01 = window.CreatePopupMenu();
  2497.         var _child02 = window.CreatePopupMenu();
  2498.         var _child03 = window.CreatePopupMenu();
  2499.        
  2500.         this.metadblist_selection = plman.GetPlaylistSelectedItems(this.playlist);
  2501.         Context.InitContext(this.metadblist_selection);
  2502.        
  2503.         // check if selection is single and is in the Media Library to provide if ok a link to Album View panel
  2504.         var showInAlbumView = false;
  2505.         if(this.metadblist_selection.Count == 1) {
  2506.             if(fb.IsMetadbInMediaLibrary(this.metadblist_selection.Item(0))) {
  2507.                 showInAlbumView = true;
  2508.                 //_menu.AppendMenuItem(MF_STRING, 3000, "Show in Album View");
  2509.                 //_menu.AppendMenuSeparator();
  2510.             };
  2511.         };
  2512.            
  2513.         _menu.AppendMenuItem(MF_STRING, 1, "Panel Settings...");
  2514.         _menu.AppendMenuSeparator();
  2515.         if(plman.GetPlaybackQueueCount() > 0) {
  2516.             _menu.AppendMenuItem(MF_STRING, 2, "Show playback queue");
  2517.         };
  2518.         Context.BuildMenu(_menu, 3, -1);
  2519.        
  2520.         _child01.AppendTo(_menu, MF_STRING, "Selection...");
  2521.         _child01.AppendMenuItem(fb.IsAutoPlaylist(this.playlist)?MF_DISABLED|MF_GRAYED:MF_STRING, 1010, "Remove");
  2522.         _child02.AppendTo(_child01, MF_STRING, "Add to...");
  2523.         _child03.AppendTo(_child01, MF_STRING, "Send to...");
  2524.         _child03.AppendMenuItem(MF_STRING, 4000, "a New playlist...");
  2525.  
  2526.         var pl_count = plman.PlaylistCount;
  2527.        
  2528.         if(plman.PlaylistCount>1) {
  2529.             _child03.AppendMenuItem(MF_SEPARATOR, 0, "");
  2530.         };
  2531.         for(var i=0;i<pl_count;i++) {
  2532.             if(i!=this.playlist && !fb.IsAutoPlaylist(i)) {
  2533.                 _child02.AppendMenuItem(MF_STRING, 2001+i, plman.GetPlaylistName(i));
  2534.                 _child03.AppendMenuItem(MF_STRING, 4001+i, plman.GetPlaylistName(i));
  2535.             };
  2536.         };
  2537.  
  2538.         var ret = _menu.TrackPopupMenu(x, y);
  2539.         if(ret > 2 && ret < 800) {
  2540.             Context.ExecuteByID(ret - 3);
  2541.         }; else if(ret<3) {
  2542.             switch (ret) {
  2543.             case 1:
  2544.                 p.settings.currentPageId = 0;
  2545.                 cSettings.visible = true;
  2546.                 full_repaint();
  2547.                 break;
  2548.             case 2:
  2549.                 plman.ActivePlaylist = isQueuePlaylistPresent();
  2550.                 break;
  2551.             };
  2552.         }; else {
  2553.             switch (true) {
  2554.             case (ret==1000):
  2555.                 //window.NotifyOthers("ASK_albumView_showItem", this.metadblist_selection.Item(0));
  2556.                 break;
  2557.             case (ret==1010):
  2558.                 plman.RemovePlaylistSelection(this.playlist, false);
  2559.                 break;
  2560.             case (ret==4000):
  2561.                 fb.RunMainMenuCommand("File/New playlist");
  2562.                 plman.InsertPlaylistItems(plman.PlaylistCount-1, 0, this.metadblist_selection, false);
  2563.                 break;
  2564.             case (ret>2000 && ret <4000):
  2565.                 var insert_index = plman.PlaylistItemCount(ret-2001);
  2566.                 plman.InsertPlaylistItems((ret-2001), insert_index, this.metadblist_selection, false);
  2567.                 if(cPlaylistManager.visible) full_repaint();
  2568.                 break;
  2569.             case (ret>4000):
  2570.                 var insert_index = 0;
  2571.                 var pl_name = plman.GetPlaylistName(ret-4001);
  2572.                 g_avoid_on_playlists_changed = true;
  2573.                 plman.RemovePlaylist(ret-4001);
  2574.                 plman.CreatePlaylist(ret-4001, pl_name);
  2575.                 g_avoid_on_playlists_changed = false;
  2576.                 plman.InsertPlaylistItems((ret-4001), insert_index, this.metadblist_selection, false);
  2577.                 if(cPlaylistManager.visible) full_repaint();
  2578.                 break;
  2579.             };
  2580.         };
  2581.         _child01.Dispose();
  2582.         _child02.Dispose();
  2583.         _menu.Dispose();
  2584.         return true;
  2585.     };
  2586. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement