Added app setting to enable/disable IHI slidescan
This commit is contained in:
parent
de7f4f6dfe
commit
f0ce85fc3f
6 changed files with 209 additions and 120 deletions
|
|
@ -55,24 +55,20 @@
|
|||
>
|
||||
<i class="material-icons">camera_alt</i>
|
||||
</tabIcon>
|
||||
<tabIcon
|
||||
id="slidescan-tab-icon"
|
||||
tab-i-d="slidescan"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">camera_alt</i>
|
||||
</tabIcon>
|
||||
<tabIcon
|
||||
id="settings-tab-icon"
|
||||
tab-i-d="settings"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">settings</i>
|
||||
</tabIcon>
|
||||
|
||||
<template v-if="$store.state.globalSettings.IHIEnabled">
|
||||
<hr id="extension-tab-divider" />
|
||||
|
||||
<tabIcon
|
||||
id="slidescan-tab-icon"
|
||||
tab-i-d="slidescan"
|
||||
:require-connection="true"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">camera_alt</i>
|
||||
</tabIcon>
|
||||
</template>
|
||||
|
||||
<hr id="extension-tab-divider" />
|
||||
|
||||
|
|
@ -90,8 +86,18 @@
|
|||
</tabIcon>
|
||||
|
||||
<tabIcon
|
||||
id="about-tab-icon"
|
||||
id="settings-tab-icon"
|
||||
class="uk-margin-auto-top"
|
||||
tab-i-d="settings"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<i class="material-icons">settings</i>
|
||||
</tabIcon>
|
||||
|
||||
<tabIcon
|
||||
id="about-tab-icon"
|
||||
tab-i-d="about"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
|
|
@ -205,6 +211,7 @@ export default {
|
|||
tabContent,
|
||||
navigateContent,
|
||||
captureContent,
|
||||
slideScanContent,
|
||||
viewContent,
|
||||
settingsContent,
|
||||
galleryContent,
|
||||
|
|
|
|||
|
|
@ -4,44 +4,61 @@
|
|||
<div v-show="scanUri">
|
||||
<h1>Sample Scan Wizard</h1>
|
||||
|
||||
<form v-on:submit.prevent v-on:keyup.enter="increment()">
|
||||
<div id="step-user" v-show="stepValue==0">
|
||||
<form @submit.prevent @keyup.enter="increment()">
|
||||
<div v-show="stepValue == 0" id="step-user">
|
||||
<h2>User information (1/4)</h2>
|
||||
|
||||
<label for="username">Your name:</label>
|
||||
<input type="text" id="username" name="username" v-model="username" required />
|
||||
<input
|
||||
id="username"
|
||||
v-model="username"
|
||||
type="text"
|
||||
name="username"
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
<label for="currentTime">Current time (check this is correct):</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
id="currentTime"
|
||||
name="currentTime"
|
||||
v-model="currentTimeForm"
|
||||
type="datetime-local"
|
||||
name="currentTime"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="step-patient" v-show="stepValue==1">
|
||||
<div v-show="stepValue == 1" id="step-patient">
|
||||
<h2>Patient information (2/4)</h2>
|
||||
|
||||
<label for="patientID">Patient ID:</label>
|
||||
<input type="text" id="patientID" name="patientID" v-model="patientID" required />
|
||||
<input
|
||||
id="patientID"
|
||||
v-model="patientID"
|
||||
type="text"
|
||||
name="patientID"
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="step-sample" v-show="stepValue==2">
|
||||
<div v-show="stepValue == 2" id="step-sample">
|
||||
<h2>Sample information (3/4)</h2>
|
||||
|
||||
<label>Sample type:</label>
|
||||
<br />
|
||||
<input type="radio" id="typeThin" value="thin" v-model="sampleType" />
|
||||
<input id="typeThin" v-model="sampleType" type="radio" value="thin" />
|
||||
<label for="typeThin">Thin smear</label>
|
||||
<br />
|
||||
<input type="radio" id="typeThick" value="thick" v-model="sampleType" />
|
||||
<input
|
||||
id="typeThick"
|
||||
v-model="sampleType"
|
||||
type="radio"
|
||||
value="thick"
|
||||
/>
|
||||
<label for="typeThick">Thick smear</label>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="step-scan" v-show="stepValue==3">
|
||||
<div v-show="stepValue == 3" id="step-scan">
|
||||
<h2>Start scan (4/4)</h2>
|
||||
|
||||
<label>Check details:</label>
|
||||
|
|
@ -62,38 +79,44 @@
|
|||
|
||||
<div id="form-stepper">
|
||||
<p class="warning">{{ message }}</p>
|
||||
<taskSubmitter
|
||||
v-if="scanUri"
|
||||
v-show="stepValue == 3"
|
||||
:base-url="baseURL"
|
||||
:submit-url="scanUri"
|
||||
:submit-data="payload"
|
||||
submit-label="Start scan"
|
||||
@submit="scanRunning=true"
|
||||
@response="scanRunning=false"
|
||||
@error="scanRunning=false"
|
||||
></taskSubmitter>
|
||||
<taskSubmitter
|
||||
v-if="scanUri"
|
||||
v-show="stepValue == 3"
|
||||
:base-url="baseURL"
|
||||
:submit-url="scanUri"
|
||||
:submit-data="payload"
|
||||
submit-label="Start scan"
|
||||
@submit="scanRunning = true"
|
||||
@response="scanRunning = false"
|
||||
@error="scanRunning = false"
|
||||
></taskSubmitter>
|
||||
<br />
|
||||
|
||||
<div class="grid-container">
|
||||
<button
|
||||
:disabled="stepValue <= 0 || scanRunning"
|
||||
type="button"
|
||||
v-on:click="decrement()"
|
||||
>Previous</button>
|
||||
@click="decrement()"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
:disabled="stepValue >= 3 || scanRunning"
|
||||
type="button"
|
||||
v-on:click="increment()"
|
||||
>Next</button>
|
||||
@click="increment()"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
<button
|
||||
v-show="stepValue == 3"
|
||||
:disabled="scanRunning"
|
||||
type="button"
|
||||
v-on:click="restart()"
|
||||
>Restart</button>
|
||||
@click="restart()"
|
||||
>
|
||||
Restart
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -124,14 +147,60 @@ export default {
|
|||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginsUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/extensions`;
|
||||
},
|
||||
currentTimeForm: {
|
||||
get() {
|
||||
// Chop the timezone information from the end
|
||||
return this.currentTime.substr(0, 19);
|
||||
},
|
||||
set(val) {
|
||||
console.log(val);
|
||||
// Get timezone
|
||||
var dt = new Date();
|
||||
var tzo = -dt.getTimezoneOffset(),
|
||||
dif = tzo >= 0 ? "+" : "-",
|
||||
pad = function(num) {
|
||||
var norm = Math.floor(Math.abs(num));
|
||||
return (norm < 10 ? "0" : "") + norm;
|
||||
};
|
||||
// Stick to the end of the new timestring from the form
|
||||
this.currentTime = val + dif + pad(tzo / 60) + ":" + pad(tzo % 60);
|
||||
}
|
||||
},
|
||||
|
||||
payload: {
|
||||
get() {
|
||||
return {
|
||||
filename: `${this.patientID}_${this.sampleType}`,
|
||||
temporary: false,
|
||||
bayer: false,
|
||||
grid: [10, 10, 9],
|
||||
stride_size: [800, 600, 10],
|
||||
fast_autofocus: true,
|
||||
autofocus_dz: 2000,
|
||||
use_video_port: false,
|
||||
annotations: {
|
||||
patientID: this.patientID,
|
||||
username: this.username,
|
||||
clientDatetime: this.currentTime
|
||||
},
|
||||
tags: ["medscan"]
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
baseURL: function (val) {
|
||||
baseURL: function(val) {
|
||||
if (this.baseURL) {
|
||||
this.updateScanUri();
|
||||
} else {
|
||||
this.message = "No baseURL given";
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
mounted: function() {
|
||||
|
|
@ -147,7 +216,6 @@ export default {
|
|||
axios
|
||||
.get(this.pluginsUri) // Get a list of plugins
|
||||
.then(response => {
|
||||
console.log(response);
|
||||
var plugins = response.data;
|
||||
var foundExtension = plugins.find(
|
||||
e => e.title === "org.openflexure.scan"
|
||||
|
|
@ -159,7 +227,7 @@ export default {
|
|||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error); // Let mixin handle error
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
},
|
||||
|
||||
|
|
@ -223,53 +291,6 @@ export default {
|
|||
pad(tzo % 60)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
pluginsUri: function() {
|
||||
return `${this.baseURL}/extensions`;
|
||||
},
|
||||
|
||||
currentTimeForm: {
|
||||
get() {
|
||||
// Chop the timezone information from the end
|
||||
return this.currentTime.substr(0, 19);
|
||||
},
|
||||
set(val) {
|
||||
console.log(val);
|
||||
// Get timezone
|
||||
var dt = new Date();
|
||||
var tzo = -dt.getTimezoneOffset(),
|
||||
dif = tzo >= 0 ? "+" : "-",
|
||||
pad = function(num) {
|
||||
var norm = Math.floor(Math.abs(num));
|
||||
return (norm < 10 ? "0" : "") + norm;
|
||||
};
|
||||
// Stick to the end of the new timestring from the form
|
||||
this.currentTime = val + dif + pad(tzo / 60) + ":" + pad(tzo % 60);
|
||||
}
|
||||
},
|
||||
|
||||
payload: {
|
||||
get() {
|
||||
return {
|
||||
filename: `${this.patientID}_${this.sampleType}`,
|
||||
temporary: false,
|
||||
bayer: false,
|
||||
grid: [10, 10, 9],
|
||||
stride_size: [800, 600, 10],
|
||||
fast_autofocus: true,
|
||||
autofocus_dz: 2000,
|
||||
use_video_port: false,
|
||||
annotations: {
|
||||
patientID: this.patientID,
|
||||
username: this.username,
|
||||
clientDatetime: this.currentTime
|
||||
},
|
||||
tags: ["medscan"]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -281,23 +302,6 @@ export default {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="datetime-local"] {
|
||||
display: block;
|
||||
margin: 0 10px 0 0;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 0 10px 0 0;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
|
|
@ -309,4 +313,4 @@ button {
|
|||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import paneSlideScan from "../controlComponents/paneSlideScan";
|
|||
import streamDisplay from "../viewComponents/streamDisplay.vue";
|
||||
|
||||
export default {
|
||||
name: "NavigateContent",
|
||||
name: "SlideScanContent",
|
||||
|
||||
components: {
|
||||
paneSlideScan,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div id="appSettings">
|
||||
<h3>Additional features</h3>
|
||||
<p class="uk-margin-small">
|
||||
<label
|
||||
><input v-model="IHIEnabled" class="uk-checkbox" type="checkbox" />
|
||||
Enable IHI Slide Scan</label
|
||||
>
|
||||
</p>
|
||||
<p class="uk-margin-small uk-width-xlarge">
|
||||
Enabling IHI Slide Scan will add a new tab designed to simplify
|
||||
acquiring blood smear tile scans. </br>
|
||||
While this may be useful for other applications, it is primarily designed
|
||||
for use in clinics acquiring blood smear samples using a 100x oil-immersion
|
||||
objective, with a Raspberry Pi Camera v2.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Export main app
|
||||
export default {
|
||||
name: "FeaturesSettings",
|
||||
|
||||
data: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
computed: {
|
||||
IHIEnabled: {
|
||||
get() {
|
||||
return this.$store.state.globalSettings.IHIEnabled;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeSetting", ["IHIEnabled", value]);
|
||||
this.$root.$emit("globalSafeTogglePreview", value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
IHIEnabled() {
|
||||
console.log("Saving IHIEnabled setting");
|
||||
this.setLocalStorageObj("IHIEnabled", this.IHIEnabled);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// Try loading settings from localStorage. If null, don't change.
|
||||
this.IHIEnabled = this.getLocalStorageObj("IHIEnabled") || this.IHIEnabled;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
|
@ -17,6 +17,19 @@
|
|||
Display
|
||||
</tabIcon>
|
||||
</li>
|
||||
<li>
|
||||
<tabIcon
|
||||
id="settings-features-icon"
|
||||
tab-i-d="features"
|
||||
:show-title="false"
|
||||
:show-tooltip="false"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
Features
|
||||
</tabIcon>
|
||||
</li>
|
||||
<li class="uk-nav-header">Microscope settings</li>
|
||||
<li>
|
||||
<tabIcon
|
||||
|
|
@ -71,6 +84,16 @@
|
|||
</div>
|
||||
</tabContent>
|
||||
|
||||
<tabContent
|
||||
tab-i-d="features"
|
||||
:require-connection="false"
|
||||
:current-tab="currentTab"
|
||||
>
|
||||
<div class="settings-pane uk-padding-small">
|
||||
<featuresSettings />
|
||||
</div>
|
||||
</tabContent>
|
||||
|
||||
<tabContent
|
||||
tab-i-d="camera"
|
||||
:require-connection="true"
|
||||
|
|
@ -116,6 +139,7 @@ import streamSettings from "./settingsComponents/streamSettings.vue";
|
|||
import microscopeSettings from "./settingsComponents/microscopeSettings.vue";
|
||||
import cameraSettings from "./settingsComponents/cameraSettings.vue";
|
||||
import appSettings from "./settingsComponents/appSettings.vue";
|
||||
import featuresSettings from "./settingsComponents/featuresSettings.vue";
|
||||
import cameraStageMappingSettings from "./settingsComponents/cameraStageMappingSettings.vue";
|
||||
|
||||
// Import generic components
|
||||
|
|
@ -132,6 +156,7 @@ export default {
|
|||
microscopeSettings,
|
||||
cameraStageMappingSettings,
|
||||
appSettings,
|
||||
featuresSettings,
|
||||
tabIcon,
|
||||
tabContent
|
||||
},
|
||||
|
|
@ -157,9 +182,6 @@ export default {
|
|||
// Custom UIkit CSS modifications
|
||||
@import "../../assets/less/theme.less";
|
||||
|
||||
.settings-pane {
|
||||
}
|
||||
|
||||
.settings-nav {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export default new Vuex.Store({
|
|||
disableStream: false,
|
||||
autoGpuPreview: false,
|
||||
trackWindow: true,
|
||||
IHIEnabled: false,
|
||||
appTheme: "system"
|
||||
},
|
||||
activeStreams: {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue