var Yes = true;
var No = false;

// controls
var blocks = new Array();
var blocks_cnt = 0;

var sliders = new Array();
var sliders_cnt = 0;

var labels = new Array();
var labels_cnt = 0;

var checkboxes = new Array();
var checkboxes_cnt = 0;

var radios = new Array();
var radios_cnt = 0;

var buttons = new Array();
var buttons_cnt = 0;

var numbers = new Array();
var numbers_cnt = 0;

var stringboxes = new Array();
var stringboxes_cnt = 0;

var colors = new Array();
var colors_cnt = 0;

var textboxes = new Array();
var textboxes_cnt = 0;

var textures = new Array();
var textures_cnt = 0;

var luaboxes = new Array();
var luaboxes_cnt = 0;

var listboxes = new Array();
var listboxes_cnt = 0;

var tables = new Array();
var tables_cnt = 0;

var textures_root_directory = "..\\Textures\\";

// predefined colors

var my_colors_1 = "#67778F"; var my_colors_1b = "#F0F0F0";
var my_colors_2 = "#8D9AAD"; var my_colors_2b = "#F0F0F0";
var my_colors_3 = "#67778F"; var my_colors_3b = "#F0F0F0";
var my_colors_4 = "#67778F"; var my_colors_4b = "#F0F0F0";
var my_colors_5 = "#67778F"; var my_colors_5b = "#F0F0F0";
var my_colors_6 = "#67778F"; var my_colors_6b = "#F0F0F0";
var my_colors_7 = "#79889F"; var my_colors_7b = "#F0F0F0";
var my_colors_8 = "#67778F"; var my_colors_8b = "#F0F0F0";

var my_colors_selected = "#F4E7CE";
var my_colors_unselected = "#FFFFFF";

// selecting control for edy builder
var control_id_selected_for_edy_builder = "";
var control_id_do_selected = false;

var hintboxobj; // object for hintbox
function select_control_for_edy_builder(event)
{
    if (event.srcElement)
        control_id_selected_for_edy_builder = event.srcElement.id;
    else if (event.target)
        control_id_selected_for_edy_builder = event.target.id;

    if(control_id_do_selected)
    {
         if(control_id_selected_for_edy_builder != "")
             add_lua_script("cve:GetEdyBuilder():SelectControlByID('"+control_id_selected_for_edy_builder+"');");
    }
}
document.onmouseover = function(event)
{
    select_control_for_edy_builder(event);
}
document.onkeydown = function(event)
{
    var key_code = (event.which) ? event.which : event.keyCode;
    if((key_code == 162) || (key_code == 163) || (key_code == 17) /*in external window the ctrl is 17*/) 
    {
        control_id_do_selected = true;
         if(control_id_selected_for_edy_builder != "")
             add_lua_script("cve:GetEdyBuilder():SelectControlByID('"+control_id_selected_for_edy_builder+"');");
    }
}
document.onkeyup = function(event)
{
    var key_code = (event.which) ? event.which : event.keyCode;
    if((key_code == 162) || (key_code == 163) || (key_code == 17) /*in external window the ctrl is 17*/) 
    {
        control_id_do_selected = false;
    }
}

// reload edit page
function reload_edy_page(create_script)
{
    var mdiv = document.getElementById("mdiv");
    if(!mdiv) return;
    while(mdiv.childNodes.length>0) mdiv.removeChild(mdiv.childNodes[0]);
    
    control_id_selected_for_edy_builder = "";
    hidehintbox();
    
    blocks = new Array();
    blocks_cnt = 0;
    sliders = new Array();
    sliders_cnt = 0;
    labels = new Array();
    labels_cnt = 0;
    checkboxes = new Array();
    checkboxes_cnt = 0;
    radios = new Array();
    radios_cnt = 0;
    buttons = new Array();
    buttons_cnt = 0;
    numbers = new Array();
    numbers_cnt = 0;
    stringboxes = new Array();
    stringboxes_cnt = 0;
    colors = new Array();
    colors_cnt = 0;
    textboxes = new Array();
    textboxes_cnt = 0;
    textures = new Array();
    textures_cnt = 0;
    luaboxes = new Array();
    luaboxes_cnt = 0;
    listboxes = new Array();
    listboxes_cnt = 0;
    tables = new Array();
    tables_cnt = 0;
    //mdiv.innerHTML = create_script.length;
    var i=0;
    for(i=0; i<create_script.length; i++) eval(unescape(create_script[i]));
}


// mouse events

var number_wheeling_obj;
var number_wheeling_obj_started = false;
var number_wheeling_obj_lastX = 0;
var number_wheeling_obj_lastY = 0;
var number_wheeling_obj_undo_serie_started = false;

function start_num_wheel(on_obj) 
{
    number_wheeling_obj = on_obj;
    number_wheeling_obj_started = false;
    number_wheeling_obj_undo_serie_started = false;
}

document.onmousemove = function(event)
{
    if(number_wheeling_obj) 
    {
        if(!number_wheeling_obj_started)
        {
            number_wheeling_obj_started = true;
            number_wheeling_obj_lastX = event.clientX;
            number_wheeling_obj_lastY = event.clientY;
        }
        else
        {
            if(!number_wheeling_obj_undo_serie_started)
            {
                number_wheeling_obj.wheel_undo_serie_start();
                number_wheeling_obj_undo_serie_started = true;
            }
            var steps = number_wheeling_obj_lastY-event.clientY + event.clientX - number_wheeling_obj_lastX;
            number_wheeling_obj.wheel_update_value(steps);
            number_wheeling_obj_lastX = event.clientX;
            number_wheeling_obj_lastY = event.clientY;
        }
    }
}

document.onmouseup = function(event)
{
    if((number_wheeling_obj) && (number_wheeling_obj_undo_serie_started))
    {
        number_wheeling_obj.wheel_undo_serie_end();
    }
    number_wheeling_obj = null;
    number_wheeling_obj_lastY = -1;
    number_wheeling_obj_started = false;
    number_wheeling_obj_undo_serie_started = false;
}

// get element position function
function get_element_position(obj) 
{
    var obj_y = 0;
    var obj_x = 0;
    var obj2 = obj;
    if (document.getElementById || document.all) 
    {
        do  
        {
            obj_x += (obj.offsetLeft-obj.scrollLeft);
            obj_y += (obj.offsetTop-obj.scrollTop);
            obj = obj.offsetParent;
            obj2 = obj2.parentNode;
            while (obj2!=obj) 
            {
                obj_x -= obj2.scrollLeft;
                obj_y -= obj2.scrollTop;
                obj2 = obj2.parentNode;
            }
        } while (obj.offsetParent)
    } 
    else if (document.layers) 
    {
        obj_y += obj.y;
        obj_x += obj.x;
    }
    return [obj_x, obj_y];
}  

function is_my_ctrl_hidden_now(obj)
{
    if(obj.style.display == "none") return true;
    var obj2 = obj.parentNode;
    while (obj2!=document.body)
    {
        if(obj2.style.display == "none") return true;
        obj2 = obj2.parentNode;
    }
    return false;
}


// animated scroll
var animscroll_timer = 0;
var animscroll_target_y = 0;
var animscroll_steps = 0;
var anim_scroll_plus_offset_y = 70;
function scroll_to_element(obj)
{
    animscroll_target_y = get_element_position(obj)[1] - anim_scroll_plus_offset_y;
    animscroll_steps = 20;
    animscroll_timer = setTimeout("animscroll_on_timer()", 30);
}

function animscroll_on_timer()
{
    animscroll_steps = animscroll_steps -1;
    var where_y = animscroll_target_y;
    if(animscroll_steps>0) 
    {
        where_y = window.pageYOffset;
        var shift = (animscroll_target_y-where_y);
        if((shift>4) || (shift<-4)) shift = shift*0.3;
        where_y = where_y + shift;
    }
    window.scrollTo(0, where_y);
    
    if(animscroll_steps>0)
        animscroll_timer = setTimeout("animscroll_on_timer()", 30);
}

// HINTBOX

// hintbox occupies two events of hinted object: onMouseOver and onMouseOut

var hintbox_timer = 0;
var hintbox_text = "";
var hintbox_for_obj;
var hintbox_width = "";

function showhintbox(hint_text, hint_for_obj, hint_width)
{
    hintbox_text = hint_text;
    hintbox_for_obj = hint_for_obj;
    hintbox_width = hintbox_width;
    hintbox_for_obj.onmouseout=hidehintbox;
    clearTimeout(hintbox_timer);
    hintbox_timer = setTimeout("showhintbox_on_timer()", 1500);
}

function fix_hintbox_position()
{
    var obj_pos = get_element_position(hintbox_for_obj);

    // calculate hint position and shift it if out of scroll area

    var cx,cy,cw,ch;
    cx =  document.body.scrollLeft;
    cy =  document.body.scrollTop;
    cw =  document.body.clientWidth;
    ch =  document.body.clientHeight;
    
    var hx,hy; 
    hx = obj_pos[0]+5;
    hy = obj_pos[1]+hintbox_for_obj.offsetHeight+2;
    
    if(hx+hintboxobj.offsetWidth>(cx+cw) ) hx = (cx+cw) - hintboxobj.offsetWidth;
    if(hx < cx) hx = cx;
    if(hy+hintboxobj.offsetHeight>(cy+ch) ) hy = (cy+ch) - hintboxobj.offsetHeight;
    if(hy < cy) hy = cy;
    
    hx -= cx;
    hy -= cy; // hintbox style position is "fixed", so we adjust position by scroll

    hintboxobj.style.left = hx + "px";
    hintboxobj.style.top = hy + "px";
}

function showhintbox_on_timer()
{

    hintboxobj=document.getElementById("hintbox");
    hintboxobj.innerHTML=hintbox_text;
//     hintboxobj.style.left=hintboxobj.style.top=-1000;
//     if (hintbox_width!="") hintboxobj.style.width=hintbox_width;
//     else hintboxobj.style.width="200px";

    hintboxobj.style.width="";
    hintboxobj.style.height="";

    //if(hintboxobj.clientWidth>200) hintboxobj.style.width="200px";


    
    // show the hintbox window now
    hintboxobj.style.visibility="visible";

    fix_hintbox_position();

    hintbox_for_obj.onmouseout=hidehintbox;
}



function hidehintbox()
{
    clearTimeout(hintbox_timer);
    hintboxobj = document.getElementById("hintbox");
    hintboxobj.style.visibility="hidden";
    hintboxobj.style.left="-1000px";
}

function createhintbox()
{
    hintboxobj = document.createElement("div");
    hintboxobj.setAttribute("id", "hintbox");
    hintboxobj.style.position = "fixed";
    hintboxobj.style.backgroundColor = "lightyellow";
    hintboxobj.style.padding = "4px";
    hintboxobj.style.border = "1px solid black";
    hintboxobj.style.font = "normal 11px Arial";
    hintboxobj.style.zIndex = "101";
    hintboxobj.style.visibility="hidden";
    hintboxobj.style.borderRight = "2px solid black";
    hintboxobj.style.borderBottom = "2px solid black";
    document.body.appendChild(hintboxobj);
}

function cve_editor_init()
{
    createhintbox(); // create hint box on startup
}

// JAVA EVALUATE FUNCTION

function my_eval(eval_str)
{
    // java script evaluations can be checked here
    eval(eval_str);
}

// LUA SCRIPT handling

var lua_script_string = "";
var request_update_all_done_once = false; // we remember this so we don't call request update controls more times in one frame, just once

function add_lua_script(lua_script_str)
{
    // one complete lua script can be added, so we check if it ends with semicolon
    if(lua_script_str==undefined) return;
    if(lua_script_str=="") return;
    if(lua_script_str.charAt(lua_script_str.length-1)!=';') lua_script_str = lua_script_str + ';';
    lua_script_string = lua_script_string + lua_script_str;
}

function add_lua_script_if_not_added_already(lua_script_str)
{
    // one complete lua script can be added, so we check if it ends with semicolon
    if(lua_script_str==undefined) return;
    if(lua_script_str=="") return;
    if(lua_script_str.charAt(lua_script_str.length-1)!=';') lua_script_str = lua_script_str + ';';
    if(lua_script_string.indexOf(lua_script_str) == -1)
        lua_script_string = lua_script_string + lua_script_str;
}

function get_lua_script()
{
    // application calls this function to get all lua scripts we want to run from editor
    if(lua_script_string == undefined) return "";
    var my_ret = lua_script_string;
    lua_script_string = "";
    request_update_all_done_once = false; // we send lua script to update controls, so we can collect next ones
    return my_ret;
}

// request update all controls
function request_update_all_controls()
{
    if(request_update_all_done_once) return;
    
    var i=0;
    for(i=0; i<labels_cnt; i++) request_update_label(i);
    for(i=0; i<sliders_cnt; i++) request_update_slider(i);
    for(i=0; i<checkboxes_cnt; i++) request_update_checkbox(i);
    for(i=0; i<buttons_cnt; i++) request_update_button(i);
    for(i=0; i<radios_cnt; i++) request_update_radio(i);
    for(i=0; i<numbers_cnt; i++) request_update_number(i);
    for(i=0; i<stringboxes_cnt; i++) request_update_stringbox(i);
    for(i=0; i<textboxes_cnt; i++) request_update_textbox(i);
    for(i=0; i<colors_cnt; i++) request_update_color(i);
    for(i=0; i<textures_cnt; i++) request_update_texture(i);
    for(i=0; i<luaboxes_cnt; i++) request_update_luabox(i);
    for(i=0; i<listboxes_cnt; i++) request_update_listbox(i);
    
    request_update_all_done_once = true;
}

//update string for lua adding the escape character \
// function escape_string_for_lua(str)
// {
//     str = escape(str);
//     str = str.replace(/%0A/g, "\\n");
//     str = unescape(str);
//     var ret = "";
//     var charr = "q";
//     for(var i=0;i<str.length;i++)
//     {
//         charr = str.charAt(i);
//         switch(charr) 
//         {
//         //case (%10): ret=ret+"G"; break;
//         case "\\": ret=ret+"\\\\"; break;
//         case "\"": ret=ret+"\\\""; break;
//         case "\'": ret=ret+"\\\'"; break;
//         default: ret=ret+charr;
//         }
//     }
//document.getElementById("my_helpy_label").innerHTML = ;
//     // for more info about lua escaping string characters see: http://en.wikibooks.org/wiki/Lua_Programming/How_to_Lua/escape_sequence
//     return ret;
// }

// TIMER

var main_cve_editor_update_timer = 0;
function timer_event()
{
    request_update_all_controls();
    main_cve_editor_update_timer = setTimeout("timer_event()", 200);
}

function startup_timer()
{
    main_cve_editor_update_timer = setTimeout("timer_event()", 200);
}

function stop_timer()
{
    if(main_cve_editor_update_timer!=0) clearTimeout(main_cve_editor_update_timer);
    main_cve_editor_update_timer = 0;
}

// SHOW and HIDE WINDOW EVENTS that are sent from app

function show_window_event()
{
    timer_event(); // requests to update all controls and starts the timer
    hidehintbox();
}

function hide_window_event()
{
    stop_timer(); // stops the timer when the window is hidden, so we don't request game to update controls
    hidehintbox();

}

function focus_window_event()
{

}

function blur_all_elements()
{
    var len = document.all.length;
    for(var i=0; i<len; i++) { document.all[i].blur(); }
}

function blur_window_event()
{
    blur_all_elements();
    hidehintbox();
}


function disable_all_elements()
{
    var i=0;
    //for(i=0; i<labels_cnt; i++) 
    //for(i=0; i<textures_cnt; i++) 
    for(i=0; i<sliders_cnt; i++) document.getElementById(sliders[i].obj_id).disabled = true;
    for(i=0; i<buttons_cnt; i++) document.getElementById(buttons[i].obj_id).disabled = true;
    for(i=0; i<radios_cnt; i++) document.getElementById(radios[i].obj_id).disabled = true;
    for(i=0; i<numbers_cnt; i++) document.getElementById(numbers[i].obj_id).disabled = true;
    for(i=0; i<stringboxes_cnt; i++) document.getElementById(stringboxes[i].obj_id).disabled = true;
    for(i=0; i<textboxes_cnt; i++) document.getElementById(textboxes[i].obj_id).disabled = true;
    for(i=0; i<colors_cnt; i++) document.getElementById(colors[i].obj_id).disabled = true;
    for(i=0; i<luaboxes_cnt; i++) document.getElementById(luaboxes[i].obj_id).disabled = true;
    for(i=0; i<listboxes_cnt; i++) document.getElementById(listboxes[i].obj_id).disabled = true;
    for(i=0; i<checkboxes_cnt; i++) document.getElementById(checkboxes[i].obj_id).disabled = true;
}

function focus_element(obj_id)
{
    document.getElementById(obj_id).focus();
}


// CONTROLS:



// NEW LINE

function add_new_line(obj_id, append_to_obj)
{
    var my_br = document.createElement("br");
    my_br.id = obj_id;
    document.getElementById(append_to_obj).appendChild(my_br);
}

function add_hr_line(append_to_obj)
{
    document.getElementById(append_to_obj).appendChild(document.createElement("hr"));
}


// BLOCK

function add_block(block_id, label_string, append_to_obj, block_width, block_height, valign, color_index, icon_img, forbid_minimize, forbid_autoscroll, label_color)
{
    if(icon_img == undefined) icon_img = "";
    if(forbid_minimize == undefined) forbid_minimize = false;
    if(forbid_autoscroll == undefined) forbid_autoscroll = false;
    if(label_color == undefined) label_color = "#FFFFFF";
    if(label_color == "") label_color = "#FFFFFF";
    
    var block_color_1 = my_colors_1b;
    var block_color_2 = my_colors_1;
    switch(color_index) 
    {                           
        case 2: block_color_1 = my_colors_2b; block_color_2 = my_colors_2; break;
        case 3: block_color_1 = my_colors_3b; block_color_2 = my_colors_3; break;
        case 4: block_color_1 = my_colors_4b; block_color_2 = my_colors_4; break;
        case 5: block_color_1 = my_colors_5b; block_color_2 = my_colors_5; break;
        case 6: block_color_1 = my_colors_6b; block_color_2 = my_colors_6; break;
        case 7: block_color_1 = my_colors_7b; block_color_2 = my_colors_7; break;
        case 8: block_color_1 = my_colors_8b; block_color_2 = my_colors_8; break;
    }
    blocks[blocks_cnt] = new Object();
    blocks[blocks_cnt].block_id = block_id;
    blocks_cnt = blocks_cnt +1;
    var block = document.createElement("table");
    block.id = block_id;

    document.getElementById(append_to_obj).appendChild(block);
    if(block_width!="") block.style.width = block_width;
    if(block_height!="") block.style.height = block_height;
    block.style.display = "inline";
    block.style.verticalAlign = "top";
    block.style.fontSize = "small";
    block.style.border = "1px solid grey";
    block.style.padding = "3px";
    block.style.margin = "1px";
    block.style.marginTop = "6px";
    block.style.marginBottom = "6px";
    block.style.paddingBottom = "0";
    block.style.backgroundColor = block_color_1;
    block.my_controls_hidden = false;
    block.this_is_my_block = true;
    block.my_block_forbid_minimize = forbid_minimize;
    if(valign!="") { block.style.textAlign = valign; }
    block.my_mouse_press = false;
    block.onselectstart = function () { return false; }

    var label = document.createElement('div')
    block.appendChild(label);
    label.style.width = "100%";
    label.style.textAlign = "center";
    if(!forbid_minimize) label.style.cursor = "pointer";
    label.style.borderBottom = "1px solid grey";
    label.style.backgroundColor = block_color_2;
    label.style.marginBottom = "3px";
    

    if(icon_img != "")
    {
        //label.style.textAlign = "left";
        var lab_ico = document.createElement("img");
        lab_ico.src = icon_img + "?" + (new Date()).getTime();
        lab_ico.style.display = "inline-block";
        lab_ico.style.verticalAlign = "middle";
        label.appendChild(lab_ico);

        label.appendChild( document.createTextNode("  ") );
    }

    label.style.color = label_color;
    label.style.fontWeight = "bolder";
    //label.style.textShadow="0px 0px 30px #FFFFFF";
    label.style.fontSize = "14";
    label.style.paddingTop = "4px";

    var tnode = document.createTextNode(label_string);
    
    label.appendChild( tnode );

//    label.innerHTML = label_string;
    block.block_label = label;
    label.onselectstart = function () { return false; }
    if(!forbid_minimize) 
    {
        label.onmousedown = function ()
        {
            block.my_mouse_press = true;
        }

        label.onmouseup = function () 
        {
            if(block.my_mouse_press)
            {
                block.my_mouse_press = false;
                if(block.my_controls_hidden) 
                {
                    restore_block(block_id)
                    if(!forbid_autoscroll) scroll_to_element(block);
                }
                else minimize_block(block_id)
            }
        }
    }
    

}

function minimize_block(block_id) 
{
    var block = document.getElementById(block_id);
    if(block.my_block_forbid_minimize) return;
    var c = block.childNodes;
    block.my_controls_hidden = true;
    for(var i=0; i<c.length; i++) {
        if(c[i]==block.block_label) continue;
        c[i].style.display = "none";
        //c[i].my_control_is_hidden = true;
    }
}

function restore_block(block_id) 
{
    var block = document.getElementById(block_id);
    var c = block.childNodes;
    block.my_controls_hidden = false;
    for(var i=0; i<c.length; i++) {
        if(c[i]==block.block_label) continue;
        if(c[i].my_control_leave_hidden) continue;
        if(c[i].this_is_my_block) c[i].style.display = "inline";
        else c[i].style.display = "inline";
        //c[i].my_control_is_hidden = false;
    }
}

function minimize_all_blocks()
{
    for(var i=0; i<blocks_cnt; i++) minimize_block(blocks[i].block_id);
}

function all_blocks_are_minimized()
{
    for(var i=0; i<blocks_cnt; i++) 
    {
        var block = document.getElementById(blocks[i].block_id);
        if(block.my_block_forbid_minimize) continue;
        if(block.my_controls_hidden == false) return false;
    }
    return true;
}
function restore_all_blocks() 
{
    for(var i=0; i<blocks_cnt; i++) restore_block(blocks[i].block_id);
}


// CHECK BOX

function request_update_checkbox(wh)
{
    if(checkboxes[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(checkboxes[wh].obj)) return; 
    add_lua_script("cve:EdyUpdateCheckbox('"+checkboxes[wh].obj_id+"', " + checkboxes[wh].update_script + ");");
}

function update_checkbox(checkbox_id, new_value)
{
    document.getElementById(checkbox_id).checked = new_value == "true";
}

function add_checkbox(obj_id, label_string, is_checked, lua_on_check, lua_on_uncheck, update_script, hint_text, append_to_obj, end_with_new_line)
{
    var checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    if(obj_id!="")
    {
        checkboxes[checkboxes_cnt] = new Object();
        checkboxes[checkboxes_cnt].obj_id = obj_id;
        checkboxes[checkboxes_cnt].obj = checkbox;
        checkboxes[checkboxes_cnt].update_script = update_script;
        checkboxes_cnt = checkboxes_cnt +1;
    }
    
    checkbox.id = obj_id;
    checkbox.checked = is_checked;
    
    var label = document.createElement('label')
    label.htmlFor = obj_id;
    label.appendChild(document.createTextNode(label_string));
    label.onselectstart = function() {return false;}

    var mdivv = document.getElementById(append_to_obj);
    mdivv.appendChild(checkbox);
    mdivv.appendChild(label);
    
    checkbox.style.cursor = "pointer";
    label.style.cursor = "pointer";

    checkbox.setAttribute("onclick", "hidehintbox(); if(checked) {add_lua_script(\""+lua_on_check+"\");} else {add_lua_script(\""+lua_on_uncheck+"\");}");
    
    if(hint_text!="") 
    {
        checkbox.onmouseover = function(){showhintbox(hint_text, this, '')};
        label.onmouseover = function(){showhintbox(hint_text, this, '')};
    }
    
    if(end_with_new_line) add_new_line("", append_to_obj);
}


// RADIO

function request_update_radio(wh)
{
    if(radios[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(radios[wh].obj)) return; 
    add_lua_script("cve:EdyUpdateRadio('"+radios[wh].obj_id+"', " + radios[wh].update_script + ");");
}

function update_radio(radio_id, new_value)
{
    document.getElementById(radio_id).checked = new_value == document.getElementById(radio_id).value;
}

function add_radio(obj_id, checkbox_group, label_string, value, lua_on_click, update_script, hint_text, append_to_obj, end_with_new_line)
{
    var radio = document.createElement("input");
    radio.type = "radio";
    if(obj_id!="")
    {
        radios[radios_cnt] = new Object();
        radios[radios_cnt].obj_id = obj_id;
        radios[radios_cnt].obj = radio;
        radios[radios_cnt].update_script = update_script;
        radios_cnt = radios_cnt +1;
    }

    radio.id = obj_id;
    radio.name = checkbox_group;
    radio.value = value;

    var label = document.createElement('label')
    label.htmlFor = obj_id;
    label.appendChild(document.createTextNode(label_string));

    var mdivv = document.getElementById(append_to_obj);
    mdivv.appendChild(radio);
    mdivv.appendChild(label);
    
    radio.style.cursor = "pointer";
    label.style.cursor = "pointer";

    //radio.setAttribute("onclick", "hidehintbox(); my_eval(\"add_lua_script('"+lua_on_click+"');\");");
    radio.onclick = function () 
    {
        hidehintbox(); 
        add_lua_script(lua_on_click);
    }

    if(hint_text!="") 
    {
        radio.onmouseover = function(){showhintbox(hint_text, this, '')};
        label.onmouseover = function(){showhintbox(hint_text, this, '')};
    }
    
    if(end_with_new_line) add_new_line("", append_to_obj);
}


// BUTTON

function request_update_button(wh)
{
    if(is_my_ctrl_hidden_now(buttons[wh].obj)) return; 
    if(buttons[wh].update_script!="")
        add_lua_script("cve:EdyUpdateButton('"+buttons[wh].obj_id+"', " + buttons[wh].update_script + ");");
    if(buttons[wh].visibility_script!="")
        add_lua_script("cve:EdyUpdateButtonVisibility('"+buttons[wh].obj_id+"', " + buttons[wh].visibility_script + ");");
}

function update_button(obj_id, new_value)
{
    document.getElementById(obj_id).value = unescape(new_value);
}

function add_button(obj_id, label_string, button_width, button_height, lua_on_click, update_script, hint_text, append_to_obj, end_with_new_line, lua_visibility_script, jscript_on_click, icon_image, btn_margin)
{
    if(lua_visibility_script == undefined) lua_visibility_script = "";
    if(jscript_on_click == undefined) jscript_on_click = "";
    if(icon_image == undefined) icon_image = "";
    if(btn_margin == undefined) btn_margin = "";

    var button = document.createElement("button");
    if(obj_id!="")
    {
        buttons[buttons_cnt] = new Object();
        buttons[buttons_cnt].obj_id = obj_id;
        buttons[buttons_cnt].obj = button;
        buttons[buttons_cnt].update_script = update_script;
        buttons[buttons_cnt].visibility_script = lua_visibility_script;
        buttons_cnt = buttons_cnt +1;
    }

    button.id = obj_id;
    button.style.width = button_width;
    button.style.height = button_height;
    if(btn_margin!="") button.style.margin = btn_margin;
    
    if(icon_image != "")
    {
        var btn_icon = document.createElement("img");
        btn_icon.src = icon_image + "?" + (new Date()).getTime();
        btn_icon.style.verticalAlign = "middle";
        button.appendChild(btn_icon);
    }

    button.appendChild(document.createTextNode(label_string));
    
//     var button_onclick = "hidehintbox(); my_eval(\"add_lua_script('"+lua_on_click+"');"+jscript_on_click+"\");";
//     button.setAttribute("onclick", button_onclick);
   
    button.onclick = function()
    {
        hidehintbox();
        add_lua_script(lua_on_click);
        my_eval(jscript_on_click);      
    }

    if(hint_text!="") button.onmouseover = function(){showhintbox(hint_text, this, '')};
    
    document.getElementById(append_to_obj).appendChild(button);


    if(end_with_new_line) add_new_line("", append_to_obj);
}

function hide_button(obj_id)
{
    document.getElementById(obj_id).style.display = "none";
}

function show_button(obj_id)
{
    document.getElementById(obj_id).style.display = "inline";
}

function disable_button(obj_id)
{
    document.getElementById(obj_id).disabled = true;
}

function enable_button(obj_id)
{
    document.getElementById(obj_id).disabled = false;
}


// SLIDER

function four_digits(value)
{
    return Math.round(value * 10000) / 10000;
}
function request_update_slider(wh)
{
    if(sliders[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(sliders[wh].obj)) return; 
    add_lua_script("cve:EdyUpdateSlider('"+sliders[wh].obj_id+"', " + sliders[wh].update_script + ");");
}

function update_slider(slider_id, new_value)
{
    document.getElementById(slider_id).value = new_value;
    document.getElementById(slider_id+"_sliderlabel1").childNodes[0].nodeValue = four_digits(new_value);
}

function add_slider(obj_id, current_value, min_value, max_value, step_value, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line, width)
{
    var slider = document.createElement("input");
    slider.type = "range";
    if(obj_id!="")
    {
        sliders[sliders_cnt] = new Object();
        sliders[sliders_cnt].obj_id = obj_id;
        sliders[sliders_cnt].obj = slider;
        sliders[sliders_cnt].update_script = update_script;
        sliders_cnt = sliders_cnt +1;
    }
    
    slider.id = obj_id;
    slider.value = current_value;
    slider.min = min_value;
    slider.max = max_value;
    slider.step = step_value;

    if(width=="") width = 175;
    slider.style.width = width;

    var label_id = obj_id+"_sliderlabel1";
    var label = document.createElement('label')
    label.htmlFor = obj_id;
    label.id = label_id;
    label.appendChild(document.createTextNode(current_value));


    var mdivv = document.getElementById(append_to_obj);
    mdivv.appendChild(slider);
    mdivv.appendChild(label);
    

//     var slider_onchange = "";
//     slider_onchange += "hidehintbox(); document.getElementById(\""+label_id+"\").childNodes[0].nodeValue = four_digits(document.getElementById('"+obj_id+"').value);";
//     slider_onchange += "my_eval(\"add_lua_script('"+lua_onchange+"');\");";
//     slider.setAttribute("onchange", slider_onchange);
    slider.onchange = function () 
    {
        hidehintbox(); 
        document.getElementById(label_id).childNodes[0].nodeValue = four_digits(document.getElementById(obj_id).value);

        var the_lua = lua_onchange;
        the_lua = the_lua.replace(/~VALUE~/g, document.getElementById(obj_id).value);
        add_lua_script(the_lua);
    }
    
    if(hint_text!="")
    {
        slider.onmouseover = function(){showhintbox(hint_text, this, '')};
        label.onmouseover = function(){showhintbox(hint_text, this, '')};
    }
    
    if(end_with_new_line) add_new_line("", append_to_obj);
}


// NUMBER

function request_update_number(wh)
{
    if(numbers[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(numbers[wh].obj)) return;
    if(numbers[wh].obj.my_focus_store) return;
    add_lua_script("cve:EdyUpdateNumber('"+numbers[wh].obj_id+"', " + numbers[wh].update_script + ");");
}

function update_number(number_id, new_value)
{
    document.getElementById(number_id).value = new_value;
}

function string_is_a_number(the_number)
{
   return ((the_number - 0) == the_number) && (the_number.length > 0);
}

function add_number(obj_id, current_value, min_value, max_value, step_value, accept_float_number, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line, ctrl_width, ctrl_height, wheel_undo_serie_start_lua, wheel_undo_serie_end_lua)
{
    if(wheel_undo_serie_start_lua==undefined) wheel_undo_serie_start_lua = "";
    if(wheel_undo_serie_end_lua==undefined) wheel_undo_serie_end_lua = "";

    var number = document.createElement("input");
    number.type = "text";
    if(obj_id!="")
    {
        numbers[numbers_cnt] = new Object();
        numbers[numbers_cnt].obj_id = obj_id;
        numbers[numbers_cnt].obj = number;
        numbers[numbers_cnt].update_script = update_script;
        numbers_cnt = numbers_cnt +1;
    }
    
    number.id = obj_id;
    number.value = current_value;
    number.min = min_value;
    number.max = max_value;
    number.step = step_value;
    number.my_focus_store = false;

    number.onfocus = function() {this.my_focus_store = true; this.style.backgroundColor = my_colors_selected;}
    number.onblur = function() {this.my_focus_store = false; this.style.backgroundColor = my_colors_unselected;}

    var c_width = 50; 
    if(ctrl_width!="") c_width = ctrl_width;
    number.style.width = c_width;
    number.style.height = "20px";
    
    number.style.padding = "0px";
    number.style.margin = "0px";
    number.style.verticalAlign = "middle";
    number.style.display = "inline";

    number.num_wheel = document.createElement("img");
    number.num_wheel.src = "num_wheel.png";
    number.num_wheel.style.verticalAlign = "middle";
    number.num_wheel.height = 20;
    number.num_wheel.style.cursor = "pointer";
    //number.num_wheel.onselect = function () { return false; };
    
    number.wheel_undo_serie_start = function()
    {
        if(wheel_undo_serie_start_lua=="") return;
        add_lua_script(wheel_undo_serie_start_lua);
    }
    
    number.wheel_undo_serie_end = function()
    {
        if(wheel_undo_serie_end_lua=="") return;
        add_lua_script(wheel_undo_serie_end_lua);
    }
    
    number.num_wheel.onmousedown = function (event) 
    {
        // editing the number with mouse
        if(number.disabled) return;
        number.focus();
        start_num_wheel(number); 
        return false; 
    }
//     number.num_wheel.onmousemove = function (event) { number.value = event.clientY; return true; }
//     number.num_wheel.onmouseout = function (event) { return false; }

    var mdivv = document.createElement("table");
    mdivv.style.backgroundColor = "red";
    mdivv.cellPadding = "0px";
    mdivv.cellSpacing = "0px";
    mdivv.style.margin = "1px";
    mdivv.style.padding = "0px";
    mdivv.style.marginRight = "3px";
    mdivv.style.border = "0px solid black";
    mdivv.style.verticalAlign = "middle";
    mdivv.style.display = "inline";
    
    mdivv.appendChild(number);
    
    mdivv.appendChild(number.num_wheel);
    
    document.getElementById(append_to_obj).appendChild(mdivv);

    number.wheel_update_value = function(steps)
    {
        var the_num = Number(number.value);
        var the_step = Number(number.step);
        the_num = the_num + Number(steps) * the_step;
        if(number.min<number.max)
        {
            if(the_num<number.min) the_num = number.min;
            else if(the_num>number.max) the_num = number.max;
        }
        number.value = the_num;
        var lua_onchange_script = lua_onchange;
        lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, the_num);
        add_lua_script(lua_onchange_script);
    }
    

    number.onkeydown = function(evt)
    {
        hidehintbox();
    
        // this function helps to accept numbers only
        var charCode = (evt.which) ? evt.which : evt.keyCode;
        //this.style.backgroundColor = "white";
        
        if(charCode==8) return true; // backspace
        if(charCode==46) return true; // delete
        
        if(charCode==38) // arrow up
        {
            this.wheel_update_value(1); 
            return false;
        }
        if(charCode==40) // arrow down
        {
            this.wheel_update_value(-1); 
            return false;
        }
        
        if((charCode==37) || (charCode<=39)) return true; // arrows left and right
        if((charCode>=33) && (charCode<=36)) return true; // home, end, page down and page down
        if((charCode==109) || (charCode==189)) // minus on num pad
        {
            if(this.value==0)
            {
                this.value="-";
                return false;
            }
            this.value = -this.value;
            return false; 
        }
        if((charCode >= 48) && (charCode <= 57)) return true; // numbers
        if((charCode >= 96) && (charCode <= 105)) return true; // numbers on num pad

        if(accept_float_number)
        {
            if((charCode==190) || (charCode==110)) // point or point on keypad
            {
                var value_string = this.value;
                if(value_string.indexOf(".")!=-1) return false; // there's already a point in a number
                if(value_string=="-")
                {
                    this.value = "-0";
                    return true;
                }
                return true;
            }
        }

        // when enter is pressed, we accept and send new value
        if((charCode==13) || (charCode==108) || (charCode==9)) // enter or enter on keypad or TAB
        {
        }

        // all other keys are not accepted
        return false;
    }

    number.onkeyup = function(evt)
    {
        var charCode = (evt.which) ? evt.which : evt.keyCode;
        if(charCode==9) return true;
            var red_bck_color = "#FFAAAA"; // red
            if(string_is_a_number(this.value)) 
            {
                var the_num = Number(this.value);
                if(this.min<this.max)
                {
                    if((the_num<this.min) || (the_num>this.max))
                    {
                        // number not in min/max interval
                        this.style.backgroundColor = red_bck_color;
                        return false; 
                    }
                }
                // everything ok, let's send lua script with the number
                this.style.backgroundColor = my_colors_selected;
                //this.value = the_num;
                //document.getElementById("my_helpy_label").innerHTML = ;

                var lua_onchange_script = lua_onchange;
                lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, the_num);
                add_lua_script(lua_onchange_script);
            }
            else 
            {
                this.style.backgroundColor = red_bck_color;
                return false; // not a number
            }
    }

    if(hint_text!="") number.onmouseover = function(){showhintbox(hint_text, this, '')};

    if(end_with_new_line) add_new_line("", append_to_obj);
}


// STRINGBOX

function request_update_stringbox(wh)
{
    if(stringboxes[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(stringboxes[wh].obj)) return;
    if(stringboxes[wh].obj.my_focus_store) return;
    add_lua_script("cve:EdyUpdateStringBox('"+stringboxes[wh].obj_id+"', " + stringboxes[wh].update_script + ");");
}

function update_stringbox(stringbox_id, new_value)
{
    document.getElementById(stringbox_id).value = new_value;
}

function add_stringbox(obj_id, current_value, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line, ctrl_width, ctrl_height, max_string_length)
{
    var stringbox = document.createElement("input");
    stringbox.type = "text";
    if(obj_id!="")
    {
        stringboxes[stringboxes_cnt] = new Object();
        stringboxes[stringboxes_cnt].obj_id = obj_id;
        stringboxes[stringboxes_cnt].obj = stringbox;
        stringboxes[stringboxes_cnt].update_script = update_script;
        stringboxes_cnt = stringboxes_cnt +1;
    }
    
    stringbox.id = obj_id;
    stringbox.value = current_value;
    stringbox.my_focus_store = false;
    if(max_string_length!="") stringbox.maxLength = max_string_length;
    stringbox.onfocus = function() {this.my_focus_store = true; this.style.backgroundColor = my_colors_selected;}
    stringbox.onblur = function() {this.my_focus_store = false; this.style.backgroundColor = my_colors_unselected;}
    
    stringbox.style.font = "normal 12px Arial"

    var c_width = 50; 
    if(ctrl_width!="") c_width = ctrl_width;
    stringbox.style.width = c_width;
    if(ctrl_height!="") stringbox.style.height = ctrl_height;
    
    

    var mdivv = document.getElementById(append_to_obj);
    mdivv.appendChild(stringbox);

    stringbox.onkeyup = function(evt)
    {
        hidehintbox();
        // send string value
        if(lua_onchange != "")
        {
            var lua_onchange_script = lua_onchange;
            lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, "\""+escape(this.value)+"\"");
            add_lua_script(lua_onchange_script);
        }
        return true;
    }

    if(hint_text!="") stringbox.onmouseover = function(){showhintbox(hint_text, this, '')};

    if(end_with_new_line) add_new_line("", append_to_obj);
}

// TEXTBOX

function request_update_textbox(wh)
{
    if(textboxes[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(textboxes[wh].obj)) return; 
    if(textboxes[wh].obj.my_focus_store) return;
    add_lua_script("cve:EdyUpdateTextbox('"+textboxes[wh].obj_id+"', " + textboxes[wh].update_script + ");");
}

function update_textbox(textbox_id, new_value)
{
    document.getElementById(textbox_id).value = unescape(new_value); // we need to get here escaped string and we unescape it
}

function add_textbox(obj_id, current_value, rows_count, box_width, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line)
{
    var textbox = document.createElement("textarea");
    if(obj_id!="")
    {
        textboxes[textboxes_cnt] = new Object();
        textboxes[textboxes_cnt].obj_id = obj_id;
        textboxes[textboxes_cnt].obj = textbox;
        textboxes[textboxes_cnt].update_script = update_script;
        textboxes_cnt = textboxes_cnt +1;
    }
    
    //textbox.setAttribute('wrap', 'off');
    textbox.id = obj_id;
    textbox.value = current_value;
    textbox.readonly = false;
    textbox.rows = rows_count;
    //textbox.cols = 10;
    textbox.style.width = box_width;

    textbox.my_focus_store = false;
    textbox.onfocus = function() {this.my_focus_store = true; this.style.backgroundColor = my_colors_selected;}
    textbox.onblur = function() {this.my_focus_store = false; this.style.backgroundColor = my_colors_unselected;}

    var mdivv = document.getElementById(append_to_obj);
    mdivv.appendChild(textbox);
    
    textbox.onkeyup = function(evt)
    {
        hidehintbox();
        var charCode = (evt.which) ? evt.which : evt.keyCode;
        
        //if(charCode==9) return false; // TAB key not accepted
        
        //if((charCode==13) || (charCode==108) || (charCode==9)) // enter or enter on keypad or TAB
        {
            var lua_onchange_script = lua_onchange;
            //lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, "\""+escape_string_for_lua(this.value)+"\"");
            lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, "\""+escape(this.value)+"\"");
            add_lua_script(lua_onchange_script);
        }

        // key is accepted
        return true;
    }
    
    if(hint_text!="") textbox.onmouseover = function(){showhintbox(hint_text, this, '')};
    
    if(end_with_new_line) add_new_line("", append_to_obj);
}


// COLOR

function request_update_color(wh)
{
    if(colors[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(colors[wh].obj)) return; 
    add_lua_script("cve:EdyUpdateColor('"+colors[wh].obj_id+"', " + colors[wh].update_script + ");");
}

function update_color(obj_id, red, green, blue)
{
    document.getElementById(obj_id).style.backgroundColor = "rgb("+red+","+green+","+blue+")";
}

function add_color(obj_id, label_string, width, height, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line, lua_undo_start_serie, lua_undo_end_serie, color_name)
{
    if(lua_undo_start_serie==undefined) lua_undo_start_serie="";
    if(lua_undo_end_serie==undefined) lua_undo_end_serie="";
    if(color_name==undefined) color_name="";
    
    var color = document.createElement('input')
    color.type = "button";
    if(obj_id!="")
    {
        colors[colors_cnt] = new Object();
        colors[colors_cnt].obj_id = obj_id;
        colors[colors_cnt].obj = color;
        colors[colors_cnt].update_script = update_script;
        colors_cnt = colors_cnt +1;
    }

    color.id = obj_id;
    color.value = label_string;
    if(width!="") color.style.width = width; else if(label_string=="") color.style.width = 60;
    if(height!="") color.style.height = height; else if(label_string=="") color.style.height = 30;
    color.style.backgroundColor = "rgb(255,255,255)";
    document.getElementById(append_to_obj).appendChild(color);

    if(hint_text!="") color.onmouseover = function(){showhintbox(hint_text, this, '')};
    
    //color.setAttribute("onclick", "hidehintbox(); add_lua_script(\"cve:ColorPickStart(\'"+lua_onchange+"\',"+update_script+",\'"+lua_undo_start_serie+"\',\'"+lua_undo_end_serie+"\')\")");
    
    color.onclick = function () 
    {
        hidehintbox(); 
        add_lua_script("cve:ColorPickStart('"+escape(lua_onchange)+"',"+update_script+",'"+escape(lua_undo_start_serie)+"','"+escape(lua_undo_end_serie)+"','"+escape(update_script)+"','"+escape(color_name)+"')");
    }
    
    if(end_with_new_line) add_new_line("", append_to_obj);

}


// LABEL

function request_update_label(wh)
{
    if(labels[wh].update_script=="") return;
    if(!labels[wh].obj.my_jscript_on_control_update)
        if(is_my_ctrl_hidden_now(labels[wh].obj)) return; 
    add_lua_script("cve:EdyUpdateLabel('"+labels[wh].obj_id+"', " + labels[wh].update_script + ");");
}

function update_label(obj_id, new_value)
{
    var label = document.getElementById(obj_id);
    if(label.readOnly) label.value = new_value; // is input
    else label.innerHTML = new_value; // is label
    if(label.my_jscript_on_control_update) eval(label.my_jscript_on_control_update);
}

function add_label(obj_id, label_string, update_script, hint_text, append_to_obj, end_with_new_line, label_width)
{
    var wtype = 0;
    if(label_width != undefined) if(label_width != "") wtype = 1;
    
    var label;
    if(wtype == 0)
    {
         label = document.createElement('label');
         label.innerHTML = label_string;
         //label.style.fontWeight = "bolder";
         label.onselectstart = function () { return true; }
    }
    else
    {
        label = document.createElement('input');
        label.type = "text";
        label.style.backgroundColor = "transparent";
        label.style.border = "none";
        label.readOnly = true;
        label.style.font = "normal 13px Times";
        label.style.width = label_width;
        label.tabIndex = -1;
        label.value = label_string;
    }
        
    label.id = obj_id;
    
    
    if(obj_id!="")
    {
        labels[labels_cnt] = new Object();
        labels[labels_cnt].obj_id = obj_id;
        labels[labels_cnt].obj = label;
        labels[labels_cnt].update_script = update_script;
        labels_cnt = labels_cnt +1;
    }

    document.getElementById(append_to_obj).appendChild(label);

    if(hint_text!="") label.onmouseover = function(){showhintbox(hint_text, this, '')};
    
    if(end_with_new_line) add_new_line("", append_to_obj);

}


//TEXTURE

function request_update_texture(wh)
{
    if(textures[wh].update_script=="") return;
    if(is_my_ctrl_hidden_now(textures[wh].obj)) return; 
    if(textures[wh].obj.lua_get_multitex == "")
    {
        add_lua_script("cve:EdyUpdateTexture('"+textures[wh].obj_id+"', " + textures[wh].update_script + ");");
    }
    else
    {
        add_lua_script("cve:EdyUpdateTexture('"+textures[wh].obj_id+"', " + textures[wh].update_script + ","+textures[wh].obj.lua_get_multitex+");");
    }
}


function update_texture(obj_id, texture_fn, frags_x, frags_y) 
{
    if(frags_x==undefined) frags_x = 1;
    if(frags_y==undefined) frags_y = 1;

    texture_fn = unescape(texture_fn);
    texture_fn = texture_fn.replace(/\\/gi, '/');  // replace all \ to /
    var texture = document.getElementById(obj_id);
    
    // check if we really need to update the picture:
    if((texture.texture_src_fn == texture_fn) && (texture.shown_frags_x == frags_x) && (texture.shown_frags_y == frags_y)) return;

    texture.texture_src_fn = texture_fn;
    texture.shown_frags_x = frags_x;
    texture.shown_frags_y = frags_y;
    
    texture.updating_rect_now = false;
    
    if(texture_fn == "") 
    {
        texture.width = 0;
        texture.height = 0;
        texture.label.childNodes[1].nodeValue = "(!none)";
        return;
    }

    delete texture.img_loader; // it's important to delete and re-create img_loader
    texture.img_loader = new Image();
    
    texture.img_loader.onerror = function ()
    {
        texture.width = 0;
        texture.height = 0;
        texture.label.childNodes[1].nodeValue = "(error loading img)";
        texture.texture_src_fn = "";
    }
    
    texture.img_loader.onload = function () 
    {
        // picture is loaded, let's resize or crop it if needed
        var c_w = texture.img_loader.width;
        var c_h = texture.img_loader.height;
        var crop_x = 0;
        var crop_y = 0;
        var crop_w = texture.img_loader.width;
        var crop_h = texture.img_loader.height;
        
        texture.orig_width = texture.img_loader.width;
        texture.orig_height = texture.img_loader.height;
        
        var rest_w = 0;
        var rest_h = 0;

        if((texture.crop_w>0) && (texture.crop_h>0))
        {
            c_w = texture.crop_w;
            c_h = texture.crop_h;
            crop_x = texture.crop_x;
            crop_y = texture.crop_y;
            crop_w = texture.crop_w;
            crop_h = texture.crop_h;
            if(texture.crop_x+crop_w > texture.img_loader.width) 
            {
                crop_w = texture.img_loader.width - texture.crop_x;
                if(crop_w<0) crop_w = 0;
                rest_w = texture.crop_x + texture.crop_w - texture.img_loader.width;
            }
            if(texture.crop_y+crop_h > texture.img_loader.height) 
            {
                crop_h = texture.img_loader.height - texture.crop_y;
                if(crop_h<0) crop_h = 0;
                rest_h = texture.crop_y + texture.crop_h - texture.img_loader.height;
            }
        }
        var w = 1; if(c_w > texture.max_show_width) w = texture.max_show_width / c_w;
        var h = 1; if(c_h > texture.max_show_height) h = texture.max_show_height / c_h;
        if((w!=1) || (h!=1)) {if(h<w) w = h;} // w is now how we scale image to fit in max width and height
        texture.width = c_w * w;
        texture.height = c_h * w;
        if((rest_w>0) || (rest_h>0))
        {
            // the crop rect goes beyond the picture, let's fill this area red
            texture.getContext("2d").fillStyle="#FF0000";
            var wx = texture.width-rest_w*w; if(wx<0) wx=0;
            var wy = texture.height-rest_h*w; if(wy<0) wy=0;
            texture.getContext("2d").fillRect(wx,0,texture.width, texture.height);
            texture.getContext("2d").fillRect(0,wy,texture.width, texture.height);
        }
        // draw loaded picture data cropped and/or resized as needed:
        texture.imgdrw_x = crop_x;
        texture.imgdrw_y = crop_y;
        texture.imgdrw_w = crop_w;
        texture.imgdrw_h = crop_h;
        texture.imgdrw_xx = texture.width-rest_w*w;
        texture.imgdrw_yy = texture.height-rest_h*w;

        texture.getContext("2d").drawImage(texture.img_loader, texture.imgdrw_x, texture.imgdrw_y, texture.imgdrw_w, texture.imgdrw_h, 0, 0, texture.imgdrw_xx, texture.imgdrw_yy);
        
        if((frags_x != 1) || (frags_y != 1))
        {
            // draw multi-texture fragments
            var ctx=texture.getContext("2d");
            ctx.strokeStyle="#FF0000";
            var i,w;
            for(i=1; i<frags_x; i++)
            {
                w = i*texture.width/frags_x;
                ctx.beginPath();
                ctx.moveTo(w,0);
                ctx.lineTo(w,texture.height);
                ctx.stroke();
            }
            for(i=1; i<frags_y; i++)
            {
                w = i*texture.height/frags_y;
                ctx.beginPath();
                ctx.moveTo(0,w);
                ctx.lineTo(texture.width,w);
                ctx.stroke();
            }
            
        }
        
    }
    
    var colon_index = texture_fn.indexOf(":",0);
    var load_fn = texture_fn;

    var pid_index = load_fn.indexOf("|",0);
    if(pid_index != -1) load_fn = load_fn.substr(0,pid_index);
    
    if(colon_index != -1)
    {
        // get texture crop rect
        var crop_str = load_fn.substr(colon_index+1);
        var jpos = 0;

        texture.crop_x = Number( crop_str.substring(jpos, crop_str.indexOf(",",jpos+1)) ); 
        jpos = crop_str.indexOf(",",jpos+1) + 1;
        texture.crop_y = Number( crop_str.substring(jpos, crop_str.indexOf(",",jpos+1)) );
        jpos = crop_str.indexOf(",",jpos+1) + 1;
        texture.crop_w = Number( crop_str.substring(jpos, crop_str.indexOf(",",jpos+1)) );
        jpos = crop_str.indexOf(",",jpos+1) + 1;
        texture.crop_h = Number( crop_str.substring(jpos) );
        load_fn = texture_fn.substr(0,colon_index);
    }
    else
    {
        // no texture crop
        texture.crop_x = 0;
        texture.crop_y = 0;
        texture.crop_w = 0;
        texture.crop_h = 0;
    }
    
    // texture label
    texture.label.childNodes[1].nodeValue = texture_fn; // texture.crop_x + "," + texture.crop_y + "," + texture.crop_w + "," + texture.crop_h;// + Math.random();

    load_fn = escape(load_fn);
    var load_url = textures_root_directory + load_fn;
    // this little hack with '?' and getTime avoids using the images cached in browser and loads image every time instead
    load_url = load_url + "?" + (new Date()).getTime(); 
    
    // load picture now:
    texture.img_loader.src = load_url;
}

function add_texture(obj_id, tex_fn, max_show_width, max_show_height, update_script, hint_text, append_to_obj, end_with_new_line, border, hide_texture_label, lua_update_rect, lua_get_multitex)
{
    var texture = document.createElement('canvas');

    if(obj_id!="")
    {
        textures[textures_cnt] = new Object();
        textures[textures_cnt].obj_id = obj_id;
        textures[textures_cnt].obj = texture;
        textures[textures_cnt].update_script = update_script;
        textures_cnt = textures_cnt +1;
    }
    
    if(lua_update_rect == undefined) lua_update_rect = "";
    if(lua_get_multitex == undefined) lua_get_multitex = "";

    texture.width = max_show_width;
    texture.height = max_show_height;
    texture.id = obj_id;
    texture.style.border =  border;//"1px solid black";
    texture.texture_src_fn = "";
    texture.shown_frags_x = 1;
    texture.shown_frags_y = 1;
    texture.max_show_width = max_show_width;
    texture.max_show_height = max_show_height;
    texture.img_loader = new Image();
    texture.lua_update_rect = lua_update_rect;
    if(lua_update_rect!="") texture.style.cursor = "crosshair";
    texture.lua_get_multitex = lua_get_multitex;
    texture.updating_rect_now = false;
    texture.updating_rect_px = 0;
    texture.updating_rect_py = 0;
    texture.updating_rect_pxx = 0;
    texture.updating_rect_pyy = 0;
    
    texture.label = document.createElement('label'); // label
    texture.label.appendChild(document.createElement("br"));
    texture.label.appendChild(document.createTextNode(""));
    texture.label.style.width = max_show_width;
    texture.label.style.maxWidth = max_show_width;
    texture.label.style.display = 'block';
    if(hide_texture_label) 
    {
        texture.label.my_control_leave_hidden = true;
        texture.label.style.display = "none";
    }
    
    document.getElementById(append_to_obj).appendChild(texture);
    document.getElementById(append_to_obj).appendChild(texture.label);

    update_texture(obj_id, tex_fn) 

    if(lua_update_rect != "")
    {
        // define texture crop rectangle with mouse (drawing a rect on texture)
        texture.onmousedown = function(event)
        {
            hidehintbox();
            if(texture.updating_rect_now) return; // we're already dragging the rectangle
            blur_all_elements();
            texture.updating_rect_now = true;

            texture.updating_rect_px = event.offsetX;
            texture.updating_rect_py = event.offsetY;
            texture.updating_rect_pxx = texture.updating_rect_px;
            texture.updating_rect_pyy = texture.updating_rect_py;
            return false;
        }
        texture.onmousemove = function(event)
        {
            if(!texture.updating_rect_now) return;

            texture.updating_rect_pxx = event.offsetX;
            texture.updating_rect_pyy = event.offsetY;

            var ctx=texture.getContext("2d");

            ctx.clearRect(0, 0, texture.width, texture.height);
            
            ctx.globalCompositeOperation = 'copy'; // set overwrite color mode
            ctx.fillStyle = "rgba(255, 0, 255, 0.1)";
            ctx.fillRect(0, 0, texture.width, texture.height);
            ctx.fill();
            ctx.globalCompositekOperation = 'source-over'; // set back the default draw mode

            ctx.drawImage(texture.img_loader, texture.imgdrw_x, texture.imgdrw_y, texture.imgdrw_w, texture.imgdrw_h, 0, 0, texture.imgdrw_xx, texture.imgdrw_yy);

//             ctx.fillStyle = "rgba(0, 0, 0, 0.2)";
//             ctx.fillRect(texture.updating_rect_px, texture.updating_rect_py, texture.updating_rect_pxx - texture.updating_rect_px, texture.updating_rect_pyy - texture.updating_rect_py);

            ctx.strokeStyle="#FF0000";
            ctx.strokeRect(texture.updating_rect_px, texture.updating_rect_py, texture.updating_rect_pxx - texture.updating_rect_px, texture.updating_rect_pyy - texture.updating_rect_py);
        }
        
        texture.onmouseup = function(event)
        {

            if(!texture.updating_rect_now) return;
            texture.updating_rect_now = false;
            
            // redraw texture
            var ctx=texture.getContext("2d");
            ctx.drawImage(texture.img_loader, texture.imgdrw_x, texture.imgdrw_y, texture.imgdrw_w, texture.imgdrw_h, 0, 0, texture.imgdrw_xx, texture.imgdrw_yy);
           
            // calculate crop rectangle and send lua to change it
            
            if(texture.updating_rect_px == texture.updating_rect_pxx) return;
            if(texture.updating_rect_py == texture.updating_rect_pyy) return;
            
            var cx,cy,cxx,cyy;
            var txw = texture.crop_w;
            var txh = texture.crop_h;
            if((txw==0) || (txh==0))
            {
                txw = texture.orig_width / texture.width;
                txh = texture.orig_height / texture.height;
            }
            else
            {
                txw /= texture.width;
                txh /= texture.height;
            }
            cx = texture.updating_rect_px   * txw + texture.crop_x;
            cy = texture.updating_rect_py   * txh + texture.crop_y;
            cxx = texture.updating_rect_pxx * txw + texture.crop_x;
            cyy = texture.updating_rect_pyy * txh + texture.crop_y;
            if(cx>cxx) {var cxc = cx; cx=cxx; cxx=cxc;}
            if(cy>cyy) {var cyc = cy; cy=cyy; cyy=cyc;}
            cxx = cxx - cx;
            cyy = cyy - cy;
            var params = cx.toString()+","+cy.toString()+","+cxx.toString()+","+cyy.toString();
            var lua_script = texture.lua_update_rect;
            lua_script = lua_script.replace(/~VALUE~/g, params);
            add_lua_script(lua_script);            
        }
        
// this doesn't work:
//         texture.onmouseout = function(event)
//         {
//             texture.updating_rect_now = false;
//         }
// 
//         texture.blur = function(event)
//         {
//             texture.updating_rect_now = false;
//         }
    }

    if(hint_text!="") 
    {
        texture.onmouseover = function(){showhintbox(hint_text, this, '')};
        texture.label.onmouseover = function(){showhintbox(hint_text, this, '')};
    }

    if(end_with_new_line) add_new_line("", append_to_obj);
}

function hide_texture(obj_id, hide_img, hide_label)
{
    obj_id = document.getElementById(obj_id);
    if(hide_img) obj_id.style.display = "none";
    if(hide_label) obj_id.label.style.display = "none";
}

function show_texture(obj_id, show_img, show_label)
{
    obj_id = document.getElementById(obj_id);
    if(show_img) obj_id.style.display = "inline";
    if(show_label) obj_id.label.style.display = "inline";
}


// LUABOX

function request_update_luabox(wh)
{
    if(luaboxes[wh].update_script=="") return;
    
    if(luaboxes[wh].obj.parentNode.style.display == "none") return;
    //if(is_my_ctrl_hidden_now(luaboxes[wh].obj)) return; 

    var w = document.body.offsetWidth - 20;
    luaboxes[wh].obj.CM_Editor.getScrollerElement().style.width = w;
    luaboxes[wh].obj.CM_Editor.getScrollerElement().style.height = "100%";
    luaboxes[wh].obj.CM_Editor.refresh();

     
     if(luaboxes[wh].obj.my_focus_store) return;
     add_lua_script("cve:EdyUpdateLuaBox('"+luaboxes[wh].obj_id+"', " + luaboxes[wh].update_script + ");");
}

function update_luabox(luabox_id, new_value)
{
     document.getElementById(luabox_id).CM_Editor.setValue(unescape(new_value)); // we need to get here escaped string and we unescape it
}

function luabox_key_event(editor, event)
{
    var key_code = (event.which) ? event.which : event.keyCode;
    
    var luabox = document.getElementById(editor.cve_luabox_id);
    if(event.type == "keyup") 
    {
            hidehintbox();
            var lua_onchange_script = luabox.lua_onchange;
            lua_onchange_script = lua_onchange_script.replace(/~VALUE~/g, "\""+escape(luabox.CM_Editor.getValue())+"\"");
            add_lua_script(lua_onchange_script);
    
        //editor.setValue(luabox.id);
    }
}

function luabox_on_focus(editor, event)
{
    document.getElementById(editor.cve_luabox_id).my_focus_store = true;
}

function luabox_on_blur(editor, event)
{
    document.getElementById(editor.cve_luabox_id).my_focus_store = false;
}

function add_luabox(obj_id, current_value, box_width, box_height, lua_onchange, update_script, hint_text, append_to_obj, end_with_new_line, do_read_only)
{
    if(do_read_only==undefined) do_read_only = false;
    else if(do_read_only) do_read_only = "nocursor";
    else do_read_only = false;
    
    var luabox_div = document.createElement("div");
    document.getElementById(append_to_obj).appendChild(luabox_div);
    //luabox_div.style.lineHeight = "15px";
    //luabox_div.style.fontSize = "large";
    luabox_div.style.width = "100%";
    //luabox_div.style.height = "100%";
    luabox_div.id = obj_id + "_div";

    var luabox = document.createElement("textarea");

    luabox.id = obj_id;
    luabox.value = current_value;
    luabox.readonly = false;
//     luabox.style.width = "100px";
//     luabox.style.height = "300px";
    //luabox.style.lineHeight = "20px";
    //luabox.style.fontSize = "20px";

    luabox.my_focus_store = false;
    luabox.lua_onchange = lua_onchange;

    luabox_div.appendChild(luabox);

//    /*if(hint_text!="") */luabox.onmouseover = function(){showhintbox("hint_text", this, '')};
    
    luabox.CM_Editor = CodeMirror.fromTextArea(luabox, {
        tabMode: "indent",
        tabSize: "2",
        matchBrackets: true,
        lineNumbers: true,
        theme: "neat",
        onKeyEvent: luabox_key_event,
        onFocus: luabox_on_focus,
        onBlur: luabox_on_blur,
        readOnly: do_read_only
    });
    
    luabox.CM_Editor.cve_luabox_id = obj_id;
    
//     luabox.CM_Editor.getScrollerElement().style.width = box_width;
//     luabox.CM_Editor.getScrollerElement().style.height = box_height;
//     luabox.CM_Editor.refresh();

    if(obj_id!="")
    {
        luaboxes[luaboxes_cnt] = new Object();
        luaboxes[luaboxes_cnt].obj_id = obj_id;
        luaboxes[luaboxes_cnt].obj = luabox;
        luaboxes[luaboxes_cnt].update_script = update_script;
        luaboxes[luaboxes_cnt].CM_Editor = luabox.CM_Editor;
        luaboxes_cnt = luaboxes_cnt +1;
    }
    
    if(end_with_new_line) add_new_line("", append_to_obj);
}


// LISTBOX

function add_listbox(obj_id, lines_cnt, box_width, box_height, lua_onselect, get_selected_option_script, update_script, hint_text, bg_color, append_to_obj, end_with_new_line, lua_copy, lua_paste)
{

    var listbox = document.createElement("select");

    listbox.id = obj_id;
    listbox.size = lines_cnt;
    listbox.style.width = box_width;
    listbox.style.height = box_height;
    listbox.style.backgroundColor = bg_color;

    listbox.lua_onselect = lua_onselect;
    listbox.allow_one_select_change = false;
    listbox.wanna_return_back_to_dropdown_list = false;
    listbox.hide_to_dropdown_list_now = false;

    listbox.my_focus_store = false;
    listbox.onfocus = function() {this.my_focus_store = true;}
    listbox.onblur = function() {this.my_focus_store = false;}
    
    listbox.do_auto_lines_cnt = (box_height == "auto");

    listbox.onfocus = function() 
    {
        this.my_focus_store = true; 
        this.style.backgroundColor = my_colors_selected;
        if(this.size == 1) 
        {
            this.size = 9;
            this.wanna_return_back_to_dropdown_list = true;
            this.hide_to_dropdown_list_now = false;
        }
    }
    listbox.onblur = function() 
    {
        this.my_focus_store = false; 
        this.style.backgroundColor = my_colors_unselected;
        if(this.wanna_return_back_to_dropdown_list)
        {
            this.size=1;
            this.wanna_return_back_to_dropdown_list = false;
        }
    }

    if(obj_id!="")
    {
        listboxes[listboxes_cnt] = new Object();
        listboxes[listboxes_cnt].obj_id = obj_id;
        listboxes[listboxes_cnt].obj = listbox;
        listboxes[listboxes_cnt].update_script = update_script;
        listboxes[listboxes_cnt].get_selected_option_script = get_selected_option_script;
        listboxes_cnt = listboxes_cnt +1;
    }

    document.getElementById(append_to_obj).appendChild(listbox);

    if(hint_text!="") listbox.onmouseover = function(){showhintbox(hint_text, this, '')};

    if(lua_onselect != "")
    {
        listbox.onchange = function () { 
            // on select
            var lua_script = lua_onselect;
            lua_script = lua_script.replace(/~VALUE~/g, listbox.options.selectedIndex);
            add_lua_script(lua_script);
            hidehintbox();
            if(listbox.wanna_return_back_to_dropdown_list)
            {
                if(listbox.hide_to_dropdown_list_now)
                {
                    listbox.size=1;
                    listbox.wanna_return_back_to_dropdown_list = false;
                }
            }
        }
        listbox.onmouseup = function () 
        { 
            if(listbox.size == 1) 
            {
                listbox.size = 9;
                listbox.wanna_return_back_to_dropdown_list = true;
                listbox.hide_to_dropdown_list_now = false;
            }
            else
            {
                if(listbox.wanna_return_back_to_dropdown_list)
                    listbox.hide_to_dropdown_list_now = true;
            }
        }
    }

    // lua copy and paste
    if(lua_copy == undefined) lua_copy = "";
    if(lua_paste == undefined) lua_paste = "";
    if((lua_copy != "") || (lua_paste != ""))
    {
        listbox.onkeyup = function (evt) { 
            var charCode = (evt.which) ? evt.which : evt.keyCode;
            hidehintbox();
            if(evt.ctrlKey)
            {
                if(charCode == 67) if(lua_copy != "") add_lua_script(lua_copy);
                if(charCode == 86) if(lua_paste != "") 
                {
                    add_lua_script(lua_paste);
                    listbox.allow_one_select_change = true;
                }
            }
        }
    }

    if(end_with_new_line) add_new_line("", append_to_obj);
}

function request_update_listbox(wh)
{
     if(listboxes[wh].update_script=="") return;
     if(is_my_ctrl_hidden_now(listboxes[wh].obj)) return; 
     //if(listboxes[wh].obj.my_focus_store) return;
     var sel_opt = listboxes[wh].get_selected_option_script;
     if(sel_opt == "") sel_opt = 0;
     add_lua_script("cve:EdyUpdateListBox('"+listboxes[wh].obj_id+"', " + listboxes[wh].update_script + ", " + sel_opt + ");");
}

function update_listbox(listbox_id, new_values, selected_index)
{
    var listbox = document.getElementById(listbox_id);
    var new_cnt = new_values.length;
    var old_cnt = listbox.options.length;
    var i;
    for(i=0; i<new_cnt; i++)
    {
        if(i>=old_cnt) 
        {
            var new_opt = new Option(unescape(new_values[i]), i.toString());
            if(listbox.lua_onselect!="")
            {
                new_opt.onclick = function () {
                    hidehintbox();
                    var lua_script = listbox.lua_onselect;
                    lua_script = lua_script.replace(/~VALUE~/g, this.value);
                    add_lua_script(lua_script);
                }
            }
            listbox.add(new_opt); // add item
        }
        else listbox.options.item(i).text = unescape(new_values[i]); // change item title
    }
    // delete old options if they new_value contain less elements then are created in our listbox
    for(i=old_cnt-1; i>=new_cnt; i--) listbox.options.remove(i);
    
    var lcnt = new_cnt; if(lcnt<2) lcnt=2; if(lcnt>10) lcnt=10;
    if(listbox.do_auto_lines_cnt) listbox.size = lcnt;
    
    // select one option
    var chng = !listbox.my_focus_store;
    if(listbox.allow_one_select_change && (listbox.options.selectedIndex != selected_index))
    {
        chng = true;
        listbox.allow_one_select_change = false;
    }
    if(chng)
    {
        if((selected_index>=0) && (selected_index<new_cnt)) listbox.options.selectedIndex = selected_index;
    }
}




// PANEL

function add_table(obj_id, table_width, table_height, margin, border, cell_padding, cell_spacing, bg_color, hint_text, append_to_obj, end_with_new_line)
{
    var table = document.createElement("table");
    table.id = obj_id;
    table.style.width = table_width;
    table.style.height = table_height;
    table.style.margin = margin
    table.style.border = border;
    table.cellPadding = cell_padding;
    table.cellSpacing = cell_spacing;
    table.style.backgroundColor = bg_color;
    table.style.fontSize = "inherit";
    document.getElementById(append_to_obj).appendChild(table);
    if(end_with_new_line) add_new_line("", append_to_obj);
}

function add_table_tr(obj_id, tr_height, v_align, bg_color, hint_text, append_to_obj)
{
    var tr = document.createElement("tr");
    tr.id = obj_id;
    tr.style.height = tr_height;
    tr.vAlign = v_align;
    tr.style.backgroundColor = bg_color;
    document.getElementById(append_to_obj).appendChild(tr);
   
}

function add_table_td(obj_id, width, height, col_span, row_span, hint_text, border, bg_color, append_to_obj)
{
    var my_td = document.createElement("td");

    my_td.id = obj_id;
    my_td.style.width = width;
    my_td.style.height = height;
    if(col_span!="") my_td.colSpan = col_span;
    if(row_span!="") my_td.rowSpan = row_span;
    my_td.style.backgroundColor = bg_color;
    my_td.style.border = border;

    document.getElementById(append_to_obj).appendChild(my_td);

    
}