diff --git a/public/index.html b/public/index.html index db5494e5d..ce5117be1 100644 --- a/public/index.html +++ b/public/index.html @@ -325,5 +325,6 @@ + diff --git a/public/red/history.js b/public/red/history.js index ea8ed42ae..bd4b28aec 100644 --- a/public/red/history.js +++ b/public/red/history.js @@ -23,6 +23,9 @@ RED.history = function() { undo_history[i].dirty = true; } }, + depth: function() { + return undo_history.length; + }, push: function(ev) { undo_history.push(ev); }, diff --git a/public/red/ui/touch/radialMenu.js b/public/red/ui/touch/radialMenu.js new file mode 100644 index 000000000..5fabf1e4d --- /dev/null +++ b/public/red/ui/touch/radialMenu.js @@ -0,0 +1,186 @@ +/** + * Copyright 2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +RED.touch = RED.touch||{}; +RED.touch.radialMenu = function() { + + + var touchMenu = null; + var isActive = false; + var isOutside = false; + var activeOption = null; + + + function createRadial(obj,pos,options) { + isActive = true; + try { + var w = $("body").width(); + var h = $("body").height(); + + touchMenu = d3.select("body").append("div") + .style({ + position:"absolute", + top: 0, + left:0, + bottom:0, + right:0, + "z-index": 1000 + }) + .on('touchstart',function() { + hide(); + d3.event.preventDefault(); + }); + + + + + var menu = touchMenu.append("div") + .style({ + position: "absolute", + top: (pos[1]-80)+"px", + left:(pos[0]-80)+"px", + "border-radius": "80px", + width: "160px", + height: "160px", + background: "rgba(255,255,255,0.6)", + border: "1px solid #666" + }); + + var menuOpts = []; + function createMenuOpt(x,y,opt) { + opt.el = menu.append("div") + .style({ + position: "absolute", + top: (y+80-25)+"px", + left:(x+80-25)+"px", + "border-radius": "20px", + width: "50px", + height: "50px", + background: "#fff", + border: "2px solid #666", + "text-align": "center", + "line-height":"50px" + }); + if (opt.icon) { + opt.el.append("i").attr("class","icon "+opt.icon) + } else { + opt.el.html(opt.name); + } + if (opt.disabled) { + opt.el.style({"border-color":"#ccc",color:"#ccc"}); + } + opt.x = x; + opt.y = y; + menuOpts.push(opt); + + opt.el.on('touchstart',function() { + opt.el.style("background","#999"); + d3.event.preventDefault(); + d3.event.stopPropagation(); + }); + opt.el.on('touchend',function() { + hide(); + opt.onselect(); + d3.event.preventDefault(); + d3.event.stopPropagation(); + }); + } + + var n = options.length; + var dang = Math.max(Math.PI/(n-1),Math.PI/4); + var ang = Math.PI; + for (var i=0;iopt.x-30 && p[0]opt.y-30 && p[1] 80*80); + } + + } catch(err) { + RED._debug(err); + } + + + }); + + } catch(err) { + RED._debug(err); + } + } + + + return { + show: createRadial, + active: function() { + return isActive; + } + } + +}(); + diff --git a/public/red/ui/view.js b/public/red/ui/view.js index 2a458d309..9dba7ea1c 100644 --- a/public/red/ui/view.js +++ b/public/red/ui/view.js @@ -22,6 +22,13 @@ RED.view = function() { scaleFactor = 1, node_width = 100, node_height = 30; + + var touchLongPressTimeout = 1000, + startTouchDistance = 0, + startTouchCenter = [], + moveTouchCenter = [], + touchStartTime = 0; + var activeWorkspace = 0; var workspaceScrollPositions = {}; @@ -39,13 +46,8 @@ RED.view = function() { dirty = false, lasso = null, showStatus = false, - touchStartTime = 0, clickTime = 0, - clickElapsed = 0, - startTouchDistance = 0, - startTouchCenter = [], - moveTouchCenter = [], - touches = 0; + clickElapsed = 0; var clipboard = ""; @@ -74,13 +76,16 @@ RED.view = function() { .on("touchend", function() { clearTimeout(touchStartTime); touchStartTime = null; + if (RED.touch.radialMenu.active()) { + return; + } if (lasso) { outer_background.attr("fill","#fff"); } canvasMouseUp.call(this); }) .on("touchcancel", canvasMouseUp) - .on("touchstart", function(){ + .on("touchstart", function() { if (d3.event.touches.length>1) { d3.event.preventDefault(); var touch0 = d3.event.touches.item(0); @@ -100,35 +105,41 @@ RED.view = function() { ] startTouchDistance = Math.sqrt((a*a)+(b*b)); } else { + var obj = d3.select(document.body); var touch0 = d3.event.touches.item(0); + var pos = [touch0.pageX,touch0.pageY]; startTouchCenter = [touch0.pageX,touch0.pageY]; startTouchDistance = 0; var point = d3.touches(this)[0]; touchStartTime = setTimeout(function() { - lasso = vis.append('rect') - .attr("ox",point[0]) - .attr("oy",point[1]) - .attr("rx",2) - .attr("ry",2) - .attr("x",point[0]) - .attr("y",point[1]) - .attr("width",0) - .attr("height",0) - .attr("class","lasso"); - touchStartTime = null; - outer_background.attr("fill","#f3f3f3"); - },1000); - canvasMouseDown(); + touchStartTime = null; + showTouchMenu(obj,pos); + //lasso = vis.append('rect') + // .attr("ox",point[0]) + // .attr("oy",point[1]) + // .attr("rx",2) + // .attr("ry",2) + // .attr("x",point[0]) + // .attr("y",point[1]) + // .attr("width",0) + // .attr("height",0) + // .attr("class","lasso"); + //outer_background.attr("fill","#e3e3f3"); + },touchLongPressTimeout); } }) .on("touchmove", function(){ + if (RED.touch.radialMenu.active()) { + d3.event.preventDefault(); + return; + } if (d3.event.touches.length<2) { if (touchStartTime) { var touch0 = d3.event.touches.item(0); var dx = (touch0.pageX-startTouchCenter[0]); var dy = (touch0.pageY-startTouchCenter[1]); - var d = Math.sqrt(dx*dx+dy*dy); - if (d > 7) { + var d = Math.abs(dx*dx+dy*dy); + if (d > 64) { clearTimeout(touchStartTime); touchStartTime = null; } @@ -311,22 +322,19 @@ RED.view = function() { $( "#node-dialog-delete-workspace" ).dialog('open'); } - //d3.select(window).on("keydown", keydown); - function canvasMouseDown() { - if (!mousedown_node && !mousedown_link) { selected_link = null; updateSelection(); - //vis.call(d3.behavior.zoom().on("zoom"), rescale); } if (mouse_mode == 0) { if (lasso) { lasso.remove(); lasso = null; } - var point = d3.touches(this)[0]||d3.mouse(this); - if (d3.touches(this).length === 0) { + + if (!touchStartTime) { + var point = d3.mouse(this); lasso = vis.append('rect') .attr("ox",point[0]) .attr("oy",point[1]) @@ -823,6 +831,9 @@ RED.view = function() { } function nodeMouseDown(d) { + //var touch0 = d3.event; + //var pos = [touch0.pageX,touch0.pageY]; + //RED.touch.radialMenu.show(d3.select(this),pos); if (mouse_mode == RED.state.IMPORT_DRAGGING) { RED.keyboard.remove(/* ESCAPE */ 27); updateSelection(); @@ -899,6 +910,20 @@ RED.view = function() { d3.event.preventDefault(); } + function showTouchMenu(obj,pos) { + var mdn = mousedown_node; + var options = []; + options.push({name:"delete",disabled:(moving_set.length==0),onselect:function() {deleteSelection();}}); + options.push({name:"cut",disabled:(moving_set.length==0),onselect:function() {copySelection();deleteSelection();}}); + options.push({name:"copy",disabled:(moving_set.length==0),onselect:function() {copySelection();}}); + options.push({name:"paste",disabled:(clipboard.length==0),onselect:function() {importNodes(clipboard,true);}}); + options.push({name:"edit",disabled:(moving_set.length != 1),onselect:function() { RED.editor.edit(mdn);}}); + options.push({name:"select",onselect:function() {selectAll();}}); + options.push({name:"undo",disabled:(RED.history.depth() == 0),onselect:function() {RED.history.pop();}}); + + RED.touch.radialMenu.show(obj,pos,options); + resetMouseVars(); + } function redraw() { vis.attr("transform","scale("+scaleFactor+")"); outer.attr("width", space_width*scaleFactor).attr("height", space_height*scaleFactor); @@ -967,8 +992,28 @@ RED.view = function() { .attr("rx", 6) .attr("ry", 6) .attr("fill",function(d) { return d._def.color;}) + .on("mouseup",nodeMouseUp) .on("mousedown",nodeMouseDown) - .on("touchstart",nodeMouseDown) + .on("touchstart",function(d) { + var obj = d3.select(this); + var touch0 = d3.event.touches.item(0); + var pos = [touch0.pageX,touch0.pageY]; + startTouchCenter = [touch0.pageX,touch0.pageY]; + startTouchDistance = 0; + touchStartTime = setTimeout(function() { + showTouchMenu(obj,pos); + },touchLongPressTimeout); + nodeMouseDown.call(this,d) + }) + .on("touchend", function(d) { + clearTimeout(touchStartTime); + touchStartTime = null; + if (RED.touch.radialMenu.active()) { + d3.event.stopPropagation(); + return; + } + nodeMouseUp.call(this,d); + }) .on("mouseover",function(d) { if (mouse_mode == 0) { var node = d3.select(this); @@ -983,10 +1028,6 @@ RED.view = function() { //node.append("rect").attr("class", "node-gradient-top").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-top)").style("pointer-events","none"); //node.append("rect").attr("class", "node-gradient-bottom").attr("rx", 6).attr("ry", 6).attr("height",30).attr("stroke","none").attr("fill","url(#gradient-bottom)").style("pointer-events","none"); - mainRect.on("mouseup",nodeMouseUp); - mainRect.on("touchend",nodeMouseUp); - //mainRect.on("touchend",nodeMouseUp); - if (d._def.icon) { var icon = node.append("image") .attr("xlink:href","icons/"+d._def.icon) @@ -1281,7 +1322,7 @@ RED.view = function() { * - all 'selected' * - attached to mouse for placing - 'IMPORT_DRAGGING' */ - function importNodes(newNodesStr) { + function importNodes(newNodesStr,touchImport) { try { var result = RED.nodes.import(newNodesStr,true); if (result) { @@ -1320,7 +1361,9 @@ RED.view = function() { node.dx -= minX; node.dy -= minY; } - mouse_mode = RED.state.IMPORT_DRAGGING; + if (!touchImport) { + mouse_mode = RED.state.IMPORT_DRAGGING; + } RED.keyboard.add(/* ESCAPE */ 27,function(){ RED.keyboard.remove(/* ESCAPE */ 27); diff --git a/public/style.css b/public/style.css index 31734b362..7a6cb3b84 100644 --- a/public/style.css +++ b/public/style.css @@ -62,6 +62,10 @@ a.brand img { height: 16px; } +.navbar-fixed-top { + position: absolute !important; + z-index: 100 !important; +} .navbar-inner > .container-fluid { padding-right: 10px; }