Source: gui/handlers.js

/**@overview Contains handlers for UI elements.*/
/**@module GUI Handlers*/

// SWITCH VIEW BUTTON
// Swithes 'preview mode' which will allow the user to display the phantom in unfaded mode while editing
function switchViewButton() {
  /** @function switchViewButton
   * @memberof module:GUI Handlers
   * @desc Handler for preview button. Switches fade of the scene.
   */
  var button = document.getElementById('switchViewButton');

  if (!guiStatus.previewing) {
    phantom.addToScene(scene);
    if (guiStatus.isEditing()) {
      phantom.addSkeleton(scene);
    }
    button.value = "Back";
    button.className = 'w3-button w3-aqua w3-hover-cyan w3-border-top w3-border-left w3-border-right w3-block w3-ripple';
    guiStatus.previewing = true;
  } else {
    guiStatus.previewing = false;
    guiStatus.retrieve();
    button.className = 'w3-btn w3-border-top w3-border-left w3-border-right w3-hover-aqua w3-block w3-ripple';
    button.value = "Preview";
  }

  if (guiStatus.dragAndDropping) {
    dragAndDrop();
  }
}

function toggleSkeleton() {
  /** @function toggleSkeleton
   * @memberof module:GUI Handlers
   * @desc Handler for toggle skeleton button. Reveals all skeleton forms of the phantom.
   */
  var button = document.getElementById('skeletonButton');
  if (guiStatus.skeleting) {
    button.className = 'w3-btn w3-border w3-hover-grey w3-block w3-ripple';
    guiStatus.skeleting = false;
    guiStatus.retrieve();
  } else {
    guiStatus.skeleting = true;
    phantom.addAsSkeleton(scene);
    button.className = 'w3-button w3-white w3-border w3-hover-grey w3-block w3-ripple'
  }

}


// disable booleans must be true when the user does not click directly the option.
// This saves resources by not rebuilding editingGUI and does not reclick selectors, which would be annoying.
function fiberSelectClick(index, notclicked) {
  /** @function fiberSelectClick
    * @memberof module:GUI Handlers
    * @param {Number} index Index of the fiber in {@link Phantom} array.
    * @param {Boolean} [notclicked=false] If true, does not change UI or {@link guiStatus}
    object. Useful when changing the scene or previewing.
    * @desc Events to be fired when a fiber was selected in the list.
    <br>May be called to tweak the scene.
    */
  if (!notclicked) {
    guiStatus.editing('fiber', index);
    fiberEdit(index);
  } else {
    // We only want CP edition to be undefined when actually clicked!
    guiStatus.editingFiber = index;
  }
  phantom.revealSkeleton(scene, index);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }
}

function regionSelectClick(index, notclicked) {
  /** @function regionSelectClick
    * @memberof module:GUI Handlers
    * @param {Number} index Index of the isotropic region in {@link Phantom} array.
    * @param {Boolean} [notclicked=false] If true, does not change UI or {@link guiStatus}
    object. Useful when changing the scene or previewing.
    * @desc Events to be fired when an isotropic region was selected in the list.
    <br>May be called to tweak the scene.
    */
  if (!notclicked) {
    guiStatus.editing('region', index);
    regionEdit(index);
  }
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }
  phantom.regionHighlight(index);
}

function cpSelectClick(fiberindex, cpindex, notclicked) {
  /** @function cpSelectClick
    * @memberof module:GUI Handlers
    * @param {Number} index Index of the fiber in {@link Phantom} array.
    * @param {Number} cp Index of the control point in {@link FiberSource} array.
    * @param {Boolean} [notclicked=false] If true, does not change UI or {@link guiStatus}
    object. Useful when changing the scene or previewing.
    * @desc Events to be fired when a control point was selected in the list.
    <br>May be called to tweak the scene.
    */
  if (!notclicked) {
    guiStatus.formerCP = phantom.fibers.source[fiberindex].controlPoints[cpindex].slice(0);
    guiStatus.dragAndDropping = false;
    cpEdit(cpindex);
  }
  phantom.cpHighlight(fiberindex, cpindex, 'red');
  phantom.cpHighlight(fiberindex, cpindex, 'green');
  guiStatus.editing('CP', cpindex);
  scene.removeControls();
}

// NEW MESH BUTTONS
function newFiberClick() {
  /** @function newFiberClick
   * @memberof module:GUI Handlers
   * @desc Fires the creation of a new fiber and goes into edition.
   */
  phantom.newFiber();
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }

  setupGUI();
  selectOption(document.getElementById("fiberSelector"), phantom.fibers.source.length);
  fiberSelectClick(phantom.fibers.source.length - 1);
}

function newIsotropicRegionClick() {
  /** @function newIsotropicRegionClick
   * @memberof module:GUI Handlers
   * @desc Fires the creation of a new isotropic region and goes into edition.
   */

  phantom.newIsotropicRegion();
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }

  setupGUI();
  selectOption(document.getElementById("regionSelector"), phantom.isotropicRegions.source.length);
  regionSelectClick(phantom.isotropicRegions.source.length - 1);
}

// REMOVE MESH
function removeFiberClick() {
  /** @function removeFiberClick
   * @memberof module:GUI Handlers
   * @desc Fires the removal of a fiber and quits edition. Prompts the user for confirmation.
   */
  if (window.confirm("Are you sure you want to remove this fiber? This action cannot be undone.")) {
    var index = guiStatus.editingFiber;
    phantom.fibers.source.splice(index, 1);
    phantom.fibers.tube.splice(index, 1);
    phantom.fibers.skeleton.splice(index, 1);

    phantom.addToScene(scene);
    if (guiStatus.skeleting) {
      phantom.addSkeleton(scene);
    }

    setupGUI();
  }
}

function removeIsotropicRegionClick() {
  /** @function removeIsotropicRegionClick
   * @memberof module:GUI Handlers
   * @desc Fires the removal of an isotropic region and quits edition. Prompts the user for confirmation.
   */
  if (window.confirm("Are you sure you want to remove this isotropic region? This action cannot be undone.")) {
    var index = guiStatus.editingRegion;
    phantom.isotropicRegions.source.splice(index, 1);
    phantom.isotropicRegions.sphere.splice(index, 1);

    phantom.addToScene(scene);
    if (guiStatus.skeleting) {
      phantom.addSkeleton(scene);
    }

    setupGUI();
  }
}

// CP ADD+REMOVE
function newCPclick(fiber, cp) {
  /** @function newCPclick
   * @memberof module:GUI Handlers
   * @param {Number} index Index of the fiber in {@link Phantom} array.
   * @param {Number} index Index of the control point in {@link FiberSource} array.
   * @desc Fires the addition of a new Control Point after the current one. Gets into edit.
   */
  // Control point was yet created by hover function; it just needs to be formerly added.
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }

  guiStatus.editing('CP', cp + 1);
  guiStatus.retrieve();
  exitCPedit();
  cpSelectClick(fiber, cp + 1);
  selectOption(document.getElementById("cpSelector"), cp + 2);
}

function newCPonmouseover(fiber, cp) {
  /** @function newCPonmouseover
   * @memberof module:GUI Handlers
   * @param {Number} index Index of the fiber in {@link Phantom} array.
   * @param {Number} cp Index of the control point in {@link FiberSource} array.
   * @desc Hover for new control point button. Simulates in the scene the addition of a new control point in green color.
   */
  phantom.addCP(fiber, cp);
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }

  fiberSelectClick(fiber, true);
  phantom.cpHighlight(fiber, cp, 'red');
  phantom.cpHighlight(fiber, cp + 1, 'green');
  document.getElementById('guiFiberLength').innerHTML = roundToPrecision(phantom.fibers.source[guiStatus.editingFiber].length);
}

function newCPonmouseout(fiber, cp) {
  /** @function newCPonmouseout
   * @memberof module:GUI Handlers
   * @param {Number} index Index of the fiber in {@link Phantom} array.
   * @param {Number} cp Index of the control point in {@link FiberSource} array.
   * @desc Restores the scene after unhover in new control point button.
   * @returns {FiberSource} Actual source object.
   */
  phantom.removeCP(fiber, cp + 1);
  phantom.addToScene(scene);
  if (guiStatus.skeleting) {
    phantom.addSkeleton(scene);
  }

  guiStatus.retrieve();
  var source = phantom.fibers.source[guiStatus.editingFiber];
  document.getElementById('guiFiberLength').innerHTML = roundToPrecision(source.length);

  return source;
}

function removeCPclick(fiber, cp) {
  /** @function removeCPclick
   * @memberof module:GUI Handlers
   * @desc Fires the removal of a control point and quits edition. Prompts the user for confirmation.
   */
  if (window.confirm("Are you sure you want to remove this control point? This action cannot be undone.")) {
    phantom.removeCP(fiber, cp);
    phantom.addToScene(scene);
    if (guiStatus.skeleting) {
      phantom.addSkeleton(scene);
    }

    guiStatus.editing('CP', undefined);
    guiStatus.retrieve();
    exitCPedit();
    document.getElementById('guiFiberLength').innerHTML = roundToPrecision(phantom.fibers.source[guiStatus.editingFiber].length);
    document.getElementById("guiFiberTitle").innerHTML = phantom.fibers.source[guiStatus.editingFiber].controlPoints.length + " Points";
    document.getElementById('fiberSelector').childNodes[guiStatus.editingFiber + 1].childNodes[1].innerHTML = phantom.fibers.source[guiStatus.editingFiber].controlPoints.length + " points";
  }
}

// AXES TOGGLE
function toggleAxes() {
  /** @function toggleAxes
   * @memberof module:GUI Handlers
   * @desc Toogle axes view button. Switches between showing or removing in the scene.
   */
  button = document.getElementById('toggleAxesButton');
  name = 'axes';
  var length = phantom.radius() * 1.5;

  if (scene.getObjectByName(name)) {
    scene.remove(scene.getObjectByName(name))
    button.className = 'w3-btn w3-border w3-hover-deep-purple w3-block w3-ripple';
  } else {
    var axes = buildAxes(length);
    axes.name = name;
    scene.add(axes);
    button.className = 'w3-button w3-deep-purple w3-hover-indigo w3-border w3-block w3-ripple';
  }
  render();
}
// PLANE SELECTORS
// Double click for inverted axis was commented for it to be disabled for the moment. Found it annoying when attempting to move points.
function moveCameraXY() {
  /** @function moveCameraXY
   * @memberof module:GUI Handlers
   * @desc Moves view to the XY plane.
   */
  camera.up = new THREE.Vector3(0, 1, 0);
  controls.target = new THREE.Vector3(0, 0, 0);
  // if (camera.position.z == phantom.radius()*1.5) {
  camera.position.set(0, 0, 0);
  camera.position.z = phantom.radius() * 2 * 1.5;
  // }
  // else {
  //   camera.position.set(0, 0, 0);
  //   camera.position.z = phantom.radius()*1.5;
  // }
}

function moveCameraXZ() {
  /** @function moveCameraXZ
   * @memberof module:GUI Handlers
   * @desc Moves view to the XZ plane.
   */
  camera.up = new THREE.Vector3(0, 0, 1);
  controls.target = new THREE.Vector3(0, 0, 0);
  // if (camera.position.y == phantom.radius()*1.5) {
  camera.position.set(0, 0, 0);
  camera.position.y = phantom.radius() * 2 * -1.5;
  // }
  // else {
  //   camera.position.set(0, 0, 0);
  //   camera.position.y = phantom.radius()*-1.5;
  // }
}

function moveCameraZY() {
  /** @function moveCameraZY
   * @memberof module:GUI Handlers
   * @desc Moves view to the ZY plane.
   */
  camera.up = new THREE.Vector3(0, 1, 0);
  controls.target = new THREE.Vector3(0, 0, 0);
  // if (camera.position.x == phantom.radius()*1.5) {
  camera.position.set(0, 0, 0);
  camera.position.x = phantom.radius() * 2 * -1.5;
  // }
  // else {
  //   camera.position.set(0, 0, 0);
  //   camera.position.x = phantom.radius()*-1.5;
  // }
}


// OPACITY
function opacitySelectChange(selector) {
  /** @function opacitySelectChange
   * @memberof module:GUI Handlers
   * @param {DOM} selector Opacity selector DOM element.
   * @desc Fired when value in the opacity selector is changed. Corrects the value and fires the scene change.
   */
  // Make the value stay between min and max.
  if (Number(selector.value) > Number(selector.max)) {
    selector.value = selector.max;
  } else if (Number(selector.value) < Number(selector.min)) {
    selector.value = selector.min;
  }
  // Allow custom step; do not allow decimal values.
  selector.value = Math.round(Number(selector.value));

  phantom.highlightOpacity = selector.value / 100;
  guiStatus.retrieve();

  if ((guiStatus.editingRegion + 1) & (guiStatus.dragAndDropping) ) {
    dragAndDrop()
  }
}

function saveClick() {
  /** @function saveClick
   * @memberof module:GUI Handlers
   * @desc Pushes the download of the current Phantom.
   */
  pushDownload(phantom.export());
}