Added window opening and closing

This commit is contained in:
Prozilla 2023-07-16 14:58:31 +02:00
parent 0008d7dc4b
commit 30046b6f77
No known key found for this signature in database
GPG key ID: 5858DFE71CAF31EE
11 changed files with 133 additions and 49 deletions

View file

@ -2,7 +2,7 @@
ProzillaOS is a web operating system inspired by Ubuntu Linux and Windows made with React by Prozilla. It aims to function much like a real operating system, with the exception of running entirely on the web. ProzillaOS is a web operating system inspired by Ubuntu Linux and Windows made with React by Prozilla. It aims to function much like a real operating system, with the exception of running entirely on the web.
> Please note that ProzillaOS is far from complete and many additional features will be added in the future. > Please note that ProzillaOS is a WIP and far from complete and many additional features will be added in the future.
## Features ## Features

View file

@ -1,22 +1,16 @@
import { useEffect, useState } from "react";
import "./App.css"; import "./App.css";
import { TaskBar } from "./components/TaskBar.js"; import { TaskBar } from "./components/TaskBar.js";
import WindowsManager from "./modules/windows/windows.js"; import { WindowsManagerProvider } from "./hooks/WindowsManagerContext.js";
import { WindowsView } from "./components/WindowsView.js";
export const windowsManager = new WindowsManager();
function App() { function App() {
const [windows, setWindows] = useState([]);
useEffect(() => {
setWindows(Object.values(windowsManager.windows));
}, []);
return ( return (
<div className="App"> <WindowsManagerProvider>
<TaskBar/> <div className="App">
{windows} <TaskBar/>
</div> <WindowsView/>
</div>
</WindowsManagerProvider>
); );
} }

View file

@ -23,6 +23,7 @@
cursor: pointer; cursor: pointer;
border: none; border: none;
outline: none; outline: none;
transition: background-color 100ms ease-in-out;
} }
.Task-bar button:hover { .Task-bar button:hover {

View file

@ -4,10 +4,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBatteryFull, faSearch, faVolumeHigh, faWifi } from "@fortawesome/free-solid-svg-icons"; import { faBatteryFull, faSearch, faVolumeHigh, faWifi } from "@fortawesome/free-solid-svg-icons";
import { ReactSVG } from "react-svg"; import { ReactSVG } from "react-svg";
import ApplicationsManager from "../modules/applications/applications.js"; import ApplicationsManager from "../modules/applications/applications.js";
import { windowsManager } from "../App.js"; import { useWindowsManager } from "../hooks/WindowsManagerContext.js";
export function TaskBar() { export function TaskBar() {
const [date, setDate] = useState(new Date()); const [date, setDate] = useState(new Date());
const windowsManager = useWindowsManager();
useEffect(() => { useEffect(() => {
setInterval(() => { setInterval(() => {
@ -21,11 +22,11 @@ export function TaskBar() {
<button> <button>
<FontAwesomeIcon icon={faSearch}/> <FontAwesomeIcon icon={faSearch}/>
</button> </button>
{ApplicationsManager.APPLICATIONS.forEach((app) => {ApplicationsManager.APPLICATIONS.map((app) => {
<button key={app.id} onClick={windowsManager.open(app.id)}> return (<button key={app.id} onClick={() => { windowsManager.open(app.id); }}>
<ReactSVG src={process.env.PUBLIC_URL + `/media/applications/icons/${app.id}.svg`}/> <ReactSVG src={process.env.PUBLIC_URL + `/media/applications/icons/${app.id}.svg`}/>
</button> </button>);
)} })}
</div> </div>
<div className="Util-icons"> <div className="Util-icons">
<button> <button>

View file

@ -3,11 +3,14 @@ import "./Window.css";
import { faMinus, faXmark } from "@fortawesome/free-solid-svg-icons"; import { faMinus, faXmark } from "@fortawesome/free-solid-svg-icons";
import { faSquare } from "@fortawesome/free-regular-svg-icons"; import { faSquare } from "@fortawesome/free-regular-svg-icons";
import { ReactSVG } from "react-svg"; import { ReactSVG } from "react-svg";
import { windowsManager } from "../App.js"; import { useWindowsManager } from "../hooks/WindowsManagerContext.js";
export function Window({ id, app, size, position, focused = false, minimized = false, maximized = false }) { export function Window({ id, app, size, position, focused = false, minimized = false, maximized = false }) {
const windowsManager = useWindowsManager();
return ( return (
<div <div
key={id}
className="Window-container" className="Window-container"
style={{ style={{
width: size.x, width: size.x,
@ -25,7 +28,7 @@ export function Window({ id, app, size, position, focused = false, minimized = f
<button> <button>
<FontAwesomeIcon icon={faSquare}/> <FontAwesomeIcon icon={faSquare}/>
</button> </button>
<button onClick={windowsManager.close(id)}> <button onClick={() => { windowsManager.close(id); }}>
<FontAwesomeIcon icon={faXmark}/> <FontAwesomeIcon icon={faXmark}/>
</button> </button>
</div> </div>

View file

@ -0,0 +1,18 @@
import { Window } from "./Window.js";
import { useWindows } from "../hooks/WindowsContext.js";
export function WindowsView() {
const windows = useWindows();
return (<div>
{windows.map(({ id, app, size, position}) =>
<Window
id={id}
key={id}
app={app}
size={size}
position={position}
/>
)}
</div>);
}

View file

@ -0,0 +1,26 @@
import { createContext, useCallback, useContext, useState } from "react";
const WindowsContext = createContext();
/**
* @returns {React.Provider<any>}
*/
export function WindowsProvider({ children, windowsManager }) {
const [windows, setWindows] = useState([]);
const updateWindows = useCallback((updatedWindows) => {
setWindows(Object.values(updatedWindows));
}, []);
windowsManager.setUpdateWindows(updateWindows);
return (
<WindowsContext.Provider value={windows}>
{children}
</WindowsContext.Provider>
);
}
export function useWindows() {
return useContext(WindowsContext);
}

View file

@ -0,0 +1,27 @@
import { createContext, useContext } from "react";
import WindowsManager from "../modules/windows/windows.js";
import { WindowsProvider } from "./WindowsContext.js";
const WindowsManagerContext = createContext();
/**
* @returns {React.Provider<any>}
*/
export function WindowsManagerProvider({ children }) {
const windowsManager = new WindowsManager();
return (
<WindowsManagerContext.Provider value={windowsManager}>
<WindowsProvider windowsManager={windowsManager}>
{children}
</WindowsProvider>
</WindowsManagerContext.Provider>
);
}
/**
* @returns {WindowsManager}
*/
export function useWindowsManager() {
return useContext(WindowsManagerContext);
}

View file

@ -1,13 +1,5 @@
export default class Application { export default class Application {
constructor(name, id) { constructor(name, id, windowContent) {
Object.assign(this, { name, id }); Object.assign(this, { name, id, windowContent });
}
start() {
}
stop() {
} }
} }

View file

@ -1,3 +1,4 @@
/* eslint-disable eqeqeq */
import Application from "./application.js"; import Application from "./application.js";
export default class ApplicationsManager { export default class ApplicationsManager {
@ -9,7 +10,7 @@ export default class ApplicationsManager {
let application = null; let application = null;
this.APPLICATIONS.forEach((app) => { this.APPLICATIONS.forEach((app) => {
if (app.id === id) { if (app.id == id) {
application = app; application = app;
return; return;
} }

View file

@ -1,40 +1,61 @@
import { Window } from "../../components/Window.js";
import ApplicationsManager from "../applications/applications.js"; import ApplicationsManager from "../applications/applications.js";
import Vector2 from "../math/vector2.js"; import Vector2 from "../math/vector2.js";
export default class WindowsManager { export default class WindowsManager {
windows = {}; constructor() {
this.windows = {};
this.updateWindows = () => {};
console.log("Windows manager init");
}
open(appId) { open(appId) {
const appData = ApplicationsManager.getApplication(appId); const app = ApplicationsManager.getApplication(appId);
const size = new Vector2(800, 400); const size = new Vector2(800, 400);
const position = new Vector2(300, 200); const position = new Vector2(300, 200);
let id = 0; let id = 0;
while (Object.keys(this.windows).includes(id)) { while (this.windowIds.includes(id.toString())) {
id++; id++;
} }
console.log(`Opening window ${id}:${appData.id}`); console.log(`Opening window ${id}:${app.id}`);
this.windows[id] = <Window this.windows[id.toString()] = {
id={id} id,
key={id} app,
app={appData} size,
size={size} position
position={position} };
/>;
this.updateWindows(this.windows);
// console.log(this);
} }
close(windowId) { close(windowId) {
if (!Object.keys(this.windows).includes(windowId)) windowId = windowId.toString();
return;
if (!this.windowIds.includes(windowId)) {
console.log(`Failed to close window ${windowId}: window not found`);
return;
}
console.log(`Closing window ${windowId}`); console.log(`Closing window ${windowId}`);
delete this.windows[windowId]; delete this.windows[windowId];
this.updateWindows(this.windows);
// console.log(this);
} }
get windowsCount() { setUpdateWindows(updateWindows) {
return Object.keys(this.windows).length; this.updateWindows = updateWindows;
}
get windowIds() {
return Object.keys(this.windows);
}
get windowsData() {
return Object.values(this.windows);
} }
} }