mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge branch 'master' into particlesInEdit2
This commit is contained in:
commit
f9a76a7502
61 changed files with 1224 additions and 1184 deletions
|
@ -680,11 +680,11 @@ void AudioMixer::domainSettingsRequestComplete() {
|
|||
void AudioMixer::broadcastMixes() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
int nextFrame = 0;
|
||||
int64_t nextFrame = 0;
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
int usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
||||
int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||
|
@ -826,12 +826,7 @@ void AudioMixer::broadcastMixes() {
|
|||
break;
|
||||
}
|
||||
|
||||
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us
|
||||
|
||||
if (usecToSleep > int(USECS_PER_SECOND)) {
|
||||
qDebug() << "DANGER: amount to sleep is" << usecToSleep;
|
||||
qDebug() << "NextFrame is" << nextFrame << "and timer nsecs elapsed is" << timer.nsecsElapsed();
|
||||
}
|
||||
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000);
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
|
|
|
@ -976,6 +976,187 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-header text-section">
|
||||
<label>Text</label>
|
||||
</div>
|
||||
|
||||
<div class="text-section property">
|
||||
<div class="label">Text Content</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-text-text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Line Height</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Text Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-text-text-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Background Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-text-background-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-header zone-section">
|
||||
<label>Zone</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<span class="label">Stage Sun Model Enabled</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-sun-model-enabled">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section keyLight-section">
|
||||
<label>KeyLight</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-zone-key-light-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Direction</div>
|
||||
<div class="value">
|
||||
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></div>
|
||||
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></div>
|
||||
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Ambient Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Ambient URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-zone-key-ambient-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section stage-section">
|
||||
<label>Stage</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Latitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Longitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Altitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-altitude" step="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<span class="label">Automatically calculate stage hour and day from location and clock.</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-automatic-hour-day">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Day</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Hour</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section background-section">
|
||||
<label>Background</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section background-section property">
|
||||
<div class="label">Background Mode</div>
|
||||
<div class="value">
|
||||
<select name="SelectBackgroundMode" id="property-zone-background-mode">
|
||||
<option value='inherit'>Nothing</option>
|
||||
<option value='skybox'>Skybox</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sub-section-header zone-section skybox-section">
|
||||
<label>Skybox</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section skybox-section property">
|
||||
<div class="label">Skybox Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-zone-skybox-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section skybox-section property">
|
||||
<div class="label">Skybox URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-zone-skybox-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-header web-section">
|
||||
<label>Web</label>
|
||||
</div>
|
||||
|
||||
<div class="web-section property">
|
||||
<div class="label">Source URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-web-source-url" class="url">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section-header">
|
||||
<label>Hyperlink</label>
|
||||
|
@ -1311,18 +1492,6 @@
|
|||
</div>
|
||||
|
||||
|
||||
<div class="section-header web-section">
|
||||
<label>Web</label>
|
||||
</div>
|
||||
|
||||
<div class="web-section property">
|
||||
<div class="label">Source URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-web-source-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section-header particle-section">
|
||||
<label>Particle</label>
|
||||
</div>
|
||||
|
@ -1365,41 +1534,7 @@
|
|||
</div>
|
||||
|
||||
|
||||
<div class="section-header text-section">
|
||||
<label>Text</label>
|
||||
</div>
|
||||
|
||||
<div class="text-section property">
|
||||
<div class="label">Text Content</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-text-text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Line Height</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Text Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-text-text-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-section property">
|
||||
<div class="label">Background Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-text-background-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="section-header light-section">
|
||||
<label>Light</label>
|
||||
|
@ -1438,141 +1573,6 @@
|
|||
<input class="coord" type='number' id="property-light-cutoff">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section-header zone-section">
|
||||
<label>Zone</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<span class="label">Stage Sun Model Enabled</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-sun-model-enabled">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section keyLight-section">
|
||||
<label>KeyLight</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-zone-key-light-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Light Direction</div>
|
||||
<div class="value">
|
||||
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></div>
|
||||
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></div>
|
||||
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Ambient Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="zone-section keyLight-section property">
|
||||
<div class="label">Ambient URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-zone-key-ambient-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section stage-section">
|
||||
<label>Stage</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Latitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Longitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Altitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-altitude" step="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<span class="label">Automatically calculate stage hour and day from location and clock.</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-automatic-hour-day">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Day</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section stage-section property">
|
||||
<div class="label">Stage Hour</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sub-section-header zone-section background-section">
|
||||
<label>Background</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section background-section property">
|
||||
<div class="label">Background Mode</div>
|
||||
<div class="value">
|
||||
<select name="SelectBackgroundMode" id="property-zone-background-mode">
|
||||
<option value='inherit'>Nothing</option>
|
||||
<option value='skybox'>Skybox</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="sub-section-header zone-section skybox-section">
|
||||
<label>Skybox</label>
|
||||
</div>
|
||||
|
||||
<div class="zone-section skybox-section property">
|
||||
<div class="label">Skybox Color</div>
|
||||
<div class="value">
|
||||
<div class='color-picker' id="property-zone-skybox-color"></div>
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section skybox-section property">
|
||||
<div class="label">Skybox URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-zone-skybox-url" class="url">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
|
@ -236,18 +236,10 @@
|
|||
"dimensions"
|
||||
]);
|
||||
|
||||
ImageOverlay = generateOverlayClass(Overlay2D, "image", [
|
||||
"subImage", "imageURL"
|
||||
]);
|
||||
|
||||
Image3DOverlay = generateOverlayClass(Billboard3DOverlay, "image3d", [
|
||||
"url", "subImage"
|
||||
]);
|
||||
|
||||
TextOverlay = generateOverlayClass(Overlay2D, "text", [
|
||||
"font", "text", "backgroundColor", "backgroundAlpha", "leftMargin", "topMargin"
|
||||
]);
|
||||
|
||||
Text3DOverlay = generateOverlayClass(Billboard3DOverlay, "text3d", [
|
||||
"text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin",
|
||||
"rightMargin", "bottomMargin"
|
||||
|
|
|
@ -132,14 +132,15 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
this.y = y;
|
||||
this.width = 0;
|
||||
this.height = ToolBar.TITLE_BAR_HEIGHT;
|
||||
this.back = this.back = Overlays.addOverlay("text", {
|
||||
backgroundColor: { red: 255, green: 255, blue: 255 },
|
||||
this.backAlpha = 1.0;
|
||||
this.back = Overlays.addOverlay("rectangle", {
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
radius: 4,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
alpha: 1.0,
|
||||
backgroundAlpha: 1.0,
|
||||
alpha: this.backAlpha,
|
||||
visible: false
|
||||
});
|
||||
this.spacing = [];
|
||||
|
@ -246,10 +247,8 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
this.tools[tool].setAlpha(alpha);
|
||||
}
|
||||
if (this.back != null) {
|
||||
Overlays.editOverlay(this.back, {
|
||||
alpha: alpha,
|
||||
backgroundAlpha: alpha
|
||||
});
|
||||
this.backAlpha = alpha;
|
||||
Overlays.editOverlay(this.back, { alpha: alpha });
|
||||
}
|
||||
} else {
|
||||
this.tools[tool].setAlpha(alpha);
|
||||
|
@ -258,9 +257,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
|
||||
this.setBack = function(color, alpha) {
|
||||
if (color == null) {
|
||||
Overlays.editOverlay(this.back, {
|
||||
visible: false
|
||||
});
|
||||
Overlays.editOverlay(this.back, { visible: false });
|
||||
} else {
|
||||
Overlays.editOverlay(this.back, {
|
||||
width: this.width +
|
||||
|
@ -268,8 +265,8 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
height: this.height +
|
||||
((direction == ToolBar.VERTICAL) ? 1 : 2) * ToolBar.SPACING,
|
||||
visible: true,
|
||||
backgroundColor: color,
|
||||
backgroundAlpha: alpha
|
||||
color: color,
|
||||
alpha: alpha
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -339,12 +336,9 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
that.hover = function (enable) { // Can be overriden or extended by clients.
|
||||
that.isHovering = enable;
|
||||
if (that.back) {
|
||||
if (enable) {
|
||||
that.oldAlpha = Overlays.getProperty(that.back, 'backgroundAlpha');
|
||||
}
|
||||
Overlays.editOverlay(this.back, {
|
||||
visible: enable,
|
||||
backgroundAlpha: enable ? 0.5 : that.oldAlpha
|
||||
alpha: enable ? 0.5 : that.backAlpha
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
"id": "rightHandGraspOpen",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_right.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -157,7 +157,7 @@
|
|||
"id": "rightHandGraspClosed",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_right.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -205,7 +205,7 @@
|
|||
"id": "leftHandGraspOpen",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_left.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -217,7 +217,7 @@
|
|||
"id": "leftHandGraspClosed",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_left.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_left.fbx",
|
||||
"startFrame": 10.0,
|
||||
"endFrame": 10.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -420,7 +420,7 @@
|
|||
"id": "idleStand",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -432,7 +432,7 @@
|
|||
"id": "idleTalk",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/talk/talk.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/talk.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 801.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -457,7 +457,7 @@
|
|||
"id": "walkFwdShort",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_fwd.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_fwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 39.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -469,7 +469,7 @@
|
|||
"id": "walkFwdNormal",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_fwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 35.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -481,7 +481,7 @@
|
|||
"id": "walkFwdRun",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/run_fwd.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/run_fwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 21.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -495,7 +495,7 @@
|
|||
"id": "idleToWalkFwd",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/idle_to_walk.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle_to_walk.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 19.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -518,7 +518,7 @@
|
|||
"id": "walkBwdShort",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_bwd.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_bwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 38.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -530,7 +530,7 @@
|
|||
"id": "walkBwdNormal",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_bwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 36.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -544,7 +544,7 @@
|
|||
"id": "turnLeft",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_left.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 28.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -556,7 +556,7 @@
|
|||
"id": "turnRight",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_right.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 30.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -579,7 +579,7 @@
|
|||
"id": "strafeLeftShort",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_left.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 28.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -591,7 +591,7 @@
|
|||
"id": "strafeLeftNormal",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_left.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 30.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -616,7 +616,7 @@
|
|||
"id": "strafeRightShort",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_right.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 28.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -628,7 +628,7 @@
|
|||
"id": "strafeRightNormal",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_right.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_right.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 30.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -642,7 +642,7 @@
|
|||
"id": "awayIntro",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 83.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -654,7 +654,7 @@
|
|||
"id": "away",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 83.0,
|
||||
"endFrame": 84.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -666,7 +666,7 @@
|
|||
"id": "awayOutro",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx",
|
||||
"startFrame": 84.0,
|
||||
"endFrame": 167.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -678,7 +678,7 @@
|
|||
"id": "fly",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/fly.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 80.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -700,7 +700,7 @@
|
|||
"id": "userAnimA",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -712,7 +712,7 @@
|
|||
"id": "userAnimB",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx",
|
||||
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
TextOverlayElement {
|
||||
id: root
|
||||
Rectangle {
|
||||
color: root.backgroundColor
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
x: root.leftMargin
|
||||
y: root.topMargin
|
||||
id: text
|
||||
objectName: "textElement"
|
||||
text: root.text
|
||||
color: root.textColor
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.fontSize
|
||||
lineHeightMode: Text.FixedHeight
|
||||
lineHeight: root.lineHeight
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,8 +91,10 @@ FocusScope {
|
|||
id: popup
|
||||
parent: desktop
|
||||
anchors.fill: parent
|
||||
z: desktop.zLevels.menu
|
||||
visible: false
|
||||
focus: true
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: hideList();
|
||||
|
@ -116,7 +118,7 @@ FocusScope {
|
|||
|
||||
ListView {
|
||||
id: listView
|
||||
height: textView.height * count
|
||||
height: textField.height * count * 1.4
|
||||
model: root.model
|
||||
highlight: Rectangle{
|
||||
width: listView.currentItem ? listView.currentItem.width : 0
|
||||
|
|
|
@ -25,7 +25,7 @@ FocusScope {
|
|||
readonly property alias zLevels: zLevels
|
||||
QtObject {
|
||||
id: zLevels;
|
||||
readonly property real normal: 0
|
||||
readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls.
|
||||
readonly property real top: 2000
|
||||
readonly property real modal: 4000
|
||||
readonly property real menu: 8000
|
||||
|
@ -252,11 +252,17 @@ FocusScope {
|
|||
return messageDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: queryDialogBuilder; QueryDialog { } }
|
||||
function queryBox(properties) {
|
||||
return queryDialogBuilder.createObject(desktop, properties);
|
||||
Component { id: inputDialogBuilder; QueryDialog { } }
|
||||
function inputDialog(properties) {
|
||||
return inputDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: fileDialogBuilder; FileDialog { } }
|
||||
function fileOpenDialog(properties) {
|
||||
return fileDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
|
||||
MenuMouseHandler { id: menuPopperUpper }
|
||||
function popupMenu(point) {
|
||||
menuPopperUpper.popup(desktop, rootMenu.items, point);
|
||||
|
|
|
@ -12,6 +12,27 @@ import "fileDialog"
|
|||
//FIXME implement shortcuts for favorite location
|
||||
ModalWindow {
|
||||
id: root
|
||||
resizable: true
|
||||
width: 640
|
||||
height: 480
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
}
|
||||
|
||||
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias caption: root.title;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias dir: model.folder;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias filter: selectionType.filtersString;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property int options; // <-- FIXME unused
|
||||
|
||||
property bool selectDirectory: false;
|
||||
property bool showHidden: false;
|
||||
|
@ -19,17 +40,11 @@ ModalWindow {
|
|||
property bool multiSelect: false;
|
||||
// FIXME implement
|
||||
property bool saveDialog: false;
|
||||
property var helper: fileDialogHelper
|
||||
property alias model: fileTableView.model
|
||||
|
||||
signal selectedFile(var file);
|
||||
signal canceled();
|
||||
resizable: true
|
||||
width: 640
|
||||
height: 480
|
||||
|
||||
property var helper: fileDialogHelper
|
||||
property alias model: fileTableView.model
|
||||
property alias filterModel: selectionType.model
|
||||
property alias folder: model.folder
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
@ -120,6 +135,7 @@ ModalWindow {
|
|||
onDoubleClicked: navigateToRow(row);
|
||||
model: FolderListModel {
|
||||
id: model
|
||||
nameFilters: selectionType.currentFilter
|
||||
showDirsFirst: true
|
||||
showDotAndDotDot: false
|
||||
showFiles: !root.selectDirectory
|
||||
|
@ -157,12 +173,10 @@ ModalWindow {
|
|||
readOnly: true
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
FileTypeSelection {
|
||||
id: selectionType
|
||||
anchors { bottom: buttonRow.top; bottomMargin: 8; right: parent.right; rightMargin: 8; left: buttonRow.left }
|
||||
visible: !selectDirectory
|
||||
model: ListModel { ListElement { text: "All Files (*.*)"; filter: "*.*" } }
|
||||
// onCurrentIndexChanged: model.nameFilters = [ filterModel.get(currentIndex).filter ]
|
||||
KeyNavigation.left: fileTableView
|
||||
KeyNavigation.right: openButton
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs
|
|||
import "../controls"
|
||||
import "../styles"
|
||||
import "../windows"
|
||||
import "messageDialog"
|
||||
|
||||
// FIXME respect default button functionality
|
||||
ModalWindow {
|
||||
|
@ -126,126 +127,23 @@ ModalWindow {
|
|||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
layoutDirection: Qt.RightToLeft
|
||||
anchors { bottom: details.top; right: parent.right; margins: d.spacing * 2; bottomMargin: 0 }
|
||||
Button {
|
||||
id: okButton
|
||||
text: qsTr("OK")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Ok
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Ok)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Ok
|
||||
|
||||
}
|
||||
Button {
|
||||
id: openButton
|
||||
text: qsTr("Open")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Open
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Open)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Open
|
||||
}
|
||||
Button {
|
||||
id: saveButton
|
||||
text: qsTr("Save")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Save
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Save)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Save
|
||||
}
|
||||
Button {
|
||||
id: saveAllButton
|
||||
text: qsTr("Save All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.SaveAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.SaveAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.SaveAll
|
||||
}
|
||||
Button {
|
||||
id: retryButton
|
||||
text: qsTr("Retry")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Retry
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Retry)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Retry
|
||||
}
|
||||
Button {
|
||||
id: ignoreButton
|
||||
text: qsTr("Ignore")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Ignore
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Ignore)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Ignore
|
||||
}
|
||||
Button {
|
||||
id: applyButton
|
||||
text: qsTr("Apply")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Apply
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Apply)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Apply
|
||||
}
|
||||
Button {
|
||||
id: yesButton
|
||||
text: qsTr("Yes")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Yes
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Yes)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Yes
|
||||
}
|
||||
Button {
|
||||
id: yesAllButton
|
||||
text: qsTr("Yes to All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.YesToAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.YesToAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.YesToAll
|
||||
}
|
||||
Button {
|
||||
id: noButton
|
||||
text: qsTr("No")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.No
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.No)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.No
|
||||
}
|
||||
Button {
|
||||
id: noAllButton
|
||||
text: qsTr("No to All")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.NoToAll
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.NoToAll)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.NoToAll
|
||||
}
|
||||
Button {
|
||||
id: discardButton
|
||||
text: qsTr("Discard")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Discard
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Discard)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Discard
|
||||
}
|
||||
Button {
|
||||
id: resetButton
|
||||
text: qsTr("Reset")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Reset
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Reset)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Reset
|
||||
}
|
||||
Button {
|
||||
id: restoreDefaultsButton
|
||||
text: qsTr("Restore Defaults")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.RestoreDefaults
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.RestoreDefaults)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.RestoreDefaults
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: qsTr("Cancel")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Cancel
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Cancel)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Cancel
|
||||
}
|
||||
Button {
|
||||
id: abortButton
|
||||
text: qsTr("Abort")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Abort
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Abort)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Abort
|
||||
}
|
||||
Button {
|
||||
id: closeButton
|
||||
text: qsTr("Close")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Close
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Close)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Close
|
||||
}
|
||||
MessageDialogButton { dialog: root; text: qsTr("OK"); button: OriginalDialogs.StandardButton.Ok; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes"); button: OriginalDialogs.StandardButton.Yes; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No"); button: OriginalDialogs.StandardButton.No; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; }
|
||||
MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; }
|
||||
Button {
|
||||
id: moreButton
|
||||
text: qsTr("Show Details...")
|
||||
|
@ -253,13 +151,7 @@ ModalWindow {
|
|||
}
|
||||
visible: detailedText && detailedText.length > 0
|
||||
}
|
||||
Button {
|
||||
id: helpButton
|
||||
text: qsTr("Help")
|
||||
focus: root.defaultButton === OriginalDialogs.StandardButton.Help
|
||||
onClicked: root.click(OriginalDialogs.StandardButton.Help)
|
||||
visible: root.buttons & OriginalDialogs.StandardButton.Help
|
||||
}
|
||||
MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; }
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -328,7 +220,7 @@ ModalWindow {
|
|||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true
|
||||
root.click(OriginalDialogs.StandardButton.Ok)
|
||||
root.click(root.defaultButton)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,17 @@ ModalWindow {
|
|||
signal selected(var result);
|
||||
signal canceled();
|
||||
|
||||
property alias result: textResult.text
|
||||
property var items;
|
||||
property alias label: mainTextContainer.text
|
||||
property var result;
|
||||
// FIXME not current honored
|
||||
property var current;
|
||||
|
||||
// For text boxes
|
||||
property alias placeholderText: textResult.placeholderText
|
||||
property alias text: mainTextContainer.text
|
||||
|
||||
// For combo boxes
|
||||
property bool editable: true;
|
||||
|
||||
Rectangle {
|
||||
clip: true
|
||||
|
@ -55,10 +63,20 @@ ModalWindow {
|
|||
anchors { top: mainTextContainer.bottom; bottom: buttons.top; left: parent.left; right: parent.right; margins: d.spacing }
|
||||
// FIXME make a text field type that can be bound to a history for autocompletion
|
||||
TextField {
|
||||
focus: true
|
||||
id: textResult
|
||||
focus: items ? false : true
|
||||
visible: items ? false : true
|
||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
}
|
||||
|
||||
VrControls.ComboBox {
|
||||
id: comboBox
|
||||
focus: items ? true : false
|
||||
visible: items ? true : false
|
||||
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
|
||||
model: items ? items : []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Flow {
|
||||
|
@ -86,6 +104,7 @@ ModalWindow {
|
|||
text: qsTr("OK")
|
||||
shortcut: Qt.Key_Return
|
||||
onTriggered: {
|
||||
root.result = items ? comboBox.currentText : textResult.text
|
||||
root.selected(root.result);
|
||||
root.destroy();
|
||||
}
|
||||
|
|
|
@ -72,23 +72,6 @@ Window {
|
|||
scripts.stopAllScripts();
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDialogBuilder
|
||||
FileDialog { }
|
||||
}
|
||||
|
||||
function loadFromFile() {
|
||||
var fileDialog = fileDialogBuilder.createObject(desktop, { filterModel: fileFilters });
|
||||
fileDialog.canceled.connect(function(){
|
||||
console.debug("Cancelled file open")
|
||||
})
|
||||
|
||||
fileDialog.selectedFile.connect(function(file){
|
||||
console.debug("Selected " + file)
|
||||
scripts.loadOneScript(file);
|
||||
})
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "white"
|
||||
anchors.fill: parent
|
||||
|
@ -123,26 +106,42 @@ Window {
|
|||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
clip: true
|
||||
anchors { fill: parent; margins: 0 }
|
||||
|
||||
model: runningScriptsModel
|
||||
|
||||
delegate: Rectangle {
|
||||
id: rectangle
|
||||
clip: true
|
||||
radius: 3
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
|
||||
height: scriptName.height + 12
|
||||
color: index % 2 ? "#ddd" : "#eee"
|
||||
height: scriptName.height + 12 + (ListView.isCurrentItem ? scriptName.height + 6 : 0)
|
||||
color: ListView.isCurrentItem ? "#39f" :
|
||||
index % 2 ? "#ddd" : "#eee"
|
||||
|
||||
Text {
|
||||
anchors { left: parent.left; leftMargin: 4; verticalCenter: parent.verticalCenter }
|
||||
id: scriptName
|
||||
anchors { left: parent.left; leftMargin: 4; top: parent.top; topMargin:6 }
|
||||
text: name
|
||||
}
|
||||
|
||||
Text {
|
||||
id: scriptUrl
|
||||
anchors { left: scriptName.left; right: parent.right; rightMargin: 4; top: scriptName.bottom; topMargin: 6 }
|
||||
text: url
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: listView.currentIndex = index
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenter: scriptName.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
spacing: 4
|
||||
|
@ -185,31 +184,38 @@ Window {
|
|||
anchors.bottomMargin: 8
|
||||
anchors.right: parent.right
|
||||
|
||||
// For some reason trigginer an API that enters
|
||||
// an internal event loop directly from the button clicked
|
||||
// trigger below causes the appliction to behave oddly.
|
||||
// Most likely because the button onClicked handling is never
|
||||
// completed until the function returns.
|
||||
// FIXME find a better way of handling the input dialogs that
|
||||
// doesn't trigger this.
|
||||
Timer {
|
||||
id: asyncAction
|
||||
interval: 50
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: ApplicationInterface.loadScriptURLDialog();
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "from URL";
|
||||
onClicked: {
|
||||
focus = false;
|
||||
asyncAction.running = true;
|
||||
onClicked: fromUrlTimer.running = true;
|
||||
|
||||
// For some reason trigginer an API that enters
|
||||
// an internal event loop directly from the button clicked
|
||||
// trigger below causes the appliction to behave oddly.
|
||||
// Most likely because the button onClicked handling is never
|
||||
// completed until the function returns.
|
||||
// FIXME find a better way of handling the input dialogs that
|
||||
// doesn't trigger this.
|
||||
Timer {
|
||||
id: fromUrlTimer
|
||||
interval: 5
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: ApplicationInterface.loadScriptURLDialog();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "from Disk"
|
||||
onClicked: loadFromFile();
|
||||
onClicked: fromDiskTimer.running = true;
|
||||
|
||||
Timer {
|
||||
id: fromDiskTimer
|
||||
interval: 5
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: ApplicationInterface.loadDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import QtQuick 2.5
|
||||
|
||||
import "../../controls" as VrControls
|
||||
|
||||
VrControls.ComboBox {
|
||||
id: root
|
||||
property string filtersString: "All Files (*.*)";
|
||||
property var currentFilter: [ "*.*" ];
|
||||
|
||||
// Per http://doc.qt.io/qt-5/qfiledialog.html#getOpenFileName the string can contain
|
||||
// multiple filters separated by semicolons
|
||||
// ex: "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
|
||||
model: filtersString.split(';;');
|
||||
|
||||
enabled: model.length > 1
|
||||
|
||||
onCurrentTextChanged: {
|
||||
var globRegex = /\((.*)\)$/
|
||||
var globs = globRegex.exec(currentText);
|
||||
if (!globs[1]) {
|
||||
console.warn("Unable to parse filter " + currentText);
|
||||
return;
|
||||
}
|
||||
currentFilter = globs[1].split(" ");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
Button {
|
||||
property var dialog;
|
||||
property int button: StandardButton.NoButton;
|
||||
|
||||
focus: dialog.defaultButton === button
|
||||
onClicked: dialog.click(button)
|
||||
visible: dialog.buttons & button
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtWebEngine 1.1
|
||||
|
||||
import "../../windows" as Windows
|
||||
|
@ -11,9 +11,7 @@ Windows.Window {
|
|||
HifiConstants { id: hifi }
|
||||
width: 900; height: 700
|
||||
resizable: true
|
||||
anchors.centerIn: parent
|
||||
modality: Qt.ApplicationModal
|
||||
frame: Windows.ModalFrame {}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
|
78
interface/resources/qml/hifi/overlays/ImageOverlay.qml
Normal file
78
interface/resources/qml/hifi/overlays/ImageOverlay.qml
Normal file
|
@ -0,0 +1,78 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
import "."
|
||||
|
||||
Overlay {
|
||||
id: root
|
||||
|
||||
Image {
|
||||
id: image
|
||||
property bool scaleFix: true;
|
||||
property real xOffset: 0
|
||||
property real yOffset: 0
|
||||
property real imageScale: 1.0
|
||||
property var resizer: Timer {
|
||||
interval: 50
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: {
|
||||
var targetAspect = root.width / root.height;
|
||||
var sourceAspect = image.sourceSize.width / image.sourceSize.height;
|
||||
if (sourceAspect <= targetAspect) {
|
||||
if (root.width === image.sourceSize.width) {
|
||||
return;
|
||||
}
|
||||
image.imageScale = root.width / image.sourceSize.width;
|
||||
} else if (sourceAspect > targetAspect){
|
||||
if (root.height === image.sourceSize.height) {
|
||||
return;
|
||||
}
|
||||
image.imageScale = root.height / image.sourceSize.height;
|
||||
}
|
||||
image.sourceSize = Qt.size(image.sourceSize.width * image.imageScale, image.sourceSize.height * image.imageScale);
|
||||
}
|
||||
}
|
||||
x: -1 * xOffset * imageScale
|
||||
y: -1 * yOffset * imageScale
|
||||
|
||||
onSourceSizeChanged: {
|
||||
if (sourceSize.width !== 0 && sourceSize.height !== 0 && progress === 1.0 && scaleFix) {
|
||||
scaleFix = false;
|
||||
resizer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateSubImage(subImage) {
|
||||
var keys = Object.keys(subImage);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = subImage[key];
|
||||
switch (key) {
|
||||
case "x": image.xOffset = value; break;
|
||||
case "y": image.yOffset = value; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePropertiesFromScript(properties) {
|
||||
var keys = Object.keys(properties);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = properties[key];
|
||||
switch (key) {
|
||||
case "height": root.height = value; break;
|
||||
case "width": root.width = value; break;
|
||||
case "x": root.x = value; break;
|
||||
case "y": root.y = value; break;
|
||||
case "visible": root.visible = value; break;
|
||||
case "alpha": root.opacity = value; break;
|
||||
case "imageURL": image.source = value; break;
|
||||
case "subImage": updateSubImage(value); break;
|
||||
default: console.log("OVERLAY Unhandled image property " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
interface/resources/qml/hifi/overlays/Overlay.qml
Normal file
30
interface/resources/qml/hifi/overlays/Overlay.qml
Normal file
|
@ -0,0 +1,30 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
Item {
|
||||
id: root
|
||||
clip: true
|
||||
|
||||
property int dumpDepth: 0;
|
||||
|
||||
|
||||
function dumpObject(object) {
|
||||
var keys = Object.keys(object);
|
||||
var tabsString = "";
|
||||
for (var j = 0; j < dumpDepth; ++j) {
|
||||
tabsString = tabsString + "\t";
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = object[key];
|
||||
console.log(tabsString + "OVERLAY Key " + key + " (" + typeof(value) + "): " + value);
|
||||
if (typeof(value) === "object") {
|
||||
++dumpDepth;
|
||||
dumpObject(value)
|
||||
--dumpDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
interface/resources/qml/hifi/overlays/RectangleOverlay.qml
Normal file
38
interface/resources/qml/hifi/overlays/RectangleOverlay.qml
Normal file
|
@ -0,0 +1,38 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
import "."
|
||||
|
||||
Overlay {
|
||||
id: root
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
anchors.fill: parent
|
||||
color: "black"
|
||||
}
|
||||
|
||||
function updatePropertiesFromScript(properties) {
|
||||
var keys = Object.keys(properties);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = properties[key];
|
||||
console.log("OVERLAY rectangle property " + key + " set to value " + value);
|
||||
switch (key) {
|
||||
case "height": root.height = value; break;
|
||||
case "width": root.width = value; break;
|
||||
case "x": root.x = value; break;
|
||||
case "y": root.y = value; break;
|
||||
case "visible": root.visible = value; break;
|
||||
case "alpha": rectangle.color.a = value; break;
|
||||
case "color": rectangle.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.color.a); break;
|
||||
case "borderAlpha": rectangle.border.color.a = value; break;
|
||||
case "borderColor": rectangle.border.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.border.color.a); break;
|
||||
case "borderWidth": rectangle.border.width = value; break;
|
||||
case "radius": rectangle.radius = value; break;
|
||||
default: console.log("OVERLAY Unhandled rectangle property " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
54
interface/resources/qml/hifi/overlays/TextOverlay.qml
Normal file
54
interface/resources/qml/hifi/overlays/TextOverlay.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
import "."
|
||||
|
||||
Overlay {
|
||||
id: root
|
||||
clip: true
|
||||
Rectangle {
|
||||
id: background;
|
||||
anchors.fill: parent
|
||||
color: "#B2000000"
|
||||
|
||||
Text {
|
||||
id: textField;
|
||||
anchors { fill: parent; bottomMargin: textField.anchors.topMargin; rightMargin: textField.anchors.leftMargin; }
|
||||
objectName: "textElement"
|
||||
color: "white"
|
||||
lineHeightMode: Text.FixedHeight
|
||||
font.family: "Helvetica"
|
||||
font.pixelSize: 18
|
||||
lineHeight: 18
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updatePropertiesFromScript(properties) {
|
||||
var keys = Object.keys(properties);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = properties[key];
|
||||
switch (key) {
|
||||
case "height": root.height = value; break;
|
||||
case "width": root.width = value; break;
|
||||
case "x": root.x = value; break;
|
||||
case "y": root.y = value; break;
|
||||
case "visible": root.visible = value; break;
|
||||
case "alpha": textField.color.a = value; break;
|
||||
case "margin": textField.anchors.margins = value; break;
|
||||
case "leftMargin": textField.anchors.leftMargin = value; break;
|
||||
case "topMargin": textField.anchors.topMargin = value; break;
|
||||
case "color": // fall through
|
||||
case "textColor": textField.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, textField.color.a); break;
|
||||
case "text": textField.text = value; break;
|
||||
case "backgroundAlpha": background.color = Qt.rgba(background.color.r, background.color.g, background.color.b, value); break;
|
||||
case "backgroundColor": background.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, background.color.a); break;
|
||||
case "font": textField.font.pixelSize = value.size; break;
|
||||
case "lineHeight": textField.lineHeight = value; break;
|
||||
default:
|
||||
console.log("OVERLAY text unhandled property " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,12 +20,8 @@ Frame {
|
|||
|
||||
Row {
|
||||
id: controlsRow
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: iconSize
|
||||
anchors.topMargin: iconSize / 2
|
||||
anchors { right: parent.right; top: parent.top; rightMargin: iconSize; topMargin: iconSize / 2; }
|
||||
spacing: iconSize / 4
|
||||
|
||||
FontAwesome {
|
||||
visible: false
|
||||
text: "\uf08d"
|
||||
|
@ -54,6 +50,18 @@ Frame {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: titleText
|
||||
anchors { left: parent.left; leftMargin: iconSize; right: controlsRow.left; rightMargin: iconSize; top: parent.top; topMargin: iconSize / 2; }
|
||||
text: window.title
|
||||
elide: Text.ElideRight
|
||||
font.bold: true
|
||||
color: window.focus ? "white" : "gray"
|
||||
style: Text.Outline;
|
||||
styleColor: "black"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Item {
|
|||
id: debugZ
|
||||
visible: DebugQML
|
||||
text: window ? "Z: " + window.z : ""
|
||||
y: -height
|
||||
y: window.height + 4
|
||||
}
|
||||
|
||||
function deltaSize(dx, dy) {
|
||||
|
|
|
@ -13,5 +13,16 @@ Frame {
|
|||
color: "#7f7f7f7f";
|
||||
radius: 3;
|
||||
}
|
||||
|
||||
Text {
|
||||
y: -implicitHeight - iconSize / 2
|
||||
text: window.title
|
||||
elide: Text.ElideRight
|
||||
font.bold: true
|
||||
color: window.focus ? "white" : "gray"
|
||||
style: Text.Outline;
|
||||
styleColor: "black"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -406,6 +406,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_entityClipboard(new EntityTree()),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_scaleMirror(1.0f),
|
||||
_rotateMirror(0.0f),
|
||||
|
@ -4501,14 +4502,24 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject
|
|||
}
|
||||
|
||||
void Application::loadDialog() {
|
||||
// To be migratd to QML
|
||||
QString fileNameString = QFileDialog::getOpenFileName(
|
||||
_glWidget, tr("Open Script"), "", tr("JavaScript Files (*.js)"));
|
||||
if (!fileNameString.isEmpty()) {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
QString fileNameString = OffscreenUi::getOpenFileName(
|
||||
_glWidget, tr("Open Script"), getPreviousScriptLocation(), tr("JavaScript Files (*.js)"));
|
||||
if (!fileNameString.isEmpty() && QFile(fileNameString).exists()) {
|
||||
setPreviousScriptLocation(QFileInfo(fileNameString).absolutePath());
|
||||
DependencyManager::get<ScriptEngines>()->loadScript(fileNameString, true, false, false, true); // Don't load from cache
|
||||
}
|
||||
}
|
||||
|
||||
QString Application::getPreviousScriptLocation() {
|
||||
QString result = _previousScriptLocation.get();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Application::setPreviousScriptLocation(const QString& location) {
|
||||
_previousScriptLocation.set(location);
|
||||
}
|
||||
|
||||
void Application::loadScriptURLDialog() {
|
||||
auto newScript = OffscreenUi::getText(nullptr, "Open and Run Script", "Script URL");
|
||||
if (!newScript.isEmpty()) {
|
||||
|
|
|
@ -103,6 +103,9 @@ public:
|
|||
|
||||
void postLambdaEvent(std::function<void()> f) override;
|
||||
|
||||
QString getPreviousScriptLocation();
|
||||
void setPreviousScriptLocation(const QString& previousScriptLocation);
|
||||
|
||||
void initializeGL();
|
||||
void initializeUi();
|
||||
void paintGL();
|
||||
|
@ -431,6 +434,7 @@ private:
|
|||
Camera _mirrorCamera; // Cammera for mirror view
|
||||
QRect _mirrorViewRect;
|
||||
|
||||
Setting::Handle<QString> _previousScriptLocation;
|
||||
Setting::Handle<float> _fieldOfView;
|
||||
|
||||
float _scaleMirror;
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
|
||||
#include <AddressManager.h>
|
||||
#include <Application.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#include "Bookmarks.h"
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
Bookmarks::Bookmarks() {
|
||||
_bookmarksFilename = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + BOOKMARKS_FILENAME;
|
||||
|
@ -104,18 +106,13 @@ void Bookmarks::setupMenus(Menu* menubar, MenuWrapper* menu) {
|
|||
}
|
||||
|
||||
void Bookmarks::bookmarkLocation() {
|
||||
QInputDialog bookmarkLocationDialog(qApp->getWindow());
|
||||
bookmarkLocationDialog.setWindowTitle("Bookmark Location");
|
||||
bookmarkLocationDialog.setLabelText("Name:");
|
||||
bookmarkLocationDialog.setInputMode(QInputDialog::TextInput);
|
||||
bookmarkLocationDialog.resize(400, 200);
|
||||
|
||||
if (bookmarkLocationDialog.exec() == QDialog::Rejected) {
|
||||
bool ok = false;
|
||||
auto bookmarkName = OffscreenUi::getText(nullptr, "Bookmark Location", "Name:", QLineEdit::Normal, QString(), &ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString bookmarkName = bookmarkLocationDialog.textValue().trimmed();
|
||||
bookmarkName = bookmarkName.replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||
bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " ");
|
||||
if (bookmarkName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -125,13 +122,14 @@ void Bookmarks::bookmarkLocation() {
|
|||
|
||||
Menu* menubar = Menu::getInstance();
|
||||
if (contains(bookmarkName)) {
|
||||
QMessageBox duplicateBookmarkMessage;
|
||||
duplicateBookmarkMessage.setIcon(QMessageBox::Warning);
|
||||
duplicateBookmarkMessage.setText("The bookmark name you entered already exists in your list.");
|
||||
duplicateBookmarkMessage.setInformativeText("Would you like to overwrite it?");
|
||||
duplicateBookmarkMessage.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
duplicateBookmarkMessage.setDefaultButton(QMessageBox::Yes);
|
||||
if (duplicateBookmarkMessage.exec() == QMessageBox::No) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto duplicateBookmarkMessage = offscreenUi->createMessageBox(QMessageBox::Warning, "Duplicate Bookmark",
|
||||
"The bookmark name you entered already exists in your list.",
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
duplicateBookmarkMessage->setProperty("informativeText", "Would you like to overwrite it?");
|
||||
|
||||
auto result = offscreenUi->waitForMessageBoxResult(duplicateBookmarkMessage);
|
||||
if (result != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
removeLocationFromMenu(menubar, bookmarkName);
|
||||
|
@ -157,19 +155,13 @@ void Bookmarks::deleteBookmark() {
|
|||
bookmarkList.append(menuItems[i]->text());
|
||||
}
|
||||
|
||||
QInputDialog deleteBookmarkDialog(qApp->getWindow());
|
||||
deleteBookmarkDialog.setWindowTitle("Delete Bookmark");
|
||||
deleteBookmarkDialog.setLabelText("Select the bookmark to delete");
|
||||
deleteBookmarkDialog.resize(400, 400);
|
||||
deleteBookmarkDialog.setOption(QInputDialog::UseListViewForComboBoxItems);
|
||||
deleteBookmarkDialog.setComboBoxItems(bookmarkList);
|
||||
deleteBookmarkDialog.setOkButtonText("Delete");
|
||||
|
||||
if (deleteBookmarkDialog.exec() == QDialog::Rejected) {
|
||||
bool ok = false;
|
||||
auto bookmarkName = OffscreenUi::getItem(nullptr, "Delete Bookmark", "Select the bookmark to delete", bookmarkList, 0, false, &ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString bookmarkName = deleteBookmarkDialog.textValue().trimmed();
|
||||
bookmarkName = bookmarkName.trimmed();
|
||||
if (bookmarkName.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QSharedMemory>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <gl/OpenGLVersionChecker.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AddressManager.h"
|
||||
|
@ -83,6 +84,17 @@ int main(int argc, const char* argv[]) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Check OpenGL version.
|
||||
// This is done separately from the main Application so that start-up and shut-down logic within the main Application is
|
||||
// not made more complicated than it already is.
|
||||
{
|
||||
OpenGLVersionChecker openGLVersionChecker(argc, const_cast<char**>(argv));
|
||||
if (!openGLVersionChecker.isValidVersion()) {
|
||||
qCDebug(interfaceapp, "Early exit due to OpenGL version.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QElapsedTimer startupTime;
|
||||
startupTime.start();
|
||||
|
||||
|
@ -96,6 +108,7 @@ int main(int argc, const char* argv[]) {
|
|||
usecTimestampNowForceClockSkew(clockSkew);
|
||||
qCDebug(interfaceapp, "clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
|
||||
}
|
||||
|
||||
// Oculus initialization MUST PRECEDE OpenGL context creation.
|
||||
// The nature of the Application constructor means this has to be either here,
|
||||
// or in the main window ctor, before GL startup.
|
||||
|
|
|
@ -191,10 +191,10 @@ bool ScriptEditorWidget::save() {
|
|||
bool ScriptEditorWidget::saveAs() {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save script"),
|
||||
scriptEngines->getPreviousScriptLocation(),
|
||||
qApp->getPreviousScriptLocation(),
|
||||
tr("JavaScript Files (*.js)"));
|
||||
if (!fileName.isEmpty()) {
|
||||
scriptEngines->setPreviousScriptLocation(fileName);
|
||||
qApp->setPreviousScriptLocation(fileName);
|
||||
return saveFile(fileName);
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -87,12 +87,11 @@ void ScriptEditorWindow::loadScriptMenu(const QString& scriptName) {
|
|||
}
|
||||
|
||||
void ScriptEditorWindow::loadScriptClicked() {
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
QString scriptName = QFileDialog::getOpenFileName(this, tr("Interface"),
|
||||
scriptEngines->getPreviousScriptLocation(),
|
||||
qApp->getPreviousScriptLocation(),
|
||||
tr("JavaScript Files (*.js)"));
|
||||
if (!scriptName.isEmpty()) {
|
||||
scriptEngines->setPreviousScriptLocation(scriptName);
|
||||
qApp->setPreviousScriptLocation(scriptName);
|
||||
addScriptEditorWidget("loading...")->loadFile(scriptName);
|
||||
updateButtons();
|
||||
}
|
||||
|
@ -100,7 +99,7 @@ void ScriptEditorWindow::loadScriptClicked() {
|
|||
|
||||
void ScriptEditorWindow::loadMenuAboutToShow() {
|
||||
_loadMenu->clear();
|
||||
QStringList runningScripts = DependencyManager::get<ScriptEngines>()->getRunningScripts();;
|
||||
QStringList runningScripts = DependencyManager::get<ScriptEngines>()->getRunningScripts();
|
||||
if (runningScripts.count() > 0) {
|
||||
QSignalMapper* signalMapper = new QSignalMapper(this);
|
||||
foreach (const QString& runningScript, runningScripts) {
|
||||
|
|
|
@ -17,159 +17,15 @@
|
|||
|
||||
|
||||
QString const ImageOverlay::TYPE = "image";
|
||||
QUrl const ImageOverlay::URL(QString("hifi/overlays/ImageOverlay.qml"));
|
||||
|
||||
ImageOverlay::ImageOverlay() :
|
||||
_imageURL(),
|
||||
_renderImage(false),
|
||||
_wantClipFromImage(false)
|
||||
{
|
||||
}
|
||||
ImageOverlay::ImageOverlay()
|
||||
: QmlOverlay(URL) { }
|
||||
|
||||
ImageOverlay::ImageOverlay(const ImageOverlay* imageOverlay) :
|
||||
Overlay2D(imageOverlay),
|
||||
_imageURL(imageOverlay->_imageURL),
|
||||
_textureImage(imageOverlay->_textureImage),
|
||||
_texture(imageOverlay->_texture),
|
||||
_fromImage(imageOverlay->_fromImage),
|
||||
_renderImage(imageOverlay->_renderImage),
|
||||
_wantClipFromImage(imageOverlay->_wantClipFromImage)
|
||||
{
|
||||
}
|
||||
QmlOverlay(URL, imageOverlay) { }
|
||||
|
||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||
void ImageOverlay::setImageURL(const QUrl& url) {
|
||||
_imageURL = url;
|
||||
if (url.isEmpty()) {
|
||||
_isLoaded = true;
|
||||
_renderImage = false;
|
||||
_texture.clear();
|
||||
} else {
|
||||
_isLoaded = false;
|
||||
_renderImage = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageOverlay::render(RenderArgs* args) {
|
||||
if (!_isLoaded && _renderImage) {
|
||||
_isLoaded = true;
|
||||
_texture = DependencyManager::get<TextureCache>()->getTexture(_imageURL);
|
||||
}
|
||||
// If we are not visible or loaded, return. If we are trying to render an
|
||||
// image but the texture hasn't loaded, return.
|
||||
if (!_visible || !_isLoaded || (_renderImage && !_texture->isLoaded())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
if (_renderImage) {
|
||||
batch.setResourceTexture(0, _texture->getGPUTexture());
|
||||
} else {
|
||||
batch.setResourceTexture(0, args->_whiteTexture);
|
||||
}
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
xColor color = getColor();
|
||||
float alpha = getAlpha();
|
||||
glm::vec4 quadColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
int left = _bounds.left();
|
||||
int right = _bounds.right() + 1;
|
||||
int top = _bounds.top();
|
||||
int bottom = _bounds.bottom() + 1;
|
||||
|
||||
glm::vec2 topLeft(left, top);
|
||||
glm::vec2 bottomRight(right, bottom);
|
||||
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
// if for some reason our image is not over 0 width or height, don't attempt to render the image
|
||||
if (_renderImage) {
|
||||
float imageWidth = _texture->getWidth();
|
||||
float imageHeight = _texture->getHeight();
|
||||
if (imageWidth > 0 && imageHeight > 0) {
|
||||
QRect fromImage;
|
||||
if (_wantClipFromImage) {
|
||||
float scaleX = imageWidth / _texture->getOriginalWidth();
|
||||
float scaleY = imageHeight / _texture->getOriginalHeight();
|
||||
|
||||
fromImage.setX(scaleX * _fromImage.x());
|
||||
fromImage.setY(scaleY * _fromImage.y());
|
||||
fromImage.setWidth(scaleX * _fromImage.width());
|
||||
fromImage.setHeight(scaleY * _fromImage.height());
|
||||
}
|
||||
else {
|
||||
fromImage.setX(0);
|
||||
fromImage.setY(0);
|
||||
fromImage.setWidth(imageWidth);
|
||||
fromImage.setHeight(imageHeight);
|
||||
}
|
||||
|
||||
float x = fromImage.x() / imageWidth;
|
||||
float y = fromImage.y() / imageHeight;
|
||||
float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure
|
||||
float h = fromImage.height() / imageHeight;
|
||||
|
||||
glm::vec2 texCoordTopLeft(x, y);
|
||||
glm::vec2 texCoordBottomRight(x + w, y + h);
|
||||
glm::vec4 texcoordRect(texCoordTopLeft, w, h);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
|
||||
}
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
|
||||
QScriptValue subImageBounds = properties.property("subImage");
|
||||
if (subImageBounds.isValid()) {
|
||||
QRect oldSubImageRect = _fromImage;
|
||||
QRect subImageRect = _fromImage;
|
||||
if (subImageBounds.property("x").isValid()) {
|
||||
subImageRect.setX(subImageBounds.property("x").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setX(oldSubImageRect.x());
|
||||
}
|
||||
if (subImageBounds.property("y").isValid()) {
|
||||
subImageRect.setY(subImageBounds.property("y").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setY(oldSubImageRect.y());
|
||||
}
|
||||
if (subImageBounds.property("width").isValid()) {
|
||||
subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setWidth(oldSubImageRect.width());
|
||||
}
|
||||
if (subImageBounds.property("height").isValid()) {
|
||||
subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt());
|
||||
} else {
|
||||
subImageRect.setHeight(oldSubImageRect.height());
|
||||
}
|
||||
setClipFromSource(subImageRect);
|
||||
}
|
||||
|
||||
QScriptValue imageURL = properties.property("imageURL");
|
||||
if (imageURL.isValid()) {
|
||||
setImageURL(imageURL.toVariant().toString());
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ImageOverlay::getProperty(const QString& property) {
|
||||
if (property == "subImage") {
|
||||
return qRectToScriptValue(_scriptEngine, _fromImage);
|
||||
}
|
||||
if (property == "imageURL") {
|
||||
return _imageURL.toString();
|
||||
}
|
||||
|
||||
return Overlay2D::getProperty(property);
|
||||
}
|
||||
ImageOverlay* ImageOverlay::createClone() const {
|
||||
return new ImageOverlay(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,48 +11,22 @@
|
|||
#ifndef hifi_ImageOverlay_h
|
||||
#define hifi_ImageOverlay_h
|
||||
|
||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include <QImage>
|
||||
#include <QRect>
|
||||
#include <QUrl>
|
||||
|
||||
#include <TextureCache.h>
|
||||
#include "QmlOverlay.h"
|
||||
|
||||
#include "Overlay2D.h"
|
||||
|
||||
class ImageOverlay : public Overlay2D {
|
||||
class ImageOverlay : public QmlOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
static QUrl const URL;
|
||||
|
||||
ImageOverlay();
|
||||
ImageOverlay(const ImageOverlay* imageOverlay);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
// getters
|
||||
const QRect& getClipFromSource() const { return _fromImage; }
|
||||
const QUrl& getImageURL() const { return _imageURL; }
|
||||
|
||||
// setters
|
||||
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; }
|
||||
void setImageURL(const QUrl& url);
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual ImageOverlay* createClone() const;
|
||||
|
||||
private:
|
||||
|
||||
QUrl _imageURL;
|
||||
QImage _textureImage;
|
||||
|
||||
NetworkTexturePointer _texture;
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
bool _renderImage; // is there an image associated with this overlay, or is it just a colored rectangle
|
||||
bool _wantClipFromImage;
|
||||
virtual ImageOverlay* createClone() const override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
virtual void render(RenderArgs* args) = 0;
|
||||
|
||||
virtual AABox getBounds() const = 0;
|
||||
virtual bool supportsGetProperty() const { return true; }
|
||||
|
||||
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Sphere3DOverlay.h"
|
||||
#include "Grid3DOverlay.h"
|
||||
#include "TextOverlay.h"
|
||||
#include "RectangleOverlay.h"
|
||||
#include "Text3DOverlay.h"
|
||||
#include "Web3DOverlay.h"
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
@ -175,6 +176,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
thisOverlay = std::make_shared<ModelOverlay>();
|
||||
} else if (type == Web3DOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<Web3DOverlay>();
|
||||
} else if (type == RectangleOverlay::TYPE) {
|
||||
thisOverlay = std::make_shared<RectangleOverlay>();
|
||||
}
|
||||
|
||||
if (thisOverlay) {
|
||||
|
@ -373,7 +376,7 @@ OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& prop
|
|||
OverlayPropertyResult result;
|
||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||
QReadLocker lock(&_lock);
|
||||
if (thisOverlay) {
|
||||
if (thisOverlay && thisOverlay->supportsGetProperty()) {
|
||||
result.value = thisOverlay->getProperty(property);
|
||||
}
|
||||
return result;
|
||||
|
|
74
interface/src/ui/overlays/QmlOverlay.cpp
Normal file
74
interface/src/ui/overlays/QmlOverlay.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/01/27
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
#include "QmlOverlay.h"
|
||||
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextureCache.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "text/FontFamilies.h"
|
||||
|
||||
QmlOverlay::QmlOverlay(const QUrl& url) {
|
||||
buildQmlElement(url);
|
||||
}
|
||||
|
||||
QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay)
|
||||
: Overlay2D(textOverlay) {
|
||||
buildQmlElement(url);
|
||||
}
|
||||
|
||||
void QmlOverlay::buildQmlElement(const QUrl& url) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->returnFromUiThread([=] {
|
||||
offscreenUi->load(url, [=](QQmlContext* context, QObject* object) {
|
||||
_qmlElement = dynamic_cast<QQuickItem*>(object);
|
||||
});
|
||||
while (!_qmlElement) {
|
||||
qApp->processEvents();
|
||||
}
|
||||
return QVariant();
|
||||
});
|
||||
}
|
||||
|
||||
QmlOverlay::~QmlOverlay() {
|
||||
if (_qmlElement) {
|
||||
_qmlElement->deleteLater();
|
||||
_qmlElement = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
auto bounds = _bounds;
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
||||
_qmlElement->setX(bounds.left());
|
||||
_qmlElement->setY(bounds.top());
|
||||
_qmlElement->setWidth(bounds.width());
|
||||
_qmlElement->setHeight(bounds.height());
|
||||
});
|
||||
QMetaObject::invokeMethod(_qmlElement, "updatePropertiesFromScript", Q_ARG(QVariant, properties.toVariant()));
|
||||
}
|
||||
|
||||
void QmlOverlay::render(RenderArgs* args) {
|
||||
if (!_qmlElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_visible != _qmlElement->isVisible()) {
|
||||
_qmlElement->setVisible(_visible);
|
||||
}
|
||||
}
|
41
interface/src/ui/overlays/QmlOverlay.h
Normal file
41
interface/src/ui/overlays/QmlOverlay.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/01/27
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
#ifndef hifi_QmlOverlay_h
|
||||
#define hifi_QmlOverlay_h
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include "Overlay2D.h"
|
||||
|
||||
class QQuickItem;
|
||||
|
||||
class QmlOverlay : public Overlay2D {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlOverlay(const QUrl& url);
|
||||
QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay);
|
||||
~QmlOverlay();
|
||||
|
||||
// Cannot fetch properties from QML based overlays due to race conditions
|
||||
bool supportsGetProperty() const override { return false; }
|
||||
|
||||
void setProperties(const QScriptValue& properties) override;
|
||||
void render(RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
void buildQmlElement(const QUrl& url);
|
||||
|
||||
protected:
|
||||
QQuickItem* _qmlElement{ nullptr };
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_QmlOverlay_h
|
21
interface/src/ui/overlays/RectangleOverlay.cpp
Normal file
21
interface/src/ui/overlays/RectangleOverlay.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/01/27
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
#include "RectangleOverlay.h"
|
||||
|
||||
QString const RectangleOverlay::TYPE = "rectangle";
|
||||
QUrl const RectangleOverlay::URL(QString("hifi/overlays/RectangleOverlay.qml"));
|
||||
|
||||
RectangleOverlay::RectangleOverlay() : QmlOverlay(URL) {}
|
||||
|
||||
RectangleOverlay::RectangleOverlay(const RectangleOverlay* rectangleOverlay)
|
||||
: QmlOverlay(URL, rectangleOverlay) { }
|
||||
|
||||
RectangleOverlay* RectangleOverlay::createClone() const {
|
||||
return new RectangleOverlay(this);
|
||||
}
|
27
interface/src/ui/overlays/RectangleOverlay.h
Normal file
27
interface/src/ui/overlays/RectangleOverlay.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/01/27
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
|
||||
#ifndef hifi_RectangleOverlay_h
|
||||
#define hifi_RectangleOverlay_h
|
||||
|
||||
#include "QmlOverlay.h"
|
||||
|
||||
class RectangleOverlay : public QmlOverlay {
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
static QUrl const URL;
|
||||
|
||||
RectangleOverlay();
|
||||
RectangleOverlay(const RectangleOverlay* RectangleOverlay);
|
||||
|
||||
virtual RectangleOverlay* createClone() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_RectangleOverlay_h
|
|
@ -24,216 +24,21 @@
|
|||
#include "Application.h"
|
||||
#include "text/FontFamilies.h"
|
||||
|
||||
#define TEXT_OVERLAY_PROPERTY(type, name, initialValue) \
|
||||
Q_PROPERTY(type name READ name WRITE set##name NOTIFY name##Changed) \
|
||||
public: \
|
||||
type name() { return _##name; }; \
|
||||
void set##name(const type& name) { \
|
||||
if (name != _##name) { \
|
||||
_##name = name; \
|
||||
emit name##Changed(); \
|
||||
} \
|
||||
} \
|
||||
private: \
|
||||
type _##name{ initialValue };
|
||||
|
||||
|
||||
class TextOverlayElement : public QQuickItem {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
private:
|
||||
TEXT_OVERLAY_PROPERTY(QString, text, "")
|
||||
TEXT_OVERLAY_PROPERTY(QString, fontFamily, SANS_FONT_FAMILY)
|
||||
TEXT_OVERLAY_PROPERTY(QString, textColor, "#ffffffff")
|
||||
TEXT_OVERLAY_PROPERTY(QString, backgroundColor, "#B2000000")
|
||||
TEXT_OVERLAY_PROPERTY(qreal, fontSize, 18)
|
||||
TEXT_OVERLAY_PROPERTY(qreal, lineHeight, 18)
|
||||
TEXT_OVERLAY_PROPERTY(qreal, leftMargin, 0)
|
||||
TEXT_OVERLAY_PROPERTY(qreal, topMargin, 0)
|
||||
|
||||
public:
|
||||
TextOverlayElement(QQuickItem* parent = nullptr) : QQuickItem(parent) {
|
||||
}
|
||||
|
||||
signals:
|
||||
void textChanged();
|
||||
void fontFamilyChanged();
|
||||
void fontSizeChanged();
|
||||
void lineHeightChanged();
|
||||
void leftMarginChanged();
|
||||
void topMarginChanged();
|
||||
void textColorChanged();
|
||||
void backgroundColorChanged();
|
||||
};
|
||||
|
||||
HIFI_QML_DEF(TextOverlayElement)
|
||||
|
||||
QString toQmlColor(const glm::vec4& v) {
|
||||
QString templat("#%1%2%3%4");
|
||||
return templat.
|
||||
arg((int)(v.a * 255), 2, 16, QChar('0')).
|
||||
arg((int)(v.r * 255), 2, 16, QChar('0')).
|
||||
arg((int)(v.g * 255), 2, 16, QChar('0')).
|
||||
arg((int)(v.b * 255), 2, 16, QChar('0'));
|
||||
}
|
||||
|
||||
QString const TextOverlay::TYPE = "text";
|
||||
QUrl const TextOverlay::URL(QString("hifi/overlays/TextOverlay.qml"));
|
||||
|
||||
TextOverlay::TextOverlay() :
|
||||
_backgroundColor(DEFAULT_BACKGROUND_COLOR),
|
||||
_backgroundAlpha(DEFAULT_BACKGROUND_ALPHA),
|
||||
_leftMargin(DEFAULT_MARGIN),
|
||||
_topMargin(DEFAULT_MARGIN),
|
||||
_fontSize(DEFAULT_FONTSIZE)
|
||||
{
|
||||
qApp->postLambdaEvent([=] {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
TextOverlayElement::registerType();
|
||||
});
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
TextOverlayElement::show([=](QQmlContext* context, QObject* object) {
|
||||
_qmlElement = static_cast<TextOverlayElement*>(object);
|
||||
});
|
||||
});
|
||||
while (!_qmlElement) {
|
||||
QThread::msleep(1);
|
||||
}
|
||||
TextOverlay::TextOverlay() : QmlOverlay(URL) { }
|
||||
|
||||
TextOverlay::TextOverlay(const TextOverlay* textOverlay)
|
||||
: QmlOverlay(URL, textOverlay) {
|
||||
}
|
||||
|
||||
TextOverlay::TextOverlay(const TextOverlay* textOverlay) :
|
||||
Overlay2D(textOverlay),
|
||||
_text(textOverlay->_text),
|
||||
_backgroundColor(textOverlay->_backgroundColor),
|
||||
_backgroundAlpha(textOverlay->_backgroundAlpha),
|
||||
_leftMargin(textOverlay->_leftMargin),
|
||||
_topMargin(textOverlay->_topMargin),
|
||||
_fontSize(textOverlay->_fontSize)
|
||||
{
|
||||
qApp->postLambdaEvent([=] {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
TextOverlayElement::show([this](QQmlContext* context, QObject* object) {
|
||||
_qmlElement = static_cast<TextOverlayElement*>(object);
|
||||
});
|
||||
});
|
||||
while (!_qmlElement) {
|
||||
QThread::msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
TextOverlay::~TextOverlay() {
|
||||
if (_qmlElement) {
|
||||
_qmlElement->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
xColor TextOverlay::getBackgroundColor() {
|
||||
if (_colorPulse == 0.0f) {
|
||||
return _backgroundColor;
|
||||
}
|
||||
|
||||
float pulseLevel = updatePulse();
|
||||
xColor result = _backgroundColor;
|
||||
if (_colorPulse < 0.0f) {
|
||||
result.red *= (1.0f - pulseLevel);
|
||||
result.green *= (1.0f - pulseLevel);
|
||||
result.blue *= (1.0f - pulseLevel);
|
||||
} else {
|
||||
result.red *= pulseLevel;
|
||||
result.green *= pulseLevel;
|
||||
result.blue *= pulseLevel;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextOverlay::render(RenderArgs* args) {
|
||||
if (!_qmlElement) {
|
||||
return;
|
||||
}
|
||||
if (_visible != _qmlElement->isVisible()) {
|
||||
_qmlElement->setVisible(_visible);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TextOverlay::setProperties(const QScriptValue& properties) {
|
||||
Overlay2D::setProperties(properties);
|
||||
_qmlElement->setX(_bounds.left());
|
||||
_qmlElement->setY(_bounds.top());
|
||||
_qmlElement->setWidth(_bounds.width());
|
||||
_qmlElement->setHeight(_bounds.height());
|
||||
_qmlElement->settextColor(toQmlColor(vec4(toGlm(_color), _alpha)));
|
||||
QScriptValue font = properties.property("font");
|
||||
if (font.isObject()) {
|
||||
if (font.property("size").isValid()) {
|
||||
setFontSize(font.property("size").toInt32());
|
||||
}
|
||||
QFont font(_qmlElement->fontFamily());
|
||||
font.setPixelSize(_qmlElement->fontSize());
|
||||
QFontMetrics fm(font);
|
||||
_qmlElement->setlineHeight(fm.lineSpacing() * 1.2);
|
||||
}
|
||||
|
||||
QScriptValue text = properties.property("text");
|
||||
if (text.isValid()) {
|
||||
setText(text.toVariant().toString());
|
||||
}
|
||||
|
||||
QScriptValue backgroundColor = properties.property("backgroundColor");
|
||||
if (backgroundColor.isValid()) {
|
||||
QScriptValue red = backgroundColor.property("red");
|
||||
QScriptValue green = backgroundColor.property("green");
|
||||
QScriptValue blue = backgroundColor.property("blue");
|
||||
if (red.isValid() && green.isValid() && blue.isValid()) {
|
||||
_backgroundColor.red = red.toVariant().toInt();
|
||||
_backgroundColor.green = green.toVariant().toInt();
|
||||
_backgroundColor.blue = blue.toVariant().toInt();
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.property("backgroundAlpha").isValid()) {
|
||||
_backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat();
|
||||
}
|
||||
_qmlElement->setbackgroundColor(toQmlColor(vec4(toGlm(_backgroundColor), _backgroundAlpha)));
|
||||
|
||||
if (properties.property("leftMargin").isValid()) {
|
||||
setLeftMargin(properties.property("leftMargin").toVariant().toInt());
|
||||
}
|
||||
|
||||
if (properties.property("topMargin").isValid()) {
|
||||
setTopMargin(properties.property("topMargin").toVariant().toInt());
|
||||
}
|
||||
}
|
||||
TextOverlay::~TextOverlay() { }
|
||||
|
||||
TextOverlay* TextOverlay::createClone() const {
|
||||
return new TextOverlay(this);
|
||||
}
|
||||
|
||||
QScriptValue TextOverlay::getProperty(const QString& property) {
|
||||
if (property == "font") {
|
||||
QScriptValue font = _scriptEngine->newObject();
|
||||
font.setProperty("size", _fontSize);
|
||||
return font;
|
||||
}
|
||||
if (property == "text") {
|
||||
return _text;
|
||||
}
|
||||
if (property == "backgroundColor") {
|
||||
return xColorToScriptValue(_scriptEngine, _backgroundColor);
|
||||
}
|
||||
if (property == "backgroundAlpha") {
|
||||
return _backgroundAlpha;
|
||||
}
|
||||
if (property == "leftMargin") {
|
||||
return _leftMargin;
|
||||
}
|
||||
if (property == "topMargin") {
|
||||
return _topMargin;
|
||||
}
|
||||
|
||||
return Overlay2D::getProperty(property);
|
||||
}
|
||||
|
||||
QSizeF TextOverlay::textSize(const QString& text) const {
|
||||
int lines = 1;
|
||||
foreach(QChar c, text) {
|
||||
|
@ -241,31 +46,15 @@ QSizeF TextOverlay::textSize(const QString& text) const {
|
|||
++lines;
|
||||
}
|
||||
}
|
||||
QFont font(_qmlElement->fontFamily());
|
||||
font.setPixelSize(_qmlElement->fontSize());
|
||||
QFont font(SANS_FONT_FAMILY);
|
||||
font.setPixelSize(18);
|
||||
QFontMetrics fm(font);
|
||||
QSizeF result = QSizeF(fm.width(text), _qmlElement->lineHeight() * lines);
|
||||
QSizeF result = QSizeF(fm.width(text), 18 * lines);
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextOverlay::setFontSize(int fontSize) {
|
||||
_fontSize = fontSize;
|
||||
_qmlElement->setfontSize(fontSize);
|
||||
}
|
||||
|
||||
void TextOverlay::setText(const QString& text) {
|
||||
_text = text;
|
||||
_qmlElement->settext(text);
|
||||
}
|
||||
|
||||
void TextOverlay::setLeftMargin(int margin) {
|
||||
_leftMargin = margin;
|
||||
_qmlElement->setleftMargin(margin);
|
||||
}
|
||||
|
||||
void TextOverlay::setTopMargin(int margin) {
|
||||
_topMargin = margin;
|
||||
_qmlElement->settopMargin(margin);
|
||||
}
|
||||
|
||||
#include "TextOverlay.moc"
|
||||
void TextOverlay::setTopMargin(float margin) {}
|
||||
void TextOverlay::setLeftMargin(float margin) {}
|
||||
void TextOverlay::setFontSize(float size) {}
|
||||
void TextOverlay::setText(const QString& text) {}
|
||||
|
|
|
@ -11,59 +11,27 @@
|
|||
#ifndef hifi_TextOverlay_h
|
||||
#define hifi_TextOverlay_h
|
||||
|
||||
#include <QString>
|
||||
#include "QmlOverlay.h"
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Overlay2D.h"
|
||||
|
||||
const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 };
|
||||
const float DEFAULT_BACKGROUND_ALPHA = 0.7f;
|
||||
const int DEFAULT_MARGIN = 10;
|
||||
const int DEFAULT_FONTSIZE = 12;
|
||||
const int DEFAULT_FONT_WEIGHT = 50;
|
||||
|
||||
class TextOverlayElement;
|
||||
|
||||
class TextOverlay : public Overlay2D {
|
||||
Q_OBJECT
|
||||
|
||||
class TextOverlay : public QmlOverlay {
|
||||
public:
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const { return TYPE; }
|
||||
QString getType() const override { return TYPE; }
|
||||
static QUrl const URL;
|
||||
|
||||
|
||||
TextOverlay();
|
||||
TextOverlay(const TextOverlay* textOverlay);
|
||||
~TextOverlay();
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
// getters
|
||||
const QString& getText() const { return _text; }
|
||||
int getLeftMargin() const { return _leftMargin; }
|
||||
int getTopMargin() const { return _topMargin; }
|
||||
xColor getBackgroundColor();
|
||||
float getBackgroundAlpha() const { return _backgroundAlpha; }
|
||||
|
||||
// setters
|
||||
void setTopMargin(float margin);
|
||||
void setLeftMargin(float margin);
|
||||
void setFontSize(float size);
|
||||
void setText(const QString& text);
|
||||
void setLeftMargin(int margin);
|
||||
void setTopMargin(int margin);
|
||||
void setFontSize(int fontSize);
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual TextOverlay* createClone() const;
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
TextOverlay* createClone() const;
|
||||
QSizeF textSize(const QString& text) const; // Pixels
|
||||
|
||||
private:
|
||||
TextOverlayElement* _qmlElement{ nullptr };
|
||||
QString _text;
|
||||
xColor _backgroundColor;
|
||||
float _backgroundAlpha;
|
||||
int _leftMargin;
|
||||
int _topMargin;
|
||||
int _fontSize;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,10 @@ namespace AudioConstants {
|
|||
const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample);
|
||||
const float NETWORK_FRAME_MSECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL
|
||||
/ (float)AudioConstants::SAMPLE_RATE) * 1000.0f;
|
||||
|
||||
// be careful with overflows when using this constant
|
||||
const int NETWORK_FRAME_USECS = static_cast<int>(NETWORK_FRAME_MSECS * 1000.0f);
|
||||
|
||||
const int MIN_SAMPLE_VALUE = std::numeric_limits<AudioSample>::min();
|
||||
const int MAX_SAMPLE_VALUE = std::numeric_limits<AudioSample>::max();
|
||||
}
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
//
|
||||
// AudioEditBuffer.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Craig Hansen-Sturm on 8/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
#ifndef hifi_AudioEditBuffer_h
|
||||
#define hifi_AudioEditBuffer_h
|
||||
|
||||
template< typename T >
|
||||
class AudioEditBuffer : public AudioFrameBuffer<T> {
|
||||
|
||||
public:
|
||||
|
||||
AudioEditBuffer();
|
||||
AudioEditBuffer(const uint32_t channelCount, const uint32_t frameCount);
|
||||
~AudioEditBuffer();
|
||||
|
||||
bool getZeroCrossing(uint32_t start, bool direction, float32_t epsilon, uint32_t& zero);
|
||||
|
||||
void linearFade(uint32_t start, uint32_t stop, bool increasing);
|
||||
void exponentialFade(uint32_t start, uint32_t stop, bool increasing);
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
AudioEditBuffer<T>::AudioEditBuffer() :
|
||||
AudioFrameBuffer<T>() {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
AudioEditBuffer<T>::AudioEditBuffer(const uint32_t channelCount, const uint32_t frameCount) :
|
||||
AudioFrameBuffer<T>(channelCount, frameCount) {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
AudioEditBuffer<T>::~AudioEditBuffer() {
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool AudioEditBuffer<T>::getZeroCrossing(uint32_t start, bool direction, float32_t epsilon, uint32_t& zero) {
|
||||
|
||||
zero = this->_frameCount;
|
||||
|
||||
if (direction) { // scan from the left
|
||||
if (start < this->_frameCount) {
|
||||
for (uint32_t i = start; i < this->_frameCount; ++i) {
|
||||
for (uint32_t j = 0; j < this->_channelCount; ++j) {
|
||||
if (this->_frameBuffer[j][i] >= -epsilon && this->_frameBuffer[j][i] <= epsilon) {
|
||||
zero = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // scan from the right
|
||||
if (start != 0 && start < this->_frameCount) {
|
||||
for (uint32_t i = start; i != 0; --i) {
|
||||
for (uint32_t j = 0; j < this->_channelCount; ++j) {
|
||||
if (this->_frameBuffer[j][i] >= -epsilon && this->_frameBuffer[j][i] <= epsilon) {
|
||||
zero = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void AudioEditBuffer<T>::linearFade(uint32_t start, uint32_t stop, bool increasing) {
|
||||
|
||||
if (start >= stop || start > this->_frameCount || stop > this->_frameCount ) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = stop - start;
|
||||
float32_t delta;
|
||||
float32_t gain;
|
||||
|
||||
if (increasing) { // 0.0 to 1.0f in delta increments
|
||||
delta = 1.0f / (float32_t)count;
|
||||
gain = 0.0f;
|
||||
} else { // 1.0f to 0.0f in delta increments
|
||||
delta = -1.0f / (float32_t)count;
|
||||
gain = 1.0f;
|
||||
}
|
||||
|
||||
for (uint32_t i = start; i < stop; ++i) {
|
||||
for (uint32_t j = 0; j < this->_channelCount; ++j) {
|
||||
this->_frameBuffer[j][i] *= gain;
|
||||
}
|
||||
gain += delta;
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void AudioEditBuffer<T>::exponentialFade(uint32_t start, uint32_t stop, bool increasing) {
|
||||
// TBD
|
||||
}
|
||||
|
||||
typedef AudioEditBuffer< float32_t > AudioEditBufferFloat32;
|
||||
typedef AudioEditBuffer< int32_t > AudioEditBufferSInt32;
|
||||
|
||||
#endif // hifi_AudioEditBuffer_h
|
||||
|
|
@ -102,6 +102,11 @@ void AudioInjector::restart() {
|
|||
// reset the current send offset to zero
|
||||
_currentSendOffset = 0;
|
||||
|
||||
// reset state to start sending from beginning again
|
||||
_nextFrame = 0;
|
||||
_frameTimer->invalidate();
|
||||
_hasSentFirstFrame = false;
|
||||
|
||||
// check our state to decide if we need extra handling for the restart request
|
||||
if (_state == State::Finished) {
|
||||
// we finished playing, need to reset state so we can get going again
|
||||
|
@ -246,6 +251,11 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!_frameTimer->isValid()) {
|
||||
// in the case where we have been restarted, the frame timer will be invalid and we need to start it back over here
|
||||
_frameTimer->restart();
|
||||
}
|
||||
|
||||
int totalBytesLeftToCopy = (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
||||
if (!_options.loop) {
|
||||
// If we aren't looping, let's make sure we don't read past the end
|
||||
|
@ -314,14 +324,16 @@ int64_t AudioInjector::injectNextFrame() {
|
|||
const int MAX_ALLOWED_FRAMES_TO_FALL_BEHIND = 7;
|
||||
int64_t currentTime = _frameTimer->nsecsElapsed() / 1000;
|
||||
auto currentFrameBasedOnElapsedTime = currentTime / AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
if (currentFrameBasedOnElapsedTime - _nextFrame > MAX_ALLOWED_FRAMES_TO_FALL_BEHIND) {
|
||||
// If we are falling behind by more frames than our threshold, let's skip the frames ahead
|
||||
qDebug() << "AudioInjector::injectNextFrame() skipping ahead, fell behind by " << (currentFrameBasedOnElapsedTime - _nextFrame) << " frames";
|
||||
qDebug() << this << "injectNextFrame() skipping ahead, fell behind by " << (currentFrameBasedOnElapsedTime - _nextFrame) << " frames";
|
||||
_nextFrame = currentFrameBasedOnElapsedTime;
|
||||
_currentSendOffset = _nextFrame * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL * (_options.stereo ? 2 : 1) % _audioData.size();
|
||||
}
|
||||
|
||||
int64_t playNextFrameAt = ++_nextFrame * AudioConstants::NETWORK_FRAME_USECS;
|
||||
|
||||
return std::max(INT64_C(0), playNextFrameAt - currentTime);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ private:
|
|||
AbstractAudioInterface* _localAudioInterface { nullptr };
|
||||
AudioInjectorLocalBuffer* _localBuffer { nullptr };
|
||||
|
||||
int _nextFrame { 0 };
|
||||
int64_t _nextFrame { 0 };
|
||||
std::unique_ptr<QElapsedTimer> _frameTimer { nullptr };
|
||||
quint16 _outgoingSequenceNumber { 0 };
|
||||
|
||||
|
|
|
@ -79,6 +79,12 @@ void AudioInjectorManager::run() {
|
|||
if (_injectors.size() > 0) {
|
||||
// loop through the injectors in the map and send whatever frames need to go out
|
||||
auto front = _injectors.top();
|
||||
|
||||
// create an InjectorQueue to hold injectors to be queued
|
||||
// this allows us to call processEvents even if a single injector wants to be re-queued immediately
|
||||
std::vector<TimeInjectorPointerPair> heldInjectors;
|
||||
heldInjectors.reserve(_injectors.size());
|
||||
|
||||
while (_injectors.size() > 0 && front.first <= usecTimestampNow()) {
|
||||
// either way we're popping this injector off - get a copy first
|
||||
auto injector = front.second;
|
||||
|
@ -87,10 +93,10 @@ void AudioInjectorManager::run() {
|
|||
if (!injector.isNull()) {
|
||||
// this is an injector that's ready to go, have it send a frame now
|
||||
auto nextCallDelta = injector->injectNextFrame();
|
||||
|
||||
|
||||
if (nextCallDelta >= 0 && !injector->isFinished()) {
|
||||
// re-enqueue the injector with the correct timing
|
||||
_injectors.emplace(usecTimestampNow() + nextCallDelta, injector);
|
||||
// enqueue the injector with the correct timing in our holding queue
|
||||
heldInjectors.emplace(heldInjectors.end(), usecTimestampNow() + nextCallDelta, injector);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +107,12 @@ void AudioInjectorManager::run() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if there are injectors in the holding queue, push them to our persistent queue now
|
||||
while (!heldInjectors.empty()) {
|
||||
_injectors.push(heldInjectors.back());
|
||||
heldInjectors.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "AudioRingBuffer.h"
|
||||
#include "AudioFormat.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioEditBuffer.h"
|
||||
#include "AudioLogging.h"
|
||||
#include "Sound.h"
|
||||
|
||||
|
@ -69,7 +68,6 @@ void Sound::downloadFinished(const QByteArray& data) {
|
|||
|
||||
interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||
downSample(outputAudioByteArray);
|
||||
trimFrames();
|
||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||
// check if this was a stereo raw file
|
||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||
|
@ -80,7 +78,6 @@ void Sound::downloadFinished(const QByteArray& data) {
|
|||
|
||||
// Process as RAW file
|
||||
downSample(rawAudioByteArray);
|
||||
trimFrames();
|
||||
} else {
|
||||
qCDebug(audio) << "Unknown sound file type";
|
||||
}
|
||||
|
@ -98,11 +95,23 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
|||
|
||||
int numSourceSamples = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample);
|
||||
|
||||
int numDestinationBytes = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample);
|
||||
if (_isStereo && numSourceSamples % 2 != 0) {
|
||||
numDestinationBytes += sizeof(AudioConstants::AudioSample);
|
||||
if (_isStereo && numSourceSamples % 2 != 0){
|
||||
// in the unlikely case that we have stereo audio but we seem to be missing a sample
|
||||
// (the sample for one channel is missing in a set of interleaved samples)
|
||||
// then drop the odd sample
|
||||
--numSourceSamples;
|
||||
}
|
||||
|
||||
int numDestinationSamples = numSourceSamples / 2.0f;
|
||||
|
||||
if (_isStereo && numDestinationSamples % 2 != 0) {
|
||||
// if this is stereo we need to make sure we produce stereo output
|
||||
// which means we should have an even number of output samples
|
||||
numDestinationSamples += 1;
|
||||
}
|
||||
|
||||
int numDestinationBytes = numDestinationSamples * sizeof(AudioConstants::AudioSample);
|
||||
|
||||
_byteArray.resize(numDestinationBytes);
|
||||
|
||||
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
|
||||
|
@ -129,26 +138,6 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
|||
}
|
||||
}
|
||||
|
||||
void Sound::trimFrames() {
|
||||
|
||||
const uint32_t inputFrameCount = _byteArray.size() / sizeof(int16_t);
|
||||
const uint32_t trimCount = 1024; // number of leading and trailing frames to trim
|
||||
|
||||
if (inputFrameCount <= (2 * trimCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t* inputFrameData = (int16_t*)_byteArray.data();
|
||||
|
||||
AudioEditBufferFloat32 editBuffer(1, inputFrameCount);
|
||||
editBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/);
|
||||
|
||||
editBuffer.linearFade(0, trimCount, true);
|
||||
editBuffer.linearFade(inputFrameCount - trimCount, inputFrameCount, false);
|
||||
|
||||
editBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/);
|
||||
}
|
||||
|
||||
//
|
||||
// Format description from https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
|
||||
//
|
||||
|
|
|
@ -38,7 +38,6 @@ private:
|
|||
bool _isStereo;
|
||||
bool _isReady;
|
||||
|
||||
void trimFrames();
|
||||
void downSample(const QByteArray& rawAudioByteArray);
|
||||
void interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define GPU_LEGACY 0
|
||||
#define GPU_CORE_41 410
|
||||
#define GPU_CORE_43 430
|
||||
#define GPU_CORE_MINIMUM GPU_CORE_41
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
|
|
61
libraries/gl/src/gl/OpenGLVersionChecker.cpp
Normal file
61
libraries/gl/src/gl/OpenGLVersionChecker.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// OpenGLVersionChecker.cpp
|
||||
// libraries/gl/src/gl
|
||||
//
|
||||
// Created by David Rowe on 28 Jan 2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
#include "OpenGLVersionChecker.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "Config.h"
|
||||
#include "GLWidget.h"
|
||||
|
||||
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
||||
QApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
bool OpenGLVersionChecker::isValidVersion() {
|
||||
bool valid = true;
|
||||
|
||||
// Retrieve OpenGL version
|
||||
GLWidget* glWidget = new GLWidget();
|
||||
glWidget->initializeGL();
|
||||
QString glVersion = QString((const char*)glGetString(GL_VERSION));
|
||||
delete glWidget;
|
||||
|
||||
// Compare against minimum
|
||||
// The GL_VERSION string begins with a version number in one of these forms:
|
||||
// - major_number.minor_number
|
||||
// - major_number.minor_number.release_number
|
||||
// Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml
|
||||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||
int majorNumber = versionParts[0].toInt();
|
||||
int minorNumber = versionParts[1].toInt();
|
||||
int minimumMajorNumber = GPU_CORE_MINIMUM / 100;
|
||||
int minimumMinorNumber = (GPU_CORE_MINIMUM - minimumMajorNumber * 100) / 10;
|
||||
valid = (majorNumber > minimumMajorNumber
|
||||
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));
|
||||
|
||||
// Prompt user if below minimum
|
||||
if (!valid) {
|
||||
QMessageBox messageBox;
|
||||
messageBox.setWindowTitle("OpenGL Version Too Low");
|
||||
messageBox.setIcon(QMessageBox::Warning);
|
||||
messageBox.setText(QString().sprintf("Your OpenGL version of %i.%i is lower than the minimum of %i.%i.",
|
||||
majorNumber, minorNumber, minimumMajorNumber, minimumMinorNumber));
|
||||
messageBox.setInformativeText("Press OK to exit; Ignore to continue.");
|
||||
messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Ignore);
|
||||
messageBox.setDefaultButton(QMessageBox::Ok);
|
||||
valid = messageBox.exec() == QMessageBox::Ignore;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
25
libraries/gl/src/gl/OpenGLVersionChecker.h
Normal file
25
libraries/gl/src/gl/OpenGLVersionChecker.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// OpenGLVersionChecker.h
|
||||
// libraries/gl/src/gl
|
||||
//
|
||||
// Created by David Rowe on 28 Jan 2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
#ifndef hifi_OpenGLVersionChecker_h
|
||||
#define hifi_OpenGLVersionChecker_h
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
class OpenGLVersionChecker : public QApplication {
|
||||
|
||||
public:
|
||||
OpenGLVersionChecker(int& argc, char** argv);
|
||||
|
||||
static bool isValidVersion();
|
||||
};
|
||||
|
||||
#endif // hifi_OpenGLVersionChecker_h
|
|
@ -490,6 +490,9 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
|
||||
// emit our signal so listeners know we just heard from the DS
|
||||
emit receivedDomainServerList();
|
||||
|
||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList);
|
||||
|
||||
QDataStream packetStream(message->getMessage());
|
||||
|
|
|
@ -87,6 +87,7 @@ public slots:
|
|||
|
||||
signals:
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
void receivedDomainServerList();
|
||||
private slots:
|
||||
void stopKeepalivePingTimer();
|
||||
void sendPendingDSPathQuery();
|
||||
|
|
|
@ -30,6 +30,10 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
|
|||
|
||||
connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit);
|
||||
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||
|
||||
// if the NL tells us we got a DS response, clear our member variable of queued check-ins
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
connect(nodeList.data(), &NodeList::receivedDomainServerList, this, &ThreadedAssignment::clearQueuedCheckIns);
|
||||
}
|
||||
|
||||
void ThreadedAssignment::setFinished(bool isFinished) {
|
||||
|
@ -103,11 +107,18 @@ void ThreadedAssignment::sendStatsPacket() {
|
|||
}
|
||||
|
||||
void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
||||
if (DependencyManager::get<NodeList>()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
// verify that the number of queued check-ins is not >= our max
|
||||
// the number of queued check-ins is cleared anytime we get a response from the domain-server
|
||||
if (_numQueuedCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
qDebug() << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server"
|
||||
<< "Stopping the current assignment";
|
||||
setFinished(true);
|
||||
} else {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn");
|
||||
|
||||
// increase the number of queued check ins
|
||||
_numQueuedCheckIns++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ public slots:
|
|||
virtual void run() = 0;
|
||||
Q_INVOKABLE virtual void stop() { setFinished(true); }
|
||||
virtual void sendStatsPacket();
|
||||
void clearQueuedCheckIns() { _numQueuedCheckIns = 0; }
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
@ -42,6 +43,7 @@ protected:
|
|||
bool _isFinished;
|
||||
QTimer _domainServerTimer;
|
||||
QTimer _statsTimer;
|
||||
int _numQueuedCheckIns { 0 };
|
||||
|
||||
protected slots:
|
||||
void domainSettingsRequestFailed();
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "render/DrawStatus.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
#include "AntialiasingEffect.h"
|
||||
#include "ToneMappingEffect.h"
|
||||
|
||||
#include "RenderDeferredTask.h"
|
||||
|
||||
|
@ -67,20 +68,6 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo
|
|||
DependencyManager::get<DeferredLightingEffect>()->render(renderContext);
|
||||
}
|
||||
|
||||
void ToneMappingDeferred::configure(const Config& config) {
|
||||
if (config.exposure >= 0.0f) {
|
||||
_toneMappingEffect.setExposure(config.exposure);
|
||||
}
|
||||
|
||||
if (config.curve >= 0) {
|
||||
_toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)config.curve);
|
||||
}
|
||||
}
|
||||
|
||||
void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
_toneMappingEffect.render(renderContext->args);
|
||||
}
|
||||
|
||||
RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
#include "ToneMappingEffect.h"
|
||||
|
||||
class SetupDeferred {
|
||||
public:
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
@ -40,32 +38,6 @@ public:
|
|||
using JobModel = render::Job::Model<RenderDeferred>;
|
||||
};
|
||||
|
||||
|
||||
class ToneMappingConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
Q_PROPERTY(float exposure MEMBER exposure NOTIFY dirty);
|
||||
Q_PROPERTY(int curve MEMBER curve NOTIFY dirty);
|
||||
public:
|
||||
ToneMappingConfig() : render::Job::Config(true) {}
|
||||
|
||||
float exposure{ 0.0f };
|
||||
int curve{ 3 };
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class ToneMappingDeferred {
|
||||
public:
|
||||
using Config = ToneMappingConfig;
|
||||
using JobModel = render::Job::Model<ToneMappingDeferred, Config>;
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
ToneMappingEffect _toneMappingEffect;
|
||||
};
|
||||
|
||||
class DrawConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int numDrawn READ getNumDrawn)
|
||||
|
|
|
@ -145,4 +145,19 @@ void ToneMappingEffect::render(RenderArgs* args) {
|
|||
batch.setResourceTexture(ToneMappingEffect_LightingMapSlot, lightingBuffer);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ToneMappingDeferred::configure(const Config& config) {
|
||||
if (config.exposure >= 0.0f) {
|
||||
_toneMappingEffect.setExposure(config.exposure);
|
||||
}
|
||||
|
||||
if (config.curve >= 0) {
|
||||
_toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)config.curve);
|
||||
}
|
||||
}
|
||||
|
||||
void ToneMappingDeferred::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
_toneMappingEffect.render(renderContext->args);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <gpu/Resource.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
|
||||
class RenderArgs;
|
||||
|
||||
|
@ -50,7 +52,7 @@ private:
|
|||
float _exposure = 0.0f;
|
||||
float _twoPowExposure = 1.0f;
|
||||
glm::vec2 spareA;
|
||||
int _toneCurve = Filmic;
|
||||
int _toneCurve = Gamma22;
|
||||
glm::vec3 spareB;
|
||||
|
||||
Parameters() {}
|
||||
|
@ -61,4 +63,33 @@ private:
|
|||
void init();
|
||||
};
|
||||
|
||||
class ToneMappingConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure);
|
||||
Q_PROPERTY(int curve MEMBER curve WRITE setCurve);
|
||||
public:
|
||||
ToneMappingConfig() : render::Job::Config(true) {}
|
||||
|
||||
void setExposure(float newExposure) { exposure = std::max(0.0f, newExposure); emit dirty(); }
|
||||
void setCurve(int newCurve) { curve = std::max((int)ToneMappingEffect::None, std::min((int)ToneMappingEffect::Filmic, newCurve)); emit dirty(); }
|
||||
|
||||
|
||||
float exposure{ 0.0f };
|
||||
int curve{ ToneMappingEffect::Gamma22 };
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class ToneMappingDeferred {
|
||||
public:
|
||||
using Config = ToneMappingConfig;
|
||||
using JobModel = render::Job::Model<ToneMappingDeferred, Config>;
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
ToneMappingEffect _toneMappingEffect;
|
||||
};
|
||||
|
||||
#endif // hifi_ToneMappingEffect_h
|
||||
|
|
|
@ -34,8 +34,7 @@ ScriptsModel& getScriptsModel() {
|
|||
}
|
||||
|
||||
ScriptEngines::ScriptEngines()
|
||||
: _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION)
|
||||
: _scriptsLocationHandle("scriptsLocation", DESKTOP_LOCATION)
|
||||
{
|
||||
_scriptsModelFilter.setSourceModel(&_scriptsModel);
|
||||
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
|
||||
|
@ -445,14 +444,3 @@ void ScriptEngines::onScriptEngineError(const QString& scriptFilename) {
|
|||
qCDebug(scriptengine) << "Application::loadScript(), script failed to load...";
|
||||
emit scriptLoadError(scriptFilename, "");
|
||||
}
|
||||
|
||||
QString ScriptEngines::getPreviousScriptLocation() const {
|
||||
return _previousScriptLocation.get();
|
||||
}
|
||||
|
||||
void ScriptEngines::setPreviousScriptLocation(const QString& previousScriptLocation) {
|
||||
if (_previousScriptLocation.get() != previousScriptLocation) {
|
||||
_previousScriptLocation.set(previousScriptLocation);
|
||||
emit previousScriptLocationChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ class ScriptEngines : public QObject, public Dependency {
|
|||
|
||||
Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT)
|
||||
Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT)
|
||||
Q_PROPERTY(QString previousScriptLocation READ getPreviousScriptLocation WRITE setPreviousScriptLocation NOTIFY previousScriptLocationChanged)
|
||||
|
||||
public:
|
||||
using ScriptInitializer = std::function<void(ScriptEngine*)>;
|
||||
|
@ -48,9 +47,6 @@ public:
|
|||
QStringList getRunningScripts();
|
||||
ScriptEngine* getScriptEngine(const QString& scriptHash);
|
||||
|
||||
QString getPreviousScriptLocation() const;
|
||||
void setPreviousScriptLocation(const QString& previousScriptLocation);
|
||||
|
||||
ScriptsModel* scriptsModel() { return &_scriptsModel; };
|
||||
ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; };
|
||||
|
||||
|
@ -73,7 +69,6 @@ signals:
|
|||
void scriptCountChanged();
|
||||
void scriptsReloading();
|
||||
void scriptLoadError(const QString& filename, const QString& error);
|
||||
void previousScriptLocationChanged();
|
||||
|
||||
protected slots:
|
||||
void onScriptFinished(const QString& fileNameString, ScriptEngine* engine);
|
||||
|
@ -97,7 +92,6 @@ protected:
|
|||
std::atomic<bool> _stoppingAllScripts { false };
|
||||
std::list<ScriptInitializer> _scriptInitializers;
|
||||
mutable Setting::Handle<QString> _scriptsLocationHandle;
|
||||
mutable Setting::Handle<QString> _previousScriptLocation;
|
||||
ScriptsModel _scriptsModel;
|
||||
ScriptsModelFilter _scriptsModelFilter;
|
||||
};
|
||||
|
|
|
@ -199,19 +199,7 @@ private slots:
|
|||
}
|
||||
};
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton;
|
||||
QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QMessageBox::StandardButton, result),
|
||||
Q_ARG(QMessageBox::Icon, icon),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, text),
|
||||
Q_ARG(QMessageBox::StandardButtons, buttons),
|
||||
Q_ARG(QMessageBox::StandardButton, defaultButton));
|
||||
return result;
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenUi::createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
QVariantMap map;
|
||||
map.insert("title", title);
|
||||
map.insert("text", text);
|
||||
|
@ -225,12 +213,34 @@ QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, cons
|
|||
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create message box";
|
||||
return QMessageBox::StandardButton::NoButton;
|
||||
return nullptr;
|
||||
}
|
||||
return qvariant_cast<QQuickItem*>(result);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) {
|
||||
if (!messageBox) {
|
||||
return QMessageBox::NoButton;
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton resultButton = MessageBoxListener(qvariant_cast<QQuickItem*>(result)).waitForButtonResult();
|
||||
qDebug() << "Message box got a result of " << resultButton;
|
||||
return resultButton;
|
||||
return MessageBoxListener(messageBox).waitForButtonResult();
|
||||
}
|
||||
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton;
|
||||
QMetaObject::invokeMethod(this, "messageBox", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QMessageBox::StandardButton, result),
|
||||
Q_ARG(QMessageBox::Icon, icon),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, text),
|
||||
Q_ARG(QMessageBox::StandardButtons, buttons),
|
||||
Q_ARG(QMessageBox::StandardButton, defaultButton));
|
||||
return result;
|
||||
}
|
||||
|
||||
return waitForMessageBoxResult(createMessageBox(icon, title, text, buttons, defaultButton));
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text,
|
||||
|
@ -273,6 +283,7 @@ private slots:
|
|||
|
||||
// FIXME many input parameters currently ignored
|
||||
QString OffscreenUi::getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode, const QString & text, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) {
|
||||
if (ok) { *ok = false; }
|
||||
QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(title, label, text).toString();
|
||||
if (ok && result.isValid()) {
|
||||
*ok = true;
|
||||
|
@ -280,35 +291,70 @@ QString OffscreenUi::getText(void* ignored, const QString & title, const QString
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
// FIXME many input parameters currently ignored
|
||||
QString OffscreenUi::getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current, bool editable, bool * ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) {
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
QVariant OffscreenUi::inputDialog(const QString& query, const QString& placeholderText, const QString& currentValue) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto inputDialog = offscreenUi->createInputDialog(title, label, current);
|
||||
if (!inputDialog) {
|
||||
return QString();
|
||||
}
|
||||
inputDialog->setProperty("items", items);
|
||||
inputDialog->setProperty("editable", editable);
|
||||
|
||||
QVariant result = offscreenUi->waitForInputDialogResult(inputDialog);
|
||||
if (!result.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
QVariant OffscreenUi::inputDialog(const QString& title, const QString& label, const QVariant& current) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QVariant result;
|
||||
QMetaObject::invokeMethod(this, "queryBox", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QString, query),
|
||||
Q_ARG(QString, placeholderText),
|
||||
Q_ARG(QString, currentValue));
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, label),
|
||||
Q_ARG(QVariant, current));
|
||||
return result;
|
||||
}
|
||||
|
||||
return waitForInputDialogResult(createInputDialog(title, label, current));
|
||||
}
|
||||
|
||||
|
||||
QQuickItem* OffscreenUi::createInputDialog(const QString& title, const QString& label, const QVariant& current) {
|
||||
QVariantMap map;
|
||||
map.insert("text", query);
|
||||
map.insert("placeholderText", placeholderText);
|
||||
map.insert("result", currentValue);
|
||||
map.insert("title", title);
|
||||
map.insert("label", label);
|
||||
map.insert("current", current);
|
||||
QVariant result;
|
||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "queryBox",
|
||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create message box";
|
||||
return QVariant();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return InputDialogListener(qvariant_cast<QQuickItem*>(result)).waitForResult();
|
||||
return qvariant_cast<QQuickItem*>(result);
|
||||
}
|
||||
|
||||
QVariant OffscreenUi::waitForInputDialogResult(QQuickItem* inputDialog) {
|
||||
if (!inputDialog) {
|
||||
return QVariant();
|
||||
}
|
||||
return InputDialogListener(inputDialog).waitForResult();
|
||||
}
|
||||
|
||||
bool OffscreenUi::navigationFocused() {
|
||||
return offscreenFlags->isNavigationFocused();
|
||||
|
@ -412,4 +458,66 @@ void OffscreenUi::toggleMenu(const QPoint& screenPosition) {
|
|||
}
|
||||
|
||||
|
||||
class FileDialogListener : public ModalDialogListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OffscreenUi;
|
||||
FileDialogListener(QQuickItem* messageBox) : ModalDialogListener(messageBox) {
|
||||
if (_finished) {
|
||||
return;
|
||||
}
|
||||
connect(_dialog, SIGNAL(selectedFile(QVariant)), this, SLOT(onSelectedFile(QVariant)));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void onSelectedFile(QVariant file) {
|
||||
_result = file;
|
||||
_finished = true;
|
||||
disconnect(_dialog);
|
||||
}
|
||||
};
|
||||
|
||||
QString OffscreenUi::fileOpenDialog(const QString& caption, const QString& dir, const QString& filter, QString* selectedFilter, QFileDialog::Options options) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QString result;
|
||||
QMetaObject::invokeMethod(this, "fileOpenDialog", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QString, result),
|
||||
Q_ARG(QString, caption),
|
||||
Q_ARG(QString, dir),
|
||||
Q_ARG(QString, filter),
|
||||
Q_ARG(QString*, selectedFilter),
|
||||
Q_ARG(QFileDialog::Options, options));
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME support returning the selected filter... somehow?
|
||||
QVariantMap map;
|
||||
map.insert("caption", caption);
|
||||
map.insert("dir", QUrl::fromLocalFile(dir));
|
||||
map.insert("filter", filter);
|
||||
map.insert("options", static_cast<int>(options));
|
||||
|
||||
QVariant buildDialogResult;
|
||||
bool invokeResult = QMetaObject::invokeMethod(_desktop, "fileOpenDialog",
|
||||
Q_RETURN_ARG(QVariant, buildDialogResult),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create file open dialog";
|
||||
return QString();
|
||||
}
|
||||
|
||||
QVariant result = FileDialogListener(qvariant_cast<QQuickItem*>(buildDialogResult)).waitForResult();
|
||||
if (!result.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
qDebug() << result.toString();
|
||||
return result.toUrl().toLocalFile();
|
||||
}
|
||||
|
||||
QString OffscreenUi::getOpenFileName(void* ignored, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) {
|
||||
return DependencyManager::get<OffscreenUi>()->fileOpenDialog(caption, dir, filter, selectedFilter, options);
|
||||
}
|
||||
|
||||
|
||||
#include "OffscreenUi.moc"
|
||||
|
|
|
@ -42,6 +42,13 @@ public:
|
|||
QQuickItem* getToolWindow();
|
||||
|
||||
|
||||
// Message box compatibility
|
||||
Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||
// Must be called from the main thread
|
||||
QQuickItem* createMessageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||
// Must be called from the main thread
|
||||
QMessageBox::StandardButton waitForMessageBoxResult(QQuickItem* messageBox);
|
||||
|
||||
/// Same design as QMessageBox::critical(), will block, returns result
|
||||
static QMessageBox::StandardButton critical(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
|
@ -80,18 +87,21 @@ public:
|
|||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
Q_INVOKABLE QMessageBox::StandardButton messageBox(QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
|
||||
Q_INVOKABLE QVariant inputDialog(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString());
|
||||
|
||||
// FIXME implement
|
||||
static QVariant query(const QString& query, const QString& placeholderText = QString(), const QString& currentValue = QString());
|
||||
|
||||
// FIXME implement
|
||||
// file dialog compatibility
|
||||
Q_INVOKABLE QString fileOpenDialog(const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
|
||||
// Compatibility with QFileDialog::getOpenFileName
|
||||
static QString getOpenFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
|
||||
|
||||
|
||||
// input dialog compatibility
|
||||
Q_INVOKABLE QVariant inputDialog(const QString& title, const QString& label = QString(), const QVariant& current = QVariant());
|
||||
QQuickItem* createInputDialog(const QString& title, const QString& label, const QVariant& current);
|
||||
QVariant waitForInputDialogResult(QQuickItem* inputDialog);
|
||||
|
||||
// Compatibility with QInputDialog::getText
|
||||
static QString getText(void* ignored, const QString & title, const QString & label, QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
||||
// Compatibility with QInputDialog::getItem
|
||||
static QString getItem(void *ignored, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0, Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
|
||||
|
||||
private:
|
||||
QQuickItem* _desktop { nullptr };
|
||||
|
|
|
@ -21,11 +21,13 @@ DISTFILES += \
|
|||
../../interface/resources/qml/dialogs/*.qml \
|
||||
../../interface/resources/qml/dialogs/fileDialog/*.qml \
|
||||
../../interface/resources/qml/dialogs/preferences/*.qml \
|
||||
../../interface/resources/qml/dialogs/messageDialog/*.qml \
|
||||
../../interface/resources/qml/desktop/*.qml \
|
||||
../../interface/resources/qml/menus/*.qml \
|
||||
../../interface/resources/qml/styles/*.qml \
|
||||
../../interface/resources/qml/windows/*.qml \
|
||||
../../interface/resources/qml/hifi/*.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/*.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/*.qml
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/*.qml \
|
||||
../../interface/resources/qml/hifi/overlays/*.qml
|
||||
|
||||
|
|
Loading…
Reference in a new issue