Integrate supported ops into the UI
This commit is contained in:
6
api.cpp
6
api.cpp
@@ -185,12 +185,6 @@ class Context {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void triggerCapture() {
|
|
||||||
gpp_rethrow([=]() {
|
|
||||||
gpp_try(gp_camera_trigger_capture(camera.get(), context.get()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gpp_unique_ptr<Camera, gp_camera_unref> camera;
|
gpp_unique_ptr<Camera, gp_camera_unref> camera;
|
||||||
gpp_unique_ptr<GPContext, gp_context_unref> context;
|
gpp_unique_ptr<GPContext, gp_context_unref> context;
|
||||||
|
|||||||
10
libapi.mjs.d.ts
vendored
10
libapi.mjs.d.ts
vendored
@@ -13,6 +13,15 @@ export type Config = {
|
|||||||
| { type: 'datetime'; value: number }
|
| { type: 'datetime'; value: number }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
declare interface SupportedOps {
|
||||||
|
captureImage: boolean;
|
||||||
|
captureVideo: boolean;
|
||||||
|
captureAudio: boolean;
|
||||||
|
capturePreview: boolean;
|
||||||
|
config: boolean;
|
||||||
|
triggerCapture: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
declare class Context {
|
declare class Context {
|
||||||
configToJS(): Promise<Config & { type: 'window' }>;
|
configToJS(): Promise<Config & { type: 'window' }>;
|
||||||
setConfigValue(
|
setConfigValue(
|
||||||
@@ -22,6 +31,7 @@ declare class Context {
|
|||||||
capturePreviewAsBlob(): Promise<Blob>;
|
capturePreviewAsBlob(): Promise<Blob>;
|
||||||
captureImageAsFile(): Promise<File>;
|
captureImageAsFile(): Promise<File>;
|
||||||
hasPendingEvent(): Promise<boolean>;
|
hasPendingEvent(): Promise<boolean>;
|
||||||
|
supportedOps(): SupportedOps;
|
||||||
|
|
||||||
delete(): void;
|
delete(): void;
|
||||||
isDeleted(): boolean;
|
isDeleted(): boolean;
|
||||||
|
|||||||
@@ -143,7 +143,9 @@ class App extends Component {
|
|||||||
'div',
|
'div',
|
||||||
{ class: 'pure-u-2-3' },
|
{ class: 'pure-u-2-3' },
|
||||||
h(Preview, {
|
h(Preview, {
|
||||||
getPreview: this.capturePreview
|
getPreview: this.connection.supportedOps.capturePreview
|
||||||
|
? this.capturePreview
|
||||||
|
: undefined
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
h(
|
h(
|
||||||
@@ -152,7 +154,9 @@ class App extends Component {
|
|||||||
h(
|
h(
|
||||||
'form',
|
'form',
|
||||||
{ class: 'pure-form pure-form-aligned' },
|
{ class: 'pure-form pure-form-aligned' },
|
||||||
h(CaptureButton, { getFile: this.captureImage }),
|
this.connection.supportedOps.triggerCapture
|
||||||
|
? h(CaptureButton, { getFile: this.captureImage })
|
||||||
|
: undefined,
|
||||||
h(Widget, { config: state.config, setValue: this.setValue })
|
h(Widget, { config: state.config, setValue: this.setValue })
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import initModule from '../libapi.mjs';
|
|||||||
|
|
||||||
/** @typedef {import('../libapi.mjs').Context} Context */
|
/** @typedef {import('../libapi.mjs').Context} Context */
|
||||||
|
|
||||||
const ContextPromise = initModule().then(Module => Module.Context);
|
const ModulePromise = initModule();
|
||||||
|
|
||||||
export async function connect() {
|
export async function connect() {
|
||||||
let Context = await ContextPromise;
|
const Module = await ModulePromise;
|
||||||
|
|
||||||
let context = await new Context();
|
let context = await new Module.Context();
|
||||||
|
let supportedOps = await context.supportedOps();
|
||||||
|
|
||||||
let queue = Promise.resolve();
|
let queue = Promise.resolve();
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ export async function connect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
supportedOps,
|
||||||
schedule,
|
schedule,
|
||||||
disconnect() {
|
disconnect() {
|
||||||
context.delete();
|
context.delete();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const Stats = isDebug
|
|||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
/** @extends Component<{ getPreview: () => Promise<Blob> }, { error?: string }> */
|
/** @extends Component<{ getPreview?: () => Promise<Blob> }, { error?: string }> */
|
||||||
export class Preview extends Component {
|
export class Preview extends Component {
|
||||||
canvasHolderRef = createRef();
|
canvasHolderRef = createRef();
|
||||||
canvasRef = createRef();
|
canvasRef = createRef();
|
||||||
@@ -20,17 +20,15 @@ export class Preview extends Component {
|
|||||||
return h(
|
return h(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'center-parent', ref: this.canvasHolderRef },
|
{ class: 'center-parent', ref: this.canvasHolderRef },
|
||||||
this.state.error
|
!this.props.getPreview
|
||||||
? h(
|
? h('div', { class: 'center' }, `Preview is unsupported`)
|
||||||
'div',
|
|
||||||
{ class: 'center' },
|
|
||||||
`Could not retrieve preview: ${this.state.error}`
|
|
||||||
)
|
|
||||||
: h('canvas', { class: 'center', ref: this.canvasRef })
|
: h('canvas', { class: 'center', ref: this.canvasRef })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
if (!this.props.getPreview) return;
|
||||||
|
|
||||||
let canvas = /** @type {HTMLCanvasElement} */ (this.canvasRef.current);
|
let canvas = /** @type {HTMLCanvasElement} */ (this.canvasRef.current);
|
||||||
let canvasHolder = this.canvasHolderRef.current;
|
let canvasHolder = this.canvasHolderRef.current;
|
||||||
|
|
||||||
@@ -70,13 +68,8 @@ export class Preview extends Component {
|
|||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
while (this.canvasRef.current) {
|
while (this.canvasRef.current) {
|
||||||
let blob;
|
|
||||||
try {
|
try {
|
||||||
blob = await this.props.getPreview();
|
let blob = await this.props.getPreview();
|
||||||
} catch (error) {
|
|
||||||
this.setState({ error: error.message });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If ratio is known; decode resized image right away - it's a bit faster.
|
// If ratio is known; decode resized image right away - it's a bit faster.
|
||||||
// If it isn't known, retrieve entire image to calculate ratio from its dimensions.
|
// If it isn't known, retrieve entire image to calculate ratio from its dimensions.
|
||||||
@@ -94,15 +87,15 @@ export class Preview extends Component {
|
|||||||
updateCanvasSize();
|
updateCanvasSize();
|
||||||
}
|
}
|
||||||
canvasCtx.transferFromImageBitmap(img);
|
canvasCtx.transferFromImageBitmap(img);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
await new Promise(resolve => requestAnimationFrame(resolve));
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
this.stats?.update();
|
this.stats?.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.resizeObserver.disconnect();
|
this.resizeObserver?.disconnect();
|
||||||
if (isDebug) {
|
|
||||||
this.canvasHolderRef.current.removeChild(this.stats.dom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,13 @@ export class Widget extends Component {
|
|||||||
let { label, name } = config;
|
let { label, name } = config;
|
||||||
let id = `config-${name}`;
|
let id = `config-${name}`;
|
||||||
if (config.type === 'window' || config.type === 'section') {
|
if (config.type === 'window' || config.type === 'section') {
|
||||||
|
let children = Object.values(config.children);
|
||||||
|
if (!children.length) return;
|
||||||
return h(
|
return h(
|
||||||
'fieldset',
|
'fieldset',
|
||||||
{ id },
|
{ id },
|
||||||
h('legend', {}, label),
|
h('legend', {}, label),
|
||||||
Object.values(config.children).map(config =>
|
children.map(config =>
|
||||||
h(Widget, { key: config.name, config, setValue })
|
h(Widget, { key: config.name, config, setValue })
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user