mirror of
https://github.com/ducbao414/win32.run.git
synced 2025-12-15 08:42:49 +09:00
258 lines
8.1 KiB
Svelte
258 lines
8.1 KiB
Svelte
<script>
|
|
import {onMount} from 'svelte';
|
|
import TitleBar from './TitleBar.svelte';
|
|
import * as utils from '../../utils';
|
|
const {click_outside} = utils;
|
|
import _ from 'lodash';
|
|
import {get, set} from 'idb-keyval';
|
|
import { zIndex, runningPrograms } from '../../store';
|
|
|
|
export let options = {};
|
|
|
|
let titlebar;
|
|
export let node_ref;
|
|
let saved_position;
|
|
export let maximized;
|
|
export let minimized;
|
|
let translateX = '';
|
|
let translateY = '';
|
|
let animation_enabled = false;
|
|
|
|
export let on_focused = () => {
|
|
}
|
|
|
|
export let z_index = 0;
|
|
|
|
onMount(async () => {
|
|
if(options.exec_path != null){
|
|
let rect = await get(options.exec_path);
|
|
console.log(rect);
|
|
if(rect){
|
|
let workspace = document.querySelector('#work-space');
|
|
if(rect.left + rect.width <= workspace.offsetWidth
|
|
&& rect.top + rect.height <= workspace.offsetHeight){
|
|
options.top = rect.top;
|
|
options.left = rect.left;
|
|
options.width = rect.width;
|
|
options.height = rect.height;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(options.top == null){
|
|
options.top = (node_ref.parentNode.offsetHeight - node_ref.offsetHeight)/2;
|
|
}
|
|
if(options.left == null){
|
|
options.left = (node_ref.parentNode.offsetWidth - node_ref.offsetWidth)/2;
|
|
}
|
|
set_position({top: options.top, left: options.left, width: node_ref.width, height: node_ref.height});
|
|
|
|
if(options.resizable == null){
|
|
options.resizable = true;
|
|
}
|
|
if(options.draggable == null){
|
|
options.draggable = true;
|
|
}
|
|
|
|
|
|
setup_gestures();
|
|
zIndex.update(value => value + 1);
|
|
z_index = $zIndex;
|
|
|
|
node_ref.style.removeProperty('opacity');
|
|
setTimeout(() => {
|
|
animation_enabled = true;
|
|
}, 500)
|
|
|
|
})
|
|
|
|
|
|
export let on_click_close = () => {
|
|
}
|
|
|
|
export let on_click_maximize = () => {
|
|
if(!options.resizable) return;
|
|
minimized = false;
|
|
if(maximized){
|
|
set_position(saved_position);
|
|
maximized = false;
|
|
} else {
|
|
// let rect = utils.relative_rect(node_ref.parentNode.getBoundingClientRect(), node_ref.getBoundingClientRect());
|
|
// console.log(rect);
|
|
saved_position = {top: node_ref.offsetTop, left: node_ref.offsetLeft, width: node_ref.offsetWidth, height: node_ref.offsetHeight};
|
|
set_position({top: 0, left: 0, width: node_ref.parentNode.offsetWidth, height: node_ref.parentNode.offsetHeight});
|
|
maximized = true;
|
|
}
|
|
focus();
|
|
}
|
|
|
|
export let on_click_minimize = () => {
|
|
let window_center = get_center_point(node_ref.getBoundingClientRect());
|
|
let tile_center = get_center_point(document.querySelector(`.program-tile[program-id="${options.id}"]`)?.getBoundingClientRect());
|
|
|
|
translateX = `translateX(${tile_center.x-window_center.x}px)`;
|
|
translateY = `translateY(${tile_center.y-window_center.y}px)`;
|
|
console.log(`${translateX} ${translateY} scale(0.1)`);
|
|
|
|
minimized = true;
|
|
loose_focus();
|
|
}
|
|
|
|
export function restore(){
|
|
if(minimized){
|
|
minimized = false;
|
|
} else if(maximized) {
|
|
on_click_maximize();
|
|
}
|
|
focus();
|
|
}
|
|
|
|
export function focus(){
|
|
if(z_index != $zIndex){
|
|
zIndex.update(value => value + 1);
|
|
z_index = $zIndex;
|
|
on_focused();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function loose_focus(){
|
|
if(z_index == $zIndex){
|
|
console.log('loose focus');
|
|
zIndex.update(value => value + 1);
|
|
}
|
|
}
|
|
|
|
function get_center_point(rect){
|
|
if(rect == null){
|
|
return {x: document.body.offsetWidth*0.5, y: document.body.offsetHeight*0.5}
|
|
}
|
|
return {x: rect.x + rect.width*0.5, y: rect.y+rect.height*0.5}
|
|
}
|
|
|
|
|
|
|
|
export function set_position({top, left, width, height}){
|
|
|
|
node_ref.style.top = `${top}px`;
|
|
node_ref.style.left = `${left}px`;
|
|
node_ref.style.width = `${width}px`;
|
|
node_ref.style.height = `${height}px`;
|
|
}
|
|
|
|
|
|
|
|
function setup_gestures(){
|
|
if(options.draggable){
|
|
jQuery(node_ref).draggable({
|
|
containment: 'parent',
|
|
handle: '.titlebar',
|
|
stop: async () => {
|
|
if(options.exec_path){
|
|
await set(options.exec_path, node_ref.getBoundingClientRect())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
if(options.resizable){
|
|
jQuery(node_ref).resizable({
|
|
minWidth: options.min_width,
|
|
minHeight: options.min_height,
|
|
aspectRatio: options.aspect_ratio,
|
|
containment: 'parent',
|
|
handles: 'all',
|
|
classes: {
|
|
"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se opacity-0"
|
|
},
|
|
stop: async () => {
|
|
if(options.exec_path){
|
|
await set(options.exec_path, node_ref.getBoundingClientRect())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
export function update_icon(icon){
|
|
titlebar.update_icon(icon);
|
|
}
|
|
|
|
export function update_title(title){
|
|
runningPrograms.update(values => {
|
|
let program = values.find(el => el.options.id == options.id);
|
|
let index = values.indexOf(program);
|
|
if(index >= 0){
|
|
values[index].options.title = title;
|
|
}
|
|
|
|
return values;
|
|
})
|
|
titlebar.update_title(title);
|
|
}
|
|
|
|
export function show_toast({theme='dark', message}){
|
|
let toast = document.createElement('div');
|
|
toast.style.position = 'absolute';
|
|
toast.style.transform = 'translate(-50%)';
|
|
toast.style.left = '50%';
|
|
toast.style.top = '50%';
|
|
toast.style.padding = '10px';
|
|
toast.innerText = message;
|
|
toast.style.borderRadius = '7px';
|
|
toast.style.opacity = 1;
|
|
toast.style.fontSize = '12px';
|
|
toast.style.minHeight = '30px';
|
|
toast.style.minWidth = '70px';
|
|
toast.style.zIndex = 99999;
|
|
if(theme == 'dark'){
|
|
toast.style.backgroundColor = '#0f172a';
|
|
toast.style.border = '1px solid #f1f5f9';
|
|
toast.style.color = '#f8fafc';
|
|
} else {
|
|
toast.style.backgroundColor = '#f1f5f9';
|
|
toast.style.border = '1px solid #1e293b';
|
|
toast.style.color = '#0f172a';
|
|
}
|
|
node_ref.append(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.remove()
|
|
}, 3000);
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
<div
|
|
on:mousedown={focus}
|
|
use:click_outside on:click_outside={loose_focus}
|
|
bind:this={node_ref} style="
|
|
opacity:0;
|
|
position: absolute;
|
|
border-top-left-radius: 8px;
|
|
border-top-right-radius: 8px;
|
|
padding: 0px;
|
|
-webkit-font-smoothing: antialiased;"
|
|
program-id="{options.id}"
|
|
class="window absolute flex flex-col bg-xp-yellow {animation_enabled ? 'transition duration-300' : ''} {minimized ? `opacity-0` : ''}"
|
|
style:width="{options.width}px" style:height="{options.height}px"
|
|
style:min-width="{options.min_width}px" style:min-height="{options.min_height}px"
|
|
style:transform="{minimized ? `${translateX} ${translateY} scale(0.1)` : 'none'}"
|
|
style:background="{options.background}"
|
|
style:z-index="{z_index}" style:box-shadow="{z_index < $zIndex ? 'var(--window-box-shadow-inactive)' : 'var(--window-box-shadow)'}">
|
|
|
|
<div class="shrink-0">
|
|
<TitleBar bind:this={titlebar} options={options} inactive={z_index < $zIndex} maximized={maximized}
|
|
on_click_close={on_click_close} on_click_maximize={on_click_maximize} on_click_minimize={on_click_minimize}>
|
|
</TitleBar>
|
|
</div>
|
|
|
|
<div class="grow shrink-0 relative shadow-xl">
|
|
<slot name="content"></slot>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<svelte:options accessors={true}></svelte:options> |