Merge branch 'better-settings' into 'master'
Better settings Closes #185 and #156 See merge request openflexure/openflexure-microscope-server!95
This commit is contained in:
commit
f54684b460
6 changed files with 262 additions and 129 deletions
|
|
@ -170,6 +170,12 @@
|
|||
/* UIkit modifiers
|
||||
========================================================================== */
|
||||
|
||||
h4, .uk-h4 {
|
||||
line-height: normal;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Navbar
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1 uk-text-center"
|
||||
>
|
||||
<!-- For each top tab -->
|
||||
<template v-for="(item, index) in enabledTopTabs">
|
||||
<template v-for="(item, index) in topTabs">
|
||||
<!-- Render the tab icon -->
|
||||
<tabIcon
|
||||
:id="item.id + '-tab-icon'"
|
||||
|
|
@ -34,8 +34,6 @@
|
|||
<hr v-if="item.divide" :key="'tab-divider-' + index" />
|
||||
</template>
|
||||
|
||||
<hr id="extension-tab-divider" />
|
||||
|
||||
<!-- For each plugin tab -->
|
||||
<tabIcon
|
||||
v-for="plugin in pluginsGuiList"
|
||||
|
|
@ -79,7 +77,7 @@
|
|||
>
|
||||
<!-- For each top tab -->
|
||||
<tabContent
|
||||
v-for="item in enabledTopTabs"
|
||||
v-for="item in topTabs"
|
||||
:id="item.id + '-tab-content'"
|
||||
:key="item.id + '-tab-content'"
|
||||
:tab-i-d="item.id"
|
||||
|
|
@ -212,18 +210,6 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
enabledTopTabs: function() {
|
||||
var enabledTabs = this.topTabs;
|
||||
if (this.$store.state.IHIEnabled) {
|
||||
enabledTabs.push({
|
||||
id: "slidescan",
|
||||
icon: "settings_overscan",
|
||||
component: slideScanContent
|
||||
});
|
||||
}
|
||||
return enabledTabs;
|
||||
},
|
||||
|
||||
pluginsUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/extensions`;
|
||||
},
|
||||
|
|
@ -241,7 +227,7 @@ export default {
|
|||
|
||||
tabOrder: function() {
|
||||
var ind = [];
|
||||
for (const tab of this.enabledTopTabs) {
|
||||
for (const tab of this.topTabs) {
|
||||
ind.push(tab.id);
|
||||
}
|
||||
for (const plugin of this.pluginsGuiList) {
|
||||
|
|
@ -270,12 +256,24 @@ export default {
|
|||
this.$store.commit("changeAutoGpuPreview", true);
|
||||
this.$store.commit("changeTrackWindow", true);
|
||||
}
|
||||
// Update top tabs
|
||||
this.updateTopTabs(this.$store.state.IHIEnabled);
|
||||
// Update plugins
|
||||
this.updatePlugins().then(() => {
|
||||
// Start initialisation modals
|
||||
this.startModals();
|
||||
});
|
||||
}
|
||||
|
||||
// Watch for host 'ready', then update status
|
||||
this.unwatchStoreFunction = this.$store.watch(
|
||||
state => {
|
||||
return state.IHIEnabled;
|
||||
},
|
||||
IHIEnabled => {
|
||||
this.updateTopTabs(IHIEnabled);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
|
@ -302,6 +300,19 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
updateTopTabs: function(IHIEnabled) {
|
||||
if (IHIEnabled) {
|
||||
this.topTabs.push({
|
||||
id: "slidescan",
|
||||
icon: "settings_overscan",
|
||||
component: slideScanContent,
|
||||
divide: true
|
||||
});
|
||||
} else {
|
||||
// If the connection is now disconnected, empty capture list
|
||||
this.topTabs = this.topTabs.filter(tab => tab.id != "slidescan");
|
||||
}
|
||||
},
|
||||
updatePlugins: function() {
|
||||
return axios
|
||||
.get(this.pluginsUri)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,30 @@
|
|||
<template>
|
||||
<div id="CSMCalibrationSettings">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<!--Show auto calibrate if default plugin is enabled-->
|
||||
<div v-if="'calibrate_xy' in recalibrationLinks" class="uk-margin-small">
|
||||
<taskSubmitter
|
||||
:button-primary="true"
|
||||
:can-terminate="false"
|
||||
:requires-confirmation="true"
|
||||
:confirmation-message="
|
||||
'Start recalibration of the stage to the camera? This may take a while, and the microscope will be locked during this time.'
|
||||
"
|
||||
:submit-url="recalibrationLinks.calibrate_xy.href"
|
||||
:submit-label="'Auto-Calibrate using camera'"
|
||||
@response="onRecalibrateResponse"
|
||||
@error="onRecalibrateError"
|
||||
>
|
||||
</taskSubmitter>
|
||||
</div>
|
||||
<button
|
||||
v-if="'get_calibration' in recalibrationLinks"
|
||||
v-show="dataAvailable && showExtraSettings"
|
||||
type="button"
|
||||
class="uk-button uk-button-default uk-width-1-1"
|
||||
@click="getCalibrationData()"
|
||||
<!--Show auto calibrate if default plugin is enabled-->
|
||||
<div v-if="'calibrate_xy' in recalibrationLinks" class="uk-margin-small">
|
||||
<taskSubmitter
|
||||
:button-primary="true"
|
||||
:can-terminate="false"
|
||||
:requires-confirmation="true"
|
||||
:confirmation-message="
|
||||
'Start recalibration of the stage to the camera? This may take a while, and the microscope will be locked during this time.'
|
||||
"
|
||||
:submit-url="recalibrationLinks.calibrate_xy.href"
|
||||
:submit-label="'Auto-Calibrate using camera'"
|
||||
@response="onRecalibrateResponse"
|
||||
@error="onRecalibrateError"
|
||||
>
|
||||
Download calibration data
|
||||
</button>
|
||||
</form>
|
||||
</taskSubmitter>
|
||||
</div>
|
||||
<button
|
||||
v-if="'get_calibration' in recalibrationLinks"
|
||||
v-show="dataAvailable && showExtraSettings"
|
||||
type="button"
|
||||
class="uk-button uk-button-default uk-width-1-1"
|
||||
@click="getCalibrationData()"
|
||||
>
|
||||
Download calibration data
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
<template>
|
||||
<div v-if="settings" id="cameraSettings">
|
||||
<div id="cameraSettings">
|
||||
<div class="uk-grid uk-grid-divider uk-child-width-expand" uk-grid>
|
||||
<div class="uk-width-large">
|
||||
<h3>Manual camera settings</h3>
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<div v-if="settings.picamera">
|
||||
<form @submit.prevent="applySettingsRequest">
|
||||
<div class="uk-margin-small-bottom">
|
||||
<h4>Raspberry Pi Camera</h4>
|
||||
<!--PiCamera settings block-->
|
||||
<div v-if="settings.picamera.shutter_speed !== undefined">
|
||||
<div v-if="picamera.shutter_speed !== undefined">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Exposure time</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.picamera.shutter_speed"
|
||||
v-model="picamera.shutter_speed"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="settings.picamera.analog_gain !== undefined">
|
||||
<div v-if="picamera.analog_gain !== undefined">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Analogue gain</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.picamera.analog_gain"
|
||||
v-model="picamera.analog_gain"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
|
|
@ -33,13 +34,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="settings.picamera.digital_gain !== undefined">
|
||||
<div v-if="picamera.digital_gain !== undefined">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Digital gain</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.picamera.digital_gain"
|
||||
v-model="picamera.digital_gain"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
|
|
@ -48,6 +49,40 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-margin-small-bottom">
|
||||
<h4>Image quality</h4>
|
||||
|
||||
<div class="uk-child-width-1-2" uk-grid>
|
||||
<div v-if="mjpeg_quality !== undefined">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Web stream quality (%)</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="mjpeg_quality"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="jpeg_quality !== undefined">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>JPEG capture quality (%)</label
|
||||
>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="jpeg_quality"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-margin-small uk-width-1-1"
|
||||
|
|
@ -83,7 +118,13 @@ export default {
|
|||
|
||||
data: function() {
|
||||
return {
|
||||
settings: {}
|
||||
picamera: {
|
||||
shutter_speed: undefined,
|
||||
analog_gain: undefined,
|
||||
digital_gain: undefined
|
||||
},
|
||||
mjpeg_quality: undefined,
|
||||
jpeg_quality: undefined
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -102,24 +143,37 @@ export default {
|
|||
axios
|
||||
.get(this.settingsUri)
|
||||
.then(response => {
|
||||
this.settings = response.data.camera;
|
||||
const cameraSettings = response.data.camera;
|
||||
// Get base camera settings
|
||||
this.mjpeg_quality = cameraSettings.mjpeg_quality;
|
||||
this.jpeg_quality = cameraSettings.jpeg_quality;
|
||||
// Get Pi Camera settings if they exist
|
||||
if (cameraSettings.picamera) {
|
||||
this.picamera.analog_gain = cameraSettings.picamera.analog_gain;
|
||||
this.picamera.digital_gain = cameraSettings.picamera.digital_gain;
|
||||
this.picamera.shutter_speed = cameraSettings.picamera.shutter_speed;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
applyConfigRequest: function() {
|
||||
applySettingsRequest: function() {
|
||||
// We have to use parseInt/parseFloat because JS sometimes seems to
|
||||
// make the numbers be strings... TypeScript would solve this...
|
||||
var payload = {
|
||||
camera: {
|
||||
mjpeg_quality: parseInt(this.mjpeg_quality),
|
||||
jpeg_quality: parseInt(this.jpeg_quality),
|
||||
picamera: {
|
||||
shutter_speed: this.settings.picamera.shutter_speed,
|
||||
analog_gain: this.settings.picamera.analog_gain,
|
||||
digital_gain: this.settings.picamera.digital_gain
|
||||
shutter_speed: parseFloat(this.picamera.shutter_speed),
|
||||
analog_gain: parseFloat(this.picamera.analog_gain),
|
||||
digital_gain: parseFloat(this.picamera.digital_gain)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
console.log(payload);
|
||||
// Send request
|
||||
axios
|
||||
.put(this.settingsUri, payload)
|
||||
|
|
|
|||
|
|
@ -1,46 +1,6 @@
|
|||
<template>
|
||||
<div v-if="settings" id="microscopeSettings" class="uk-width-large">
|
||||
<form @submit.prevent="applyConfigRequest">
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Backlash compensation</label
|
||||
>
|
||||
<div class="uk-grid-small uk-child-width-1-3" uk-grid>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.stage.backlash.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.stage.backlash.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settings.stage.backlash.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<form @submit.prevent="applySettingsRequest">
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text"
|
||||
>Microscope name</label
|
||||
|
|
@ -57,7 +17,7 @@
|
|||
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-form-small uk-float-right uk-margin-small uk-width-1-1"
|
||||
class="uk-button uk-button-primary uk-margin-small uk-width-1-1"
|
||||
>
|
||||
Apply Settings
|
||||
</button>
|
||||
|
|
@ -100,12 +60,9 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
applyConfigRequest: function() {
|
||||
applySettingsRequest: function() {
|
||||
var payload = {
|
||||
name: this.settings.name,
|
||||
stage: {
|
||||
backlash: this.settings.stage.backlash
|
||||
}
|
||||
name: this.settings.name
|
||||
};
|
||||
|
||||
// Send request to update config
|
||||
|
|
|
|||
|
|
@ -1,31 +1,96 @@
|
|||
<template>
|
||||
<div id="stageSettings" class="uk-width-large">
|
||||
<div>
|
||||
<div v-if="stageType === 'MissingStage'" class="uk-text-danger">
|
||||
<b>No stage connected</b>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h3>Stage settings</h3>
|
||||
<p>
|
||||
<label class="uk-form-label">
|
||||
Stage geometry
|
||||
<div v-if="stageType != 'MissingStage'">
|
||||
<form @submit.prevent="setStageType">
|
||||
<div class="uk-margin-small">
|
||||
<select v-model="stageType" class="uk-select">
|
||||
<option value="SangaStage">SangaStage (Standard)</option>
|
||||
<option value="SangaDeltaStage"> SangaStage (Delta)</option>
|
||||
</select>
|
||||
<form @submit.prevent="setStageType">
|
||||
<div class="uk-margin-small-bottom">
|
||||
<h4>Stage geometry</h4>
|
||||
<select v-model="stageType" class="uk-select uk-margin-small-top">
|
||||
<option value="SangaStage">SangaStage (Standard)</option>
|
||||
<option value="SangaDeltaStage"> SangaStage (Delta)</option>
|
||||
</select>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-margin-small uk-width-1-1"
|
||||
>
|
||||
Change stage geometry
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form @submit.prevent="applySettingsRequest">
|
||||
<div class="uk-margin-small-bottom">
|
||||
<h4>Backlash compensation</h4>
|
||||
<p class="uk-margin-remove">
|
||||
Backlash compentation causes movements to overshoot by that number
|
||||
of motor steps, reducing the effect of mechanical backlash.
|
||||
</p>
|
||||
<div
|
||||
class="uk-grid-small uk-child-width-1-3 uk-margin-small-bottom"
|
||||
uk-grid
|
||||
>
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">x</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="backlash.x"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-width-1-1"
|
||||
>
|
||||
Change stage geometry
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">y</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="backlash.y"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="uk-form-label" for="form-stacked-text">z</label>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="backlash.z"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="uk-text-danger"><b>No stage connected</b></div>
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<h4>Settle time</h4>
|
||||
<div v-if="settle_time !== undefined">
|
||||
<p class="uk-margin-small-bottom">
|
||||
When moving or scanning, captures will be delayed by the settle
|
||||
time (in seconds) to reduce motion blur.
|
||||
</p>
|
||||
<div class="uk-form-controls">
|
||||
<input
|
||||
v-model="settle_time"
|
||||
class="uk-input uk-form-small"
|
||||
type="number"
|
||||
step="0.1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="uk-button uk-button-primary uk-margin-small uk-width-1-1"
|
||||
>
|
||||
Apply Settings
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -40,11 +105,20 @@ export default {
|
|||
|
||||
data: function() {
|
||||
return {
|
||||
stageType: "MissingStage"
|
||||
stageType: "MissingStage",
|
||||
backlash: {
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
z: undefined
|
||||
},
|
||||
settle_time: undefined
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
settingsUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
|
||||
},
|
||||
stageTypeUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/instrument/stage/type`;
|
||||
}
|
||||
|
|
@ -52,9 +126,42 @@ export default {
|
|||
|
||||
mounted() {
|
||||
this.getStageType();
|
||||
this.updateSettings();
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateSettings: function() {
|
||||
axios
|
||||
.get(this.settingsUri)
|
||||
.then(response => {
|
||||
const stageSettings = response.data.stage;
|
||||
this.backlash.x = stageSettings.backlash.x;
|
||||
this.backlash.y = stageSettings.backlash.y;
|
||||
this.backlash.z = stageSettings.backlash.z;
|
||||
this.settle_time = stageSettings.settle_time;
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
applySettingsRequest: function() {
|
||||
var payload = {
|
||||
stage: {
|
||||
backlash: this.backlash
|
||||
}
|
||||
};
|
||||
// Send request to update settings
|
||||
axios
|
||||
.put(this.settingsUri, payload)
|
||||
.then(() => {
|
||||
// Update local settings
|
||||
this.updateSettings();
|
||||
this.modalNotify("Stage settings applied.");
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
getStageType: function() {
|
||||
axios
|
||||
.get(this.stageTypeUri)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue