You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
13 KiB
460 lines
13 KiB
<script>
|
|
import {
|
|
appWindow,
|
|
WebviewWindow,
|
|
LogicalSize,
|
|
UserAttentionType,
|
|
PhysicalSize,
|
|
PhysicalPosition,
|
|
} from "tauri-plugin-window-api";
|
|
import { open as openDialog } from "tauri-plugin-dialog-api";
|
|
import { open } from "tauri-plugin-shell-api";
|
|
|
|
let selectedWindow = appWindow.label;
|
|
const windowMap = {
|
|
[appWindow.label]: appWindow,
|
|
};
|
|
|
|
const cursorIconOptions = [
|
|
"default",
|
|
"crosshair",
|
|
"hand",
|
|
"arrow",
|
|
"move",
|
|
"text",
|
|
"wait",
|
|
"help",
|
|
"progress",
|
|
// something cannot be done
|
|
"notAllowed",
|
|
"contextMenu",
|
|
"cell",
|
|
"verticalText",
|
|
"alias",
|
|
"copy",
|
|
"noDrop",
|
|
// something can be grabbed
|
|
"grab",
|
|
/// something is grabbed
|
|
"grabbing",
|
|
"allScroll",
|
|
"zoomIn",
|
|
"zoomOut",
|
|
// edge is to be moved
|
|
"eResize",
|
|
"nResize",
|
|
"neResize",
|
|
"nwResize",
|
|
"sResize",
|
|
"seResize",
|
|
"swResize",
|
|
"wResize",
|
|
"ewResize",
|
|
"nsResize",
|
|
"neswResize",
|
|
"nwseResize",
|
|
"colResize",
|
|
"rowResize",
|
|
];
|
|
|
|
export let onMessage;
|
|
|
|
let newWindowLabel;
|
|
|
|
let urlValue = "https://tauri.app";
|
|
let resizable = true;
|
|
let maximized = false;
|
|
let decorations = true;
|
|
let alwaysOnTop = false;
|
|
let contentProtected = true;
|
|
let fullscreen = false;
|
|
let width = null;
|
|
let height = null;
|
|
let minWidth = null;
|
|
let minHeight = null;
|
|
let maxWidth = null;
|
|
let maxHeight = null;
|
|
let x = null;
|
|
let y = null;
|
|
let scaleFactor = 1;
|
|
let innerPosition = new PhysicalPosition(x, y);
|
|
let outerPosition = new PhysicalPosition(x, y);
|
|
let innerSize = new PhysicalSize(width, height);
|
|
let outerSize = new PhysicalSize(width, height);
|
|
let resizeEventUnlisten;
|
|
let moveEventUnlisten;
|
|
let cursorGrab = false;
|
|
let cursorVisible = true;
|
|
let cursorX = null;
|
|
let cursorY = null;
|
|
let cursorIcon = "default";
|
|
let cursorIgnoreEvents = false;
|
|
let windowTitle = "Awesome Tauri Example!";
|
|
|
|
function openUrl() {
|
|
open(urlValue);
|
|
}
|
|
|
|
function setTitle_() {
|
|
windowMap[selectedWindow].setTitle(windowTitle);
|
|
}
|
|
|
|
function hide_() {
|
|
windowMap[selectedWindow].hide();
|
|
setTimeout(windowMap[selectedWindow].show, 2000);
|
|
}
|
|
|
|
function minimize_() {
|
|
windowMap[selectedWindow].minimize();
|
|
setTimeout(windowMap[selectedWindow].unminimize, 2000);
|
|
}
|
|
|
|
function getIcon() {
|
|
openDialog({
|
|
multiple: false,
|
|
}).then((path) => {
|
|
if (typeof path === "string") {
|
|
windowMap[selectedWindow].setIcon(path);
|
|
}
|
|
});
|
|
}
|
|
|
|
function createWindow() {
|
|
if (!newWindowLabel) return;
|
|
|
|
const webview = new WebviewWindow(newWindowLabel);
|
|
windowMap[newWindowLabel] = webview;
|
|
webview.once("tauri://error", function () {
|
|
onMessage("Error creating new webview");
|
|
});
|
|
}
|
|
|
|
function loadWindowSize() {
|
|
windowMap[selectedWindow].innerSize().then((response) => {
|
|
innerSize = response;
|
|
width = innerSize.width;
|
|
height = innerSize.height;
|
|
});
|
|
windowMap[selectedWindow].outerSize().then((response) => {
|
|
outerSize = response;
|
|
});
|
|
}
|
|
|
|
function loadWindowPosition() {
|
|
windowMap[selectedWindow].innerPosition().then((response) => {
|
|
innerPosition = response;
|
|
});
|
|
windowMap[selectedWindow].outerPosition().then((response) => {
|
|
outerPosition = response;
|
|
x = outerPosition.x;
|
|
y = outerPosition.y;
|
|
});
|
|
}
|
|
|
|
async function addWindowEventListeners(window) {
|
|
if (!window) return;
|
|
if (resizeEventUnlisten) {
|
|
resizeEventUnlisten();
|
|
}
|
|
if (moveEventUnlisten) {
|
|
moveEventUnlisten();
|
|
}
|
|
moveEventUnlisten = await window.listen("tauri://move", loadWindowPosition);
|
|
resizeEventUnlisten = await window.listen("tauri://resize", loadWindowSize);
|
|
}
|
|
|
|
async function requestUserAttention_() {
|
|
await windowMap[selectedWindow].minimize();
|
|
await windowMap[selectedWindow].requestUserAttention(
|
|
UserAttentionType.Critical
|
|
);
|
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
await windowMap[selectedWindow].requestUserAttention(null);
|
|
}
|
|
|
|
$: {
|
|
windowMap[selectedWindow];
|
|
loadWindowPosition();
|
|
loadWindowSize();
|
|
}
|
|
$: windowMap[selectedWindow]?.setResizable(resizable);
|
|
$: maximized
|
|
? windowMap[selectedWindow]?.maximize()
|
|
: windowMap[selectedWindow]?.unmaximize();
|
|
$: windowMap[selectedWindow]?.setDecorations(decorations);
|
|
$: windowMap[selectedWindow]?.setAlwaysOnTop(alwaysOnTop);
|
|
$: windowMap[selectedWindow]?.setContentProtected(contentProtected);
|
|
$: windowMap[selectedWindow]?.setFullscreen(fullscreen);
|
|
|
|
$: width &&
|
|
height &&
|
|
windowMap[selectedWindow]?.setSize(new PhysicalSize(width, height));
|
|
$: minWidth && minHeight
|
|
? windowMap[selectedWindow]?.setMinSize(
|
|
new LogicalSize(minWidth, minHeight)
|
|
)
|
|
: windowMap[selectedWindow]?.setMinSize(null);
|
|
$: maxWidth > 800 && maxHeight > 400
|
|
? windowMap[selectedWindow]?.setMaxSize(
|
|
new LogicalSize(maxWidth, maxHeight)
|
|
)
|
|
: windowMap[selectedWindow]?.setMaxSize(null);
|
|
$: x !== null &&
|
|
y !== null &&
|
|
windowMap[selectedWindow]?.setPosition(new PhysicalPosition(x, y));
|
|
$: windowMap[selectedWindow]
|
|
?.scaleFactor()
|
|
.then((factor) => (scaleFactor = factor));
|
|
$: addWindowEventListeners(windowMap[selectedWindow]);
|
|
|
|
$: windowMap[selectedWindow]?.setCursorGrab(cursorGrab);
|
|
$: windowMap[selectedWindow]?.setCursorVisible(cursorVisible);
|
|
$: windowMap[selectedWindow]?.setCursorIcon(cursorIcon);
|
|
$: cursorX !== null &&
|
|
cursorY !== null &&
|
|
windowMap[selectedWindow]?.setCursorPosition(
|
|
new PhysicalPosition(cursorX, cursorY)
|
|
);
|
|
$: windowMap[selectedWindow]?.setIgnoreCursorEvents(cursorIgnoreEvents);
|
|
</script>
|
|
|
|
<div class="flex flex-col children:grow gap-2">
|
|
<div class="flex gap-1">
|
|
<input
|
|
class="input grow"
|
|
type="text"
|
|
placeholder="New Window label.."
|
|
bind:value={newWindowLabel}
|
|
/>
|
|
<button class="btn" on:click={createWindow}>New window</button>
|
|
</div>
|
|
<br />
|
|
{#if Object.keys(windowMap).length >= 1}
|
|
<span class="font-700 text-sm">Selected window:</span>
|
|
<select class="input" bind:value={selectedWindow}>
|
|
<option value="" disabled selected>Choose a window...</option>
|
|
{#each Object.keys(windowMap) as label}
|
|
<option value={label}>{label}</option>
|
|
{/each}
|
|
</select>
|
|
{/if}
|
|
{#if windowMap[selectedWindow]}
|
|
<br />
|
|
<div class="flex flex-wrap gap-2">
|
|
<button
|
|
class="btn"
|
|
title="Unminimizes after 2 seconds"
|
|
on:click={() => windowMap[selectedWindow].center()}
|
|
>
|
|
Center
|
|
</button>
|
|
<button
|
|
class="btn"
|
|
title="Unminimizes after 2 seconds"
|
|
on:click={minimize_}
|
|
>
|
|
Minimize
|
|
</button>
|
|
<button
|
|
class="btn"
|
|
title="Visible again after 2 seconds"
|
|
on:click={hide_}
|
|
>
|
|
Hide
|
|
</button>
|
|
<button class="btn" on:click={getIcon}> Change icon </button>
|
|
<button
|
|
class="btn"
|
|
on:click={requestUserAttention_}
|
|
title="Minimizes the window, requests attention for 3s and then resets it"
|
|
>Request attention</button
|
|
>
|
|
</div>
|
|
<br />
|
|
<div class="flex flex-wrap gap-2">
|
|
<label>
|
|
Maximized
|
|
<input type="checkbox" bind:checked={maximized} />
|
|
</label>
|
|
<label>
|
|
Resizable
|
|
<input type="checkbox" bind:checked={resizable} />
|
|
</label>
|
|
<label>
|
|
Has decorations
|
|
<input type="checkbox" bind:checked={decorations} />
|
|
</label>
|
|
<label>
|
|
Always on top
|
|
<input type="checkbox" bind:checked={alwaysOnTop} />
|
|
</label>
|
|
<label>
|
|
Content protected
|
|
<input type="checkbox" bind:checked={contentProtected} />
|
|
</label>
|
|
<label>
|
|
Fullscreen
|
|
<input type="checkbox" bind:checked={fullscreen} />
|
|
</label>
|
|
</div>
|
|
<br />
|
|
<div class="flex flex-row gap-2 flex-wrap">
|
|
<div class="flex children:grow flex-col">
|
|
<div>
|
|
X
|
|
<input class="input" type="number" bind:value={x} min="0" />
|
|
</div>
|
|
<div>
|
|
Y
|
|
<input class="input" type="number" bind:value={y} min="0" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex children:grow flex-col">
|
|
<div>
|
|
Width
|
|
<input class="input" type="number" bind:value={width} min="400" />
|
|
</div>
|
|
<div>
|
|
Height
|
|
<input class="input" type="number" bind:value={height} min="400" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex children:grow flex-col">
|
|
<div>
|
|
Min width
|
|
<input class="input" type="number" bind:value={minWidth} />
|
|
</div>
|
|
<div>
|
|
Min height
|
|
<input class="input" type="number" bind:value={minHeight} />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex children:grow flex-col">
|
|
<div>
|
|
Max width
|
|
<input class="input" type="number" bind:value={maxWidth} min="800" />
|
|
</div>
|
|
<div>
|
|
Max height
|
|
<input class="input" type="number" bind:value={maxHeight} min="400" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<br />
|
|
<div>
|
|
<div class="flex">
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Inner Size
|
|
</div>
|
|
<span>Width: {innerSize.width}</span>
|
|
<span>Height: {innerSize.height}</span>
|
|
</div>
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Outer Size
|
|
</div>
|
|
<span>Width: {outerSize.width}</span>
|
|
<span>Height: {outerSize.height}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex">
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Inner Logical Size
|
|
</div>
|
|
<span>Width: {innerSize.toLogical(scaleFactor).width}</span>
|
|
<span>Height: {innerSize.toLogical(scaleFactor).height}</span>
|
|
</div>
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Outer Logical Size
|
|
</div>
|
|
<span>Width: {outerSize.toLogical(scaleFactor).width}</span>
|
|
<span>Height: {outerSize.toLogical(scaleFactor).height}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex">
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Inner Position
|
|
</div>
|
|
<span>x: {innerPosition.x}</span>
|
|
<span>y: {innerPosition.y}</span>
|
|
</div>
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Outer Position
|
|
</div>
|
|
<span>x: {outerPosition.x}</span>
|
|
<span>y: {outerPosition.y}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex">
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Inner Logical Position
|
|
</div>
|
|
<span>x: {innerPosition.toLogical(scaleFactor).x}</span>
|
|
<span>y: {innerPosition.toLogical(scaleFactor).y}</span>
|
|
</div>
|
|
<div class="grow">
|
|
<div class="text-accent dark:text-darkAccent font-700">
|
|
Outer Logical Position
|
|
</div>
|
|
<span>x: {outerPosition.toLogical(scaleFactor).x}</span>
|
|
<span>y: {outerPosition.toLogical(scaleFactor).y}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<br />
|
|
<h4 class="mb-2">Cursor</h4>
|
|
<div class="flex gap-2">
|
|
<label>
|
|
<input type="checkbox" bind:checked={cursorGrab} />
|
|
Grab
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" bind:checked={cursorVisible} />
|
|
Visible
|
|
</label>
|
|
<label>
|
|
<input type="checkbox" bind:checked={cursorIgnoreEvents} />
|
|
Ignore events
|
|
</label>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<label>
|
|
Icon
|
|
<select class="input" bind:value={cursorIcon}>
|
|
{#each cursorIconOptions as kind}
|
|
<option value={kind}>{kind}</option>
|
|
{/each}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
X position
|
|
<input class="input" type="number" bind:value={cursorX} />
|
|
</label>
|
|
<label>
|
|
Y position
|
|
<input class="input" type="number" bind:value={cursorY} />
|
|
</label>
|
|
</div>
|
|
<br />
|
|
<div class="flex flex-col gap-1">
|
|
<form class="flex gap-1" on:submit|preventDefault={setTitle_}>
|
|
<input class="input grow" id="title" bind:value={windowTitle} />
|
|
<button class="btn" type="submit">Set title</button>
|
|
</form>
|
|
<form class="flex gap-1" on:submit|preventDefault={openUrl}>
|
|
<input class="input grow" id="url" bind:value={urlValue} />
|
|
<button class="btn" id="open-url"> Open URL </button>
|
|
</form>
|
|
</div>
|
|
{/if}
|
|
</div>
|