Skip to content

Commit 57992ac

Browse files
authored
Merge pull request #1 from plainlab/select_rectangle
Select rectangle frame
2 parents 5689eb6 + db8358d commit 57992ac

File tree

7 files changed

+233
-28
lines changed

7 files changed

+233
-28
lines changed

src/App.global.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
@apply outline-none hover:opacity-80 active:text-gray-300 active:outline-none focus:outline-none;
1212
}
1313

14-
input[type='text'] {
15-
@apply rounded focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-inset;
14+
input[type='number'] {
15+
@apply px-1 py-0.5 rounded focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-inset;
1616
}
1717

1818
input[type='radio'] {

src/App.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ export default function App() {
1616
render={(props) => {
1717
const { search } = props.location;
1818
const so = qs.parse(search.slice(search.lastIndexOf('?') + 1));
19-
return so.page === 'screen' ? <Screen /> : <Main />;
19+
return so.page === 'screen' ? (
20+
<Screen select={so.select?.toString() || 'frame'} />
21+
) : (
22+
<Main />
23+
);
2024
}}
2125
/>
2226
</Switch>

src/components/printer/Main.tsx

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,107 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { ipcRenderer } from 'electron';
33

4+
interface Coord {
5+
select: string;
6+
x0: number;
7+
y0: number;
8+
x1: number;
9+
y1: number;
10+
}
11+
412
const Main = () => {
5-
const handleScreenSelect = async () => {
6-
await ipcRenderer.invoke('open-screen');
13+
const [frameCoord, setFrameCoord] = useState<Coord>();
14+
const [nextCoord, setNextCoord] = useState<Coord>();
15+
const [pages, setPages] = useState(0);
16+
17+
const handleCloseScreen = (c: Coord) => {
18+
if (c.select === 'frame') {
19+
setFrameCoord({ ...c });
20+
} else if (c.select === 'next') {
21+
setNextCoord({ ...c });
22+
}
23+
};
24+
25+
const handleOpenScreen = (select: string) => {
26+
if (select === 'frame') {
27+
setFrameCoord(undefined);
28+
} else {
29+
setNextCoord(undefined);
30+
}
31+
32+
ipcRenderer.invoke('open-screen', { select });
733
};
834

35+
const handlePrint = () => {
36+
ipcRenderer.invoke('start-printing', { frameCoord, nextCoord, pages });
37+
};
38+
39+
ipcRenderer.on('close-screen', (_, c: Coord) => {
40+
handleCloseScreen(c);
41+
});
42+
943
return (
10-
<section className="flex flex-1">
11-
<button type="button" onClick={handleScreenSelect}>
12-
Open
13-
</button>
44+
<section className="absolute inset-0 flex flex-col items-stretch justify-center p-8 space-y-8 bg-gray-100">
45+
<section className="flex flex-col items-stretch flex-1 p-4 border rounded space-y-7">
46+
<section className="flex items-center justify-start space-x-4">
47+
<button
48+
type="button"
49+
onClick={() => handleOpenScreen('frame')}
50+
className="btn"
51+
>
52+
Select screenshot frame...
53+
</button>
54+
{frameCoord ? (
55+
<p>
56+
Rect: ({frameCoord.x0}, {frameCoord.y0}) and ({frameCoord.x1},{' '}
57+
{frameCoord.y1})
58+
</p>
59+
) : (
60+
<p />
61+
)}
62+
</section>
63+
64+
<section className="flex items-center justify-start space-x-4">
65+
<button
66+
type="button"
67+
onClick={() => handleOpenScreen('next')}
68+
className="btn"
69+
>
70+
Select next button...
71+
</button>
72+
{nextCoord ? (
73+
<p>
74+
Point: ({(nextCoord.x0 + nextCoord.x1) / 2},{' '}
75+
{(nextCoord.y0 + nextCoord.y1) / 2})
76+
</p>
77+
) : (
78+
<p />
79+
)}
80+
</section>
81+
82+
<section className="flex items-center justify-start ml-1 space-x-4">
83+
<p>Total pages:</p>
84+
<input
85+
value={pages}
86+
onChange={(e) => setPages(parseInt(e.target.value, 10))}
87+
type="number"
88+
/>
89+
</section>
90+
</section>
91+
92+
<section className="flex flex-col items-center space-y-4">
93+
<button
94+
type="button"
95+
onClick={handlePrint}
96+
className="w-full py-2 text-base btn"
97+
disabled={!frameCoord || !nextCoord || !pages}
98+
>
99+
Start printing
100+
</button>
101+
<p className="opacity-50">
102+
You can stop printing anytime by pressing the &quot;ESC&quot; button
103+
</p>
104+
</section>
14105
</section>
15106
);
16107
};

src/components/printer/Screen.tsx

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,104 @@
1-
import React from 'react';
1+
import { ipcRenderer } from 'electron';
2+
import React, { MouseEvent, useRef, useState, useEffect } from 'react';
3+
4+
const Screen = ({ select }: { select: string }) => {
5+
const parentRef = useRef<HTMLDivElement>(null);
6+
const canvasRef = useRef<HTMLCanvasElement>(null);
7+
8+
const [mouse, setMouse] = useState({
9+
select,
10+
startX: 0,
11+
startY: 0,
12+
x0: 0,
13+
y0: 0,
14+
x1: 0,
15+
y1: 0,
16+
});
17+
const [draging, setDraging] = useState(false);
18+
19+
const closeScreen = () => {
20+
ipcRenderer.invoke('close-screen', { ...mouse });
21+
};
22+
23+
const setCanvasSize = () => {
24+
const ctx = canvasRef.current;
25+
if (ctx) {
26+
ctx.width = window.innerWidth || 1000;
27+
ctx.height = window.innerHeight || 1000;
28+
}
29+
};
30+
31+
const handleMouseDown = (ev: MouseEvent) => {
32+
setMouse({
33+
...mouse,
34+
startX: ev.pageX - (canvasRef.current?.getBoundingClientRect().left || 0),
35+
startY: ev.pageY - (canvasRef.current?.getBoundingClientRect().top || 0),
36+
x0: ev.screenX,
37+
y0: ev.screenY,
38+
});
39+
40+
setCanvasSize();
41+
setDraging(true);
42+
};
43+
44+
const handleMouseMove = (ev: MouseEvent) => {
45+
if (!draging) {
46+
return;
47+
}
48+
49+
const ctx = canvasRef.current?.getContext('2d');
50+
51+
if (ctx) {
52+
const width =
53+
ev.pageX -
54+
(canvasRef.current?.getBoundingClientRect().left || 0) -
55+
mouse.startX;
56+
const height =
57+
ev.pageY -
58+
(canvasRef.current?.getBoundingClientRect().top || 0) -
59+
mouse.startY;
60+
61+
setMouse({
62+
...mouse,
63+
x1: ev.screenX,
64+
y1: ev.screenY,
65+
});
66+
67+
ctx.clearRect(
68+
0,
69+
0,
70+
parentRef.current?.clientWidth || 1000,
71+
parentRef.current?.clientHeight || 1000
72+
);
73+
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
74+
ctx.fillRect(mouse.startX, mouse.startY, width, height);
75+
}
76+
};
77+
78+
const handleMouseUp = () => {
79+
setDraging(false);
80+
closeScreen();
81+
};
82+
83+
useEffect(() => {
84+
window.onblur = closeScreen;
85+
window.onresize = setCanvasSize;
86+
}, []);
287

3-
const Screen = () => {
488
return (
5-
<section className="flex flex-1">
6-
<p>Hello!</p>
7-
</section>
89+
<div
90+
style={{ cursor: draging ? 'crosshair' : 'default' }}
91+
className="w-full h-full"
92+
ref={parentRef}
93+
>
94+
<canvas
95+
ref={canvasRef}
96+
className="bg-gray-50 opacity-20"
97+
onMouseDown={handleMouseDown}
98+
onMouseMove={handleMouseMove}
99+
onMouseUp={handleMouseUp}
100+
/>
101+
</div>
8102
);
9103
};
10104

src/main.dev.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ const installExtensions = async () => {
7171
.catch(console.log);
7272
};
7373

74+
let stopPrinting = false;
75+
7476
const createWindow = async () => {
7577
if (
7678
process.env.NODE_ENV === 'development' ||
@@ -89,8 +91,8 @@ const createWindow = async () => {
8991

9092
mainWindow = new BrowserWindow({
9193
show: false,
92-
width: 1024,
93-
height: 728,
94+
width: 512,
95+
height: 364,
9496
icon: getAssetPath('icon.png'),
9597
webPreferences: {
9698
nodeIntegration: true,
@@ -113,6 +115,12 @@ const createWindow = async () => {
113115
}
114116
});
115117

118+
mainWindow.webContents.on('before-input-event', (event, ipnut) => {
119+
if (ipnut.key === 'Escape') {
120+
stopPrinting = true;
121+
}
122+
});
123+
116124
mainWindow.on('closed', () => {
117125
mainWindow = null;
118126
});
@@ -177,21 +185,25 @@ ipcMain.handle(
177185
}
178186
);
179187

180-
const createScreenWindow = () => {
188+
const createScreenWindow = (select: string) => {
181189
if (screenWindow == null) {
182190
screenWindow = new BrowserWindow({
183191
frame: false,
184192
transparent: true,
185193
webPreferences: {
186194
nodeIntegration: true,
195+
contextIsolation: false,
187196
},
197+
parent: mainWindow || undefined,
188198
});
189199
}
190-
screenWindow.loadURL(`file://${__dirname}/index.html?page=screen`);
200+
screenWindow.loadURL(
201+
`file://${__dirname}/index.html?page=screen&select=${select}`
202+
);
191203

192204
screenWindow.webContents.on('did-finish-load', () => {
193-
screenWindow?.show();
194205
screenWindow?.maximize();
206+
screenWindow?.show();
195207
});
196208

197209
screenWindow.webContents.on('before-input-event', (event, ipnut) => {
@@ -207,14 +219,23 @@ const createScreenWindow = () => {
207219
screenWindow.webContents.openDevTools({ mode: 'undocked' });
208220
};
209221

210-
ipcMain.handle('open-screen', async () => {
211-
createScreenWindow();
222+
ipcMain.handle('open-screen', async (_, { select }) => {
223+
createScreenWindow(select);
212224
});
213225

214226
ipcMain.handle('get-store', (_event, { key }) => {
215227
return store.get(key);
216228
});
217229

230+
ipcMain.handle('close-screen', (_, coord) => {
231+
mainWindow?.webContents.send('close-screen', coord);
232+
screenWindow?.close();
233+
});
234+
235+
ipcMain.handle('start-printing', (_, { frameCoord, nextCoord, pages }) => {
236+
console.log('Print with params', frameCoord, nextCoord, pages);
237+
});
238+
218239
/**
219240
* Add event listeners...
220241
*/

src/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "plainprinter",
33
"productName": "PlainPrinter",
4-
"version": "0.0.7",
4+
"version": "0.0.1",
55
"description": "Plain screen printer",
66
"main": "./main.prod.js",
77
"author": {

yarn.lock

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,11 +1586,6 @@
15861586
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz"
15871587
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
15881588

1589-
"@types/diff@^5.0.1":
1590-
version "5.0.1"
1591-
resolved "https://registry.npmjs.org/@types/diff/-/diff-5.0.1.tgz"
1592-
integrity sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==
1593-
15941589
"@types/enzyme-adapter-react-16@^1.0.6":
15951590
version "1.0.6"
15961591
resolved "https://registry.npmjs.org/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.6.tgz"

0 commit comments

Comments
 (0)