Screen rotation dialog

This commit is contained in:
David Carley
2022-07-16 19:02:38 -07:00
parent fc4bf1cba3
commit f0bb9079d4
10 changed files with 163 additions and 36 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "bbctrl", "name": "bbctrl",
"version": "1.0.10b2", "version": "1.0.10b4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "bbctrl", "name": "bbctrl",
"version": "1.0.10b2", "version": "1.0.10b4",
"license": "GPL-3.0+", "license": "GPL-3.0+",
"dependencies": { "dependencies": {
"browserify": "^17.0.0", "browserify": "^17.0.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "bbctrl", "name": "bbctrl",
"version": "1.0.10b2", "version": "1.0.10b4",
"homepage": "https://onefinitycnc.com/", "homepage": "https://onefinitycnc.com/",
"repository": "https://github.com/OneFinityCNC/onefinity", "repository": "https://github.com/OneFinityCNC/onefinity",
"license": "GPL-3.0+", "license": "GPL-3.0+",

View File

@@ -21,5 +21,11 @@ module.exports = {
this.$dispatch('config-changed'); this.$dispatch('config-changed');
return false; return false;
} }
},
methods: {
showScreenRotationDialog: function () {
SvelteComponents.showDialog("ScreenRotation");
}
} }
} }

View File

@@ -4,16 +4,14 @@ script#settings-view-template(type="text/x-template")
.pure-form.pure-form-aligned .pure-form.pure-form-aligned
fieldset fieldset
h2 Units h2 Screen
.pure-control-group .pure-control-group
label(for="units") units label(for="screen-rotation")
select(name="units", v-model="display_units") button.pure-button(name="screen-rotation", @click="showScreenRotationDialog") Change Screen Rotation
option(value="METRIC") METRIC
option(value="IMPERIAL") IMPERIAL
fieldset fieldset
h2 Probe Dimensions h2 Probe Dimensions
templated-input(v-for="templ in template.probe", :name="$key", templated-input(v-for="templ in template.probe", v-if="$key !== 'probe-diameter'", :name="$key"
:model.sync="config.probe[$key]", :template="templ") :model.sync="config.probe[$key]", :template="templ")
fieldset fieldset

View File

@@ -1,4 +1,5 @@
import os import os
import re
import json import json
import tornado import tornado
import sockjs.tornado import sockjs.tornado
@@ -349,6 +350,46 @@ class JogHandler(bbctrl.APIHandler):
self.get_ctrl().mach.jog(self.json) self.get_ctrl().mach.jog(self.json)
displayRotatePattern = re.compile(r'display_rotate\s*=\s*(\d)')
transformationMatrixPattern = re.compile(
r'(\n)(\s+)(MatchIsTouchscreen.*?\n)(\s+Option\s+\"TransformationMatrix\".*?\n)(.*?EndSection)', re.DOTALL)
matchIsTouchscreenPattern = re.compile(
r'(\n)(\s+)(MatchIsTouchscreen.*?\n)(.*?EndSection)', re.DOTALL)
class ScreenRotationHandler(bbctrl.APIHandler):
@gen.coroutine
def get(self):
with open("/boot/config.txt", 'rt') as config:
lines = config.readlines()
for line in lines:
if line.startswith('display_rotate'):
self.write_json({
'rotated': int(displayRotatePattern.search(line).group(1)) != 0
})
return
self.write_json({'rotated': False})
return
@gen.coroutine
def put_ok(self):
rotated = self.json['rotated']
subprocess.Popen(
['/usr/local/bin/edit-boot-config', 'display_rotate={}'.format(2 if rotated else 0)])
with open("/usr/share/X11/xorg.conf.d/40-libinput.conf", 'rt') as config:
text = config.read()
text = transformationMatrixPattern.sub(r'\1\2\3\5', text)
if rotated:
text = matchIsTouchscreenPattern.sub(r'\1\2\3\2Option "TransformationMatrix" "-1 0 1 0 -1 1 0 0 1"\1\4', text)
with open("/usr/share/X11/xorg.conf.d/40-libinput.conf", 'wt') as config:
config.write(text)
subprocess.run('reboot')
# Base class for Web Socket connections # Base class for Web Socket connections
class ClientConnection(object): class ClientConnection(object):
def __init__(self, app): def __init__(self, app):
@@ -484,6 +525,7 @@ class Web(tornado.web.Application):
(r'/api/modbus/write', ModbusWriteHandler), (r'/api/modbus/write', ModbusWriteHandler),
(r'/api/jog', JogHandler), (r'/api/jog', JogHandler),
(r'/api/video', bbctrl.VideoHandler), (r'/api/video', bbctrl.VideoHandler),
(r'/api/screen-rotation', ScreenRotationHandler),
(r'/(.*)', StaticFileHandler, (r'/(.*)', StaticFileHandler,
{'path': bbctrl.get_resource('http/'), {'path': bbctrl.get_resource('http/'),
'default_filename': 'index.html'}), 'default_filename': 'index.html'}),

View File

@@ -88,7 +88,7 @@
<Label>Cancel</Label> <Label>Cancel</Label>
</Button> </Button>
<Button defaultAction on:click={onConfirm} disabled={hostname.length === 0}> <Button defaultAction on:click={onConfirm} disabled={hostname.length === 0}>
<Label>Confirm</Label> <Label>Confirm & Reboot</Label>
</Button> </Button>
</Actions> </Actions>
</Dialog> </Dialog>

View File

@@ -1,31 +1,48 @@
<script lang="ts" context="module"> <script lang="ts" context="module">
import { writable } from "svelte/store";
import HomeMachineDialog from "$dialogs/HomeMachineDialog.svelte"; import HomeMachineDialog from "$dialogs/HomeMachineDialog.svelte";
import ProbeDialog from "$dialogs/ProbeDialog.svelte"; import ProbeDialog from "$dialogs/ProbeDialog.svelte";
import { import ScreenRotationDialog from "$dialogs/ScreenRotationDialog.svelte";
HomeMachineProps,
ProbeProps, const HomeMachineDialogProps = writable<HomeMachineDialogPropsType>();
type HomeMachinePropsType, type HomeMachineDialogPropsType = {
type ProbePropsType, open: boolean;
} from "$dialogs/DialogProps"; home: () => void;
};
const ProbeDialogProps = writable<ProbeDialogPropsType>();
type ProbeDialogPropsType = {
open: boolean;
probeType: "xyz" | "z";
};
const ScreenRotationDialogProps = writable<ProbeDialogPropsType>();
type ScreenRotationDialogPropsType = {
open: boolean;
};
export function showDialog( export function showDialog(
dialog: "HomeMachine", dialog: "HomeMachine",
props: Omit<HomeMachinePropsType, "open"> props: Omit<HomeMachineDialogPropsType, "open">
); );
export function showDialog( export function showDialog(
dialog: "Probe", dialog: "Probe",
props: Omit<ProbePropsType, "open"> props: Omit<ProbeDialogPropsType, "open">
); );
export function showDialog(dialog: string, props: any) { export function showDialog(dialog: string, props: any) {
switch (dialog) { switch (dialog) {
case "HomeMachine": case "HomeMachine":
HomeMachineProps.set({ ...props, open: true }); HomeMachineDialogProps.set({ ...props, open: true });
break; break;
case "Probe": case "Probe":
ProbeProps.set({ ...props, open: true }); ProbeDialogProps.set({ ...props, open: true });
break;
case "ScreenRotation":
ScreenRotationDialogProps.set({ ...props, open: true });
break; break;
default: default:
@@ -34,5 +51,6 @@
} }
</script> </script>
<HomeMachineDialog {...$HomeMachineProps} /> <HomeMachineDialog {...$HomeMachineDialogProps} />
<ProbeDialog {...$ProbeProps} /> <ProbeDialog {...$ProbeDialogProps} />
<ScreenRotationDialog {...$ScreenRotationDialogProps} />

View File

@@ -1,13 +0,0 @@
import { writable } from "svelte/store";
export const HomeMachineProps = writable<HomeMachinePropsType>();
export type HomeMachinePropsType = {
open: boolean,
home: () => void
}
export const ProbeProps = writable<ProbePropsType>();
export type ProbePropsType = {
open: boolean,
probeType: "xyz" | "z"
};

View File

@@ -0,0 +1,76 @@
<script type="ts">
import Dialog, { Title, Content, Actions } from "@smui/dialog";
import Button, { Label } from "@smui/button";
import Radio from "@smui/radio";
import FormField from "@smui/form-field";
import MessageDialog from "$dialogs/MessageDialog.svelte";
import * as Api from "$lib/api";
import { onMount } from "svelte";
const options = [
{ value: 0, label: "Normal" },
{ value: 1, label: "Upside-down" },
];
export let open;
let currentValue;
let value;
let rebooting;
onMount(async () => {
const result = await Api.GET("screen-rotation");
currentValue = value = result.rotated ? 1 : 0;
});
async function onConfirm() {
rebooting = true;
await Api.PUT("screen-rotation", { rotated: value === 1 });
}
</script>
<MessageDialog open={rebooting} title="Rebooting">
Rebooting to apply the new screen rotation...
</MessageDialog>
<Dialog
bind:open
scrimClickAction=""
aria-labelledby="screen-rotation-title"
aria-describedby="screen-rotation-content"
>
<Title id="screen-rotation-title">Screen Rotation</Title>
<Content id="screen-rotation-content">
{#each options as option}
<FormField>
<Radio bind:group={value} value={option.value} />
<span slot="label">
{option.label}
</span>
</FormField>
{/each}
</Content>
<Actions>
<Button>
<Label>Cancel</Label>
</Button>
<Button
defaultAction
disabled={value === currentValue}
on:click={onConfirm}
>
<Label>Confirm & Reboot</Label>
</Button>
</Actions>
</Dialog>
<style lang="scss">
:global {
#screen-rotation-content {
display: flex;
flex-direction: column;
}
}
</style>

View File

@@ -92,7 +92,7 @@
on:click={onConfirm} on:click={onConfirm}
disabled={needPassword && (password.length < 8 || password.length > 128)} disabled={needPassword && (password.length < 8 || password.length > 128)}
> >
<Label>{connectOrDisconnect}</Label> <Label>{connectOrDisconnect} & Reboot</Label>
</Button> </Button>
</Actions> </Actions>
</Dialog> </Dialog>