
/*Image Editor's Commands*/
const PAINT_TYPE_INVALID   = 0;
const PAINT_TYPE_IE        = 1;
const PAINT_TYPE_SE        = 2;

const IE_CMD_INVALID       = 0;
const IE_CMD_GET_IE        = 1;
const IE_CMD_ITM_INFO      = 2;
const IE_CMD_NXT_AP        = 3;
const IE_CMD_NXT_FI        = 4;
const IE_CMD_NXT_FLD       = 5;

const IE_CMD_MOVE          = 6;
const IE_CMD_BOLD          = 7;
const IE_CMD_ITALIC        = 8;
const IE_CMD_INVERSE       = 9;
const IE_CMD_COLOR         = 10;
const IE_CMD_DEFER	       = 11;
const IE_CMD_DO_ULINE	   = 70;		// Underline all selections
const IE_CMD_DO_BOLD	   = 71;		// Bold all selections
const IE_CMD_DO_INVERSE    = 73;		// Inverse-video all selections
const IE_CMD_DO_COLOR	   = 74;		// Adjust color for all selections
const IE_CMD_DO_CHR	       = 75;		// Adjust characteristics for all selections
const IE_CMD_DO_BUTTON     = 76;		// Define a button covering selection rectangle
const IE_CMD_DO_LABEL	   = 77;		// Define a label covering selection rectangle
const IE_CMD_DO_IMAGE	   = 78;		// Define an image covering selection rectangle
const IE_CMD_DO_BOX	       = 79;		// Define a box  covering selection rectangle
const IE_CMD_DO_LINE       = 80;		// Define a line covering selection rectangle
const IE_CMD_DO_TABLE      = 81;		// Define a table covering selection rectangle

const IE_CMD_DO_CUT	       = 60;		// Cut all selections
const IE_CMD_DO_COPY	   = 61;		// Copy all selections
const IE_CMD_DO_MOVE	   = 62;		// Move all selections
const IE_CMD_DO_PASTE	   = 63;		// Paste contents of cut buffer
const IE_CMD_DO_DEL	       = 64;		// Del all selections

const IE_CMD_NULL		   = -1;		// Invalid command

const IE_SUB_CMD_ULINE     = 90;
const IE_SUB_CMD_BOLD      = 91;
const IE_SUB_CMD_ITALIC    = 92;
const IE_SUB_CMD_INVERSE   = 93;
const IE_SUB_CMD_COLOR     = 94;
const IE_SUB_CMD_CHR       = 95;
const IE_SUB_CMD_BTN       = 96;
const IE_SUB_CMD_LABEL     = 97;
const IE_SUB_CMD_PICTURE   = 98;
const IE_SUB_CMD_BOX       = 99;
const IE_SUB_CMD_COPY	   = 100;
const IE_SUB_CMD_CUT       = 101;
const IE_SUB_CMD_MOVE      = 102;	
const IE_SUB_CMD_PASTE     = 103;	
const IE_SUB_CMD_SELECTION = 104;
const IE_SUB_CMD_DEL       = 105;
const IE_SUB_CMD_MWE_SEL   = 107;

function initGuiEditCmd(){
    return guiCmd = {
               // type:   0,
               // handle: 0,
                cmd:    0,
                subCmd: 0,
                posOldRow: -1,
                posOldCol: -1,
                posNewRow: -1,
                posNewCol: -1,
                sizeRows:  -1,
                sizeCols:  -1,
                posNewRowOffset: 0,
                posNewColOffset: 0,
                sizeRowsOffset:  0,
                sizeColsOffset:  0,
                ap:  null,
                fld: null
            }
}

function sendGuiEditCmd(guiEditCmdObj){
    if(!guiEditCmdObj){
        return;
    }
    sendGuiEditCmdEx( guiEditCmdObj.cmd, 
                      guiEditCmdObj.subCmd, 
                      guiEditCmdObj.posOldRow, 
                      guiEditCmdObj.posOldCol, 
                      guiEditCmdObj.posNewRow, 
                      guiEditCmdObj.posNewCol, 
                      guiEditCmdObj.sizeRows, 
                      guiEditCmdObj.sizeCols, 
                      guiEditCmdObj.posNewRowOffset, 
                      guiEditCmdObj.posNewColOffset,
                      guiEditCmdObj.sizeRowsOffset,
                      guiEditCmdObj.sizeColsOffset,
                      guiEditCmdObj.ap, 
                      guiEditCmdObj.fld );
}

/*this functions sends the image editor changes to appx*/
function sendGuiEditCmdEx(cmd, subCmd, pOldRow, pOldCol, pNewRow, pNewCol, sRows, sCols, pNewRowOff, pNewColOff, sRowsOff, sColsOff, ap, fld )
{
    if((appx_session.server_feature_mask & TMNET_FEATURE_GUI_EDIT_CMD) == TMNET_FEATURE_GUI_EDIT_CMD){
        var type = PAINT_TYPE_IE;
        var	handle = 0;
        var ms = {
            'cmd': 'appxImageEditorCommand',
            'args': [type,handle,cmd,subCmd,
                pOldRow,pOldCol, pNewRow, pNewCol,
                sRows, sCols,ap, fld,pNewRowOff,
                pNewColOff, sRowsOff, sColsOff ],
            'handler': 'appxImageEditorCommandHandler',
            'data': null
        };
        appx_session.ws.send(JSON.stringify(ms));	
    }
}

/*unselect all items on imageeditor*/
function appxImageEditor_unselectAllItems(){
    //manage selected items Array
    appx_session.imageEditorSelectedItems = [];
    //remove all selected items
    imageEditor_remove_all_resizable();
    $(".appx_ie_selected").removeClass("appx_ie_selected").removeClass("appx_ie_selected_proto");
    imageEditor_updateToolbar();
}

/*unselect an Item on ImageEditor screen*/
function appxImageEditor_unselectItem($tag){
    if(appx_session.imageEditorSelectedItems && appx_session.imageEditorSelectedItems.length > 0){
        for(var i = 0; i< appx_session.imageEditorSelectedItems.length; i++){
            if(appx_session.imageEditorSelectedItems[i].originalRow == $tag.data("row") && appx_session.imageEditorSelectedItems[i].originalCol == $tag.data("col"))
            {
                //remove the item from the slected element's array
                appx_session.imageEditorSelectedItems.splice(i, 1);
                //remove the class from the tag
                $tag.removeClass("appx_ie_selected").removeClass("appx_ie_selected_proto");
                imageEditor_remove_resizable($tag);
                break;
            }//end if
        }//end for 
        imageEditor_updateToolbar();
    }    
}

/* reselect selected items
** This function selects the items on the screen based on the stored selected items
*/
function appxImageEditor_reselect_items(){
    //check if we have any selected items
    if(!appx_session.imageEditorSelectedItems || appx_session.imageEditorSelectedItems.length <= 0){
        appx_session.imageEditorSelectedItems = [];
        return;
    }
    //get a copy of selecteditems first. We are using shallow copy here
    var selectedItems = [...appx_session.imageEditorSelectedItems];
    //then clear the selected items structure so we can add to it
    appxImageEditor_unselectAllItems();
    //go through all appx elements in screenBuf section and check if they are marked as selected. Reselect them if they do
    var allElements = $("#screenBuf .appx_ie_widget:data('row')");
    for(var i = 0; i < selectedItems.length; i++){
        var sel = selectedItems[i];
        var found = false;
        //look for the selectedItem object that corresponds to the current tag by its newRow and Col if exists
        if(sel.newRow){
            for(var j = 0; j < allElements.length; j++){
                var $elem = $(allElements[j]);
                if(sel.newRow == $elem.data('row') && sel.newCol == $elem.data('col')){
                    found = true;
                    appxImageEditor_selectItem($elem, sel.prototypeItem);
                    break;
                }
            }
        }
        //if the newRow and Col couldn't find the item, use the originalRow and col
        if( found == false){
            for(var j = 0; j < allElements.length; j++){
                var $elem = $(allElements[j]);
                if(sel.originalRow == $elem.data('row') && sel.originalCol == $elem.data('col')){
                    found = true;
                    appxImageEditor_selectItem($elem, sel.prototypeItem);
                    break;
                }
            }
        }
        //if we still couldn't find it give a console error
        if(found == false){
            console.log("appxImageEditor_reselect_items - Error: couldn't find selected item - " + JSON.stringify(sel));
        }
    }
    //delete selectedItem object
    selectedItems = null;
}
/*This function recreates selectedItems structure based on appx_ie_selected class*/
function appxImageEditor_recreate_selected_items(){
    //manage selected items Array
    appx_session.imageEditorSelectedItems = [];
    //go though all selected items and add them to selectedItems structure
    $(".appx_ie_selected").each(function(){
        var prototype = false;
        //check if this item is a prototype item
        if( $(this).hasClass("appx_ie_selected_proto")){
            prototype = true;
        }
        appxImageEditor_selectItem($(this), prototype);
    });
}
/*This updates the new location of the element after a move*/
function appxImageEditor_update_new_location($tag, newRow, newCol){
    for (var i=0; i<appx_session.imageEditorSelectedItems.length; i++){
        var sel = appx_session.imageEditorSelectedItems[i];
        //look for the selectedItem object that corresponds to the current tag
        if(sel.originalRow == $tag.data('row') && sel.originalCol == $tag.data('col')){
            sel.newCol = newCol;
            sel.newRow = newRow;
            break;
        }
    }
}

/*select an item on the imageEditor screen*/
function appxImageEditor_selectItem($tag, prototypeItem){
    //create selected Items array if doesn't exist
    if(!appx_session.imageEditorSelectedItems){
        appx_session.imageEditorSelectedItems = [];
    }
    //create a selected item object
    var selectedItem = {};
    selectedItem.originalRow = $tag.data("row");
    selectedItem.originalCol = $tag.data("col");

    $tag.addClass("appx_ie_selected");
    $tag.data('top', parseInt($tag.css('top'))); //This are needed for drag/move
    $tag.data('left', parseInt($tag.css('left'))); //This are needed for drag/move
    //if this one is prototype, we need to remove the other one that marked as prototype
    if(prototypeItem == true){
        //the previous prototype most likely is at the end, so go backward to find it
        for(var i = appx_session.imageEditorSelectedItems.length - 1; i >= 0; i--){
            if(appx_session.imageEditorSelectedItems[i].prototypeItem == true)
            {
                appx_session.imageEditorSelectedItems[i].prototypeItem = false;
                break;
            }//end if
        }//end for
        $(".appx_ie_selected_proto").removeClass("appx_ie_selected_proto");
        $tag.addClass("appx_ie_selected_proto");
        selectedItem.prototypeItem = true;
        var row = parseInt(selectedItem.originalRow);
        var col = parseInt(selectedItem.originalCol);
        appxPutCursor( col, row );
    }
    //add the selecteditem object to the array
    appx_session.imageEditorSelectedItems.push(selectedItem);
    //if only one item is selected, make it resizable
    if($(".appx_ie_selected").length == 1){
        imageEditor_set_resizable($tag);
    }
    else{
        imageEditor_remove_all_resizable();
    }
    //update toolbar buttons
    imageEditor_updateToolbar();
}

/*select items in lasso rectangle
    -rect is the boundry of lasso rectangle. rect={bottom, left, top, right}. Note that rect numbers are relative to imageeditor box
    -fullyBounded: a flag that controls the selction of items that are fully bounded or intersected
    -ctrlIsDown: control key is down. Don't unselect the already selected items
*/
function appxImageEditor_selectItems_lasso(rect, fullyBounded, ctrlIsDown){
    //unselect all items if ctrl key is not down
    if(ctrlIsDown != true){
        appxImageEditor_unselectAllItems();
    }
    var itemsToCheck = $(".appxwidget:data('row')"); //all appxwidgets which are not selected
    var selectionCount = 0;
    //go through each item on the screen and check if they overlap with newly moved items
    for(var ii = 0; ii < itemsToCheck.length; ii++){
        var $item = $(itemsToCheck[ii]);
        var rect2 = $item.get(0).getBoundingClientRect();
        //bounding client rect gives numbers related to viewport not page, so if you scroll down, you get wrong numbers
        //for this reason we add the pageOffsets to the bounding rect
        if(fullyBounded == true ){
            //only select fully bounded items
            if( 
                rect.top <= (rect2.top + window.pageYOffset) &&
                rect.right >= (rect2.right + window.pageXOffset) &&
                rect.bottom >= (rect2.bottom + window.pageYOffset)&&
                rect.left <= (rect2.left + window.pageXOffset)
            ){
                selectionCount++;
                var prototypeItem = false;
                if(selectionCount == 1){
                    prototypeItem = true; 
                }
                appxImageEditor_selectItem($item, prototypeItem)
            }
        }
        else{
            //this checks intersection between items
            if( !(
                rect.top >= (rect2.bottom + window.pageYOffset) ||
                rect.right <= (rect2.left + window.pageXOffset) ||
                rect.bottom <= (rect2.top + window.pageYOffset) ||
                rect.left >= (rect2.right + window.pageXOffset)
            )){
                selectionCount++;
                var prototypeItem = false;
                if(selectionCount == 1){
                    prototypeItem = true; 
                }
                appxImageEditor_selectItem($item, prototypeItem)
            }
        }

    }
}

/*to make a row text modifiable*/
function appxImageEditor_selectRowtext($tag){
    $tag.attr("readonly", false);
    $tag.prop("readonly", false);
    $tag.off('focus');
    $tag.removeClass("unselectable");
    $tag.addClass("appx_ie_rowtext_enabled");
    $tag.focus();
    //also hide blockcursor
    $("#appxCursor").css("visibility","hidden");
}

/*to make selected rowtexts non-modifiable*/
function appxImageEditor_unselectRowtext(){
    var $tag = $(".appx_ie_rowtext_enabled");
    if($tag.length >0 ){
        $tag.attr("readonly", true);
        $tag.prop("readonly", true);
        $tag.on('focus', function not_focusable(event){
            this.blur();
        });
        $tag.removeClass("appx_ie_rowtext_enabled");
        $tag.addClass("unselectable");
        $tag.trigger("blur");
    }
}

/*hide horizontal and vertical guide lines*/
function appxImageEditor_hideGuideLines(){
    var $line_h = $(".appx-horizontal-guide-line");
    var $line_v = $(".appx-vertical-guide-line");
    if($line_h.length > 0){
        $line_h.css("display", "none");
    }
    if($line_v.length > 0){
        $line_v.css("display", "none");
    }
}
function  appxImageEditor_drawHorizontalGuideLine(location_top){
    //create it first if it doesnt exist
    var $line = $(".appx-horizontal-guide-line");
    if( $line.length == 0){
        $line = $("<div class='appx-horizontal-guide-line' style='display:none;'>&nbsp;</div>");
        $(".appxImageEditor").append($line);
    }
    $line.css({'top': location_top+"px",
                'left': '0px',
                'width':'100%',
                'display':'block'
              });
}
function  appxImageEditor_drawVerticalGuideLine(location_left){
    //create it first if it doesnt exist
    var $line = $(".appx-vertical-guide-line");
    if( $line.length == 0){
        $line = $("<div class='appx-vertical-guide-line' style='display:none;'>&nbsp;</div>");
        $(".appxImageEditor").append($line);
    }
    $line.css({'left': location_left+"px",
                'top': '0px',
                'height':'100%',
                'display':'block'
              });
}

/* displays a guide bar in the image editor
**    type: specifies types of the guide bar. Valid values are "VERTICAL" and "HORIZONTAL"
**    offset: The location of the bar. if the bar is VERTICAL, it is the offset from the left. If the bar is Horrizintal it is the offset from the top
*/
function  appxImageEditor_drawGuideBar(type, offset){
    var $boxhtml = $("#screenBuf .appxImageEditor");
    if($boxhtml.length == 0){
        var $boxhtml = $(".appxImageEditor");
    }
    if(offset < 0){
        return;
    }
    //create it with display none initially
    var $line = $("<div style='display:none;'></div>");
    $boxhtml.append($line);
    if(type == "VERTICAL"){
        if(offset >= $boxhtml.width()){
            //guidebar is not inside of the image. Don't draw it
            return; 
        }
        $line.addClass('appx-vertical-guide-bar');
        $line.css({'left': offset+"px",
                'display':'block',
                'z-index':parseInt($boxhtml.css("z-index"))+ 50 //we want this to be on top of everything
                });
    }
    else{
        if(offset >= $boxhtml.height()){
            //guidebar is not inside of the image. Don't draw it
            return; 
        }
        $line.addClass('appx-horizontal-guide-bar');
        $line.css({'top': offset+"px",
                'display':'block',
                'z-index':parseInt($boxhtml.css("z-index")) + 50 //we want this to be on top of everything
                });
    }
    //add data to the tag so we can find its object easier
    $line.data("type", type);
    $line.data("offset", offset);

    //Make the bar movable
    $line.draggable({
        grid: [ appx_session.colWidthPx, appx_session.rowHeightPx ],
        cancel: false,
        axis: (type == "VERTICAL")? "x":"y",
        /*containment: "parent",*/
        /*This is an extended custom function added by appx and is not part of the API*/
        beforeStart: function drag_beforeStart(event, ui){
            //if shift is down don't use grid
            if(event.shiftKey){
                $(this).draggable( "option", "grid", false );
            }
            else{
                $(this).draggable( "option", "grid", [ appx_session.colWidthPx, appx_session.rowHeightPx ] );
            }
        },
        drag: function dragging(event){
            //if shift is down don't use grid
            if(event.shiftKey){
                $(this).draggable( "option", "grid", false );
            }
            else{
                $(this).draggable( "option", "grid", [ appx_session.colWidthPx, appx_session.rowHeightPx ] );
            } 
        },
        stop: function drag_stop(event) {
            var t = $(this).data('type');
            var off = parseInt($(this).data('offset'));
            var top = parseInt($(this).css('top'));
            var left = parseInt($(this).css('left'));
            var remove_guidebar = false;
            //check if the guide needs to be deleted. If user moves the bar outside of the screen
            //it means they want to delete the bar.
            if(t == "VERTICAL"){
                if( left < 0 || left > $boxhtml.width()){
                    remove_guidebar = true;
                }
            }
            else{
                if( top < 0 || top > $boxhtml.height()){
                    remove_guidebar = true;
                }
            }
            //delete the bar
            if(remove_guidebar == true){
                appxImageEditor_deleteGuideBar(t, off);
            }
            //find the object for the guidebar and update it with the new offset
            else{
                var guides = appx_session.imageEditor_guideBars;
                if(guides && guides.length > 0){
                    for(var i = 0; i < guides.length; i++){
                        if(guides[i].type == t && guides[i].offset == off){
                            guides[i].offset = (t=="VERTICAL")?left:top;
                            break;
                        }
                    }//end for
                } 
            }//end else   
        }//end stop
    });
}

/* add a guide bar to the image editor
**    type: specifies types of the guide bar. Valid values are "VERTICAL" and "HORIZONTAL"
**    offset: The location of the bar. if the bar is VERTICAL, it is the offset from the left. If the bar is Horrizintal it is the offset from the top
*/
function  appxImageEditor_addGuideBar(type, offset){
    if(!appx_session.imageEditor_guideBars){
        appx_session.imageEditor_guideBars = [];
    }
    var bar = { "type": type,
                "offset": offset
              };
    appx_session.imageEditor_guideBars.push(bar);
    appxImageEditor_drawGuideBar(type, offset);
}

/* delete a guidebars */
function appxImageEditor_deleteGuideBar(type, offset){
    var guides = appx_session.imageEditor_guideBars;
    if(guides && guides.length > 0){
        for(var i = 0; i < guides.length; i++){
            if(guides[i].type == type && guides[i].offset == offset){
                guides.splice(i, 1); //remove the guidebar from the array
                break;
            }
        }
        //redsiplay guidebars
        appxImageEditor_displayGuideBars();
    }
}

/* display all existing guidebars */
function appxImageEditor_displayGuideBars(){
    //first delete all guidebars on the screen
    $(".appx-vertical-guide-bar,.appx-horizontal-guide-bar").remove();
    var guides = appx_session.imageEditor_guideBars;
    if(guides && guides.length > 0){
        for(var i = 0; i < guides.length; i++){
            appxImageEditor_drawGuideBar(guides[i].type, guides[i].offset);
        }
    }
}

/*Modify the style of the items on the screen to fit the imageEditor functionality*/
function appxImageEditorStyle(widget, $tag){
    /*in inquire mode row texts show up as divs with class rowtext. In change mode, they show up as input type=text with wWidgetOriginalType as row text*/
    if( (widget != null && widget.wWidgetOriginalType == WIDGET_TYPE_ROWTEXT) || ($tag.prop('nodeName')=='DIV' && $tag.hasClass("rowtext")))
    {
        $tag.addClass("appx_ie_rowtext");
        /*these are rowtext widgets, we want to be able to modify the data in these only when you double click on them*/
        $tag.attr("readonly", true);
        $tag.prop("readonly", true);
        //to make the data non selectable
        $tag.addClass("unselectable");
        //to make it non-focusable
        $tag.off("focus");
        $tag.off("blur");
        $tag.on('focus', function not_focusable(event){
            this.blur();
        });

        //rowtext got created as raw text, but we still want it to go behind all other widgets. So adjust the z-index to be like rowtext
        //wLayer for RAWTEXT is 10 and for ROWTEXT is 25. Reduce the zindex by 15 to make up the differfence
        //Note: during runtime boxes are poistioned behind row text (for a reason unknown to me). In Image editor we want 
        //      the boxes to be infront of row texts so we can select them and move them. For this reason, reduce the 
        //      z-index by another 10 whch puts wlater at -25
        $tag.css("z-index", parseInt($tag.css("z-index"))-25);

        /* select and unselect event
        ** We want to unselect the selected item if user clicks outside of an item
        */
        $tag.click(function(event){
            if(event.ctrlKey == true || event.metaKey == true){
               //don't do anything if ctrl is down, user probably miss-clicked
            }
            else{
                //remove all selected items
                appxImageEditor_unselectAllItems();
                if($(this).hasClass("appx_ie_rowtext_enabled")){
                    //user has clicked on a selected row text. We don't do anything. We need to stop propagating this event so parent elements do do anything either
                    event.stopPropagation();
                }
                else{
                    //user cliked on a rowtext which is not enabled. Unselect the currently enabled row text if exists
                    appxImageEditor_unselectRowtext();//unselect active rowtext
                }
                var loc = imageEditor_offset_to_location(event.pageX, event.pageY);
                if(loc.row && loc.col){
                    appxPutCursor( loc.col, loc.row );
                } 
            }
        });
         /*bring up properties of the object*/
         $tag.dblclick(function(event){
            event.stopPropagation();
            imageEditor_toolbarButton_toggle_control();//change the selected control to select
            appxImageEditor_unselectAllItems();//unselect all the items
            if(!$(this).hasClass("appx_ie_rowtext_enabled")){
                appxImageEditor_unselectRowtext();//unselect active rowtext
                appxImageEditor_selectRowtext($(this));
            }
        });

        /*TODO: disable autoselect in appxitemhandler function*/
        

    }
    else{
        /*make the widgets non-modifiable*/
        $tag.attr("readonly", true);
        $tag.prop("readonly", true);
        $tag.addClass("appx_ie_widget");
        /*TODO: unhide hidden widgets*/

        /* add the icon and input tag to datetime fields to make them recognizable*/
        if($tag.hasClass("appxdatefield")){
            var $datefield = $("<input class='appxdatevalue' type='text' readonly='readonly'>");
            //appx sets the widget properties at the div level. Some of these properties like bg color are being ignored
            //at the input level. So copy the style from the div level to input level so the widget propertirs become visible
            $datefield.attr("style", $tag.attr("style"));
            //now override width and height style properties
            $datefield.css({
                                "height":"100%",
                                "width": "100%",
                                "top":"", //delete top css property if exists
                                "left":"", //delete left css property if exists
                                "outline":"inherit", //needed to view the outline of the selected item in image editor
                                "outline-offset":"inherit",
                                "cursor":"inherit" //to keep the cursor as defult on hover
                            });
            $tag.append($datefield);//add the input field to div
            $tag.append($("<img src='./images/calendar.gif' style='position: absolute; right: 2px; top: 2px; z-index: 100000;'/>"));
        } 
        //if color picker, override some css
        else if($tag.hasClass("appxcolorpickerwrapper")){
            $tag.width( $tag.width() + WIDGET_COLOR_CHOOSER_EXTRA_WIDTH - WIDGET_RAW_TEXT_EXTRA_WIDTH);
            var $colpick = $tag.find(".appxcolorpicker");
            if($colpick.length == 1){
                 //now override style properties
                $colpick.css("cursor","default");
                //make the inner feild readonly as well
                $colpick.attr("readonly", true);
                $colpick.prop("readonly", true);
            }
        }
        else if($tag.hasClass("togglebutton")){
            //override the cursor so it shows up as default
            $tag.css("cursor","default");
        }
        else if($tag.hasClass("picture")){
            //if there is no image, use default image
            var wx = $tag.data("widget");
            if(wx && wx.wIconDisabled == null){
                $tag.css({  "background-image":"url('./images/Picture.png')",
                            "background-repeat": "no-repeat",
                            "background-position": "center",
                            "background-color": "white",
                            "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                        });
            }
        }
        else if($tag.hasClass("ckeditor")){
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/HTMLEditor.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });  
        }
        else if($tag.hasClass("appx-html-viewer")){
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/HTMLViewer.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-color": "white",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });  
        }
        else if($tag.hasClass("appx-web-browser")){
            //since this is an iframe tag, clicks wouldn't work on it, so we replace it with a div
            var $elem = $("<div>");
            //copy all the attributes and styles from the iframe element to div
            var attrib = $tag.prop('attributes');
            $.each(attrib, function(){
                $elem.attr(this.name, this.value)
            });
            //now copy the data
            $elem.data($tag.data());
            //copy all children to the new div
            $tag.children().appendTo($elem);
            //add div to the page
            $tag.parent().append($elem);
            //delete the iframe from the page
            $tag.remove();
            //now the div is our new guy. change the reference
            $tag = $elem;
            //change the style so it will be more obvious what type of widget we are working with
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/WebBrowser.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-color": "white",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });
        }
        else if($tag.hasClass("appx-mediaplayer")){
            //remove the embed tag. We don't need it in image editor
            $tag.children().remove();
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/MediaPlayer.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });
        }
        else if($tag.hasClass("appx-flashplayer")){
            //remove the object tag. We don't need it in image editor
            $tag.children().remove();
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/FlashPlayer.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });

        }
        else if($tag.hasClass("appx-code-viewer")){
            //put a bg image so we can differentiate between text areas and html editors in image editor
            $tag.css({  "background-image":"url('./images/CodeViewer.png')",
                        "background-repeat": "no-repeat",
                        "background-position": "center",
                        "background-size": Math.min($tag.height() * 0.8, 128) + "px"
                    });

        }
        else if($tag.hasClass("button")){
            //TODO: show option number as tooltip
            var wx = $tag.data("widget");
            if(wx && wx.wCommand != null){
                //convert option number to text
                var tooltip = appx_get_option_name(wx.wCommand);
                $tag.prop('title', tooltip);
                $tag.tooltip({
                    content: function tooltipCallback() {
                        if (typeof this.title == 'function')
                            return this.title();
                        else
                            return '';
                    }
                });
            }
        }
        else if($tag.hasClass("appxSlider")){
            $tag.height($tag.height() - 50);//we add 50 to the tag height if it is slider in appxwisgwthandlerpropsex function
            $tag.width($tag.width() - 15); //we add 15 to  the tag width if it is slider in appxwisgwthandlerpropsex function
        }

        //delete the existing on click event. This is to prevent buttons to fire option
        $tag.off("click");

        //ability to move the tag
        make_element_movable($tag);

        /*select and unselect event*/
        $tag.on("click",function(event){
            /* if ctrl key is held, anditem is selected, unselect it. if not select it.
            ** if ctrl is not held, unselect all selected items and only select this one
            */
            event.stopPropagation();

            //If we are resizing an element, ignore click event
            if(appx_session.imageEditorResizable && appx_session.imageEditorResizable.ignoreClickEvent == true){
                appx_session.imageEditorResizable.ignoreClickEvent = false;
                return;
            }
            appxImageEditor_unselectRowtext();//unselect active rowtext
            if(event.ctrlKey == true || event.metaKey == true){
                if($(this).hasClass("appx_ie_selected")==false){
                    appxImageEditor_selectItem($(this), true);
                }
                else{
                    appxImageEditor_unselectItem($(this))
                }
            }
            else{
                appxImageEditor_unselectAllItems();
                appxImageEditor_selectItem($(this), true);
            }
        });
        /*bring up properties of the object*/
        $tag.dblclick(function(event){
            event.stopPropagation();
            imageEditor_toolbarButton_toggle_control();//change the selected control to select
            appxImageEditor_unselectAllItems();//unselect all the items
            appxImageEditor_unselectRowtext();//unselect active rowtext
            //bring up object properties of this items
            var row = parseInt($(this).data("row"));
            var col = parseInt($(this).data("col"));
            appxPutCursor( col, row );
            appxwidgetcallback( OPT_CHG_MODE );
        });
    }
}

/*get size of a tag in appx format (rows and columns). You can override height and width to get the number of rows and columns for the new size.
*   $tag: jqery object of the element
*   height : overridden height in pixels (optional)
*   width : overridden width in pixels (Optional)
*/
function get_tag_size($tag, height, width){
    var size = {};
    var h = height!=null? height:parseInt($tag.css("height"));
    var w = width!=null? width:parseInt($tag.css("width"));
    var wx = $tag.data("widget");
    var wt = null;
    if(wx)
        wt = wx.wWidgetType;
/*the code below is the exact opposite of appxwidgetdimensions function.
 Any changes to those functions need to be applied here for accurate size detection */
    if (wt == WIDGET_TYPE_HTML_VIEWER) {
        h -= WIDGET_HTML_VIEWER_EXTRA_HEIGHT;
    }
    if (wt != WIDGET_TYPE_CHECK_BOX && wt != WIDGET_TYPE_LINE) {
        // The java client adds an extra 5 pixel to the widget of input fields
        // to make room for the decorations
        if (wt != WIDGET_TYPE_TABLE && wt != WIDGET_TYPE_BOX && wt != WIDGET_TYPE_BUTTON && wt != WIDGET_TYPE_LABEL && wt != WIDGET_TYPE_PICTURE && wt != WIDGET_TYPE_LISTBOX) {
            w -= WIDGET_RAW_TEXT_EXTRA_WIDTH;
        }
        /* html client changes the listbox to row text in inquire mode. If the original type was token,
         we still want to add extra padding for consistency */
        if (wt == WIDGET_TYPE_LISTBOX || wx.wWidgetOriginalType == WIDGET_TYPE_LISTBOX) {
            var pad = WIDGET_LISTBOX_EXTRA_WIDTH; //Added width to accomodate drop down arrow
            w -= pad;
            //if the type is raw-text remove extra 5 px that we added to the widget width
            if (wt == WIDGET_TYPE_RAW_TEXT && wx.wWidgetOriginalType == WIDGET_TYPE_LISTBOX) {
                w += WIDGET_RAW_TEXT_EXTRA_WIDTH;
            }
        }
    }
    if (wt == WIDGET_TYPE_BOX) {
        if (wx.wLabel && wx.wLabel.length > 0) {
             w -= WIDGET_BOX_WITH_LABEL_EXTRA_WIDTH;
             h -= WIDGET_BOX_WITH_LABEL_EXTRA_HEIGHT;
        }
        else {
            w -= WIDGET_BOX_WITHOUT_LABEL_EXTRA_WIDTH;
            h -= WIDGET_BOX_WITHOUT_LABEL_EXTRA_HEIGHT;
        }
    }
    if (wt == WIDGET_TYPE_LINE){
        var insets = $tag.data("insets");
        w = w - ( insets.left + insets.right  - appx_session.colWidthPx );
        h = h - ( insets.top  + insets.bottom - appx_session.rowHeightPx);
    }
    if(wt == WIDGET_TYPE_DATE_CHOOSER){
        //appx adds 2.5 column to date fields for the date picker icon. Deduct that to get accurate size
        w -= WIDGET_DATE_CHOOSER_EXTRA_WIDTH - WIDGET_RAW_TEXT_EXTRA_WIDTH;
    }
    if(wt == WIDGET_TYPE_COLOR_CHOOSER){
        w -= WIDGET_COLOR_CHOOSER_EXTRA_WIDTH - WIDGET_RAW_TEXT_EXTRA_WIDTH;
    }
    /*if ($tag.hasClass("defaultBorder") && $tag.is("button") && wx.wBorder != BORDER_NONE) {
        $tag.css({
            "top": (dim.y + 1),
            "left": (dim.x + 1),
            "height": (dim.h - 2),
            "width": (dim.w - 2)
        });
    }*/

    size["rows"] = Math.floor( h / appx_session.rowHeightPx);
    size["cols"] = Math.floor( w / appx_session.colWidthPx);
    size["rowOffset"] = Math.round((( h / appx_session.rowHeightPx) - size.rows) * 100);
    size["colOffset"] = Math.round((( w / appx_session.colWidthPx ) - size.cols) * 100);

    //Appx doesn't like row/col 0, so if it is 0 and has positive offset, change it to 1 and adjust the offset
    if(size.rows == 0 && size.rowOffset > 0){
        size.rows = 1;
        size.rowOffset -= 100;
    }
    if(size.cols == 0 && size.colOffset > 0){
        size.cols = 1;
        size.colOffset -= 100;
    }

    /*Lines can have negative size. Negetive size basically identifies the slope of the line*/
    if (wt == WIDGET_TYPE_LINE){
        var $line = $tag.find("line");
        if($line.length == 1){
            var x1 = $line.attr("x1") * 1;// times one to get treated as number
            var x2 = $line.attr("x2") * 1;
            var y1 = $line.attr("y1") * 1;
            var y2 = $line.attr("y2") * 1;
            if(y1 > y2)
                size.rows *= -1;
            if(x1 > x2)
                size.cols *= -1;
        }
    }
    /*debug -delete*/
    //console.log("get_tag_size "+$tag.prop("id") + " row="+size.rows+" col="+size.cols+" rowoff="+size.rowOffset+" coloff="+size.colOffset);

    return(size);
}

/*
* get position of a tag in appx format (rows and columns). You can override top and left. In case of line widget, you can also override height and width
*    $tag: jquery element
*    t:  overridden top in pixels(optional)
*    l:  overridden left in pixels(optional)
*    h:  overridden height in px- used for line widgets (optional)
*    w:  overridden width in px- used for line widgets (optional)
*/
function get_tag_location($tag, t, l, h, w){
    var loc = {};
    var left = l!=null? l:parseInt($tag.css("left"));
    var top = t!=null? t:parseInt($tag.css("top"));
    var wx = $tag.data("widget");
    var wt = null;
    if(wx)
    {
        wt = wx.wWidgetType;
    }
    if (wt == WIDGET_TYPE_BOX && wx.wLabel && wx.wLabel.length > 0) {
        left -= 2;
    }
    if(wt == WIDGET_TYPE_LINE){
        var $line = $tag.find("line");
        var insets = $tag.data("insets");
        if($line.length == 1){
            var x1 = $line.attr("x1") * 1;// times one to get treated as number
            var x2 = $line.attr("x2") * 1;
            var y1 = $line.attr("y1") * 1;
            var y2 = $line.attr("y2") * 1;
            var height = h!=null? h: parseInt($tag.css("height"));
            var width = w!=null? w:  parseInt($tag.css("width"));
            left = x2 >= x1 ? left : left + width - appx_session.colWidthPx;
            top  = y2 >= y1 ? top  : top  + height - appx_session.rowHeightPx;
            left +=  insets.left;
            top  +=  insets.top;
        }
    }

    var row = top  / appx_session.rowHeightPx;
    var col = left / appx_session.colWidthPx;
    loc["rowOffset"] = Math.round((row - Math.floor(row)) * 100);
    loc["colOffset"] = Math.round((col - Math.floor(col)) * 100);
    loc["row"] = Math.floor(row);
    loc["col"] = Math.floor(col);
    //if row or column is zero with positive offset, change the row/col to one and make offset negative. Appx doesn't handle row/col 0 very well
    if(loc.row == 0 && loc.rowOffset > 0){
        loc.row = 1;
        loc.rowOffset -= 100;
    }
    if(loc.col == 0 && loc.colOffset > 0){
        loc.col = 1;
        loc.colOffset -= 100;
    }
    //console.log("get_tag_location "+$tag.prop("id") + " row="+loc.row+" col="+loc.col+" rowoff="+loc.rowOffset+" coloff="+loc.colOffset);
    return(loc);
}

function make_element_movable($element){
    var oldLeft, oldTop;
    var error_during_move = false;
    /*make the widgets movable (draggable)*/
    $element.draggable({
    grid: [ appx_session.colWidthPx, appx_session.rowHeightPx ],
    cancel: false,
    /*This is an extended custom function added by appx and is not part of the API*/
    beforeStart: function drag_beforeStart(event, ui){
        /*if tag is not selected, select it first*/
        if($(this).hasClass("appx_ie_selected")==false){
            //remove all selected items first, then select the current item
            appxImageEditor_unselectAllItems();
            appxImageEditor_unselectRowtext();//unselect active rowtext
            appxImageEditor_selectItem($(this), true);
        }
        //to prevent conflict with resizable api, remove the resizable
        if($(this).hasClass("appx_ie_resizable")){
            imageEditor_remove_resizable($(this));
        }
        //if shift is down don't use grid
        if(event.shiftKey){
            $(this).draggable( "option", "grid", false );
        }
        else{
            $(this).draggable( "option", "grid", [ appx_session.colWidthPx, appx_session.rowHeightPx ] );
        }
    },
    start: function drag_start(event, ui){
        /*capture starting position*/
        oldTop = parseInt($(this).css('top'));
        oldLeft = parseInt($(this).css('left'));
    },
    drag: function dragging(event){
        //if shift is down don't use grid
        if(event.shiftKey){
            $(this).draggable( "option", "grid", false );
        }
        else{
            $(this).draggable( "option", "grid", [ appx_session.colWidthPx, appx_session.rowHeightPx ] );
        }
        var top = parseInt($(this).css('top'));
        var left = parseInt($(this).css('left'));
        var topOffset = top - oldTop;
        var leftOffset = left - oldLeft;
        var leftGuideLine = false;
        var topGuideLine = false;
        /*move all the selected items based on the offset*/
        var selectedItems = $(".appx_ie_selected");
        var itemsToCheck = $(".appxwidget:data('row'):not('.appx_ie_selected')"); //all appxwidgets which are not selected
        var $anchor = $(this);
        error_during_move = false; //reset the error flag

        selectedItems.each(
            function(){      
                //move all selected except for the item we are dragging
                if($(this) !== $anchor){
                    //get the tag position at the time of selection
                    var t = $(this).data('top');
                    var l = $(this).data('left');
                    //move the tag based on the offset anchot tag moved
                    $(this).css('top',  (t  + topOffset )+"px");
                    $(this).css('left', (l  + leftOffset)+"px");
                }

                //Now check of item overlap happens - exclude appx labels (divs) from the check
                //Don't do overlap check for labels
                var overlap2check = true;
                var overlap = false;
                var overlap2 = false;
                //don't check overlap2 for div elements, they can overlap
                if(imageEditor_widget_can_intersect($(this))){
                    overlap2check = false;
                }
                var loc = get_tag_location($(this));
                var rect1 = this.getBoundingClientRect();
                var col_overlap_epsilon = appx_session.colWidthPx - 2; //we want to be able to overlap the fields as long as the overlap is less than one column. Allow 75% overlap
                var row_overlap_epsilon = appx_session.rowHeightPx - 5.25; //we want to be able to overlap the fields as long as the overlap is less than one row.  Allow 75% overlap
                //go through each item on the screen and check if they overlap with newly moved items
                for(var ii = 0; ii < itemsToCheck.length; ii++){
                    var $item = $(itemsToCheck[ii]);
                    //if selected item has the exact row and column of another item on the screen, produce an error
                    if( $item.data('row') == loc.row && $item.data('col') == loc.col){
                        overlap = true;
                        break;
                    }
                    //Don't do the following overlap check on labels
                    if(overlap2check == true && imageEditor_widget_can_intersect($item) == false)
                    {
                        var rect2 = $item.get(0).getBoundingClientRect();
                        //this checks intersection between items
                        if( !(
                            rect1.top > rect2.bottom - row_overlap_epsilon ||
                            rect1.right < rect2.left + col_overlap_epsilon ||
                            rect1.bottom < rect2.top + row_overlap_epsilon ||
                            rect1.left > rect2.right - col_overlap_epsilon
                        )){
                            overlap2 = true;
                            break;
                        }
                    }
                }

                if(overlap){
                    $(this).css("outline","solid 1px red");
                    error_during_move = true;
                }
                else if(overlap2){
                    $(this).css("outline","dotted 1px red");
                    error_during_move = true;
                }
                else{
                    $(this).css("outline","solid 1px green");
                }
            }

        );//end each
        /*
        ** select all the items on the screen which have row, exclude the selected items and the current item from the list
        ** Check if the another widget/item exists on the same location
        */
        $(".appxwidget:data('row'):not('.appx_ie_selected')").each(
            function(){
                /*add a guide line if the left sides are the same, or top are the same*/
                if(parseInt($(this).css('top')) == top){
                    topGuideLine = true;
                }
                if(parseInt($(this).css('left')) == left){
                    leftGuideLine = true;
                }
            }
        );

        //hide the guide lines if they exist
        appxImageEditor_hideGuideLines();
        //if the top position matches another element, draw a guide line
        if(topGuideLine){
            appxImageEditor_drawHorizontalGuideLine(top);
        }
        //if the left position matches another element, draw a guide line
        if(leftGuideLine){
            appxImageEditor_drawVerticalGuideLine(left);
        }
    },
    stop: function drag_stop(event) {
        if( error_during_move ){
            appxwidgetcallback(IE_CMD_NULL);
        }
        else{
            $(".appx_ie_selected").each(
                function drag_move_finished(){
                    var guiEditCmd = initGuiEditCmd();
                    guiEditCmd.cmd    = IE_CMD_DEFER;
                    guiEditCmd.subCmd = IE_SUB_CMD_MOVE;
                    /*get the old position*/
                    guiEditCmd.posOldRow = $(this).data('row');
                    guiEditCmd.posOldCol = $(this).data('col');
                    /*capture the new position and the size and send the info to the engine to apply the change*/ 
                    var size = get_tag_size($(this));
                    guiEditCmd.sizeRows = size.rows;
                    guiEditCmd.sizeCols = size.cols;
                    guiEditCmd.sizeRowsOffset = size.rowOffset;
                    guiEditCmd.sizeColsOffset = size.colOffset;
                    //get the new location
                    var loc = get_tag_location($(this));
                    console.log("Moved Item To:" + " row="+loc.row+" col="+loc.col+" rowoff="+loc.rowOffset+" coloff="+loc.colOffset);
                    guiEditCmd.posNewRow = loc.row;
                    guiEditCmd.posNewCol = loc.col;
                    guiEditCmd.posNewRowOffset = loc.rowOffset;
                    guiEditCmd.posNewColOffset = loc.colOffset;

                    appxImageEditor_update_new_location($(this), guiEditCmd.posNewRow, guiEditCmd.posNewCol);
                    appxPutCursor(guiEditCmd.posNewCol, guiEditCmd.posNewRow);
                    /*send the changes with Defer command. Defer is used to tell engine wait for more changes before applying them in case we are moving multiple widgets*/
                    sendGuiEditCmd(guiEditCmd);
                }
            );
            /*apply the Move changes*/
            appxwidgetcallback(IE_CMD_DO_MOVE);
        }
        
        
    }//end stop
    });
}
//This function gets x,y coordinates in pixle and gives row and col location
function imageEditor_offset_to_location(x, y){
    var $boxhtml = $(".appxbox.appxImageEditor");
    var row = null;
    var col = null;
    if($boxhtml){
        var box_loc = $boxhtml.offset();
        row = y - box_loc.top - parseFloat($boxhtml.css("border-top-width"));
        row = Math.floor(row/appx_session.rowHeightPx);
        col = x - box_loc.left - parseFloat($boxhtml.css("border-left-width"));
        col = Math.floor(col/appx_session.colWidthPx);
    }
    return({"row": row, "col": col});
}

/*
** This function makes the selected tag resizable
*/
function imageEditor_set_resizable($tag){
    //Check if item is resizable. If not, don't bother applying reziable to it
    if(imageEditor_can_be_resized($tag) == false){
        return;
    }
    var $boxhtml = $(".appxImageEditor");
    var image_editor_width  = $boxhtml.width(); 
    var image_editor_height = $boxhtml.height();
    var image_editor_cols   = Math.floor( image_editor_width / appx_session.colWidthPx) - 1;
    var image_editor_rows   = Math.floor( image_editor_height / appx_session.rowHeightPx) - 1;
    var box_loc = $boxhtml.offset();
    var image_editor_top = box_loc.top + parseFloat($boxhtml.css("border-top-width"));
    var image_editor_left = box_loc.left + parseFloat($boxhtml.css("border-left-width"));

    $tag.addClass("appx_ie_resizable");
    var use_helper_class = false;
    var error_during_resize = false;
    
    //use a helper function so user don't see missmatch in size during resize if resizable uses a wrapper
    if(!$tag.is("div")){
        use_helper_class = "appx-resizable-helper";
    }

    //https://api.jqueryui.com/resizable/
    $tag.resizable({
        grid:[appx_session.colWidthPx, appx_session.rowHeightPx],
        //containment: "parent", //containment is buggy when used with helper and parent has absolute positioning. see https://bugs.jqueryui.com/ticket/8044
        handles: "n, e, s, w, se, sw, nw, ne",
        helper: use_helper_class,
        classes: {
            "ui-resizable-se": "" /*don't assign ucon to bottom right corner*/
        },
        create: function( event, ui ) {
            //for certain elements like input, resizable library wraps the elements in ui_wrapper
            //this wrapper sometimes causes the element to resize because of the padding it adds
            if($(this).hasClass("ui-wrapper")){
                $elem = $(this).children(".appx_ie_widget"); //at this event ui is blank so get the element this way
                //remove padding for better presentation
                $(this).css({"padding":"0px",
                              "z-index": $elem.css("z-index")
                            });
                //make the elem the same size as the wrapper
                $elem.css({
                    "width": $(this).css("width"),
                    "height": $(this).css("height")
                });
            }
            /*we need to override css fo fieldsets with label*/
            if($(this).is("fieldset") && $(this).children("legend").length > 0){
                //if fieldset legend is located at the bottom it will be tricky. We roatte the field set by 180 degree and the legendt by 180 degree to format it
                if($(this).hasClass("fieldset-bottom")){
                    //FIXME: figure out how to do this
                    var $n = $(this).children(".ui-resizable-n");
                    var $s = $(this).children(".ui-resizable-s");
                    var $e = $(this).children(".ui-resizable-e");
                    var $w = $(this).children(".ui-resizable-w");
                    var $ne = $(this).children(".ui-resizable-ne");
                    var $nw = $(this).children(".ui-resizable-nw");
                    var $se = $(this).children(".ui-resizable-se");
                    var $sw = $(this).children(".ui-resizable-sw");
                    //switch north and south
                    var tmp =  $n.css("top");
                    $n.css("bottom", $s.css("bottom")).css("top", "unset");
                    $s.css("top", tmp).css("bottom", "unset");
                    //switch east and west
                    tmp = $e.css("right");
                    $e.css("left", $w.css("left")).css("right", "unset");
                    $w.css("right", tmp).css("left", "unset");
                    //switch sw with ne
                    var tmp1 =  $ne.css("top");
                    tmp =  $ne.css("right");
                    $ne.css({"bottom": $sw.css("bottom"),
                             "top"   : "unset",
                             "left"  : $sw.css("left"),
                             "right" : "unset"
                             }
                    );
                    $sw.css({"bottom": "unset",
                             "top"   : tmp1,
                             "left"  : "unset",
                             "right" : tmp
                             }
                    );
                    //switch se with nw
                    tmp1 =  $nw.css("top");
                    tmp =  $nw.css("left");
                    $nw.css({"bottom": $se.css("bottom"),
                             "top"   : "unset",
                             "left"  : "unset",
                             "right" : $se.css("right")
                             }
                    );
                    $se.css({"bottom": "unset",
                             "top"   : tmp1,
                             "left"  : tmp,
                             "right" : "unset"
                             }
                    );
                }
                //the legend is on top
                else{
                    var padding_top = parseFloat($(this).css("padding-start")) + 3;
                    var $ne = $(this).children(".ui-resizable-ne");
                    var $n = $(this).children(".ui-resizable-n");
                    var $nw = $(this).children(".ui-resizable-nw");
                    if(padding_top && $nw.length == 1) $nw.css("top", parseFloat($nw.css("top"))-padding_top);
                    if(padding_top && $ne.length == 1) $ne.css("top", parseFloat($ne.css("top"))-padding_top);
                    if(padding_top && $n.length == 1)  $n.css("top", parseFloat($n.css("top"))-padding_top);
                }
            }
            /*resize handles should get higher zindex so they stay on top*/
            $(this).children(".ui-resizable-handle").css("z-index", $(this).css("z-index"));
        },
        start: function( event, ui ) {
            //if we are using helper, we need to adjust its z-index so it shows up on top
            if(ui.helper.length > 0 && ui.helper.hasClass("appx-resizable-helper")){
                ui.helper.css("z-index", 9000);
                //helper shrinks the original element. resize it back to its original size
                ui.originalElement.css({    "width": ui.originalSize.width,
                                            "height": ui.originalSize.height
                                        });
            }
            //we need to ignore click event that gets fired after the resize is done to maintain the selected item
            //we set a flag here to tell click event to not do anything
            appx_session.imageEditorResizable = {};
            appx_session.imageEditorResizable.ignoreClickEvent = true;
            //capture the original size and position of the item
            var wx = ui.originalElement.data("widget");
            appx_session.imageEditorResizable.oldPos = {};
            appx_session.imageEditorResizable.oldPos.row = ui.originalElement.data('row');
            appx_session.imageEditorResizable.oldPos.col = ui.originalElement.data('col');
            appx_session.imageEditorResizable.oldSize= {};
            ///capture the original size - use widget if exists, otherwise calculate it based on elements width and height 
            if(wx && ( wx.wSizeH || wx.size_row)){
                appx_session.imageEditorResizable.oldSize.rows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                appx_session.imageEditorResizable.oldSize.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                appx_session.imageEditorResizable.oldSize.rowOffset = wx.wOffsetH!=null?wx.wOffsetH:0;
                appx_session.imageEditorResizable.oldSize.colOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
            }
            else{
                appx_session.imageEditorResizable.oldSize = get_tag_size(ui.originalElement);
            }

            //debug info
            /*console.log("resize start - orig size -" + JSON.stringify(ui.originalSize));
            console.log("resize start - orig pos  -" + JSON.stringify(ui.originalPosition));
            console.log("resize start - size -" + JSON.stringify(ui.size));
            console.log("resize start - pos  -" + JSON.stringify(ui.position));
            console.log("resize start - oldItemProp -" + JSON.stringify(appx_session.imageEditorResizable));*/

        },
        //beforeResize is an extended event added by appx and is not part of the standard api
        beforeResize: function(event, ui){
            //if shift is down don't use grid
            if(event.shiftKey){
                ui.originalElement.resizable( "option", "grid", false );
            }
            else{
                ui.originalElement.resizable( "option", "grid", [ appx_session.colWidthPx, appx_session.rowHeightPx ] );
            } 
        },
        resize: function( event, ui ) {
            error_during_resize = false; //reset the flag and test for it each time resize happens
            var itemsToCheck = $(".appxwidget:data('row'):not('.appx_ie_resizable')"); //all appxwidgets which are not selected
            //Now check of item overlap happens - exclude appx labels (divs) from the check
            //Don't do overlap check for labels
            var overlap2check = true;
            var overlap = false;
            var overlap2 = false;
            //don't check overlap2 for div elements, they can overlap
            if(imageEditor_widget_can_intersect(ui.originalElement)){
                overlap2check = false;
            }
            //since sometimes we use helper to resize, the helper doesn't have widget and other info. So, pass the original element and overide dimentions
            var loc;
            if(use_helper_class){
                loc = get_tag_location(ui.originalElement, ui.position.top - image_editor_top, ui.position.left - image_editor_left, ui.size.height, ui.size.width);
            }
            else{
                loc = get_tag_location(ui.originalElement, ui.position.top, ui.position.left, ui.size.height, ui.size.width);
            }
            //to get the size, we pass the original element with overridden height and width
            var size = get_tag_size(ui.originalElement, ui.size.height, ui.size.width);
            var newBottom = (loc.row + size.rows)-1; // + (( loc.rowOffset + size.rowOffset)/100)); //We don't need to calculate offsets
            var newRight = (loc.col + size.cols )-1; //+ (( loc.colOffset + size.colOffset)/100)); //We don't need to calculate offsets
  
            //check to make sure the item is still inside of the image editor
            if(loc.col <= 0 || loc.row <= 0 || size.rows < 1 || size.cols < 1 || newBottom > image_editor_rows || newRight > image_editor_cols){
                error_during_resize = true;
            }

            //console.log("resizing to " +JSON.stringify(ui.size)+ "--" + JSON.stringify(ui.position)+ "--" + JSON.stringify(size) + "--" + JSON.stringify(loc));
            var rect1 = ui.helper.get(0).getBoundingClientRect(); //getBoundingCliientRect requires javascript object not jquery
            var col_overlap_epsilon = appx_session.colWidthPx - 2; //we want to be able to overlap the fields as long as the overlap is less than one column. Allow 75% overlap
            var row_overlap_epsilon = appx_session.rowHeightPx - 5.25; //we want to be able to overlap the fields as long as the overlap is less than one row. allow 75% overlap
            //go through each item on the screen and check if they overlap with newly moved items
            for(var ii = 0; !error_during_resize && ii < itemsToCheck.length; ii++){
                var $item = $(itemsToCheck[ii]);
                //if selected item has the exact row and column of another item on the screen, produce an error
                if( $item.data('row') == loc.row && $item.data('col') == loc.col){
                    overlap = true;
                    break;
                }
                //Don't do the following overlap check on labels
                if(overlap2check == true && imageEditor_widget_can_intersect($item) == false)
                {
                    var rect2 = $item.get(0).getBoundingClientRect();
                    //this checks intersection between items
                    //Relax this to allow less than one row and col of overlap
                    if( !(
                        rect1.top > rect2.bottom - row_overlap_epsilon ||
                        rect1.right < rect2.left + col_overlap_epsilon ||
                        rect1.bottom < rect2.top + row_overlap_epsilon ||
                        rect1.left > rect2.right - col_overlap_epsilon
                    )){
                        overlap2 = true;
                        break;
                    }
                }
            }
            //console.log("hasError="+error_during_resize+"  overlap="+overlap+"  overlap2="+overlap2)
            if(overlap || overlap2 || error_during_resize){
                ui.helper.css("outline","solid 2px red");
                error_during_resize = true;
            }
            else{
                ui.helper.css("outline","");
            }
        },
        stop: function( event, ui ) {
            if(ui.helper.length > 0 && ui.helper.hasClass("appx-resizable-helper")){
                //helper shrinks the original element. resize it back to its original size
                ui.originalElement.css({    "width": ui.size.width,
                                            "height": ui.size.height
                                        });
            }

            //don't do resize if any error were detected during resize like out of bount, item overlap, ....
            if(error_during_resize == true ){
                appxwidgetcallback(IE_CMD_NULL);
            }
            //no error? send resize info to the engine
            else{
                try{
                    var wx = ui.originalElement.data("widget");
                    //find new pos in appx format
                    //To do that we get the difference between original position and current position, then we convert that to
                    //row and columns. And we use that to calculate the new postion
                    var deltaRow = (ui.position.top  - ui.originalPosition.top ) / appx_session.rowHeightPx;
                    var deltaCol = (ui.position.left - ui.originalPosition.left) / appx_session.colWidthPx;

                    var posNewRow = appx_session.imageEditorResizable.oldPos.row + roundTowardsZero(deltaRow);
                    var posNewCol = appx_session.imageEditorResizable.oldPos.col + roundTowardsZero(deltaCol);

                    //calculate the new position offset
                    var posRowOffset = null;
                    var posColOffset = null;
                    var deltaRowOffset = (deltaRow - roundTowardsZero(deltaRow)) * 100;
                    var deltaColOffset = (deltaCol - roundTowardsZero(deltaCol)) * 100;
                    //we need to adjust the new col offset with the original offset if it exists
                    if(deltaColOffset && deltaColOffset != 0){
                        if( wx && wx.wOffsetX != null){
                            //add the offset to the original offset. 
                            posColOffset = wx.wOffsetX + deltaColOffset;
                            //If the reuslting offset is greater than 100, add 1 to the col and deduct 100 from the offset
                            if(posColOffset >= 100 ){
                                posNewCol++;
                                posColOffset -= 100;
                            }
                            //If the reuslting offset is less than -100, deduct 1 from the col and add 100 to the offset
                            else if(posColOffset <= -100){
                                posNewCol--;
                                posColOffset += 100;
                            }
                        }
                        else{
                            posColOffset = deltaColOffset;
                        }
                    }
                    //we need to adjust the new row offset with the original offset if it exists
                    if(deltaRowOffset && deltaRowOffset != 0){
                        if( wx && wx.wOffsetY != null){
                            //add the offset to the original offset. 
                            posRowOffset = wx.wOffsetY + deltaRowOffset;
                            //If the reuslting offset is greater than 100, add 1 to the row and deduct 100 from offset
                            if(posRowOffset >= 100 ){
                                posNewRow++;
                                posRowOffset -= 100;
                            }
                            //If the reuslting offset is less than -100, deduct 1 from the row and add 100 to the offset
                            else if(posRowOffset <= -100){
                                posNewRow--;
                                posRowOffset += 100;
                            }
                        }
                        else{
                            posRowOffset = deltaRowOffset;
                        }
                    }

                    //if row/column is zero with positive offset, change the row/col to 1 and make offset negative. Appx doesn't handle row/col 0 very well
                    if(posNewRow == 0 && ( posRowOffset > 0 || (posRowOffset == null && wx && wx.wOffsetY > 0))){
                        if(posRowOffset == null && wx){
                            posRowOffset = wx.wOffsetY;
                        }
                        posNewRow = 1;
                        posRowOffset -= 100;
                    }
                    if(posNewCol == 0 && ( posColOffset> 0 || (posColOffset == null && wx && wx.wOffsetX > 0))){
                        if(posColOffset == null && wx){
                            posColOffset = wx.wOffsetX;
                        }
                        posNewCol = 1;
                        posColOffset -= 100;
                    }

                    //now calculate new size in appx format
                    //To do that we get the difference between original size and current size, then we convert that to
                    //row and columns. And we use that to calculate the new size
                    var deltaRowSize = (ui.size.height - ui.originalSize.height) / appx_session.rowHeightPx;
                    var deltaColSize = (ui.size.width  - ui.originalSize.width ) / appx_session.colWidthPx;

                    var newRowSize = appx_session.imageEditorResizable.oldSize.rows + roundTowardsZero(deltaRowSize);
                    var newColSize = appx_session.imageEditorResizable.oldSize.cols + roundTowardsZero(deltaColSize);

                    //calculate the new size offsets
                    var newRowSizeOffset = null;
                    var newColSizeOffset = null;
                    var deltaRowSizeOffset = (deltaRowSize - roundTowardsZero(deltaRowSize)) * 100;
                    var deltaColSizeOffset = (deltaColSize - roundTowardsZero(deltaColSize)) * 100;
                    //we need to adjust the new col offset with the original offset if it exists
                    if(deltaColSizeOffset && deltaColSizeOffset != 0){
                        if( wx && wx.wOffsetW != null){
                            //add the offset to the original offset. 
                            newColSizeOffset = wx.wOffsetW + deltaColSizeOffset;
                            //If the reuslting offset is greater than 100, add 1 to the col and deduct 100 from the offset
                            if(newColSizeOffset >= 100 ){
                                newColSize++;
                                newColSizeOffset -= 100;
                            }
                            //If the reuslting offset is less than -100, deduct 1 from the col and add 100 to the offset
                            else if(newColSizeOffset <= -100){
                                newColSize--;
                                newColSizeOffset += 100;
                            }
                        }
                        else{
                            newColSizeOffset = deltaColSizeOffset;
                        }
                    }
                    //we need to adjust the new row offset with the original offset if it exists
                    if(deltaRowSizeOffset && deltaRowSizeOffset != 0){
                        if( wx && wx.wOffsetH != null){
                            //add the offset to the original offset. 
                            newRowSizeOffset = wx.wOffsetH + deltaRowSizeOffset;
                            //If the reuslting offset is greater than 100, add 1 to the row and deduct 100 from offset
                            if(newRowSizeOffset >= 100 ){
                                newRowSize++;
                                newRowSizeOffset -= 100;
                            }
                            //If the reuslting offset is less than -100, deduct 1 from the row and add 100 to the offset
                            else if(newRowSizeOffset <= -100){
                                newRowSize--;
                                newRowSizeOffset += 100;
                            }
                        }
                        else{
                            newRowSizeOffset = deltaRowSizeOffset;
                        }
                    }
                    //if row/column is zero with positive offset, change the row/col to 1 and make offset negative. Appx doesn't handle row/col 0 very well
                    if(newRowSize == 0 && ( newRowSizeOffset > 0 || (newRowSizeOffset == null && wx && wx.wOffsetH > 0))){
                        if(newRowSizeOffset == null && wx){
                            newRowSizeOffset = wx.wOffsetH;
                        }
                        newRowSize = 1;
                        newRowSizeOffset -= 100;
                    }
                    if(newColSize == 0 && ( newColSizeOffset > 0 || (newColSizeOffset == null && wx && wx.wOffsetW > 0))){
                        if(newColSizeOffset == null && wx){
                            newColSizeOffset = wx.wOffsetW;
                        }
                        newColSize = 1;
                        newColSizeOffset -= 100;
                    }

                    /*console.log("resize stopped - orig size -" + JSON.stringify(appx_session.imageEditorResizable.oldSize));
                    console.log("resize stopped - orig pos  -" + JSON.stringify(appx_session.imageEditorResizable.oldPos));
                    console.log("resize stopped - new size { rows:" +newRowSize+ ", cols:"+newColSize+", rowOffset:"+newRowSizeOffset+", colOffset:"+newColSizeOffset +" }" );
                    console.log("resize stopped - new pos  { row:" +posNewRow+ ", col:"+posNewCol+", rowOffset:"+posRowOffset+", colOffset:"+posColOffset +" }" );*/

                    appxImageEditor_update_new_location(ui.originalElement, posNewRow, posNewCol);
                    appxPutCursor(posNewCol, posNewRow);

                    //Now that we gathered all necessary info, send the resize info to the engine and ask it to resize the element
                    imageEditor_resize_item_prep(ui.originalElement, newRowSize, newColSize, newRowSizeOffset, newColSizeOffset, posNewRow, posNewCol, posRowOffset, posColOffset);
                    /*apply the Move changes*/
                    appxwidgetcallback(IE_CMD_DO_MOVE);
                }//end try
                catch(e){
                    console.log("imageEditor_resize_stop: Couldn't resize the element " + e);
                    console.log(e.stack);
                }

            }
        }//end stop

    });
}

/*
** This function makes the selected element non-resizable
*/
function imageEditor_remove_resizable($tag){
    if($tag.hasClass("appx_ie_resizable")){
        $tag.removeClass("appx_ie_resizable");
        $tag.resizable("destroy");
    }
}

/*
** this function removes resizability from all resizable items
*/
function imageEditor_remove_all_resizable(){
    $(".appx_ie_resizable").each( function (){
        imageEditor_remove_resizable($(this));
    });
}

/*
** This function creates a new popup menu item object
*/
function imageEditor_create_popupMenuItem(label, shortcut, command, icon, disabled){
    var item = {};
    item.name = label;
    if(icon){
        item.icon = function(opt, $itemElement, itemKey, item){
            $itemElement.css({ "background-image": "url(" + icon + ")",
                               "background-repeat": "no-repeat",
                               "background-size": "contain"
                            });
        }
    }
    if(command){
        item.callback = function(itemKey, Opt, OriginalEvent){
            imageEditor_performAction(command);
        }
    }
    if(disabled == true){
        item.disable = disabled; //this is an added property and is not part of the api
    }
    
    item.disabled = function(itemKey, opt){
        if( appx_session.imageEditor_popupMenuItems && 
            appx_session.imageEditor_popupMenuItems[itemKey] && 
            appx_session.imageEditor_popupMenuItems[itemKey].disable == true){
                return true
            }
            return false
    }
    
    if(shortcut){
        item.accesskey = shortcut;
    }
    return item;
}

/*
** create image editor's specific popup menu items
** appxprepscreen function uses these items to create the popup menu
*/
function imageEditor_create_popupMenu(){

			var popupMenuItems = {};
			popupMenuItems.popupDel          = imageEditor_create_popupMenuItem( "Delete", 'd',  OPT_DELETE, IMAGEEDITOR_ICON_DELETE, false);
			popupMenuItems.popupCut          = imageEditor_create_popupMenuItem( "Cut",    'x',  OPT_CUT,    IMAGEEDITOR_ICON_CUT   , false);
			popupMenuItems.popupCopy         = imageEditor_create_popupMenuItem( "Copy",   'C',  OPT_COPY,   IMAGEEDITOR_ICON_COPY  , false);
			popupMenuItems.popupPaste        = imageEditor_create_popupMenuItem( "Paste",  'P',  OPT_PASTE,  IMAGEEDITOR_ICON_PASTE , false);
			popupMenuItems.sep1              = "----------";
			popupMenuItems.popupObjProps     = imageEditor_create_popupMenuItem( "Object Properties", 'O', OPT_OBJECT_PROPS,  IMAGEEDITOR_ICON_OBJECT_PROPERTIES , false);
			popupMenuItems.popupWinProps     = imageEditor_create_popupMenuItem( "Window Properties", 'W', OPT_WINDOW_PROPS,  IMAGEEDITOR_ICON_WINDOW_PROPERTIES , false);
			popupMenuItems.sep2              = "----------";
			popupMenuItems.popupAlignTop     = imageEditor_create_popupMenuItem( "Align Tops",        'T', OPT_ALIGN_TOP,   IMAGEEDITOR_ICON_ALIGN_TOP      , false);
			popupMenuItems.popupAlignBottom  = imageEditor_create_popupMenuItem( "Align Bottoms",     'B', OPT_ALIGN_BOTTOM,IMAGEEDITOR_ICON_ALIGN_BOTTOM   , false);
			popupMenuItems.popupAlignLeft    = imageEditor_create_popupMenuItem( "Align Left sides",  'L', OPT_ALIGN_LEFT,  IMAGEEDITOR_ICON_ALIGN_LEFT     , false);
			popupMenuItems.popupAlignRight   = imageEditor_create_popupMenuItem( "Align Right sides", 'R', OPT_ALIGN_RIGHT, IMAGEEDITOR_ICON_ALIGN_RIGHT    , false);
			popupMenuItems.sep3              = "----------";
			popupMenuItems.popupSameSizeVert = imageEditor_create_popupMenuItem( "Make same size (vertical)",   'v', OPT_SAME_SIZE_VERT,    IMAGEEDITOR_ICON_SAME_SIZE_VERT , false);
			popupMenuItems.popupSameSizeHorz = imageEditor_create_popupMenuItem( "Make same size (horizontal)", 'h', OPT_SAME_SIZE_HORIZ,   IMAGEEDITOR_ICON_SAME_SIZE_HORIZ, false);
			popupMenuItems.popupSpreadVert   = imageEditor_create_popupMenuItem( "Spread vertical space",       'e', OPT_SPREAD_VERT,       IMAGEEDITOR_ICON_SPREAD_VERT    , false);
			popupMenuItems.popupSpreadHorz   = imageEditor_create_popupMenuItem( "Spread horizontal space",     'S', OPT_SPREAD_HORIZ,      IMAGEEDITOR_ICON_SPREAD_HORIZ   , false);
			popupMenuItems.sep4              = "----------";

			popupMenuItems.popupNewGuideVert = imageEditor_create_popupMenuItem( "New Vertical Guide",   'v', OPT_NEW_GUIDE_VERT,  null , false);
			popupMenuItems.popupNewGuideHorz = imageEditor_create_popupMenuItem( "New Horizontal Guide", 'h', OPT_NEW_GUIDE_HORIZ, null , false);
			popupMenuItems.sep5              = "----------";

            popupMenuItems.popupMultiWidgetEditor = imageEditor_create_popupMenuItem( "Multi Object Properties", 'M', OPT_MULTI_WIDGET,  IMAGEEDITOR_ICON_MULTI_OBJ_PROPS , false);
            popupMenuItems.sep6              = "----------";             
            popupMenuItems.popupOptionNumbers= imageEditor_create_popupMenuItem( "Toggle Option Numbers", 'N', OPT_SHOW_OPT_NUMS,  null , false);

            appx_session.imageEditor_popupMenuItems = popupMenuItems;
}

/*This function enables and disables popup menu items based on the state of the image editor*/
function imageEditor_updatePopupMenu(){
    var selectedItemCount = appx_session.imageEditorSelectedItems? appx_session.imageEditorSelectedItems.length: 0;
    //first make everything enables
    var items = appx_session.imageEditor_popupMenuItems;
    for (var keys in items) {
        if(typeof items[keys] != "string"){ //exclude separators
            items[keys].disable = false;
        }
    }

    //No item is selected
    if(selectedItemCount <= 0){
        items.popupDel.disable =  true;
        items.popupCut.disable =  true;
        items.popupCopy.disable =  true;
        items.popupObjProps.disable =  true;
    }
    //at least one item is selected
    else{
        items.popupPaste.disable =  true;
        items.popupObjProps.disable =  (selectedItemCount != 1); //only enable obj prop when 1 item is selected
    }
    //less than 2 items are selected
    if(selectedItemCount < 2){
        items.popupAlignTop.disable =  true;
        items.popupAlignBottom.disable =  true;
        items.popupAlignLeft.disable =  true;
        items.popupAlignRight.disable =  true;
        items.popupSameSizeVert.disable =  true;
        items.popupSameSizeHorz.disable =  true;
    }
    //less than 3 items are selected
    if(selectedItemCount < 3){
        items.popupSpreadVert.disable =  true;
        items.popupSpreadHorz.disable =  true;
    }   
}

/*This function runs before the popup menu shows*/
function imageEditor_popupMenu_preshow_event($item, event){
    //if we are on a modifiable rowtext don't display this contect menu and dislay the default popup menu
    /*When we return false, the event propagates to the imageEditor box. We need to detect if the right click 
      happened on the imageEditor box or it propagated down. We do that by checking event.target. If the target
      is the rowtext, then we return false again so the default browser menu pops up*/
    if($item.hasClass("appx_ie_rowtext_enabled") || $(event.target).hasClass("appx_ie_rowtext_enabled") ){
        return false;
    }
    //if we are on a widget and the widget is not selected, unselect all and select this widget
    if($item.hasClass("appx_ie_widget") && !$item.hasClass("appx_ie_selected")){
        appxImageEditor_unselectRowtext();//unselect active rowtext
        appxImageEditor_unselectAllItems();
        appxImageEditor_selectItem($item, true);  
    }
    //if rightclick happens on an unselected rowtext or imageEditor box, unselect everything
    if($item.hasClass("appx_ie_rowtext") || $item.hasClass("appxImageEditor")){
        appxImageEditor_unselectRowtext();//unselect active rowtext
        appxImageEditor_unselectAllItems();
    }
    var loc = imageEditor_offset_to_location(event.pageX, event.pageY);
    if(loc.row && loc.col){
        appxPutCursor( loc.col, loc.row );
    }
}

/*
** Create ImageEditor toolbar
*/
function imageEditor_create_toolbar(){
    $("#toolbar").empty();
    $("#toolbar").append( imageEditor_create_toolbarButton("Save&Exit", "Save & Exit (ESC)", IMAGEEDITOR_ICON_SAVE_EXIT,      OPT_END,         "appx_ie_toolbar_end",     false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Cancel",    "Cancel (Ctrl+F8)" , IMAGEEDITOR_ICON_CANCEL,         OPT_CAN,         "appx_ie_toolbar_cancel",  false, true ) );

    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Select",   "Select a region"  , IMAGEEDITOR_ICON_SELECT_REGION,  OPT_ARROW_TOOL,  "appx_ie_toolbar_arrow",   false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Button",   "Paint a button"   , IMAGEEDITOR_ICON_PAINT_BUTTON,   OPT_BUTTON_TOOL, "appx_ie_toolbar_button",  false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Label",    "Paint a label"    , IMAGEEDITOR_ICON_PAINT_LABEL,    OPT_LABEL_TOOL,  "appx_ie_toolbar_label",   false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Picture",  "Paint a picture"  , IMAGEEDITOR_ICON_PAINT_IMAGE,    OPT_PICTURE_TOOL,"appx_ie_toolbar_image",   false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Box",      "Paint a box"      , IMAGEEDITOR_ICON_PAINT_BOX,      OPT_BOX_TOOL,    "appx_ie_toolbar_box",     false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Line",     "Paint a line"     , IMAGEEDITOR_ICON_PAINT_LINE,     OPT_LINE_TOOL,   "appx_ie_toolbar_line",    false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton("ie_control_grp",  "Table",    "Paint a table"    , IMAGEEDITOR_ICON_PAINT_TABLE,    OPT_TABLE_TOOL,  "appx_ie_toolbar_table",   false, true) );
    
    $("#toolbar").append( imageEditor_create_toolbarButton("Field",        "Add a Field (F9)",                  IMAGEEDITOR_ICON_PAINT_FIELD,   OPT_ADD_MODE,      "appx_ie_toolbar_field",    false, true ) );

    $("#toolbar").append( imageEditor_create_toolbarToggleButton(null,  "Bounds",   "Show Object Bounds",       IMAGEEDITOR_ICON_SHOW_BOUNDS,   OPT_SHOW_BOUNDS,   "appx_ie_toolbar_bounds",  false, false) );
    $("#toolbar").append( imageEditor_create_toolbarToggleButton(null,  "Grid",     "Show Grid",                IMAGEEDITOR_ICON_SHOW_GRID,     OPT_SHOW_GRIDLINES,"appx_ie_toolbar_grid",    false, true ) );
    /*not supported on html client
    $("#toolbar").append( imageEditor_create_toolbarToggleButton(null,  "GUI Off",  "Show Character Interface", IMAGEEDITOR_ICON_SHOW_CHAR_UI,  OPT_GUI_INTERFACE, "appx_ie_toolbar_gui",     false, false) );*/
    /*not supported on html client
    $("#toolbar").append( imageEditor_create_toolbarButton("Data Palette","Data Palette (Not Implemented)",  IMAGEEDITOR_ICON_DATA_PALETTE,  OPT_DATA_PALETTE,  "appx_ie_toolbar_palette",  false, false) );
    */
    $("#toolbar").append( imageEditor_create_toolbarButton("Cut",           "Cut selection (Ctrl+X)",            IMAGEEDITOR_ICON_CUT,               OPT_CUT,            "appx_ie_toolbar_cut",          false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Copy",          "Copy selection (Ctrl+C)",           IMAGEEDITOR_ICON_COPY,              OPT_COPY,           "appx_ie_toolbar_copy",         false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Delete",        "Delete selection (DEL)",            IMAGEEDITOR_ICON_DELETE,            OPT_DELETE,         "appx_ie_toolbar_delete",       false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Paste",         "Paste selection (Ctrl+V)",          IMAGEEDITOR_ICON_PASTE,             OPT_PASTE,          "appx_ie_toolbar_paste",        false, true ) );
    
    $("#toolbar").append( imageEditor_create_toolbarButton("Win Prop",      "Edit Windows Properties",           IMAGEEDITOR_ICON_WINDOW_PROPERTIES, OPT_WINDOW_PROPS,   "appx_ie_toolbar_winProp",      false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Obj Prop",      "Edit Object Properties (F12)",      IMAGEEDITOR_ICON_OBJECT_PROPERTIES, OPT_OBJECT_PROPS,   "appx_ie_toolbar_prop",         false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("MObj Prop",     "Multi Object Properties",           IMAGEEDITOR_ICON_MULTI_OBJ_PROPS,   OPT_MULTI_WIDGET,   "appx_ie_toolbar_multiWidget",  false, true ) );

    $("#toolbar").append( imageEditor_create_toolbarButton("Align Top",     "Align Tops (Alt+Up)",               IMAGEEDITOR_ICON_ALIGN_TOP,         OPT_ALIGN_TOP,      "appx_ie_toolbar_alignTop",     false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Align Bottom",  "Align Bottoms (Alt+Down)",          IMAGEEDITOR_ICON_ALIGN_BOTTOM,      OPT_ALIGN_BOTTOM,   "appx_ie_toolbar_alignBot",     false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Align Left",    "Align Left Sides (Alt+Left)",       IMAGEEDITOR_ICON_ALIGN_LEFT,        OPT_ALIGN_LEFT,     "appx_ie_toolbar_alignLeft",    false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Align Top",     "Align Right Sides (Alt+Right)",     IMAGEEDITOR_ICON_ALIGN_RIGHT,       OPT_ALIGN_RIGHT,    "appx_ie_toolbar_alignRight",   false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Same Height",   "Make same vertical size (Alt+=)",   IMAGEEDITOR_ICON_SAME_SIZE_VERT,    OPT_SAME_SIZE_VERT, "appx_ie_toolbar_sameVert",     false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Same Width",    "Make same horizontal size (Alt+\\)",IMAGEEDITOR_ICON_SAME_SIZE_HORIZ,   OPT_SAME_SIZE_HORIZ,"appx_ie_toolbar_sameHoriz",    false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Spread Vert",   "Spread vertical space",             IMAGEEDITOR_ICON_SPREAD_VERT,       OPT_SPREAD_VERT,    "appx_ie_toolbar_spreadVert",   false, false) );
    $("#toolbar").append( imageEditor_create_toolbarButton("Spread Hori",   "Spread hotizontal space",           IMAGEEDITOR_ICON_SPREAD_HORIZ,      OPT_SPREAD_HORIZ,   "appx_ie_toolbar_spreadHoriz",  false, true ) );

    $("#toolbar").append( imageEditor_create_toolbarButton("Toolbox",       "Toolbox (OPT+0)",                   IMAGEEDITOR_ICON_TOOLBOX,           OPT_TOOLBOX,        "appx_ie_toolbar_toolbox",      false, false) );


    //set lasso as default selected when lasso is implemented
    if(!appx_session.imageEditor_selected_control){
        appx_session.imageEditor_selected_control = OPT_ARROW_TOOL;
    }
    imageEditor_toolbarButton_toggle_control(appx_session.imageEditor_selected_control);


    //set showgrid based on user's preferences when grid is implamented
    if(appx_session.getProp("showGridlines") == true){
        $("#toolbar #"+OPT_SHOW_GRIDLINES).addClass("down");
    }
    //reselect show_bounds button
    //show bound is session dependent and is not stored on disk
    if(appx_session.imageEditor_show_bound == true){
        $("#toolbar #"+OPT_SHOW_BOUNDS).addClass("down");
    }

    //enable and disable buttons
    imageEditor_updateToolbar();

}
function imageEditor_create_toolbarButton(label, tooltip, icon, option_no, buttonClass, sep_before, sep_after){ 
    var item = $('<div>');
    //add seperators
    if (sep_before && sep_after) {
        item.addClass("appx-sep-before appx-sep-after");
    } else if (sep_before) {
        item.addClass("appx-sep-before");
    } else if (sep_after) {
        item.addClass("appx-sep-after");
    }
    /*don't do this for image editor*/
    /*assign button label if exists
    if (label && label.trim().length > 0) {
        item.html('<span class="appx-toolbar-label">' + label + '</span>');
    }*/
    //assign classes
    item.addClass("appxitem"); //item
    item.addClass("toolbaritem imageEditorToolbarButton");
    if(buttonClass){
        item.addClass(buttonClass);
    }
    //add icon
    if(icon){
        item.css("background-image", "url('" + icon + "')");
    }
    
    //always start with buttons as disabled, later on enable them via update toolbar
    item.addClass("tbdisabled");

    //add option no as id, This may not be a good idea, but we stick to it because it is how normal toolbar handles the buttons
    item.attr("id", option_no);
    
    if (tooltip) {
        item.prop('title', tooltip);
        item.tooltip({
            content: function tooltipCallback() {
                if (typeof this.title == 'function')
                    return this.title();
                else
                    return '';
            }
        });
    }
    return(item);
}
function imageEditor_create_toolbarToggleButton(toggleGroup, label, tooltip, icon, option_no, buttonClass, sep_before, sep_after){ 
    var item = $('<div>');
    //add seperators
    if (sep_before && sep_after) {
        item.addClass("appx-sep-before appx-sep-after");
    } else if (sep_before) {
        item.addClass("appx-sep-before");
    } else if (sep_after) {
        item.addClass("appx-sep-after");
    }
    /*don't do this for image editor*/
    /*assign button label if exists
    if (label && label.trim().length > 0) {
        item.html('<span class="appx-toolbar-label">' + label + '</span>');
    }*/
    //assign classes
    item.addClass("appxitem"); //item
    item.addClass("toolbaritem imageEditorToolbarToggleButton");
    if(buttonClass){
        item.addClass(buttonClass);
    }
    //add icon
    if(icon){
        item.css("background-image", "url('" + icon + "')");
    }
    
    //always start with buttons as disabled, later on enable them via update toolbar
    item.addClass("tbdisabled");

    //add option no as id, This may not be a good idea, but we stick to it because it is how normal toolbar handles the buttons
    item.attr("id", option_no);

    //assign toggle group
    item.data("toggleGroup", toggleGroup);
    item.addClass(toggleGroup);
    
    if (tooltip) {
        item.prop('title', tooltip);
        item.tooltip({
            content: function tooltipCallback() {
                if (typeof this.title == 'function')
                    return this.title();
                else
                    return '';
            }
        });
    }
    return(item);
}

/*Enables or disables toolbar butons based on the selected items*/
function imageEditor_updateToolbar()
{ 
    
    var selectedItemCount = appx_session.imageEditorSelectedItems? appx_session.imageEditorSelectedItems.length: 0;
    
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_end"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_cancel"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_arrow"), true);

    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_button"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_label"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_image"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_box"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_line"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_table"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_field"), true);

    //Leave the following disbaled since they are not implemented
    //imageEditor_toolbarButton_setEnabled($("#toolbar.appx_ie_toolbar_palette"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_gui"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_bounds"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_grid"), true);

    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_cut"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_copy"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_delete"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_paste"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_winProp"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_prop"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_multiWidget"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignTop"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignBot"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignLeft"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignRight"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameVert"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameHoriz"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadHoriz"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadVert"), true);
    imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_toolbox"), true);

    if( selectedItemCount == 0 )
    {
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_cut"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_copy"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_delete"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_prop"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignTop"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignBot"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignLeft"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignRight"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameVert"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameHoriz"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadHoriz"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadVert"), false);
    }
    else if( selectedItemCount == 1 )
    {
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_paste"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignTop"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignBot"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignLeft"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_alignRight"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameVert"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_sameHoriz"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadHoriz"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadVert"), false);
    }
    else if( selectedItemCount == 2 )
    {
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_paste"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_prop"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadHoriz"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_spreadVert"), false);
    }
    else
    {
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_paste"), false);
        imageEditor_toolbarButton_setEnabled($("#toolbar .appx_ie_toolbar_prop"), false);
    }

    /*update popup menu items as well*/
    imageEditor_updatePopupMenu();
}

function imageEditor_toolbarButton_setEnabled(button, enabled){
    //if button doesn't exist, return
    if(!button){
        return;
    }
    button.off('click');//remove any existing click listener
    if(enabled)
    {
        button.on('click', function $_clickCallback() {
            var toggleGroup = $(this).data("toggleGroup");
            //if it is a toggle button
            if($(this).hasClass("imageEditorToolbarToggleButton")){
                if($(this).hasClass("down")){
                    //if toggle_group doesn't exist, unselect; otherwise don't do anything
                    if(toggleGroup){
                        return;
                    }
                    else{
                        $(this).removeClass("down");
                        imageEditor_performAction(this.id);
                    }
                    
                }
                //the curent item is not selected, unselect all the other buttons in the group and select this one.
                else{
                    $("#toolbar .imageEditorToolbarToggleButton."+toggleGroup).removeClass("down");
                    $(this).addClass("down");
                    //if this button is part of the control buttons, store it
                    if($(this).is(".imageEditorToolbarToggleButton.ie_control_grp")){
                        appx_session.imageEditor_selected_control = $(this).attr('id');
                    }
                    imageEditor_performAction(this.id);
                }
            }
            //not a toggle button
            else{
                imageEditor_performAction(this.id);
            }
        });
        button.removeClass('tbdisabled');
    }
    else{
        button.addClass('tbdisabled');
    }
}

/*
** This function toggles the toolbar control button that has the give option (id) number
** if we couldn't find the button, we default it to select
*/ 
function imageEditor_toolbarButton_toggle_control(control_opt){
    //unselect current selected item first
    $("#toolbar .imageEditorToolbarToggleButton.ie_control_grp").removeClass("down");
    //select the appropriate button
    if(control_opt>=0){
        var button = $("#toolbar #"+control_opt+".ie_control_grp");
        if(button.length == 1){
            button.addClass("down");
        }
        //if we didn't find the button, default it to select button
        else{
            $("#toolbar appx_ie_toolbar_arrow").addClass("down");
        }

    }
    //no control is provided? default to select
    else{
        $("#toolbar appx_ie_toolbar_arrow").addClass("down");
    }
}

    /* ////////////////////////////////////////////////////////////////////////////////////////
    imageEditor_performAction( action, location{row:r,col:c} )

    Description:
            This method will perform a given operation.  Most operations are performed on a 
            set of selected objects (the selectState), so we just ask the selectState to 
            actually carry out the operation.

    Input:
            action	- desired operation (one of the ImgEditorPane.OPC_* constants)
            location- if non-null, represents the point at which the action should occur
    */
	
function imageEditor_performAction( action, location )
{
    appxImageEditor_unselectRowtext();//unselect active rowtext
    //convert to number
    action = parseInt(action);
    switch( action )
    {
        case OPT_WINDOW_PROPS:
            appxwidgetcallback( 21 ); //send option 21 USER_21
            break;

        case OPT_OBJECT_PROPS:
            /*Make sure only one widget is selected and move the cursor to that widget*/
            if(appx_session.imageEditorSelectedItems.length == 1)
            {
                var row = appx_session.imageEditorSelectedItems[0].originalRow;
                var col = appx_session.imageEditorSelectedItems[0].originalCol;
                appxPutCursor( col, row );
                appxwidgetcallback( OPT_CHG_MODE );
            }			
            break;
        
        case OPT_SHOW_GRIDLINES:
            /*toggle the grid line*/
            if(appx_session.getProp("showGridlines") == true){
                appx_session.setProp("showGridlines", "false");
                imageEditor_update_gridlines(false);
            }
            else{
                appx_session.setProp("showGridlines", "true");
                imageEditor_update_gridlines(true);
            }
            
            break;

        case OPT_SHOW_BOUNDS:
            /*toggle the show bound*/
            if(appx_session.imageEditor_show_bound == true){
                appx_session.imageEditor_show_bound = false;
            }
            else{
                appx_session.imageEditor_show_bound = true;
            }
            //update the screen
            imageEditor_update_showBounds(appx_session.imageEditor_show_bound);   
            break;
        
        case OPT_CUT:
            // The user selected the Cut option - cut all selections (if any)
            imageEditor_cut_selected();
            break;			

        case OPT_DELETE:
            // The user selected the Delete option - delete all selections (if any)
            imageEditor_delete_selected();
            break;			
        
        case OPT_COPY:
            // The user selected the Copy option - tell the server to copy all
            // selections (if any)
            imageEditor_copy_selected();
            break;		
    
        case OPT_PASTE:
            //  The user selected the Paste option - if there are any selections,
            //	we want to delete (not cut) those objects, and then tell the server
            //	to paste into that space.
            //
            //  If there are no selections, we paste at the given location.
            //
            //  TODO:  Implement the "paste over current selections" part of this operation.  
            
            imageEditor_paste();
            break;

        case OPT_ADD_MODE:
            appxwidgetcallback( OPT_ADD_MODE );
            break;

        case OPT_ALIGN_TOP:
            imageEditor_align_selected( "TOP" );
            break;

        case OPT_ALIGN_BOTTOM:
            imageEditor_align_selected( "BOTTOM" );
            break;

        case OPT_ALIGN_LEFT:
            imageEditor_align_selected( "LEFT" );
            break;

        case OPT_ALIGN_RIGHT:
            imageEditor_align_selected( "RIGHT" );
            break;

        case OPT_SAME_SIZE_VERT:
            imageEditor_resize_selected( "HEIGHT" );
            break;
        
        case OPT_SAME_SIZE_HORIZ:
            imageEditor_resize_selected( "WIDTH" );
            break;
       
        case OPT_SPREAD_HORIZ:
            imageEditor_spread_horizontally();
            break;

        case OPT_SPREAD_VERT:
            imageEditor_spread_vertically();
            break;

        case OPT_NEW_GUIDE_VERT:
            var cur = appxGetCursorPos();
            appxImageEditor_addGuideBar("VERTICAL", cur.col * appx_session.colWidthPx);
            break;
        
        case OPT_NEW_GUIDE_HORIZ:
            var cur = appxGetCursorPos();
            appxImageEditor_addGuideBar("HORIZONTAL", cur.row * appx_session.rowHeightPx);
            break;
        
        case OPT_MULTI_WIDGET:
            //  The user selected the Multi-Widget Properties option. Copy selected widgets to buffer, then call engine to invoke consolidated input process
            imageEditor_multi_widget_editor();
            break;
            
        case OPT_TOOLBOX:
            imageEditor_toolbox();
            break;
        case OPT_END:
            imageEditor_save_exit_prep();
            appxwidgetcallback( action );
            break;
        case OPT_CAN:
            imageEditor_cancel_prep();
            appxwidgetcallback( action );
            break;
        case OPT_BUTTON_TOOL:
        case OPT_LABEL_TOOL:
        case OPT_BOX_TOOL:
        case OPT_PICTURE_TOOL:
        case OPT_LINE_TOOL:
        case OPT_TABLE_TOOL:
        case OPT_ARROW_TOOL:
            /*we handle these in imageEditor_applyTool function*/
            break;
        default:
            console.log("invalid or unimplemented imageEditor toolbar action - "+ action);

    }	

    //  We have changed the client-side selections, now go
    //	apply those changes to the server.
            
    //applyChanges();

}

/*//////////////////////////////////////////////////////////////////////////////////////
    Name: applyTool

    Description:
        This method will apply a toolbar tool to the lasso-rectangle.  Basically, we
        send the lasso-rectangle to the server (so that the server knows the screen
        real-estate we want to affect), then we send an option number to tell the 
        server what to do with that real-estate.
        This takes care of adding the following widgets to the screen:
            BUTTON, LABEL, BOX, PICTURE, TABLE, LINE

    Input:
        pointStart, pointEnd	- screen real-estate selected by the user -- point* = {x,y}. This position should be relative to imageeditor box.
        cmd		- a handy reference to an MGuiEditCmd object - we only create one
                    of these objects and keep it around forever so we don't have to
                    create one each time we need it.
*/

function imageEditor_applyTool( pointStart, pointEnd )
{
    //  The user has indicated a rectangle and wants us to apply 
    //  one of the tools to that rectangle.  The tools are things
    //	like "make a button which covers this rectangle", "make a
    //	label which covers this rectangle", etc.  We will send 
    //	the rectangle to the server, then send a command which 
    //	corresponds to the currently selected tool.
    //
    //  First, send the selected rectangle
        
    var guiCmd = initGuiEditCmd(); //create and init guiEditCmd struct

    guiCmd.cmd     = IE_CMD_DEFER;
    guiCmd.subCmd  = IE_SUB_CMD_SELECTION;

    guiCmd.posNewRow = Math.floor(pointStart.y/appx_session.rowHeightPx);
    guiCmd.posNewCol = Math.floor(pointStart.x/appx_session.colWidthPx);

    guiCmd.sizeRows  = Math.floor(pointEnd.y/appx_session.rowHeightPx) - guiCmd.posNewRow;
    guiCmd.sizeCols  = Math.floor(pointEnd.x/appx_session.colWidthPx ) - guiCmd.posNewCol;

    guiCmd.posNewRowOffset = Math.round((pointStart.y - (guiCmd.posNewRow * appx_session.rowHeightPx)) *  100 / appx_session.rowHeightPx );
    guiCmd.posNewColOffset = Math.round((pointStart.x - (guiCmd.posNewCol * appx_session.colWidthPx )) *  100 / appx_session.colWidthPx );

    guiCmd.sizeRowsOffset  = Math.round((Math.abs(pointEnd.y - pointStart.y) - Math.abs(guiCmd.sizeRows * appx_session.rowHeightPx)) * 100 / appx_session.rowHeightPx );
    guiCmd.sizeColsOffset  = Math.round((Math.abs(pointEnd.x - pointStart.x) - Math.abs(guiCmd.sizeCols * appx_session.colWidthPx )) * 100 / appx_session.colWidthPx  );

    var currentTool = appx_session.imageEditor_selected_control;

    if( currentTool == OPT_LINE_TOOL )
    {
        guiCmd.sizeRows += guiCmd.sizeRows >= 0 ? 1 : -1;
        guiCmd.sizeCols += guiCmd.sizeCols >= 0 ? 1 : -1;
    }
    
    //send the selected portion of the screen
    sendGuiEditCmd(guiCmd);

    //  Then, send an option number which corresponds to the selected tool
    if( currentTool == OPT_BUTTON_TOOL )
        appxwidgetcallback( IE_CMD_DO_BUTTON );
    else if( currentTool == OPT_LABEL_TOOL )
        appxwidgetcallback( IE_CMD_DO_LABEL );
    else if( currentTool == OPT_PICTURE_TOOL )
        appxwidgetcallback( IE_CMD_DO_IMAGE );
    else if( currentTool == OPT_BOX_TOOL )
        appxwidgetcallback( IE_CMD_DO_BOX );
    else if( currentTool == OPT_LINE_TOOL )
        appxwidgetcallback( IE_CMD_DO_LINE );
    else if( currentTool == OPT_TABLE_TOOL )
        appxwidgetcallback( IE_CMD_DO_TABLE );
                        
}

/*
** This function runs when lasso is stopped.
** lasso = {startX, startY, stopX, stopY, lastEvent}
**/
function imageEditor_process_lasso(lasso){
    if(appx_session.imageEditor_selected_control == OPT_ARROW_TOOL){
        //select items
        var rect =  {};
        var fullyBounded = true;
        if(lasso.startX > lasso.stopX){
            rect.left = lasso.stopX;
            rect.right = lasso.startX;
            fullyBounded = false;
        }
        else{
            rect.left = lasso.startX;
            rect.right = lasso.stopX;
        }
        if(lasso.startY > lasso.stopY){
            rect.top = lasso.stopY;
            rect.bottom = lasso.startY;
            fullyBounded = false;
        }
        else{
            rect.top = lasso.startY;
            rect.bottom = lasso.stopY;
        }
        //rect numbers are relative to image. We need the client numbers so we can compare the numbers with items numbers easily
        var box_loc = $(lasso.lastEvent.currentTarget).offset();
        rect.top    += box_loc.top;
        rect.bottom += box_loc.top;
        rect.left   += box_loc.left;
        rect.right  += box_loc.left;
        //now select the items
        appxImageEditor_selectItems_lasso(rect, fullyBounded, lasso.lastEvent.ctrlKey)
    }
    else{
        //create widget
        var pointStart ={   'x':lasso.startX, 
                            'y':lasso.startY
                        };
        var pointEnd =  {   'x':lasso.stopX, 
                            'y':lasso.stopY
                        };
        imageEditor_applyTool( pointStart, pointEnd);
    }
    //now change the tool back to arrrow (selection)
    appx_session.imageEditor_selected_control = OPT_ARROW_TOOL;
}

/*we setup mouse events and other events for imageeditor box in here*/
function imageEditor_event_setup($boxhtml){
        //add mouse location to status bar
    $boxhtml.on("mousemove", function(event){
        var box_loc = $(this).offset();
        var row = event.pageY - box_loc.top - parseInt($(this).css("border-top-width"));
        row = Math.floor(row/appx_session.rowHeightPx);
        var col = event.pageX - box_loc.left - parseInt($(this).css("border-left-width"));
        col = Math.floor(col/appx_session.colWidthPx);
        // If mouse is down we are dragging. In this case, set isDragging to yes and create a rectangle on the screen
        if(appx_session.lasso && appx_session.lasso.isDown){
            appx_session.lasso.isDragging = true;
            appx_session.lasso.lastEvent = event;
            imageEditor_create_lasso_rectangle(appx_session.lasso.startX, appx_session.lasso.startY, event.pageX - box_loc.left, event.pageY - box_loc.top );
        }
        
        /*now show it in appx_mouse_loc tag. If it doesn't exist add it*/
        if($("#appx_mouse_loc").length <= 0 ){
            $("<span id='appx_mouse_loc'></span>").insertAfter("#appx_status_date");
        }
        $("#appx_mouse_loc").html("x=" + col+", y="+row);
    });
    /* select and unselect event
    ** We want to unselect the selected item if user clicks outside of an item
    */
    $boxhtml.on("click", function(event){
        //if we are comming here after lasso, we want to ignore this event
        if(appx_session.lasso && appx_session.lasso.ignoreClickEvent && appx_session.lasso.ignoreClickEvent == true){
            appx_session.lasso.ignoreClickEvent = false;
            return;
        }
        //If we are resizing an element, ignore click
        if(appx_session.imageEditorResizable && appx_session.imageEditorResizable.ignoreClickEvent == true){
            appx_session.imageEditorResizable.ignoreClickEvent = false;
            return;
        }

        if(event.ctrlKey == true  || event.metaKey == true){
        //don't do anything if ctrl is down, user probably miss-clicked
        }
        else{
            //remove all selected items
            appxImageEditor_unselectAllItems();
            appxImageEditor_unselectRowtext();//unselect active rowtext
            var loc = imageEditor_offset_to_location(event.pageX, event.pageY);
            if(loc.row && loc.col){
                appxPutCursor( loc.col, loc.row );
            }
        }
    });

    /*Lasso*
    ** This is a combination of 3 events: Mousedown, mousemove, and mouseup
    */
    $boxhtml.on("mousedown", function(event){
        //check if the mouse down happend on a widget and then propagated down to here. In this case 
        //ignore the event. We cannot stop the propagation at the widget because it breaks the draggable
        //api on the widget. So, work around it here.
        //also consider resizable. When resizing we don't want to fire lasso select
        if( $(event.target).closest(".appx_ie_widget").length == 0 && //not moving an element
            $(event.target).closest(".ui-resizable-handle").length == 0 && //not resizing an element
            $(event.target).closest(".appx-horizontal-guide-bar,.appx-vertical-guide-bar").length == 0) //not moving the guidebars
            {
                var box_loc = $(this).offset();
                appx_session.lasso ={  "isDragging": false,
                                        "isDown": true,
                                        "startX": event.pageX - box_loc.left,
                                        "startY": event.pageY - box_loc.top,
                                        "lastEvent": event
                                    };
            }
    });
    $boxhtml.on("mouseup", function(event){
        if(appx_session.lasso && appx_session.lasso.isDragging) {
            var box_loc = $(this).offset();
            appx_session.lasso.isDragging = false;
            appx_session.lasso.isDown = false;
            appx_session.lasso.stopX = event.pageX - box_loc.left;
            appx_session.lasso.stopY = event.pageY - box_loc.top;
            appx_session.lasso.lastEvent = event;
            imageEditor_process_lasso(appx_session.lasso);
            imageEditor_hide_lasso_rectangle();
            imageEditor_hide_lasso_line();
            //if we are lassoing, we want the click event that happens after mouse up to be ignored
            //we set this flag here to tell click event to cancel itself
            appx_session.lasso.ignoreClickEvent = true; 
        }
        else if(appx_session.lasso){
            //reset the isDown flags
            appx_session.lasso.isDown = false;
        }
    });

    /*We need to intercept some of the keys that has special meaning in Image Editor*/
    $boxhtml.on("keydown", function(event){
        imageEditor_keydown_event(event);
    });
}

/*keyboard events for image editor*/
function imageEditor_keydown_event(event){
    if (appxIsLocked()) {
        event.preventDefault();
        event.stopPropagation();
        return;
    }
    /*Ctrl-c, Ctrl-x, Ctrl-v for cut, copy, and paste*/
    if(event.ctrlKey == true || event.metaKey == true){
        //ctrl-c
        if(event.which == 67){
            event.stopPropagation();
            imageEditor_copy_selected();
        }
        //Ctrl-v
        else if(event.which == 86){
            event.stopPropagation();
            imageEditor_paste();
        }
        //Ctrl-x
        else if(event.which == 88){
            event.stopPropagation();
            imageEditor_cut_selected();
        }
    }
    //delete or F10 if there is anything selected
    if(event.which == 46 || event.which == 121){
        if($(".appx_ie_selected").length > 0){
            event.stopPropagation();
            imageEditor_delete_selected();
        }
    }
    //F8 or EndKey (default ESC = 27)
    if( event.which == 119 || event.which == appx_session.getProp("mapEndKey")){
        //if ctrl key is down, it means cancel, otherwise it is End
        if(event.ctrlKey == true || event.metaKey == true){
            //cancel - We don't stope propagation here, just clear the selected items and let sendKey handle the reset
            imageEditor_cancel_prep();
        }
        else{
            //End - We don't stope propagation here, just clear the selected items and let sendKey handle the reset
            imageEditor_save_exit_prep();
        }

    }

    //Key Left Arrow
    if( event.which == 37 && $(".appx_ie_selected").length > 0){
        event.stopPropagation();
        //if alt is down do align left
        if(event.altKey){
            event.preventDefault(); //this is also a shortcut for back in the browser, so we do prevent default
            imageEditor_align_selected("LEFT");
        }
        //otherwise move selected items 1 col/offset to the left
        else{
            var delta = 0;
            var deltaOffset = 0;
            if(event.shiftKey){
                deltaOffset = Math.ceil(100 / appx_session.colWidthPx) * -1; //This is how java client does it
            }
            else{
                delta = -1;
            }
            var itemsToMove = 0;
            $(".appx_ie_selected").each( function (){
                var wx = $(this).data("widget");
                var newCol = parseInt($(this).data('col')) + delta;
                var newColOffset = (wx?wx.wOffsetX:0) + deltaOffset;
                //sum of colOffset and additionalOffset may result in additional column
                if(newColOffset > 100){
                    newCol++;
                    newColOffset -= 100;
                }
                else if( newColOffset < -100 ){
                    newCol--;
                    newColOffset += 100;
                }
                if(newCol >= 1){
                    imageEditor_move_item_prep( $(this), $(this).data('row'), newCol, wx?wx.wOffsetY:0, newColOffset);
                    itemsToMove++;
                }
            });
            if(itemsToMove > 0){
                /*apply the Move changes*/
                appxwidgetcallback(IE_CMD_DO_MOVE);
            }
        }
    }

    //Key Up Arrow
    if( event.which == 38 && $(".appx_ie_selected").length > 0){
        event.stopPropagation();
        //if alt is down do align top
        if(event.altKey){
            imageEditor_align_selected("TOP");
        }
        //otherwise move selected items 1 row/offset up
        else{
            var delta = 0;
            var deltaOffset = 0;
            if(event.shiftKey){
                deltaOffset = Math.ceil(100 / appx_session.rowHeightPx) * -1; //This is how java client does it
            }
            else{
                delta = -1;
            }
            var itemsToMove = 0;
            $(".appx_ie_selected").each( function (){
                var wx = $(this).data("widget");
                var newRow = parseInt($(this).data('row')) + delta;
                var newRowOffset = (wx?wx.wOffsetY:0) + deltaOffset;
                //sum of rowOffset and deltaOffset may result in additional row
                if(newRowOffset > 100){
                    newRow++;
                    newRowOffset -= 100;
                }
                else if( newRowOffset < -100 ){
                    newRow--;
                    newRowOffset += 100;
                }
                if(newRow >= 1){
                    imageEditor_move_item_prep( $(this), newRow, $(this).data('col'), newRowOffset, wx?wx.wOffsetX:0);
                    itemsToMove++;
                }
            });
            if(itemsToMove > 0){
                /*apply the Move changes*/
                appxwidgetcallback(IE_CMD_DO_MOVE);
            }
        }
    }

    //Key Right Arrow 
    if( event.which == 39 && $(".appx_ie_selected").length > 0){
        event.stopPropagation();
        //if alt is down do align right
        if(event.altKey){
            event.preventDefault(); //this is also a shortcut for forward in the browser, so we do prevent default
            imageEditor_align_selected("RIGHT");
        }
        //otherwise move selected items 1 col/offset to the right
        else{
            var delta = 0;
            var deltaOffset = 0;
            if(event.shiftKey){
                deltaOffset = Math.ceil(100 / appx_session.colWidthPx); //This is how java client does it
            }
            else{
                delta = 1;
            }
            var itemsToMove = 0;
            var $boxhtml = $(".appxImageEditor");
            var image_editor_cols   = Math.floor( $boxhtml.width() / appx_session.colWidthPx) - 1;
            $(".appx_ie_selected").each( function (){
                var wx = $(this).data("widget");
                var newCol = parseInt($(this).data('col')) + delta;
                var newColOffset = (wx?wx.wOffsetX:0) + deltaOffset;
                //sum of colOffset and deltaOffset may result in additional column
                if(newColOffset >= 100){
                    newCol++;
                    newColOffset -= 100;
                }
                else if( newColOffset <= -100 ){
                    newCol--;
                    newColOffset += 100;
                }
                if(newCol <= image_editor_cols){
                    imageEditor_move_item_prep( $(this), $(this).data('row'), newCol, wx?wx.wOffsetY:0, newColOffset);
                    itemsToMove++;
                }
            });
            if(itemsToMove > 0){
                /*apply the Move changes*/
                appxwidgetcallback(IE_CMD_DO_MOVE);
            }
        }
    }

    //Key Down Arrow
    if( event.which == 40 && $(".appx_ie_selected").length > 0){
        event.stopPropagation();
        //if alt is down do align bottom
        if(event.altKey){
            imageEditor_align_selected("BOTTOM");
        }
        //otherwise move selected items 1 row/offset down
        else{
            var delta = 0;
            var deltaOffset = 0;
            if(event.shiftKey){
                deltaOffset = Math.ceil(100 / appx_session.rowHeightPx); //This is how java client does it
            }
            else{
                delta = 1;
            }
            var itemsToMove = 0;
            var $boxhtml = $(".appxImageEditor");
            var image_editor_rows   = Math.floor( $boxhtml.height() / appx_session.rowHeightPx) - 1;
            $(".appx_ie_selected").each( function (){
                var wx = $(this).data("widget");
                var newRow = parseInt($(this).data('row')) + delta;
                var newRowOffset = (wx?wx.wOffsetY:0) + deltaOffset;
                //sum of rowOffset and deltaOffset may result in additional row
                if(newRowOffset >= 100){
                    newRow++;
                    newRowOffset -= 100;
                }
                else if( newRowOffset <= -100 ){
                    newRow--;
                    newRowOffset += 100;
                }
                if(newRow <= image_editor_rows){
                    imageEditor_move_item_prep( $(this), newRow, $(this).data('col'), newRowOffset, wx?wx.wOffsetX:0);
                    itemsToMove++;
                }
            });
            if(itemsToMove > 0){
                /*apply the Move changes*/
                appxwidgetcallback(IE_CMD_DO_MOVE);
            }
        }
    }

    //ALT+=
    if( event.which == 61 && event.altKey && $(".appx_ie_selected").length > 1){//need at least 2 items for same size vertically
        event.stopPropagation();
        //do same size vertically
        imageEditor_resize_selected("HEIGHT");

    }

    //ALT+\
    if( event.which == 220 && event.altKey && $(".appx_ie_selected").length > 1){//need at least 2 items for same size Horizontally
        event.stopPropagation();
        //do same size Horizintally
        imageEditor_resize_selected("WIDTH");
    }
    
}

/*This function draws a lasso rectable on the screen while the mouse is being dragged*/
function imageEditor_create_lasso_rectangle(x1, y1, x2, y2){
    //if we are drawing a line on the screen, show a line instead of a box
    if(appx_session.imageEditor_selected_control == OPT_LINE_TOOL){
        //create it first if it doesnt exist
        //<svg><line></svg>
        var $svg = $("#appx-lasso-line");
        if( $svg.length == 0){
            //svg elements are different and need to be created this way
            $svg = $(document.createElementNS('http://www.w3.org/2000/svg', 'svg'));
            $svg.attr("id","appx-lasso-line");
            $svg.addClass("appx-lasso-line");
            $svg.css("display","none");
            $line = $(document.createElementNS('http://www.w3.org/2000/svg', 'line'));
            $svg.append($line);
            $(".appxImageEditor").append($svg);
        }
        var top = y1;
        var left = x1;
        var width = x2 - x1;
        var height = y2 - y1;
        /*There are 4 ways that user can drow a line:
                top left to bottomright  -- x1=0 y1=0 x2=width y2=height
                bottom left to top right -- x1=0 y1=height x2=width y2=0
                top right to bottom left -- x1=width y1=0 x2=0 y2=height
                bottom right to top left -- x1=width y1=height x2=0 y2=0
            The line dimentions are relative to svg's dimentions
        */
        var linex1 = 0;
        var linex2 = 0;
        var liney1 = 0;
        var liney2 = 0;
        var bottomup = false; //line direction is from bottom to top
        var rightToLeft = false; //line direction is from right to left

        if(height < 0){
            top = y2; //make y2 the new top
            height = height * (-1); //make the height positive
            bottomup = true;
        }
        if(width < 0){
            left = x2;
            width = width * (-1);
            rightToLeft = true;
        }

            $svg.css({'top': top+'px',
                        'left': left+'px',
                        'width': width+'px',
                        'height': height+'px',
                        'display': 'block'
                    });
        if( bottomup==false && rightToLeft==false){
            //top left to bottomright  -- x1=0 y1=0 x2=width y2=height
            linex1 = 0;
            liney1 = 0;
            linex2 = width;
            liney2 = height;
        }
        else if(bottomup==false && rightToLeft==true){
            //top right to bottom left -- x1=width y1=0 x2=0 y2=height
            linex1 = width;
            liney1 = 0;
            linex2 = 0;
            liney2 = height;
        }
        else if(bottomup==true && rightToLeft==false){
            //bottom left to top right -- x1=0 y1=height x2=width y2=0
            linex1 = 0;
            liney1 = height;
            linex2 = width;
            liney2 = 0;
        }
        else{
            //bottom right to top left -- x1=width y1=height x2=0 y2=0
            linex1 = width;
            liney1 = height;
            linex2 = 0;
            liney2 = 0;
        }
        $line.attr("x1", linex1);
        $line.attr("x2", linex2);
        $line.attr("y1", liney1);
        $line.attr("y2", liney2);

    }//end if
    else{
        //create it first if it doesnt exist
        var $rect = $("#appx-lasso-rect");
        if( $rect.length == 0){
            $rect = $("<div class='appx-lasso-rect' id='appx-lasso-rect' style='display:none;'>");
            $(".appxImageEditor").append($rect);
        }
        $rect.removeClass("bottomup"); //remove this class if exists. Add it later if needed
        var top = y1;
        var left = x1;
        var width = x2 - x1;
        var height = y2 - y1;
        //there is a difference between lassoing from top to bottom and from bottom to top
        // if we lasso from top to bottom, we select only elements that are bounded by lasso
        // if we lasso from bottom up, we select all intersected ellements
        if(height < 0){
            top = y2; //make y2 the new top
            height = height * (-1); //make the height positive
            $rect.addClass("bottomup");
        }
        if(width < 0){
            left = x2;
            width = width * (-1);
            $rect.addClass("bottomup");
        }

        $rect.css({'top': top+'px',
                    'left': left+'px',
                    'width': width+'px',
                    'height': height+'px',
                    'display': 'block'
                });
    }//end else

}

/*this function removes the lasso rectangle from the screen*/
function imageEditor_hide_lasso_rectangle(){
    var $rect = $("#appx-lasso-rect");
    if( $rect.length > 0){
        $rect.css('display','none');
    }
}
/*this function removes the lasso line from the screen - This is for when user is drwing a line on the screen*/
function imageEditor_hide_lasso_line(){
    var $svg = $("#appx-lasso-line");
    if( $svg.length > 0){
        $svg.css('display','none');
    }
}

/*display and undisplay gridlines in image editor
**  dislpay_gridlines: boolean value controling the display or undisl=paly of grid lines
**/
function imageEditor_update_gridlines(dislpay_gridlines){
    /*remove gridlne*/
    if(dislpay_gridlines == true){
        //first select the buffered screen whcih appx uses to build the box behind the scene. If the buffered screen does not exist then use the current one.
        var $boxhtml = $("#screenBuf .appxImageEditor");
        if($boxhtml.length == 0){
            var $boxhtml = $(".appxImageEditor");
        }
        var printerAspect = false;
        var wx;
        if( $boxhtml){
            wx = $boxhtml.data("widget");
            if( wx && ( wx.wSetProcessType == PROCESS_TYPE_OUTPUT || ( wx.wSetProcessType == PROCESS_TYPE_INQUIRY && wx.wSetFrameClass != FRAME_CLASS_KEY_ENTRY ))){
                printerAspect = true; //every 10th gridline should be red
            }
        }
        var image_editor_width = $boxhtml.width(); 
        var image_editor_height = $boxhtml.height();
        var horizontal_tick = appx_session.rowHeightPx;
        var vertical_tick = appx_session.colWidthPx;
        var image_editor_cols = Math.floor( image_editor_width / appx_session.colWidthPx) - 1;
        var image_editor_rows = Math.floor( image_editor_height / appx_session.rowHeightPx) - 1;
        //add horizontal gridlines
        for(var i = 1; i<= image_editor_height/horizontal_tick; i++){
            $line = $("<div class='appx-horizontal-gridline'></div>");
            $boxhtml.append($line); 
            $line.css( {"left": vertical_tick + "px",
                        "top": (i*horizontal_tick)+ "px" ,
                        "width": image_editor_cols * appx_session.colWidthPx + "px",
                        "z-index": $boxhtml.css("z-index") - 45 //we want this to go behind the row texts
                        });

            //make every 10th line red
            if( printerAspect == true && ((i-1) % 10 ) == 0){
                $line.addClass("appx-gridline-pa");
                //we want these lines to stick out from the sides
                $line.css({ "left": vertical_tick - 3  + "px",
                            "width": (image_editor_cols * appx_session.colWidthPx) + 6 + "px"
                            });
            }
        }
        //add vertical gridlines
        for(var i = 1; i<= image_editor_width/vertical_tick; i++){
            $line = $("<div class='appx-vertical-gridline'></div>");
            $boxhtml.append($line); 
            $line.css( {"left": (i*vertical_tick)+ "px",
                        "top":  horizontal_tick + "px",
                        "height": image_editor_rows * appx_session.rowHeightPx + "px",
                        "z-index": $boxhtml.css("z-index") - 45 //we want this to go behind the row texts
                        });
            //make every 10th line red
            if( printerAspect == true && ((i-1) % 10 ) == 0){
                $line.addClass("appx-gridline-pa");
                
                $line.css( {"top":  horizontal_tick - 3 + "px",
                            "height": (image_editor_rows * appx_session.rowHeightPx) + 6 + "px"
                            });
            } 
        }
    }
    else{
        /*remove gridlines*/
        $(".appx-horizontal-gridline").remove();
        $(".appx-vertical-gridline").remove();
    }
}

/*
** Display or hide the bounds for widgets. We only show bounds on widgets with no borders
*/
function imageEditor_update_showBounds(show){
    try{
        if(show == true){
            //show bounds
            $(".appx_ie_widget.appx-border-none").addClass("appx-bound-border");
            //elements to check if they need bounds
            var $elems = $(".appx_ie_widget.appx-no-border");
            for(var i = 0; i < $elems.length; i++){
                if(parseInt($($elems[i]).css("border-width")) <= 0){
                    $($elems[i]).addClass("appx-bound-border");
                }
            }
        }
        else{
            $(".appx-bound-border").removeClass("appx-bound-border");
        }
    }
    catch(e){
        console.log("imageEditor_update_showBounds: Couldn't show bounds for all elements " + e);
        console.log(e.stack);
    }
}

//convert option number to text
function appx_get_option_name(opt){
    var opt_text = "";
    if(opt >= 0 && opt <= 255){
        opt_text = "USER_"+opt;
    }
    else{
        switch(opt){
            case OPT_SCAN:
                opt_text = "SCAN";
                break;
            case OPT_PREV_IMG:
                opt_text = "PREVIOUSE_ACTIVITY";
                break;
            case OPT_NXT_REC:
                opt_text = "NEXT_RECORD";
                break;
            case OPT_REDISPLAY:
                opt_text = "REDISPLAY";
                break;
            case OPT_ADD_MODE:
                opt_text = "ADD_MODE";
                break;
            case OPT_DEL_MODE:
                opt_text = "DELETE_MODE";
                break;
            case OPT_INQ_MODE:
                opt_text = "INQUIRE_MODE";
                break;
            case OPT_CHG_MODE:
                opt_text = "CHANGE_MODE";
                break;
            case OPT_KEY_ENTRY:
                opt_text = "KEY_ENTRY";
                break;
            case OPT_DIR_PROC_1:
                opt_text = "DIRECT_PROCESS_1";
                break;
            case OPT_DIR_PROC_2:
                opt_text = "DIRECT_PROCESS_2";
                break;
            case OPT_END:
                opt_text = "END";
                break;
            case OPT_HELP_ITM:
                opt_text = "HELP_ITEM";
                break;
            case OPT_CAN:
                opt_text = "CANCEL";
                break;
            case OPT_HELP_OPT:
                opt_text = "HELP_OPTION";
                break;
            case OPT_ENTER:
                opt_text = "RETURN";
                break;
            case OPT_ACK_DEL:
                opt_text = "ACKNOWLEDGE_DELETE";
                break;
            case OPT_LOGOUT:
                opt_text = "LOGOUT";
                break;
            case OPT_NEW_INSTANCE:
                opt_text = "NEW_SESSION";
                break;
            default:
                opt_text = "OPT_"+opt;

        }//end switch
    }//end else
    return opt_text;
}

/*send the selected items to the engine for CUT*/
function imageEditor_cut_selected(){
    var selected = 0;
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_CUT;

    $(".appx_ie_selected").each( function (){
        //cut only requires row and col of selected items
        guiEditCmd.posNewRow = $(this).data('row');
        guiEditCmd.posNewCol = $(this).data('col');
        sendGuiEditCmd(guiEditCmd);
        selected++;
    });
    //if any item was selected, cut them
    if(selected > 0){
        //unselect the cutted items
        appxImageEditor_unselectAllItems();
        //do the cut
        appxwidgetcallback( IE_CMD_DO_CUT );
    }
}

/*send the selected items to the engine for COPY*/
function imageEditor_copy_selected(){
    var selected = 0;
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_COPY;

    $(".appx_ie_selected").each( function (){
        //copy only requires row and col of selected items
        guiEditCmd.posNewRow = $(this).data('row');
        guiEditCmd.posNewCol = $(this).data('col');
        sendGuiEditCmd(guiEditCmd);
        selected++;
    });
    //if any item was selected, tell the engine to copy them
    if(selected > 0){
        //do the copy
        appxwidgetcallback( IE_CMD_DO_COPY );
    }
}

/*send the selected items to the engine for DELETION*/
function imageEditor_delete_selected(){
    var selected = 0;
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_DEL;

    $(".appx_ie_selected").each( function (){
        //delete only requires row and col of selected items
        guiEditCmd.posNewRow = $(this).data('row');
        guiEditCmd.posNewCol = $(this).data('col');
        sendGuiEditCmd(guiEditCmd);
        selected++;
    });
    //if any item was selected, tell the engine to delete them
    if(selected > 0){
        //unselect the cutted items
        appxImageEditor_unselectAllItems();
        //do the delete
        appxwidgetcallback( IE_CMD_DO_DEL );
    }
}

/*Paste the buffer to the cursor location*/
function imageEditor_paste(){
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_PASTE;

    //get cursor's position
    var cursor = appxGetCursorPos();
    guiEditCmd.posNewRow = cursor.row;
    guiEditCmd.posNewCol = cursor.col;
    sendGuiEditCmd(guiEditCmd);

    //do the paste
    appxwidgetcallback( IE_CMD_DO_PASTE );
}

/*preparing things before canceling out of image editor */
function imageEditor_cancel_prep(){
    appxImageEditor_unselectAllItems();//unselect all the items
    appx_session.imageEditor_selected_control = "";
}

/*Preparing things before saveing and exiting out of image editor */
function imageEditor_save_exit_prep(){
    appxImageEditor_unselectAllItems();//unselect all the items
    appx_session.imageEditor_selected_control = "";
}

/*show toolbox*/
function imageEditor_toolbox(){
    imageEditor_toolbarButton_toggle_control();//change the selected control to select
    appxImageEditor_unselectAllItems();//unselect all the items
    appxwidgetcallback( SCR_OPT_TOOLBOX );//run toolbox
}

/*show multi widget editor (MWE)*/
function imageEditor_multi_widget_editor(){
    imageEditor_toolbarButton_toggle_control();//change the selected control to select
    //send selected items to the engine then run MWE command
    if((appx_session.server_extended_feature_mask & TMNET_FEATURE2_MWE_NO_COPY_BUFF) == TMNET_FEATURE2_MWE_NO_COPY_BUFF){
        var guiEditCmd = initGuiEditCmd();
        guiEditCmd.cmd    = IE_CMD_DEFER;
        guiEditCmd.subCmd = IE_SUB_CMD_MWE_SEL;

        $(".appx_ie_selected").each( function (){
            //only requires row and col of selected items
            guiEditCmd.posNewRow = $(this).data('row');
            guiEditCmd.posNewCol = $(this).data('col');
            sendGuiEditCmd(guiEditCmd);
        });
    }
    else{
        //FIXME: for older engines (6.1 and older) we need to copy the items before running MWE, but that logic doesn't work on html client
        //       try to find a work around.
        //imageEditor_copy_selected(); // put selected fields into the paste buffer
    }
    appxImageEditor_unselectAllItems();//unselect all the items on the screen
    appxwidgetcallback( SCR_OPT_MWE );
}

/*
** align selected items based of the selected prototype widget
** align: specify the alignment mode. Valid values are: TOP, BOTTOM, LEFT, RIGHT
*/
function imageEditor_align_selected(align){
    try{
        //must have a prototype selected item
        var $boxhtml = $(".appxImageEditor");
        var image_editor_width  = $boxhtml.width(); 
        var image_editor_height = $boxhtml.height();
        var image_editor_cols   = Math.floor( image_editor_width / appx_session.colWidthPx) - 1;
        var image_editor_rows   = Math.floor( image_editor_height / appx_session.rowHeightPx) - 1;
        var $proto = $(".appx_ie_selected_proto");
        var $protoWidget = $proto.data("widget");
        var canMove = true; //flag that tells us if we can move all the selected items or not. default it to true

        //need a prototype select to be able to align everything with it. Normally the last item selected
        if($proto.length != 1){
            console.log("imageEditor_align_selected: no protoType Item selected");
            return;
        }

        //at least we need 2 items
        if( $(".appx_ie_selected").length < 2 ){
            console.log("imageEditor_align_selected: not enough selected items");
            return;
        }
        
        switch(align){
            case "TOP":
                //var newTop = parseInt($proto.css("top"));
                var newBottomRow = $proto.data("row");
                var newRowOffset = $protoWidget?$protoWidget.wOffsetY:0;
                if(newBottomRow < 1){
                    canMove = false;
                    break;
                }
                //before doing anything, make sure all selected items can be moved
                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var rowSize = 0;
                    //get row size of this element. Use widget if exists, use element size if it doesn't
                    if(wx && ( wx.wSizeH || wx.size_row)){
                        rowSize = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                    }
                    else{
                        rowSize = get_tag_size($(this)).rows;
                    }
                    if( (newBottomRow + rowSize)-1 > image_editor_rows){
                        canMove = false;
                    }
                });
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                if(canMove == true){
                    $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                        var wx = $(this).data("widget");
                        imageEditor_move_item_prep( $(this), newBottomRow, $(this).data('col'), newRowOffset, wx.wOffsetX);
                        itemsToMove++;
                    });
                    if(itemsToMove > 0){
                        /*apply the Move changes*/
                        appxwidgetcallback(IE_CMD_DO_MOVE);
                    }
                }
                else{
                    console.log("Not enough space to move items");
                }
                break;
            
            case "BOTTOM":
                var newBottom = 0;
                //calculate prototype's bottom. If we have widget use the widget to do calculation, otherwise use the element's properties to find the bottom
                //Note: we can't use css properties blindly to calculate the bottom since those properties are being modified based on the element type
                if($protoWidget){
                    newBottom = $proto.data('row') + ($protoWidget.wSizeH>=0?$protoWidget.wSizeH:$protoWidget.size_row) + (( ($protoWidget.wOffsetH!=null?$protoWidget.wOffsetH:0) + ($protoWidget.wOffsetY!=null?$protoWidget.wOffsetY:0))/100);
                }
                else{
                    var ptotoLoc = get_tag_location($proto);
                    var ptotoSize = get_tag_size($proto);
                    newBottom = ($proto.data('row')>=0?$proto.data('row'):ptotoLoc.row) + ptotoSize.rows + (( ptotoLoc.rowOffset + ptotoSize.rowOffset)/100);
                }

                var newBottomRow = Math.floor(newBottom);
                var newRowOffset = Math.round((newBottom - Math.floor(newBottom)) * 100);
                if(newBottomRow < 2){
                    //if new row is less than 1, then use row one and do negative offset
                    newBottomRow = 2
                    newRowOffset = newRowOffset - 100;
                }
                //make sure the new bottom is not out of bound
                if( (newBottomRow-1) > image_editor_rows){
                    canMove = false;
                    break;
                }
                //before doing anything, make sure all selected items can be moved
                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var rowSize = 0;
                    //get row size of this element. Use widget if exists, use element size if it doesn't
                    if(wx && ( wx.wSizeH || wx.size_row)){
                        rowSize = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                    }
                    else{
                        rowSize = get_tag_size($(this)).rows;
                    }
                    //make sure that by aligning the bottoms we dont make op to go out of bound
                    if( (newBottomRow - rowSize ) < 1){
                        canMove = false;
                    }
                });
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                if(canMove == true){
                    $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                        var wx = $(this).data("widget");
                        var size = {};
                        /*capture the current size*/ 
                        if(wx && ( wx.wSizeH || wx.size_row)){
                            size.rows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                            size.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                        }
                        else{
                            size = get_tag_size($(this));
                        }
                        imageEditor_move_item_prep($(this), (newBottomRow - size.rows), $(this).data('col'), newRowOffset, wx.wOffsetX);
                        itemsToMove++;
                    });
                    if(itemsToMove > 0){
                        /*apply the Move changes*/
                        appxwidgetcallback(IE_CMD_DO_MOVE);
                    }
                }
                else{
                    console.log("Not enough space to move items");
                }
                break;
            
            case "LEFT":
                //get prototype's left and col offset
                var newLeftCol = $proto.data("col");
                var newColOffset = $protoWidget?$protoWidget.wOffsetX:0;
                if(newLeftCol < 1){
                    canMove = false;
                    break;
                }
                //before doing anything, make sure all selected items can be moved
                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var colSize = 0;
                    //get row size of this element. Use widget if exists, use element size if it doesn't
                    if(wx && ( wx.wSizeW || wx.size_col)){
                        colSize = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                    }
                    else{
                        colSize = get_tag_size($(this)).cols;
                    }
                    if((newLeftCol + colSize) > image_editor_cols){
                        canMove = false;
                    }
                });
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                if(canMove == true){
                    $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    imageEditor_move_item_prep( $(this), $(this).data('row'), newLeftCol, wx.wOffsetY, newColOffset);
                    itemsToMove++;
                    });
                    if(itemsToMove > 0){
                        /*apply the Move changes*/
                        appxwidgetcallback(IE_CMD_DO_MOVE);
                    }
                }
                else{
                    console.log("Not enough space to move items");
                }
                break;
            
            case "RIGHT":
                var newRight = 0;
                //calculate extra width that the clients adds to the widget for better presentation
                //Note: if we want the items to aligned in inquire mode, protoExtraWidth needs to be 0- there may be a need for fine tuning some widgets(like listboxes)
                var protoExtraWidth = get_element_extra_width($proto) / appx_session.colWidthPx;
                //calculate prototype's right. If we have widget use the widget to do calculation, otherwise use the element's properties to find the bottom
                //Note: we can't use css properties blindly to calculate the bottom since those properties are being modified based on the element type
                if($protoWidget){
                    newRight = $proto.data('col') + ($protoWidget.wSizeW>=0?$protoWidget.wSizeW:$protoWidget.size_col) + protoExtraWidth + ((($protoWidget.wOffsetW|0) + ($protoWidget.wOffsetX|0))/100);
                }
                else{
                    var protoLoc = get_tag_location($proto);
                    var protoSize = get_tag_size($proto);
                    newRight = ($proto.data('col')>=0?$proto.data('col'):protoLoc.col) + protoSize.cols + protoExtraWidth + (( protoLoc.colOffset + protoSize.colOffset)/100);
                }

                var newRightCol = Math.floor(newRight);
                var newColOffset = Math.round((newRight - Math.floor(newRight)) * 100);
                if(newRightCol < 2){
                    //if new row is less than 1, then use row one and do negative offset
                    newRightCol = 2
                    newColOffset = newColOffset - 100;
                }
                //make sure the new bottom is not out of bound
                if( newRightCol - 1 > image_editor_cols){
                    canMove = false;
                    break;
                }
                //before doing anything, make sure all selected items can be moved
                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var colSize = 0;
                    var size = {}
                    //get row size of this element. Use widget if exists, use element size if it doesn't
                    if(wx && ( wx.wSizeW || wx.size_col)){
                        size.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                        size.colOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
                    }
                    else{
                        size = get_tag_size($(this));
                    }
                    //check if we need to add/reduce the size based on widget type. Some widgets add extra width
                    var extraWidthPx = get_element_extra_width($(this));
                    var additionalCols = 0;
                    var additionalColOffset = 0;
                    if(extraWidthPx != 0){
                        additionalCols = roundTowardsZero(extraWidthPx / appx_session.colWidthPx);
                        additionalColOffset = Math.round( ((extraWidthPx / appx_session.colWidthPx) - additionalCols) * 100 );
                        //sum of colOffset and additionalOffset may result in additional column
                        if((additionalColOffset + size.colOffset) > 100){
                            additionalCols++;
                            additionalColOffset -= 100;
                        }
                        else if((additionalColOffset + size.colOffset) < -100){
                            additionalCols--;
                            additionalColOffset += 100;
                        }
                    }
                    //make sure that by aligning the rights we dont make element to go out of bound
                    if( (newRight - (size.cols + additionalCols) ) < 1){
                        canMove = false;
                    }
                });
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                if(canMove == true){
                    $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                        var wx = $(this).data("widget");
                        var size = {};
                        /*capture the current size*/ 
                        if(wx && ( wx.wSizeH || wx.size_row)){
                            size.rows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                            size.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                            size.colOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
                            size.rowOffset = wx.wOffsetH!=null?wx.wOffsetH:0;
                        }
                        else{
                            size = get_tag_size($(this));
                        }
                        //check if we need to add/reduce the size based on widget type. Some widgets add extra width
                        var extraWidthPx = get_element_extra_width($(this));
                        var additionalCols = 0;
                        var additionalColOffset = 0;
                        if(extraWidthPx != 0){
                            additionalCols = roundTowardsZero(extraWidthPx / appx_session.colWidthPx);
                            additionalColOffset = Math.round( ((extraWidthPx / appx_session.colWidthPx) - additionalCols) * 100);
                            //sum of colOffset and additionalOffset may result in additional column
                            if((additionalColOffset + size.colOffset) > 100){
                                additionalCols++;
                                additionalColOffset -= 100;
                            }
                            else if((additionalColOffset + size.colOffset) < -100){
                                additionalCols--;
                                additionalColOffset += 100;
                            }
                        }
                        // Here is how an element sizing look like. We need to deduct all the pieces from the new Right position to get an accurate Left position
                        // Since we are replacing the offset with newColOffset, we don't make it part of this calculation
                        //     ----------------------------------------------------------------------
                        //    | colOffetX | ColSize...| colSizeOffset | ExtraColSize| ExtraColOffset |
                        //     ----------------------------------------------------------------------
                        //
                        var newColPos = newRight - (size.cols + additionalCols + ( (size.colOffset + additionalColOffset)/100 ) );
                        var newColOffsetPos = Math.round( (newColPos - Math.floor(newColPos)) * 100 );
                        newColPos = Math.floor(newColPos);
                        imageEditor_move_item_prep( $(this), $(this).data('row'), newColPos, wx.wOffsetY!=null?wx.wOffsetY:0, newColOffsetPos);
                        itemsToMove++;
                    });
                    if(itemsToMove > 0){
                        /*apply the Move changes*/
                        appxwidgetcallback(IE_CMD_DO_MOVE);
                    }
                }
                else{
                    console.log("Not enough space to move items");
                }
                break;

            default:
                console.log("imageEditor_align_selected: Invalid align mode");
                return;
        }//end switch

    }//end try
    catch(e){
        console.log("imageEditor_align_selected: Couldn't align elements " + e);
        console.log(e.stack);
    }
}

/*
** resize selected items based of the selected prototype widget
** resize_mode: specify the resize mode. Valid values are: WIDTH, HEIGHT
*/
function imageEditor_resize_selected(resize_mod){
    try{
        //must have a prototype selected item
        var $boxhtml = $(".appxImageEditor");
        var image_editor_width  = $boxhtml.width(); 
        var image_editor_height = $boxhtml.height();
        var image_editor_cols   = Math.floor( image_editor_width / appx_session.colWidthPx) - 1;
        var image_editor_rows   = Math.floor( image_editor_height / appx_session.rowHeightPx) - 1;
        var $proto = $(".appx_ie_selected_proto");
        var $protoWidget = $proto.data("widget");
        var protoSizeRows;
        var protoSizeCols;
        var protoSizeRowsOffset;
        var protoSizeColsOffset;

        //need a prototype select to be able to align everything with it. Normally the last item selected
        if($proto.length != 1){
            console.log("imageEditor_resize_selected: no protoType Item selected");
            return;
        }

        //at least we need 2 items
        if( $(".appx_ie_selected").length < 2 ){
            console.log("imageEditor_resize_selected: not enough selected items");
            return;
        }

        /*capture the prototype's size*/ 
        if($protoWidget && ( $protoWidget.wSizeH || $protoWidget.size_row)){
            protoSizeRows = $protoWidget.wSizeH>=0?$protoWidget.wSizeH:$protoWidget.size_row;
            protoSizeCols = $protoWidget.wSizeW>=0?$protoWidget.wSizeW:$protoWidget.size_col;
            protoSizeRowsOffset = $protoWidget.wOffsetH!=null?$protoWidget.wOffsetH:0;
            protoSizeColsOffset = $protoWidget.wOffsetW!=null?$protoWidget.wOffsetW:0;
        }
        else{
            var size = get_tag_size($proto);
            protoSizeRows = size.rows;
            protoSizeCols = size.cols;
            protoSizeRowsOffset = size.rowOffset;
            protoSizeColsOffset = size.colOffset;
        }
        
        switch(resize_mod){
            case "WIDTH":
                //resize by width of the prototype
                if(protoSizeCols < 1){
                    break;
                }
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                //get the extra width and height
                var protoExtraWidth = get_element_extra_width($proto);

                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var row = $(this).data('row');
                    var col = $(this).data('col');
                    var size = {};
                    /*capture the prototype's size*/ 
                    if(wx && ( wx.wSizeH || wx.size_row)){
                        size.rows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                        size.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                        size.rowOffset = wx.wOffsetH!=null?wx.wOffsetH:0;
                        size.colOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
                    }
                    else{
                        size = get_tag_size($(this));
                    }
                    //check if we need to add/reduce the size based on widget type. Some widgets add extra width
                    var extraWidthPx = protoExtraWidth - get_element_extra_width($(this));
                    var additionalCols = 0;
                    var additionalColOffset = 0;
                    if(extraWidthPx != 0){
                        additionalCols = roundTowardsZero(extraWidthPx / appx_session.colWidthPx);
                        additionalColOffset = Math.round( ((extraWidthPx / appx_session.colWidthPx) - additionalCols) * 100);
                        //sum of colOffset and additionalOffset may result in additional column
                        if((additionalColOffset + protoSizeColsOffset) > 100){
                            additionalCols++;
                            additionalColOffset -= 100;
                        }
                        else if((additionalColOffset + protoSizeColsOffset) < -100){
                            additionalCols--;
                            additionalColOffset += 100;
                        }
                    }
                    //make sure the new width doesn't push the item out of the bound. If it does, resize it
                    if( (col + protoSizeCols + additionalCols - 1) > image_editor_cols){
                        imageEditor_resize_item_prep( $(this), size.rows, protoSizeCols + additionalCols - (col + protoSizeCols + additionalCols - image_editor_cols - 1) , size.rowOffset, protoSizeColsOffset + additionalColOffset);
                    } 
                    else{
                        imageEditor_resize_item_prep( $(this), size.rows, protoSizeCols + additionalCols, size.rowOffset, protoSizeColsOffset + additionalColOffset);
                    }
                    itemsToMove++;
                });
                if(itemsToMove > 0){
                    /*apply the Move changes*/
                    appxwidgetcallback(IE_CMD_DO_MOVE);
                }
                break;
            case "HEIGHT":
                //resize by height of the prototype
                if(protoSizeRows < 1){
                    break;
                }
                //if we can move all the items, go ahead and ask the engine to do so
                var itemsToMove = 0;
                //get the extra width and height
                var protoExtraHeight = get_element_extra_height($proto);

                $(".appx_ie_selected:not(.appx_ie_selected_proto)").each( function (){
                    var wx = $(this).data("widget");
                    var row = $(this).data('row');
                    var col = $(this).data('col');
                    var size = {};
                    /*capture the prototype's size*/ 
                    if(wx && ( wx.wSizeH || wx.size_row)){
                        size.rows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
                        size.cols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
                        size.rowOffset = wx.wOffsetH!=null?wx.wOffsetH:0;
                        size.colOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
                    }
                    else{
                        size = get_tag_size($(this));
                    }
                    //check if we need to add/reduce the size based on widget type. Some widgets add extra height
                    var extraHeightPx = protoExtraHeight - get_element_extra_height($(this));
                    var additionalRows = 0;
                    var additionalRowOffset = 0;
                    if(extraHeightPx != 0){
                        additionalRows = roundTowardsZero(extraHeightPx / appx_session.rowHeightPx);
                        additionalRowOffset = Math.round( ((extraHeightPx / appx_session.rowHeightPx) - additionalRows) * 100);
                        //sum of rowOffset and additionalRowOffset may result in additional row
                        if((additionalRowOffset + protoSizeRowsOffset) > 100){
                            additionalRows++;
                            additionalRowOffset -= 100;
                        }
                        else if((additionalRowOffset + protoSizeRowsOffset) < -100){
                            additionalRows--;
                            additionalRowOffset += 100;
                        }
                    }
                    //make sure the new height doesn't push the item out of the bound. If it does, resize it
                    if( (row + protoSizeRows + additionalRows - 1) > image_editor_rows){
                        imageEditor_resize_item_prep( $(this), protoSizeRows + additionalRows - (row + protoSizeRows + additionalRows - image_editor_rows - 1) , size.cols, protoSizeRowsOffset + additionalRowOffset, size.colOffset);
                    } 
                    else{
                        imageEditor_resize_item_prep( $(this), protoSizeRows + additionalRows, size.cols, protoSizeRowsOffset + additionalRowOffset, size.colOffset);
                    }
                    itemsToMove++;
                });
                if(itemsToMove > 0){
                    /*apply the Move changes*/
                    appxwidgetcallback(IE_CMD_DO_MOVE);
                }

                break;
            default:
                console.log("imageEditor_resize_selected: invalid resize mode: "+ resize_mod);
                return;
        }
    }//end try
    catch(e){
        console.log("imageEditor_resize_selected: Couldn't resize elements " + e);
        console.log(e.stack);
    }
}

/*
** This function spreads the items horizontally with equal gap between thhem
*/
function imageEditor_spread_horizontally(){
    var totalX = 0;
    var totalUsed = 0;
    var itemCount = 0;
    var deltaPx = 0;
    var deltaCol = 0;
    var deltaColOffset = 0;
    var minX = 9999; //arbitrary large number so it gets replaced by min
    var maxX = 0;
    try{
        //make sure we at least have 3 items selected
        if( $(".appx_ie_selected").length < 3 ){
            console.log("imageEditor_spread_horizontally: not enough selected items");
            return;
        }
        $(".appx_ie_selected").each( function (){
            itemCount++;
            totalUsed += $(this).outerWidth();
            if(minX > parseInt($(this).css("left")) ){
                minX = parseInt($(this).css("left"));
            }
            if(maxX < parseInt($(this).css("left")) + $(this).width()){
                maxX = parseInt($(this).css("left")) + $(this).width();
            }
        });//end foreach
        totalX = maxX - minX;
        deltaPx = (totalX - totalUsed) / (itemCount - 1);

        //convert deltaPx to col and offset. DeltaPx can be negative
        if(deltaPx != 0){
            deltaCol = roundTowardsZero(deltaPx / appx_session.colWidthPx);
            deltaColOffset = Math.round( ((deltaPx / appx_session.colWidthPx) - deltaCol) * 100);
        }
        //first convert the selected items's object to an array and sort them by their column, row
        var selectedItems = $(".appx_ie_selected").toArray().sort( function(a,b){
                                                                                    var result = parseInt( $(a).data("col") ) - parseInt( $(b).data("col") );
                                                                                    if(result == 0){
                                                                                        result = parseInt( $(a).data("row") ) - parseInt( $(b).data("row") );
                                                                                    }
                                                                                    return result;
                                                                                });
        //now that we have the delta, we should go ahead and move the elements except for the first and last element
        //Note: selectedItems are sorted by column and row
        for(var i = 1; i < selectedItems.length - 1; i++){
            var $previousItem = $(selectedItems[i-1]);
            var $currentItem = $(selectedItems[i]);
            var prev_wx = $previousItem.data("widget");
            var cur_wx = $currentItem.data("widget");
            //we need to calculate the previous item's right, then add delta to it to get the current item's position
            var previouseItemRight = 0;
            //calculate extra width that the clients adds to the widget for better presentation
            //Note: This is the Item's right in change mode. if we want the items to aligned in inquire mode, protoExtraWidth needs to be 0- there may be a need for fine tuning some widgets(like listboxes)
            var extraWidth = get_element_extra_width($previousItem) / appx_session.colWidthPx;
            //If we have widget use the widget to do calculation, otherwise use the element's properties to find the right
            //Note: we can't use css properties blindly to calculate the right since those properties are being modified based on the element type
            if(prev_wx){
                previouseItemRight = $previousItem.data('col') + (prev_wx.wSizeW>=0?prev_wx.wSizeW:prev_wx.size_col) + extraWidth + (((prev_wx.wOffsetW|0) + (prev_wx.wOffsetX|0))/100);
            }
            else{
                var protoLoc = get_tag_location($previousItem);
                var protoSize = get_tag_size($previousItem);
                previouseItemRight = ($previousItem.data('col')>=0?$previousItem.data('col'):protoLoc.col) + protoSize.cols + extraWidth + (( protoLoc.colOffset + protoSize.colOffset)/100);
            }

            var newLeftCol = Math.floor(previouseItemRight) + deltaCol;
            var newColOffset = Math.round((previouseItemRight - Math.floor(previouseItemRight)) * 100) + deltaColOffset;

            if(newColOffset >= 100){
                newLeftCol++;
                newColOffset -= 100;
            }
            else if(newColOffset <= -100){
                newLeftCol--;
                newColOffset += 100;
            }
            
            //make the engine know about the move
            imageEditor_move_item_prep( $currentItem, $currentItem.data('row'), newLeftCol, cur_wx?cur_wx.wOffsetY:0, newColOffset);    

            //modify the item so next item can calculate things corrctly
            $currentItem.data("col", newLeftCol);
            if(cur_wx){
                cur_wx.wOffsetX = newColOffset;
            }
        }
        //apply the move
        appxwidgetcallback(IE_CMD_DO_MOVE);
    }//end try
    catch(e){
        console.log("imageEditor_spread_horizontally: spread failed! " + e);
        console.log(e.stack);
    }

}

/*
** This function spreads the items vertically with equal gap between them
*/
function imageEditor_spread_vertically(){
    var totalY = 0;
    var totalUsed = 0;
    var itemCount = 0;
    var deltaPx = 0;
    var deltaRow = 0;
    var deltaRowOffset = 0;
    var minY = 9999; //arbitrary large number so it gets replaced by min
    var maxY = 0;
    try{
        //make sure we at least have 3 items selected
        if( $(".appx_ie_selected").length < 3 ){
            console.log("imageEditor_spread_vertically: not enough selected items");
            return;
        }
        $(".appx_ie_selected").each( function (){
            itemCount++;
            totalUsed += $(this).outerHeight();
            if(minY > parseInt($(this).css("top")) ){
                minY = parseInt($(this).css("top"));
            }
            if(maxY < parseInt($(this).css("top")) + $(this).height()){
                maxY = parseInt($(this).css("top")) + $(this).height();
            }
        });//end foreach
        totalY = maxY - minY;
        deltaPx = (totalY - totalUsed) / (itemCount - 1);

        //convert deltaPx to row and offset. DeltaPx can be negative
        if(deltaPx != 0){
            deltaRow = roundTowardsZero(deltaPx / appx_session.rowHeightPx);
            deltaRowOffset = Math.round( ((deltaPx / appx_session.rowHeightPx) - deltaRow) * 100);
        }
        //first convert the selected items's object to an array and sort them by their row and column
        var selectedItems = $(".appx_ie_selected").toArray().sort( function(a,b){
                                                                                    var result = parseInt( $(a).data("row") ) - parseInt( $(b).data("row") );
                                                                                    if(result == 0){
                                                                                        result = parseInt( $(a).data("col") ) - parseInt( $(b).data("col") );
                                                                                    }
                                                                                    return result;
                                                                                });
        //now that we have the delta, we should go ahead and move the elements except for the first and last element
        //Note: selectedItems are sorted by row and column
        for(var i = 1; i < selectedItems.length - 1; i++){
            var $previousItem = $(selectedItems[i-1]);
            var $currentItem = $(selectedItems[i]);
            var prev_wx = $previousItem.data("widget");
            var cur_wx = $currentItem.data("widget");
            //we need to calculate the previous item's bottom, then add delta to it to get the current item's top position
            var previouseItemBottom = 0;
            //calculate extra height that the clients adds to the widget for better presentation
            var extraHeight = get_element_extra_height($previousItem) / appx_session.rowHeightPx;
            //If we have widget use the widget to do calculation, otherwise use the element's properties to find the bottom
            //Note: we can't use css properties blindly to calculate the right since those properties are being modified based on the element type
            if(prev_wx){
                previouseItemBottom = $previousItem.data('row') + (prev_wx.wSizeH>=0?prev_wx.wSizeH:prev_wx.size_row) + extraHeight + (((prev_wx.wOffsetH|0) + (prev_wx.wOffsetY|0))/100);
            }
            else{
                var protoLoc = get_tag_location($previousItem);
                var protoSize = get_tag_size($previousItem);
                previouseItemBottom = ($previousItem.data('row')>=0?$previousItem.data('row'):protoLoc.row) + protoSize.rows + extraHeight + (( protoLoc.rowOffset + protoSize.rowOffset)/100);
            }

            var newTopRow = Math.floor(previouseItemBottom) + deltaRow;
            var newRowOffset = Math.round((previouseItemBottom - Math.floor(previouseItemBottom)) * 100) + deltaRowOffset;

            if(newRowOffset >= 100){
                newTopRow++;
                newRowOffset -= 100;
            }
            else if(newRowOffset <= -100){
                newTopRow--;
                newRowOffset += 100;
            }
            
            //make the engine know about the move
            imageEditor_move_item_prep( $currentItem, newTopRow, $currentItem.data('col'), newRowOffset, cur_wx?cur_wx.wOffsetX:0,);    

            //modify the item so next item can calculate things corrctly
            $currentItem.data("row", newTopRow);
            if(cur_wx){
                cur_wx.wOffsetY = newRowOffset;
            }
        }
        //apply the move
        appxwidgetcallback(IE_CMD_DO_MOVE);
    }//end try
    catch(e){
        console.log("imageEditor_spread_vertically: spread failed! " + e);
        console.log(e.stack);
    }

}

/* Prepare Item to move to the given location
** to complete the move, you need to run appxwidgetcallback(IE_CMD_DO_MOVE); after this function*/
function imageEditor_move_item_prep($tag, newRow, newCol, newRowOffset, newColOffset){

    var wx = $tag.data("widget");
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_MOVE;
    /*get the old position*/
    guiEditCmd.posOldRow = $tag.data('row');
    guiEditCmd.posOldCol = $tag.data('col');
    /*capture the current size*/ 
    if(wx && ( wx.wSizeH || wx.size_row)){
        guiEditCmd.sizeRows = wx.wSizeH>=0?wx.wSizeH:wx.size_row;
        guiEditCmd.sizeCols = wx.wSizeW>=0?wx.wSizeW:wx.size_col;
        guiEditCmd.sizeRowsOffset = wx.wOffsetH!=null?wx.wOffsetH:0;
        guiEditCmd.sizeColsOffset = wx.wOffsetW!=null?wx.wOffsetW:0;
    }
    else{
        var size = get_tag_size($tag);
        guiEditCmd.sizeRows = size.rows;
        guiEditCmd.sizeCols = size.cols;
        guiEditCmd.sizeRowsOffset = size.rowOffset;
        guiEditCmd.sizeColsOffset = size.colOffset;
    }
    
    //get the new location - only chage row and rowOffset
    guiEditCmd.posNewRow = newRow;
    guiEditCmd.posNewCol = newCol;
    guiEditCmd.posNewRowOffset = newRowOffset;
    guiEditCmd.posNewColOffset = newColOffset;

    appxImageEditor_update_new_location($tag, guiEditCmd.posNewRow, guiEditCmd.posNewCol);
    /*send the changes with Defer command. Defer is used to tell engine wait for more changes before applying them in case we are moving multiple widgets*/
    sendGuiEditCmd(guiEditCmd); 
}

/* Prepare Item for resizing to the new dimmentions
    **  $tag: jQuery object of the elemt we want to resize
    **  sizeRows, sizeCols: row and column size in appx format (not pixels)
    **  sizeRowsOffset, sizeColsOffset: Optional parameter for Micro adjustment of the row and column size. Valid valies are frpm -100 to 100
    **  posNewRow, posNewRow: new position in appx row and column format. This is optional and if not passed elemt keeps its original position
    **  posNewRowOffset, posNewColOffset: Optional parameter for Micro adjustment of the row and column positioning. Valid valies are frpm -100 to 100
** to complete the resize, you need to run appxwidgetcallback(IE_CMD_DO_MOVE); after this function*/
function imageEditor_resize_item_prep($tag, sizeRows, sizeCols, sizeRowsOffset, sizeColsOffset, posNewRow, posNewCol, posNewRowOffset, posNewColOffset){

    var wx = $tag.data("widget");
    var guiEditCmd = initGuiEditCmd();
    guiEditCmd.cmd    = IE_CMD_DEFER;
    guiEditCmd.subCmd = IE_SUB_CMD_MOVE;
    /*Keep the old and new position the same*/
    guiEditCmd.posOldRow = $tag.data('row');
    guiEditCmd.posOldCol = $tag.data('col');
    guiEditCmd.posNewRow = posNewRow>=0?posNewRow:guiEditCmd.posOldRow;
    guiEditCmd.posNewCol = posNewCol>=0?posNewCol:guiEditCmd.posOldCol;
    guiEditCmd.posNewRowOffset = posNewRowOffset!=null?posNewRowOffset:(wx?wx.wOffsetY:0);
    guiEditCmd.posNewColOffset = posNewColOffset!=null?posNewColOffset:(wx?wx.wOffsetX:0);
    /*set the new size*/ 
    guiEditCmd.sizeRows = sizeRows;
    guiEditCmd.sizeCols = sizeCols;
    guiEditCmd.sizeRowsOffset = sizeRowsOffset?sizeRowsOffset:(wx?wx.wOffsetH:0);
    guiEditCmd.sizeColsOffset = sizeColsOffset?sizeColsOffset:(wx?wx.wOffsetW:0);
    /*send the changes with Defer command. Defer is used to tell engine wait for more changes before applying them in case we are moving multiple widgets*/
    sendGuiEditCmd(guiEditCmd); 
}

/*client adds extra width to some widget in order to display them better, 
** for example it adds around 3 column to tokens to be able to disoplay arrow. 
** When we resize to match the size on multiple widgets, we need to keep those 
** extra widths in mind so we can correctly match the size. This function gives 
** the extra width based on the widget type of the given element*/
function get_element_extra_width($elem){
    var wx = $elem.data("widget");
    var extra_width = 0;
    if(wx && wx.wWidgetType){
        switch(wx.wWidgetType){
            case WIDGET_TYPE_BUTTON:
            case WIDGET_TYPE_LABEL:
            case WIDGET_TYPE_PICTURE:
            case WIDGET_TYPE_LINE:
            case WIDGET_TYPE_CHECK_BOX:
            case WIDGET_TYPE_TABLE:
                extra_width = 0;
                break;

            case WIDGET_TYPE_BOX:
                if(wx.wLabel && wx.wLabel.length > 0){
                    extra_width = WIDGET_BOX_WITH_LABEL_EXTRA_WIDTH;
                }
                else{
                    extra_width = WIDGET_BOX_WITHOUT_LABEL_EXTRA_WIDTH;
                }
                break;

            case WIDGET_TYPE_COLOR_CHOOSER:
                extra_width = WIDGET_COLOR_CHOOSER_EXTRA_WIDTH;
                break;

            case WIDGET_TYPE_DATE_CHOOSER:
                extra_width = WIDGET_DATE_CHOOSER_EXTRA_WIDTH;
                break;

            case WIDGET_TYPE_LISTBOX:
                extra_width = WIDGET_LISTBOX_EXTRA_WIDTH;
                break;

            case WIDGET_TYPE_RAW_TEXT:
                if (wx.wWidgetOriginalType == WIDGET_TYPE_LISTBOX){
                    extra_width = WIDGET_LISTBOX_EXTRA_WIDTH;
                }
                else if(wx.wWidgetOriginalType == WIDGET_TYPE_DATE_CHOOSER){
                    extra_width = WIDGET_DATE_CHOOSER_EXTRA_WIDTH;
                }
                else if(wx.wWidgetOriginalType == WIDGET_TYPE_COLOR_CHOOSER){
                    extra_width = WIDGET_COLOR_CHOOSER_EXTRA_WIDTH;
                }
                else if(wx.wWidgetOriginalType == WIDGET_TYPE_FILE_CHOOSER){
                    extra_width = WIDGET_RAW_TEXT_EXTRA_WIDTH;
                }
                else{
                    extra_width = WIDGET_RAW_TEXT_EXTRA_WIDTH;
                }
                break;
            
            default:
                extra_width = WIDGET_RAW_TEXT_EXTRA_WIDTH;
        }
    }
    else{
        extra_width = WIDGET_NONE_EXTRA_WIDTH
    }
    return extra_width;
}
/*client adds extra height to some widget in order to display them better, 
** for example it adds around -2 pixels to html viewer. 
** When we resize to match the size on multiple widgets, we need to keep those 
** extra heights in mind so we can correctly match the size. This function gives 
** the extra height based on the widget type of the given element*/
function get_element_extra_height($elem){
    var wx = $elem.data("widget");
    var extra_height = 0;
    if(wx && wx.wWidgetType){
        switch(wx.wWidgetType){

            case WIDGET_TYPE_BOX:
                if(wx.wLabel && wx.wLabel.length > 0){
                    extra_height = WIDGET_BOX_WITH_LABEL_EXTRA_HEIGHT;
                }
                else{
                    extra_height = WIDGET_BOX_WITHOUT_LABEL_EXTRA_HEIGHT;
                }
                break;

            case WIDGET_TYPE_HTML_VIEWER:
                extra_height = WIDGET_HTML_VIEWER_EXTRA_HEIGHT;
                break;

            default:
                extra_height = 0;
        }
    }
    return extra_height;
}

/* This function will tell us if we need to do intersection check for the givern element
** For example, lebels are okay to intersect with other elements but raw texts cannot intersect
** with other fields.
**      $elem: the hquery object erpresenting the element
**      Return value: true/false
*/
function imageEditor_widget_can_intersect($elem){
    if(!$elem.data("widget")){
        return true;
    }
    else{
        var wx = $elem.data("widget");
        var wt = wx.wWidgetType;
        //if we overridden the widget type use the original type
        if(wx && wx.wWidgetOriginalType){
            wt = wx.wWidgetOriginalType;
        }
        //now check if the widgettype is intersectabble
        switch(wt){
            case WIDGET_TYPE_BOX:
            case WIDGET_TYPE_BUTTON:
            case WIDGET_TYPE_LABEL:
            case WIDGET_TYPE_LINE:
            case WIDGET_TYPE_PICTURE:
            case WIDGET_TYPE_TABLE:
                return true;

            default:
                return false;
        }
    }
}

/*
** This function checks to see if the item can be resized in image editor. Some items like checkbox or numeric fields 
** cannot be resized
*/
function imageEditor_can_be_resized($elem){
    var result = true; //assume it is resizeble
    var wx = $elem.data("widget");
    var wt = wx?wx.wWidgetType:null;
    //if we overridden the widget type use the original type
    if(wx && wx.wWidgetOriginalType){
        wt = wx.wWidgetOriginalType;
    }
    //engine sets resizable for some elements (like numeric fields)
    if(wx && wt && wt == WIDGET_TYPE_RAW_TEXT && wx.wResizable == false ){
        result = false;
    }
    //checkbox cannot be resized
    else if( wt && wt == WIDGET_TYPE_CHECK_BOX){
        result = false;
    }  
    //date fields
    else if( wt && wt == WIDGET_TYPE_DATE_CHOOSER){
        result = false;
    }

    return result;
}

/*
** ICONS for ImageEditor Toolbar
*/
var IMAGEEDITOR_ICON_SAVE_EXIT          = "./images/save-exit.png";
var IMAGEEDITOR_ICON_CANCEL             = "./images/cancel.png";
var IMAGEEDITOR_ICON_SELECT_REGION      = "./images/select.png";         
var IMAGEEDITOR_ICON_PAINT_BUTTON       = "./images/btn.png";              
var IMAGEEDITOR_ICON_PAINT_LABEL        = "./images/txt.png";              
var IMAGEEDITOR_ICON_PAINT_IMAGE        = "./images/img.png";              
var IMAGEEDITOR_ICON_PAINT_BOX          = "./images/box.png";             
var IMAGEEDITOR_ICON_PAINT_LINE         = "./images/line.png";             
var IMAGEEDITOR_ICON_PAINT_TABLE        = "./images/table.png"; 
var IMAGEEDITOR_ICON_PAINT_FIELD        = "./images/field.png";           
var IMAGEEDITOR_ICON_SHOW_BOUNDS        = "./images/showCtl.png";         
var IMAGEEDITOR_ICON_SHOW_GRID          = "./images/showGrid.png";         
var IMAGEEDITOR_ICON_SHOW_CHAR_UI       = "./images/showChar.png";         
var IMAGEEDITOR_ICON_DATA_PALETTE       = "./images/data.png";            
var IMAGEEDITOR_ICON_CUT                = "./images/cut.png";             
var IMAGEEDITOR_ICON_COPY               = "./images/copy.png";             
var IMAGEEDITOR_ICON_PASTE              = "./images/paste.png";  
var IMAGEEDITOR_ICON_DELETE             = "./images/del-mode.png";          
var IMAGEEDITOR_ICON_WINDOW_PROPERTIES  = "./images/winprop.png";          
var IMAGEEDITOR_ICON_OBJECT_PROPERTIES  = "./images/prop.png";            
var IMAGEEDITOR_ICON_MULTI_OBJ_PROPS    = "./images/propmulti.png";        
var IMAGEEDITOR_ICON_ALIGN_TOP          = "./images/align-top.png";        
var IMAGEEDITOR_ICON_ALIGN_BOTTOM       = "./images/align-bot.png";        
var IMAGEEDITOR_ICON_ALIGN_LEFT         = "./images/align-left.png";       
var IMAGEEDITOR_ICON_ALIGN_RIGHT        = "./images/align-right.png";     
var IMAGEEDITOR_ICON_SAME_SIZE_VERT     = "./images/same-vert.png";       
var IMAGEEDITOR_ICON_SAME_SIZE_HORIZ    = "./images/same-horiz.png";      
var IMAGEEDITOR_ICON_SPREAD_VERT        = "./images/spread-vert.png";     
var IMAGEEDITOR_ICON_SPREAD_HORIZ       = "./images/spread-horiz.png";
var IMAGEEDITOR_ICON_TOOLBOX            = "./images/toolbox.png";

/*These are the extra widths that we add to each widget for better presentation of the widget
** for example we add extra width to token lists to have space for the arrow. This extra width is not 
** part of the widget size and engine is not aware of it. We use these values in image editor to come
** up with more accurate size and location when we design the screen*/
var WIDGET_NONE_EXTRA_WIDTH = 5;
//var WIDGET_BUTTON_EXTRA_WIDTH = 0; 
//var WIDGET_LABEL_EXTRA_WIDTH = 0;
//var WIDGET_PICTURE_EXTRA_WIDTH = 0;
var WIDGET_BOX_WITH_LABEL_EXTRA_WIDTH = -((2 * appx_session.colWidthPx) + 2 - 14);
var WIDGET_BOX_WITH_LABEL_EXTRA_HEIGHT = -(appx_session.rowHeightPx - 5 - 14);
var WIDGET_BOX_WITHOUT_LABEL_EXTRA_WIDTH = -((2 * appx_session.colWidthPx) - 2 - 14);
var WIDGET_BOX_WITHOUT_LABEL_EXTRA_HEIGHT = -(appx_session.rowHeightPx - 5 - 2 - 14);
//var WIDGET_LINE_EXTRA_WIDTH = 0;
var WIDGET_RAW_TEXT_EXTRA_WIDTH = 5;
var WIDGET_SLIDER_EXTRA_WIDTH = 5;
var WIDGET_PROGRESS_BAR_EXTRA_WIDTH = 5;
//var WIDGET_CHECK_BOX_EXTRA_WIDTH = 0;
var WIDGET_LISTBOX_EXTRA_WIDTH = appx_session.colWidthPx * 3.96;
var WIDGET_TOGGLE_BUTTON_EXTRA_WIDTH = 5;
var WIDGET_PASSWORD_EXTRA_WIDTH = 5;
var WIDGET_FILE_CHOOSER_EXTRA_WIDTH = 5;
var WIDGET_COLOR_CHOOSER_EXTRA_WIDTH = (2 * appx_session.colWidthPx) - 2 + 5;
var WIDGET_TEXT_AREA_EXTRA_WIDTH = 5;
var WIDGET_HTML_VIEWER_EXTRA_WIDTH = 5;
var WIDGET_HTML_VIEWER_EXTRA_HEIGHT = -2;
var WIDGET_HTML_EDITOR_EXTRA_WIDTH = 5;
var WIDGET_FLASH_PLAYER_EXTRA_WIDTH = 5;
var WIDGET_MEDIA_PLAYER_EXTRA_WIDTH = 5;
var WIDGET_DATE_CHOOSER_EXTRA_WIDTH = (appx_session.colWidthPx * 2.5) + 5;
//var WIDGET_TABLE_EXTRA_WIDTH = 0;
var WIDGET_ROWTEXT_EXTRA_WIDTH = 5;
//var WIDGET_IMG_EDITOR_FRAME_EXTRA_WIDTH = 0;
//var WIDGET_ILF_EDITOR_FRAME_EXTRA_WIDTH = 0;
//var WIDGET_PRT_ON_SCR_FRAME_EXTRA_WIDTH = 0;

