// *****************************************************************************************************************************************
// scrollbar & scrollBar object by Br3tt aka Falstaff (c)2015
// *****************************************************************************************************************************************

oScrollbar = function (themed) {
	this.themed = themed;
	if (themed) {
		this.theme = window.CreateThemeManager("scrollbar");
	} else {
		this.theme = false;
	};
	this.cursorScrollTimer = false;
	this.buttons = Array(null, null, null);

	this.draw = function (gr, x, y) {
		// draw background and buttons up & down
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(6, 1);
				this.theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);
			} catch (e) {
				gr.FillSolidRect(this.x, this.y, this.w, this.h, g_color_normal_txt & 0x15ffffff);
			};
		} else {
			gr.FillSolidRect(this.x, this.y, this.w, this.h, g_color_normal_txt & 0x15ffffff);
		};
		// draw up & down buttons
		this.buttons[cScrollBar.buttonType.up] && this.buttons[cScrollBar.buttonType.up].draw(gr, this.x, this.y, 255);
		this.buttons[cScrollBar.buttonType.down] && this.buttons[cScrollBar.buttonType.down].draw(gr, this.x, this.y + this.h - this.w, 255);

		// draw cursor
		this.buttons[cScrollBar.buttonType.cursor] && this.buttons[cScrollBar.buttonType.cursor].draw(gr, this.x, this.cursorPos, 255);
	};

	this.setCursor = function (totalRowVisible, totalRows, offset) {
		if (totalRows > 0 && totalRows > totalRowVisible && this.w > 2) {
			this.cursorWidth = this.w;
			// calc cursor height
			this.cursorHeight = Math.round((totalRowVisible / totalRows) * this.area_h);
			if (this.cursorHeight < this.w - 2 || this.cursorHeight > p.list.h)
				this.cursorHeight = this.w - 2;
			// cursor pos
			var ratio = offset / (totalRows - totalRowVisible);
			this.cursorPos = this.area_y + Math.round((this.area_h - this.cursorHeight) * ratio);
			this.setCursorButton();
		};
	};

	this.setCursorButton = function () {
		// normal cursor Image
		this.cursorImage_normal = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		var gb = this.cursorImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(3, 1);
			this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			if (this.cursorHeight >= 16) {
				this.theme.SetPartAndStateId(9, 1);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			};
		} catch (e) {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x33ffffff);
		};
		this.cursorImage_normal.ReleaseGraphics(gb);

		// hover cursor Image
		this.cursorImage_hover = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		gb = this.cursorImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(3, 2);
			this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			if (this.cursorHeight >= 16) {
				this.theme.SetPartAndStateId(9, 1);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			};
		} catch (e) {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x55ffffff);
		};
		this.cursorImage_hover.ReleaseGraphics(gb);

		// down cursor Image
		this.cursorImage_down = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		gb = this.cursorImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(3, 3);
			this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			if (this.cursorHeight >= 16) {
				this.theme.SetPartAndStateId(9, 1);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
			};
		} catch (e) {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, g_color_normal_txt & 0x99ffffff);
		};
		this.cursorImage_down.ReleaseGraphics(gb);

		// create/refresh cursor Button in buttons array
		this.buttons[cScrollBar.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
	};

	this.setButtons = function () {

		// normal scroll_up Image
		this.upImage_normal = gdi.CreateImage(this.w, this.w);
		var gb = this.upImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 1);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_normal.ReleaseGraphics(gb);

		// hover scroll_up Image
		this.upImage_hover = gdi.CreateImage(this.w, this.w);
		gb = this.upImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 2);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_hover.ReleaseGraphics(gb);

		// down scroll_up Image
		this.upImage_down = gdi.CreateImage(this.w, this.w);
		gb = this.upImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 3);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, g_color_normal_txt, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_down.ReleaseGraphics(gb);

		// normal scroll_down Image
		this.downImage_normal = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 5);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_normal.ReleaseGraphics(gb);

		// hover scroll_down Image
		this.downImage_hover = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 6);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_hover.ReleaseGraphics(gb);

		// down scroll_down Image
		this.downImage_down = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		try {
			this.theme.SetPartAndStateId(1, 7);
			this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
		} catch (e) {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, g_color_normal_txt, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_down.ReleaseGraphics(gb);

		var fin = this.buttons.length;
		for (i = 1; i < fin; i++) {
			switch (i) {
			case cScrollBar.buttonType.cursor:
				this.buttons[cScrollBar.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
				break;
			case cScrollBar.buttonType.up:
				this.buttons[cScrollBar.buttonType.up] = new button(this.upImage_normal, this.upImage_hover, this.upImage_down);
				break;
			case cScrollBar.buttonType.down:
				this.buttons[cScrollBar.buttonType.down] = new button(this.downImage_normal, this.downImage_hover, this.downImage_down);
				break;
			};
		};
	};

	this.setSize = function (x, y, w, h) {
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
		// scrollbar area for the cursor (<=> scrollbar height minus up & down buttons height)
		this.area_y = y + w;
		this.area_h = h - (w * 2);
		this.setButtons();
	};

	this.setOffsetFromCursorPos = function () {
		// calc ratio of the scroll cursor to calc the equivalent item for the full playlist (with gh)
		var ratio = (this.cursorPos - this.area_y) / (this.area_h - this.cursorHeight);
		// calc idx of the item (of the full playlist with gh) to display at top of the panel list (visible)
		var newOffset = Math.round((p.list.totalRows - p.list.totalRowVisible) * ratio);
		return newOffset;
	};

	this.cursorCheck = function (event, x, y) {
		this.ishover = (x >= this.x && x <= this.x + this.w && y >= this.cursorPos && y <= (this.cursorPos + this.cursorHeight));

		switch (event) {
		case "down":
			this.buttons[0] && this.buttons[0].checkstate(event, x, y);
			if (this.ishover) {
				this.cursorClickX = x;
				this.cursorClickY = y;
				this.cursorDrag = true;
				this.cursorDragDelta = y - this.cursorPos;
				this.clicked = true;
			};
			break;
		case "up":
			this.buttons[0] && this.buttons[0].checkstate(event, x, y);
			if (this.cursorDrag) {
				p.list.offset = this.setOffsetFromCursorPos();
				p.list.setItems(false);
				full_repaint();
			};
			this.cursorClickX = 0;
			this.cursorClickY = 0;
			this.cursorDrag = false;
			this.clicked = false;
			break;
		case "move":
			this.buttons[0] && this.buttons[0].checkstate(event, x, y);
			if (this.cursorDrag) {
				this.cursorPos = y - this.cursorDragDelta;
				if (this.cursorPos + this.cursorHeight > this.area_y + this.area_h) {
					this.cursorPos = (this.area_y + this.area_h) - this.cursorHeight;
				};
				if (this.cursorPos < this.area_y) {
					this.cursorPos = this.area_y;
				};

				p.list.offset = this.setOffsetFromCursorPos();
				if (!g_mouse_wheel_timer) {
					g_mouse_wheel_timer = window.SetTimeout(function () {
							p.list.setItems(false);
							full_repaint();
							g_mouse_wheel_timer && window.ClearTimeout(g_mouse_wheel_timer);
							g_mouse_wheel_timer = false;
						}, 30);
				};
			};
			break;
		case "leave":
			this.buttons[0] && this.buttons[0].checkstate(event, x, y);
			break;
		};
	};

	this.isHoverObject = function (x, y) {
		return (x >= this.x && x <= this.x + this.w && y > this.area_y && y < this.area_y + this.area_h);
	};

	this.check = function (event, x, y) {

		this.hover = this.isHoverObject(x, y);

		// check cursor
		this.cursorCheck(event, x, y);

		// check other buttons
		var fin = this.buttons.length;
		for (var i = 1; i < fin; i++) {
			switch (event) {
			case "dblclk":
				switch (i) {
				case 1: // up button
					if (this.buttons[i] && this.buttons[i].checkstate(event, x, y) == ButtonStates.hover) {
						this.clicked = true;
						p.list.buttonclicked = true;
						this.buttons[i].checkstate("down", x, y);

						p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
						p.list.setItems(false);
						p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
						if (properties.smoothscrolling) {
							cList.scroll_direction = 1;
							set_scroll_delta();
						};
						full_repaint();
						if (!cScrollBar.timerID2) {
							cScrollBar.timerID2 = window.SetInterval(function () {
									cScrollBar.timer_counter++;
									if (cScrollBar.timer_counter > 7) {
										p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
										p.list.setItems(false);
										p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
										full_repaint();
									};
								}, 60);
						};
					};
					break;
				case 2: // down button
					if (this.buttons[i] && this.buttons[i].checkstate(event, x, y) == ButtonStates.hover) {
						this.clicked = true;
						p.list.buttonclicked = true;
						this.buttons[i].checkstate("down", x, y);

						p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
						p.list.setItems(false);
						p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
						if (properties.smoothscrolling) {
							cList.scroll_direction = -1;
							set_scroll_delta();
						};
						full_repaint();
						if (!cScrollBar.timerID2) {
							cScrollBar.timerID2 = window.SetInterval(function () {
									cScrollBar.timer_counter++;
									if (cScrollBar.timer_counter > 7) {
										p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
										p.list.setItems(false);
										p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
										full_repaint();
									};
								}, 60);
						};
					};
					break;
				};
				break;
			case "down":
				switch (i) {
				case 1: // up button
					if (this.buttons[i] && this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
						this.clicked = true;
						p.list.buttonclicked = true;
						cScrollBar.timer_counter = 0;
						p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
						p.list.setItems(false);
						p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
						if (properties.smoothscrolling) {
							cList.scroll_direction = 1;
							set_scroll_delta();
						};
						full_repaint();
						if (!cScrollBar.timerID2) {
							cScrollBar.timerID2 = window.SetInterval(function () {
									cScrollBar.timer_counter++;
									if (cScrollBar.timer_counter > 7) {
										p.list.offset = p.list.offset > 0 ? p.list.offset - 1 : 0;
										p.list.setItems(false);
										p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
										full_repaint();
									};
								}, 60);
						};
					};
					break;
				case 2: // down button
					if (this.buttons[i] && this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
						this.clicked = true;
						p.list.buttonclicked = true;
						cScrollBar.timer_counter = 0;
						p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
						p.list.setItems(false);
						p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
						if (properties.smoothscrolling) {
							cList.scroll_direction = -1;
							set_scroll_delta();
						};
						full_repaint();
						if (!cScrollBar.timerID2) {
							cScrollBar.timerID2 = window.SetInterval(function () {
									cScrollBar.timer_counter++;
									if (cScrollBar.timer_counter > 7) {
										p.list.offset = p.list.offset >= (p.list.totalRows - p.list.totalRowVisible) ? (p.list.totalRows - p.list.totalRowVisible) : p.list.offset + 1;
										p.list.setItems(false);
										p.scrollbar.setCursor(p.list.totalRowVisible, p.list.totalRows, p.list.offset);
										full_repaint();
									};
								}, 60);
						};
					};
					break;
				};
				break;
			case "up":
				if (cScrollBar.timerID2) {
					window.ClearInterval(cScrollBar.timerID2);
					cScrollBar.timerID2 = false;
				};
				cScrollBar.timer_counter = 0;
				this.buttons[i] && this.buttons[i].checkstate(event, x, y);
				this.clicked = false;
				break;
			default:
				this.buttons[i] && this.buttons[i].checkstate(event, x, y);
			};
		};
	};
	this.repaint = function () {
		window.RepaintRect(this.x, this.y, this.w, this.h);
	};
};

oScrollBar = function (id, object_name, x, y, w, h, total_items, item_height, offset, parent_object, show_buttons, scroll_step, is_themed) {
	this.id = id;
	this.objectName = object_name;
	this.x = x;
	this.y = y;
	this.w = w;
	this.h = h;
	this.total = total_items;
	this.itemHeight = item_height;
	this.offset = offset;
	this.parentObject = parent_object;
	this.buttons = Array(null, null, null);
	this.buttonType = {
		cursor: 0,
		up: 1,
		down: 2
	};
	this.showButtons = show_buttons;
	this.scrollStep = scroll_step;
	this.themed = is_themed;
	if (this.themed) {
		this.theme = window.CreateThemeManager("scrollbar");
	} else {
		this.theme = false;
	};

	this.parentRepaint = function () {
		eval(this.parentObject).repaint();
		//window.Repaint();
	};

	this.repaint = function () {
		window.RepaintRect(this.x, this.y, this.w, this.h);
	};

	this.setCursorButton = function () {
		// normal cursor Image
		this.cursorImage_normal = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		var gb = this.cursorImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(3, 1);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				if (this.cursorHeight >= 25) {
					this.theme.SetPartAndStateId(9, 1);
					this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				};
			} catch (e) {
				gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x33ffffff);
			};
		} else {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x33ffffff);
		};
		this.cursorImage_normal.ReleaseGraphics(gb);

		// hover cursor Image
		this.cursorImage_hover = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		gb = this.cursorImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(3, 2);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				if (this.cursorHeight >= 25) {
					this.theme.SetPartAndStateId(9, 1);
					this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				};
			} catch (e) {
				gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x55ffffff);
			};
		} else {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x55ffffff);
		};
		this.cursorImage_hover.ReleaseGraphics(gb);

		// down cursor Image
		this.cursorImage_down = gdi.CreateImage(this.cursorWidth, this.cursorHeight);
		gb = this.cursorImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(3, 3);
				this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				if (this.cursorHeight >= 25) {
					this.theme.SetPartAndStateId(9, 1);
					this.theme.DrawThemeBackground(gb, 0, 0, this.cursorWidth, this.cursorHeight);
				};
			} catch (e) {
				gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x99ffffff);
			};
		} else {
			gb.FillSolidRect(0, 0, this.cursorWidth, this.cursorHeight, this.color_txt & 0x99ffffff);
		};
		this.cursorImage_down.ReleaseGraphics(gb);

		// create/refresh cursor Button in buttons array
		this.buttons[this.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
	};

	this.setButtons = function () {
		// normal scroll_up Image
		this.upImage_normal = gdi.CreateImage(this.w, this.w);
		var gb = this.upImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 1);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_normal.ReleaseGraphics(gb);

		// hover scroll_up Image
		this.upImage_hover = gdi.CreateImage(this.w, this.w);
		gb = this.upImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 2);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_hover.ReleaseGraphics(gb);

		// down scroll_up Image
		this.upImage_down = gdi.CreateImage(this.w, this.w);
		gb = this.upImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 3);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(112), g_font_wd3_scrollBar, this.color_txt, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.upImage_down.ReleaseGraphics(gb);

		// normal scroll_down Image
		this.downImage_normal = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_normal.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 5);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt & 0x55ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_normal.ReleaseGraphics(gb);

		// hover scroll_down Image
		this.downImage_hover = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_hover.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 6);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt & 0x99ffffff, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_hover.ReleaseGraphics(gb);

		// down scroll_down Image
		this.downImage_down = gdi.CreateImage(this.w, this.w);
		gb = this.downImage_down.GetGraphics();
		// Draw Themed Scrollbar (lg/col)
		if (this.themed) {
			try {
				this.theme.SetPartAndStateId(1, 7);
				this.theme.DrawThemeBackground(gb, 0, 0, this.w, this.w);
			} catch (e) {
				gb.SetTextRenderingHint(4);
				gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt, 0, 0, this.w, this.w, cc_stringformat);
			};
		} else {
			gb.SetTextRenderingHint(4);
			gb.DrawString(String.fromCharCode(113), g_font_wd3_scrollBar, this.color_txt, 0, 0, this.w, this.w, cc_stringformat);
		};
		this.downImage_down.ReleaseGraphics(gb);

		for (i = 1; i < this.buttons.length; i++) {
			switch (i) {
			case this.buttonType.cursor:
				this.buttons[this.buttonType.cursor] = new button(this.cursorImage_normal, this.cursorImage_hover, this.cursorImage_down);
				break;
			case this.buttonType.up:
				this.buttons[this.buttonType.up] = new button(this.upImage_normal, this.upImage_hover, this.upImage_down);
				break;
			case this.buttonType.down:
				this.buttons[this.buttonType.down] = new button(this.downImage_normal, this.downImage_hover, this.downImage_down);
				break;
			};
		};
	};

	this.setDefaultColors = function () {
		this.color_bg = g_color_normal_bg;
		this.color_txt = g_color_normal_txt;
		if (this.cursorHeight)
			this.setCursorButton();
		this.setButtons();
	};
	this.setDefaultColors();

	this.setCustomColors = function (color_bg, color_txt) {
		this.color_bg = color_bg;
		this.color_txt = color_txt;
		if (this.cursorHeight)
			this.setCursorButton();
		this.setButtons();
	};

	this.updateCursorPos = function (offset) {
		this.offset = offset;
		// calc cursor position and height / offset
		this.ratio1 = this.totalRowsFull / this.total;
		this.cursorWidth = this.w;
		this.cursorHeight = Math.round(this.ratio1 * this.cursorAreaHeight);
		if (this.cursorHeight < this.w - 2 || this.cursorHeight > p.list.h)
			this.cursorHeight = this.w - 2;
		var ratio2 = this.offset / (this.total - this.totalRowsFull);
		this.cursorY = this.cursorAreaY + Math.round((this.cursorAreaHeight - this.cursorHeight) * ratio2);
		this.setCursorButton();
	};

	this.reSet = function (total_items, item_height, offset) {
		this.total = total_items;
		this.itemHeight = item_height;
		this.offset = offset;
		//
		this.setButtons();
		this.totalRowsFull = Math.floor(this.h / this.itemHeight);
		this.totalRowsVisibles = Math.ceil(this.h / this.itemHeight);
		this.visible = (this.total > this.totalRowsFull);
		if (this.showButtons) {
			this.buttonHeight = this.buttons[this.buttonType.up].h;
			this.cursorAreaY = this.y + this.buttonHeight;
			this.cursorAreaHeight = this.h - (this.buttonHeight * 2);
		} else {
			this.buttonHeight = 0;
			this.cursorAreaY = this.y;
			this.cursorAreaHeight = this.h;
		};
		if (this.visible)
			this.updateCursorPos(this.offset);

	};
	this.reSet(this.total, this.itemHeight, this.offset);

	this.reSize = function (x, y, w, h, total_items, item_height, offset) {
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
		this.total = total_items;
		this.itemHeight = item_height;
		this.offset = offset;
		this.reSet(this.total, this.itemHeight, this.offset);
	};

	this.drawXY = function (gr, x, y) {
		this.x = x;
		this.y = y;
		if (this.visible) {
			// scrollbar background
			if (this.themed) {
				try {
					this.theme.SetPartAndStateId(6, 1);
					this.theme.DrawThemeBackground(gr, x, y, this.w, this.h);
				} catch (e) {
					gr.FillSolidRect(this.x, this.y, this.w, this.h, this.color_txt & 0x15ffffff);
				};
			} else {
				gr.FillSolidRect(this.x, this.y, this.w, this.h, this.color_txt & 0x15ffffff);
			};
			// scrollbar buttons
			this.buttons[this.buttonType.cursor].draw(gr, x, this.cursorY, 255);
			if (this.showButtons) {
				this.buttons[this.buttonType.up].draw(gr, x, y, 255);
				this.buttons[this.buttonType.down].draw(gr, x, this.cursorAreaY + this.cursorAreaHeight, 255);
			};
		};
	};

	this.draw = function (gr) {
		if (this.visible) {
			// scrollbar background
			if (this.themed) {
				try {
					this.theme.SetPartAndStateId(6, 1);
					this.theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);
				} catch (e) {
					gr.FillSolidRect(this.x, this.y, this.w, this.h, this.color_txt & 0x15ffffff);
				};
			} else {
				gr.FillSolidRect(this.x, this.y, this.w, this.h, this.color_txt & 0x15ffffff);
			};
			// scrollbar buttons
			this.buttons[this.buttonType.cursor].draw(gr, this.x, this.cursorY, 255);
			if (this.showButtons) {
				this.buttons[this.buttonType.up].draw(gr, this.x, this.y, 255);
				this.buttons[this.buttonType.down].draw(gr, this.x, this.cursorAreaY + this.cursorAreaHeight, 255);
			};
		};
	};

	this.getOffsetFromCursorPos = function () {
		// calc ratio of the scroll cursor to calc the equivalent item for the full playlist (with gh)
		var ratio = (this.cursorY - this.cursorAreaY) / (this.cursorAreaHeight - this.cursorHeight);
		// calc idx of the item (of the full list with gh) to display at top of the panel list (visible)
		var newOffset = Math.round((this.total - this.totalRowsFull) * ratio);
		return newOffset;
	};

	this.setCursorPosFromOffset = function () {
		return;
		this.cursorY = Math.round((this.y + this.buttonHeight) + this.offset * (this.cursorAreaHeight / this.total));
		if (this.cursorY + this.cursorHeight > this.cursorAreaY + this.cursorAreaHeight) {
			this.cursorY = (this.cursorAreaY + this.cursorAreaHeight) - this.cursorHeight;
		};
		if (this.cursorY < this.cursorAreaY) {
			this.cursorY = this.cursorAreaY;
		};
	};

	this.cursorCheck = function (event, x, y) {
		this.ishover = (x >= this.x && x <= this.x + this.w && y >= this.cursorY && y <= (this.cursorY + this.cursorHeight));

		if (!this.buttons[this.buttonType.cursor])
			return;

		switch (event) {
		case "down":
			if (this.buttons[this.buttonType.cursor].checkstate(event, x, y) == ButtonStates.down) {
				this.cursorClickX = x;
				this.cursorClickY = y;
				this.cursorDrag = true;
				this.cursorDragDelta = y - this.cursorY;
			};
			break;
		case "up":
			this.buttons[this.buttonType.cursor].checkstate(event, x, y);
			if (this.cursorDrag) {
				eval(this.parentObject).offset = this.getOffsetFromCursorPos();
				this.setCursorPosFromOffset();
				this.parentRepaint();
			};
			this.cursorClickX = 0;
			this.cursorClickY = 0;
			this.cursorDrag = false;
			break;
		case "move":
			this.buttons[this.buttonType.cursor].checkstate(event, x, y);
			if (this.cursorDrag) {
				this.cursorY = y - this.cursorDragDelta;
				if (this.cursorY + this.cursorHeight > this.cursorAreaY + this.cursorAreaHeight) {
					this.cursorY = (this.cursorAreaY + this.cursorAreaHeight) - this.cursorHeight;
				};
				if (this.cursorY < this.cursorAreaY) {
					this.cursorY = this.cursorAreaY;
				};
				this.offset = this.getOffsetFromCursorPos();
				eval(this.parentObject).offset = this.offset;

				if (!cScrollBar.timer_repaint) {
					cScrollBar.timer_repaint = window.SetTimeout(function () {
							//this.parentRepaint();
							full_repaint();
							window.ClearTimeout(cScrollBar.timer_repaint);
							cScrollBar.timer_repaint = false;
						}, 32);
				};
			};
			break;
		case "leave":
			this.buttons[this.buttonType.cursor].checkstate(event, x, y);
			break;
		};
	};

	this.check = function (event, x, y, delta) {

		this.isHoverScrollbar = (x >= this.x && x <= this.x + this.w && y >= this.y && y <= this.y + this.h);
		this.isHoverCursor = (x >= this.x && x <= this.x + this.w && y >= this.cursorY && y <= this.cursorY + this.cursorHeight);
		this.isHoverEmptyArea = (x >= this.x && x <= this.x + this.w && y >= this.y + this.buttonHeight && y <= this.cursorAreaY + this.cursorAreaHeight) && !this.isHoverCursor;
		this.isHoverButtons = this.isHoverScrollbar && !this.isHoverCursor && !this.isHoverEmptyArea;

		// cursor events
		if (!this.buttonClick)
			this.cursorCheck(event, x, y);

		if (!this.cursorDrag) {
			// buttons events
			var totalButtonToCheck = (this.themed ? 3 : 3);
			for (var i = 1; i < totalButtonToCheck; i++) {
				switch (event) {
				case "down":
					switch (i) {
					case 1: // up button
						if (this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
							this.buttonClick = true;
							this.offset = this.offset > 0 ? this.offset - 1 : 0;
							eval(this.parentObject).offset = this.offset;
							this.updateCursorPos(this.offset);
							this.parentRepaint();
							cScrollBar.obj = eval(this.objectName);
							if (!cScrollBar.timerID) {
								cScrollBar.timerID = window.SetInterval(function () {
										if (cScrollBar.timerCounter > 7) {
											var obj = cScrollBar.obj;
											obj.offset = obj.offset > 0 ? obj.offset - 1 : 0;
											eval(obj.parentObject).offset = obj.offset;
											obj.updateCursorPos(obj.offset);
											obj.parentRepaint();
										} else {
											cScrollBar.timerCounter++;
										};
									}, 60);
							};
						};
						break;
					case 2: // down button
						if (this.buttons[i].checkstate(event, x, y) == ButtonStates.down) {
							this.buttonClick = true;
							var max_offset = this.total - this.totalRowsFull;
							this.offset = (this.offset + 1 >= max_offset ? max_offset : this.offset + 1);
							eval(this.parentObject).offset = this.offset;
							this.updateCursorPos(this.offset);
							this.parentRepaint();
							cScrollBar.obj = eval(this.objectName);
							if (!cScrollBar.timerID) {
								cScrollBar.timerID = window.SetInterval(function () {
										if (cScrollBar.timerCounter > 7) {
											var obj = cScrollBar.obj;
											var max_offset = obj.total - obj.totalRowsFull;
											obj.offset = (obj.offset + 1 >= max_offset ? max_offset : obj.offset + 1);
											eval(obj.parentObject).offset = obj.offset;
											obj.updateCursorPos(obj.offset);
											obj.parentRepaint();
										} else {
											cScrollBar.timerCounter++;
										};
									}, 60);
							};
						};
						break;
					};
					break;
				case "up":
					this.buttonClick = false;
					if (cScrollBar.timerID) {
						window.ClearInterval(cScrollBar.timerID);
						cScrollBar.timerID = false;
					};
					cScrollBar.timerCounter = 0;
					this.buttons[i].checkstate(event, x, y);
					this.setCursorPosFromOffset();
					break;
				default:
					this.buttons[i].checkstate(event, x, y);
				};
			};

			// click on empty scrollbar area to scroll page
			if (this.isHoverEmptyArea) {
				switch (event) {
				case "down":
				case "dblclk":
					switch (y < this.cursorY) {
					case true: // up
						this.offset = this.offset > this.totalRowsFull ? this.offset - this.totalRowsFull : 0;
						eval(this.parentObject).offset = this.offset;
						this.reSet(this.total, this.itemHeight, this.offset);
						this.parentRepaint();
						cScrollBar.obj = eval(this.objectName);
						if (!cScrollBar.timerID) {
							cScrollBar.timerID = window.SetInterval(function () {
									var obj = cScrollBar.obj;
									if (cScrollBar.timerCounter > 7 && mouse_y < obj.cursorY) {
										obj.offset = obj.offset > obj.totalRowsFull ? obj.offset - obj.totalRowsFull : 0;
										eval(obj.parentObject).offset = obj.offset;
										obj.reSet(obj.total, obj.itemHeight, obj.offset);
										obj.parentRepaint();
									} else {
										cScrollBar.timerCounter++;
									};
								}, 60);
						};
						break;
					case false: // down
						var max_offset = this.total - this.totalRowsFull;
						this.offset = (this.offset + this.totalRowsFull >= max_offset ? max_offset : this.offset + this.totalRowsFull);
						eval(this.parentObject).offset = this.offset;
						this.reSet(this.total, this.itemHeight, this.offset);
						this.parentRepaint();
						cScrollBar.obj = eval(this.objectName);
						if (!cScrollBar.timerID) {
							cScrollBar.timerID = window.SetInterval(function () {
									var obj = cScrollBar.obj;
									if (cScrollBar.timerCounter > 7 && mouse_y > obj.cursorY + obj.cursorHeight) {
										var max_offset = obj.total - obj.totalRowsFull;
										obj.offset = (obj.offset + obj.totalRowsFull >= max_offset ? max_offset : obj.offset + obj.totalRowsFull);
										eval(obj.parentObject).offset = obj.offset;
										obj.reSet(obj.total, obj.itemHeight, obj.offset);
										obj.parentRepaint();
									} else {
										cScrollBar.timerCounter++;
									};
								}, 60);
						};
						break;
					};
					break;
				};
			};

			// mouse wheel event
			if (event == "wheel") {
				if (delta > 0) {
					this.offset = this.offset > this.scrollStep ? this.offset - this.scrollStep : 0;
					eval(this.parentObject).offset = this.offset;
					this.reSet(this.total, this.itemHeight, this.offset);
					this.parentRepaint();
				} else {
					this.offset = (this.offset < (this.total - this.totalRowsFull - this.scrollStep) ? (this.offset + this.scrollStep) : (this.total - this.totalRowsFull));
					eval(this.parentObject).offset = this.offset;
					this.reSet(this.total, this.itemHeight, this.offset);
					this.parentRepaint();
				};
			};
		};
	};

	this.on_key = function (event, vkey) {
		switch (event) {
		case "down":
			switch (vkey) {
			case VK_DOWN:
				var max_offset = this.total - this.totalRowsFull;
				this.offset = (this.offset + 1 >= max_offset ? max_offset : this.offset + 1);
				eval(this.parentObject).offset = this.offset;
				this.updateCursorPos(this.offset);
				this.parentRepaint();
				cScrollBar.obj = eval(this.objectName);
				if (!cScrollBar.timerID) {
					cScrollBar.timerID = window.SetInterval(function () {
							if (cScrollBar.timerCounter > 7) {
								var obj = cScrollBar.obj;
								var max_offset = obj.total - obj.totalRowsFull;
								obj.offset = (obj.offset + 1 >= max_offset ? max_offset : obj.offset + 1);
								eval(obj.parentObject).offset = obj.offset;
								obj.updateCursorPos(obj.offset);
								obj.parentRepaint();
							} else {
								cScrollBar.timerCounter++;
							};
						}, 60);
				};
				break;
			case VK_UP:
				this.offset = this.offset > 0 ? this.offset - 1 : 0;
				eval(this.parentObject).offset = this.offset;
				this.updateCursorPos(this.offset);
				this.parentRepaint();
				cScrollBar.obj = eval(this.objectName);
				if (!cScrollBar.timerID) {
					cScrollBar.timerID = window.SetInterval(function () {
							if (cScrollBar.timerCounter > 7) {
								var obj = cScrollBar.obj;
								obj.offset = obj.offset > 0 ? obj.offset - 1 : 0;
								eval(obj.parentObject).offset = obj.offset;
								obj.updateCursorPos(obj.offset);
								obj.parentRepaint();
							} else {
								cScrollBar.timerCounter++;
							};
						}, 60);
				};
				break;
			};
			break;
		case "up":
			if (cScrollBar.timerID) {
				window.ClearInterval(cScrollBar.timerID);
				cScrollBar.timerID = false;
			};
			cScrollBar.timerCounter = 0;
			break;
		};
	};

	this.on_char = function (code) {};

	this.on_focus = function (is_focused) {};
};
