diff --git a/css/style.css b/css/style.css index 6c4d1a5aa1..8956bd21cf 100644 --- a/css/style.css +++ b/css/style.css @@ -17,8 +17,12 @@ body { font-family: Verdana, Arial, Helvetica, sans-serif; } .infoLayer canvas { margin: 0; padding: 2px; } /* Tag list */ -table.tagList { border-collapse: collapse; } -table.tagList thead td { font-weight: bold; } -table.tagList td { border: 1px solid grey; padding: 2px; } -.tags .highlighted { background: #f87217; } +table.tagsTable { border-collapse: collapse; } +table.tagsTable thead th { text-transform: uppercase; + font-weight: bold; opacity: 0.5;} +table.drawsTable { border-collapse: collapse; } +table.drawsTable td { vertical-align: middle; } +table.drawsTable thead th { text-transform: uppercase; + font-weight: bold; opacity: 0.5;} +.highlighted { background: #f87217; } .tags form { width: 50%; } diff --git a/locales/en/translation.json b/locales/en/translation.json index 8be0a2ce62..9d85890b82 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -19,7 +19,17 @@ "history": "History", "image": "Image", "info": "Info", - "downloadState": "Download state" + "downloadState": "Download state", + "drawList": "Annotations", + "search": "Search", + "id": "ID", + "slice": "Slice", + "frame": "Frame", + "type": "Type", + "color": "Color", + "label": "Label", + "description": "Description", + "editMode": "Edit Mode" }, "colour": { "Yellow": { diff --git a/locales/fr/translation.json b/locales/fr/translation.json index 36fdf1d4e0..204e80014f 100644 --- a/locales/fr/translation.json +++ b/locales/fr/translation.json @@ -19,7 +19,17 @@ "history": "Historique", "image": "Image", "info": "Info", - "downloadState": "Télécharger state" + "downloadState": "Télécharger state", + "drawList": "Annotations", + "search": "Recherche", + "id": "ID", + "slice": "Coupe", + "frame": "Frame", + "type": "Type", + "color": "Couleur", + "label": "Label", + "description": "Description", + "editMode": "Mode Edition" }, "colour": { "Yellow": { diff --git a/src/app/application.js b/src/app/application.js index 87d3b58970..f503e4f483 100644 --- a/src/app/application.js +++ b/src/app/application.js @@ -60,6 +60,8 @@ dwv.App = function () // Dicom tags gui var tagsGui = null; + var drawListGui = null; + // Image layer var imageLayer = null; // Draw layers @@ -128,6 +130,12 @@ dwv.App = function () */ this.getScale = function () { return scale / windowScale; }; + /** + * Get the window scale. + * @return {Number} The window scale. + */ + this.getWindowScale = function () { return windowScale; }; + /** * Get the scale center. * @return {Object} The coordinates of the scale center. @@ -248,6 +256,9 @@ dwv.App = function () var toolClass = toolName; if (typeof dwv.tool[toolClass] !== "undefined") { toolList[toolClass] = new dwv.tool[toolClass](this); + if (typeof toolList[toolClass].addEventListener !== "undefined") { + toolList[toolClass].addEventListener(fireEvent); + } } else { console.warn("Could not initialise unknown tool: "+toolName); @@ -294,6 +305,14 @@ dwv.App = function () if ( config.gui.indexOf("tags") !== -1 ) { tagsGui = new dwv.gui.DicomTags(this); } + // Draw list + if ( config.gui.indexOf("drawList") !== -1 ) { + drawListGui = new dwv.gui.DrawList(this); + // update list on draw events + this.addEventListener("draw-create", drawListGui.update); + this.addEventListener("draw-change", drawListGui.update); + this.addEventListener("draw-delete", drawListGui.update); + } // version number if ( config.gui.indexOf("version") !== -1 ) { dwv.gui.appendVersionHtml(this.getVersion()); @@ -795,6 +814,72 @@ dwv.App = function () translateLayers(); }; + /** + * Get a list of drawing details. + * @return {Object} A list of draw details including id, slice, frame... + */ + this.getDrawDetailsList = function () + { + var list = []; + var size = image.getGeometry().getSize(); + for ( var z = 0; z < size.getNumberOfSlices(); ++z ) { + + for ( var f = 0; f < image.getNumberOfFrames(); ++f ) { + + var collec = this.getDrawLayer(z,f).getChildren(); + for ( var i = 0; i < collec.length; ++i ) { + var shape = collec[i].getChildren()[0]; + var label = collec[i].getChildren()[1]; + var text = label.getChildren()[0]; + var type = shape.className; + if (type === "Line" && shape.closed()) { + type = "Roi"; + } + if (type === "Rect") { + type = "Rectangle"; + } + list.push( { + "id": collec[i].id(), + //"id": i, + "slice": z, + "frame": f, + "type": type, + "color": shape.stroke(), + "label": text.textExpr, + "description": text.longText + }); + } + } + } + // return + return list; + }; + + /** + * Update a drawing. + * @param {Object} drawDetails Details of the drawing to update. + */ + this.updateDraw = function (drawDetails) + { + var layer = this.getDrawLayer(drawDetails.slice, drawDetails.frame); + //var collec = layer.getChildren()[drawDetails.id]; + var collec = layer.getChildren( function (node) { + return node.id() === drawDetails.id; + })[0]; + // shape + var shape = collec.getChildren()[0]; + shape.stroke(drawDetails.color); + // label + var label = collec.getChildren()[1]; + var text = label.getChildren()[0]; + text.fill(drawDetails.color); + text.textExpr = drawDetails.label; + text.longText = drawDetails.description; + text.setText(dwv.utils.replaceFlags(text.textExpr, text.quant)); + // udpate layer + this.getDrawLayer().draw(); + }; + // Handler Methods ----------------------------------------------------------- /** @@ -1434,7 +1519,7 @@ dwv.App = function () viewController = new dwv.ViewController(view); // append the DICOM tags table if ( tagsGui ) { - tagsGui.initialise(data.info); + tagsGui.update(data.info); } // store image originalImage = view.getImage(); diff --git a/src/app/state.js b/src/app/state.js index 8fcf093c60..5884b6bece 100644 --- a/src/app/state.js +++ b/src/app/state.js @@ -19,31 +19,46 @@ dwv.State = function (app) var nSlices = app.getImage().getGeometry().getSize().getNumberOfSlices(); var nFrames = app.getImage().getNumberOfFrames(); var drawings = []; + var drawingsDetails = []; for ( var k = 0; k < nSlices; ++k ) { - drawings[k] = []; - for ( var f = 0; f < nFrames; ++f ) { - // getChildren always return, so drawings will have the good size - var groups = app.getDrawLayer(k,f).getChildren(); - // remove anchors - for ( var i = 0; i < groups.length; ++i ) { - var anchors = groups[i].find(".anchor"); - for ( var a = 0; a < anchors.length; ++a ) { - anchors[a].remove(); + drawings[k] = []; + drawingsDetails[k] = []; + for ( var f = 0; f < nFrames; ++f ) { + // getChildren always return, so drawings will have the good size + var groups = app.getDrawLayer(k,f).getChildren(); + var details = []; + // remove anchors + for ( var i = 0; i < groups.length; ++i ) { + var anchors = groups[i].find(".anchor"); + for ( var a = 0; a < anchors.length; ++a ) { + anchors[a].remove(); + } + var texts = groups[i].find(".text"); + for ( var b = 0; b < texts.length; ++b ) { + details.push({ + "id": groups[i].id(), + "textExpr": texts[b].textExpr, + "longText": texts[b].longText, + "quant": texts[b].quant + }); + } } + drawings[k].push(groups); + drawingsDetails[k].push(details); } - drawings[k].push(groups); - } } // return a JSON string return JSON.stringify( { - "version": "0.1", - "window-center": app.getViewController().getWindowLevel().center, + "version": "0.2", + "window-center": app.getViewController().getWindowLevel().center, "window-width": app.getViewController().getWindowLevel().width, "position": app.getViewController().getCurrentPosition(), "scale": app.getScale(), "scaleCenter": app.getScaleCenter(), "translation": app.getTranslation(), - "drawings": drawings + "drawings": drawings, + // new in v0.2 + "drawingsDetails": drawingsDetails } ); }; /** @@ -54,14 +69,17 @@ dwv.State = function (app) this.fromJSON = function (json, eventCallback) { var data = JSON.parse(json); if (data.version === "0.1") { - readV01(data, eventCallback); + readV01(data, eventCallback); + } + else if (data.version === "0.2") { + readV02(data, eventCallback); } else { - throw new Error("Unknown state file format version: '"+data.version+"'."); + throw new Error("Unknown state file format version: '"+data.version+"'."); } }; /** - * Read an application state from an Object. + * Read an application state from an Object in v0.1 format. * @param {Object} data The Object representation of the state. * @param {Object} eventCallback The callback to associate to draw commands. */ @@ -78,21 +96,68 @@ dwv.State = function (app) return node.name() === "shape"; }; for ( var k = 0 ; k < nSlices; ++k ) { - for ( var f = 0; f < nFrames; ++f ) { - for ( var i = 0 ; i < data.drawings[k][f].length; ++i ) { - var group = Kinetic.Node.create(data.drawings[k][f][i]); - var shape = group.getChildren( isShape )[0]; - var cmd = new dwv.tool.DrawGroupCommand( - group, shape.className, - app.getDrawLayer(k,f) ); - if ( typeof eventCallback !== "undefined" ) { - cmd.onExecute = eventCallback; - cmd.onUndo = eventCallback; + for ( var f = 0; f < nFrames; ++f ) { + for ( var i = 0 ; i < data.drawings[k][f].length; ++i ) { + var group = Kinetic.Node.create(data.drawings[k][f][i]); + var shape = group.getChildren( isShape )[0]; + var cmd = new dwv.tool.DrawGroupCommand( + group, shape.className, + app.getDrawLayer(k,f) ); + if ( typeof eventCallback !== "undefined" ) { + cmd.onExecute = eventCallback; + cmd.onUndo = eventCallback; + } + cmd.execute(); + app.addToUndoStack(cmd); } - cmd.execute(); - app.addToUndoStack(cmd); } } + } + /** + * Read an application state from an Object in v0.2 format. + * @param {Object} data The Object representation of the state. + * @param {Object} eventCallback The callback to associate to draw commands. + */ + function readV02(data, eventCallback) { + // display + app.getViewController().setWindowLevel(data["window-center"], data["window-width"]); + app.getViewController().setCurrentPosition(data.position); + app.zoom(data.scale, data.scaleCenter.x, data.scaleCenter.y); + app.translate(data.translation.x, data.translation.y); + // drawings + var nSlices = app.getImage().getGeometry().getSize().getNumberOfSlices(); + var nFrames = app.getImage().getNumberOfFrames(); + var isShape = function (node) { + return node.name() === "shape"; + }; + var isLabel = function (node) { + return node.name() === "label"; + }; + for ( var k = 0 ; k < nSlices; ++k ) { + for ( var f = 0; f < nFrames; ++f ) { + for ( var i = 0 ; i < data.drawings[k][f].length; ++i ) { + var group = Kinetic.Node.create(data.drawings[k][f][i]); + var shape = group.getChildren( isShape )[0]; + var cmd = new dwv.tool.DrawGroupCommand( + group, shape.className, + app.getDrawLayer(k,f) ); + if ( typeof eventCallback !== "undefined" ) { + cmd.onExecute = eventCallback; + cmd.onUndo = eventCallback; + } + // text (new in v0.2) + // TODO Verify ID? + var details = data.drawingsDetails[k][f][i]; + var label = group.getChildren( isLabel )[0]; + var text = label.getText(); + text.textExpr = details.textExpr; + text.longText = details.longText; + text.quant = details.quant; + // execute + cmd.execute(); + app.addToUndoStack(cmd); + } + } } } }; // State class diff --git a/src/app/toolboxController.js b/src/app/toolboxController.js index 99bb40f635..0cd752f7b8 100644 --- a/src/app/toolboxController.js +++ b/src/app/toolboxController.js @@ -44,11 +44,11 @@ dwv.ToolboxController = function (toolbox) /** * Set the tool line colour. - * @param {String} name The name of the colour. + * @param {String} colour The colour. */ - this.setLineColour = function (name) + this.setLineColour = function (colour) { - toolbox.getSelectedTool().setLineColour(name); + toolbox.getSelectedTool().setLineColour(colour); }; /** diff --git a/src/dicom/dicomParser.js b/src/dicom/dicomParser.js index 28b52c8b27..a292f4ca0a 100755 --- a/src/dicom/dicomParser.js +++ b/src/dicom/dicomParser.js @@ -1331,23 +1331,23 @@ dwv.dicom.DicomElementsWrapper = function (dicomElements) { } // name if ( dictElement !== null ) { - row[dwv.i18n("basics.name")] = dictElement[2]; + row.name = dictElement[2]; } else { - row[dwv.i18n("basics.name")] = "Unknown Tag & Data"; + row.name = "Unknown Tag & Data"; } // value if ( dicomElement.tag.name !== "x7FE00010" ) { - row[dwv.i18n("basics.value")] = dicomElement.value; + row.value = dicomElement.value; } else { - row[dwv.i18n("basics.value")] = "..."; + row.value = "..."; } // others - row[dwv.i18n("basics.group")] = dicomElement.tag.group; - row[dwv.i18n("basics.element")] = dicomElement.tag.element; - row[dwv.i18n("basics.vr")] = dicomElement.vr; - row[dwv.i18n("basics.vl")] = dicomElement.vl; + row.group = dicomElement.tag.group; + row.element = dicomElement.tag.element; + row.vr = dicomElement.vr; + row.vl = dicomElement.vl; table.push( row ); } diff --git a/src/gui/generic.js b/src/gui/generic.js index 99c7331327..b4bec766e8 100644 --- a/src/gui/generic.js +++ b/src/gui/generic.js @@ -31,6 +31,24 @@ dwv.gui.base.displayProgress = function (/*percent*/) // default does nothing... }; +/** + * Focus the view on the image. + */ +dwv.gui.base.focusImage = function () +{ + // default does nothing... +}; + +/** + * Post process a HTML table. + * @param {Object} table The HTML table to process. + * @return The processed HTML table. + */ +dwv.gui.base.postProcessTable = function (/*table*/) +{ + // default does nothing... +}; + /** * Get a HTML element associated to a container div. * @param {Number} containerDivId The id of the container div. @@ -157,19 +175,21 @@ dwv.gui.base.Slider = function (app) /** * DICOM tags base gui. + * @param {Object} app The associated application. * @constructor */ dwv.gui.base.DicomTags = function (app) { /** - * Initialise the DICOM tags table. To be called once the DICOM has been parsed. + * Update the DICOM tags table with the input info. * @param {Object} dataInfo The data information. */ - this.initialise = function (dataInfo) + this.update = function (dataInfo) { // HTML node var node = app.getElement("tags"); if( node === null ) { + console.warn("Cannot find a node to append the DICOM tags."); return; } // remove possible previous @@ -178,17 +198,181 @@ dwv.gui.base.DicomTags = function (app) } // tags HTML table var table = dwv.html.toTable(dataInfo); + // css table.className = "tagsTable"; - //table.setAttribute("class", "tagsList"); - table.setAttribute("data-role", "table"); - table.setAttribute("data-mode", "columntoggle"); - table.setAttribute("data-column-btn-text", dwv.i18n("basics.columns") + "..."); - // search form + + // optional gui specific table post process + dwv.gui.postProcessTable(table); + + // translate first row + if (table.rows.length !== 0) { + dwv.html.translateTableRow(table.rows.item(0)); + } + + // append search form node.appendChild(dwv.html.getHtmlSearchForm(table)); - // tags table + // append tags table node.appendChild(table); // refresh dwv.gui.refreshElement(node); }; }; // class dwv.gui.base.DicomTags + +/** + * Drawing list base gui. + * @param {Object} app The associated application. + * @constructor + */ +dwv.gui.base.DrawList = function (app) +{ + /** + * Closure to self. + */ + var self = this; + + /** + * Update the draw list html element + * @param {Object} event A change event, decides if the table is editable or not. + */ + this.update = function (event) + { + var isEditable = false; + if (typeof event.editable !== "undefined") { + isEditable = event.editable; + } + + // HTML node + var node = app.getElement("drawList"); + if( node === null ) { + return; + } + // remove possible previous + while (node.hasChildNodes()) { + node.removeChild(node.firstChild); + } + // tags HTML table + var drawDetailsList = app.getDrawDetailsList(); + var table = dwv.html.toTable(drawDetailsList); + table.className = "drawsTable"; + + // optional gui specific table post process + dwv.gui.postProcessTable(table); + + // translate first row + if (table.rows.length !== 0) { + dwv.html.translateTableRow(table.rows.item(0)); + } + + // translate shape names + dwv.html.translateTableColumn(table, 3, "shape", "name"); + + // do not go there if just one row... + if ( table.rows.length > 0 ) { + + // create a color onkeyup handler + var createColorOnKeyUp = function (details) { + return function () { + details.color = this.value; + app.updateDraw(details); + }; + }; + // create a text onkeyup handler + var createTextOnKeyUp = function (details) { + return function () { + details.label = this.value; + app.updateDraw(details); + }; + }; + // create a long text onkeyup handler + var createLongTextOnKeyUp = function (details) { + return function () { + details.description = this.value; + app.updateDraw(details); + }; + }; + // create a row onclick handler + var createRowOnClick = function (slice, frame) { + return function () { + // update slice + var pos = app.getViewController().getCurrentPosition(); + pos.k = slice; + app.getViewController().setCurrentPosition(pos); + // update frame + app.getViewController().setCurrentFrame(frame); + // focus on the image + dwv.gui.focusImage(); + }; + }; + + // loop through rows + for (var r = 1; r < table.rows.length; ++r) { + var drawId = r - 1; + var drawDetails = drawDetailsList[drawId]; + var row = table.rows.item(r); + var cells = row.cells; + + // if not editable, allow click on row + if (!isEditable) { + row.onclick = createRowOnClick( + cells[1].firstChild.data, + cells[2].firstChild.data); + row.onmouseover = dwv.html.setCursorToPointer; + row.onmouseout = dwv.html.setCursorToDefault; + } + + // loop through cells + for (var c = 0; c < cells.length; ++c) { + if (isEditable) { + // color + if (c === 4) { + dwv.html.makeCellEditable(cells[c], createColorOnKeyUp(drawDetails), "color"); + } + // text + else if (c === 5) { + dwv.html.makeCellEditable(cells[c], createTextOnKeyUp(drawDetails)); + } + // long text + else if (c === 6) { + dwv.html.makeCellEditable(cells[c], createLongTextOnKeyUp(drawDetails)); + } + } + else { + // color: just display the input color with no callback + if (c === 4) { + dwv.html.makeCellEditable(cells[c], null, "color"); + } + } + } + } + + // editable checkbox + var tickBox = document.createElement("input"); + tickBox.setAttribute("type", "checkbox"); + tickBox.id = "checkbox-editable"; + tickBox.checked = isEditable; + tickBox.onclick = function () { self.update({"editable": this.checked}); }; + // checkbox label + var tickLabel = document.createElement("label"); + tickLabel.setAttribute( "for", tickBox.id ); + tickLabel.setAttribute( "class", "inline" ); + tickLabel.appendChild( document.createTextNode( dwv.i18n("basics.editMode") ) ); + // checkbox div + var tickDiv = document.createElement("div"); + tickDiv.appendChild(tickLabel); + tickDiv.appendChild(tickBox); + + // search form + node.appendChild(dwv.html.getHtmlSearchForm(table)); + // tick form + node.appendChild(tickDiv); + + } // if more than one row + + // draw list table + node.appendChild(table); + // refresh + dwv.gui.refreshElement(node); + }; + +}; // class dwv.gui.base.DrawList diff --git a/src/gui/html.js b/src/gui/html.js index 282e48fa38..f3bd5559d1 100644 --- a/src/gui/html.js +++ b/src/gui/html.js @@ -14,8 +14,8 @@ dwv.html.appendCell = function (row, content) var str = content; // special care for arrays if ( content instanceof Array || - content instanceof Uint8Array || - content instanceof Uint16Array || + content instanceof Uint8Array || content instanceof Int8Array || + content instanceof Uint16Array || content instanceof Int16Array || content instanceof Uint32Array ) { if ( content.length > 10 ) { content = Array.prototype.slice.call( content, 0, 10 ); @@ -35,21 +35,17 @@ dwv.html.appendCell = function (row, content) dwv.html.appendHCell = function (row, text) { var cell = document.createElement("th"); - // TODO jquery-mobile specific... - if ( text !== dwv.i18n("basics.value") && text !== dwv.i18n("basics.name") ) { - cell.setAttribute("data-priority", "1"); - } cell.appendChild(document.createTextNode(text)); row.appendChild(cell); }; /** * Append a row to an array. - * @param {} table - * @param {} input - * @param {} level - * @param {} maxLevel - * @param {} rowHeader + * @param {Object} table The HTML table to append a row to. + * @param {Array} input The input row array. + * @param {Number} level The depth level of the input array. + * @param {Number} maxLevel The maximum depth level. + * @param {String} rowHeader The content of the first cell of a row (mainly for objects). */ dwv.html.appendRowForArray = function (table, input, level, maxLevel, rowHeader) { @@ -77,11 +73,11 @@ dwv.html.appendRowForArray = function (table, input, level, maxLevel, rowHeader) /** * Append a row to an object. - * @param {} table - * @param {} input - * @param {} level - * @param {} maxLevel - * @param {} rowHeader + * @param {Object} table The HTML table to append a row to. + * @param {Array} input The input row array. + * @param {Number} level The depth level of the input array. + * @param {Number} maxLevel The maximum depth level. + * @param {String} rowHeader The content of the first cell of a row (mainly for objects). */ dwv.html.appendRowForObject = function (table, input, level, maxLevel, rowHeader) { @@ -115,7 +111,7 @@ dwv.html.appendRowForObject = function (table, input, level, maxLevel, rowHeader var header = table.createTHead(); var th = header.insertRow(-1); if ( rowHeader ) { - dwv.html.appendHCell(th, "name"); + dwv.html.appendHCell(th, ""); } for ( var k=0; k= columnNumber) { + var text = cells[columnNumber].firstChild.data; + cells[columnNumber].firstChild.data = dwv.i18n( prefix + text + suffix ); + } + } + } +}; + +/** + * Make a HTML table cell editable by putting its content inside an input element. + * @param {Object} cell The cell to make editable. + * @param {Function} onchange The callback to call when cell's content is changed. + * if set to null, the HTML input will be disabled. + * @param {String} inputType The type of the HTML input, default to 'text'. + */ +dwv.html.makeCellEditable = function (cell, onchange, inputType) { + // check event + if (typeof cell === "undefined" ) { + console.warn("Cannot create input for non existing cell."); + return; + } + // HTML input + var input = document.createElement("input"); + // handle change + if (onchange) { + input.onchange = onchange; + } + else { + input.disabled = true; + } + // set input value + input.value = cell.firstChild.data; + // input type + if (typeof inputType === "undefined" || + (inputType === "color" && !dwv.browser.hasInputColor() ) ) { + input.type = "text"; + } + else { + input.type = inputType; + } + + // clean cell + dwv.html.cleanNode(cell); + + // HTML form + var form = document.createElement("form"); + form.onsubmit = function (event) { + event.preventDefault(); + }; + form.appendChild(input); + // add form to cell + cell.appendChild(form); +}; + +/** + * Set the document cursor to 'pointer'. + */ +dwv.html.setCursorToPointer = function () { + document.body.style.cursor = 'pointer'; +}; + +/** + * Set the document cursor to 'default'. + */ +dwv.html.setCursorToDefault = function () { + document.body.style.cursor = 'default'; +}; + + /** * Create a HTML select from an input array of options. * The values of the options are the name of the option made lower case. diff --git a/src/gui/style.js b/src/gui/style.js index 3109e7d089..039b7ed62c 100644 --- a/src/gui/style.js +++ b/src/gui/style.js @@ -31,7 +31,7 @@ dwv.html.Style = function () * @private * @type String */ - var lineColour = ""; + var lineColour = "#ffff80"; /** * Display scale. * @private diff --git a/src/gui/tools.js b/src/gui/tools.js index 91e6ad5640..a4b1af5618 100644 --- a/src/gui/tools.js +++ b/src/gui/tools.js @@ -139,7 +139,7 @@ dwv.gui.base.WindowLevel = function (app) this.initialise = function () { // create new preset select - var wlSelector = dwv.html.createHtmlSelect("presetSelect", + var wlSelector = dwv.html.createHtmlSelect("presetSelect", app.getViewController().getPresets(), "wl.presets", true); wlSelector.onchange = app.onChangeWindowLevelPreset; wlSelector.title = "Select w/l preset."; @@ -178,9 +178,16 @@ dwv.gui.base.Draw = function (app) "Yellow", "Red", "White", "Green", "Blue", "Lime", "Fuchsia", "Black" ]; /** - * Get the available colours. + * Get the default colour. */ - this.getColours = function () { return colours; }; + this.getDefaultColour = function () { + if ( dwv.browser.hasInputColor() ) { + return "#FFFF80"; + } + else { + return colours[0]; + } + }; /** * Setup the tool HTML. @@ -191,7 +198,16 @@ dwv.gui.base.Draw = function (app) var shapeSelector = dwv.html.createHtmlSelect("shapeSelect", shapeList, "shape"); shapeSelector.onchange = app.onChangeShape; // colour select - var colourSelector = dwv.html.createHtmlSelect("colourSelect", colours, "colour"); + var colourSelector = null; + if ( dwv.browser.hasInputColor() ) { + colourSelector = document.createElement("input"); + colourSelector.className = "colourSelect"; + colourSelector.type = "color"; + colourSelector.value = "#FFFF80"; + } + else { + colourSelector = dwv.html.createHtmlSelect("colourSelect", colours, "colour"); + } colourSelector.onchange = app.onChangeLineColour; // shape list element @@ -244,7 +260,9 @@ dwv.gui.base.Draw = function (app) // colour select: reset selected option var colourSelector = app.getElement("colourSelect"); - colourSelector.selectedIndex = 0; + if ( !dwv.browser.hasInputColor() ) { + colourSelector.selectedIndex = 0; + } // refresh dwv.gui.refreshElement(colourSelector); }; @@ -252,19 +270,31 @@ dwv.gui.base.Draw = function (app) }; // class dwv.gui.base.Draw /** - * Livewire tool base gui. + * Base gui for a tool with a colour setting. * @constructor */ -dwv.gui.base.Livewire = function (app) +dwv.gui.base.ColourTool = function (app, prefix) { // default colours var colours = [ "Yellow", "Red", "White", "Green", "Blue", "Lime", "Fuchsia", "Black" ]; + // colour selector class + var colourSelectClassName = prefix + "ColourSelect"; + // colour selector class + var colourLiClassName = prefix + "ColourLi"; + /** - * Get the available colours. + * Get the default colour. */ - this.getColours = function () { return colours; }; + this.getDefaultColour = function () { + if ( dwv.browser.hasInputColor() ) { + return "#FFFF80"; + } + else { + return colours[0]; + } + }; /** * Setup the tool HTML. @@ -272,12 +302,21 @@ dwv.gui.base.Livewire = function (app) this.setup = function () { // colour select - var colourSelector = dwv.html.createHtmlSelect("lwColourSelect", colours, "colour"); + var colourSelector = null; + if ( dwv.browser.hasInputColor() ) { + colourSelector = document.createElement("input"); + colourSelector.className = colourSelectClassName; + colourSelector.type = "color"; + colourSelector.value = "#FFFF80"; + } + else { + colourSelector = dwv.html.createHtmlSelect(colourSelectClassName, colours, "colour"); + } colourSelector.onchange = app.onChangeLineColour; // colour list element var colourLi = document.createElement("li"); - colourLi.className = "lwColourLi ui-block-b"; + colourLi.className = colourLiClassName + " ui-block-b"; colourLi.style.display = "none"; //colourLi.setAttribute("class","ui-block-b"); colourLi.appendChild(colourSelector); @@ -297,7 +336,7 @@ dwv.gui.base.Livewire = function (app) this.display = function (bool) { // colour list - var node = app.getElement("lwColourLi"); + var node = app.getElement(colourLiClassName); dwv.html.displayElement(node, bool); }; @@ -306,12 +345,14 @@ dwv.gui.base.Livewire = function (app) */ this.initialise = function () { - var colourSelector = app.getElement("lwColourSelect"); - colourSelector.selectedIndex = 0; + var colourSelector = app.getElement(colourSelectClassName); + if ( !dwv.browser.hasInputColor() ) { + colourSelector.selectedIndex = 0; + } dwv.gui.refreshElement(colourSelector); }; -}; // class dwv.gui.base.Livewire +}; // class dwv.gui.base.ColourTool /** * ZoomAndPan tool base gui. diff --git a/src/tools/draw.js b/src/tools/draw.js index 954ca8aef2..5884ae3416 100644 --- a/src/tools/draw.js +++ b/src/tools/draw.js @@ -7,10 +7,16 @@ var Kinetic = Kinetic || {}; /** * Draw group command. + * @param {Object} group The group draw. + * @param {String} name The name of the shape. + * @param {Object} layer The layer where to draw the group. + * @param {Object} silent Whether to send a creation event or not. * @constructor */ -dwv.tool.DrawGroupCommand = function (group, name, layer) +dwv.tool.DrawGroupCommand = function (group, name, layer, silent) { + var isSilent = (typeof silent === "undefined") ? false : true; + /** * Get the command name. * @return {String} The command name. @@ -25,7 +31,9 @@ dwv.tool.DrawGroupCommand = function (group, name, layer) // draw layer.draw(); // callback - this.onExecute({'type': 'draw-create', 'id': group.id()}); + if (!isSilent) { + this.onExecute({'type': 'draw-create', 'id': group.id()}); + } }; /** * Undo the command. @@ -59,6 +67,10 @@ dwv.tool.DrawGroupCommand.prototype.onUndo = function (/*event*/) /** * Move group command. + * @param {Object} group The group draw. + * @param {String} name The name of the shape. + * @param {Object} translation A 2D translation to move the group by. + * @param {Object} layer The layer where to move the group. * @constructor */ dwv.tool.MoveGroupCommand = function (group, name, translation, layer) @@ -118,6 +130,12 @@ dwv.tool.MoveGroupCommand.prototype.onUndo = function (/*event*/) /** * Change group command. + * @param {String} name The name of the shape. + * @param {Object} func The change function. + * @param {Object} startAnchor The anchor that starts the change. + * @param {Object} endAnchor The anchor that ends the change. + * @param {Object} layer The layer where to change the group. + * @param {Object} image The associated image. * @constructor */ dwv.tool.ChangeGroupCommand = function (name, func, startAnchor, endAnchor, layer, image) @@ -171,6 +189,9 @@ dwv.tool.ChangeGroupCommand.prototype.onUndo = function (/*event*/) /** * Delete group command. + * @param {Object} group The group draw. + * @param {String} name The name of the shape. + * @param {Object} layer The layer where to delete the group. * @constructor */ dwv.tool.DeleteGroupCommand = function (group, name, layer) @@ -315,7 +336,16 @@ dwv.tool.Draw = function (app, shapeFactoryList) trash.add(trashLine1); trash.add(trashLine2); - // listeners + /** + * Drawing style. + * @type Style + */ + this.style = new dwv.html.Style(); + + /** + * Event listeners. + * @private + */ var listeners = {}; /** @@ -397,7 +427,7 @@ dwv.tool.Draw = function (app, shapeFactoryList) shapeGroup.destroy(); } // create shape group - shapeGroup = factory.create(points, app.getStyle(), app.getImage()); + shapeGroup = factory.create(points, self.style, app.getImage()); // do not listen during creation var shape = shapeGroup.getChildren( function (node) { return node.name() === 'shape'; @@ -405,7 +435,7 @@ dwv.tool.Draw = function (app, shapeFactoryList) shape.listening(false); drawLayer.hitGraphEnabled(false); // draw shape command - command = new dwv.tool.DrawGroupCommand(shapeGroup, self.shapeName, drawLayer); + command = new dwv.tool.DrawGroupCommand(shapeGroup, self.shapeName, drawLayer, true); // draw command.execute(); } @@ -424,7 +454,7 @@ dwv.tool.Draw = function (app, shapeFactoryList) } // create final shape var factory = new self.shapeFactoryList[self.shapeName](); - var group = factory.create(points, app.getStyle(), app.getImage()); + var group = factory.create(points, self.style, app.getImage()); group.id( dwv.math.guid() ); // re-activate layer drawLayer.hitGraphEnabled(true); @@ -631,14 +661,16 @@ dwv.tool.Draw = function (app, shapeFactoryList) cmdName = "ellipse"; } - // shape colour - var colour = shape.stroke(); + // store original colour + var colour = null; // drag start event handling shape.on('dragstart', function (event) { // save start position var offset = dwv.html.getEventOffset( event.evt )[0]; dragStartPos = getRealPosition( offset ); + // colour + colour = shape.stroke(); // display trash var stage = app.getDrawStage(); var scale = stage.scale(); @@ -694,6 +726,8 @@ dwv.tool.Draw = function (app, shapeFactoryList) shape.on('dragend', function (/*event*/) { var pos = dragLastPos; dragLastPos = null; + // remove trash + trash.remove(); // delete case if ( Math.abs( pos.x - trash.x() ) < 10 && Math.abs( pos.y - trash.y() ) < 10 ) { @@ -705,8 +739,6 @@ dwv.tool.Draw = function (app, shapeFactoryList) shape.x( shape.x() - delTranslation.x ); shape.y( shape.y() - delTranslation.y ); }); - // restore colour - shape.stroke(colour); // disable editor shapeEditor.disable(); shapeEditor.setShape(null); @@ -735,8 +767,6 @@ dwv.tool.Draw = function (app, shapeFactoryList) shapeEditor.setAnchorsActive(true); shapeEditor.resetAnchors(); } - // remove trash - trash.remove(); // draw drawLayer.draw(); }); @@ -753,16 +783,22 @@ dwv.tool.Draw = function (app, shapeFactoryList) var ktext = labels[0].getText(); // ask user for new label - var labelText = dwv.gui.prompt("Add label", ktext.textExpr); + var labelText = dwv.gui.prompt("Shape label", ktext.textExpr); // if press cancel do nothing if (labelText === null) { - return false; + return; + } + else if (labelText === ktext.textExpr) { + return; } // update text expression and set text ktext.textExpr = labelText; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); + // trigger event + fireEvent({'type': 'draw-change'}); + // draw drawLayer.draw(); }); @@ -781,8 +817,10 @@ dwv.tool.Draw = function (app, shapeFactoryList) this.setShapeName(shapeName); // init gui if ( gui ) { + // init with the app window scale + this.style.setScale(app.getWindowScale()); // same for colour - this.setLineColour(gui.getColours()[0]); + this.setLineColour(this.style.getLineColour()); // init html gui.initialise(); } @@ -826,7 +864,7 @@ dwv.tool.Draw = function (app, shapeFactoryList) */ this.setLineColour = function (colour) { - app.getStyle().setLineColour(colour); + this.style.setLineColour(colour); }; // Private Methods ----------------------------------------------------------- diff --git a/src/tools/ellipse.js b/src/tools/ellipse.js index e979cde336..df880070e4 100644 --- a/src/tools/ellipse.js +++ b/src/tools/ellipse.js @@ -53,6 +53,7 @@ dwv.tool.EllipseFactory.prototype.create = function (points, style, image) name: "text" }); ktext.textExpr = "{surface}"; + ktext.longText = ""; ktext.quant = quant; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); // label diff --git a/src/tools/floodfill.js b/src/tools/floodfill.js index bbe53fad38..04cb5e8048 100644 --- a/src/tools/floodfill.js +++ b/src/tools/floodfill.js @@ -119,6 +119,12 @@ dwv.tool.Floodfill = function(app) */ this.style = new dwv.html.Style(); + /** + * Event listeners. + * @private + */ + var listeners = []; + /** * Set extend option for painting border on all slices. * @param {Boolean} The option to set @@ -190,10 +196,16 @@ dwv.tool.Floodfill = function(app) if(border){ var factory = new dwv.tool.RoiFactory(); shapeGroup = factory.create(border, self.style); + shapeGroup.id( dwv.math.guid() ); // draw shape command command = new dwv.tool.DrawGroupCommand(shapeGroup, "floodfill", app.getDrawLayer()); + command.onExecute = fireEvent; + command.onUndo = fireEvent; // // draw command.execute(); + // save it in undo stack + app.addToUndoStack(command); + return true; } else{ @@ -243,12 +255,12 @@ dwv.tool.Floodfill = function(app) this.modifyThreshold = function(modifyThreshold){ // remove previous draw clearTimeout(painterTimeout); - painterTimeout = setTimeout(function(){ - if ( shapeGroup && self.started) { - shapeGroup.destroy(); - } - paintBorder(initialpoint, modifyThreshold); - },100); + painterTimeout = setTimeout( function () { + if ( shapeGroup && self.started) { + shapeGroup.destroy(); + } + paintBorder(initialpoint, modifyThreshold); + }, 100); }; /** @@ -338,7 +350,7 @@ dwv.tool.Floodfill = function(app) */ this.setup = function () { - gui = new dwv.gui.Livewire(app); + gui = new dwv.gui.ColourTool(app, "ff"); gui.setup(); }; @@ -360,14 +372,54 @@ dwv.tool.Floodfill = function(app) this.init = function() { if ( gui ) { + // init with the app window scale + this.style.setScale(app.getWindowScale()); // set the default to the first in the list - this.setLineColour(gui.getColours()[0]); + this.setLineColour(this.style.getLineColour()); // init html gui.initialise(); } return true; }; + + /** + * Add an event listener on the app. + * @param {Object} listener The method associated with the provided event type. + */ + this.addEventListener = function (listener) + { + listeners.push(listener); + }; + + /** + * Remove an event listener from the app. + * @param {Object} listener The method associated with the provided event type. + */ + this.removeEventListener = function (listener) + { + for ( var i = 0; i < listeners.length; ++i ) + { + if ( listeners[i] === listener ) { + listeners.splice(i,1); + } + } + }; + + // Private Methods ----------------------------------------------------------- + + /** + * Fire an event: call all associated listeners. + * @param {Object} event The event to fire. + */ + function fireEvent (event) + { + for ( var i=0; i < listeners.length; ++i ) + { + listeners[i](event); + } + } + }; // Floodfill class /** diff --git a/src/tools/line.js b/src/tools/line.js index c940223b38..ff940a8a15 100644 --- a/src/tools/line.js +++ b/src/tools/line.js @@ -49,6 +49,7 @@ dwv.tool.LineFactory.prototype.create = function (points, style, image) name: "text" }); ktext.textExpr = "{length}"; + ktext.longText = ""; ktext.quant = quant; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); // label diff --git a/src/tools/livewire.js b/src/tools/livewire.js index 86641cd314..2d63d5e948 100644 --- a/src/tools/livewire.js +++ b/src/tools/livewire.js @@ -45,6 +45,8 @@ dwv.tool.Livewire = function(app) * @type Style */ this.style = new dwv.html.Style(); + // init with the app window scale + this.style.setScale(app.getWindowScale()); /** * Path storage. Paths are stored in reverse order. @@ -71,6 +73,12 @@ dwv.tool.Livewire = function(app) */ var tolerance = 5; + /** + * Event listeners. + * @private + */ + var listeners = []; + /** * Clear the parent points list. * @private @@ -124,6 +132,10 @@ dwv.tool.Livewire = function(app) if( (Math.abs(event._x - self.x0) < tolerance) && (Math.abs(event._y - self.y0) < tolerance) ) { // draw self.mousemove(event); + // listen + command.onExecute = fireEvent; + command.onUndo = fireEvent; + // debug console.log("Done."); // save command in undo stack app.addToUndoStack(command); @@ -201,6 +213,7 @@ dwv.tool.Livewire = function(app) // create shape var factory = new dwv.tool.RoiFactory(); shapeGroup = factory.create(currentPath.pointArray, self.style); + shapeGroup.id( dwv.math.guid() ); // draw shape command command = new dwv.tool.DrawGroupCommand(shapeGroup, "livewire", app.getDrawLayer()); // draw @@ -276,7 +289,7 @@ dwv.tool.Livewire = function(app) */ this.setup = function () { - gui = new dwv.gui.Livewire(app); + gui = new dwv.gui.ColourTool(app, "lw"); gui.setup(); }; @@ -305,8 +318,10 @@ dwv.tool.Livewire = function(app) this.init = function() { if ( gui ) { + // init with the app window scale + this.style.setScale(app.getWindowScale()); // set the default to the first in the list - this.setLineColour(gui.getColours()[0]); + this.setLineColour(this.style.getLineColour()); // init html gui.initialise(); } @@ -314,6 +329,43 @@ dwv.tool.Livewire = function(app) return true; }; + /** + * Add an event listener on the app. + * @param {Object} listener The method associated with the provided event type. + */ + this.addEventListener = function (listener) + { + listeners.push(listener); + }; + + /** + * Remove an event listener from the app. + * @param {Object} listener The method associated with the provided event type. + */ + this.removeEventListener = function (listener) + { + for ( var i = 0; i < listeners.length; ++i ) + { + if ( listeners[i] === listener ) { + listeners.splice(i,1); + } + } + }; + + // Private Methods ----------------------------------------------------------- + + /** + * Fire an event: call all associated listeners. + * @param {Object} event The event to fire. + */ + function fireEvent (event) + { + for ( var i=0; i < listeners.length; ++i ) + { + listeners[i](event); + } + } + }; // Livewire class /** diff --git a/src/tools/protractor.js b/src/tools/protractor.js index 58e45ef609..9970c259fd 100644 --- a/src/tools/protractor.js +++ b/src/tools/protractor.js @@ -69,6 +69,7 @@ dwv.tool.ProtractorFactory.prototype.create = function (points, style/*, image*/ name: "text" }); ktext.textExpr = "{angle}"; + ktext.longText = ""; ktext.quant = quant; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); diff --git a/src/tools/rectangle.js b/src/tools/rectangle.js index 5dd8d449a8..23d13795a1 100644 --- a/src/tools/rectangle.js +++ b/src/tools/rectangle.js @@ -51,6 +51,7 @@ dwv.tool.RectangleFactory.prototype.create = function (points, style, image) name: "text" }); ktext.textExpr = "{surface}"; + ktext.longText = ""; ktext.quant = quant; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); diff --git a/src/tools/roi.js b/src/tools/roi.js index b15b0faaa6..e4d146c548 100644 --- a/src/tools/roi.js +++ b/src/tools/roi.js @@ -58,6 +58,7 @@ dwv.tool.RoiFactory.prototype.create = function (points, style /*, image*/) name: "text" }); ktext.textExpr = ""; + ktext.longText = ""; ktext.quant = null; ktext.setText(dwv.utils.replaceFlags(ktext.textExpr, ktext.quant)); diff --git a/src/utils/browser.js b/src/utils/browser.js index 0301564c38..350c9fe643 100644 --- a/src/utils/browser.js +++ b/src/utils/browser.js @@ -76,6 +76,22 @@ dwv.browser.hasClampedArray = function() return dwv.browser._hasClampedArray; }; +/** + * Browser check for input with type='color'. + * Missing in IE 11. + */ +dwv.browser.hasInputColor = function() +{ + var caughtException = false; + var colorInput = document.createElement("input"); + try { + colorInput.type = "color"; + } catch (error) { + caughtException = true; + } + return !caughtException; +}; + /** * Browser checks to see if it can run dwv. Throws an error if not. * Silently replaces basic functions. diff --git a/tests/html/html.test.js b/tests/html/html.test.js index 717b587d0d..200ce148e0 100644 --- a/tests/html/html.test.js +++ b/tests/html/html.test.js @@ -28,7 +28,7 @@ QUnit.test("Test array to html function.", function (assert) { // array of objects var array2 = [{"a":0, "b":1}, {"a":2, "b":3}]; var table2 = dwv.html.toTable(array2); - var table2_ref = "
ab
01
23
"; + var table2_ref = "
ab
01
23
"; assert.equal(table2.outerHTML, table2_ref, "Array of objects"); // object @@ -37,6 +37,6 @@ QUnit.test("Test array to html function.", function (assert) { obj.first = {"a":0, "b":1}; obj.second = {"a":"hello", "b":undefined}; var table3 = dwv.html.toTable(obj); - var table3_ref = "
nameab
first01
secondhelloundefined
"; + var table3_ref = "
ab
first01
secondhelloundefined
"; assert.equal(table3.outerHTML, table3_ref, "Object"); }); diff --git a/tests/visual/appgui.js b/tests/visual/appgui.js index 8339179f51..8ba735fb14 100644 --- a/tests/visual/appgui.js +++ b/tests/visual/appgui.js @@ -1,6 +1,6 @@ -/** +/** * Application GUI. - * + * * Snapshots were created using synedra View Personal (http://www.synedra.com), * version 14 for Microsoft Windows: * - Right click on the thumbnail in the left 'Document tree area', @@ -27,11 +27,6 @@ dwv.gui.displayProgress = function (/*percent*/) {}; // check browser support dwv.browser.check(); -// fake translation function used in table creation. -dwv.i18n = function (text) { - return text.substring(text.lastIndexOf('.') + 1, text.length); -}; - // test data line dwv.addDataLine = function (id, fileroot, doc) { @@ -57,7 +52,7 @@ dwv.addDataLine = function (id, fileroot, doc) var app = new dwv.App(); app.init(config); // display loading time - var listener = function (event) { + var listener = function (event) { if (event.type === "load-start") { console.time("load-data"); } diff --git a/viewers/mobile/appgui.js b/viewers/mobile/appgui.js index 7b5acf3a67..ed86542133 100644 --- a/viewers/mobile/appgui.js +++ b/viewers/mobile/appgui.js @@ -67,6 +67,11 @@ dwv.gui.displayProgress = function (percent) { $.mobile.loading("hide"); } }; +// Focus +dwv.gui.focusImage = function () +{ + $.mobile.changePage("#main"); +}; // get element dwv.gui.getElement = dwv.gui.base.getElement; // refresh @@ -80,8 +85,47 @@ dwv.gui.refreshElement = function (element) { }; // Slider dwv.gui.Slider = dwv.gui.base.Slider; -// Tags gui +// Post process table +dwv.gui.postProcessTable = function (table) +{ + var tableClass = table.className; + // css + table.className += " table-stripe ui-responsive"; + // add columntoggle + table.setAttribute("data-role", "table"); + table.setAttribute("data-mode", "columntoggle"); + table.setAttribute("data-column-btn-text", dwv.i18n("basics.columns") + "..."); + // add priority columns for columntoggle + var addDataPriority = function (cell) { + var text = cell.firstChild.data; + if ( tableClass === "tagsTable" ) { + if ( text !== "value" && text !== "name" ) { + cell.setAttribute("data-priority", "5"); + } + } + else if ( tableClass === "drawsTable" ) { + if ( text === "description" ) { + cell.setAttribute("data-priority", "1"); + } + else if ( text === "id" || text === "frame" || text === "slice" ) { + cell.setAttribute("data-priority", "5"); + } + + } + }; + if (table.rows.length !== 0) { + var hCells = table.rows.item(0).cells; + for (var c = 0; c < hCells.length; ++c) { + addDataPriority(hCells[c]); + } + } + // return + return table; +}; +// Tags table dwv.gui.DicomTags = dwv.gui.base.DicomTags; +// DrawList table +dwv.gui.DrawList = dwv.gui.base.DrawList; // Loaders dwv.gui.Loadbox = dwv.gui.base.Loadbox; @@ -135,6 +179,10 @@ dwv.gui.Toolbox = function (app) tags.href = "#tags_page"; tags.setAttribute("class", buttonClass + " ui-icon-grid"); + var drawList = document.createElement("a"); + drawList.href = "#drawList_page"; + drawList.setAttribute("class", buttonClass + " ui-icon-edit"); + var node = app.getElement("toolbar"); node.appendChild(open); node.appendChild(undo); @@ -142,6 +190,7 @@ dwv.gui.Toolbox = function (app) node.appendChild(toggleInfo); node.appendChild(toggleSaveState); node.appendChild(tags); + node.appendChild(drawList); dwv.gui.refreshElement(node); }; this.display = function (flag) @@ -158,8 +207,8 @@ dwv.gui.Toolbox = function (app) dwv.gui.WindowLevel = dwv.gui.base.WindowLevel; // Draw dwv.gui.Draw = dwv.gui.base.Draw; -// Livewire -dwv.gui.Livewire = dwv.gui.base.Livewire; +// ColourTool +dwv.gui.ColourTool = dwv.gui.base.ColourTool; // ZoomAndPan dwv.gui.ZoomAndPan = dwv.gui.base.ZoomAndPan; // Scroll diff --git a/viewers/mobile/applauncher.js b/viewers/mobile/applauncher.js index 22fe9abbe9..35677706fd 100644 --- a/viewers/mobile/applauncher.js +++ b/viewers/mobile/applauncher.js @@ -6,12 +6,12 @@ function startApp() { // translate page dwv.i18nPage(); - + // main application var myapp = new dwv.App(); // display loading time - var listener = function (event) { + var listener = function (event) { if (event.type === "load-start") { console.time("load-data"); } @@ -22,7 +22,7 @@ function startApp() { // before myapp.init since it does the url load myapp.addEventListener("load-start", listener); myapp.addEventListener("load-end", listener); - + // also available: //myapp.addEventListener("load-progress", listener); //myapp.addEventListener("draw-create", listener); @@ -38,7 +38,7 @@ function startApp() { myapp.init({ "containerDivId": "dwv", "fitToWindow": true, - "gui": ["tool", "load", "help", "undo", "version", "tags"], + "gui": ["tool", "load", "help", "undo", "version", "tags", "drawList"], "loaders": ["File", "Url", "GoogleDrive", "Dropbox"], "tools": ["Scroll", "WindowLevel", "ZoomAndPan", "Draw", "Livewire", "Filter", "Floodfill"], "filters": ["Threshold", "Sharpen", "Sobel"], diff --git a/viewers/mobile/index.html b/viewers/mobile/index.html index c78504ace5..13a174f013 100644 --- a/viewers/mobile/index.html +++ b/viewers/mobile/index.html @@ -14,8 +14,24 @@ .layerContainer { margin: auto; text-align: center; } .imageLayer { left: 0px; } .dropBox { margin: 20px auto; } +.inline { display: inline-block !important; } + @@ -100,7 +116,7 @@ - @@ -194,6 +210,23 @@

DICOM Tags

+ +
+ +
+Back +

Draw list

+
+ +
+ +
+
+ +
+ +
diff --git a/viewers/static/appgui.js b/viewers/static/appgui.js index 97e9fdf54c..939bd98c40 100644 --- a/viewers/static/appgui.js +++ b/viewers/static/appgui.js @@ -40,6 +40,8 @@ dwv.gui.displayProgress = function (percent) { $("#progressbar").progressbar({ value: percent }); } }; +// Focus +dwv.gui.focusImage = dwv.gui.base.focusImage; // get element dwv.gui.getElement = dwv.gui.base.getElement; // refresh @@ -79,8 +81,12 @@ function toggle(dialogId) $(dialogId).dialog('open'); } } +// post process table +dwv.gui.postProcessTable = dwv.gui.base.postProcessTable; // Tags table dwv.gui.DicomTags = dwv.gui.base.DicomTags; +// DrawList table +dwv.gui.DrawList = dwv.gui.base.DrawList; // Loaders dwv.gui.Loadbox = dwv.gui.base.Loadbox; @@ -115,6 +121,10 @@ dwv.gui.Toolbox = function (app) tags.appendChild(document.createTextNode(dwv.i18n("basics.dicomTags"))); tags.onclick = function() { toggle(".tags"); }; + var drawList = document.createElement("button"); + drawList.appendChild(document.createTextNode(dwv.i18n("basics.drawList"))); + drawList.onclick = function() { toggle(".drawList"); }; + var image = document.createElement("button"); image.appendChild(document.createTextNode(dwv.i18n("basics.image"))); image.onclick = function() { toggle(".layerDialog"); }; @@ -132,6 +142,7 @@ dwv.gui.Toolbox = function (app) node.appendChild(toolbox); node.appendChild(history); node.appendChild(tags); + node.appendChild(drawList); node.appendChild(image); node.appendChild(info); node.appendChild(help); @@ -166,8 +177,8 @@ dwv.gui.Toolbox = function (app) dwv.gui.WindowLevel = dwv.gui.base.WindowLevel; // Draw dwv.gui.Draw = dwv.gui.base.Draw; -// Livewire -dwv.gui.Livewire = dwv.gui.base.Livewire; +// ColourTool +dwv.gui.ColourTool = dwv.gui.base.ColourTool; // ZoomAndPan dwv.gui.ZoomAndPan = dwv.gui.base.ZoomAndPan; // Scroll @@ -213,6 +224,11 @@ dwv.gui.setup = function () { autoOpen: false, width: 500, height: 590, appendTo: "#dwv" }); + $(".drawList").dialog({ position: + {my: "right top", at: "right top", of: "#pageMain"}, + autoOpen: false, width: 500, height: 250, + appendTo: "#dwv" + }); $(".help").dialog({ position: {my: "right top", at: "right top", of: "#pageMain"}, autoOpen: false, width: 500, height: 590, diff --git a/viewers/static/applauncher.js b/viewers/static/applauncher.js index 075861a6f6..65542c6078 100644 --- a/viewers/static/applauncher.js +++ b/viewers/static/applauncher.js @@ -13,7 +13,7 @@ function startApp() { myapp.init({ "containerDivId": "dwv", "fitToWindow": true, - "gui": ["tool", "load", "help", "undo", "version", "tags"], + "gui": ["tool", "load", "help", "undo", "version", "tags", "drawList"], "loaders": ["File", "Url"], "tools": ["Scroll", "WindowLevel", "ZoomAndPan", "Draw", "Livewire", "Filter", "Floodfill"], "filters": ["Threshold", "Sharpen", "Sobel"], diff --git a/viewers/static/index.html b/viewers/static/index.html index cb39e826e9..6900c31b54 100644 --- a/viewers/static/index.html +++ b/viewers/static/index.html @@ -125,6 +125,9 @@

DWV

+ +
+