//all the gui stuff that's not specifically the webchemy instance
//not really ideal right now
//requires: lib.js
var UI = {};

(function() {
	"use strict";
	
	
	/*UI.theme
	Defining grid size, colors, tile coordinates, etc. for all the UI elements
	*/
    UI.theme = {
        halfBoxSize: 22,
        barCol: "#666",
        expandCol: "#444",
        bgCol: "#444",
        textColor: "#fff",
        labelColor: "#ccc",
        linkColor: "#83d1e9",
        linkHoverColor: "#b2edff",
        opacityOff: 0.4,
        buttonSVG: "icons.svg",
        svgGrid: [ //name, i, e
			["btn_undo.svg", 0, 0],
            ["btn_redo.svg", 1, 0],
            ["btn_hand.svg", 2, 0],
            ["btn_zoomIn.svg", 3, 0],
            ["btn_zoomOut.svg", 4, 0],
            ["btn_resetView.svg", 5, 0],
            ["btn_fitView.svg", 6, 0],
            ["btn_help.svg", 3, 1],
            ["btn_brushFill.svg", 6, 1],
            ["btn_brushStroke.svg", 0, 2],
            ["btn_more.svg", 2, 2],
            ["btn_export.svg", 4, 2],
            ["btn_load.svg", 5, 3],
            ["btn_save.svg", 6, 3],
            ["btn_fill.svg", 5, 2],
            ["btn_stroke.svg", 6, 2],
            ["btn_pull.svg", 5, 1],
            ["btn_gradientUp.svg", 0, 1],
            ["btn_flipHor.svg", 1, 1],
            ["btn_flipVert.svg", 2, 1],
            ["btn_splat.svg", 4, 1],
            ["btn_picker.svg", 0, 3],
            ["btn_swatch.svg", 1, 3],
            ["btn_colSlider.svg", 2, 3],
            ["btn_previous.svg", 3, 3],
            ["btn_next.svg", 4, 3]
        ]
    };
	
	
	
	
	/*UI.spawnMessage(msg, parent)
	Creates a bar (within the parent) that comes down from the top with a message, and stays there until you
	remove it.
	msg - message to be displayed
	parent - parent of div containing message
	Returns function you need to call in order to remove the bar/message
	*/
    UI.spawnMessage = (function () {
        return function (msg, parent) {
            var div, bar, prnt, removed;
            div = document.createElement("div");
            bar = document.createElement("div");
            LIB.css(div, {
                position: "absolute",
                left: 0,
                top: 0,
                width: "100%",
                pointerEvents: "none"
            });
            LIB.css(bar, {
                marginLeft: "auto",
                marginRight: "auto",
                width: (UI.theme.halfBoxSize * 2 * 7) + "px",
                height: (UI.theme.halfBoxSize * 2) + "px",
                background: "rgba(0, 0, 0, 0.5)",
                transition: "margin 0.1s ease-out",
                marginTop: (-UI.theme.halfBoxSize * 2) + "px",
                opacity: 0.8,
                fontWeight: "bold",
                textAlign: "center",
                borderBottomRightRadius: (UI.theme.halfBoxSize / 3) + "px",
                borderBottomLeftRadius: (UI.theme.halfBoxSize / 3) + "px",
                color: "#fff",
                fontFamily: "arial",
                fontSize: (UI.theme.halfBoxSize * 2 / 3.0) + "px",
                lineHeight: (UI.theme.halfBoxSize * 2) + "px"
            });
            bar.innerHTML = msg;
            div.appendChild(bar);
            prnt = document.body;
            if (parent) {
                prnt = parent;
            }
            removed = false;
            prnt.appendChild(div);
            setTimeout(function () {
                LIB.css(bar, {
                    marginTop: 0
                });

            }, 10);
            return function () {
                if (!removed) {
                    removed = true;
                    prnt.removeChild(div);
                }
            };
        };
    }());
	
	
	/*UI.spawnGlow(x, y, parent)
	Animates a glow effect, useful for touch events (good visual feedback). The effect div
	will be automatically disposed.
	x, y - absolute coordinates where it should be placed
	parent - parent of the glow effect div
	*/
    UI.spawnGlow = (function () {
        //preload glowing effect
        var imCount, imArr;
        imCount = 0;
        imArr = [];
        imArr[0] = new Image();
        imArr[0].src = "glow.png";
        imArr[1] = new Image();
        imArr[1].src = "glow.png";
        imArr[2] = new Image();
        imArr[2].src = "glow.png";
        return function (x, y, parent) {
            var glow, prnt;
            glow = imArr[imCount];
            LIB.css(glow, {
                position: "absolute",
                left: (x - 64) + "px",
                top: (y - 64) + "px",
                width: "128px",
                height: "128px",
                transition: "opacity 0.2s linear",
                pointerEvents: "none",
                opacity: 1
            });
            prnt = document.body;
            if (parent) {
                prnt = parent;
            }
            prnt.appendChild(glow);
            setTimeout(function () {
                LIB.css(glow, {
                    opacity: "0"
                });
                setTimeout(function () {
                    prnt.removeChild(glow);
                }, 200);
            }, 30);
            imCount = (imCount + 1) % imArr.length;
        };
    }());
	
	
	
	
    /*UI.Button(p)
	Basic button
	P =	{
		im: <string>			Icon from UI.theme.svgGrid. Example: "btn_clear.svg"
		text: <string>			The alternative to an image
		title: <string>			Title attribute (tooltip on hover)
		animated: <boolean>,	Animates on pressing
		disabled: <boolean>,	Disable/enable button
		touchGlow: <boolean>,	Glow effect on touch
		style: {...}			Applies these style attributes to the button
		callback: <function()>	Gets called when pressed.
	}
	enable(<boolean>)			Enable/disable button
	setImage(<string>)			Change icon
	setTitle(<string>)			Sets title attribute (tooltip on hover)
	setTouchGlow(<boolean>)		Enable/disable touch glow effect
	getDiv()					Returns div element of button
	isEnabled()
	*/
    UI.Button = function (p) {
        var im, text, animated, disabled, touchGlow, callback, boxSize, div, innerDiv, mozInvertFilter;
        im = p.im;
        text = p.text;
        animated = p.animated || false;
        disabled = p.disabled || false;
        touchGlow = p.touchGlow || false;
        callback = p.callback;
        boxSize = 2 * UI.theme.halfBoxSize;
        div = document.createElement("div");
        innerDiv = document.createElement("div");
        div.appendChild(innerDiv);
        mozInvertFilter = "url(\"data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feComponentTransfer><feFuncR type=\'table\' tableValues=\'1 0\'/><feFuncG type=\'table\' tableValues=\'1 0\'/><feFuncB type=\'table\' tableValues=\'1 0\'/></feComponentTransfer></filter></svg>#grayscale\"";
        if (p.title) {
            div.title = p.title;
        }

        function updateBackground() {
            var bgScale, i, e, h, borderSize, scaleX, scaleY, offx, offy;
            bgScale = 0.75;
            i = 0;
            e = 0;
            for (h = 0; h < UI.theme.svgGrid.length; h += 1) {
                if (im === UI.theme.svgGrid[h][0]) {
                    i = UI.theme.svgGrid[h][1];
                    e = UI.theme.svgGrid[h][2];
                    break;
                }
            }
            borderSize = (1 - bgScale) * boxSize * 0.5;
            scaleX = (boxSize * bgScale) * (7 * 3);
            scaleY = (boxSize * bgScale) * (4 * 3);
            offx = -(boxSize * bgScale * 3 * i) + borderSize;
            offy = (boxSize * bgScale * 3 * e) - (scaleY - boxSize) - borderSize;
            LIB.css(innerDiv, {
                backgroundSize: scaleX + "px " + scaleY + "px ",
                backgroundRepeat: "no-repeat",
                backgroundPosition: offx + "px " + offy + "px",
                width: boxSize + "px",
                height: boxSize + "px"
            });
        }
        if (im) {
            LIB.css(innerDiv, {
                backgroundImage: "url(" + UI.theme.buttonSVG + ")"
            });
            updateBackground();
        } else if (text) {
            LIB.css(innerDiv, {
                fontSize: (boxSize / 3.0) + "px",
                lineHeight: boxSize + "px",
                textAlign: "center",
                fontWeight: "bold",
                textShadow: "1px 2px 1px rgba(0, 0, 0, 0.5)"
            });
            innerDiv.innerHTML = text;
        }

        function click() {
            if (disabled) {
                return;
            }
            callback();
            if (animated) {
                LIB.css(innerDiv, {
                    transition: "",
                    transform: "scale(0.9, 0.9)"
                });
                setTimeout(function () {
                    LIB.css(innerDiv, {
                        transition: "all 0.1s ease-in",
                        transform: ""
                    });
                    setTimeout(function () {
                        LIB.css(innerDiv, {
                            transition: ""
                        });
                    }, 110);
                }, 10);
            }
        }
        div.onmousedown = function () {
            click();
        };
        div.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            if (!disabled) {
                if (touchGlow) {
                    off = LIB.getGlobalOff(div);
                    UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
                }
            }
            click();
            return false;
        };
        //style
        LIB.css(div, {
            width: boxSize + "px",
            height: boxSize + "px",
            cssFloat: "left",
            cursor: "pointer",
            transition: "background 0.1s ease-in"
        });
        if (disabled) {
            LIB.css(div, {
                opacity: 0.5 * UI.theme.opacityOff,
                cursor: "default",
                webkitFilter: "invert(1)",
                filter: mozInvertFilter
            });
        }
        if (p.style) {
            LIB.css(div, p.style);
        }
        //interface
        this.enable = function (p) {
            if (p === disabled) {
                disabled = !disabled;
                if (disabled) {
                    LIB.css(div, {
                        opacity: 0.5 * UI.theme.opacityOff,
                        cursor: "default",
                        webkitFilter: "invert(1)",
                        filter: mozInvertFilter
                    });
                } else {
                    LIB.css(div, {
                        opacity: 1,
                        cursor: "pointer",
                        webkitFilter: "",
                        filter: ""
                    });
                }
            }
        };
        this.setImage = function (p) {
            im = p;
            updateBackground();
        };
        this.setTitle = function (p) {
            if (p) {
                div.title = p;
            }
        };
		this.setTouchGlow = function (p) {
            touchGlow = p;
        };
        this.getDiv = function () {
            return div;
        };
        this.isEnabled = function () {
            return !disabled;
        };
    };
	/*
	Button that has a canvas as the icon
	*/
	UI.CanvasButton = function (p) {
        var im, animated, disabled, touchGlow, callback, boxSize, div, innerDiv, mozInvertFilter;
        im = p.im;
        animated = p.animated || false;
        disabled = p.disabled || false;
        touchGlow = p.touchGlow || false;
        callback = p.callback;
        boxSize = 2 * UI.theme.halfBoxSize;
        div = document.createElement("div");
        innerDiv = p.canvas;
        div.appendChild(innerDiv);
        mozInvertFilter = "url(\"data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feComponentTransfer><feFuncR type=\'table\' tableValues=\'1 0\'/><feFuncG type=\'table\' tableValues=\'1 0\'/><feFuncB type=\'table\' tableValues=\'1 0\'/></feComponentTransfer></filter></svg>#grayscale\"";
        if (p.title) {
            div.title = p.title;
        }

        /*function updateBackground() {
            var bgScale, i, e, h, borderSize, scaleX, scaleY, offx, offy;
            bgScale = 0.75;
            i = 0;
            e = 0;
            for (h = 0; h < UI.theme.svgGrid.length; h += 1) {
                if (im === UI.theme.svgGrid[h][0]) {
                    i = UI.theme.svgGrid[h][1];
                    e = UI.theme.svgGrid[h][2];
                    break;
                }
            }
            borderSize = (1 - bgScale) * boxSize * 0.5;
            scaleX = (boxSize * bgScale) * (7 * 3);
            scaleY = (boxSize * bgScale) * (4 * 3);
            offx = -(boxSize * bgScale * 3 * i) + borderSize;
            offy = (boxSize * bgScale * 3 * e) - (scaleY - boxSize) - borderSize;
            LIB.css(innerDiv, {
                backgroundSize: scaleX + "px " + scaleY + "px ",
                backgroundRepeat: "no-repeat",
                backgroundPosition: offx + "px " + offy + "px",
                width: boxSize + "px",
                height: boxSize + "px"
            });
        }*/
		LIB.css(innerDiv, {
			width: boxSize + "px",
			height: boxSize + "px"
		});

        function click() {
            if (disabled) {
                return;
            }
            callback();
            if (animated) {
                LIB.css(innerDiv, {
                    transition: "",
                    transform: "scale(0.9, 0.9)"
                });
                setTimeout(function () {
                    LIB.css(innerDiv, {
                        transition: "all 0.1s ease-in",
                        transform: ""
                    });
                    setTimeout(function () {
                        LIB.css(innerDiv, {
                            transition: ""
                        });
                    }, 110);
                }, 10);
            }
        }
        div.onmousedown = function () {
            click();
        };
        div.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            if (!disabled) {
                if (touchGlow) {
                    off = LIB.getGlobalOff(div);
                    UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
                }
            }
            click();
            return false;
        };
        //style
        LIB.css(div, {
            width: boxSize + "px",
            height: boxSize + "px",
            cssFloat: "left",
            cursor: "pointer",
            transition: "background 0.1s ease-in"
        });
        if (disabled) {
            LIB.css(div, {
                opacity: 0.5 * UI.theme.opacityOff,
                cursor: "default",
                webkitFilter: "invert(1)",
                filter: mozInvertFilter
            });
        }
        if (p.style) {
            LIB.css(div, p.style);
        }
        //interface
        this.enable = function (p) {
            if (p === disabled) {
                disabled = !disabled;
                if (disabled) {
                    LIB.css(div, {
                        opacity: 0.5 * UI.theme.opacityOff,
                        cursor: "default",
                        webkitFilter: "invert(1)",
                        filter: mozInvertFilter
                    });
                } else {
                    LIB.css(div, {
                        opacity: 1,
                        cursor: "pointer",
                        webkitFilter: "",
                        filter: ""
                    });
                }
            }
        };
        this.setTitle = function (p) {
            if (p) {
                div.title = p;
            }
        };
		this.setTouchGlow = function (p) {
            touchGlow = p;
        };
        this.getDiv = function () {
            return div;
        };
        this.isEnabled = function () {
            return !disabled;
        };
    };
	/*
	button with and icon (left) and text (right)
	pretty much the same as button
	*/
	UI.IconTextButton = function (p) {
        var im, text, animated, disabled, touchGlow, callback, boxSize, div, iconDiv, textDiv, mozInvertFilter;
        im = p.im;
        text = p.text;
        animated = p.animated || false;
        disabled = p.disabled || false;
        touchGlow = p.touchGlow || false;
        callback = p.callback;
        boxSize = 2 * UI.theme.halfBoxSize;
        div = document.createElement("div");
        iconDiv = document.createElement("div");
        textDiv = document.createElement("div");
        div.appendChild(iconDiv);
        div.appendChild(textDiv);
        mozInvertFilter = "url(\"data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feComponentTransfer><feFuncR type=\'table\' tableValues=\'1 0\'/><feFuncG type=\'table\' tableValues=\'1 0\'/><feFuncB type=\'table\' tableValues=\'1 0\'/></feComponentTransfer></filter></svg>#grayscale\"";
        if (p.title) {
            div.title = p.title;
        }

        function updateBackground() {
            var bgScale, i, e, h, borderSize, scaleX, scaleY, offx, offy;
            bgScale = 0.75;
            i = 0;
            e = 0;
            for (h = 0; h < UI.theme.svgGrid.length; h += 1) {
                if (im === UI.theme.svgGrid[h][0]) {
                    i = UI.theme.svgGrid[h][1];
                    e = UI.theme.svgGrid[h][2];
                    break;
                }
            }
            borderSize = (1 - bgScale) * boxSize * 0.5;
            scaleX = (boxSize * bgScale) * (7 * 3);
            scaleY = (boxSize * bgScale) * (4 * 3);
            offx = -(boxSize * bgScale * 3 * i) + borderSize;
            offy = (boxSize * bgScale * 3 * e) - (scaleY - boxSize) - borderSize;
            LIB.css(iconDiv, {
                backgroundSize: scaleX + "px " + scaleY + "px ",
                backgroundRepeat: "no-repeat",
                backgroundPosition: offx + "px " + offy + "px",
                width: boxSize + "px",
                height: boxSize + "px"
            });
        }
        if (im) {
            LIB.css(iconDiv, {
                backgroundImage: "url(" + UI.theme.buttonSVG + ")",
				cssFloat: "left",
				marginLeft: (UI.theme.halfBoxSize * 0.15) + "px"
            });
            updateBackground();
        }
		if (text) {
            LIB.css(textDiv, {
                fontSize: (boxSize / 3.0) + "px",
                lineHeight: boxSize + "px",
                textAlign: "center",
                fontWeight: "bold",
                textShadow: "1px 2px 1px rgba(0, 0, 0, 0.5)",
				cssFloat: "left",
				marginLeft: (-UI.theme.halfBoxSize * 0.2) + "px"
            });
            textDiv.innerHTML = text;
        }

        function click() {
            if (disabled) {
                return;
            }
            callback();
            if (animated) {
               /* LIB.css(innerDiv, {
                    transition: "",
                    transform: "scale(0.9, 0.9)"
                });
                setTimeout(function () {
                    LIB.css(innerDiv, {
                        transition: "all 0.1s ease-in",
                        transform: ""
                    });
                    setTimeout(function () {
                        LIB.css(innerDiv, {
                            transition: ""
                        });
                    }, 110);
                }, 10);*/
            }
        }
        div.onmousedown = function () {
            click();
        };
        div.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            if (!disabled) {
                if (touchGlow) {
                    off = LIB.getGlobalOff(div);
                    UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
                }
            }
            click();
            return false;
        };
        //style
        LIB.css(div, {
            width: (boxSize * 2) + "px",
            height: boxSize + "px",
            cssFloat: "left",
            cursor: "pointer",
            transition: "background 0.1s ease-in"
        });
        if (disabled) {
            LIB.css(div, {
                opacity: 0.5 * UI.theme.opacityOff,
                cursor: "default",
                webkitFilter: "invert(1)",
                filter: mozInvertFilter
            });
        }
        if (p.style) {
            LIB.css(div, p.style);
        }
        //interface
        this.enable = function (p) {
            if (p === disabled) {
                disabled = !disabled;
                if (disabled) {
                    LIB.css(div, {
                        opacity: 0.5 * UI.theme.opacityOff,
                        cursor: "default",
                        webkitFilter: "invert(1)",
                        filter: mozInvertFilter
                    });
                } else {
                    LIB.css(div, {
                        opacity: 1,
                        cursor: "pointer",
                        webkitFilter: "",
                        filter: ""
                    });
                }
            }
        };
        this.setImage = function (p) {
            im = p;
            updateBackground();
        };
        this.setTitle = function (p) {
            if (p) {
                div.title = p;
            }
        };
		this.setTouchGlow = function (p) {
            touchGlow = p;
        };
        this.getDiv = function () {
            return div;
        };
        this.isEnabled = function () {
            return !disabled;
        };
    };
    /*UI.ToggleButton(p)
	A button that can be turned on and off by pressing.
	P =	{
		state: <boolean>				Initial state: on/off
		im: <string>					Icon from UI.theme.svgGrid. Example: "btn_clear.svg"
		text: <string>					The alternative to an image
		title: <string>					Title attribute (tooltip on hover)
		animated: <boolean>				Animates on pressing
		disabled: <boolean>				Disable/enable button
		touchGlow: <boolean>			Glow effect on touch
		callback: <function(<boolean>)>	Gets called on turning on/off
	}
	setState(<boolean>)			Set state on/off
	getDiv()					Returns div element of button
	*/
    UI.ToggleButton = function (p) {
        var state, callback, button;
        state = p.state;
        callback = p.callback;

        function update() {
            LIB.css(button.getDiv(), {
                opacity: state ? 1 : UI.theme.opacityOff
            });
        }
        button = new UI.Button({
            im: p.im,
            text: p.text,
            title: p.title,
            touchGlow: p.touchGlow,
            animated: p.animated,
            disabled: p.disabled,
            callback: function () {
                state = !state;
                update();
                callback(state);
            }
        });
        update();
        this.setState = function (p) {
            if (p === state) {
                return;
            }
            state = !state;
            update();
        };
        this.getDiv = function () {
            return button.getDiv();
        };
    };
	/*UI.MultiStepSwitch(p)
	A button that lets you switch between multiple different items. Only one at a time
	can be selected.
	P =	{
		ims: [<string>,<string>,...]	Array containing n names of icons
		init: <int>						Index of item that is initially selected
		titles: [<string>,<string>,...]	Array containing n titles of icons
		width: <int>					Width in (halfBoxSize * 2) units
		callback: <function(<string>)>	Callback with id of selected item as parameter
	}
	getDiv()					Returns div element of the MultiStepSwitch
	*/
    UI.MultiStepSwitch = function (p) {
        var ims, state, titles, width, callback, boxPx, boxSize, div, modeBox, animated, icons, i;
		ims = p.ims;
        state = p.init;
        titles = p.titles;
        width = p.width;
        callback = p.callback;
        boxPx = UI.theme.halfBoxSize / 22;
		boxSize = UI.theme.halfBoxSize * 2;
		div = document.createElement("div");
        LIB.css(div, {
            width: (boxSize * width) + "px",
            height: boxSize + "px",
            cssFloat: "left",
            cursor: "pointer",
            position: "relative"
        });
        modeBox = document.createElement("div");
        LIB.css(modeBox, {
            border: (UI.theme.halfBoxSize / 11) + "px solid #777",
            position: "absolute",
            left: (boxPx * 3) + "px",
            top: (boxPx * 4) + "px",
            width: (boxSize * 3 - boxPx * 10) + "px",
            height: (boxSize - boxPx * 10) + "px",
            borderRadius: (boxPx * 5) + "px"
        });
        animated = document.createElement("div");
        LIB.css(animated, {
            position: "absolute",
            width: (boxSize - boxPx * 16) + "px",
            borderBottom: (2 * boxPx) + "px solid #999",
            transition: "left 0.1s ease-in-out",
            left: (boxSize + boxPx * 8) + "px",
            top: (boxSize - boxPx * 4) + "px"
        });
        div.appendChild(modeBox);
        div.appendChild(animated);

		icons = [];

        function updateBackground(icon, im) {
            var bgScale, i, e, h, borderSize, scaleX, scaleY, offx, offy;
			bgScale = 0.75;
            i = 0;
            e = 0;
            for (h = 0; h < UI.theme.svgGrid.length; h += 1) {
                if (im === UI.theme.svgGrid[h][0]) {
                    i = UI.theme.svgGrid[h][1];
                    e = UI.theme.svgGrid[h][2];
                    break;
                }
            }
            borderSize = (1 - bgScale) * boxSize * 0.5;
            scaleX = (boxSize * bgScale) * (7 * 3);
            scaleY = (boxSize * bgScale) * (4 * 3);
            offx = -(boxSize * bgScale * 3 * i) + borderSize;
            offy = (boxSize * bgScale * 3 * e) - (scaleY - boxSize) - borderSize;
            LIB.css(icon, {
                backgroundSize: scaleX + "px " + scaleY + "px ",
                backgroundRepeat: "no-repeat",
                backgroundPosition: offx + "px " + offy + "px",
                width: boxSize + "px",
                height: boxSize + "px"
            });
        }

		function click(i) {
			var e;
            if (i === state) {
                state = (state + 1) % titles.length;
            } else {
                state = i;
            }
            LIB.css(animated, {
                left: (state * boxSize + boxPx * 8) + "px"
            });
            for (e = 0; e < ims.length; e += 1) {
                if (e !== state) {
                    icons[e].style.opacity = 0.5;
                } else {
                    icons[e].style.opacity = 1;
                }
            }
            callback(titles[state]);
        }

		function createIcon(i) {
			icons[i] = document.createElement("div");
			LIB.css(icons[i], {
				position: "absolute",
				left: ((i * width / ims.length) * boxSize) + "px",
				top: 0,
				background: "url(" + UI.theme.buttonSVG + ")"
			});
			if (i !== state) {
				icons[i].style.opacity = 0.5;
			}
			updateBackground(icons[i], ims[i]);
			icons[i].title = titles[i];
			icons[i].onmousedown = function () {
				click(i);
			};
			icons[i].ontouchstart = function (event) {
				var off, glowIndex;
				if (event.touches.length !== 1) {
					return false;
				}
				glowIndex = i;
				if (state === i) {
					glowIndex = (i + 1) % icons.length;
				}
				off = LIB.getGlobalOff(icons[glowIndex]);
				UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
				click(i);
				return false;
			};
			div.appendChild(icons[i]);
		}
        for (i = 0; i < ims.length; i += 1) {
            createIcon(i);
        }
        this.getDiv = function () {
            return div;
        };
    };
	/*UI.ClearCanvasButton(p)
	A clear-canvas button that lets you switch between different colors. Black and
	white are always one of these colors.
	can be selected.
	P =	{
		colors: [{r,g,b},{r,g,b},..]	Array of colors to choose from
		callback: <function({r,g,b})>	Callback (when pressing clear) with selected color as param
	}
	setColors([{r,g,b},{r,g,b},..])	Change the set of colors. Won't affect the currently
									selected color.
	getDiv()						Returns div element of button
	*/
    UI.ClearCanvasButton = function (p) {
		var div, boxSize, boxPx, colors, currentColor, currentColorValue, bgDiv, svg, path1,
			path2, clearDiv, prevDiv, nextDiv;
        div = document.createElement("div");
        boxSize = UI.theme.halfBoxSize * 2;
        boxPx = boxSize / 44;
        colors = p.colors;
        currentColor = 0;
        currentColorValue = {
            r: colors[currentColor].r,
            g: colors[currentColor].g,
            b: colors[currentColor].b
        };
        LIB.css(div, {
            cssFloat: "left",
            width: (3 * boxSize) + "px",
            position: "relative",
            cursor: "pointer"
        });
        bgDiv = document.createElement("div");
        LIB.css(bgDiv, {
            width: (boxSize * 3 - 12 * boxPx) + "px",
            height: (boxSize - 12 * boxPx) + "px",
            margin: (boxPx * 5) + "px",
            backgroundColor: "#fff",
            borderRadius: (boxPx * 10) + "px",
            border: boxPx + "px solid #aaa",
            transition: "background-color 0.2s linear"
        });
        div.appendChild(bgDiv);
        svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        svg.setAttribute('width', (boxSize * 3 - 12 * boxPx));
        svg.setAttribute('height', (boxSize - 12 * boxPx));
        svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
        LIB.css(svg, {
            position: "absolute",
            left: (boxPx * 6) + "px",
            top: (boxPx * 6) + "px"
        });
        path1 = document.createElementNS("http://www.w3.org/2000/svg", "path");
        LIB.setAttributes(path1, [
            ["d", "M 5,5 L 23,15 5,25 z"],
            ["stroke", "black"],
            ["stroke-opacity", 1],
            ["stroke-width", 1],
            ["fill", "none"],
            ["transform", "scale(" + boxPx + ", " + boxPx + ") translate(90 , 1)"]
        ]);
        path2 = document.createElementNS("http://www.w3.org/2000/svg", "path");
        LIB.setAttributes(path2, [
            ["d", "M 5,5 L 23,15 5,25 z"],
            ["stroke", "black"],
            ["stroke-opacity", 1],
            ["stroke-width", 1],
            ["fill", "none"],
            ["transform", "scale(" + (-boxPx) + ", " + boxPx + "), translate(-31, 1)"]
        ]);
        svg.appendChild(path1);
        svg.appendChild(path2);
        div.appendChild(svg);

        clearDiv = document.createElement("div");
        LIB.css(clearDiv, {
            position: "absolute",
            width: boxSize + "px",
            height: boxSize + "px",
            left: boxSize + "px",
            top: 0,
            fontSize: (boxSize / 3.0) + "px",
            textAlign: "center",
            lineHeight: boxSize + "px",
            fontWeight: "bold",
            color: "#000"
        });
        clearDiv.title = "Clear Canvas";
        clearDiv.innerHTML = "Clear";
        div.appendChild(clearDiv);

        prevDiv = document.createElement("div");
        LIB.css(prevDiv, {
            position: "absolute",
            width: boxSize + "px",
            height: boxSize + "px",
            left: 0,
            top: 0
        });
        prevDiv.title = "Previous Clear Color";
        div.appendChild(prevDiv);

        nextDiv = document.createElement("div");
        LIB.css(nextDiv, {
            position: "absolute",
            width: boxSize + "px",
            height: boxSize + "px",
            left: (2 * boxSize) + "px",
            top: 0
        });
        nextDiv.title = "Next Clear Color";
        div.appendChild(nextDiv);

        function clickChange(dir) {
            currentColor = (currentColor + dir + colors.length) % colors.length;
            currentColorValue = {
                r: colors[currentColor].r,
                g: colors[currentColor].g,
                b: colors[currentColor].b
            };
            var color = "#fff";
            if ((currentColorValue.r + currentColorValue.g + currentColorValue.b * 0.2) / 2.3 / 255 > 0.4) {
                color = "#000";
            }
            LIB.css(bgDiv, {
                backgroundColor: "rgb(" + currentColorValue.r + ", " + currentColorValue.g + ", " + currentColorValue.b + ")"
            });
            clearDiv.style.color = color;
            path1.setAttribute("stroke", color);
            path2.setAttribute("stroke", color);
        }
        prevDiv.onmousedown = function () {
            clickChange(-1);
        };
        prevDiv.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            off = LIB.getGlobalOff(prevDiv);
            UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
            clickChange(-1);
            return false;
        };
        nextDiv.onmousedown = function () {
            clickChange(1);
        };
        nextDiv.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            off = LIB.getGlobalOff(nextDiv);
            UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
            clickChange(1);
            return false;
        };
        clearDiv.onmousedown = function () {
            p.callback({
                clear: {
                    r: currentColorValue.r,
                    g: currentColorValue.g,
                    b: currentColorValue.b
                }
            });
        };
        clearDiv.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            off = LIB.getGlobalOff(clearDiv);
            UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
            p.callback({
                clear: {
                    r: colors[currentColor].r,
                    g: colors[currentColor].g,
                    b: colors[currentColor].b
                }
            });
            return false;
        };

        function removeDuplicates() {
            var i, e;
            for (i = 0; i < colors.length; i += 1) {
                for (e = i + 1; e < colors.length; e += 1) {
                    if (colors[i].r === colors[e].r && colors[i].g === colors[e].g && colors[i].b === colors[e].b) {
                        colors.splice(e, 1);
                        e -= 1;
                    }
                }
            }
        }
        removeDuplicates();
        this.setColors = function (p) {
            colors = p;
            removeDuplicates();
        };
        this.getDiv = function () {
            return div;
        };
    };

    /*UI.ExpandButton(p)
	Button used together with expand bar. Pretty similar to a toggle button.
	P =	{
		im: <string>				Icon from UI.theme.svgGrid. Example: "btn_clear.svg"
		text: <string>				The alternative to an image
		title: <string>				Title attribute (tooltip on hover)
		callback: <function(evt)>	Gets called on pressing
	}
	callback evt = {
		expanded: <boolean>
	}
	collapse()			"collapse" button
	setImage(<string>)	Change icon
	getDiv()			Returns div element of button
	*/
    UI.ExpandButton = function (p) {
        var callback, button, expanded;
        callback = p.callback;
        expanded = false;

        function update() {
            if (expanded) {
                button.getDiv().style.backgroundColor = UI.theme.expandCol;
            } else {
                button.getDiv().style.backgroundColor = "";
            }
        }
        button = new UI.Button({
            im: p.im,
            title: p.title,
            text: p.text,
            callback: function () {
                expanded = !expanded;
                update();
                callback({
                    expanded: expanded
                });
            }
        });
        this.collapse = function () {
            if (!expanded) {
                return;
            }
            expanded = false;
            update();
        };
        this.setImage = function (p) {
            button.setImage(p);
        };
        this.getDiv = function () {
            return button.getDiv();
        };
    };

    /*UI.ColorButton(p)
	A different kind of ExpandButton. Previews a color. Has 3 states: not active, active, expanded
	p = {
		active: <boolean>			Initial state for active
		color: {r: , g: , b: }		Initial color
		callback: <function(evt)>	callback on state change
	}
	callback evt = {
		expanded: <boolean>
		active: <boolean>
	}
	active(<boolean>)			Set state to active or not active. automatically "collapses" button
	expand()					"expand" button
	collapse()					"collapse" button
	setColor({r: , g: , b: })	Set color of button
	getColor()					Returns color {r: , g: , b: } of button
	getDiv()					Get div element of button
	*/
    UI.ColorButton = function (p) {
        var boxSize, callback, active, expanded, color, div, colBox;
        boxSize = (2 * UI.theme.halfBoxSize);
        callback = p.callback;
        active = p.active;
        expanded = false;
        color = p.color;
        div = document.createElement("div");
        colBox = document.createElement("div");
        LIB.css(div, {
            width: boxSize + "px",
            height: boxSize + "px",
            cssFloat: "left",
            cursor: "pointer",
            transition: "background 0.1s ease-in"
        });
        LIB.css(colBox, {
            border: (UI.theme.halfBoxSize / 11) + "px solid rgba(255, 255, 255, 0.1)",
            transition: "margin 0.1s, width 0.1s, height 0.1s, border 0.1s",
            borderRadius: "50%",
            boxShadow: "0 2px 4px rgba(0, 0, 0, 1) inset"
        });
        div.appendChild(colBox);

        function update() {
            if (expanded) {
                div.style.background = UI.theme.expandCol;
            } else {
                div.style.background = "";
            }
            LIB.css(colBox, {
                background: "rgb(" + color.r + ", " + color.g + ", " + color.b + ")"
            });
            if (active) {
                LIB.css(colBox, {
                    width: (boxSize * 0.75) + "px",
                    height: (boxSize * 0.75) + "px",
                    marginLeft: ((boxSize - boxSize * 0.75) / 2 - (UI.theme.halfBoxSize / 11)) + "px",
                    marginTop: ((boxSize - boxSize * 0.75) / 2 - (UI.theme.halfBoxSize / 11)) + "px",
                    border: (UI.theme.halfBoxSize / 11) + "px solid rgba(255, 255, 255, 1)"
                });
            } else {
                LIB.css(colBox, {
                    width: (boxSize / 2) + "px",
                    height: (boxSize / 2) + "px",
                    marginLeft: ((boxSize - boxSize / 2) / 2) + "px",
                    marginTop: ((boxSize - boxSize / 2) / 2) + "px",
                    border: ""
                });
            }
        }

        function click() {
            if (active && !expanded) {
                expanded = true;
                update();
                callback({
                    expanded: true
                });
            } else if (expanded) {
                expanded = false;
                update();
                callback({
                    expanded: false
                });
            } else if (!active) {
                active = true;
                update();
                callback({
                    active: true
                });
            }
        }
        div.onmousedown = function () {
            click();
        };
        div.ontouchstart = function (event) {
            var off;
            if (event.touches.length !== 1) {
                return false;
            }
            if (!active) {
                off = LIB.getGlobalOff(div);
                UI.spawnGlow(off.x + boxSize / 2, off.y + boxSize / 2);
            }
            click();
            return false;
        };
        update();
        //interface
        this.active = function (p) {
            active = p;
            expanded = false;
            update();
        };
        this.expand = function () {
            if (expanded) {
                return;
            }
            expanded = true;
            update();
        };
        this.collapse = function () {
            if (!expanded) {
                return;
            }
            expanded = false;
            update();
        };
        this.setColor = function (c) {
            color = c;
            update();
        };
        this.getColor = function () {
            return {
                r: color.r,
                g: color.g,
                b: color.b
            };
        };
        this.getDiv = function () {
            return div;
        };
    };
    /*UI.ExpandBar(p)
	A bar on which new UI elements can be placed. Collapses and expands with an animation.
	Goes with ExpandButton/ColorButton.
	p = {
		width: <number>			width in grid units defined by UI.theme
		height: <number>		height in grid units defined by UI.theme
		leftOffset: <number>	Offset in (halfBoxSize * 2) units
	}
	collapse()		Collapse bar
	expand()		Expand bar
	isExpanded()	Returns boolean: true - expanded, false - collapsed
	getDiv()		Returns div element of bar (wrapped)
	getContentDiv()	Returns the inner div element where the UI elements go
	*/
    UI.ExpandBar = (function () {
        var classCounter = 0;
        return function (p) {
            var div, expanded, width, height, boxSize, hideTimeout, contentDiv, cssRule;
            div = document.createElement("div");
            expanded = false;
            boxSize = 2 * UI.theme.halfBoxSize;
            width = p.width * boxSize;
            height = p.height * boxSize;
            hideTimeout = undefined;
            //style
            LIB.css(div, {
                opacity: 0,
                position: "absolute",
                width: width + "px",
                left: ((p.leftOffset || 0) * boxSize) + "px",
                top: (boxSize - boxSize) + "px",
                transition: "all 0.1s ease-out",
                transform: "translate(0, " + (-height) + "px)",
                pointerEvents: "none"
            });
            div.ontouchstart = function () {
                return false;
            };

            contentDiv = document.createElement("div");
            contentDiv.className = "WebchemyAppShadedExpandBG" + classCounter;
            cssRule = "background-image: -webkit-linear-gradient(top, rgba(255,255,255, 0) " + (boxSize + 1) + "px, rgba(255,255,255, 0.2) " + (boxSize + 1 + boxSize) + "px);";
            cssRule += "background-image: -o-linear-gradient(top, rgba(255,255,255, 0) " + (boxSize + 1) + "px, rgba(255,255,255, 0.2) " + (boxSize + 1 + boxSize) + "px);";
            cssRule += "background-image: linear-gradient(to bottom, rgba(255,255,255, 0) " + (boxSize + 1) + "px, rgba(255,255,255, 0.2) " + (boxSize + 1 + boxSize) + "px);";
            cssRule += "background-image: -moz-linear-gradient(center top, rgba(255,255,255, 0) " + (boxSize + 1) + "px, rgba(255,255,255, 0.2) " + (boxSize + 1 + boxSize) + "px);";
            LIB.addCssRule("." + contentDiv.className, cssRule);
            classCounter += 1;
            LIB.css(contentDiv, {
                width: width + "px",
                height: height + "px",
                paddingTop: boxSize + "px",
                backgroundColor: UI.theme.expandCol,
                borderBottomRightRadius: (UI.theme.halfBoxSize / 3) + "px",
                borderBottomLeftRadius: (UI.theme.halfBoxSize / 3) + "px",
                boxShadow: "0 2px 4px rgba(0, 0, 0, 0.5)",
                backgroundImage: "-webkit-linear-gradient(top, rgba(255,255,255, 0) " + (boxSize + 1) + "px, rgba(255,255,255, 0.2) " + (boxSize + 1 + boxSize) + "px)"
            });
            div.appendChild(contentDiv);
            //needed so all images get loaded within each bar even before they are expanded
            setTimeout(function () {
                if (!expanded) {
                    LIB.css(contentDiv, {
                        display: "none"
                    });
                }
            }, 1000);

            function update() {
                if (!expanded) {
                    LIB.css(div, {
                        transform: "translate(0, " + (-height) + "px)",
                        opacity: 0,
                        pointerEvents: "none"
                    });
                } else {
                    LIB.css(div, {
                        transform: "translate(0, 0)",
                        opacity: 1,
                        pointerEvents: ""
                    });
                }
            }

            function expand(p) {
                if (expanded === p) {
                    return;
                }
                expanded = !expanded;
                if (expanded) {
                    clearTimeout(hideTimeout);
                    LIB.css(contentDiv, {
                        display: "block"
                    });
                    update();
                } else {
                    hideTimeout = setTimeout(function () {
                        LIB.css(contentDiv, {
                            display: "none"
                        });
                    }, 101);
                    update();
                }
            }
            //interface
            this.collapse = function () {
                expand(false);
            };
            this.expand = function () {
                expand(true);
            };
            this.isExpanded = function () {
                return expanded;
            };
            this.getDiv = function () {
                return div;
            };
            this.getContentDiv = function () {
                return contentDiv;
            };
        };
    }());
    /*UI.EmptySlot(slots)
	Creates empty space with a width of: slots * halfBoxSize * 2
	getDiv()	Returns the div element
	*/
    UI.EmptySlot = function (p) {
        var div = document.createElement("div");
        LIB.css(div, {
            cssFloat: "left",
            height: (UI.theme.halfBoxSize * 2) + "px",
            width: (p * UI.theme.halfBoxSize * 2) + "px"
        });
        this.getDiv = function () {
            return div;
        };
    };
    /*UI.Slider(p)
	A slider with snapping
	p = {
		value: <number[0.0, 1.0]>	Init value of the slider
		width: <number>				Width of slider element in px
		caption: <string>			Caption above the slider
		disabled: <boolean>			Init state disabled/enabled
		left: <number>				Left offset of slider in px (absolute positioning)
		callback: <function(<number[0.0, 1.0]>)>	Callback on value change. Value between 0-1
	}
	enable(<boolean>)		Enable/disable slider
	getDiv()				Returns the div element
	*/
    UI.Slider = function (p) {
        var div, value, callback, width, boxSize, border, enabled, eventDiv, circleDiv, hideTimeout,
			sliderSize, circleSize, fillDiv, slideBox, eventBox;
        div = document.createElement("div");
        value = p.value;
        callback = p.callback || function () {};
        width = p.width;
        div.innerHTML = p.caption;
        boxSize = UI.theme.halfBoxSize * 2;
        border = boxSize * 0.2;
        enabled = !(p.disabled || false);
        sliderSize = boxSize / 2;
        circleSize = boxSize / 2.5;
        eventDiv = document.createElement("div");
        fillDiv = document.createElement("div");
        circleDiv = document.createElement("div");
        slideBox = document.createElement("div");
        eventBox = document.createElement("div");

        function update() {
            LIB.css(fillDiv, {
                width: (sliderSize / 2 + value * (width - 2 * border - sliderSize)) + "px"
            });
            LIB.css(circleDiv, {
                left: (border + sliderSize / 2 + value * (width - 2 * border - sliderSize)) + "px"
            });
        }
        LIB.attachMouseListener(eventBox, function (val) {
            if (!enabled) {
                return;
            }
            if (val.dragdone === false) {
                value = val.x;
                value = (Math.min(6, parseInt(value * 7, 10)) / 6);
                update();
                callback(value);
            }
        });
        LIB.css(div, {
            position: "absolute",
            left: p.left + "px",
            width: width + "px",
            height: boxSize + "px",
            transition: "opacity 0.2s linear",
            fontSize: (border * 1.4) + "px",
            lineHeight: (border * 2) + "px",
            textAlign: "center",
            color: "#ccc",
            cursor: "default"
        });
        LIB.css(slideBox, {
            position: "absolute",
            backgroundColor: "#313131",
            width: (width - 2 * border) + "px",
            height: sliderSize + "px",
            borderRadius: (boxSize / 4) + "px",
            left: border + "px",
            top: (1.8 * border) + "px",
            boxShadow: "inset 0 " + (boxSize / 8) + "px " + (boxSize / 5) + "px #000, 0 " + (boxSize / 23) + "px " + (boxSize / 25) + "px #777"
        });
        LIB.css(fillDiv, {
            position: "absolute",
            backgroundColor: "#404040",
            width: (width - 2 * border) + "px",
            height: circleSize + "px",
            borderTopLeftRadius: (circleSize / 2) + "px",
            borderBottomLeftRadius: (circleSize / 2) + "px",
            left: (border + (sliderSize - circleSize) / 2) + "px",
            top: (1.8 * border + (sliderSize - circleSize) / 2) + "px",
            boxShadow: "inset " + (-boxSize / 10) + "px " + (-boxSize / 10) + "px " + (boxSize / 3) + "px #151515"
        });
        LIB.css(circleDiv, {
            width: circleSize + "px",
            height: circleSize + "px",
            borderRadius: (circleSize / 2) + "px",
            position: "absolute",
            marginLeft: (-circleSize / 2) + "px",
            marginTop: (-circleSize / 2) + "px",
            left: (border + sliderSize / 2) + "px",
            top: (1.8 * border + sliderSize / 2) + "px",
            background: "#dedede"
        });
        LIB.css(eventBox, {
            position: "absolute",
            width: (width - 2 * border) + "px",
            height: sliderSize + "px",
            left: border + "px",
            top: (1.8 * border) + "px",
            cursor: "pointer"
        });
        if (!enabled) {
            LIB.css(div, {
                opacity: 0,
                pointerEvents: "none"
            });
        }
        div.appendChild(slideBox);
        div.appendChild(fillDiv);
        div.appendChild(circleDiv);
        div.appendChild(eventBox);
        this.enable = function (p) {
            if (enabled === p) {
                return;
            }
            enabled = p;
            if (hideTimeout) {
                clearTimeout(hideTimeout);
            }
            if (!enabled) {
                div.style.opacity = 0;
                hideTimeout = setTimeout(function () {
                    eventBox.style.cursor = "default";
                    div.style.pointerEvents = "none";
                }, 200);
            } else {
                eventBox.style.cursor = "pointer";
                div.style.pointerEvents = "";
                hideTimeout = setTimeout(function () {
                    div.style.opacity = 1;
                }, 10);
            }
        };
        this.getDiv = function () {
            return div;
        };
        update();
    };
    /*UI.Label(p)
	Creates a div with text.
	p = {
		text: <string>		The text you want to display
		width: <number>		Width of label in grid size
	}
	setText(<string>)	Changes the text
	getDiv()			Returns the div element
	*/
    UI.Label = function (p) {
        var div, width, boxSize;
        div = document.createElement("div");
        width = p.width;
        boxSize = UI.theme.halfBoxSize * 2;
        div.innerHTML = p.text;
        LIB.css(div, {
            cssFloat: "left",
            width: (width * boxSize) + "px",
            fontSize: (boxSize / 3.0) + "px",
            textAlign: "center",
            lineHeight: boxSize + "px",
            cursor: "default",
            color: UI.theme.labelColor
        });
        this.setText = function (p) {
            div.innerHTML = p;
        };
        this.getDiv = function () {
            return div;
        };
    };
	
	
	
	/*UI.showPopup(p)
	Displays an overlay/popup in the target element. Opening and closing takes 0.3 seconds (fade in, out)
	p = {
		target: <div>			Element this pop-up gets appended to
		div: <div>				Content you want to display
		callback: <function()>	(Optional) Will get called when the pop-up gets closed (pop-up can do that by itself)
		setCallback: <function(<function()>)>	Tells you what function to call to close the pop-up
	}
	*/
    UI.showPopup = (function () {
        var popDiv;
        return function (p) {
            var close, closed;
            closed = false;
            if (!popDiv) {
                popDiv = document.createElement("div");
                LIB.css(popDiv, {
                    position: "fixed",
                    left: "0",
                    top: "0",
                    width: "100%",
                    height: "100%",
                    opacity: 0,
                    transition: "opacity 0.3s linear"
                });
                popDiv.bgDiv = document.createElement("div");
                LIB.css(popDiv.bgDiv, {
                    position: "fixed",
                    left: "0",
                    top: "0",
                    width: "100%",
                    height: "100%",
                    background: "rgba(0, 0, 0, 0.5)"
                });
                popDiv.appendChild(popDiv.bgDiv);
            }
            /*//to really fill the whole window. "100%" might only fill about 90% on iPhones
            function updateHeight() {
                if (closed) {
                    return;
                }
                LIB.css(popDiv, {
                    height: "100%"
                });
                setTimeout(updateHeight, 100);
            }
            updateHeight();*/
            popDiv.appendChild(p.div);
            LIB.css(p.div, {
                width: (7 * UI.theme.halfBoxSize * 2) + "px",
                marginLeft: "auto",
                marginRight: "auto",
                position: "relative"
            });
            popDiv.ontouchmove = function () {
                return false;
            };
            p.target.appendChild(popDiv);
            setTimeout(function () {
                LIB.css(popDiv, {
                    opacity: 1
                });
            }, 20);
            close = function () {
                if (closed) {
                    return;
                }
                closed = true;
                LIB.css(popDiv, {
                    opacity: 0
                });
                setTimeout(function () {
                    p.target.removeChild(popDiv);
                    popDiv.removeChild(p.div);
                    if (p.callback) {
                        p.callback();
                    }
                }, 300);
            };
            popDiv.bgDiv.onclick = function () {
                close();
                return false;
            };
            p.setCallback(close);
        };
    }());

	/*UI.div(p)
	Create a div or image with a specified style and content. Can save you a few lines.
	Returns the created element.
	p = {
		type: <string>				(Optional) Can be "image" or undefined -> creates image or div
		src: <string>				If it's an image this is the src attribute
		innerHTML: <string>			innerHTML attribute of the div
		...style...					You can add as many style attributes as you want (acts like LIB.css)
	}
	enable(<boolean>)		Enable/disable slider
	getDiv()				Returns the div element
	*/
    UI.div = function (p) {
        var div;
        if (!p.type) {
            div = document.createElement("div");
        } else if (p.type === "image") {
            div = new Image();
            div.src = p.src;
            delete p.type;
            delete p.src;
        } else {
			div = document.createElement("div");
            delete p.type;
        }
		if (p.style) {
			LIB.css(div, p.style);
			delete p.style;
		}
		if (p.onclick) {
			div.onclick = p.onclick;
			delete p.onclick;
		}
		if (p.parent) {
			p.parent.appendChild(div);
			delete p.parent;
		}
        if (p.innerHTML) {
            div.innerHTML = p.innerHTML;
            delete p.innerHTML;
        }
        LIB.css(div, p);
        return div;
    };
	
	
	
	
	
	
	/*UI.ButtonBarCombination(p)
	Coordinates an ExpandButton and an ExpandBar. ButtonBarCombinations go into a BarContainer.
	p = {
		width: <number>				(Default 7) Width in (halfBoxSize * 2) units
		expandHeight: <number>		(Default 1) height in (halfBoxSize * 2) units
		leftOffset: <number>		(Default 0) offset in (halfBoxSize * 2) units
		im: <string>				Icon from UI.theme.svgGrid, used for the button. Example: "btn_clear.svg"
		callback: <function(evt)>	Callback on expand/collapse and even when collapse() is called
	}
	callback evt = {
		expand:	<boolean>		True on expand
		collapse: <boolean>		True on collapse
	}
	collapse()						Collapses combination. Also causes a callback.
	addListener(<function(evt)>)	Adds a callback listener
	getBar()						Returns the ExpandBar object (not div)
	getButton()						Returns the ExpandButton object (not div)
	*/
    UI.ButtonBarCombination = function (p) {
        var bar, listeners, button;
        listeners = [];
        if (p.callback !== undefined) {
            listeners.push(p.callback);
        }

        function callback(p) {
            var i;
            for (i = 0; i < listeners.length; i += 1) {
                listeners[i](p);
            }
        }
        bar = new UI.ExpandBar({
            width: p.width || 7,
            height: p.expandHeight || 1,
            leftOffset: p.leftOffset || 0
        });
        button = new UI.ExpandButton({
            im: p.im,
            callback: function (val) {
                if (val.expanded) {
                    bar.expand();
                    callback({
                        expand: true
                    });
                } else if (val.expanded === false) {
                    bar.collapse();
                    callback({
                        collapse: true
                    });
                }
            }
        });
        this.collapse = function () {
            button.collapse();
            bar.collapse();
            callback({
                collapse: true
            });
        };
        this.addListener = function (p) {
            listeners.push(p);
        };
        this.getBar = function () {
            return bar;
        };
        this.getButton = function () {
            return button;
        };
    };
	
	
	
	
	
	
	/*UI.BrushPreview()
	A canvas previewing brush settings. Can expand and collapse in size. (halfBoxSize * 4 and halfBoxSize * 2)
	
	expand(<boolean>)		Expand or collapse depending on param
	update(brushState)		Updates the preview
	getDiv()				Returns the canvas
	
	brushState = {
		symmetry: "horizontal" | "vertical"		Brush symmetry
		mode: "pull" | "stroke" | "fill"		Brush mode
		gradient: <boolean>						Brush using gradient or not
		splat: <boolean>						Splat modifier
		size: <number>							Brush Size (0.0 - 1.0)
	}
	*/
    UI.BrushPreview = function () {
		var width, height, pathData, pathData2, pathData3, pathData4, canvas, brushState;
        width = UI.theme.halfBoxSize * 4;
        height = UI.theme.halfBoxSize * 4;
        pathData = {
            d: "M -41.936042,47.619745 C -53.113503,10.095445 -37.63726,-10.737795 -3.2141263,1.712345 23.995161,11.553245 55.866726,-13.457185 42.294107,-46.191174"
        };
        pathData2 = {
            d: "M 42.118953,-49.472741 L 48.008453,-34.372628 33.909333,-32.584456 42.832827,4.1724005 24.98584,-4.3710848 15.169993,25.233085 -3.033942,-2.1855418 -8.5665048,9.934286 -39.977208,-9.3382278 -29.625953,7.3513719 -47.829884,21.656742 -30.161363,26.226513 -46.223655,49.472741"
        };
        pathData3 = {
            d: "M 19.921862,-31.093434 C 11.425935,-36.559012 4.4560701,-46.078656 -6.4549733,-46.444027 -13.466007,-47.219789 -20.342393,-38.624506 -16.348469,-32.261038 -9.9770798,-27.415153 -21.782777,-24.539302 -22.099064,-19.347804 -22.355747,-15.407325 -18.817161,-12.303889 -18.657262,-8.3064167 -17.61268,-3.9385691 -20.801225,0.29790503 -25.023234,1.2827118 -30.90754,4.0144405 -36.019277,10.400293 -43.158623,8.8617894 -48.395622,6.5129021 -44.128601,0.03681353 -45.238424,-3.7931189 -49.134611,0.26500193 -49.434806,7.2004769 -48.405542,12.675947 -47.066346,18.115802 -45.277115,24.034288 -41.051169,27.94193 -37.393808,31.10386 -30.403337,31.407858 -28.200735,26.382428 -25.677447,19.86532 -25.708699,11.278318 -19.090786,7.2233169 -14.576697,5.7454856 -9.9840961,3.2928095 -8.2552994,-1.4767809 -6.1015708,-5.811949 -6.1720668,-10.796324 -4.8140148,-15.320873 -2.1770567,-19.88032 3.642171,-16.956832 6.9161095,-14.780718 12.39294,-11.46364 17.508692,-5.5083485 16.20764,1.3237977 14.987171,6.8485296 8.5683761,9.4110863 3.4269817,8.1014806 -0.48485906,7.3778123 -5.3045722,7.0931532 -7.968277,10.690126 -16.24545,18.911517 -23.448649,28.145446 -31.854942,36.242204 -34.845091,39.784791 -31.913084,44.921017 -27.591483,45.171092 -22.88718,46.205469 -19.000528,42.892733 -15.30467,40.64948 -10.676109,36.440184 -10.715707,28.398924 -4.5171342,25.743318 2.3812396,26.987126 8.1135271,34.007252 15.585616,31.566418 21.298503,29.986619 27.085321,27.990893 31.653811,24.030658 37.029217,19.654343 41.066272,13.595996 42.804926,6.8683195 48.999355,3.4457589 51.357925,-6.949582 44.98537,-11.351114 39.961286,-13.7268 32.873133,-11.890427 29.100051,-16.817082 26.901628,-20.306746 29.04063,-24.739684 26.944367,-28.340545 25.705012,-31.653445 21.971265,-32.895355 18.851234,-31.521686"
        };
        pathData4 = {
            d: "M -3.3928572,-9.1071431 C 1.8844166,-22.684329 9.1936364,-36.231724 21.2336,-44.954446 18.889152,-35.488968 8.7189094,-30.543752 6.1968079,-21.198115 4.540427,-14.127493 13.811808,-18.053971 17.904513,-16.399023 23.455825,-15.873783 31.034572,-15.577909 33.846356,-21.529381 34.97236,-27.178717 34.064519,-33.258341 36.360093,-38.646557 40.639296,-42.124064 38.798722,-33.776723 38.966474,-31.358658 38.700763,-23.545103 38.434325,-15.715787 38.903013,-7.9043399 32.18549,-10.589101 25.192172,-14.343131 17.740497,-13.365214 10.777427,-12.141435 18.490107,-5.8630115 20.207822,-2.6629816 24.448086,2.5452753 28.352576,8.0130956 31.634096,13.871162 37.75413,23.368518 43.389314,33.406784 46.172979,44.440639 40.227035,31.956693 31.8578,20.864138 23.56321,9.8762996 21.479194,6.2297593 19.486438,1.9504585 15.812957,-0.2801517 14.426089,3.4818426 17.120975,8.3035823 16.91116,12.588411 17.656821,20.294699 16.327723,29.592587 9.0185981,33.820098 3.4051168,37.675435 -3.4592808,39.156261 -10.061416,40.373571 -1.6142398,39.00424 7.5916758,35.792928 12.509583,28.31636 16.514618,21.870622 12.492442,13.681843 7.1905113,9.3595596 1.6449937,4.481116 -7.478976,3.4383431 -13.210305,8.5751687 -20.154779,13.335392 -27.819571,16.947171 -35.420274,20.520931 -30.671416,17.793559 -24.763392,16.188231 -21.490052,11.530331 -20.267852,6.6922819 -27.279828,6.8132116 -29.45833,3.7127513 -38.505789,-4.4393085 -42.045771,-16.902644 -43.183273,-28.641484 -43.008475,-34.118701 -41.270075,-40.494922 -36.284204,-43.478438 -32.187069,-45.203636 -42.834793,-38.165764 -37.002266,-37.609093 -32.514252,-37.615042 -28.346869,-41.007974 -23.839041,-38.753083 -21.66147,-37.844362 -16.347373,-36.481722 -16.698858,-34.317536 -21.89964,-34.795345 -26.81718,-38.823228 -32.125966,-36.107746 -37.208062,-34.53346 -40.488607,-28.190417 -37.305263,-23.476422 -35.36476,-19.096901 -30.585812,-15.887464 -25.748981,-17.665295 -19.915267,-19.332041 -15.346006,-23.91773 -12.73449,-29.267934 -10.388912,-32.377307 -7.2082669,-37.827343 -4.5236747,-39.047157 -6.8851377,-33.918724 -11.44606,-30.258409 -13.950533,-25.184503 -16.253969,-20.790831 -19.168687,-15.5335 -17.155062,-10.515596 -14.158456,-5.6058719 -8.0980074,-8.3345678 -3.5714286,-6.9642859"
        };
        canvas = document.createElement("canvas");
        if (window.devicePixelRatio > 1) {
            canvas.width = width * 2;
            canvas.height = height * 2;
        } else {
            canvas.width = width;
            canvas.height = height;
        }

        LIB.css(canvas, {
            transformOrigin: "100% 0",
            position: "absolute",
            left: 0,
            top: 0,
            transform: "scale(0.5)",
            transition: "all 0.1s linear",
            width: width + "px",
            height: height + "px"
        });
        brushState = {};

        function draw() {
			var context, color, max, i;
            canvas.width = parseInt(canvas.width, 10);
            context = canvas.getContext("2d");
            context.setTransform(1, 0, 0, 1, 0, 0);
            if (window.devicePixelRatio > 1) {
                context.scale(2, 2);
            }
            color = "rgba(255, 255, 255, 1)";
            context.save();
            context.translate(width / 11, height / 11);
            context.scale(9 / 11, 9 / 11);

            max = 1;
            if (brushState.symmetry === "horizontal") {
                max += 1;
                context.scale(0.5, 1);
            } else if (brushState.symmetry === "vertical") {
                max += 1;
                context.scale(1, 0.5);
            }
            for (i = 0; i < max; i += 1) {
                if (i === 1) {
                    if (brushState.symmetry === "horizontal") {
                        context.translate(2 * width, 0);
                        context.scale(-1, 1);
                    }
                    if (brushState.symmetry === "vertical") {
                        context.translate(0, 2 * height);
                        context.scale(1, -1);
                    }
                }
                context.save();
                if (brushState.mode === "pull") {
                    if (brushState.gradient) {
                        color = context.createLinearGradient(0, -50, 0, 50);
                        color.addColorStop(0, "rgba(255, 255, 255, 1)");
                        color.addColorStop(1, "rgba(255, 255, 255, 0)");
                    }
                    context.fillStyle = color;
                    context.save();
                    context.translate(width / 2, height / 2);
                    context.scale(1 / 200 * width, 1 / 200 * height);
                    if (brushState.splat) {
                        LIB.drawPathOnCanvas(pathData4, context);
                    } else {
                        LIB.drawPathOnCanvas(pathData3, context);
                    }
                    context.fill();
                    context.restore();

                    context.save();
                    context.translate(0.2 * width, 0.8 * height);
                    context.scale(1 / 200 * width, 1 / 200 * height);
                    context.rotate(786);
                    if (brushState.splat) {
                        LIB.drawPathOnCanvas(pathData4, context);
                    } else {
                        LIB.drawPathOnCanvas(pathData3, context);
                    }
                    context.fill();
                    context.restore();

                    context.save();
                    context.translate(0.8 * width, 0.2 * height);
                    context.scale(1 / 200 * width, 1 / 200 * height);
                    context.rotate(1786);
                    if (brushState.splat) {
                        LIB.drawPathOnCanvas(pathData4, context);
                    } else {
                        LIB.drawPathOnCanvas(pathData3, context);
                    }
                    context.fill();
                    context.restore();
                } else {

                    if (brushState.gradient) {
                        color = context.createLinearGradient(0, -50, 0, 50);
                        color.addColorStop(0, "rgba(255, 255, 255, 1)");
                        color.addColorStop(1, "rgba(255, 255, 255, 0)");
                    }
                    context.lineWidth = 1 + brushState.size * brushState.size;
                    context.lineJoin = "round";
                    context.lineCap = "round";
                    context.strokeStyle = color;
                    context.fillStyle = color;
                    context.translate(width / 2, height / 2);
                    context.scale(1 / 100 * width, 1 / 100 * height);

                    if (brushState.splat) {
                        LIB.drawPathOnCanvas(pathData2, context);
                    } else {
                        LIB.drawPathOnCanvas(pathData, context);
                    }
                    if (brushState.mode === "stroke") {
                        context.stroke();
                    } else {
                        context.fill();
                    }
                }
                context.restore();
            }

            context.restore();
        }
        this.expand = function (p) {
            if (p) {
                LIB.css(canvas, {
                    transform: "scale(1)"
                });
                canvas.title = "Brush Preview";
            } else {
                LIB.css(canvas, {
                    transform: "scale(0.5)"
                });
                canvas.title = "";
            }
        };
        this.update = function (p) {
            brushState = p;
            draw();
        };
        this.getDiv = function () {
            return canvas;
        };
    };
	/*UI.BrushButtonBarCombination(p)
	Like a ButtonBarCombination but with a brush preview and a width of 4 * halfBoxSize
	p = {
		callback: <function(cbVal)>		Callback on expanding/collapsing
	}
	cbVal = {
		expand:	<boolean>		True on expand
		collapse: <boolean>		True on collapse
	}
	collapse()						Collapses combination. Also causes a callback.
	addListener(<function(evt)>)	Adds a callback listener
	updateBrushPreview(brushState)	Update the brush preview and opacity label
	getBar()						Returns the ExpandBar object (not div)
	getButton()						Returns the ExpandButton object (not div)
	
	brushState = {
		opacity: <number>						Brush opacity (0.0 - 1.0)
		symmetry: "horizontal" | "vertical"		Brush symmetry
		mode: "pull" | "stroke" | "fill"		Brush mode
		gradient: <boolean>						Brush using gradient or not
		splat: <boolean>						Splat modifier
		size: <number>							Brush Size (0.0 - 1.0)
	}
	*/
    UI.BrushButtonBarCombination = function (p) {
        var bar, listeners, buttonContainer, boxSize, opacity, preview, opacityDiv, overlayTimeout, opacityOverlay, shadowBox;
        boxSize = UI.theme.halfBoxSize * 2;
        opacity = 1;
        listeners = [];
        if (p && p.callback !== undefined) {
            listeners.push(p.callback);
        }

        function callback(p) {
            var i;
            for (i = 0; i < listeners.length; i += 1) {
                listeners[i](p);
            }
        }

        function updateOpacityDiv() {
            opacityDiv.innerHTML = '<span style="font-size: ' + parseInt(UI.theme.halfBoxSize / 1.8, 10) + 'px; opacity: 0.8">opacity</span><br/>' + parseInt(100 * Math.max(0.05, Math.min(1, opacity)), 10) + '%';
        }
        bar = new UI.ExpandBar({
            width: 7,
            height: 2
        });
        buttonContainer = new UI.ExpandButton({
            text: " ",
            callback: function (val) {
                if (val.expanded) {
                    bar.expand();
                    preview.expand(true);
                    opacityDiv.style.display = "none";
                    LIB.css(opacityOverlay, {
                        top: (UI.theme.halfBoxSize * 1.5) + "px"
                    });
                    callback({
                        expand: true
                    });
                } else if (val.expanded === false) {
                    bar.collapse();
                    preview.expand(false);
                    updateOpacityDiv();
                    opacityDiv.style.display = "block";
                    preview.getDiv().style.opacity = 1;
                    LIB.css(opacityOverlay, {
                        top: (-2 * boxSize) + "px"
                    });
                    callback({
                        collapse: true
                    });
                }
            }
        });
        LIB.css(buttonContainer.getDiv(), {
            position: "relative",
            width: (boxSize * 2) + "px"
        });

        preview = new UI.BrushPreview();
        opacityDiv = document.createElement("div");
        updateOpacityDiv();
        LIB.css(opacityDiv, {
            position: "absolute",
            left: 0,
            top: 0,
            width: boxSize + "px",
            height: boxSize + "px",
            textAlign: "center",
            fontSize: (UI.theme.halfBoxSize / 1.4) + "px"
        });
        opacityOverlay = document.createElement("div");
        LIB.css(opacityOverlay, {
            position: "absolute",
            left: 0,
            top: (-2 * boxSize) + "px",
            width: (boxSize * 2) + "px",
            textAlign: "center",
            opacity: 0,
            transition: "opacity 0.1s linear",
            textShadow: "1px 2px 1px rgba(0,0,0,1)",
            fontWeight: "bold"
        });
        opacityOverlay.innerHTML = "100%";
        buttonContainer.getDiv().appendChild(preview.getDiv());
        buttonContainer.getDiv().appendChild(opacityDiv);
        buttonContainer.getDiv().appendChild(opacityOverlay);

        shadowBox = document.createElement("div");
        LIB.css(shadowBox, {
            position: "absolute",
            left: (boxSize * 2) + "px",
            top: boxSize + "px",
            width: (boxSize * 2) + "px",
            height: boxSize + "px",
            boxShadow: "0 3px 4px rgba(0,0,0,0.3)"
        });
        bar.getContentDiv().appendChild(shadowBox);

        //interface
        this.collapse = function () {
            buttonContainer.collapse();
            bar.collapse();
            preview.expand(false);
            updateOpacityDiv();
            opacityDiv.style.display = "block";
            clearTimeout(overlayTimeout);
            opacityOverlay.style.opacity = 0;
            preview.getDiv().style.opacity = 1;
            LIB.css(opacityOverlay, {
                top: (-2 * boxSize) + "px"
            });
            callback({
                collapse: true
            });
        };
        this.addListener = function (p) {
            listeners.push(p);
        };
        this.updateBrushPreview = function (p) {
            if (opacity !== p.opacity) {
                opacity = p.opacity;
                opacityOverlay.innerHTML = parseInt(100 * Math.max(0.05, Math.min(1, opacity)), 10) + "%";
                opacityOverlay.style.opacity = 1;
                preview.getDiv().style.opacity = 0.4;
                clearTimeout(overlayTimeout);
                overlayTimeout = setTimeout(function () {
                    opacityOverlay.style.opacity = 0;
                    preview.getDiv().style.opacity = 1;
                }, 500);
            } else {
                preview.update(p);
            }
        };
        this.getBar = function () {
            return bar;
        };
        this.getButton = function () {
            return buttonContainer;
        };
    };


    /*UI.ColorSelection(callback)
	2 Sliders, one for Hue and one for Saturation/Value.
	callback	{r: 0-255, g: 0-255, b: 0-255} Currently selected color. On change.
	
	setcolor({r: , g: , b: })	Set color for sliders
	getDiv()					Returns the div element with both sliders
	*/
    UI.ColorSelection = function (callback) {
        var div, color, boxSize, border, svCanvas, svDivSize, hCanvas, svPointer, hPointer;
        div = document.createElement("div");
        div.style.position = "relative";
        boxSize = UI.theme.halfBoxSize * 2;
        border = boxSize * 0.2;
        svCanvas = document.createElement("canvas");
        svCanvas.width = 10;
        svCanvas.height = 10;
        svDivSize = {
            width: parseInt(boxSize * 3 - 1.5 * border, 10),
            height: parseInt(boxSize * 3 - 2 * border, 10)
        };
        hCanvas = document.createElement("canvas");
        hCanvas.width = parseInt(boxSize - 1.5 * border, 10);
        hCanvas.height = parseInt(boxSize * 3 - 2 * border, 10);
        //create hue gradient
        (function () {
            var ctx, gradH, i, col;
            ctx = hCanvas.getContext("2d");
            gradH = ctx.createLinearGradient(0, hCanvas.height, 0, 0);
            for (i = 0; i < 1; i += 0.02) {
                col = LIB.color.hsvToRgb({
                    h: i * 360,
                    s: 100,
                    v: 100
                });
                gradH.addColorStop(i, 'rgb(' + parseInt(col.r, 10) + ", " + parseInt(col.g, 10) + ", " + parseInt(col.b, 10) + ")");
            }
            ctx.fillStyle = gradH;
            ctx.fillRect(0, 0, hCanvas.width, hCanvas.height);
        }());
        svPointer = document.createElement("div");
        hPointer = document.createElement("div");

        function updateSV() {
            var svContext, stepHeight, i, gradient1, colleft, colright;
            svContext = svCanvas.getContext("2d");
            stepHeight = 1;
            for (i = 0; i < svCanvas.height; i += stepHeight) {
                gradient1 = svContext.createLinearGradient(0, 0, svCanvas.width, 0);
                colleft = LIB.color.hsvToRgb({
                    h: color.h,
                    s: 1,
                    v: 100 - (i / svCanvas.height * 100.0)
                });
                colright = LIB.color.hsvToRgb({
                    h: color.h,
                    s: 100,
                    v: 100 - (i / svCanvas.height * 100.0)
                });
                gradient1.addColorStop(0, LIB.color.rgbToHex(colleft));
                gradient1.addColorStop(1, LIB.color.rgbToHex(colright));
                svContext.fillStyle = gradient1;
                svContext.fillRect(0, i, svCanvas.width, stepHeight);
            }
        }

        function updateCursors() {
            LIB.css(svPointer, {
                left: ((boxSize + 0.5 * border) + svDivSize.width * color.s / 100) + "px",
                top: (border + svDivSize.height * (100 - color.v) / 100) + "px"
            });
            LIB.css(hPointer, {
                left: border + "px",
                top: (border + svDivSize.height * (1 - color.h / 360)) + "px"
            });
        }

        function update() {
            updateSV();
            updateCursors();
        }
        LIB.attachMouseListener(svCanvas, function (val) {
            var newCol;
            if (val.dragdone === false) {
                color.s = val.x * 100;
                color.v = (1 - val.y) * 100;
                newCol = LIB.color.hsvToRgb({
                    h: color.h,
                    s: color.s,
                    v: color.v
                });
                color.r = newCol.r;
                color.g = newCol.g;
                color.b = newCol.b;
                updateCursors();
                callback(color);
            }
        });
        LIB.attachMouseListener(hCanvas, function (val) {
            var newCol;
            if (val.dragdone === false) {
                color.h = (1 - val.y) * 359;
                newCol = LIB.color.hsvToRgb({
                    h: color.h,
                    s: color.s,
                    v: color.v
                });
                color.r = newCol.r;
                color.g = newCol.g;
                color.b = newCol.b;
                update();
                callback(color);
            }
        });
        //css
        LIB.css(svCanvas, {
            position: "absolute",
            left: (boxSize + 0.5 * border - UI.theme.halfBoxSize / 22) + "px",
            top: (border - UI.theme.halfBoxSize / 22) + "px",
            width: svDivSize.width + "px",
            height: svDivSize.height + "px",
            border: (UI.theme.halfBoxSize / 22) + "px solid " + UI.theme.barCol
        });
        LIB.css(hCanvas, {
            position: "absolute",
            left: (border - UI.theme.halfBoxSize / 22) + "px",
            top: (border - UI.theme.halfBoxSize / 22) + "px",
            border: (UI.theme.halfBoxSize / 22) + "px solid " + UI.theme.barCol
        });
        LIB.css(svPointer, {
            position: "absolute",
            width: "10px",
            height: "10px",
            borderRadius: "5px",
            pointerEvents: "none",
            border: "1px solid rgba(255, 255, 255, 1)",
            boxShadow: "0 0 0 1px rgba(0, 0, 0, 1)",
            marginLeft: "-6px",
            marginTop: "-6px"
        });
        LIB.css(hPointer, {
            position: "absolute",
            width: hCanvas.width + "px",
            height: "0px",
            pointerEvents: "none",
            borderTop: "2px solid #fff",
            borderBottom: "2px solid #000"
        });
        div.appendChild(svCanvas);
        div.appendChild(hCanvas);
        div.appendChild(svPointer);
        div.appendChild(hPointer);

        function setColor(c) {
            var hsv;
            color = c;
            hsv = LIB.color.rgbToHsv({
                r: c.r,
                g: c.g,
                b: c.b
            });
            color.h = hsv.h;
            color.s = hsv.s;
            color.v = hsv.v;
            update();
        }
        this.setColor = function (c) {
            setColor(c);
        };
        this.getDiv = function () {
            return div;
        };
		this.getColor = function() {
			return color;
		};
    };
	/*UI.ColorSwatch(callback)
	Offers a few color palettes that can be customized.
	callback({r, g, b})		when a new color was selected
	
	setColor({r, g, b})		Set the currently selected color ... also needs to be done after callback
	getDiv()				Get the div of the element
     */
    UI.ColorSwatch = function (callback) {
        var div, size, boxSize, pxSize, pageTransitioning, colorLibrary, colorSetIndex, values, gridArea, pageContainer,
			currentSwatchSet, swatchSets, i, selectedColor, currentColBox, dragMeLabel, dragging, drawPos, target,
			lastTime, aniFac, inputPos, dragBox, previousButton, nextButton, pageLabel;
        size = 0.75;
        boxSize = UI.theme.halfBoxSize * 2;
        pxSize = UI.theme.halfBoxSize / 22;
        pageTransitioning = false;
        div = document.createElement("div");
        LIB.css(div, {
            position: "relative"
        });

        colorLibrary = [
            [{
                r: 75,
				g: 82,
				b: 22
            }, {
                r: 24,
				g: 36,
				b: 20
            }, {
                r: 243,
                g: 244,
                b: 243
            }, {
                r: 178,
                g: 146,
                b: 54
            }, {
                r: 234,
                g: 134,
                b: 12
            }, {
                r: 197,
                g: 75,
                b: 20
            }, {
                r: 150,
                g: 30,
                b: 14
            }, {
                r: 79,
                g: 145,
                b: 176
            }],
            [{
                r: 68,
                g: 253,
                b: 72
            }, {
                r: 249,
                g: 220,
                b: 55
            }, {
                r: 252,
                g: 14,
                b: 28
            }, {
                r: 4,
                g: 40,
                b: 129
            }, {
                r: 252,
                g: 41,
                b: 252
            }, {
                r: 28,
                g: 166,
                b: 253
            }, {
                r: 255,
                g: 255,
                b: 255
            }, {
                r: 0,
                g: 0,
                b: 0
            }],
			[{
                r: 66,
                g: 95,
                b: 67
            }, {
                r: 113,
                g: 85,
                b: 63
            }, {
                r: 35,
                g: 68,
                b: 147
            }, {
                r: 227,
                g: 215,
                b: 199
            }, {
                r: 210,
                g: 166,
                b: 119
            }, {
                r: 236,
                g: 89,
                b: 71
            }, {
                r: 127,
                g: 54,
                b: 39
            }, {
                r: 15,
                g: 27,
                b: 27
            }],
            [{
                r: 29,
                g: 42,
                b: 74
            }, {
                r: 69,
                g: 74,
                b: 138
            }, {
                r: 140,
                g: 152,
                b: 193
            }, {
                r: 244,
                g: 249,
                b: 255
            }, {
                r: 57,
                g: 231,
                b: 255
            }, {
                r: 47,
                g: 119,
                b: 195
            }, {
                r: 54,
                g: 75,
                b: 78
            }, {
                r: 111,
                g: 143,
                b: 43
            }],
            [{
                r: 181,
                g: 153,
                b: 211
            }, {
                r: 227,
                g: 154,
                b: 139
            }, {
                r: 150,
                g: 216,
                b: 228
            }, {
                r: 223,
                g: 140,
                b: 77
            }, {
                r: 251,
                g: 252,
                b: 238
            }, {
                r: 76,
                g: 72,
                b: 115
            }, {
                r: 111,
                g: 80,
                b: 84
            }, {
                r: 198,
                g: 188,
                b: 97
            }]
        ];
        colorSetIndex = 0;
        values = colorLibrary[colorSetIndex];

        function createButton(x, y) {
            var div = document.createElement("div");
            LIB.css(div, {
                position: "absolute",
                left: (x * boxSize) + "px",
                top: (y * boxSize) + "px",
                width: (size * boxSize) + "px",
                height: (size * boxSize) + "px",
                marginLeft: ((1 - size) * UI.theme.halfBoxSize - pxSize) + "px",
                marginTop: ((1 - size) * UI.theme.halfBoxSize - pxSize) + "px",
                border: pxSize + "px solid rgba(255, 255, 255, 0.5)",
                backgroundColor: "rgb(0, 0, 0)"
            });
            div.setColor = function (p) {
                LIB.css(div, {
                    backgroundColor: "rgb(" + p.r + ", " + p.g + ", " + p.b + ")"
                });
            };
            return div;
        }

        gridArea = document.createElement("div");
        LIB.css(gridArea, {
            position: "absolute",
            overflow: "hidden",
            width: (4 * boxSize) + "px",
            height: (2 * boxSize) + "px",
            top: boxSize + "px",
            left: 0,
            cursor: "pointer"
        });

        function gridClick(i) {
            if (i < 0 || i > 7) {
                return;
            }
            callback({
                r: values[i].r,
                g: values[i].g,
                b: values[i].b
            });
        }
        gridArea.onmousedown = function (event) {
            var off, x, y;
            off = LIB.getGlobalOff(gridArea);
            x = parseInt((event.pageX - off.x) / boxSize, 10);
            y = parseInt((event.pageY - off.y) / boxSize, 10);
            gridClick(x + 4 * y);
        };
        gridArea.ontouchstart = function (event) {
            var off, x, y;
            if (event.touches.length !== 1) {
                return false;
            }
            off = LIB.getGlobalOff(gridArea);
            x = parseInt((event.touches[0].pageX - off.x) / boxSize, 10);
            y = parseInt((event.touches[0].pageY - off.y) / boxSize, 10);
            UI.spawnGlow(off.x + boxSize * x + UI.theme.halfBoxSize, off.y + boxSize * y + UI.theme.halfBoxSize);
            gridClick(x + 4 * y);
            return false;
        };

        //PAGE Container
        pageContainer = [];
        pageContainer[0] = document.createElement("div");
        LIB.css(pageContainer[0], {
            position: "absolute",
            width: (4 * boxSize) + "px",
            height: (2 * boxSize) + "px",
            transition: "all 0.2s ease-out",
            left: (-4 * boxSize) + "px",
            top: 0
        });
        pageContainer[1] = document.createElement("div");
        LIB.css(pageContainer[1], {
            position: "absolute",
            width: (4 * boxSize) + "px",
            height: (2 * boxSize) + "px",
            transition: "all 0.2s ease-out",
            left: 0,
            top: 0
        });
        pageContainer[2] = document.createElement("div");
        LIB.css(pageContainer[2], {
            position: "absolute",
            width: (4 * boxSize) + "px",
            height: (2 * boxSize) + "px",
            transition: "all 0.2s ease-out",
            left: (4 * boxSize) + "px",
            top: 0
        });
        gridArea.appendChild(pageContainer[0]);
        gridArea.appendChild(pageContainer[1]);
        gridArea.appendChild(pageContainer[2]);
        //color boxes that get put into the pageContainers
        currentSwatchSet = 0;
        swatchSets = [
            [],
            []
        ];
        for (i = 0; i < 8; i += 1) {
            swatchSets[0][i] = createButton(i % 4, parseInt(i / 4, 10));
            swatchSets[1][i] = createButton(i % 4, parseInt(i / 4, 10));
            swatchSets[currentSwatchSet][i].setColor(values[i]);
            pageContainer[1].appendChild(swatchSets[currentSwatchSet][i]);
        }

        selectedColor = {
            r: 0,
            g: 0,
            b: 0
        };
        currentColBox = document.createElement("div");
        LIB.css(currentColBox, {
            position: "absolute",
            width: (boxSize + size * boxSize) + "px",
            height: (size * boxSize) + "px",
            left: ((1 - size) * UI.theme.halfBoxSize - pxSize * 2) + "px",
            top: ((1 - size) * UI.theme.halfBoxSize - pxSize * 2) + "px",
            backgroundColor: "rgb(" + selectedColor.r + ", " + selectedColor.g + ", " + selectedColor.b + ")",
            cursor: "move",
            border: (pxSize * 2) + "px solid rgba(255, 255, 255, 1)",
            borderRadius: (size * UI.theme.halfBoxSize + pxSize * 2) + "px",
            boxShadow: "0 2px 4px rgba(0, 0, 0, 1) inset"
        });
        dragMeLabel = document.createElement("div");
        dragMeLabel.innerHTML = "drag me";
        LIB.css(dragMeLabel, {
            opacity: 0.5,
            width: "100%",
            textAlign: "center",
            marginTop: (boxSize / 7) + "px",
            fontSize: (boxSize / 2.8) + "px"
        });
        currentColBox.appendChild(dragMeLabel);
        dragging = false;
        drawPos = {};
		inputPos = {};
        target = -1;

        function animate() {
			var delta, dist;
            if (!dragging) {
                return;
            }
            delta = new Date().getTime() - lastTime;
            while (delta > 16) {
                if (target !== -1) {
                    drawPos.x = 0.75 * drawPos.x + 0.25 * inputPos.x;
                    drawPos.y = 0.75 * drawPos.y + 0.25 * inputPos.y;

                } else {
                    drawPos.x = 0.9 * drawPos.x + 0.1 * inputPos.x;
                    drawPos.y = 0.9 * drawPos.y + 0.1 * inputPos.y;
                    if (Math.abs(drawPos.x - inputPos.x) < 1) {
                        drawPos.x = inputPos.x;
                    }
                    if (Math.abs(drawPos.y - inputPos.y) < 1) {
                        drawPos.y = inputPos.y;
                    }
                }
                aniFac = Math.max(0, aniFac * 0.8);
                delta -= 16;
                lastTime = new Date().getTime() - delta;
            }
            if (target !== -1) {
                LIB.css(dragBox, {
                    boxShadow: "0 0 4px 4px rgba(255, 255, 255, 1)"
                });
            } else {
                LIB.css(dragBox, {
                    boxShadow: "0 0 4px 4px rgba(255, 255, 255, 0.2)"
                });
            }
            dist = LIB.Vec2.dist(drawPos, {
                x: boxSize * 2,
                y: boxSize * 2
            });
            dist = Math.min(1, Math.max(0, 1 - (dist / UI.theme.halfBoxSize - 3) * 0.1));
            LIB.css(dragBox, {
                left: (aniFac * ((1 - size) * UI.theme.halfBoxSize) + (1 - aniFac) * (drawPos.x - size * UI.theme.halfBoxSize)) + "px",
                top: (aniFac * ((1 - size) * UI.theme.halfBoxSize) + (1 - aniFac) * (drawPos.y - size * UI.theme.halfBoxSize)) + "px",
                width: (aniFac * (boxSize + size * boxSize) + (1 - aniFac) * (size * boxSize)) + "px",
                opacity: dist,
                borderRadius: (aniFac * (size * UI.theme.halfBoxSize)) + "px"
            });

            requestAnimFrame(animate);
        }
        LIB.attachMouseListener(currentColBox, function (val) {
			var gridX, gridY, off;
            if (val.down && val.code === 0 && !dragging) {
                inputPos.x = val.absX + ((1 - size) * UI.theme.halfBoxSize);
                inputPos.y = Math.max(UI.theme.halfBoxSize, val.absY + ((1 - size) * UI.theme.halfBoxSize));
                drawPos.x = inputPos.x;
                drawPos.y = inputPos.y;
                dragging = true;
                LIB.css(dragBox, {
                    display: "block"
                });
                target = -1;
                aniFac = 1;
                lastTime = new Date().getTime();
                animate();
            }
            if (val.dragdone === false && dragging) {
                inputPos.x = val.absX + ((1 - size) * UI.theme.halfBoxSize);
                inputPos.y = Math.max(UI.theme.halfBoxSize, val.absY + ((1 - size) * UI.theme.halfBoxSize));
                gridX = parseInt(inputPos.x / boxSize, 10);
                gridY = parseInt(inputPos.y / boxSize, 10);
                target = -1;
                if (inputPos.x > 0 && gridX >= 0 && gridX < 4 && gridY > 0 && gridY < 3 && !pageTransitioning) {
                    inputPos.x = parseInt(inputPos.x / boxSize, 10) * boxSize + UI.theme.halfBoxSize;
                    inputPos.y = parseInt(inputPos.y / boxSize, 10) * boxSize + UI.theme.halfBoxSize;
                    target = gridX + (gridY - 1) * 4;
                }
            }
            if (val.dragdone && dragging) {
                LIB.css(dragBox, {
                    display: "none"
                });
                if (target !== -1 && !pageTransitioning) {
                    off = LIB.getGlobalOff(div);
                    UI.spawnGlow(off.x + inputPos.x, off.y + inputPos.y);
                    values[target] = {
                        r: selectedColor.r,
                        g: selectedColor.g,
                        b: selectedColor.b
                    };
                    swatchSets[currentSwatchSet][target].setColor(selectedColor);
                }
                dragging = false;
            }
        });
        dragBox = document.createElement("div");
        LIB.css(dragBox, {
            position: "absolute",
            width: (size * boxSize) + "px",
            height: (size * boxSize) + "px",
            left: 0,
            top: 0,
            backgroundColor: "rgb(" + selectedColor.r + ", " + selectedColor.g + ", " + selectedColor.b + ")",
            cursor: "move",
            display: "none"
        });

        previousButton = new UI.Button({
            im: "btn_previous.svg",
            animated: true,
            touchGlow: true,
            callback: function () {
				var i, temp;
                if (pageTransitioning) {
                    return;
                }
                pageTransitioning = true;
                colorSetIndex = (colorLibrary.length + colorSetIndex - 1) % colorLibrary.length;
                values = colorLibrary[colorSetIndex];
                pageLabel.setText((colorSetIndex + 1) + "/" + colorLibrary.length);

                temp = pageContainer[2];
                pageContainer[2] = pageContainer[1];
                pageContainer[1] = pageContainer[0];
                pageContainer[0] = temp;

                currentSwatchSet = (currentSwatchSet + 1) % 2;
                for (i = 0; i < 8; i += 1) {
                    swatchSets[currentSwatchSet][i].setColor(values[i]);
                    pageContainer[1].appendChild(swatchSets[currentSwatchSet][i]);
                }

                LIB.css(pageContainer[2], {
                    left: (4 * boxSize) + "px"
                });
                LIB.css(pageContainer[1], {
                    left: 0
                });
                LIB.css(pageContainer[0], {
                    display: "none",
                    left: (-4 * boxSize) + "px"
                });
                setTimeout(function () {
                    LIB.css(pageContainer[0], {
                        display: "block"
                    });
                    pageTransitioning = false;
                }, 210);
            }
        });
        LIB.css(previousButton.getDiv(), {
            position: "absolute",
            left: (boxSize * 2) + "px",
            top: 0
        });

        nextButton = new UI.Button({
            im: "btn_next.svg",
            animated: true,
            touchGlow: true,
            callback: function () {
				var i, temp;
                if (pageTransitioning) {
                    return;
                }
                pageTransitioning = true;
                colorSetIndex = (colorSetIndex + 1) % colorLibrary.length;
                values = colorLibrary[colorSetIndex];
                pageLabel.setText((colorSetIndex + 1) + "/" + colorLibrary.length);

                temp = pageContainer[0];
                pageContainer[0] = pageContainer[1];
                pageContainer[1] = pageContainer[2];
                pageContainer[2] = temp;

                currentSwatchSet = (currentSwatchSet + 1) % 2;
                for (i = 0; i < 8; i += 1) {
                    swatchSets[currentSwatchSet][i].setColor(values[i]);
                    pageContainer[1].appendChild(swatchSets[currentSwatchSet][i]);
                }

                LIB.css(pageContainer[0], {
                    left: (-4 * boxSize) + "px"
                });
                LIB.css(pageContainer[1], {
                    left: 0
                });
                LIB.css(pageContainer[2], {
                    display: "none",
                    left: (4 * boxSize) + "px"
                });
                setTimeout(function () {
                    LIB.css(pageContainer[2], {
                        display: "block"
                    });
                    pageTransitioning = false;
                }, 210);
            }
        });
        LIB.css(nextButton.getDiv(), {
            position: "absolute",
            left: (boxSize * 3) + "px",
            top: 0
        });

        pageLabel = new UI.Label({
            text: "1/" +  colorLibrary.length,
            width: 1
        });
        LIB.css(pageLabel.getDiv(), {
            position: "absolute",
            left: (boxSize * 4) + "px",
            top: boxSize + "px"
        });

        div.appendChild(gridArea);
        div.appendChild(currentColBox);
        div.appendChild(previousButton.getDiv());
        div.appendChild(nextButton.getDiv());
        div.appendChild(pageLabel.getDiv());
        div.appendChild(dragBox);

        //interface
        this.setColor = function (p) {
            selectedColor = {
                r: p.r,
                g: p.g,
                b: p.b
            };
            LIB.css(currentColBox, {
                backgroundColor: "rgb(" + selectedColor.r + ", " + selectedColor.g + ", " + selectedColor.b + ")"
            });
            LIB.css(dragBox, {
                backgroundColor: "rgb(" + selectedColor.r + ", " + selectedColor.g + ", " + selectedColor.b + ")"
            });
            if ((p.r + p.g + p.b * 0.2) / 2.3 / 255 > 0.4) {
                dragMeLabel.style.color = "#000";
            } else {
                dragMeLabel.style.color = "#fff";
            }
        };
        this.getDiv = function () {
            return div;
        };
		this.getCurrentPalette = function() {
			var result = [];
			for(var i = 0; i < values.length; i++) {
				result.push({
					r: values[i].r,
					g: values[i].g,
					b: values[i].b
				});
			}
			return result;
		};
    };



    /*UI.ColorButtonBarCombination(p)
	Coordinates two ColorButtons and an ExpandBar. ColorButtonBarCombination goes into a BarContainer.
	P = {
		callback: <function(evt)>	On state change
	}
	callback evt = {
		collapse: <boolean>		True on collapse
		expand: <boolean>		True on expand
		color: {r: , g: , b: }	Currently selected color
	}
	collapse()						Collapses combination. Also causes a callback.
	addListener(<function(evt)>)	Adds a callback listener
	setColor(col, <boolean>hidden)	Set selected color. if hidden no glow animation (when whole bar is hidden)
	getBar()						Returns the ExpandBar object (not div)
	getButton()						Returns object that contains a getDiv() method to get the div element
									that contains both ColorButtons
	getColors()						Returns both colors in arrray: [c1, c2]
	*/
    UI.ColorButtonBarCombination = function (p) {
        var bar, listeners, buttonContainer, button1, activeButton, colSel, button2, boxSize, pickButton, modeButton, MODE_COLSLIDER,
			MODE_SWATCH, mode, colSwatch;
        boxSize = UI.theme.halfBoxSize * 2;
        listeners = [];
        if (p.callback !== undefined) {
            listeners.push(p.callback);
        }

        function callback(p) {
            var i;
            for (i = 0; i < listeners.length; i += 1) {
                listeners[i](p);
            }
        }
        buttonContainer = document.createElement("div");
        LIB.css(buttonContainer, {
            width: (boxSize * 2) + "px",
            cssFloat: "left"
        });
        bar = new UI.ExpandBar({
            width: 5,
            height: 3
        });
        pickButton = new UI.Button({
            im: "btn_picker.svg",
            title: "Eye Dropper",
            callback: function () {
                callback({
                    pick: true
                });
            }
        });
        LIB.css(pickButton.getDiv(), {
            position: "absolute",
            left: (boxSize * 4) + "px",
            top: (boxSize * 3) + "px"
        });

        MODE_COLSLIDER = 0;
        MODE_SWATCH = 1;
        mode = MODE_COLSLIDER;
		
		
		function updateModeButton() {
			var canvas = modeBtnCanvas;
			var ctx = canvas.getContext("2d");
			canvas.height = canvas.height;
			
			var color = LIB.color.rgbToHsv({r: 0, g: 255, b: 0});
			if(colSel) {
				color = colSel.getColor();
			}
			if(!color) {
				color = LIB.color.rgbToHsv({r: 255, g: 0, b: 0});
			}
			
			function drawHueSlider(x, y, w, h) {
				x = Math.floor(x);
				y = Math.floor(y);
				w = Math.floor(w);
				h = Math.floor(h);
				var ctx, gradH, i, col;
				ctx = canvas.getContext("2d");
				gradH = ctx.createLinearGradient(0, y+h, 0, y);
				for (i = 0; i < 1; i += 0.02) {
					col = LIB.color.hsvToRgb({
						h: i * 360,
						s: 100,
						v: 100
					});
					gradH.addColorStop(i, 'rgb(' + parseInt(col.r, 10) + ", " + parseInt(col.g, 10) + ", " + parseInt(col.b, 10) + ")");
				}
				ctx.fillStyle = gradH;
				ctx.fillRect(x, y, w, h);
			}
			function drawSaturationValueSlider(x, y, w, h) {
				x = Math.floor(x);
				y = Math.floor(y);
				w = Math.floor(w);
				h = Math.floor(h);
				var stepHeight, i, gradient1, colleft, colright;
				stepHeight = 1;
				for (i = 0; i < h; i += stepHeight) {
					gradient1 = ctx.createLinearGradient(x, y, x + w, y);
					colleft = LIB.color.hsvToRgb({
						h: color.h,
						s: 1,
						v: 100 - (i / h * 100.0)
					});
					colright = LIB.color.hsvToRgb({
						h: color.h,
						s: 100,
						v: 100 - (i / h * 100.0)
					});
					gradient1.addColorStop(0, LIB.color.rgbToHex(colleft));
					gradient1.addColorStop(1, LIB.color.rgbToHex(colright));
					ctx.fillStyle = gradient1;
					ctx.fillRect(x, y + i, w, 1);
				}
			}
			ctx.save();
			var scale = 0.65;
			var border = canvas.width * (1 - scale) / 2;
			var content = canvas.width * scale;
			//
			if (mode === MODE_SWATCH) {
				ctx.translate(canvas.width / 2, canvas.height / 2);
				ctx.fillStyle = "rgba(255,255,255,0.5)";
				ctx.fillRect(Math.floor(-scale * canvas.width / 2 - 3), Math.floor(-scale * canvas.height / 2 - 3), Math.floor(scale * canvas.width + 6), Math.floor(scale * canvas.height + 6));
				ctx.translate(-canvas.width / 2, -canvas.height / 2);
				
				color = LIB.color.rgbToHsv(activeButton.getColor());
				drawHueSlider(border, border, content / 6, content);
				drawSaturationValueSlider(border + content / 6, border, content / 6 * 5, content);
				
			} else {
				var horScale = 0.4 + scale * 0.6;
				var vertScale = 0.7 * scale;
				
				ctx.translate(canvas.width / 2, canvas.height / 2);
				
				ctx.fillStyle = "rgba(255,255,255,0.5)";
				ctx.fillRect(-horScale * canvas.width / 2 - 3, -vertScale * canvas.height / 2 - 3, horScale * canvas.width + 6, vertScale * canvas.height + 6);
				
				ctx.scale(horScale, vertScale);
				
				var colors = colSwatch.getCurrentPalette();
				for(var i = 0; i < 8; i++) {
					ctx.fillStyle = "rgb(" + colors[i].r + ", " + colors[i].g + ", " + colors[i].b + ")";
					ctx.fillRect(canvas.width/4 * (i%4 - 2), (canvas.height/2) * Math.floor(i / 4 - 1), canvas.width/4, canvas.width/2);
				}
				
			}
			ctx.restore();
		}
		
		var modeBtnCanvas = document.createElement("canvas");
		modeBtnCanvas.height = boxSize * 2;
		modeBtnCanvas.width = boxSize * 2;
		
        modeButton = new UI.CanvasButton({
            canvas: modeBtnCanvas,
			im: "btn_swatch.svg",
            title: "Swatch",
            animated: true,
            touchGlow: "true",
            callback: function () {
                if (mode === MODE_COLSLIDER) {
                    mode = MODE_SWATCH;
                    //modeButton.setImage("btn_colSlider.svg");
					updateModeButton();
                    modeButton.setTitle("Slider");
                    colSel.getDiv().style.display = "none";
                    colSwatch.getDiv().style.display = "block";
                } else {
                    mode = MODE_COLSLIDER;
                   // modeButton.setImage("btn_swatch.svg");
				   updateModeButton();
                    modeButton.setTitle("Swatch");
                    colSel.getDiv().style.display = "block";
                    colSwatch.getDiv().style.display = "none";
                }
            }
        });
        LIB.css(modeButton.getDiv(), {
            position: "absolute",
            left: (boxSize * 4) + "px",
            top: boxSize + "px"
        });

        button1 = new UI.ColorButton({
            color: {
                r: 0,
                g: 0,
                b: 0
            },
            active: true,
            callback: function (val) {
                if (val.active) {
                    activeButton = button1;
                    button2.active(false);
                    bar.collapse();
                    callback({
                        collapse: true,
                        color: button1.getColor()
                    });
                }
                if (val.expanded) {
                    bar.expand();
                    if (mode === MODE_COLSLIDER) {
                        colSwatch.getDiv().style.display = "none";
                    }
                    colSel.setColor(activeButton.getColor());
                    colSwatch.setColor(activeButton.getColor());
					updateModeButton();
                    callback({
                        expand: true
                    });
                } else if (val.expanded === false) {
                    bar.collapse();
                    callback({
                        collapse: true
                    });
                }
            }
        });
        button2 = new UI.ColorButton({
            color: {
                r: 255,
                g: 255,
                b: 255
            },
            active: false,
            callback: function (val) {
                if (val.active) {
                    activeButton = button2;
                    button1.active(false);
                    bar.collapse();
                    callback({
                        collapse: true,
                        color: button2.getColor()
                    });
                }
                if (val.expanded) {
                    bar.expand();
                    if (mode === MODE_COLSLIDER) {
                        colSwatch.getDiv().style.display = "none";
                    }
                    colSel.setColor(activeButton.getColor());
                    colSwatch.setColor(activeButton.getColor());
					updateModeButton();
                    callback({
                        expand: true
                    });
                } else if (val.expanded === false) {
                    bar.collapse();
                    callback({
                        collapse: true
                    });
                }
            }
        });
        buttonContainer.appendChild(button1.getDiv());
        buttonContainer.appendChild(button2.getDiv());
        activeButton = button1;
        colSwatch = new UI.ColorSwatch(function (c) {
            activeButton.setColor(c);
            colSel.setColor(activeButton.getColor());
            colSwatch.setColor(activeButton.getColor());
            callback({
                color: c
            });
			//collapse the menu to save some clicks
			button1.collapse();
            button2.collapse();
            bar.collapse();
        });
        //colSwatch needs to be visible to preload the graphics
        setTimeout(function () {
            if (mode === MODE_COLSLIDER) {
                colSwatch.getDiv().style.display = "none";
            }
        }, 1000);
        colSel = new UI.ColorSelection(function (c) {
            activeButton.setColor(c);
            colSwatch.setColor(activeButton.getColor());
            callback({
                color: c
            });
        });
        bar.getContentDiv().appendChild(colSel.getDiv());
        bar.getContentDiv().appendChild(modeButton.getDiv());
        bar.getContentDiv().appendChild(pickButton.getDiv());
        bar.getContentDiv().appendChild(colSwatch.getDiv());
        //interface
        this.collapse = function () {
            button1.collapse();
            button2.collapse();
            bar.collapse();
            callback({
                collapse: true
            });
        };
        this.addListener = function (p) {
            listeners.push(p);
        };
        this.setColor = function (p, hidden) {
            var off;
            activeButton.setColor(p);
            if (!hidden) {
                off = LIB.getGlobalOff(activeButton.getDiv());
                UI.spawnGlow(off.x + UI.theme.halfBoxSize, off.y + UI.theme.halfBoxSize);
            }
            colSel.setColor(activeButton.getColor());
            colSwatch.setColor(activeButton.getColor());
			updateModeButton();
        };
        this.getBar = function () {
            return bar;
        };
        this.getButton = function () {
            return {
                getDiv: function () {
                    return buttonContainer;
                }
            };
        };
        this.getColors = function () {
            return [button1.getColor(), button2.getColor()];
        };
    };
	
	
	/*UI.BarContainer(callback)
	Manages all ButtonBarCombinations. Puts all ExpandButtons and ColorButtons on their own bar.
	
	callback		Callback on toggleHide - tells you if bar is hidden or not
	
	add(<ButtonBarCombination> or <ColorButtonBarCombination>)	Add a combination
	addRegularButton(<Button>)		Add a UI.Button - so something that doesn't expand
									The button won't be affected
	toggleHide()	Toggles between showing and hiding the BarContainer. Animated.
	collapse()		Collapses currently expanded bar
	isHidden()		Is the bar hidden or visible
	getDiv()		Return div element of BarContainer
	*/
    UI.BarContainer = function (p) {
        var bars, div, frontDiv, backDiv, boxSize, current, hidden, callback, line1, line2, line3, line4, line5;
        bars = [];
        div = document.createElement("div");
        frontDiv = document.createElement("div");
        backDiv = document.createElement("div");
        boxSize = UI.theme.halfBoxSize * 2;
        hidden = false;
        callback = p.callback;
        //style
        LIB.css(div, {
            width: (7 * boxSize) + "px",
            height: boxSize + "px",
            position: "absolute",
            transition: "top 0.1s ease-out",
            marginLeft: (-boxSize * 3.5) + "px",
            top: "0"
        });
        LIB.css(frontDiv, {
            width: (7 * boxSize) + "px",
            height: boxSize + "px",
            backgroundColor: UI.theme.barCol,
            position: "absolute",
            left: "0",
            top: "0",
            borderBottomRightRadius: (UI.theme.halfBoxSize / 3) + "px",
            borderBottomLeftRadius: (UI.theme.halfBoxSize / 3) + "px"
        });
        LIB.css(backDiv, {
            width: (7 * boxSize) + "px",
            height: boxSize + "px",
            position: "absolute",
            left: "0",
            top: "0",
            borderBottomRightRadius: (UI.theme.halfBoxSize / 3) + "px",
            borderBottomLeftRadius: (UI.theme.halfBoxSize / 3) + "px",
            boxShadow: "0 2px 4px rgba(0, 0, 0, 0.5)"
        });

        line1 = UI.div({
            type: "image",
            src: "highlight.png",
            position: "absolute",
            left: (UI.theme.halfBoxSize * 2 - UI.theme.halfBoxSize / 11) + "px",
            top: "0",
            pointerEvents: "none",
            width: (UI.theme.halfBoxSize / 11) + "px",
            height: (UI.theme.halfBoxSize * 2) + "px"
        });
        line2 = UI.div({
            type: "image",
            src: "highlight.png",
            position: "absolute",
            left: (UI.theme.halfBoxSize * 2 * 2 - UI.theme.halfBoxSize / 11) + "px",
            top: "0",
            pointerEvents: "none",
            width: (UI.theme.halfBoxSize / 11) + "px",
            height: (UI.theme.halfBoxSize * 2) + "px"
        });
        line3 = UI.div({
            type: "image",
            src: "highlight.png",
            position: "absolute",
            left: (UI.theme.halfBoxSize * 2 * 4 - UI.theme.halfBoxSize / 11) + "px",
            top: "0",
            pointerEvents: "none",
            width: (UI.theme.halfBoxSize / 11) + "px",
            height: (UI.theme.halfBoxSize * 2) + "px"
        });
		line4 = UI.div({
            type: "image",
            src: "highlight.png",
            position: "absolute",
            left: (UI.theme.halfBoxSize * 2 * 5 - UI.theme.halfBoxSize / 11) + "px",
            top: "0",
            pointerEvents: "none",
            width: (UI.theme.halfBoxSize / 11) + "px",
            height: (UI.theme.halfBoxSize * 2) + "px"
        });
        line5 = UI.div({
            type: "image",
            src: "highlight.png",
            position: "absolute",
            left: (UI.theme.halfBoxSize * 2 * 6 - UI.theme.halfBoxSize / 11) + "px",
            top: "0",
            pointerEvents: "none",
            width: (UI.theme.halfBoxSize / 11) + "px",
            height: (UI.theme.halfBoxSize * 2) + "px"
        });

        frontDiv.appendChild(line1);
        frontDiv.appendChild(line2);
        frontDiv.appendChild(line3);
        frontDiv.appendChild(line4);
        frontDiv.appendChild(line5);


        frontDiv.className = "WebchemyAppShadedBar";
        LIB.addCssRule(".WebchemyAppShadedBar", "background: -webkit-linear-gradient(bottom, rgba(255, 255, 255, 0) 20%, rgba(255, 255, 255, 0.4) 100%); background-image: -moz-linear-gradient(center bottom, rgba(255, 255, 255, 0) 20%, rgba(255, 255, 255, 0.4) 100%); background-image: -o-linear-gradient(bottom, rgba(255, 255, 255, 0) 20%, rgba(255, 255, 255, 0.4) 100%); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#88ffffff', endColorstr='#00ffffff'); background-image: linear-gradient(to top, rgba(255, 255, 255, 0) 20%, rgba(255, 255, 255, 0.4) 100%);");
        div.appendChild(backDiv);
        div.appendChild(frontDiv);
        this.add = function (p) {
            bars.push(p);
            frontDiv.appendChild(p.getButton().getDiv());
            backDiv.appendChild(p.getBar().getDiv());
            p.addListener(function (val) {
                if (val.expand) {
                    if (current && current !== p) {
                        current.collapse();
                    }
                    current = p;
                }
                if (val.collapse) {
                    if (current === p) {
                        current = undefined;
                    }
                }
            });
        };
        this.addRegularButton = function (p) {
            frontDiv.appendChild(p.getDiv());
        };
        this.toggleHide = function () {
            if (current) {
                current.collapse();
                return;
            }
            hidden = !hidden;
            if (hidden) {
                LIB.css(div, {
                    top: (-boxSize - 10) + "px",
                    pointerEvents: "none"
                });
                if (current) {
                    current.collapse();
                }
                callback(true);
            } else {
                LIB.css(div, {
                    top: "0",
                    pointerEvents: ""
                });
                callback(false);
            }
        };
        this.collapse = function () {
            if (current) {
                current.collapse();
            }
        };
        this.isHidden = function () {
            return hidden;
        };
        this.getDiv = function () {
            return div;
        };
    };
	
	UI.androidPopup = function(p) {
		var div = document.createElement("div");
		var boxSize = 2 * UI.theme.halfBoxSize;
		var aniDur = 300;
		var bgCallback = function() {
		};
		if(p.callback) {
			bgCallback = p.callback;
		}
		
		LIB.css(div, {
			position: "fixed",
			left: 0,
			top: 0,
			height: "100%",
			width: "100%",
			display: "table",
			transition: "opacity " + (aniDur / 1000) + "s ease-in-out",
			opacity: 0,
			pointerEvents: "none"
		});
		
		var background = UI.div({
			position: "fixed",
			left: 0,
			top: 0,
			height: "100%",
			width: "100%",
			backgroundColor: "rgba(0, 0, 0, 0.5)",
			zIndex: -1
		});
		
		var topMargin = 1.5 * boxSize;
		if(window.innerHeight < 690) {
			topMargin = 0.5 * boxSize;
		}
		if(window.innerHeight < 380) {
			topMargin = 0.1 * boxSize;
		}
		
		var content = UI.div({
			//position: "fixed",
			//left: "50%",
			marginLeft: "auto",
			marginRight: "auto",
			//top: topMargin + "px",
			width: (7 * boxSize) + "px",
			//marginLeft: (-7 / 2 * boxSize) + "px",
			backgroundColor: UI.theme.expandCol,
			borderRadius: (boxSize / 22 * 5) + "px",
			boxSizing: "borderBox",
			boxShadow: "0 3px 4px rgba(0,0,0,0.3)",
			backgroundImage: "linear-gradient(to bottom, rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0) 70px)",
			//transition: "height 0.3s ease-in-out",
			height: 0,
			overflow: "hidden"
		});
		
		
		div.appendChild(background);
		
		var cell = UI.div({
			display: "table-cell",
			verticalAlign: "middle",
			parent: div
		});
		cell.appendChild(content);
		
		
		
		if(p.content) {
			content.appendChild(p.content);
		}
		
		background.onclick = bgCallback;
		
		this.getDiv = function() {
			return div;
		};
		this.show = function() {
			setTimeout(function() {
				LIB.css(div, {
					opacity: 1,
					pointerEvents: ""
				});
			}, 20);
		};
		this.hide = function(callback) {
			LIB.css(div, {
				opacity: 0,
				pointerEvents: "none"
			});
			setTimeout(function() {
				callback();
			}, aniDur);
		};
		this.setCallback = function(callback) {
			bgCallback = callback;
			background.onclick = bgCallback;
		}
	};
	
	UI.androidSavePopup = function(p) {
		var halfBoxSize = UI.theme.halfBoxSize;
		var blend = Math.min(1, Math.max(0, (window.innerHeight - 380) / (690 - 380)));
		halfBoxSize = blend * halfBoxSize + (1 - blend) * 19;

		
		var wc = p.webchemy;
		var dead = false;
		var isSaved = false;
		var content = UI.div({
			innerHTML: '...saving...<br><br>',
			padding: "20px",
			fontSize: (halfBoxSize * 0.8) + "px",
			textAlign: "center"
		});
		var loadingGif = UI.div({
			parent: content,
			width: "100%",
			height: (halfBoxSize * 1.5) + "px",
			backgroundRepeat: "no-repeat",
			backgroundImage: "url(loading.gif)",
			backgroundSize: (halfBoxSize * 1.5) + "px",
			backgroundPosition: "center center"
		});
		var pop = new UI.androidPopup({
			content: content
		});
		wc.getDiv().appendChild(pop.getDiv());
		
		pop.show();
		content.parentNode.style.height = content.offsetHeight + "px";
		
		var buttonStyle = {
			border: "1px solid " + UI.theme.labelColor,
			borderRadius: (halfBoxSize / 22 * 5) + "px",
			backgroundRepeat: "no-repeat",
			backgroundSize: (halfBoxSize * 2) + "px " + (halfBoxSize * 2) + "px",
			cursor: "pointer",
			lineHeight: (halfBoxSize * 2) + "px",
			fontSize: (halfBoxSize * 0.8) + "px",
			height: (halfBoxSize * 2) + "px",
			textAlign: "center",
			boxSizing: "border-box",
			backgroundColor: UI.theme.barCol
		};
		
		
		function close(cbParam) {
			if(dead) {
				return;
			}
			dead = true;
			
			if(!cbParam) {
				cbParam = {};
			}
			p.callback(cbParam);
			
			pop.hide(function() {
				wc.getDiv().removeChild(pop.getDiv());
			});
		}
		
		this.saved = function() {
			if(isSaved)	{
				return;
			}
			isSaved = true;
			content.innerHTML = "✔ Successfully Saved in Gallery<br>";
			
			pop.setCallback(function() {
				close();
			});
			
			var factor = 1;
			if(window.devicePixelRatio > 1) {
				factor = 2;
			}
			var maxWidth = factor * Math.floor(halfBoxSize * 2 * 6);
			var maxHeight = factor * Math.floor(halfBoxSize * 2 * 4);
			maxHeight = blend * maxHeight + (1 - blend) * (Math.floor(halfBoxSize * 2 * 2));
			
			var thumb = document.createElement("canvas");
			thumb.height = maxHeight;
			thumb.width = (maxHeight / p.image.height) * p.image.width;
			if(thumb.width > maxWidth) {
				thumb.width = maxWidth;
				thumb.height = (maxWidth / p.image.width) * p.image.height;
			}
			thumb.getContext("2d").drawImage(p.image, 0, 0, thumb.width, thumb.height);
			LIB.css(thumb, {
				border: "1px solid #aaa",
				marginBottom: (halfBoxSize / 4) + "px",
				marginTop: (halfBoxSize / 4) + "px",
				width: (thumb.width / factor) + "px",
				height: (thumb.height / factor) + "px"
			});
			content.appendChild(thumb);
			
			
			
			
			var okBtn = UI.div({
				parent: content,
				innerHTML: "Ok",
				style: buttonStyle,
				onclick: function() {
					close();
				},
				marginBottom: (halfBoxSize / 22 * 5) + "px"
			});
			
			/*var shareBtn = UI.div({
				parent: content,
				innerHTML: "Share Drawing",
				style: buttonStyle,
				onclick: function() {
					close({
						share: true
					});
				},
				backgroundImage: "url(share.png)"
			});*/
			
			/*if(!p.isPro) {
				UI.div({
					parent: content,
					innerHTML: "<br>Save without watermarks:"
				});
				var proBtn = UI.div({
				parent: content,
				innerHTML: "Get Pro for " + localStorage.getItem("proKeyPrice"),
				style: buttonStyle,
				onclick: function() {
					close({
						pro: true
					});
				}
			});
			}*/
		
			content.parentNode.style.height = content.offsetHeight + "px";
		};
		
		this.failed = function() {
			if(isSaved)	{
				return;
			}
			isSaved = true;
			
			content.innerHTML = "Sorry, couldn't save.<br><br>";
			
			
			pop.setCallback(function() {
				close();
			});
			
			var okBtn = UI.div({
				parent: content,
				innerHTML: "Ok",
				style: buttonStyle,
				onclick: function() {
					close();
				},
				marginBottom: (halfBoxSize / 22 * 5) + "px"
			});
			
			content.parentNode.style.height = content.offsetHeight + "px";
		};
		
		this.forceCancel = function() {
			close();
		};
	};
	/*
	p = {
		webchemy: wc, //webchemy object
		title: "Some dialog",
		msg: "Let me explain in more detail",
		buttons: [
			{
				title: "baba",
				image: "ababa.png"
			},
			{
				title,
				image
			}
		],
		skippable: true, //can click outside to close
		callback: function(val) {
			if(val == 0) //first button etc
			if(val == -1) //clicked outside
		}
	}
	*/
	UI.androidDialog = function(p) {
		var halfBoxSize = UI.theme.halfBoxSize;
		if(window.innerHeight < 600) {
			halfBoxSize = 22;
		}
		
		var wc = p.webchemy;
		var isSaved = false;
		var content = UI.div({
			innerHTML: '',
			padding: "20px",
			fontSize: (halfBoxSize * 0.8) + "px",
			textAlign: "center"
		});

		var pop = new UI.androidPopup({
			content: content
		});
		wc.getDiv().appendChild(pop.getDiv());
		pop.show();
		var dead = false;
		
		var buttonStyle = {
			border: "1px solid " + UI.theme.labelColor,
			borderRadius: (halfBoxSize / 22 * 5) + "px",
			backgroundRepeat: "no-repeat",
			backgroundSize: (halfBoxSize * 2) + "px " + (halfBoxSize * 2) + "px",
			cursor: "pointer",
			lineHeight: (halfBoxSize * 2) + "px",
			fontSize: (halfBoxSize * 0.8) + "px",
			//paddingLeft: (halfBoxSize * 2) + "px",
			height: (halfBoxSize * 2) + "px",
			textAlign: "center",
			boxSizing: "border-box",
			backgroundColor: UI.theme.barCol
		};
		
		
		content.innerHTML = p.title;
		if(p.msg) {
			new UI.div({
				parent: content,
				innerHTML: p.msg,
				textAlign: "justify",
				//color: UI.theme.labelColor,
				opacity: 0.6,
				fontSize: (halfBoxSize * 0.7) + "px",
				marginBottom: (halfBoxSize / 2) + "px",
				marginTop: (halfBoxSize / 4) + "px",
				borderTop: (halfBoxSize / 22 * 2) + "px solid " + UI.theme.labelColor,
				paddingTop: (halfBoxSize / 2) + "px"
			});
		}
		
		if(p.skippable) {
			pop.setCallback(function() {
				if(dead) {
					return;
				}
				dead = true;
				pop.hide(function() {
					wc.getDiv().removeChild(pop.getDiv());
					p.callback(-1);
				});
			});
		}
		
		var buttons = [];
		function addButton(i) {
			var btn = UI.div({
				parent: content,
				innerHTML: p.buttons[i].title,
				style: buttonStyle,
				onclick: function() {
					if(dead) {
						return;
					}
					dead = true;
					pop.hide(function() {
						wc.getDiv().removeChild(pop.getDiv());
						p.callback(i);
					});
				},
				marginTop: (halfBoxSize / 22 * 5) + "px"
			});
			if(p.buttons[i].image) {
				LIB.css(btn, {
					backgroundImage: "url(" + p.buttons[i].image + ")"
				});
			}
		}
		for(var i = 0; i < p.buttons.length; i++) {
			addButton(i);
		}
		
		content.parentNode.style.height = content.offsetHeight + "px";
		
		this.forceCancel = function() {
			if(dead) {
				return;
			}
			dead = true;
			pop.hide(function() {
				wc.getDiv().removeChild(pop.getDiv());
				p.callback(-1);
			});
		};
	};
	
})();