Skip to content
Permalink
Browse files

feat: add paint

* add paint need handle mouse event

* handle cursor and mouse event

* readme
  • Loading branch information...
ShizukuIchi committed Apr 6, 2019
1 parent 4ba5fd1 commit f5a9cfad8e0fa26aba5e6ee61f1241da07963bdb
@@ -6,7 +6,7 @@ Features:

- Drag and resize, minimize, maximize windows
- Open applications from desktop icons or start menu
- Minesweeper, Internet Explorer, My Computer, Notepad, Winamp
- Minesweeper, Internet Explorer, My Computer, Notepad, Winamp, Paint
- Power off menu

## [Try it!](https://winxp.now.sh)
@@ -24,4 +24,5 @@ Generally open an issue (or comment on an issue if there's one already) before s
The Windows XP name, artwork, trademark are surely property of Microsoft. This project is provided for educational purposes only. It is not affiliated with and has not been approved by Microsoft.

## Thanks
- [Webamp](https://github.com/captbaritone/webamp), Winamp 2 reimplementation by: [captbaritone](https://github.com/captbaritone)
- [Webamp](https://github.com/captbaritone/webamp), Winamp 2 reimplementation by: [captbaritone](https://github.com/captbaritone)
- [JS Paint](https://github.com/1j01/jspaint), Paint reimplementation by: [1j01](https://github.com/1j01)
@@ -6,7 +6,6 @@ import setAccess from 'src/assets/windowsIcons/227(32x32).png';
import outlook from 'src/assets/windowsIcons/887(32x32).png';
import mediaPlayer from 'src/assets/windowsIcons/846(32x32).png';
import messenger from 'src/assets/windowsIcons/msn.png';
import tour from 'src/assets/windowsIcons/853(32x32).png';
import documents from 'src/assets/windowsIcons/308(32x32).png';
import recentDocuments from 'src/assets/windowsIcons/301(32x32).png';
import pictures from 'src/assets/windowsIcons/307(32x32).png';
@@ -15,6 +14,7 @@ import computer from 'src/assets/windowsIcons/676(32x32).png';
import controlPanel from 'src/assets/windowsIcons/300(32x32).png';
import connect from 'src/assets/windowsIcons/309(32x32).png';
import printer from 'src/assets/windowsIcons/549(32x32).png';
import paint from 'src/assets/windowsIcons/680(32x32).png';
import help from 'src/assets/windowsIcons/747(32x32).png';
import search from 'src/assets/windowsIcons/299(32x32).png';
import run from 'src/assets/windowsIcons/743(32x32).png';
@@ -60,9 +60,9 @@ function FooterMenu({ className, onClick }) {
{ icon: mine, text: 'Minesweeper' },
{ icon: notepad, text: 'Notepad' },
{ icon: winamp, text: 'Winamp' },
{ icon: paint, text: 'Paint' },
{ icon: mediaPlayer, text: 'Windows Media Player' },
{ icon: messenger, text: 'Windows Messenger' },
{ icon: tour, text: 'Tour Windows XP' },
]}
/>
<div style={{ flex: 1 }} />
@@ -77,7 +77,7 @@ function Footer({
onMouseDown={toggleMenu}
/>
{[...apps]
.sort((a, b) => a.id - b.id)
// .sort((a, b) => a.id - b.id)
.map(app => (
<FooterWindow
key={app.id}
@@ -11,19 +11,23 @@ function Windows({
onMaximize,
focusedAppId,
}) {
return apps.map(app => (
<StyledWindow
show={!app.minimized}
key={app.id}
id={app.id}
onMouseDown={onMouseDown}
onMouseUpClose={onClose}
onMouseUpMinimize={onMinimize}
onMouseUpMaximize={onMaximize}
isFocus={focusedAppId === app.id} // for styledWindow
{...app}
/>
));
return (
<div style={{ position: 'relative', zIndex: 0 }}>
{apps.map(app => (
<StyledWindow
show={!app.minimized}
key={app.id}
id={app.id}
onMouseDown={onMouseDown}
onMouseUpClose={onClose}
onMouseUpMinimize={onMinimize}
onMouseUpMaximize={onMaximize}
isFocus={focusedAppId === app.id} // for styledWindow
{...app}
/>
))}
</div>
);
}

const Window = memo(function({
@@ -39,6 +43,8 @@ const Window = memo(function({
resizable,
maximized,
component,
zIndex,
isFocus,
className,
}) {
function _onMouseDown() {
@@ -90,6 +96,7 @@ const Window = memo(function({
transform: `translate(${x}px,${y}px)`,
width: width ? `${width}px` : 'auto',
height: height ? `${height}px` : 'auto',
zIndex,
}}
>
<div className="header__bg" />
@@ -118,6 +125,7 @@ const Window = memo(function({
{component({
onClose: _onMouseUpClose,
onMinimize: _onMouseUpMinimize,
isFocus,
...insertProps,
})}
</div>
@@ -0,0 +1,40 @@
import React from 'react';

// add child div to capture mouse event when not focused

function Paint({ onClose, isFocus }) {
return (
<div
style={{
width: '100%',
height: '100%',
position: 'relative',
}}
>
<iframe
src="https://jspaint.app"
frameBorder="0"
title="paint"
style={{
display: 'block',
width: '100%',
height: '100%',
backgroundColor: 'rgb(192,192,192)',
}}
/>
{!isFocus && (
<div
style={{
width: '100%',
height: '100%',
position: 'absolute',
left: 0,
top: 0,
}}
/>
)}
</div>
);
}

export default Paint;
@@ -18,6 +18,7 @@ function Winamp({ onClose, onMinimize }) {
});
return () => {
webamp.current.dispose();
webamp.current = null;
};
}, []);
useEffect(() => {
@@ -4,6 +4,7 @@ import ErrorBox from './ErrorBox';
import MyComputer from './MyComputer';
import Notepad from './Notepad';
import Winamp from './Winamp';
import Paint from './Paint';
import iePaper from 'src/assets/windowsIcons/ie-paper.png';
import ie from 'src/assets/windowsIcons/ie.png';
import mine from 'src/assets/minesweeper/mine-icon.png';
@@ -13,7 +14,18 @@ import computerLarge from 'src/assets/windowsIcons/676(32x32).png';
import notepad from 'src/assets/windowsIcons/327(16x16).png';
import notepadLarge from 'src/assets/windowsIcons/327(32x32).png';
import winamp from 'src/assets/windowsIcons/winamp.png';
import paintLarge from 'src/assets/windowsIcons/680(32x32).png';
import paint from 'src/assets/windowsIcons/680(16x16).png';

const gen = () => {
let id = -1;
return () => {
id += 1;
return id;
};
};
const genId = gen();
const genIndex = gen();
export const defaultAppState = [
{
component: InternetExplorer,
@@ -33,7 +45,8 @@ export const defaultAppState = [
resizable: true,
minimized: false,
maximized: window.innerWidth < 800,
id: 0,
id: genId(),
zIndex: genIndex(),
},
{
component: Minesweeper,
@@ -53,7 +66,8 @@ export const defaultAppState = [
resizable: false,
minimized: false,
maximized: false,
id: 1,
id: genId(),
zIndex: genIndex(),
},
{
component: Winamp,
@@ -73,7 +87,8 @@ export const defaultAppState = [
resizable: false,
minimized: false,
maximized: false,
id: 2,
id: genId(),
zIndex: genIndex(),
},
{
component: MyComputer,
@@ -93,7 +108,8 @@ export const defaultAppState = [
resizable: true,
minimized: false,
maximized: window.innerWidth < 800,
id: 3,
id: genId(),
zIndex: genIndex(),
},
];

@@ -133,6 +149,13 @@ export const defaultIconState = [
component: Winamp,
isFocus: false,
},
{
id: 5,
icon: paintLarge,
title: 'Paint',
component: Paint,
isFocus: false,
},
];

export const appSettings = {
@@ -228,8 +251,8 @@ export const appSettings = {
height: 500,
},
defaultOffset: {
x: 300,
y: 100,
x: 270,
y: 60,
},
resizable: true,
minimized: false,
@@ -256,6 +279,26 @@ export const appSettings = {
maximized: false,
multiInstance: false,
},
Paint: {
header: {
icon: paint,
title: 'Untitled - Paint',
disable: false,
},
component: Paint,
defaultSize: {
width: 660,
height: 500,
},
defaultOffset: {
x: 280,
y: 70,
},
resizable: true,
minimized: false,
maximized: window.innerWidth < 800,
multiInstance: true,
},
};

export { InternetExplorer, Minesweeper, ErrorBox, MyComputer, Notepad, Winamp };
@@ -28,6 +28,7 @@ import { DashedBox } from 'src/components';
const initState = {
apps: defaultAppState,
nextAppID: defaultAppState.length,
nextZIndex: defaultAppState.length,
focusing: FOCUSING.WINDOW,
icons: defaultIconState,
selecting: false,
@@ -46,16 +47,28 @@ const reducer = (state, action = { type: '' }) => {
if (action.payload.multiInstance || !app) {
return {
...state,
apps: [...state.apps, { ...action.payload, id: state.nextAppID }],
apps: [
...state.apps,
{
...action.payload,
id: state.nextAppID,
zIndex: state.nextZIndex,
},
],
nextAppID: state.nextAppID + 1,
nextZIndex: state.nextZIndex + 1,
focusing: FOCUSING.WINDOW,
};
}

const restApps = [...state.apps.filter(_app => _app.id !== app.id)];
const apps = state.apps.map(app =>
app.component === action.payload.component
? { ...app, zIndex: state.nextZIndex, minimized: false }
: app,
);
return {
...state,
apps: app ? [...restApps, { ...app, minimized: false }] : restApps,
apps,
nextZIndex: state.nextZIndex + 1,
focusing: FOCUSING.WINDOW,
};
case DEL_APP:
@@ -70,31 +83,35 @@ const reducer = (state, action = { type: '' }) => {
: FOCUSING.DESKTOP,
};
case FOCUS_APP: {
const app = state.apps.find(app => app.id === action.payload);
const restApps = [...state.apps.filter(app => app.id !== action.payload)];
const apps = state.apps.map(app =>
app.id === action.payload
? { ...app, zIndex: state.nextZIndex, minimized: false }
: app,
);
return {
...state,
apps: app ? [...restApps, { ...app, minimized: false }] : restApps,
apps,
nextZIndex: state.nextZIndex + 1,
focusing: FOCUSING.WINDOW,
};
}
case MINIMIZE_APP: {
const app = state.apps.find(app => app.id === action.payload);
const restApps = state.apps.filter(app => app.id !== action.payload);
const apps = state.apps.map(app =>
app.id === action.payload ? { ...app, minimized: true } : app,
);
return {
...state,
apps: app ? [...restApps, { ...app, minimized: true }] : restApps,
apps,
focusing: FOCUSING.WINDOW,
};
}
case TOGGLE_MAXIMIZE_APP: {
const app = state.apps.find(app => app.id === action.payload);
const restApps = state.apps.filter(app => app.id !== action.payload);
const apps = state.apps.map(app =>
app.id === action.payload ? { ...app, maximized: !app.maximized } : app,
);
return {
...state,
apps: app
? [...restApps, { ...app, maximized: !app.maximized }]
: restApps,
apps,
focusing: FOCUSING.WINDOW,
};
}
@@ -218,10 +235,10 @@ function WinXP() {
dispatch({ type: ADD_APP, payload: appSetting });
}
function getFocusedAppId() {
const lastIndex = state.apps.map(app => app.minimized).lastIndexOf(false);
return lastIndex >= 0 && state.focusing === FOCUSING.WINDOW
? state.apps[lastIndex].id
: -1;
const focusedApp = [...state.apps]
.sort((a, b) => b.zIndex - a.zIndex)
.find(app => !app.minimized);
return focusedApp ? focusedApp.id : -1;
}
function onMouseDownFooter() {
dispatch({ type: FOCUS_DESKTOP });
@@ -237,6 +254,8 @@ function WinXP() {
dispatch({ type: ADD_APP, payload: appSettings.Notepad });
else if (o === 'Winamp')
dispatch({ type: ADD_APP, payload: appSettings.Winamp });
else if (o === 'Paint')
dispatch({ type: ADD_APP, payload: appSettings.Paint });
else if (o === 'Log Off')
dispatch({ type: POWER_OFF, payload: POWER_STATE.LOG_OFF });
else if (o === 'Turn Off Computer')
Oops, something went wrong.

1 comment on commit f5a9cfa

@now

This comment has been minimized.

Copy link

now bot commented on f5a9cfa Apr 6, 2019

Please sign in to comment.
You can’t perform that action at this time.