@@ -28,6 +28,9 @@ import appContent from "./components/appContent.vue";
import loadingContent from "./components/loadingContent.vue";
import Mousetrap from "mousetrap";
import { eventBus } from "./eventBus.js";
+import { mapWritableState, mapState, mapActions } from "pinia";
+import { useSettingsStore } from "@/stores/settings.js";
+import { useWotStore } from "@/stores/wot.js";
const move_keys = ["up", "down", "left", "right", "pageup", "pagedown"];
@@ -75,6 +78,16 @@ export default {
},
computed: {
+ ...mapWritableState(useSettingsStore, [
+ "appTheme",
+ "navigationStepSize",
+ "navigationInvert",
+ "microscopeHostname",
+ "error",
+ "waiting",
+ ]),
+ ...mapState(useSettingsStore, ["ready", "baseUri"]),
+
isSystemDark: function () {
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
return true;
@@ -84,9 +97,9 @@ export default {
},
handleTheme: function () {
var isDark = false;
- if (this.$store.state.appTheme == "dark") {
+ if (this.appTheme == "dark") {
isDark = true;
- } else if (this.$store.state.appTheme == "system") {
+ } else if (this.appTheme == "system") {
if (this.systemDark) {
isDark = true;
}
@@ -98,126 +111,130 @@ export default {
},
},
+ // watch origin function refactored
+ watch: {
+ baseUri() {
+ this.checkConnection();
+ },
+ // The "Whole App" Wrapper Logic
+ ready(isReady) {
+ if (isReady) {
+ this.bindHardwareInputs(); // Turn keys ON when connected
+ } else {
+ this.unbindHardwareInputs(); // Turn keys OFF if disconnected
+ }
+ },
+ },
+
mounted() {
// Query CSS dark theme preference
- var mql = window.matchMedia("(prefers-color-scheme: dark)");
+ this.mql = window.matchMedia("(prefers-color-scheme: dark)");
+ this.systemDark = this.mql.matches;
// Check for system dark theme when mounted
- if (mql.matches) {
+ if (this.mql.matches) {
this.systemDark = true;
}
// Create a theme observer to watch for changes
- this.themeObserver = mql.addListener((e) => {
- if (e.matches) {
- this.systemDark = true;
- } else {
- this.systemDark = false;
- }
- });
+ this.themeWatchdog = (e) => {
+ this.systemDark = e.matches;
+ };
+ this.mql.addEventListener("change", this.themeWatchdog);
// Check connection to API
this.checkConnection();
},
created: function () {
window.addEventListener("beforeunload", this.handleExit);
- // Scrollwheel listener
- window.addEventListener("wheel", this.wheelMonitor);
- // Watch for origin changes
- this.unwatchOriginFunction = this.$store.watch(
- (state, getters) => {
- return getters.baseUri;
- },
- () => {
- this.checkConnection();
- },
- );
-
- // Keyboard shortcuts
- Mousetrap.bind("?", () => {
- this.toggleModalElement(this.$refs["keyboardManualModal"]); // Calls the mixin
- });
-
- Mousetrap.bind(
- move_keys,
- (event, key) => {
- event.preventDefault();
- this.keysDown.add(key);
- this.updateJogFromKeys();
- },
- "keydown",
- );
-
- Mousetrap.bind(
- move_keys,
- (event, key) => {
- event.preventDefault();
- this.keysDown.delete(key);
- this.updateJogFromKeys();
- },
- "keyup",
- );
-
- this.keyboardManual.push({
- shortcut: "←↑→↓",
- description: "Move the microscope stage",
- });
-
- this.keyboardManual.push({
- shortcut: "pgup / pgdn",
- description: "Move the microscope focus",
- });
-
- // Capture
- Mousetrap.bind("c", () => {
- eventBus.emit("globalCaptureEvent", {});
- });
- this.keyboardManual.push({
- shortcut: "c",
- description: "Take a capture",
- });
-
- // Autofocus
- Mousetrap.bind("a", () => {
- eventBus.emit("globalFastAutofocusEvent", {});
- });
- this.keyboardManual.push({
- shortcut: "a",
- description: "Fast autofocus",
- });
-
- // Increment/decrement tab
- Mousetrap.bind("shift+down", () => {
- eventBus.emit("globalIncrementTab", {});
- });
- Mousetrap.bind("shift+up", () => {
- eventBus.emit("globalDecrementTab", {});
- });
- this.keyboardManual.push({
- shortcut: "shift+↑ / shift+↓",
- description: "Switch tab",
- });
},
beforeUnmount: function () {
// Disconnect the theme observer
- if (this.themeObserver) {
- this.themeObserver.disconnect();
- }
+ this.mql.removeEventListener("change", this.themeWatchdog);
// Remove scrollwheel listener
window.removeEventListener("wheel", this.wheelMonitor);
- // Remove origin watcher
- this.unwatchOriginFunction();
// Remove key listeners
Mousetrap.reset();
},
methods: {
+ ...mapActions(useSettingsStore, ["setConnected"]),
+
+ bindHardwareInputs() {
+ window.addEventListener("wheel", this.wheelMonitor);
+
+ Mousetrap.bind("?", () => {
+ this.toggleModalElement(this.$refs["keyboardManualModal"]);
+ });
+
+ Mousetrap.bind(
+ move_keys,
+ (event, key) => {
+ event.preventDefault();
+ this.keysDown.add(key);
+ this.updateJogFromKeys();
+ },
+ "keydown",
+ );
+
+ Mousetrap.bind(
+ move_keys,
+ (event, key) => {
+ event.preventDefault();
+ this.keysDown.delete(key);
+ this.updateJogFromKeys();
+ },
+ "keyup",
+ );
+
+ this.keyboardManual.push({
+ shortcut: "←↑→↓",
+ description: "Move the microscope stage",
+ });
+
+ this.keyboardManual.push({
+ shortcut: "pgup / pgdn",
+ description: "Move the microscope focus",
+ });
+
+ Mousetrap.bind("c", () => {
+ eventBus.emit("globalCaptureEvent", {});
+ });
+ this.keyboardManual.push({
+ shortcut: "c",
+ description: "Take a capture",
+ });
+
+ Mousetrap.bind("a", () => {
+ eventBus.emit("globalFastAutofocusEvent", {});
+ });
+ this.keyboardManual.push({
+ shortcut: "a",
+ description: "Fast autofocus",
+ });
+
+ Mousetrap.bind("shift+down", () => {
+ eventBus.emit("globalIncrementTab", {});
+ });
+ Mousetrap.bind("shift+up", () => {
+ eventBus.emit("globalDecrementTab", {});
+ });
+ this.keyboardManual.push({
+ shortcut: "shift+↑ / shift+↓",
+ description: "Switch tab",
+ });
+ },
+
+ unbindHardwareInputs() {
+ window.removeEventListener("wheel", this.wheelMonitor);
+ Mousetrap.reset();
+ this.keyboardManual = [];
+ },
+
async checkConnection() {
- var baseUri = this.$store.getters.baseUri;
- this.$store.commit("changeWaiting", true);
- // TODO: more robust check - e.g. use a microscope Thing
- // TODO: should we purge existing consumedThings?
+ this.waiting = true;
+ const wotStore = useWotStore();
try {
- await this.$store.dispatch("wot/fetchThingDescriptions", `${baseUri}/thing_descriptions/`);
+ await wotStore.fetchThingDescriptions(`${this.baseUri}/thing_descriptions/`);
for (let requiredThing of ["camera", "system"]) {
if (!this.thingAvailable(requiredThing)) {
throw new Error(`No ${requiredThing} found, the GUI won't work without one.`);
@@ -225,74 +242,48 @@ export default {
}
try {
let hostname = await this.readThingProperty("system", "hostname");
- this.$store.commit("changeMicroscopeHostname", hostname);
+ this.microscopeHostname = hostname;
document.title = `OpenFlexure Microscope: ${hostname}`;
} catch {
- this.$store.commit("changeMicroscopeHostname", null);
+ this.microscopeHostname = null;
}
- // start rendering components
- this.$store.commit("setConnected");
- this.$store.commit("setErrorMessage", null);
+ this.setConnected();
+ this.error = null;
} catch (error) {
- this.$store.commit("setErrorMessage", error);
+ this.error = error;
} finally {
- this.$store.commit("changeWaiting", false);
+ this.waiting = false;
}
},
- handleExit: function () {},
- /**
- * Handle global mouse wheel events to be associated with navigation
- */
- wheelMonitor: function (event) {
- // Only capture scroll if the event target's parent contains the "scrollTarget" class
+ handleExit() {},
+
+ wheelMonitor(event) {
if (
event.target.parentNode.classList.contains("scrollTarget") ||
event.target.classList.contains("scrollTarget")
) {
const z_rel = event.deltaY / 100;
- // Emit a signal to move, acted on by panelControl.vue
- const navigationStepSize = this.$store.state.navigationStepSize;
- const z = z_rel * navigationStepSize.z;
- // Don't use `jog() due to variable size of jogs here and the rate limiting in
- // `jog()`. No need to invert on z, as navigationInvert.z isn't exposed.
+ const z = z_rel * this.navigationStepSize.z;
this.invokeAction("stage", "jog", { x: 0, y: 0, z: z });
eventBus.emit("globalUpdatePositionEvent");
}
},
- /**
- * Jog for key-presses.
- *
- * This is a similar to the function in stageControlButtons.vue however it uses
- * uses the key repeat to fire in case a key up is missed. It debounces any
- * request to jog that is too recent after the last jog.
- */
jog(x, y, z) {
- // Manually debounce extra requests from keyboard repeat rate.
- // This is used rather than an interval in case of missing a repeat.
const now = Date.now();
- const navigationInvert = this.$store.state.navigationInvert;
if (now - this.lastJogTime < this.jogTime) {
return;
}
this.lastJogTime = now;
-
this.invokeAction("stage", "jog", {
- x: x * this.jogDistance * (navigationInvert.x ? -1 : 1),
- y: y * this.jogDistance * (navigationInvert.y ? -1 : 1),
+ x: x * this.jogDistance * (this.navigationInvert.x ? -1 : 1),
+ y: y * this.jogDistance * (this.navigationInvert.y ? -1 : 1),
z: z * this.jogDistance,
});
eventBus.emit("globalUpdatePositionEvent");
},
- /**
- * Stop jogging on key-up
- *
- * This is also similar to the function in stageControlButtons.vue. It handles
- * stopping jogging and resetting the `lastJogTime` so there is no delay when
- * starting a new jog after an old jog finished.
- */
jogStop() {
this.invokeAction("stage", "jog", { stop: true });
this.lastJogTime = 0;
@@ -301,9 +292,6 @@ export default {
}, 100);
},
- /**
- * Track which keys are still down on keypress (or key repeat).
- */
updateJogFromKeys() {
let x = 0,
y = 0,
diff --git a/webapp/src/components/appContent.vue b/webapp/src/components/appContent.vue
index 502462d7..a34b9ffa 100644
--- a/webapp/src/components/appContent.vue
+++ b/webapp/src/components/appContent.vue
@@ -91,6 +91,7 @@ import slideScanContent from "./tabContentComponents/slideScanContent.vue";
import viewContent from "./tabContentComponents/viewContent.vue";
import { markRaw } from "vue";
import { eventBus } from "../eventBus.js";
+import { useSettingsStore } from "@/stores/settings.js";
// Import modal components for device initialisation
import calibrationWizard from "./modalComponents/calibrationWizard.vue";
@@ -196,6 +197,7 @@ export default {
},
mounted() {
+ const store = useSettingsStore();
// A global signal listener to switch tab
eventBus.on("globalSwitchTab", (tabID) => {
this.currentTab = tabID;
@@ -208,7 +210,7 @@ export default {
eventBus.on("globalDecrementTab", () => {
this.incrementTabBy(-1);
});
- if (this.$store.getters.ready) {
+ if (store.ready) {
this.startModals();
}
},
diff --git a/webapp/src/components/genericComponents/miniStreamDisplay.vue b/webapp/src/components/genericComponents/miniStreamDisplay.vue
index 7f5c1907..b699ab97 100644
--- a/webapp/src/components/genericComponents/miniStreamDisplay.vue
+++ b/webapp/src/components/genericComponents/miniStreamDisplay.vue
@@ -16,6 +16,8 @@
diff --git a/webapp/src/components/modalComponents/calibrationWizardComponents/cameraCalibrationSteps/cameraMainCalibrationStep.vue b/webapp/src/components/modalComponents/calibrationWizardComponents/cameraCalibrationSteps/cameraMainCalibrationStep.vue
index 54243f77..5eb4742a 100644
--- a/webapp/src/components/modalComponents/calibrationWizardComponents/cameraCalibrationSteps/cameraMainCalibrationStep.vue
+++ b/webapp/src/components/modalComponents/calibrationWizardComponents/cameraCalibrationSteps/cameraMainCalibrationStep.vue
@@ -22,6 +22,8 @@
diff --git a/webapp/src/components/tabContentComponents/slideScanComponents/slideScanControls.vue b/webapp/src/components/tabContentComponents/slideScanComponents/slideScanControls.vue
index 4ee79f5a..a88700b6 100644
--- a/webapp/src/components/tabContentComponents/slideScanComponents/slideScanControls.vue
+++ b/webapp/src/components/tabContentComponents/slideScanComponents/slideScanControls.vue
@@ -27,6 +27,7 @@
-
+
-
+
Stream preview disabled
@@ -36,11 +33,20 @@