mirror of
https://github.com/lubosz/overte.git
synced 2025-04-25 12:33:04 +02:00
3688 lines
161 KiB
JavaScript
3688 lines
161 KiB
JavaScript
//
|
|
// toolsMenu.js
|
|
//
|
|
// Created by David Rowe on 22 Jul 2017.
|
|
// Copyright 2017 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
/* global ToolsMenu: true, App, Feedback, UIT */
|
|
|
|
ToolsMenu = function (side, leftInputs, rightInputs, uiCommandCallback) {
|
|
// Tool menu displayed on top of forearm.
|
|
|
|
"use strict";
|
|
|
|
var attachmentJointName,
|
|
|
|
menuOriginLocalPosition,
|
|
menuOriginLocalRotation,
|
|
|
|
menuOriginOverlay,
|
|
menuHeaderOverlay,
|
|
menuHeaderHeadingOverlay,
|
|
menuHeaderBarOverlay,
|
|
menuHeaderBackOverlay,
|
|
menuHeaderTitleOverlay,
|
|
menuHeaderIconOverlay,
|
|
menuPanelOverlay,
|
|
|
|
menuOverlays = [],
|
|
menuHoverOverlays = [],
|
|
menuIconOverlays = [],
|
|
menuLabelOverlays = [],
|
|
menuEnabled = [],
|
|
|
|
optionsOverlays = [],
|
|
optionsOverlaysIDs = [], // Text ids (names) of options overlays.
|
|
optionsOverlaysLabels = [], // Overlay IDs of labels for optionsOverlays.
|
|
optionsOverlaysSublabels = [], // Overlay IDs of sublabels for optionsOverlays.
|
|
optionsSliderData = [], // Uses same index values as optionsOverlays.
|
|
optionsColorData = [], // Uses same index values as optionsOverlays.
|
|
optionsExtraOverlays = [],
|
|
optionsEnabled = [],
|
|
optionsSettings = {
|
|
// <option item id>: {
|
|
// key: <Settings key to store value in>
|
|
// value: <current value>
|
|
// }
|
|
// For reliable access, use the values from optionsSettings rather than doing Settings.getValue() - Settings values
|
|
// are not necessarily updated instantaneously.
|
|
},
|
|
optionsToggles = {}, // Cater for toggle buttons without a setting.
|
|
|
|
footerOverlays = [],
|
|
footerHoverOverlays = [],
|
|
footerIconOverlays = [],
|
|
footerLabelOverlays = [],
|
|
footerEnabled = [],
|
|
|
|
swatchHighlightOverlay = null,
|
|
|
|
staticOverlays = [],
|
|
|
|
LEFT_HAND = 0,
|
|
PANEL_ORIGIN_POSITION_LEFT_HAND = {
|
|
x: -UIT.dimensions.canvasSeparation - UIT.dimensions.canvas.x / 2,
|
|
y: UIT.dimensions.handOffset,
|
|
z: 0
|
|
},
|
|
PANEL_ORIGIN_POSITION_RIGHT_HAND = {
|
|
x: UIT.dimensions.canvasSeparation + UIT.dimensions.canvas.x / 2,
|
|
y: UIT.dimensions.handOffset,
|
|
z: 0
|
|
},
|
|
PANEL_ORIGIN_ROTATION_LEFT_HAND = Quat.fromVec3Degrees({ x: 0, y: -90, z: 0 }),
|
|
PANEL_ORIGIN_ROTATION_RIGHT_HAND = Quat.fromVec3Degrees({ x: 0, y: 90, z: 0 }),
|
|
panelLateralOffset,
|
|
|
|
MENU_ORIGIN_PROPERTIES = {
|
|
dimensions: { x: 0.005, y: 0.005, z: 0.005 },
|
|
color: { red: 255, blue: 0, green: 0 },
|
|
alpha: 1.0,
|
|
parentID: Uuid.SELF,
|
|
ignoreRayIntersection: true,
|
|
visible: false,
|
|
displayInFront: true
|
|
},
|
|
|
|
MENU_HEADER_HOVER_OFFSET = { x: 0, y: 0, z: 0.0040 },
|
|
|
|
MENU_HEADER_PROPERTIES = {
|
|
// Invisible box to catch laser intersections while menu heading and bar move inside.
|
|
dimensions: Vec3.sum(UIT.dimensions.header, MENU_HEADER_HOVER_OFFSET), // Keep the laser on top when hover.
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.canvas.y / 2 - UIT.dimensions.header.y / 2,
|
|
z: UIT.dimensions.header.z / 2 + MENU_HEADER_HOVER_OFFSET.z / 2
|
|
},
|
|
localRotation: Quat.ZERO,
|
|
alpha: 0.0, // Invisible
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true // Catch laser intersections.
|
|
},
|
|
|
|
MENU_HEADER_HEADING_PROPERTIES = {
|
|
url: Script.resolvePath("../assets/gray-header.fbx"),
|
|
highlightURL: Script.resolvePath("../assets/green-header.fbx"),
|
|
dimensions: UIT.dimensions.headerHeading, // Model is in rotated coordinate system but can override.
|
|
localPosition: { x: 0, y: UIT.dimensions.headerBar.y / 2, z: -MENU_HEADER_HOVER_OFFSET.z / 2 },
|
|
localRotation: Quat.ZERO,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
},
|
|
|
|
MENU_HEADER_BAR_PROPERTIES = {
|
|
url: Script.resolvePath("../assets/green-header-bar.fbx"),
|
|
dimensions: UIT.dimensions.headerBar, // Model is in rotated coordinate system but can override.
|
|
localPosition: { x: 0, y: -UIT.dimensions.headerHeading.y / 2 - UIT.dimensions.headerBar.y / 2, z: 0 },
|
|
localRotation: Quat.ZERO,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
},
|
|
|
|
MENU_HEADER_BACK_PROPERTIES = {
|
|
url: Script.resolvePath("../assets/tools/back-icon.svg"),
|
|
dimensions: { x: 0.0069, y: 0.0107 },
|
|
localPosition: {
|
|
x: -MENU_HEADER_HEADING_PROPERTIES.dimensions.x / 2 + 0.0118 + 0.0069 / 2,
|
|
y: 0,
|
|
z: MENU_HEADER_HEADING_PROPERTIES.dimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.lightGrayText,
|
|
alpha: 1.0,
|
|
emissive: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: true
|
|
},
|
|
|
|
MENU_HEADER_TITLE_PROPERTIES = {
|
|
url: Script.resolvePath("../assets/tools/tools-heading.svg"),
|
|
scale: 0.0327,
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0,
|
|
z: MENU_HEADER_HEADING_PROPERTIES.dimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.white,
|
|
alpha: 1.0,
|
|
emissive: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: true
|
|
},
|
|
|
|
MENU_HEADER_TITLE_BACK_URL = Script.resolvePath("../assets/tools/back-heading.svg"),
|
|
MENU_HEADER_TITLE_BACK_SCALE = 0.0256,
|
|
|
|
MENU_HEADER_ICON_OFFSET = {
|
|
// Default right center position for header tool icons.
|
|
x: MENU_HEADER_HEADING_PROPERTIES.dimensions.x / 2 - 0.0118,
|
|
y: 0,
|
|
z: MENU_HEADER_HEADING_PROPERTIES.dimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
|
|
MENU_HEADER_ICON_PROPERTIES = {
|
|
url: Script.resolvePath("../assets/tools/color-icon.svg"), // Initial value so that the overlay is initialized OK.
|
|
dimensions: { x: 0.01, y: 0.01 }, // Ditto.
|
|
localPosition: Vec3.ZERO, // Ditto.
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.lightGrayText,
|
|
alpha: 1.0,
|
|
emissive: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: false
|
|
},
|
|
|
|
MENU_PANEL_PROPERTIES = {
|
|
dimensions: UIT.dimensions.panel,
|
|
localPosition: { x: 0, y: (UIT.dimensions.panel.y - UIT.dimensions.canvas.y) / 2, z: UIT.dimensions.panel.z / 2 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGray,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
|
|
EMPTY_SWATCH_COLOR = UIT.colors.baseGrayShadow,
|
|
SWATCH_HIGHLIGHT_DELTA = 0.0020,
|
|
|
|
UI_ELEMENTS = {
|
|
"menuButton": {
|
|
overlay: "cube", // Invisible cube for hit area.
|
|
properties: {
|
|
dimensions: UIT.dimensions.itemCollisionZone,
|
|
localRotation: Quat.ZERO,
|
|
alpha: 0.0, // Invisible.
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true // So that laser intersects.
|
|
},
|
|
hoverButton: {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cylinder",
|
|
dimensions: {
|
|
x: UIT.dimensions.menuButtonDimensions.x,
|
|
y: UIT.dimensions.menuButtonDimensions.z,
|
|
z: UIT.dimensions.menuButtonDimensions.y
|
|
},
|
|
localPosition: UIT.dimensions.menuButtonIconOffset,
|
|
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: -90 }),
|
|
color: UIT.colors.greenHighlight,
|
|
alpha: 1.0,
|
|
emissive: true, // TODO: This has no effect.
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: false
|
|
}
|
|
},
|
|
icon: {
|
|
// Relative to hoverButton.
|
|
type: "image",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.menuButtonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset,
|
|
z: 0
|
|
},
|
|
localRotation: Quat.fromVec3Degrees({ x: -90, y: 90, z: 0 }),
|
|
color: UIT.colors.lightGrayText
|
|
},
|
|
highlightColor: UIT.colors.darkGray
|
|
},
|
|
label: {
|
|
// Relative to menuButton.
|
|
type: "image",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.menuButtonLabelYOffset,
|
|
z: -UIT.dimensions.itemCollisionZone.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white
|
|
}
|
|
},
|
|
sublabel: {
|
|
// Relative to menuButton.
|
|
type: "image",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.menuButtonSublabelYOffset,
|
|
z: -UIT.dimensions.itemCollisionZone.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.lightGrayText
|
|
}
|
|
}
|
|
},
|
|
"button": {
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: UIT.dimensions.buttonDimensions,
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
label: {
|
|
// Relative to button.
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white
|
|
}
|
|
},
|
|
"toggleButton": {
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: UIT.dimensions.buttonDimensions,
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
onColor: UIT.colors.greenHighlight,
|
|
offColor: UIT.colors.baseGrayShadow,
|
|
onHoverColor: UIT.colors.greenShadow,
|
|
offHoverColor: UIT.colors.darkGray,
|
|
label: {
|
|
// Relative to toggleButton.
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white
|
|
},
|
|
sublabel: {
|
|
// Relative to toggleButton.
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.lightGray
|
|
}
|
|
/*
|
|
onSublabel: { } // Optional properties to update sublabel with.
|
|
offSublabel: { } // Optional properties to update sublabel with.
|
|
*/
|
|
},
|
|
"swatch": {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cylinder",
|
|
dimensions: { x: 0.0294, y: UIT.dimensions.buttonDimensions.z, z: 0.0294 },
|
|
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: -90 }),
|
|
color: EMPTY_SWATCH_COLOR,
|
|
emissive: true, // TODO: This has no effect.
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
}
|
|
// Must have a setting property in order to function property.
|
|
// Setting property may optionally include a defaultValue.
|
|
// A setting value of "" means that the swatch is unpopulated.
|
|
},
|
|
"swatchHighlight": {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cylinder",
|
|
dimensions: {
|
|
x: 0.0294 + SWATCH_HIGHLIGHT_DELTA,
|
|
y: UIT.dimensions.buttonDimensions.z,
|
|
z: 0.0294 + SWATCH_HIGHLIGHT_DELTA
|
|
},
|
|
localRotation: Quat.ZERO, // Relative to swatch.
|
|
localPosition: { x: 0, y: -0.0001, z: 0 },
|
|
color: UIT.colors.faintGray,
|
|
emissive: true, // TODO: This has no effect.
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: false
|
|
}
|
|
|
|
},
|
|
"square": {
|
|
overlay: "cube", // Emulate a 2D square with a cube.
|
|
properties: {
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
},
|
|
"image": {
|
|
overlay: "image3d",
|
|
properties: {
|
|
localPosition: { x: 0, y: 0, z: 0 },
|
|
localRotation: Quat.ZERO,
|
|
alpha: 1.0,
|
|
emissive: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: true
|
|
}
|
|
},
|
|
"horizontalRule": {
|
|
overlay: "image3d",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/horizontal-rule.svg"),
|
|
dimensions: { x: UIT.dimensions.panel.x - 2 * UIT.dimensions.leftMargin, y: 0.001 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: true
|
|
}
|
|
},
|
|
"sphere": {
|
|
overlay: "sphere",
|
|
properties: {
|
|
dimensions: { x: 0.01, y: 0.01, z: 0.01 },
|
|
localRotation: Quat.ZERO,
|
|
color: { red: 192, green: 192, blue: 192 },
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
},
|
|
"barSlider": {
|
|
// Invisible cube to catch laser intersections; value and remainder entities move inside.
|
|
// Values range between 0.0 and 1.0.
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.02, y: 0.1, z: 0.01 },
|
|
localRotation: Quat.ZERO,
|
|
alpha: 0.0, // Invisible.
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true // Catch laser intersections.
|
|
},
|
|
label: {
|
|
// Relative to barSlider.
|
|
color: UIT.colors.white
|
|
},
|
|
zeroIndicator: {
|
|
overlay: "image3d",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/horizontal-rule.svg"),
|
|
dimensions: { x: 0.02, y: 0.001 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.lightGrayText,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
isFacingAvatar: false,
|
|
visible: true
|
|
}
|
|
},
|
|
sliderValue: {
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.02, y: 0.03, z: 0.01 },
|
|
localPosition: { x: 0, y: 0.035, z: 0 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.greenHighlight,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
},
|
|
sliderRemainder: {
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.02, y: 0.07, z: 0.01 },
|
|
localPosition: { x: 0, y: -0.015, z: 0 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
}
|
|
},
|
|
"imageSlider": { // Values range between 0.0 and 1.0.
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.0160, y: 0.1229, z: UIT.dimensions.buttonDimensions.z },
|
|
localRotation: Quat.ZERO,
|
|
color: { red: 128, green: 128, blue: 128 },
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
useBaseColor: false,
|
|
imageURL: null,
|
|
imageOverlayURL: null
|
|
},
|
|
"sliderPointer": {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cone",
|
|
dimensions: { x: 0.005, y: 0.005, z: 0.005 },
|
|
localRotation: Quat.fromVec3Degrees({ x: 0, y: 0, z: -90 }),
|
|
color: { red: 180, green: 180, blue: 180 },
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
},
|
|
"colorCircle": {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cylinder",
|
|
dimensions: { x: 0.1229, y: UIT.dimensions.buttonDimensions.z, z: 0.1229 },
|
|
localRotation: Quat.fromVec3Degrees({ x: 90, y: 0, z: -90 }),
|
|
color: { red: 128, green: 128, blue: 128 },
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
imageURL: null,
|
|
imageOverlayURL: null
|
|
},
|
|
"circlePointer": {
|
|
overlay: "shape",
|
|
properties: {
|
|
shape: "Cone",
|
|
dimensions: { x: 0.005, y: 0.005, z: 0.005 },
|
|
localRotation: Quat.fromVec3Degrees({ x: 0, y: 0, z: -90 }),
|
|
color: { red: 180, green: 180, blue: 180 },
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: true,
|
|
visible: true
|
|
}
|
|
},
|
|
"picklist": {
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.06, y: 0.02, z: 0.01 },
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: true
|
|
},
|
|
label: {
|
|
// Relative to picklist.
|
|
color: UIT.colors.white
|
|
}
|
|
},
|
|
"picklistItem": { // Note: When using, declare before picklist item that it's being used in.
|
|
overlay: "cube",
|
|
properties: {
|
|
dimensions: { x: 0.1416, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: Vec3.ZERO,
|
|
localRotation: Quat.ZERO,
|
|
color: UIT.colors.baseGrayShadow,
|
|
alpha: 1.0,
|
|
solid: true,
|
|
ignoreRayIntersection: false,
|
|
visible: false
|
|
},
|
|
label: {
|
|
// Relative to picklistItem.
|
|
color: UIT.colors.white
|
|
}
|
|
}
|
|
},
|
|
|
|
PICKLIST_UP_ARROW = Script.resolvePath("../assets/tools/common/up-arrow.svg"),
|
|
PICKLIST_DOWN_ARROW = Script.resolvePath("../assets/tools/common/down-arrow.svg"),
|
|
|
|
BUTTON_UI_ELEMENTS = ["button", "menuButton", "toggleButton", "swatch"],
|
|
|
|
MENU_HOVER_DELTA = { x: 0, y: 0, z: 0.006 },
|
|
OPTION_HOVER_DELTA = { x: 0, y: 0, z: 0.002 },
|
|
PICKLIST_HOVER_DELTA = { x: 0, y: 0, z: 0.006 },
|
|
BUTTON_PRESS_DELTA = { x: 0, y: 0, z: -0.002 },
|
|
|
|
MIN_BAR_SLIDER_DIMENSION = 0.0001, // Avoid visual artifact for 0 slider values.
|
|
|
|
PHYSICS_SLIDER_PRESETS = {
|
|
// Slider values in the range 0.0 to 1.0.
|
|
// Note: Friction values give the desired linear and angular damping values but friction values are a somewhat out,
|
|
// especially for the balloon.
|
|
presetDefault: { gravity: 0.5, bounce: 0.5, friction: 0.5, density: 0.5 },
|
|
presetLead: { gravity: 0.5, bounce: 0.0, friction: 0.5, density: 1.0 },
|
|
presetWood: { gravity: 0.5, bounce: 0.4, friction: 0.5, density: 0.5 },
|
|
presetIce: { gravity: 0.5, bounce: 0.99, friction: 0.151004, density: 0.349485 },
|
|
presetRubber: { gravity: 0.5, bounce: 0.99, friction: 0.5, density: 0.5 },
|
|
presetCotton: { gravity: 0.587303, bounce: 0.0, friction: 0.931878, density: 0.0 },
|
|
presetTumbleweed: { gravity: 0.595893, bounce: 0.7, friction: 0.5, density: 0.0 },
|
|
presetZeroG: { gravity: 0.596844, bounce: 0.5, friction: 0.5, density: 0.5 },
|
|
presetBalloon: { gravity: 0.606313, bounce: 0.99, friction: 0.151004, density: 0.0 }
|
|
},
|
|
|
|
OPTONS_PANELS = {
|
|
colorOptions: [
|
|
{
|
|
id: "colorSwatchesLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/color/swatches-label.svg"),
|
|
scale: 0.0345,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0345 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "colorRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.001 },
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0668 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch1",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0935,
|
|
y: 0.0513 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch1Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch2",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0561,
|
|
y: 0.0513 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch2Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch3",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0935,
|
|
y: 0.0153 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch3Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch4",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0561,
|
|
y: 0.0153 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch4Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch5",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0935,
|
|
y: -0.0207 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch5Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSwatch6",
|
|
type: "swatch",
|
|
properties: {
|
|
localPosition: {
|
|
x: -0.0561,
|
|
y: -0.0207 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.swatch6Color",
|
|
property: "color"
|
|
},
|
|
command: {
|
|
method: "setColorPerSwatch"
|
|
},
|
|
clear: {
|
|
method: "clearSwatch"
|
|
}
|
|
},
|
|
{
|
|
id: "colorRule2",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.001 },
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0668 / 2,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0481 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "colorCircle",
|
|
type: "colorCircle",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0.04675,
|
|
y: 0.01655 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
imageURL: Script.resolvePath("../assets/tools/color/color-circle.png"),
|
|
imageOverlayURL: Script.resolvePath("../assets/tools/color/color-circle-black.png"),
|
|
command: {
|
|
method: "setColorPerCircle"
|
|
}
|
|
},
|
|
{
|
|
id: "colorSlider",
|
|
type: "imageSlider",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0.04675,
|
|
y: -0.064 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
},
|
|
localRotation: Quat.fromVec3Degrees({ x: 0, y: 0, z: -90 })
|
|
},
|
|
useBaseColor: true,
|
|
imageURL: Script.resolvePath("../assets/tools/color/slider-white.png"),
|
|
// Alpha PNG created by overlaying two black-to-transparent gradients in order to achieve visual effect.
|
|
imageOverlayURL: Script.resolvePath("../assets/tools/color/slider-alpha.png"),
|
|
command: {
|
|
method: "setColorPerSlider"
|
|
}
|
|
},
|
|
{
|
|
id: "pickColor",
|
|
type: "toggleButton",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0935,
|
|
y: -0.064 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/color/pick-color-label.svg"),
|
|
scale: 0.0120
|
|
},
|
|
command: {
|
|
method: "togglePickColor"
|
|
}
|
|
},
|
|
{
|
|
id: "currentColor",
|
|
type: "square",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.0280, z: UIT.dimensions.imageOverlayOffset },
|
|
localPosition: {
|
|
x: -0.0561,
|
|
y: -0.064 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.colorTool.currentColor",
|
|
property: "color",
|
|
defaultValue: { red: 255, green: 255, blue: 255 },
|
|
command: "setPickColor"
|
|
}
|
|
}
|
|
],
|
|
scaleOptions: [
|
|
{
|
|
id: "stretchActionsLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/common/actions-label.svg"),
|
|
scale: 0.0276,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0276 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "stretchRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "stretchFinishButton",
|
|
type: "button",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - UIT.dimensions.buttonDimensions.y / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/common/finish-label.svg"),
|
|
scale: 0.0318
|
|
},
|
|
command: {
|
|
method: "clearTool"
|
|
}
|
|
},
|
|
{
|
|
id: "stretchRule2",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.1197,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "stretchInfoIcon",
|
|
type: "image",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/common/info-icon.svg"),
|
|
dimensions: { x: 0.0321, y: 0.0320 },
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0321 / 2,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0200 + 0.0320 / 2 + UIT.dimensions.footerHeight,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white // Icon SVG is already lightGray color.
|
|
}
|
|
},
|
|
{
|
|
id: "stretchInfo",
|
|
type: "image",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/stretch/info-text.svg"),
|
|
scale: 0.1340,
|
|
localPosition: { // Vertically center on info icon.
|
|
x: -UIT.dimensions.panel.x / 2 + 0.0679 + 0.1340 / 2,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0200 + 0.0320 / 2 + UIT.dimensions.footerHeight,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white
|
|
}
|
|
}
|
|
],
|
|
cloneOptions: [
|
|
{
|
|
id: "cloneActionsLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/common/actions-label.svg"),
|
|
scale: 0.0276,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0276 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "cloneRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "cloneFinishButton",
|
|
type: "button",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - UIT.dimensions.buttonDimensions.y / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/common/finish-label.svg"),
|
|
scale: 0.0318
|
|
},
|
|
command: {
|
|
method: "clearTool"
|
|
}
|
|
}
|
|
],
|
|
groupOptions: [
|
|
{
|
|
id: "groupActionsLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/common/actions-label.svg"),
|
|
scale: 0.0276,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0276 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "groupRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "groupButton",
|
|
type: "button",
|
|
properties: {
|
|
dimensions: {
|
|
x: UIT.dimensions.buttonDimensions.x,
|
|
y: 0.0400,
|
|
z: UIT.dimensions.buttonDimensions.z
|
|
},
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - 0.0400 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
},
|
|
color: UIT.colors.baseGrayShadow
|
|
},
|
|
enabledColor: UIT.colors.greenHighlight,
|
|
highlightColor: UIT.colors.greenShadow,
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/group/group-label.svg"),
|
|
scale: 0.0351,
|
|
color: UIT.colors.baseGray
|
|
},
|
|
labelEnabledColor: UIT.colors.white,
|
|
callback: {
|
|
method: "groupButton"
|
|
}
|
|
},
|
|
{
|
|
id: "ungroupButton",
|
|
type: "button",
|
|
properties: {
|
|
dimensions: { x: UIT.dimensions.buttonDimensions.x, y: 0.0400, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - 0.0400 - 0.0040 - 0.0400 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
},
|
|
color: UIT.colors.baseGrayShadow
|
|
},
|
|
enabledColor: UIT.colors.redHighlight,
|
|
highlightColor: UIT.colors.redAccent,
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/group/ungroup-label.svg"),
|
|
scale: 0.0496,
|
|
color: UIT.colors.baseGray
|
|
},
|
|
labelEnabledColor: UIT.colors.white,
|
|
callback: {
|
|
method: "ungroupButton"
|
|
}
|
|
},
|
|
{
|
|
id: "groupRule2",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0603,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "groupSelectionBoxButton",
|
|
type: "toggleButton",
|
|
properties: {
|
|
dimensions: { x: 0.1042, y: 0.0400, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0040 - 0.1042 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - 2 * 0.0400 - 0.0160 - 0.0400 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/group/selection-box-label.svg"),
|
|
scale: 0.0161
|
|
},
|
|
command: {
|
|
method: "toggleGroupSelectionBox"
|
|
}
|
|
},
|
|
{
|
|
id: "clearGroupingButton",
|
|
type: "button",
|
|
properties: {
|
|
dimensions: { x: 0.1042, y: 0.0400, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: 0.0040 + 0.1042 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - 2 * 0.0400 - 0.0160 - 0.0400 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
},
|
|
color: UIT.colors.baseGrayShadow
|
|
},
|
|
enabledColor: UIT.colors.greenHighlight,
|
|
highlightColor: UIT.colors.greenShadow,
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/group/clear-label.svg"),
|
|
scale: 0.0314,
|
|
color: UIT.colors.baseGray
|
|
},
|
|
labelEnabledColor: UIT.colors.white,
|
|
enabled: false,
|
|
command: {
|
|
method: "clearGroupSelection"
|
|
}
|
|
}
|
|
],
|
|
physicsOptions: [
|
|
{
|
|
id: "physicsPropertiesLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/physics/properties-label.svg"),
|
|
scale: 0.0376,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0376 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "physicsRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.001 },
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0668 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "gravityToggle",
|
|
type: "toggleButton",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0748,
|
|
y: 0.0480 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/gravity-label.svg"),
|
|
scale: 0.0240,
|
|
color: UIT.colors.white
|
|
},
|
|
sublabel: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104,
|
|
color: UIT.colors.white // SVG has gray color.
|
|
},
|
|
onSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/on-label.svg"),
|
|
scale: 0.0081
|
|
},
|
|
offSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.gravityOn",
|
|
defaultValue: false,
|
|
callback: "setGravityOn"
|
|
},
|
|
command: {
|
|
method: "setGravityOn"
|
|
}
|
|
},
|
|
{
|
|
id: "collideToggle",
|
|
type: "toggleButton",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0748,
|
|
y: 0.0120 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/collisions-label.svg"),
|
|
scale: 0.0338,
|
|
color: UIT.colors.white
|
|
},
|
|
sublabel: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104,
|
|
color: UIT.colors.white // SVG has gray color.
|
|
},
|
|
onSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/on-label.svg"),
|
|
scale: 0.0081
|
|
},
|
|
offSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.collideOn",
|
|
defaultValue: true,
|
|
callback: "setCollideOn"
|
|
},
|
|
command: {
|
|
method: "setCollideOn"
|
|
}
|
|
},
|
|
{
|
|
id: "grabToggle",
|
|
type: "toggleButton",
|
|
properties: {
|
|
dimensions: { x: 0.0668, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0748,
|
|
y: -0.0240 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: 0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/grabbable-label.svg"),
|
|
scale: 0.0334,
|
|
color: UIT.colors.white
|
|
},
|
|
sublabel: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.0034,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104,
|
|
color: UIT.colors.white // SVG has gray color.
|
|
},
|
|
onSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/on-label.svg"),
|
|
scale: 0.0081
|
|
},
|
|
offSublabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/buttons/off-label.svg"),
|
|
scale: 0.0104
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.grabOn",
|
|
defaultValue: false,
|
|
callback: "setGrabOn"
|
|
},
|
|
command: {
|
|
method: "setGrabOn"
|
|
}
|
|
},
|
|
|
|
{
|
|
id: "physicsPresetsLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/physics/presets-label.svg"),
|
|
scale: 0.0270,
|
|
localPosition: {
|
|
x: UIT.dimensions.panel.x / 2 - UIT.dimensions.rightMargin - 0.1416 + 0.0270 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "physicsRule2",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
dimensions: { x: 0.1416, y: 0.001 },
|
|
localPosition: {
|
|
x: UIT.dimensions.panel.x / 2 - UIT.dimensions.rightMargin - 0.1416 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "presetDefault",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/default-label.svg"),
|
|
scale: 0.0436,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0436 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: {
|
|
method: "pickPhysicsPreset",
|
|
value: "default"
|
|
}
|
|
},
|
|
{
|
|
id: "presetLead",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/lead-label.svg"),
|
|
scale: 0.0243,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0243 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetWood",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/wood-label.svg"),
|
|
scale: 0.0316,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0316 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetIce",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/ice-label.svg"),
|
|
scale: 0.0144,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0144 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetRubber",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/rubber-label.svg"),
|
|
scale: 0.0400,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0400 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetCotton",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/cotton-label.svg"),
|
|
scale: 0.0393,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0393 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetTumbleweed",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/tumbleweed-label.svg"),
|
|
scale: 0.0687,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0687 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetZeroG",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/zero-g-label.svg"),
|
|
scale: 0.0375,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0375 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "presetBalloon",
|
|
type: "picklistItem",
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/balloon-label.svg"),
|
|
scale: 0.0459,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0459 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
command: { method: "pickPhysicsPreset" }
|
|
},
|
|
{
|
|
id: "physicsPresets",
|
|
type: "picklist",
|
|
properties: {
|
|
dimensions: { x: 0.1416, y: 0.0280, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: UIT.dimensions.panel.x / 2 - UIT.dimensions.rightMargin - 0.1416 / 2,
|
|
y: 0.0480 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/default-label.svg"),
|
|
scale: 0.0436,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0436 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
sublabel: {
|
|
url: Script.resolvePath("../assets/tools/common/down-arrow.svg"),
|
|
scale: 0.0080,
|
|
localPosition: {
|
|
x: 0.1416 / 2 - 0.0108 - 0.0080 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white // SVG is colored baseGrayHighlight
|
|
},
|
|
customLabel: {
|
|
url: Script.resolvePath("../assets/tools/physics/presets/custom-label.svg"),
|
|
scale: 0.0522,
|
|
localPosition: {
|
|
x: -0.1416 / 2 + 0.017 + 0.0522 / 2,
|
|
y: 0,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.physicsPreset",
|
|
defaultValue: "presetDefault"
|
|
},
|
|
command: {
|
|
method: "togglePhysicsPresets"
|
|
},
|
|
items: [
|
|
"presetDefault",
|
|
"presetLead",
|
|
"presetWood",
|
|
"presetIce",
|
|
"presetRubber",
|
|
"presetCotton",
|
|
"presetTumbleweed",
|
|
"presetZeroG",
|
|
"presetBalloon"
|
|
]
|
|
},
|
|
|
|
{
|
|
id: "gravitySlider",
|
|
type: "barSlider",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.1000, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: -0.0187,
|
|
y: -0.0240 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.04375,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/sliders/gravity-label.svg"),
|
|
scale: 0.0240
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.gravity",
|
|
defaultValue: 0.5,
|
|
callback: "setGravity"
|
|
},
|
|
command: {
|
|
method: "setGravity"
|
|
}
|
|
},
|
|
{
|
|
id: "bounceSlider",
|
|
type: "barSlider",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.1000, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: 0.0187,
|
|
y: -0.0240 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.04375,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/sliders/bounce-label.svg"),
|
|
scale: 0.0233
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.bounce",
|
|
defaultValue: 0.5,
|
|
callback: "setBounce"
|
|
},
|
|
command: {
|
|
method: "setBounce"
|
|
}
|
|
},
|
|
{
|
|
id: "frictionSlider",
|
|
type: "barSlider",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.1000, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: 0.0561,
|
|
y: -0.0240 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.04375,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/sliders/friction-label.svg"),
|
|
scale: 0.0258
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.friction",
|
|
defaultValue: 0.5,
|
|
callback: "setFriction"
|
|
},
|
|
command: {
|
|
method: "setFriction"
|
|
}
|
|
},
|
|
{
|
|
id: "densitySlider",
|
|
type: "barSlider",
|
|
properties: {
|
|
dimensions: { x: 0.0294, y: 0.1000, z: UIT.dimensions.buttonDimensions.z },
|
|
localPosition: {
|
|
x: 0.0935,
|
|
y: -0.0240 + UIT.dimensions.footerHeight / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -0.04375,
|
|
z: UIT.dimensions.buttonDimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
url: Script.resolvePath("../assets/tools/physics/sliders/density-label.svg"),
|
|
scale: 0.0241
|
|
},
|
|
setting: {
|
|
key: "VREdit.physicsTool.density",
|
|
defaultValue: 0.5,
|
|
callback: "setDensity"
|
|
},
|
|
command: {
|
|
method: "setDensity"
|
|
}
|
|
}
|
|
],
|
|
deleteOptions: [
|
|
{
|
|
id: "deleteActionsLabel",
|
|
type: "image",
|
|
properties: {
|
|
color: UIT.colors.white,
|
|
url: Script.resolvePath("../assets/tools/common/actions-label.svg"),
|
|
scale: 0.0276,
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0276 / 2,
|
|
y: UIT.dimensions.panel.y / 2 - UIT.dimensions.topMargin - 0.0047 / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "deleteRule1",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0199,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "deleteFinishButton",
|
|
type: "button",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.0280 - UIT.dimensions.buttonDimensions.y / 2,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.buttonDimensions.z / 2
|
|
}
|
|
},
|
|
label: {
|
|
url: Script.resolvePath("../assets/tools/common/finish-label.svg"),
|
|
scale: 0.0318
|
|
},
|
|
command: {
|
|
method: "clearTool"
|
|
}
|
|
},
|
|
{
|
|
id: "deleteRule2",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: UIT.dimensions.panel.y / 2 - 0.1197,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "deleteInfoIcon",
|
|
type: "image",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/common/info-icon.svg"),
|
|
dimensions: { x: 0.0321, y: 0.0320 },
|
|
localPosition: {
|
|
x: -UIT.dimensions.panel.x / 2 + UIT.dimensions.leftMargin + 0.0321 / 2,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0200 + 0.0320 / 2 + UIT.dimensions.footerHeight,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white // Icon SVG is already lightGray color.
|
|
}
|
|
},
|
|
{
|
|
id: "deleteInfo",
|
|
type: "image",
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/delete/info-text.svg"),
|
|
scale: 0.1416,
|
|
localPosition: { // Vertically off-center w.r.t. info icon.
|
|
x: -UIT.dimensions.panel.x / 2 + 0.0679 + 0.1340 / 2,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0200 + 0.0240 / 2 + 0.0063 / 2 + UIT.dimensions.footerHeight,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
},
|
|
color: UIT.colors.white
|
|
}
|
|
}
|
|
]
|
|
},
|
|
|
|
MENU_ITEM_XS = [-0.08415, -0.02805, 0.02805, 0.08415],
|
|
MENU_ITEM_YS = [0.086, 0.030, -0.026, -0.082],
|
|
|
|
MENU_ITEMS = [
|
|
{
|
|
id: "colorButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[0],
|
|
y: MENU_ITEM_YS[0],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/color-icon.svg"),
|
|
dimensions: { x: 0.0165, y: 0.0187 }
|
|
},
|
|
headerOffset: { x: -0.00825, y: 0.0020, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/color-label.svg"),
|
|
scale: 0.0241
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/color-tool-heading.svg"),
|
|
scale: 0.0631
|
|
},
|
|
toolOptions: "colorOptions",
|
|
callback: {
|
|
method: "colorTool",
|
|
parameter: "currentColor.color"
|
|
}
|
|
},
|
|
{
|
|
id: "scaleButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[1],
|
|
y: MENU_ITEM_YS[0],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/stretch-icon.svg"),
|
|
dimensions: { x: 0.0167, y: 0.0167 }
|
|
},
|
|
headerOffset: { x: -0.00835, y: 0, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/stretch-label.svg"),
|
|
scale: 0.0311
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/stretch-tool-heading.svg"),
|
|
scale: 0.0737
|
|
},
|
|
toolOptions: "scaleOptions",
|
|
callback: {
|
|
method: "scaleTool"
|
|
}
|
|
},
|
|
{
|
|
id: "cloneButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[2],
|
|
y: MENU_ITEM_YS[0],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/clone-icon.svg"),
|
|
dimensions: { x: 0.0154, y: 0.0155 }
|
|
},
|
|
headerOffset: { x: -0.0077, y: 0, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/clone-label.svg"),
|
|
scale: 0.0231
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/clone-tool-heading.svg"),
|
|
scale: 0.0621
|
|
},
|
|
toolOptions: "cloneOptions",
|
|
callback: {
|
|
method: "cloneTool"
|
|
}
|
|
},
|
|
{
|
|
id: "groupButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[3],
|
|
y: MENU_ITEM_YS[0],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/group-icon.svg"),
|
|
dimensions: { x: 0.0161, y: 0.0114 }
|
|
},
|
|
headerOffset: { x: -0.00805, y: 0, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/group-label.svg"),
|
|
scale: 0.0250
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/group-tool-heading.svg"),
|
|
scale: 0.0647
|
|
},
|
|
toolOptions: "groupOptions",
|
|
callback: {
|
|
method: "groupTool"
|
|
}
|
|
},
|
|
{
|
|
id: "physicsButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[0],
|
|
y: MENU_ITEM_YS[1],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/physics-icon.svg"),
|
|
dimensions: { x: 0.0180, y: 0.0198 }
|
|
},
|
|
headerOffset: { x: -0.009, y: 0, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/physics-label.svg"),
|
|
scale: 0.0297
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/physics-tool-heading.svg"),
|
|
scale: 0.0712
|
|
},
|
|
toolOptions: "physicsOptions",
|
|
callback: {
|
|
method: "physicsTool"
|
|
}
|
|
},
|
|
{
|
|
id: "deleteButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[1],
|
|
y: MENU_ITEM_YS[1],
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/delete-icon.svg"),
|
|
dimensions: { x: 0.0161, y: 0.0161 }
|
|
},
|
|
headerOffset: { x: -0.00805, y: 0, z: 0 }
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/delete-label.svg"),
|
|
scale: 0.0254
|
|
}
|
|
},
|
|
sublabel: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/tool-label.svg"),
|
|
scale: 0.0152
|
|
}
|
|
},
|
|
title: {
|
|
url: Script.resolvePath("../assets/tools/delete-tool-heading.svg"),
|
|
scale: 0.0653
|
|
},
|
|
toolOptions: "deleteOptions",
|
|
callback: {
|
|
method: "deleteTool"
|
|
}
|
|
}
|
|
],
|
|
COLOR_TOOL = 0, // Indexes of corresponding MENU_ITEMS item.
|
|
SCALE_TOOL = 1,
|
|
CLONE_TOOL = 2,
|
|
GROUP_TOOL = 3,
|
|
PHYSICS_TOOL = 4,
|
|
DELETE_TOOL = 5,
|
|
|
|
FOOTER_ITEMS = [
|
|
{
|
|
id: "footerRule",
|
|
type: "horizontalRule",
|
|
properties: {
|
|
localPosition: {
|
|
x: 0,
|
|
y: -UIT.dimensions.panel.y / 2 + 0.0600,
|
|
z: UIT.dimensions.panel.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
}
|
|
}
|
|
},
|
|
{
|
|
id: "undoButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[2],
|
|
y: MENU_ITEM_YS[3] - 0.008, // Allow space for horizontal rule and Line up with Create palette row.
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/undo-icon.svg"),
|
|
dimensions: { x: 0.0180, y: 0.0186 }
|
|
}
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/undo-label.svg"),
|
|
scale: 0.0205
|
|
}
|
|
},
|
|
callback: {
|
|
method: "undoAction"
|
|
}
|
|
},
|
|
{
|
|
id: "redoButton",
|
|
type: "menuButton",
|
|
properties: {
|
|
localPosition: {
|
|
x: MENU_ITEM_XS[3],
|
|
y: MENU_ITEM_YS[3] - 0.008,
|
|
z: UIT.dimensions.panel.z / 2 + UI_ELEMENTS.menuButton.properties.dimensions.z / 2
|
|
}
|
|
},
|
|
icon: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/redo-icon.svg"),
|
|
dimensions: { x: 0.0180, y: 0.0186 }
|
|
}
|
|
},
|
|
label: {
|
|
properties: {
|
|
url: Script.resolvePath("../assets/tools/redo-label.svg"),
|
|
scale: 0.0192
|
|
}
|
|
},
|
|
callback: {
|
|
method: "redoAction"
|
|
}
|
|
}
|
|
],
|
|
|
|
NONE = -1,
|
|
|
|
optionsItems,
|
|
intersectionOverlays,
|
|
intersectionEnabled,
|
|
hoveredItem,
|
|
hoveredSourceOverlays,
|
|
hoveredSourceItems,
|
|
hoveredElementType = null,
|
|
isHoveringButtonElement,
|
|
isPicklistOpen,
|
|
pressedItem = null,
|
|
pressedSource = null,
|
|
isPicklistPressed,
|
|
isPicklistItemPressed,
|
|
isTriggerClicked,
|
|
wasTriggerClicked,
|
|
isGripClicked,
|
|
|
|
isGroupButtonEnabled,
|
|
isUngroupButtonEnabled,
|
|
isClearGroupingButtonEnabled,
|
|
groupButtonIndex,
|
|
ungroupButtonIndex,
|
|
clearGroupingButtonIndex,
|
|
|
|
hsvControl = {
|
|
hsv: { h: 0, s: 0, v: 0 },
|
|
circle: {},
|
|
slider: {}
|
|
},
|
|
|
|
isDisplaying = false,
|
|
isVisible = true,
|
|
isOptionsOpen = false,
|
|
isOptionsHeadingRaised = false,
|
|
optionsHeadingURL,
|
|
optionsHeadingScale,
|
|
|
|
otherSide,
|
|
|
|
// References.
|
|
controlHand,
|
|
|
|
// Forward declarations.
|
|
doCommand;
|
|
|
|
if (!(this instanceof ToolsMenu)) {
|
|
return new ToolsMenu();
|
|
}
|
|
|
|
controlHand = side === LEFT_HAND ? rightInputs.hand() : leftInputs.hand();
|
|
|
|
function setHand(hand) {
|
|
// Assumes UI is not displaying.
|
|
side = hand;
|
|
if (side === LEFT_HAND) {
|
|
controlHand = rightInputs.hand();
|
|
attachmentJointName = "LeftHand";
|
|
panelLateralOffset = -UIT.dimensions.handLateralOffset;
|
|
menuOriginLocalPosition = PANEL_ORIGIN_POSITION_LEFT_HAND;
|
|
menuOriginLocalRotation = PANEL_ORIGIN_ROTATION_LEFT_HAND;
|
|
} else {
|
|
controlHand = leftInputs.hand();
|
|
attachmentJointName = "RightHand";
|
|
panelLateralOffset = UIT.dimensions.handLateralOffset;
|
|
menuOriginLocalPosition = PANEL_ORIGIN_POSITION_RIGHT_HAND;
|
|
menuOriginLocalRotation = PANEL_ORIGIN_ROTATION_RIGHT_HAND;
|
|
}
|
|
otherSide = (side + 1) % 2;
|
|
}
|
|
|
|
setHand(side);
|
|
|
|
function getOverlayIDs() {
|
|
return [menuHeaderOverlay, menuPanelOverlay].concat(menuOverlays).concat(optionsOverlays).concat(footerOverlays);
|
|
}
|
|
|
|
function getIconInfo(tool) {
|
|
// Provides details of tool icon, label, and sublabel images for the specified tool.
|
|
var sublabelProperties;
|
|
|
|
sublabelProperties = Object.clone(UI_ELEMENTS.menuButton.sublabel);
|
|
sublabelProperties = Object.merge(sublabelProperties, MENU_ITEMS[tool].sublabel);
|
|
return {
|
|
icon: MENU_ITEMS[tool].icon,
|
|
label: MENU_ITEMS[tool].label,
|
|
sublabel: sublabelProperties
|
|
};
|
|
}
|
|
|
|
function openMenu() {
|
|
var properties,
|
|
itemID,
|
|
buttonID,
|
|
overlayID,
|
|
i,
|
|
length;
|
|
|
|
// Update header.
|
|
Overlays.editOverlay(menuHeaderBackOverlay, { visible: false });
|
|
Overlays.editOverlay(menuHeaderTitleOverlay, {
|
|
url: MENU_HEADER_TITLE_PROPERTIES.url,
|
|
scale: MENU_HEADER_TITLE_PROPERTIES.scale
|
|
});
|
|
Overlays.editOverlay(menuHeaderIconOverlay, { visible: false });
|
|
|
|
// Display menu items.
|
|
for (i = 0, length = MENU_ITEMS.length; i < length; i++) {
|
|
properties = Object.clone(UI_ELEMENTS[MENU_ITEMS[i].type].properties);
|
|
properties = Object.merge(properties, MENU_ITEMS[i].properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = menuPanelOverlay;
|
|
itemID = Overlays.addOverlay(UI_ELEMENTS[MENU_ITEMS[i].type].overlay, properties);
|
|
menuOverlays[i] = itemID;
|
|
menuEnabled[i] = true;
|
|
|
|
// Collision overlay.
|
|
properties = Object.clone(UI_ELEMENTS.menuButton.hoverButton.properties);
|
|
properties.parentID = itemID;
|
|
buttonID = Overlays.addOverlay(UI_ELEMENTS.menuButton.hoverButton.overlay, properties);
|
|
menuHoverOverlays[i] = buttonID;
|
|
|
|
// Icon.
|
|
properties = Object.clone(UI_ELEMENTS[UI_ELEMENTS.menuButton.icon.type].properties);
|
|
properties = Object.merge(properties, UI_ELEMENTS.menuButton.icon.properties);
|
|
properties = Object.merge(properties, MENU_ITEMS[i].icon.properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = buttonID;
|
|
overlayID = Overlays.addOverlay(UI_ELEMENTS[UI_ELEMENTS.menuButton.icon.type].overlay, properties);
|
|
menuIconOverlays[i] = overlayID;
|
|
|
|
// Label.
|
|
properties = Object.clone(UI_ELEMENTS[UI_ELEMENTS.menuButton.label.type].properties);
|
|
properties = Object.merge(properties, UI_ELEMENTS.menuButton.label.properties);
|
|
properties = Object.merge(properties, MENU_ITEMS[i].label.properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = itemID;
|
|
overlayID = Overlays.addOverlay(UI_ELEMENTS[UI_ELEMENTS.menuButton.label.type].overlay, properties);
|
|
menuLabelOverlays.push(overlayID);
|
|
|
|
// Sublabel.
|
|
if (MENU_ITEMS[i].sublabel) {
|
|
properties = Object.clone(UI_ELEMENTS[UI_ELEMENTS.menuButton.sublabel.type].properties);
|
|
properties = Object.merge(properties, UI_ELEMENTS.menuButton.sublabel.properties);
|
|
properties = Object.merge(properties, MENU_ITEMS[i].sublabel.properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = itemID;
|
|
overlayID = Overlays.addOverlay(UI_ELEMENTS[UI_ELEMENTS.menuButton.sublabel.type].overlay, properties);
|
|
menuLabelOverlays.push(overlayID);
|
|
}
|
|
}
|
|
}
|
|
|
|
function closeMenu() {
|
|
var i,
|
|
length;
|
|
|
|
for (i = 0, length = menuOverlays.length; i < length; i++) {
|
|
Overlays.deleteOverlay(menuOverlays[i]);
|
|
}
|
|
|
|
menuOverlays = [];
|
|
menuHoverOverlays = [];
|
|
menuIconOverlays = [];
|
|
menuLabelOverlays = [];
|
|
menuEnabled = [];
|
|
pressedItem = null;
|
|
}
|
|
|
|
function openOptions(menuItem) {
|
|
var properties,
|
|
childProperties,
|
|
auxiliaryProperties,
|
|
parentID,
|
|
sublabelModifier,
|
|
value,
|
|
imageOffset,
|
|
IMAGE_OFFSET = 0.0005,
|
|
CIRCLE_CURSOR_SPHERE_DIMENSIONS = { x: 0.01, y: 0.01, z: 0.01 },
|
|
CIRCLE_CURSOR_GAP = 0.002,
|
|
id,
|
|
i,
|
|
length;
|
|
|
|
// Remove menu items.
|
|
closeMenu();
|
|
|
|
// Update header.
|
|
optionsHeadingURL = menuItem.title.url;
|
|
optionsHeadingScale = menuItem.title.scale;
|
|
Overlays.editOverlay(menuHeaderBackOverlay, { visible: isVisible });
|
|
Overlays.editOverlay(menuHeaderTitleOverlay, {
|
|
url: optionsHeadingURL,
|
|
scale: optionsHeadingScale
|
|
});
|
|
Overlays.editOverlay(menuHeaderIconOverlay, {
|
|
url: menuItem.icon.properties.url,
|
|
dimensions: menuItem.icon.properties.dimensions,
|
|
localPosition: Vec3.sum(MENU_HEADER_ICON_OFFSET, menuItem.icon.headerOffset),
|
|
visible: isVisible
|
|
});
|
|
|
|
// Open specified options panel.
|
|
optionsItems = OPTONS_PANELS[menuItem.toolOptions];
|
|
parentID = menuPanelOverlay;
|
|
for (i = 0, length = optionsItems.length; i < length; i++) {
|
|
properties = Object.clone(UI_ELEMENTS[optionsItems[i].type].properties);
|
|
if (optionsItems[i].properties) {
|
|
properties = Object.merge(properties, optionsItems[i].properties);
|
|
}
|
|
properties.parentID = parentID;
|
|
sublabelModifier = null;
|
|
if (optionsItems[i].setting) {
|
|
optionsSettings[optionsItems[i].id] = { key: optionsItems[i].setting.key };
|
|
value = Settings.getValue(optionsItems[i].setting.key);
|
|
if (value === "" && optionsItems[i].setting.defaultValue !== undefined) {
|
|
value = optionsItems[i].setting.defaultValue;
|
|
}
|
|
optionsSettings[optionsItems[i].id].value = value;
|
|
if (value !== "") {
|
|
properties[optionsItems[i].setting.property] = value;
|
|
if (optionsItems[i].type === "toggleButton") {
|
|
optionsToggles[optionsItems[i].id] = value;
|
|
properties.color = value
|
|
? UI_ELEMENTS[optionsItems[i].type].onColor
|
|
: UI_ELEMENTS[optionsItems[i].type].offColor;
|
|
if (optionsItems[i].hasOwnProperty("onSublabel")) {
|
|
sublabelModifier = value ? optionsItems[i].onSublabel : optionsItems[i].offSublabel;
|
|
}
|
|
} else if (optionsItems[i].type === "picklist") {
|
|
if (value === "custom") {
|
|
optionsItems[i].label = optionsItems[i].customLabel;
|
|
} else {
|
|
optionsItems[i].label = optionsItems[optionsOverlaysIDs.indexOf(value)].label;
|
|
}
|
|
}
|
|
if (optionsItems[i].setting.command) {
|
|
doCommand(optionsItems[i].setting.command, value);
|
|
}
|
|
if (optionsItems[i].setting.callback) {
|
|
uiCommandCallback(optionsItems[i].setting.callback, value);
|
|
}
|
|
}
|
|
} else if (optionsItems[i].type === "toggleButton") {
|
|
optionsToggles[optionsItems[i].id] = false; // Default to off.
|
|
}
|
|
|
|
optionsOverlays.push(Overlays.addOverlay(UI_ELEMENTS[optionsItems[i].type].overlay, properties));
|
|
optionsOverlaysIDs.push(optionsItems[i].id);
|
|
if (optionsItems[i].label) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties = Object.merge(childProperties, UI_ELEMENTS[optionsItems[i].type].label);
|
|
childProperties = Object.merge(childProperties, optionsItems[i].label);
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
optionsOverlaysLabels[i] = id;
|
|
}
|
|
if (optionsItems[i].sublabel) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties = Object.merge(childProperties, UI_ELEMENTS[optionsItems[i].type].label);
|
|
childProperties = Object.merge(childProperties, optionsItems[i].sublabel);
|
|
if (sublabelModifier) {
|
|
childProperties = Object.merge(childProperties, sublabelModifier);
|
|
}
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
optionsOverlaysSublabels[i] = id;
|
|
}
|
|
|
|
if (optionsItems[i].type === "barSlider") {
|
|
// Value and remainder bars.
|
|
optionsSliderData[i] = {};
|
|
auxiliaryProperties = Object.clone(UI_ELEMENTS.barSlider.sliderValue.properties);
|
|
auxiliaryProperties.localPosition = { x: 0, y: (-0.5 + value / 2) * properties.dimensions.y, z: 0 };
|
|
auxiliaryProperties.dimensions = {
|
|
x: properties.dimensions.x,
|
|
y: Math.max(value * properties.dimensions.y, MIN_BAR_SLIDER_DIMENSION),
|
|
z: properties.dimensions.z
|
|
};
|
|
auxiliaryProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
optionsSliderData[i].value = Overlays.addOverlay(UI_ELEMENTS.barSlider.sliderValue.overlay,
|
|
auxiliaryProperties);
|
|
optionsExtraOverlays.push(optionsSliderData[i].value);
|
|
auxiliaryProperties = Object.clone(UI_ELEMENTS.barSlider.sliderRemainder.properties);
|
|
auxiliaryProperties.localPosition = { x: 0, y: (0.5 - (1.0 - value) / 2) * properties.dimensions.y, z: 0 };
|
|
auxiliaryProperties.dimensions = {
|
|
x: properties.dimensions.x,
|
|
y: Math.max((1.0 - value) * properties.dimensions.y, MIN_BAR_SLIDER_DIMENSION),
|
|
z: properties.dimensions.z
|
|
};
|
|
auxiliaryProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
optionsSliderData[i].remainder = Overlays.addOverlay(UI_ELEMENTS.barSlider.sliderRemainder.overlay,
|
|
auxiliaryProperties);
|
|
optionsExtraOverlays.push(optionsSliderData[i].remainder);
|
|
|
|
// Zero indicator.
|
|
childProperties = Object.clone(UI_ELEMENTS.barSlider.zeroIndicator.properties);
|
|
childProperties.dimensions = {
|
|
x: properties.dimensions.x,
|
|
y: UI_ELEMENTS.barSlider.zeroIndicator.properties.dimensions.y
|
|
};
|
|
childProperties.localPosition = {
|
|
x: 0,
|
|
y: 0,
|
|
z: properties.dimensions.z / 2 + UIT.dimensions.imageOverlayOffset
|
|
};
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = Overlays.addOverlay(UI_ELEMENTS.barSlider.zeroIndicator.overlay, childProperties);
|
|
optionsExtraOverlays.push(id);
|
|
}
|
|
|
|
if (optionsItems[i].type === "imageSlider") {
|
|
imageOffset = 0.0;
|
|
|
|
// Primary image.
|
|
if (optionsItems[i].imageURL) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties.url = optionsItems[i].imageURL;
|
|
childProperties.dimensions = { x: properties.dimensions.x, y: properties.dimensions.y };
|
|
imageOffset += 2 * IMAGE_OFFSET; // Double offset to prevent clipping against background.
|
|
if (optionsItems[i].useBaseColor) {
|
|
childProperties.color = properties.color;
|
|
}
|
|
childProperties.localPosition = { x: 0, y: 0, z: properties.dimensions.z / 2 + imageOffset };
|
|
hsvControl.slider.localPosition = childProperties.localPosition;
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
hsvControl.slider.colorOverlay = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
hsvControl.slider.length = properties.dimensions.y;
|
|
optionsExtraOverlays.push(hsvControl.slider.colorOverlay);
|
|
}
|
|
|
|
// Overlay image.
|
|
if (optionsItems[i].imageOverlayURL) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties.url = optionsItems[i].imageOverlayURL;
|
|
childProperties.dimensions = { x: properties.dimensions.x, y: properties.dimensions.y };
|
|
childProperties.emissive = false;
|
|
imageOffset += IMAGE_OFFSET;
|
|
childProperties.localPosition = { x: 0, y: 0, z: properties.dimensions.z / 2 + imageOffset };
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
optionsExtraOverlays.push(id);
|
|
}
|
|
|
|
// Value pointers.
|
|
optionsSliderData[i] = {};
|
|
optionsSliderData[i].offset =
|
|
{ x: -properties.dimensions.x / 2, y: 0, z: properties.dimensions.z / 2 + imageOffset };
|
|
auxiliaryProperties = Object.clone(UI_ELEMENTS.sliderPointer.properties);
|
|
auxiliaryProperties.localPosition = optionsSliderData[i].offset;
|
|
hsvControl.slider.localPosition = auxiliaryProperties.localPosition;
|
|
auxiliaryProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = optionsSliderData[i].value = Overlays.addOverlay(UI_ELEMENTS.sliderPointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
hsvControl.slider.pointerOverlay = optionsSliderData[i].value;
|
|
auxiliaryProperties.localPosition = { x: 0, y: properties.dimensions.x, z: 0 };
|
|
auxiliaryProperties.localRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 });
|
|
auxiliaryProperties.parentID = optionsSliderData[i].value;
|
|
id = Overlays.addOverlay(UI_ELEMENTS.sliderPointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
}
|
|
|
|
if (optionsItems[i].type === "colorCircle") {
|
|
imageOffset = 0.0;
|
|
|
|
// Primary image.
|
|
if (optionsItems[i].imageURL) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties.url = optionsItems[i].imageURL;
|
|
childProperties.scale = properties.dimensions.x;
|
|
imageOffset += 2 * IMAGE_OFFSET; // Double offset to prevent clipping against background.
|
|
childProperties.localPosition = { x: 0, y: properties.dimensions.y / 2 + imageOffset, z: 0 };
|
|
childProperties.localRotation = Quat.fromVec3Degrees({ x: -90, y: 90, z: 0 });
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
id = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
optionsExtraOverlays.push(id);
|
|
}
|
|
|
|
// Overlay image.
|
|
if (optionsItems[i].imageOverlayURL) {
|
|
childProperties = Object.clone(UI_ELEMENTS.image.properties);
|
|
childProperties.url = optionsItems[i].imageOverlayURL;
|
|
childProperties.scale = properties.dimensions.x;
|
|
imageOffset += IMAGE_OFFSET;
|
|
childProperties.emissive = false;
|
|
childProperties.localPosition = { x: 0, y: properties.dimensions.y / 2 + imageOffset, z: 0 };
|
|
childProperties.localRotation = Quat.fromVec3Degrees({ x: 90, y: 90, z: 0 });
|
|
childProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
childProperties.alpha = 0.0;
|
|
hsvControl.circle.overlay = Overlays.addOverlay(UI_ELEMENTS.image.overlay, childProperties);
|
|
optionsExtraOverlays.push(hsvControl.circle.overlay);
|
|
}
|
|
|
|
// Value pointers.
|
|
// Invisible sphere at target point with cones as decoration.
|
|
optionsColorData[i] = {};
|
|
optionsColorData[i].offset =
|
|
{ x: 0, y: properties.dimensions.y / 2 + imageOffset, z: 0 };
|
|
auxiliaryProperties = Object.clone(UI_ELEMENTS.sphere.properties);
|
|
auxiliaryProperties.dimensions = CIRCLE_CURSOR_SPHERE_DIMENSIONS;
|
|
auxiliaryProperties.localPosition = optionsColorData[i].offset;
|
|
auxiliaryProperties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
auxiliaryProperties.visible = false;
|
|
optionsColorData[i].value = Overlays.addOverlay(UI_ELEMENTS.sphere.overlay, auxiliaryProperties);
|
|
hsvControl.circle.radius = childProperties.scale / 2;
|
|
hsvControl.circle.localPosition = auxiliaryProperties.localPosition;
|
|
hsvControl.circle.cursorOverlay = optionsColorData[i].value;
|
|
|
|
auxiliaryProperties = Object.clone(UI_ELEMENTS.circlePointer.properties);
|
|
auxiliaryProperties.parentID = optionsColorData[i].value;
|
|
auxiliaryProperties.localPosition =
|
|
{ x: -(auxiliaryProperties.dimensions.x + CIRCLE_CURSOR_GAP) / 2, y: 0, z: 0 };
|
|
auxiliaryProperties.localRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: -90 });
|
|
id = Overlays.addOverlay(UI_ELEMENTS.circlePointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
auxiliaryProperties.localPosition =
|
|
{ x: (auxiliaryProperties.dimensions.x + CIRCLE_CURSOR_GAP) / 2, y: 0, z: 0 };
|
|
auxiliaryProperties.localRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 90 });
|
|
id = Overlays.addOverlay(UI_ELEMENTS.circlePointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
auxiliaryProperties.localPosition =
|
|
{ x: 0, y: 0, z: -(auxiliaryProperties.dimensions.x + CIRCLE_CURSOR_GAP) / 2 };
|
|
auxiliaryProperties.localRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 0 });
|
|
id = Overlays.addOverlay(UI_ELEMENTS.circlePointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
auxiliaryProperties.localPosition =
|
|
{ x: 0, y: 0, z: (auxiliaryProperties.dimensions.x + CIRCLE_CURSOR_GAP) / 2 };
|
|
auxiliaryProperties.localRotation = Quat.fromVec3Degrees({ x: -90, y: 0, z: 0 });
|
|
id = Overlays.addOverlay(UI_ELEMENTS.circlePointer.overlay, auxiliaryProperties);
|
|
optionsExtraOverlays.push(id);
|
|
}
|
|
|
|
if (optionsItems[i].type === "swatch" && swatchHighlightOverlay === null) {
|
|
properties = Object.clone(UI_ELEMENTS.swatchHighlight.properties);
|
|
properties.parentID = optionsOverlays[optionsOverlays.length - 1];
|
|
swatchHighlightOverlay = Overlays.addOverlay(UI_ELEMENTS.swatchHighlight.overlay, properties);
|
|
}
|
|
|
|
optionsEnabled.push(optionsItems[i].enabled === undefined || optionsItems[i].enabled);
|
|
}
|
|
|
|
// Special handling for Group options.
|
|
if (menuItem.toolOptions === "groupOptions") {
|
|
optionsEnabled[groupButtonIndex] = false;
|
|
optionsEnabled[ungroupButtonIndex] = false;
|
|
optionsEnabled[clearGroupingButtonIndex] = false;
|
|
}
|
|
|
|
isOptionsOpen = true;
|
|
}
|
|
|
|
function closeOptions() {
|
|
var i,
|
|
length;
|
|
|
|
if (swatchHighlightOverlay !== null) {
|
|
Overlays.deleteOverlay(swatchHighlightOverlay);
|
|
swatchHighlightOverlay = null;
|
|
}
|
|
|
|
for (i = 0, length = optionsOverlays.length; i < length; i++) {
|
|
Overlays.deleteOverlay(optionsOverlays[i]);
|
|
}
|
|
optionsOverlays = [];
|
|
|
|
optionsOverlaysIDs = [];
|
|
optionsOverlaysLabels = [];
|
|
optionsOverlaysSublabels = [];
|
|
optionsSliderData = [];
|
|
optionsColorData = [];
|
|
optionsEnabled = [];
|
|
optionsExtraOverlays = [];
|
|
optionsItems = null;
|
|
|
|
isPicklistOpen = false;
|
|
|
|
pressedItem = null;
|
|
|
|
isOptionsOpen = false;
|
|
}
|
|
|
|
function displayFooter() {
|
|
var properties,
|
|
itemID,
|
|
buttonID,
|
|
overlayID,
|
|
i,
|
|
length;
|
|
|
|
// Display footer items.
|
|
for (i = 0, length = FOOTER_ITEMS.length; i < length; i++) {
|
|
properties = Object.clone(UI_ELEMENTS[FOOTER_ITEMS[i].type].properties);
|
|
properties = Object.merge(properties, FOOTER_ITEMS[i].properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = menuPanelOverlay;
|
|
itemID = Overlays.addOverlay(UI_ELEMENTS[FOOTER_ITEMS[i].type].overlay, properties);
|
|
footerOverlays[i] = itemID;
|
|
footerEnabled[i] = true;
|
|
|
|
if (FOOTER_ITEMS[i].type === "menuButton") {
|
|
// Collision overlay.
|
|
properties = Object.clone(UI_ELEMENTS.menuButton.hoverButton.properties);
|
|
properties.parentID = itemID;
|
|
buttonID = Overlays.addOverlay(UI_ELEMENTS.menuButton.hoverButton.overlay, properties);
|
|
footerHoverOverlays[i] = buttonID;
|
|
|
|
// Icon.
|
|
properties = Object.clone(UI_ELEMENTS[UI_ELEMENTS.menuButton.icon.type].properties);
|
|
properties = Object.merge(properties, UI_ELEMENTS.menuButton.icon.properties);
|
|
properties = Object.merge(properties, FOOTER_ITEMS[i].icon.properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = buttonID;
|
|
overlayID = Overlays.addOverlay(UI_ELEMENTS[UI_ELEMENTS.menuButton.icon.type].overlay, properties);
|
|
footerIconOverlays[i] = overlayID;
|
|
|
|
// Label.
|
|
properties = Object.clone(UI_ELEMENTS[UI_ELEMENTS.menuButton.label.type].properties);
|
|
properties = Object.merge(properties, UI_ELEMENTS.menuButton.label.properties);
|
|
properties = Object.merge(properties, FOOTER_ITEMS[i].label.properties);
|
|
properties.visible = isVisible;
|
|
properties.parentID = itemID;
|
|
overlayID = Overlays.addOverlay(UI_ELEMENTS[UI_ELEMENTS.menuButton.label.type].overlay, properties);
|
|
footerLabelOverlays.push(overlayID);
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearTool() {
|
|
closeOptions();
|
|
openMenu();
|
|
}
|
|
|
|
function setPresetsLabelToCustom() {
|
|
var label;
|
|
if (optionsSettings.physicsPresets.value !== "custom") {
|
|
optionsSettings.physicsPresets.value = "custom";
|
|
label = optionsItems[optionsOverlaysIDs.indexOf("physicsPresets")].customLabel;
|
|
Overlays.editOverlay(optionsOverlaysLabels[optionsOverlaysIDs.indexOf("physicsPresets")], {
|
|
url: label.url,
|
|
scale: label.scale,
|
|
localPosition: label.localPosition
|
|
});
|
|
Settings.setValue(optionsSettings.physicsPresets.key, "custom");
|
|
}
|
|
}
|
|
|
|
function setBarSliderValue(item, fraction) {
|
|
var overlayDimensions,
|
|
otherFraction;
|
|
|
|
overlayDimensions = optionsItems[item].properties.dimensions;
|
|
if (overlayDimensions === undefined) {
|
|
overlayDimensions = UI_ELEMENTS.barSlider.properties.dimensions;
|
|
}
|
|
|
|
otherFraction = 1.0 - fraction;
|
|
|
|
Overlays.editOverlay(optionsSliderData[item].value, {
|
|
localPosition: { x: 0, y: (-0.5 + fraction / 2) * overlayDimensions.y, z: 0 },
|
|
dimensions: {
|
|
x: overlayDimensions.x,
|
|
y: Math.max(fraction * overlayDimensions.y, MIN_BAR_SLIDER_DIMENSION),
|
|
z: overlayDimensions.z
|
|
}
|
|
});
|
|
Overlays.editOverlay(optionsSliderData[item].remainder, {
|
|
localPosition: { x: 0, y: (0.5 - otherFraction / 2) * overlayDimensions.y, z: 0 },
|
|
dimensions: {
|
|
x: overlayDimensions.x,
|
|
y: Math.max(otherFraction * overlayDimensions.y, MIN_BAR_SLIDER_DIMENSION),
|
|
z: overlayDimensions.z
|
|
}
|
|
});
|
|
}
|
|
|
|
function hsvToRGB(hsv) {
|
|
// https://en.wikipedia.org/wiki/HSL_and_HSV
|
|
var c, h, x, rgb, m;
|
|
|
|
c = hsv.v * hsv.s;
|
|
h = hsv.h * 6.0;
|
|
x = c * (1 - Math.abs(h % 2 - 1));
|
|
if (0 <= h && h <= 1) {
|
|
rgb = { red: c, green: x, blue: 0 };
|
|
} else if (1 < h && h <= 2) {
|
|
rgb = { red: x, green: c, blue: 0 };
|
|
} else if (2 < h && h <= 3) {
|
|
rgb = { red: 0, green: c, blue: x };
|
|
} else if (3 < h && h <= 4) {
|
|
rgb = { red: 0, green: x, blue: c };
|
|
} else if (4 < h && h <= 5) {
|
|
rgb = { red: x, green: 0, blue: c };
|
|
} else {
|
|
rgb = { red: c, green: 0, blue: x };
|
|
}
|
|
m = hsv.v - c;
|
|
rgb = {
|
|
red: Math.round((rgb.red + m) * 255),
|
|
green: Math.round((rgb.green + m) * 255),
|
|
blue: Math.round((rgb.blue + m) * 255)
|
|
};
|
|
return rgb;
|
|
}
|
|
|
|
function rgbToHSV(rgb) {
|
|
// https://en.wikipedia.org/wiki/HSL_and_HSV
|
|
var mMax, mMin, c, h, v, s;
|
|
|
|
mMax = Math.max(rgb.red, rgb.green, rgb.blue);
|
|
mMin = Math.min(rgb.red, rgb.green, rgb.blue);
|
|
c = mMax - mMin;
|
|
|
|
if (c === 0) {
|
|
h = 0;
|
|
} else if (mMax === rgb.red) {
|
|
h = ((rgb.green - rgb.blue) / c) % 6;
|
|
} else if (mMax === rgb.green) {
|
|
h = (rgb.blue - rgb.red) / c + 2;
|
|
} else {
|
|
h = (rgb.red - rgb.green) / c + 4;
|
|
}
|
|
h = h / 6;
|
|
v = mMax / 255;
|
|
s = v === 0 ? 0 : c / mMax;
|
|
return { h: h, s: s, v: v };
|
|
}
|
|
|
|
function updateColorCircle() {
|
|
var theta, r, x, y;
|
|
|
|
// V overlay alpha per v.
|
|
Overlays.editOverlay(hsvControl.circle.overlay, { alpha: 1.0 - hsvControl.hsv.v });
|
|
|
|
// Cursor position per h & s.
|
|
theta = 2 * Math.PI * hsvControl.hsv.h;
|
|
r = hsvControl.hsv.s * hsvControl.circle.radius;
|
|
x = r * Math.cos(theta);
|
|
y = r * Math.sin(theta);
|
|
Overlays.editOverlay(hsvControl.circle.cursorOverlay, {
|
|
// Coordinates based on rotate cylinder entity. TODO: Use FBX model instead of cylinder entity.
|
|
localPosition: { x: -y, y: hsvControl.circle.localPosition.y, z: -x }
|
|
});
|
|
}
|
|
|
|
function updateColorSlider() {
|
|
// Base color per h & s.
|
|
Overlays.editOverlay(hsvControl.slider.colorOverlay, {
|
|
color: hsvToRGB({ h: hsvControl.hsv.h, s: hsvControl.hsv.s, v: 1.0 })
|
|
});
|
|
|
|
// Slider position per v.
|
|
Overlays.editOverlay(hsvControl.slider.pointerOverlay, {
|
|
localPosition: {
|
|
x: hsvControl.slider.localPosition.x,
|
|
y: (hsvControl.hsv.v - 0.5) * hsvControl.slider.length,
|
|
z: hsvControl.slider.localPosition.z
|
|
}
|
|
});
|
|
}
|
|
|
|
function setColorPicker(rgb) {
|
|
hsvControl.hsv = rgbToHSV(rgb);
|
|
updateColorCircle();
|
|
updateColorSlider();
|
|
}
|
|
|
|
function setCurrentColor(rgb) {
|
|
Overlays.editOverlay(optionsOverlays[optionsOverlaysIDs.indexOf("currentColor")], {
|
|
color: rgb
|
|
});
|
|
if (optionsSettings.currentColor) {
|
|
optionsSettings.currentColor.value = rgb;
|
|
Settings.setValue(optionsSettings.currentColor.key, rgb);
|
|
}
|
|
}
|
|
|
|
function evaluateParameter(parameter) {
|
|
var parameters,
|
|
overlayID,
|
|
overlayProperty;
|
|
|
|
parameters = parameter.split(".");
|
|
overlayID = parameters[0];
|
|
overlayProperty = parameters[1];
|
|
|
|
return Overlays.getProperty(optionsOverlays[optionsOverlaysIDs.indexOf(overlayID)], overlayProperty);
|
|
}
|
|
|
|
doCommand = function (command, parameter) {
|
|
var index,
|
|
value,
|
|
properties,
|
|
items,
|
|
parentID,
|
|
label,
|
|
values,
|
|
isHighlightingPicklist,
|
|
i,
|
|
length;
|
|
|
|
switch (command) {
|
|
|
|
case "setPickColor":
|
|
setColorPicker(parameter);
|
|
break;
|
|
|
|
case "setColorPerCircle":
|
|
hsvControl.hsv.h = parameter.h;
|
|
hsvControl.hsv.s = parameter.s;
|
|
updateColorSlider();
|
|
value = hsvToRGB(hsvControl.hsv);
|
|
setCurrentColor(value);
|
|
uiCommandCallback("setColor", value);
|
|
break;
|
|
|
|
case "setColorPerSlider":
|
|
hsvControl.hsv.v = parameter;
|
|
updateColorCircle();
|
|
value = hsvToRGB(hsvControl.hsv);
|
|
setCurrentColor(value);
|
|
uiCommandCallback("setColor", value);
|
|
break;
|
|
|
|
case "setColorPerSwatch":
|
|
index = optionsOverlaysIDs.indexOf(parameter);
|
|
value = optionsSettings[parameter].value;
|
|
if (value !== "") {
|
|
// Set current color to swatch color.
|
|
setCurrentColor(value);
|
|
setColorPicker(value);
|
|
uiCommandCallback("setColor", value);
|
|
} else {
|
|
// Swatch has no color; set swatch color to current color.
|
|
value = optionsSettings.currentColor.value;
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: value
|
|
});
|
|
optionsSettings[parameter].value = value;
|
|
Settings.setValue(optionsSettings[parameter].key, value);
|
|
}
|
|
break;
|
|
|
|
case "togglePickColor":
|
|
optionsToggles.pickColor = !optionsToggles.pickColor;
|
|
index = optionsOverlaysIDs.indexOf("pickColor");
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: optionsToggles.pickColor
|
|
? UI_ELEMENTS[optionsItems[index].type].onHoverColor
|
|
: UI_ELEMENTS[optionsItems[index].type].offHoverColor
|
|
});
|
|
uiCommandCallback("pickColorTool", optionsToggles.pickColor);
|
|
break;
|
|
|
|
case "setColorFromPick":
|
|
optionsToggles.pickColor = false;
|
|
index = optionsOverlaysIDs.indexOf("pickColor");
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: UI_ELEMENTS[optionsItems[index].type].offColor
|
|
});
|
|
setCurrentColor(parameter);
|
|
setColorPicker(parameter);
|
|
break;
|
|
|
|
case "toggleGroupSelectionBox":
|
|
optionsToggles.groupSelectionBoxButton = !optionsToggles.groupSelectionBoxButton;
|
|
index = optionsOverlaysIDs.indexOf("groupSelectionBoxButton");
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: optionsToggles.groupSelectionBoxButton
|
|
? UI_ELEMENTS[optionsItems[index].type].onHoverColor
|
|
: UI_ELEMENTS[optionsItems[index].type].offHoverColor
|
|
});
|
|
uiCommandCallback("toggleGroupSelectionBoxTool", optionsToggles.groupSelectionBoxButton);
|
|
break;
|
|
|
|
case "clearGroupSelection":
|
|
index = clearGroupingButtonIndex;
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: optionsItems[index].properties.color
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[index], {
|
|
color: optionsItems[index].label.color
|
|
});
|
|
optionsEnabled[index] = false;
|
|
uiCommandCallback("clearGroupSelectionTool");
|
|
break;
|
|
|
|
case "setGravityOn":
|
|
case "setGrabOn":
|
|
case "setCollideOn":
|
|
value = !optionsSettings[parameter].value;
|
|
optionsSettings[parameter].value = value;
|
|
optionsToggles[parameter] = value;
|
|
Settings.setValue(optionsSettings[parameter].key, value);
|
|
index = optionsOverlaysIDs.indexOf(parameter);
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
color: value
|
|
? UI_ELEMENTS[optionsItems[index].type].onHoverColor
|
|
: UI_ELEMENTS[optionsItems[index].type].offHoverColor
|
|
});
|
|
properties = Object.clone(value ? optionsItems[index].onSublabel : optionsItems[index].offSublabel);
|
|
Overlays.editOverlay(optionsOverlaysSublabels[index], properties);
|
|
uiCommandCallback(command, value);
|
|
break;
|
|
|
|
case "togglePhysicsPresets":
|
|
if (isPicklistOpen) {
|
|
// Close picklist.
|
|
index = optionsOverlaysIDs.indexOf("physicsPresets");
|
|
|
|
// Lower picklist.
|
|
isHighlightingPicklist = hoveredElementType === "picklist";
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
localPosition: isHighlightingPicklist
|
|
? Vec3.sum(optionsItems[index].properties.localPosition, OPTION_HOVER_DELTA)
|
|
: optionsItems[index].properties.localPosition,
|
|
color: isHighlightingPicklist
|
|
? UIT.colors.highlightColor
|
|
: UI_ELEMENTS.picklist.properties.color
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysSublabels[index], {
|
|
url: PICKLIST_DOWN_ARROW
|
|
});
|
|
|
|
// Hide options.
|
|
items = optionsItems[index].items;
|
|
for (i = 0, length = items.length; i < length; i++) {
|
|
index = optionsOverlaysIDs.indexOf(items[i]);
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
localPosition: Vec3.ZERO,
|
|
visible: false
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[index], {
|
|
visible: false
|
|
});
|
|
}
|
|
}
|
|
|
|
isPicklistOpen = !isPicklistOpen;
|
|
|
|
if (isPicklistOpen) {
|
|
// Open picklist.
|
|
index = optionsOverlaysIDs.indexOf("physicsPresets");
|
|
parentID = optionsOverlays[index];
|
|
|
|
// Raise picklist.
|
|
Overlays.editOverlay(parentID, {
|
|
localPosition: Vec3.sum(optionsItems[index].properties.localPosition, PICKLIST_HOVER_DELTA)
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysSublabels[index], {
|
|
url: PICKLIST_UP_ARROW
|
|
});
|
|
|
|
// Show options.
|
|
items = optionsItems[index].items;
|
|
for (i = 0, length = items.length; i < length; i++) {
|
|
index = optionsOverlaysIDs.indexOf(items[i]);
|
|
Overlays.editOverlay(optionsOverlays[index], {
|
|
parentID: parentID,
|
|
localPosition: { x: 0, y: (i + 1) * UI_ELEMENTS.picklistItem.properties.dimensions.y, z: 0 },
|
|
visible: true
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[index], {
|
|
visible: true
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "pickPhysicsPreset":
|
|
// Close picklist.
|
|
doCommand("togglePhysicsPresets");
|
|
|
|
// Update picklist label.
|
|
label = optionsItems[optionsOverlaysIDs.indexOf(parameter)].label;
|
|
Overlays.editOverlay(optionsOverlaysLabels[optionsOverlaysIDs.indexOf("physicsPresets")], {
|
|
url: label.url,
|
|
scale: label.scale,
|
|
localPosition: label.localPosition
|
|
});
|
|
optionsSettings.physicsPresets.value = parameter;
|
|
Settings.setValue(optionsSettings.physicsPresets.key, parameter);
|
|
|
|
// Update sliders.
|
|
values = PHYSICS_SLIDER_PRESETS[parameter];
|
|
setBarSliderValue(optionsOverlaysIDs.indexOf("gravitySlider"), values.gravity);
|
|
Settings.setValue(optionsSettings.gravitySlider.key, values.gravity);
|
|
uiCommandCallback("setGravity", values.gravity);
|
|
setBarSliderValue(optionsOverlaysIDs.indexOf("bounceSlider"), values.bounce);
|
|
Settings.setValue(optionsSettings.bounceSlider.key, values.bounce);
|
|
uiCommandCallback("setBounce", values.bounce);
|
|
setBarSliderValue(optionsOverlaysIDs.indexOf("frictionSlider"), values.friction);
|
|
Settings.setValue(optionsSettings.frictionSlider.key, values.friction);
|
|
uiCommandCallback("setFriction", values.friction);
|
|
setBarSliderValue(optionsOverlaysIDs.indexOf("densitySlider"), values.density);
|
|
Settings.setValue(optionsSettings.densitySlider.key, values.density);
|
|
uiCommandCallback("setDensity", values.density);
|
|
|
|
break;
|
|
|
|
case "setGravity":
|
|
setPresetsLabelToCustom();
|
|
Settings.setValue(optionsSettings.gravitySlider.key, parameter);
|
|
uiCommandCallback("setGravity", parameter);
|
|
break;
|
|
case "setBounce":
|
|
setPresetsLabelToCustom();
|
|
Settings.setValue(optionsSettings.bounceSlider.key, parameter);
|
|
uiCommandCallback("setBounce", parameter);
|
|
break;
|
|
case "setFriction":
|
|
setPresetsLabelToCustom();
|
|
Settings.setValue(optionsSettings.frictionSlider.key, parameter);
|
|
uiCommandCallback("setFriction", parameter);
|
|
break;
|
|
case "setDensity":
|
|
setPresetsLabelToCustom();
|
|
Settings.setValue(optionsSettings.densitySlider.key, parameter);
|
|
uiCommandCallback("setDensity", parameter);
|
|
break;
|
|
|
|
case "closeOptions":
|
|
closeOptions();
|
|
openMenu();
|
|
break;
|
|
|
|
case "clearTool":
|
|
uiCommandCallback("clearTool");
|
|
break;
|
|
|
|
default:
|
|
App.log(side, "ERROR: ToolsMenu: Unexpected command! " + command);
|
|
}
|
|
};
|
|
|
|
function doGripClicked(command, parameter) {
|
|
switch (command) {
|
|
case "clearSwatch":
|
|
// Remove highlight ring and change swatch to current color.
|
|
Overlays.editOverlay(swatchHighlightOverlay, { visible: false });
|
|
Overlays.editOverlay(optionsOverlays[optionsOverlaysIDs.indexOf(parameter)], {
|
|
color: optionsSettings.currentColor.value,
|
|
dimensions: UI_ELEMENTS.swatch.properties.dimensions
|
|
});
|
|
optionsSettings[parameter].value = ""; // Emulate Settings.getValue() returning "" for nonexistent setting.
|
|
Settings.setValue(optionsSettings[parameter].key, null); // Delete settings value.
|
|
break;
|
|
default:
|
|
App.log(side, "ERROR: ToolsMenu: Unexpected command! " + command);
|
|
}
|
|
}
|
|
|
|
function adjustSliderFraction(fraction) {
|
|
// Makes slider values achieve and saturate at 0.0 and 1.0.
|
|
return Math.min(1.0, Math.max(0.0, fraction * 1.01 - 0.005));
|
|
}
|
|
|
|
function setVisible(visible) {
|
|
var i,
|
|
length;
|
|
|
|
for (i = 0, length = staticOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(staticOverlays[i], { visible: visible });
|
|
}
|
|
|
|
if (isOptionsOpen) {
|
|
Overlays.editOverlay(menuHeaderBackOverlay, { visible: visible });
|
|
Overlays.editOverlay(menuHeaderIconOverlay, { visible: visible });
|
|
for (i = 0, length = optionsOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(optionsOverlays[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = optionsOverlaysLabels.length; i < length; i++) {
|
|
Overlays.editOverlay(optionsOverlaysLabels[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = optionsOverlaysSublabels.length; i < length; i++) {
|
|
Overlays.editOverlay(optionsOverlaysSublabels[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = optionsExtraOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(optionsExtraOverlays[i], { visible: visible });
|
|
}
|
|
} else {
|
|
for (i = 0, length = menuOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(menuOverlays[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = menuIconOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(menuIconOverlays[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = menuLabelOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(menuLabelOverlays[i], { visible: visible });
|
|
}
|
|
if (!visible) {
|
|
for (i = 0, length = menuHoverOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(menuHoverOverlays[i], { visible: false });
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0, length = footerOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(footerOverlays[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = footerIconOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(footerIconOverlays[i], { visible: visible });
|
|
}
|
|
for (i = 0, length = footerLabelOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(footerLabelOverlays[i], { visible: visible });
|
|
}
|
|
if (!visible) {
|
|
for (i = 0, length = footerHoverOverlays.length; i < length; i++) {
|
|
Overlays.editOverlay(footerHoverOverlays[i], { visible: false });
|
|
}
|
|
}
|
|
|
|
isVisible = visible;
|
|
}
|
|
|
|
function update(intersection, groupsCount, entitiesCount) {
|
|
var intersectedItem = NONE,
|
|
intersectionItems,
|
|
menuButtonHoverOverlays,
|
|
menuButtonIconOverlays,
|
|
color,
|
|
localPosition,
|
|
parameter,
|
|
parameterValue,
|
|
enableGroupButton,
|
|
enableUngroupButton,
|
|
enableClearGroupingButton,
|
|
sliderProperties,
|
|
overlayDimensions,
|
|
basePoint,
|
|
fraction,
|
|
delta,
|
|
radius,
|
|
x,
|
|
y,
|
|
s,
|
|
h;
|
|
|
|
isTriggerClicked = controlHand.triggerClicked();
|
|
|
|
// Handle heading.
|
|
if (isOptionsOpen && intersection.overlayID === menuHeaderOverlay) {
|
|
if (isTriggerClicked && !wasTriggerClicked) {
|
|
// Lower and unhighlight heading; go back to Tools menu.
|
|
Overlays.editOverlay(menuHeaderHeadingOverlay, {
|
|
url: MENU_HEADER_HEADING_PROPERTIES.url,
|
|
localPosition: MENU_HEADER_HEADING_PROPERTIES.localPosition,
|
|
emissive: false
|
|
});
|
|
isOptionsHeadingRaised = false;
|
|
doCommand("clearTool");
|
|
} else if (!isOptionsHeadingRaised) {
|
|
// Hover heading.
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
Overlays.editOverlay(menuHeaderHeadingOverlay, {
|
|
url: MENU_HEADER_HEADING_PROPERTIES.highlightURL,
|
|
localPosition: Vec3.sum(MENU_HEADER_HEADING_PROPERTIES.localPosition, MENU_HEADER_HOVER_OFFSET),
|
|
emissive: true // TODO: This has no effect.
|
|
});
|
|
Overlays.editOverlay(menuHeaderBackOverlay, {
|
|
color: UIT.colors.white
|
|
});
|
|
Overlays.editOverlay(menuHeaderTitleOverlay, {
|
|
url: MENU_HEADER_TITLE_BACK_URL,
|
|
scale: MENU_HEADER_TITLE_BACK_SCALE
|
|
});
|
|
Overlays.editOverlay(menuHeaderIconOverlay, {
|
|
visible: false
|
|
});
|
|
isOptionsHeadingRaised = true;
|
|
}
|
|
} else {
|
|
if (isOptionsHeadingRaised) {
|
|
// Unhover heading.
|
|
Overlays.editOverlay(menuHeaderHeadingOverlay, {
|
|
url: MENU_HEADER_HEADING_PROPERTIES.url,
|
|
localPosition: MENU_HEADER_HEADING_PROPERTIES.localPosition,
|
|
emissive: false
|
|
});
|
|
Overlays.editOverlay(menuHeaderBackOverlay, {
|
|
color: MENU_HEADER_BACK_PROPERTIES.color
|
|
});
|
|
Overlays.editOverlay(menuHeaderTitleOverlay, {
|
|
url: optionsHeadingURL,
|
|
scale: optionsHeadingScale
|
|
});
|
|
Overlays.editOverlay(menuHeaderIconOverlay, {
|
|
visible: isVisible
|
|
});
|
|
isOptionsHeadingRaised = false;
|
|
}
|
|
}
|
|
|
|
// Intersection details for menus and options.
|
|
intersectionOverlays = null;
|
|
intersectionEnabled = null;
|
|
if (intersection.overlayID) {
|
|
intersectedItem = menuOverlays.indexOf(intersection.overlayID);
|
|
if (intersectedItem !== NONE) {
|
|
intersectionItems = MENU_ITEMS;
|
|
intersectionOverlays = menuOverlays;
|
|
intersectionEnabled = menuEnabled;
|
|
} else {
|
|
intersectedItem = optionsOverlays.indexOf(intersection.overlayID);
|
|
if (intersectedItem !== NONE) {
|
|
intersectionItems = optionsItems;
|
|
intersectionOverlays = optionsOverlays;
|
|
intersectionEnabled = optionsEnabled;
|
|
} else {
|
|
intersectedItem = footerOverlays.indexOf(intersection.overlayID);
|
|
if (intersectedItem !== NONE) {
|
|
intersectionItems = FOOTER_ITEMS;
|
|
intersectionOverlays = footerOverlays;
|
|
intersectionEnabled = footerEnabled;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hover clickable item.
|
|
if (intersectedItem !== hoveredItem || intersectionOverlays !== hoveredSourceOverlays) {
|
|
|
|
if (hoveredItem !== NONE) {
|
|
// Unhover old item.
|
|
switch (hoveredElementType) {
|
|
case "menuButton":
|
|
if (hoveredSourceOverlays === menuOverlays) {
|
|
menuButtonHoverOverlays = menuHoverOverlays;
|
|
menuButtonIconOverlays = menuIconOverlays;
|
|
} else {
|
|
menuButtonHoverOverlays = footerHoverOverlays;
|
|
menuButtonIconOverlays = footerIconOverlays;
|
|
}
|
|
Overlays.editOverlay(menuButtonHoverOverlays[hoveredItem], {
|
|
localPosition: UI_ELEMENTS.menuButton.hoverButton.properties.localPosition,
|
|
visible: false
|
|
});
|
|
Overlays.editOverlay(menuButtonIconOverlays[hoveredItem], {
|
|
color: UI_ELEMENTS.menuButton.icon.properties.color
|
|
});
|
|
break;
|
|
case "button":
|
|
if (hoveredSourceItems[hoveredItem].enabledColor !== undefined && optionsEnabled[hoveredItem]) {
|
|
color = hoveredSourceItems[hoveredItem].enabledColor;
|
|
} else {
|
|
color = hoveredSourceItems[hoveredItem].properties.color !== undefined
|
|
? hoveredSourceItems[hoveredItem].properties.color
|
|
: UI_ELEMENTS.button.properties.color;
|
|
}
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
color: color,
|
|
localPosition: hoveredSourceItems[hoveredItem].properties.localPosition
|
|
});
|
|
break;
|
|
case "toggleButton":
|
|
color = optionsToggles[hoveredSourceItems[hoveredItem].id]
|
|
? UI_ELEMENTS.toggleButton.onColor
|
|
: UI_ELEMENTS.toggleButton.offColor;
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
color: color,
|
|
localPosition: hoveredSourceItems[hoveredItem].properties.localPosition
|
|
});
|
|
break;
|
|
case "swatch":
|
|
Overlays.editOverlay(swatchHighlightOverlay, { visible: false });
|
|
color = optionsSettings[hoveredSourceItems[hoveredItem].id].value;
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
dimensions: UI_ELEMENTS.swatch.properties.dimensions,
|
|
color: color === "" ? EMPTY_SWATCH_COLOR : color,
|
|
localPosition: hoveredSourceItems[hoveredItem].properties.localPosition
|
|
});
|
|
break;
|
|
case "barSlider":
|
|
case "imageSlider":
|
|
case "colorCircle":
|
|
// Lower old slider or color circle.
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
localPosition: hoveredSourceItems[hoveredItem].properties.localPosition
|
|
});
|
|
break;
|
|
case "picklist":
|
|
if (hoveredSourceItems[hoveredItem].type !== "picklistItem" && !isPicklistOpen) {
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
localPosition: hoveredSourceItems[hoveredItem].properties.localPosition,
|
|
color: UI_ELEMENTS.picklist.properties.color
|
|
});
|
|
} else {
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
color: UIT.colors.darkGray
|
|
});
|
|
}
|
|
break;
|
|
case "picklistItem":
|
|
Overlays.editOverlay(hoveredSourceOverlays[hoveredItem], {
|
|
color: UI_ELEMENTS.picklistItem.properties.color
|
|
});
|
|
break;
|
|
case null:
|
|
// Nothing to do.
|
|
break;
|
|
default:
|
|
App.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType);
|
|
}
|
|
|
|
// Update status variables.
|
|
hoveredItem = NONE;
|
|
isHoveringButtonElement = false;
|
|
hoveredElementType = null;
|
|
}
|
|
|
|
if (intersectedItem !== NONE && intersectionItems[intersectedItem] &&
|
|
(intersectionItems[intersectedItem].command !== undefined
|
|
|| intersectionItems[intersectedItem].callback !== undefined)) {
|
|
|
|
// Update status variables.
|
|
hoveredItem = intersectedItem;
|
|
isHoveringButtonElement = BUTTON_UI_ELEMENTS.indexOf(intersectionItems[hoveredItem].type) !== NONE;
|
|
hoveredElementType = intersectionItems[hoveredItem].type;
|
|
|
|
// Hover new item.
|
|
switch (hoveredElementType) {
|
|
case "menuButton":
|
|
Feedback.play(otherSide, Feedback.HOVER_MENU_ITEM);
|
|
if (intersectionOverlays === menuOverlays) {
|
|
menuButtonHoverOverlays = menuHoverOverlays;
|
|
menuButtonIconOverlays = menuIconOverlays;
|
|
} else {
|
|
menuButtonHoverOverlays = footerHoverOverlays;
|
|
menuButtonIconOverlays = footerIconOverlays;
|
|
}
|
|
Overlays.editOverlay(menuButtonHoverOverlays[hoveredItem], {
|
|
localPosition: Vec3.sum(UI_ELEMENTS.menuButton.hoverButton.properties.localPosition,
|
|
MENU_HOVER_DELTA),
|
|
visible: true
|
|
});
|
|
Overlays.editOverlay(menuButtonIconOverlays[hoveredItem], {
|
|
color: UI_ELEMENTS.menuButton.icon.highlightColor
|
|
});
|
|
break;
|
|
case "button":
|
|
if (intersectionEnabled[hoveredItem]) {
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
localPosition = intersectionItems[hoveredItem].properties.localPosition;
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
color: intersectionItems[hoveredItem].highlightColor !== undefined
|
|
? intersectionItems[hoveredItem].highlightColor
|
|
: UIT.colors.greenHighlight,
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA)
|
|
});
|
|
}
|
|
break;
|
|
case "toggleButton":
|
|
if (intersectionEnabled[hoveredItem]) {
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
localPosition = intersectionItems[hoveredItem].properties.localPosition;
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
color: optionsToggles[intersectionItems[hoveredItem].id]
|
|
? UI_ELEMENTS.toggleButton.onHoverColor
|
|
: UI_ELEMENTS.toggleButton.offHoverColor,
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA)
|
|
});
|
|
}
|
|
break;
|
|
case "swatch":
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
localPosition = intersectionItems[hoveredItem].properties.localPosition;
|
|
if (optionsSettings[intersectionItems[hoveredItem].id].value === "") {
|
|
// Swatch is empty; highlight it with current color.
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
color: optionsSettings.currentColor.value,
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA)
|
|
});
|
|
} else {
|
|
// Swatch is full; highlight it with ring.
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
dimensions: Vec3.subtract(UI_ELEMENTS.swatch.properties.dimensions,
|
|
{ x: SWATCH_HIGHLIGHT_DELTA, y: 0, z: SWATCH_HIGHLIGHT_DELTA }),
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA)
|
|
});
|
|
Overlays.editOverlay(swatchHighlightOverlay, {
|
|
parentID: intersectionOverlays[hoveredItem],
|
|
localPosition: UI_ELEMENTS.swatchHighlight.properties.localPosition,
|
|
visible: true
|
|
});
|
|
}
|
|
break;
|
|
case "barSlider":
|
|
case "imageSlider":
|
|
case "colorCircle":
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
localPosition = intersectionItems[hoveredItem].properties.localPosition;
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA)
|
|
});
|
|
break;
|
|
case "picklist":
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
if (!isPicklistOpen) {
|
|
localPosition = intersectionItems[hoveredItem].properties.localPosition;
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
localPosition: Vec3.sum(localPosition, OPTION_HOVER_DELTA),
|
|
color: UIT.colors.greenHighlight
|
|
});
|
|
} else {
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
color: UIT.colors.greenHighlight
|
|
});
|
|
}
|
|
break;
|
|
case "picklistItem":
|
|
Feedback.play(otherSide, Feedback.HOVER_BUTTON);
|
|
Overlays.editOverlay(intersectionOverlays[hoveredItem], {
|
|
color: UIT.colors.greenHighlight
|
|
});
|
|
break;
|
|
case null:
|
|
// Nothing to do.
|
|
break;
|
|
default:
|
|
App.log(side, "ERROR: ToolsMenu: Unexpected hover item! " + hoveredElementType);
|
|
}
|
|
}
|
|
|
|
hoveredSourceOverlays = intersectionOverlays;
|
|
hoveredSourceItems = intersectionItems;
|
|
}
|
|
|
|
// Press/unpress button.
|
|
if ((pressedItem && intersectedItem !== pressedItem.index) || intersectionOverlays !== pressedSource
|
|
|| isTriggerClicked !== (pressedItem !== null)) {
|
|
if (pressedItem) {
|
|
// Unpress previous button.
|
|
if (pressedItem !== null) {
|
|
if (pressedItem.pressedOverlays) {
|
|
pressedSource = pressedItem.pressedOverlays;
|
|
}
|
|
Overlays.editOverlay(pressedSource[pressedItem.index], {
|
|
localPosition: isHoveringButtonElement && hoveredItem === pressedItem.index
|
|
&& intersectionEnabled[pressedItem.index]
|
|
? Vec3.sum(pressedItem.localPosition, pressedItem.hoverDelta)
|
|
: pressedItem.localPosition
|
|
});
|
|
pressedItem = null;
|
|
}
|
|
pressedSource = null;
|
|
}
|
|
if (isHoveringButtonElement && (intersectionEnabled === null || intersectionEnabled[intersectedItem])
|
|
&& isTriggerClicked && !wasTriggerClicked) {
|
|
// Press new button.
|
|
pressedSource = intersectionOverlays;
|
|
if (hoveredElementType === "menuButton") {
|
|
if (intersectionItems === MENU_ITEMS) {
|
|
menuButtonHoverOverlays = menuHoverOverlays;
|
|
} else {
|
|
menuButtonHoverOverlays = footerHoverOverlays;
|
|
}
|
|
localPosition = UI_ELEMENTS.menuButton.hoverButton.properties.localPosition;
|
|
Overlays.editOverlay(menuButtonHoverOverlays[intersectedItem], {
|
|
localPosition: Vec3.sum(Vec3.sum(localPosition, MENU_HOVER_DELTA), BUTTON_PRESS_DELTA)
|
|
});
|
|
pressedItem = {
|
|
index: intersectedItem,
|
|
localPosition: localPosition,
|
|
hoverDelta: MENU_HOVER_DELTA,
|
|
pressedOverlays: menuButtonHoverOverlays
|
|
};
|
|
} else {
|
|
localPosition = intersectionItems[intersectedItem].properties.localPosition;
|
|
Overlays.editOverlay(intersectionOverlays[intersectedItem], {
|
|
localPosition: Vec3.sum(localPosition, BUTTON_PRESS_DELTA)
|
|
});
|
|
pressedItem = {
|
|
index: intersectedItem,
|
|
localPosition: localPosition,
|
|
hoverDelta: OPTION_HOVER_DELTA
|
|
};
|
|
}
|
|
pressedSource = intersectionOverlays;
|
|
|
|
// Button press actions.
|
|
if (intersectionOverlays === menuOverlays) {
|
|
openOptions(intersectionItems[intersectedItem]);
|
|
}
|
|
if (intersectionItems[intersectedItem].command) {
|
|
parameter = intersectionItems[intersectedItem].id;
|
|
doCommand(intersectionItems[intersectedItem].command.method, parameter);
|
|
}
|
|
if (intersectionItems[intersectedItem].callback) {
|
|
if (intersectionItems[intersectedItem].callback.parameter) {
|
|
parameterValue = evaluateParameter(intersectionItems[intersectedItem].callback.parameter);
|
|
}
|
|
uiCommandCallback(intersectionItems[intersectedItem].callback.method, parameterValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Picklist update.
|
|
if (intersectionItems && ((hoveredElementType === "picklist"
|
|
&& controlHand.triggerClicked() !== isPicklistPressed)
|
|
|| (intersectionItems[intersectedItem].type !== "picklist" && isPicklistPressed))) {
|
|
isPicklistPressed = controlHand.triggerClicked();
|
|
if (isPicklistPressed) {
|
|
doCommand(intersectionItems[intersectedItem].command.method, intersectionItems[intersectedItem].id);
|
|
}
|
|
}
|
|
if (intersectionItems && ((hoveredElementType === "picklistItem"
|
|
&& controlHand.triggerClicked() !== isPicklistItemPressed)
|
|
|| (intersectionItems[intersectedItem].type !== "picklistItem" && isPicklistItemPressed))) {
|
|
isPicklistItemPressed = controlHand.triggerClicked();
|
|
if (isPicklistItemPressed) {
|
|
doCommand(intersectionItems[intersectedItem].command.method, intersectionItems[intersectedItem].id);
|
|
}
|
|
}
|
|
if (intersectionItems && isPicklistOpen && controlHand.triggerClicked()
|
|
&& hoveredElementType !== "picklist" && hoveredElementType !== "picklistItem") {
|
|
doCommand("togglePhysicsPresets");
|
|
}
|
|
|
|
// Grip click.
|
|
if (controlHand.gripClicked() !== isGripClicked) {
|
|
isGripClicked = !isGripClicked;
|
|
if (isGripClicked && intersectionItems && intersectedItem && intersectionItems[intersectedItem].clear) {
|
|
controlHand.setGripClickedHandled();
|
|
parameter = intersectionItems[intersectedItem].id;
|
|
doGripClicked(intersectionItems[intersectedItem].clear.method, parameter);
|
|
}
|
|
}
|
|
|
|
// Bar slider update.
|
|
if (intersectionItems && hoveredElementType === "barSlider" && controlHand.triggerClicked()) {
|
|
sliderProperties = Overlays.getProperties(intersection.overlayID, ["position", "orientation"]);
|
|
overlayDimensions = intersectionItems[intersectedItem].properties.dimensions;
|
|
if (overlayDimensions === undefined) {
|
|
overlayDimensions = UI_ELEMENTS.barSlider.properties.dimensions;
|
|
}
|
|
basePoint = Vec3.sum(sliderProperties.position,
|
|
Vec3.multiplyQbyV(sliderProperties.orientation, { x: 0, y: -overlayDimensions.y / 2, z: 0 }));
|
|
fraction = Vec3.dot(Vec3.subtract(intersection.intersection, basePoint),
|
|
Vec3.multiplyQbyV(sliderProperties.orientation, Vec3.UNIT_Y)) / overlayDimensions.y;
|
|
fraction = adjustSliderFraction(fraction);
|
|
setBarSliderValue(intersectedItem, fraction);
|
|
if (intersectionItems[intersectedItem].command) {
|
|
doCommand(intersectionItems[intersectedItem].command.method, fraction);
|
|
}
|
|
}
|
|
|
|
// Image slider update.
|
|
if (intersectionItems && hoveredElementType === "imageSlider" && controlHand.triggerClicked()) {
|
|
sliderProperties = Overlays.getProperties(intersection.overlayID, ["position", "orientation"]);
|
|
overlayDimensions = intersectionItems[intersectedItem].properties.dimensions;
|
|
if (overlayDimensions === undefined) {
|
|
overlayDimensions = UI_ELEMENTS.imageSlider.properties.dimensions;
|
|
}
|
|
basePoint = Vec3.sum(sliderProperties.position,
|
|
Vec3.multiplyQbyV(sliderProperties.orientation, { x: 0, y: -overlayDimensions.y / 2, z: 0 }));
|
|
fraction = Vec3.dot(Vec3.subtract(intersection.intersection, basePoint),
|
|
Vec3.multiplyQbyV(sliderProperties.orientation, Vec3.UNIT_Y)) / overlayDimensions.y;
|
|
fraction = adjustSliderFraction(fraction);
|
|
Overlays.editOverlay(optionsSliderData[intersectedItem].value, {
|
|
localPosition: Vec3.sum(optionsSliderData[intersectedItem].offset,
|
|
{ x: 0, y: (fraction - 0.5) * overlayDimensions.y, z: 0 })
|
|
});
|
|
if (intersectionItems[intersectedItem].command) {
|
|
doCommand(intersectionItems[intersectedItem].command.method, fraction);
|
|
}
|
|
}
|
|
|
|
// Color circle update.
|
|
if (intersectionItems && hoveredElementType === "colorCircle" && controlHand.triggerClicked()) {
|
|
sliderProperties = Overlays.getProperties(intersection.overlayID, ["position", "orientation"]);
|
|
delta = Vec3.multiplyQbyV(Quat.inverse(sliderProperties.orientation),
|
|
Vec3.subtract(intersection.intersection, sliderProperties.position));
|
|
radius = Vec3.length(delta);
|
|
if (radius > hsvControl.circle.radius) {
|
|
delta = Vec3.multiply(hsvControl.circle.radius / radius, delta);
|
|
}
|
|
Overlays.editOverlay(optionsColorData[intersectedItem].value, {
|
|
localPosition: Vec3.sum(optionsColorData[intersectedItem].offset,
|
|
{ x: delta.x, y: 0, z: delta.z })
|
|
});
|
|
if (intersectionItems[intersectedItem].command) {
|
|
// Cartesian planar coordinates.
|
|
x = -delta.z; // Coordinates based on rotate cylinder entity. TODO: Use FBX model instead of cylinder entity.
|
|
y = -delta.x; // ""
|
|
s = Math.sqrt(x * x + y * y) / hsvControl.circle.radius;
|
|
h = Math.atan2(y, x) / (2 * Math.PI);
|
|
if (h < 0) {
|
|
h = h + 1;
|
|
}
|
|
doCommand(intersectionItems[intersectedItem].command.method, { h: h, s: s });
|
|
}
|
|
}
|
|
|
|
// Special handling for Group options.
|
|
if (optionsItems && optionsItems === OPTONS_PANELS.groupOptions) {
|
|
enableGroupButton = groupsCount > 1;
|
|
if (enableGroupButton !== isGroupButtonEnabled) {
|
|
isGroupButtonEnabled = enableGroupButton;
|
|
Overlays.editOverlay(optionsOverlays[groupButtonIndex], {
|
|
color: isGroupButtonEnabled
|
|
? (hoveredItem === groupButtonIndex
|
|
? OPTONS_PANELS.groupOptions[groupButtonIndex].highlightColor
|
|
: OPTONS_PANELS.groupOptions[groupButtonIndex].enabledColor)
|
|
: OPTONS_PANELS.groupOptions[groupButtonIndex].properties.color
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[groupButtonIndex], {
|
|
color: isGroupButtonEnabled
|
|
? OPTONS_PANELS.groupOptions[groupButtonIndex].labelEnabledColor
|
|
: OPTONS_PANELS.groupOptions[groupButtonIndex].label.color
|
|
});
|
|
optionsEnabled[groupButtonIndex] = isGroupButtonEnabled;
|
|
}
|
|
|
|
enableUngroupButton = groupsCount === 1 && entitiesCount > 1;
|
|
if (enableUngroupButton !== isUngroupButtonEnabled) {
|
|
isUngroupButtonEnabled = enableUngroupButton;
|
|
Overlays.editOverlay(optionsOverlays[ungroupButtonIndex], {
|
|
color: isUngroupButtonEnabled
|
|
? (hoveredItem === ungroupButtonIndex
|
|
? OPTONS_PANELS.groupOptions[ungroupButtonIndex].highlightColor
|
|
: OPTONS_PANELS.groupOptions[ungroupButtonIndex].enabledColor)
|
|
: OPTONS_PANELS.groupOptions[ungroupButtonIndex].properties.color
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[ungroupButtonIndex], {
|
|
color: isUngroupButtonEnabled
|
|
? OPTONS_PANELS.groupOptions[ungroupButtonIndex].labelEnabledColor
|
|
: OPTONS_PANELS.groupOptions[ungroupButtonIndex].label.color
|
|
});
|
|
optionsEnabled[ungroupButtonIndex] = isUngroupButtonEnabled;
|
|
}
|
|
|
|
enableClearGroupingButton = groupsCount > 0;
|
|
if (enableClearGroupingButton !== isClearGroupingButtonEnabled) {
|
|
isClearGroupingButtonEnabled = enableClearGroupingButton;
|
|
Overlays.editOverlay(optionsOverlays[clearGroupingButtonIndex], {
|
|
color: isClearGroupingButtonEnabled
|
|
? optionsItems[clearGroupingButtonIndex].enabledColor
|
|
: optionsItems[clearGroupingButtonIndex].properties.color
|
|
});
|
|
Overlays.editOverlay(optionsOverlaysLabels[clearGroupingButtonIndex], {
|
|
color: isClearGroupingButtonEnabled
|
|
? optionsItems[clearGroupingButtonIndex].labelEnabledColor
|
|
: optionsItems[clearGroupingButtonIndex].label.color
|
|
});
|
|
optionsEnabled[clearGroupingButtonIndex] = isClearGroupingButtonEnabled;
|
|
}
|
|
}
|
|
|
|
wasTriggerClicked = isTriggerClicked;
|
|
}
|
|
|
|
function display() {
|
|
// Creates and shows menu entities.
|
|
var handJointIndex,
|
|
properties,
|
|
id,
|
|
i,
|
|
length;
|
|
|
|
if (isDisplaying) {
|
|
return;
|
|
}
|
|
|
|
// Joint index.
|
|
handJointIndex = MyAvatar.getJointIndex(attachmentJointName);
|
|
if (handJointIndex === NONE) {
|
|
// Don't display if joint isn't available (yet) to attach to.
|
|
// User can clear this condition by toggling the app off and back on once avatar finishes loading.
|
|
App.log(side, "ERROR: ToolsMenu: Hand joint index isn't available!");
|
|
return;
|
|
}
|
|
|
|
// Menu origin.
|
|
properties = Object.clone(MENU_ORIGIN_PROPERTIES);
|
|
properties.parentJointIndex = handJointIndex;
|
|
properties.localPosition = Vec3.sum(menuOriginLocalPosition, { x: panelLateralOffset, y: 0, z: 0 });
|
|
properties.localRotation = menuOriginLocalRotation;
|
|
menuOriginOverlay = Overlays.addOverlay("sphere", properties);
|
|
|
|
// Header.
|
|
properties = Object.clone(MENU_HEADER_PROPERTIES);
|
|
properties.parentID = menuOriginOverlay;
|
|
menuHeaderOverlay = Overlays.addOverlay("cube", properties);
|
|
properties = Object.clone(MENU_HEADER_HEADING_PROPERTIES);
|
|
properties.parentID = menuHeaderOverlay;
|
|
menuHeaderHeadingOverlay = Overlays.addOverlay("model", properties);
|
|
properties = Object.clone(MENU_HEADER_BAR_PROPERTIES);
|
|
properties.parentID = menuHeaderHeadingOverlay;
|
|
menuHeaderBarOverlay = Overlays.addOverlay("model", properties);
|
|
|
|
// Heading content.
|
|
properties = Object.clone(MENU_HEADER_BACK_PROPERTIES);
|
|
properties.parentID = menuHeaderHeadingOverlay;
|
|
menuHeaderBackOverlay = Overlays.addOverlay("image3d", properties);
|
|
properties = Object.clone(MENU_HEADER_TITLE_PROPERTIES);
|
|
properties.parentID = menuHeaderHeadingOverlay;
|
|
menuHeaderTitleOverlay = Overlays.addOverlay("image3d", properties);
|
|
properties = Object.clone(MENU_HEADER_ICON_PROPERTIES);
|
|
properties.parentID = menuHeaderHeadingOverlay;
|
|
menuHeaderIconOverlay = Overlays.addOverlay("image3d", properties);
|
|
|
|
// Panel background.
|
|
properties = Object.clone(MENU_PANEL_PROPERTIES);
|
|
properties.parentID = menuOriginOverlay;
|
|
menuPanelOverlay = Overlays.addOverlay("cube", properties);
|
|
|
|
// Always-visible overlays.
|
|
staticOverlays = [menuHeaderOverlay, menuHeaderHeadingOverlay, menuHeaderBarOverlay, menuHeaderTitleOverlay,
|
|
menuPanelOverlay];
|
|
|
|
// Menu and footer.
|
|
openMenu();
|
|
displayFooter();
|
|
|
|
// Initial values.
|
|
optionsItems = null;
|
|
intersectionOverlays = null;
|
|
intersectionEnabled = null;
|
|
hoveredItem = NONE;
|
|
hoveredSourceOverlays = null;
|
|
isHoveringButtonElement = false;
|
|
hoveredElementType = null;
|
|
pressedItem = null;
|
|
pressedSource = null;
|
|
isPicklistOpen = false;
|
|
isPicklistPressed = false;
|
|
isPicklistItemPressed = false;
|
|
isTriggerClicked = false;
|
|
wasTriggerClicked = false;
|
|
isGripClicked = false;
|
|
|
|
// Special handling for Group options.
|
|
isGroupButtonEnabled = false;
|
|
isUngroupButtonEnabled = false;
|
|
isClearGroupingButtonEnabled = false;
|
|
for (i = 0, length = OPTONS_PANELS.groupOptions.length; i < length; i++) {
|
|
id = OPTONS_PANELS.groupOptions[i].id;
|
|
if (id === "groupButton") {
|
|
groupButtonIndex = i;
|
|
}
|
|
if (id === "ungroupButton") {
|
|
ungroupButtonIndex = i;
|
|
}
|
|
if (id === "clearGroupingButton") {
|
|
clearGroupingButtonIndex = i;
|
|
}
|
|
}
|
|
|
|
isDisplaying = true;
|
|
}
|
|
|
|
function clear() {
|
|
// Deletes menu entities.
|
|
if (!isDisplaying) {
|
|
return;
|
|
}
|
|
|
|
if (isOptionsOpen) {
|
|
closeOptions();
|
|
}
|
|
|
|
Overlays.deleteOverlay(menuOriginOverlay); // Automatically deletes all other overlays because they're children.
|
|
menuOverlays = [];
|
|
menuHoverOverlays = [];
|
|
menuIconOverlays = [];
|
|
menuLabelOverlays = [];
|
|
menuEnabled = [];
|
|
footerOverlays = [];
|
|
footerHoverOverlays = [];
|
|
footerIconOverlays = [];
|
|
footerLabelOverlays = [];
|
|
footerEnabled = [];
|
|
isDisplaying = false;
|
|
}
|
|
|
|
function destroy() {
|
|
clear();
|
|
}
|
|
|
|
return {
|
|
COLOR_TOOL: COLOR_TOOL,
|
|
SCALE_TOOL: SCALE_TOOL,
|
|
CLONE_TOOL: CLONE_TOOL,
|
|
GROUP_TOOL: GROUP_TOOL,
|
|
PHYSICS_TOOL: PHYSICS_TOOL,
|
|
DELETE_TOOL: DELETE_TOOL,
|
|
iconInfo: getIconInfo,
|
|
setHand: setHand,
|
|
overlayIDs: getOverlayIDs,
|
|
clearTool: clearTool,
|
|
doCommand: doCommand,
|
|
setVisible: setVisible,
|
|
update: update,
|
|
display: display,
|
|
clear: clear,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
ToolsMenu.prototype = {};
|