quickwin 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +204 -204
- package/README.md +203 -203
- package/examples/PdfCanvas.tsx +83 -83
- package/examples/exec_server.ts +35 -35
- package/examples/pdf_preview2.ts +375 -375
- package/examples/pdf_viewer.tsx +279 -279
- package/examples/test_gallery.tsx +285 -285
- package/examples/test_react_lazy.tsx +63 -63
- package/examples/test_react_listbox.tsx +71 -71
- package/examples/test_root_window.tsx +41 -41
- package/examples/test_tab.tsx +75 -75
- package/examples/tray_demo.tsx +81 -81
- package/lib/assert.ts +6 -6
- package/lib/cache-utils.ts +40 -40
- package/lib/dumpRects.ts +25 -25
- package/lib/fetch.ts +502 -502
- package/lib/http-common.ts +399 -399
- package/lib/http-server.ts +424 -424
- package/lib/polyfill.ts +171 -171
- package/lib/react-qw/components/index.ts +17 -17
- package/lib/react-qw/index.ts +90 -90
- package/lib/react-qw/jsx.d.ts +34 -34
- package/lib/react-qw/layout.ts +111 -111
- package/lib/react-qw/props.ts +36 -36
- package/lib/react-qw/reconciler.ts +373 -373
- package/lib/stream.ts +21 -21
- package/lib/text-codec.ts +171 -171
- package/lib/text-measure.ts +54 -54
- package/lib/url.ts +201 -201
- package/lib/vendor/web-streams/ponyfill.d.mts +829 -829
- package/lib/vendor/web-streams/ponyfill.mjs +8 -8
- package/lib/websocket.js +8 -0
- package/lib/websocket.ts +563 -555
- package/package.json +50 -44
- package/qwin-nowasm-x86.exe +0 -0
- package/qwin-nowasm.exe +0 -0
- package/qwin-x86.exe +0 -0
- package/qwin.exe +0 -0
- package/test/run.ts +96 -96
- package/test/test_basic.ts +9 -9
- package/test/test_basic_fetch.ts +33 -33
- package/test/test_brotli.ts +52 -52
- package/test/test_fetch_cache.ts +187 -187
- package/test/test_ffi.ts +174 -174
- package/test/test_frame_encoding.ts +132 -132
- package/test/test_helper.ts +80 -80
- package/test/test_http_import.ts +74 -74
- package/test/test_http_server.ts +136 -136
- package/test/test_import_dir.ts +5 -5
- package/test/test_ipv6.ts +129 -129
- package/test/test_meta_url.ts +4 -4
- package/test/test_mupdf_render.ts +74 -74
- package/test/test_mupdf_twice.ts +81 -81
- package/test/test_mupdf_wasm.ts +30 -30
- package/test/test_net_event.ts +55 -55
- package/test/test_net_fetch.ts +238 -238
- package/test/test_net_websocket.ts +164 -164
- package/test/test_polyfill.ts +159 -159
- package/test/test_url.ts +183 -183
- package/test/test_wasm_basic.ts +73 -73
- package/test/test_wasm_import_global.ts +45 -45
- package/test/test_wasm_sjlj.ts +125 -125
- package/test/test_wasm_types.ts +124 -124
- package/test/test_worker.ts +24 -24
- package/test/test_worker_fetch.ts +27 -27
- package/test/test_worker_net.ts +54 -54
- package/test/test_worker_wasm_concurrent.ts +45 -45
- package/test/worker_fetch.ts +13 -13
- package/test/worker_helper.ts +1 -1
- package/test/worker_http.ts +20 -20
- package/test/worker_import_lib.ts +13 -13
- package/test/worker_module.ts +17 -17
- package/test/worker_wasm_concurrent.ts +22 -22
- package/tsconfig.json +27 -27
- package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -571
- package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -2749
- package/vendor/mupdf-wasm/mupdf.d.ts +939 -939
- package/vendor/mupdf-wasm/mupdf.js +3317 -3317
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import '../lib/polyfill.js'
|
|
2
|
-
import * as gui from 'gui'
|
|
3
|
-
import { Suspense, lazy, useState } from 'react'
|
|
4
|
-
import { render } from '../lib/react-qw/index.js'
|
|
5
|
-
|
|
6
|
-
gui.RegisterClass('LazyTest', (hwnd, msg, wParam, lParam) => {
|
|
7
|
-
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
8
|
-
if (msg === gui.WmMsg.DESTROY) {
|
|
9
|
-
gui.PostQuitMessage(0)
|
|
10
|
-
return 0
|
|
11
|
-
}
|
|
12
|
-
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
function SimpleComponent() {
|
|
16
|
-
return (
|
|
17
|
-
<w type="STATIC" text="Hello from lazy component!"
|
|
18
|
-
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
19
|
-
style={{width:300, height:30}} />
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const LazySimple = lazy(async () => {
|
|
24
|
-
await new Promise(r => setTimeout(r, 500, undefined))
|
|
25
|
-
return { default: SimpleComponent }
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
function App() {
|
|
29
|
-
const [show, setShow] = useState(false)
|
|
30
|
-
return (
|
|
31
|
-
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
32
|
-
style={{flexDirection:'column', padding:10, gap:10, flexGrow:1}}>
|
|
33
|
-
<w type="BUTTON"
|
|
34
|
-
text={show ? 'Hide Lazy' : 'Show Lazy'}
|
|
35
|
-
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
36
|
-
style={{width:150, height:30}}
|
|
37
|
-
onEvent={(e: { msg: number; wParam: number; lParam: number }) => {
|
|
38
|
-
if (e.msg === 0x0202) setShow(!show)
|
|
39
|
-
}}
|
|
40
|
-
/>
|
|
41
|
-
{show && (
|
|
42
|
-
<Suspense fallback={
|
|
43
|
-
<w type="STATIC" text="Loading..."
|
|
44
|
-
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
45
|
-
style={{width:200, height:30}} />
|
|
46
|
-
}>
|
|
47
|
-
<LazySimple />
|
|
48
|
-
</Suspense>
|
|
49
|
-
)}
|
|
50
|
-
</w>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const hwnd = gui.CreateWindow(
|
|
55
|
-
'LazyTest', 'React.lazy Test',
|
|
56
|
-
gui.WindowStyle.OVERLAPPEDWINDOW,
|
|
57
|
-
200, 200, 400, 300, null, null
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
if (hwnd) {
|
|
61
|
-
gui.ShowWindow(hwnd)
|
|
62
|
-
render(<App />, hwnd)
|
|
63
|
-
}
|
|
1
|
+
import '../lib/polyfill.js'
|
|
2
|
+
import * as gui from 'gui'
|
|
3
|
+
import { Suspense, lazy, useState } from 'react'
|
|
4
|
+
import { render } from '../lib/react-qw/index.js'
|
|
5
|
+
|
|
6
|
+
gui.RegisterClass('LazyTest', (hwnd, msg, wParam, lParam) => {
|
|
7
|
+
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
8
|
+
if (msg === gui.WmMsg.DESTROY) {
|
|
9
|
+
gui.PostQuitMessage(0)
|
|
10
|
+
return 0
|
|
11
|
+
}
|
|
12
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
function SimpleComponent() {
|
|
16
|
+
return (
|
|
17
|
+
<w type="STATIC" text="Hello from lazy component!"
|
|
18
|
+
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
19
|
+
style={{width:300, height:30}} />
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const LazySimple = lazy(async () => {
|
|
24
|
+
await new Promise(r => setTimeout(r, 500, undefined))
|
|
25
|
+
return { default: SimpleComponent }
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
function App() {
|
|
29
|
+
const [show, setShow] = useState(false)
|
|
30
|
+
return (
|
|
31
|
+
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
32
|
+
style={{flexDirection:'column', padding:10, gap:10, flexGrow:1}}>
|
|
33
|
+
<w type="BUTTON"
|
|
34
|
+
text={show ? 'Hide Lazy' : 'Show Lazy'}
|
|
35
|
+
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
36
|
+
style={{width:150, height:30}}
|
|
37
|
+
onEvent={(e: { msg: number; wParam: number; lParam: number }) => {
|
|
38
|
+
if (e.msg === 0x0202) setShow(!show)
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
{show && (
|
|
42
|
+
<Suspense fallback={
|
|
43
|
+
<w type="STATIC" text="Loading..."
|
|
44
|
+
ws={gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE}
|
|
45
|
+
style={{width:200, height:30}} />
|
|
46
|
+
}>
|
|
47
|
+
<LazySimple />
|
|
48
|
+
</Suspense>
|
|
49
|
+
)}
|
|
50
|
+
</w>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const hwnd = gui.CreateWindow(
|
|
55
|
+
'LazyTest', 'React.lazy Test',
|
|
56
|
+
gui.WindowStyle.OVERLAPPEDWINDOW,
|
|
57
|
+
200, 200, 400, 300, null, null
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if (hwnd) {
|
|
61
|
+
gui.ShowWindow(hwnd)
|
|
62
|
+
render(<App />, hwnd)
|
|
63
|
+
}
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import '../lib/polyfill.js'
|
|
2
|
-
import * as gui from 'gui'
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { render, ListBox } from '../lib/react-qw/index.js'
|
|
5
|
-
|
|
6
|
-
let itemCounter = 10
|
|
7
|
-
|
|
8
|
-
function App() {
|
|
9
|
-
const [items, setItems] = useState(() => {
|
|
10
|
-
const a: string[] = []
|
|
11
|
-
for (let i = 0; i < 10; i++) a.push(`Item ${i}`)
|
|
12
|
-
return a
|
|
13
|
-
})
|
|
14
|
-
const [selectedText, setSelectedText] = useState('none')
|
|
15
|
-
const [selIndex, setSelIndex] = useState(0)
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<w
|
|
19
|
-
type="STATIC"
|
|
20
|
-
ws={gui.WindowStyle.VISIBLE}
|
|
21
|
-
style={{ width: 400, height: 500, flexDirection: 'column', alignItems: 'flex-start' }}
|
|
22
|
-
>
|
|
23
|
-
<w
|
|
24
|
-
type="STATIC"
|
|
25
|
-
ws={gui.WindowStyle.VISIBLE}
|
|
26
|
-
style={{ flexDirection: 'row', width: 400, height: 26 }}
|
|
27
|
-
>
|
|
28
|
-
<w
|
|
29
|
-
type="BUTTON"
|
|
30
|
-
text="Add Item"
|
|
31
|
-
ws={gui.WindowStyle.VISIBLE}
|
|
32
|
-
style={{ width: 80, height: 26 }}
|
|
33
|
-
onEvent={(e) => {
|
|
34
|
-
if (e.msg === gui.WmMsg.LBUTTONDOWN) {
|
|
35
|
-
setItems(prev => [...prev, `Item ${itemCounter++}`])
|
|
36
|
-
}
|
|
37
|
-
}}
|
|
38
|
-
/>
|
|
39
|
-
<w
|
|
40
|
-
type="STATIC"
|
|
41
|
-
text={`Selected[${selIndex}]: ${selectedText}`}
|
|
42
|
-
ws={gui.WindowStyle.VISIBLE}
|
|
43
|
-
style={{ width: 200, height: 26 }}
|
|
44
|
-
/>
|
|
45
|
-
</w>
|
|
46
|
-
<ListBox
|
|
47
|
-
items={items}
|
|
48
|
-
selectedIndex={selIndex}
|
|
49
|
-
onChange={(i) => {
|
|
50
|
-
setSelIndex(i)
|
|
51
|
-
setSelectedText(items[i]!)
|
|
52
|
-
}}
|
|
53
|
-
style={{ flexGrow: 1, alignSelf: 'stretch' }}
|
|
54
|
-
/>
|
|
55
|
-
</w>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
gui.RegisterClass('ListBoxDemo', (hwnd, msg, wParam, lParam) => {
|
|
60
|
-
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
61
|
-
if (msg === gui.WmMsg.CREATE) {
|
|
62
|
-
render(<App />, hwnd)
|
|
63
|
-
return 0
|
|
64
|
-
}
|
|
65
|
-
// WM_COMMAND 现在由 ListBox wrapper 通过 onEvent 处理
|
|
66
|
-
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const hwnd = gui.CreateWindow('ListBoxDemo', 'ListBox Demo',
|
|
70
|
-
gui.WindowStyle.OVERLAPPEDWINDOW, 200, 100, 400, 500, null, null)
|
|
71
|
-
if (hwnd) gui.ShowWindow(hwnd)
|
|
1
|
+
import '../lib/polyfill.js'
|
|
2
|
+
import * as gui from 'gui'
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { render, ListBox } from '../lib/react-qw/index.js'
|
|
5
|
+
|
|
6
|
+
let itemCounter = 10
|
|
7
|
+
|
|
8
|
+
function App() {
|
|
9
|
+
const [items, setItems] = useState(() => {
|
|
10
|
+
const a: string[] = []
|
|
11
|
+
for (let i = 0; i < 10; i++) a.push(`Item ${i}`)
|
|
12
|
+
return a
|
|
13
|
+
})
|
|
14
|
+
const [selectedText, setSelectedText] = useState('none')
|
|
15
|
+
const [selIndex, setSelIndex] = useState(0)
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<w
|
|
19
|
+
type="STATIC"
|
|
20
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
21
|
+
style={{ width: 400, height: 500, flexDirection: 'column', alignItems: 'flex-start' }}
|
|
22
|
+
>
|
|
23
|
+
<w
|
|
24
|
+
type="STATIC"
|
|
25
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
26
|
+
style={{ flexDirection: 'row', width: 400, height: 26 }}
|
|
27
|
+
>
|
|
28
|
+
<w
|
|
29
|
+
type="BUTTON"
|
|
30
|
+
text="Add Item"
|
|
31
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
32
|
+
style={{ width: 80, height: 26 }}
|
|
33
|
+
onEvent={(e) => {
|
|
34
|
+
if (e.msg === gui.WmMsg.LBUTTONDOWN) {
|
|
35
|
+
setItems(prev => [...prev, `Item ${itemCounter++}`])
|
|
36
|
+
}
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
<w
|
|
40
|
+
type="STATIC"
|
|
41
|
+
text={`Selected[${selIndex}]: ${selectedText}`}
|
|
42
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
43
|
+
style={{ width: 200, height: 26 }}
|
|
44
|
+
/>
|
|
45
|
+
</w>
|
|
46
|
+
<ListBox
|
|
47
|
+
items={items}
|
|
48
|
+
selectedIndex={selIndex}
|
|
49
|
+
onChange={(i) => {
|
|
50
|
+
setSelIndex(i)
|
|
51
|
+
setSelectedText(items[i]!)
|
|
52
|
+
}}
|
|
53
|
+
style={{ flexGrow: 1, alignSelf: 'stretch' }}
|
|
54
|
+
/>
|
|
55
|
+
</w>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
gui.RegisterClass('ListBoxDemo', (hwnd, msg, wParam, lParam) => {
|
|
60
|
+
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
61
|
+
if (msg === gui.WmMsg.CREATE) {
|
|
62
|
+
render(<App />, hwnd)
|
|
63
|
+
return 0
|
|
64
|
+
}
|
|
65
|
+
// WM_COMMAND 现在由 ListBox wrapper 通过 onEvent 处理
|
|
66
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const hwnd = gui.CreateWindow('ListBoxDemo', 'ListBox Demo',
|
|
70
|
+
gui.WindowStyle.OVERLAPPEDWINDOW, 200, 100, 400, 500, null, null)
|
|
71
|
+
if (hwnd) gui.ShowWindow(hwnd)
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import '../lib/polyfill.js'
|
|
2
|
-
import { useState } from 'react'
|
|
3
|
-
import { Button, Input, createRoot } from '../lib/react-qw/index.js'
|
|
4
|
-
import * as gui from 'gui'
|
|
5
|
-
|
|
6
|
-
function Counter() {
|
|
7
|
-
const [count, setCount] = useState(0)
|
|
8
|
-
return (
|
|
9
|
-
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
10
|
-
style={{ flexDirection: 'column', gap: 8, flexGrow: 1 }}>
|
|
11
|
-
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
12
|
-
style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
13
|
-
<Button onClick={() => setCount(c => c + 1)}>Count: {count}</Button>
|
|
14
|
-
<Button onClick={() => setCount(0)}>Reset</Button>
|
|
15
|
-
</w>
|
|
16
|
-
<Input placeholder="Type something..." />
|
|
17
|
-
<w type="STATIC" text={`You clicked ${count} times`} />
|
|
18
|
-
</w>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function Logger() {
|
|
23
|
-
const [logs, setLogs] = useState<string[]>([])
|
|
24
|
-
const add = () => setLogs(prev => [...prev, `log ${prev.length + 1}`])
|
|
25
|
-
return (
|
|
26
|
-
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
27
|
-
style={{ flexDirection: 'column', gap: 8, flexGrow: 1 }}>
|
|
28
|
-
<Button onClick={add}>Add Log</Button>
|
|
29
|
-
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
30
|
-
style={{ flexDirection: 'column', gap: 4, flexGrow: 1 }}>
|
|
31
|
-
{logs.map((l, i) => <w key={String(i)} type="STATIC" text={l} />)}
|
|
32
|
-
</w>
|
|
33
|
-
</w>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const win1 = createRoot({ text: 'Counter', x: 100, y: 100, width: 420, height: 340 })
|
|
38
|
-
win1.render(<Counter />)
|
|
39
|
-
|
|
40
|
-
const win2 = createRoot({ text: 'Logger', x: 550, y: 100, width: 420, height: 340 })
|
|
41
|
-
win2.render(<Logger />)
|
|
1
|
+
import '../lib/polyfill.js'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { Button, Input, createRoot } from '../lib/react-qw/index.js'
|
|
4
|
+
import * as gui from 'gui'
|
|
5
|
+
|
|
6
|
+
function Counter() {
|
|
7
|
+
const [count, setCount] = useState(0)
|
|
8
|
+
return (
|
|
9
|
+
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
10
|
+
style={{ flexDirection: 'column', gap: 8, flexGrow: 1 }}>
|
|
11
|
+
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
12
|
+
style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
13
|
+
<Button onClick={() => setCount(c => c + 1)}>Count: {count}</Button>
|
|
14
|
+
<Button onClick={() => setCount(0)}>Reset</Button>
|
|
15
|
+
</w>
|
|
16
|
+
<Input placeholder="Type something..." />
|
|
17
|
+
<w type="STATIC" text={`You clicked ${count} times`} />
|
|
18
|
+
</w>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function Logger() {
|
|
23
|
+
const [logs, setLogs] = useState<string[]>([])
|
|
24
|
+
const add = () => setLogs(prev => [...prev, `log ${prev.length + 1}`])
|
|
25
|
+
return (
|
|
26
|
+
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
27
|
+
style={{ flexDirection: 'column', gap: 8, flexGrow: 1 }}>
|
|
28
|
+
<Button onClick={add}>Add Log</Button>
|
|
29
|
+
<w type="STATIC" ws={gui.WindowStyle.VISIBLE}
|
|
30
|
+
style={{ flexDirection: 'column', gap: 4, flexGrow: 1 }}>
|
|
31
|
+
{logs.map((l, i) => <w key={String(i)} type="STATIC" text={l} />)}
|
|
32
|
+
</w>
|
|
33
|
+
</w>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const win1 = createRoot({ text: 'Counter', x: 100, y: 100, width: 420, height: 340 })
|
|
38
|
+
win1.render(<Counter />)
|
|
39
|
+
|
|
40
|
+
const win2 = createRoot({ text: 'Logger', x: 550, y: 100, width: 420, height: 340 })
|
|
41
|
+
win2.render(<Logger />)
|
package/examples/test_tab.tsx
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import '../lib/polyfill.js'
|
|
2
|
-
import * as gui from 'gui'
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { render, Button, Tab } from '../lib/react-qw/index.js'
|
|
5
|
-
|
|
6
|
-
gui.RegisterClass('TabDemo', (hwnd, msg, wParam, lParam) => {
|
|
7
|
-
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
8
|
-
if (msg === gui.WmMsg.DESTROY) {
|
|
9
|
-
gui.PostQuitMessage(0)
|
|
10
|
-
return 0
|
|
11
|
-
}
|
|
12
|
-
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
function App() {
|
|
16
|
-
const [tabIndex, setTabIndex] = useState(0)
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<w type="STATIC"
|
|
20
|
-
ws={gui.WindowStyle.VISIBLE}
|
|
21
|
-
style={{ flexDirection: 'column', width: 600, height: 400, padding: 10 }}
|
|
22
|
-
>
|
|
23
|
-
<Tab
|
|
24
|
-
tabs={[
|
|
25
|
-
{
|
|
26
|
-
title: 'Counter',
|
|
27
|
-
content: (
|
|
28
|
-
<w type="STATIC"
|
|
29
|
-
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
30
|
-
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
31
|
-
<Button onClick={() => setTabIndex(1)}>Go to Tab 2</Button>
|
|
32
|
-
</w>
|
|
33
|
-
),
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
title: 'Buttons',
|
|
37
|
-
content: (
|
|
38
|
-
<w type="STATIC"
|
|
39
|
-
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
40
|
-
style={{ flexDirection: 'row', gap: 10, padding: 10, width: 580, height: 300, alignItems: 'stretch' }}>
|
|
41
|
-
<Button onClick={() => setTabIndex(2)}>Go to Tab 3</Button>
|
|
42
|
-
<Button onClick={() => setTabIndex(0)} style={{ width: 120 }}>Back</Button>
|
|
43
|
-
</w>
|
|
44
|
-
),
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
title: 'Final',
|
|
48
|
-
content: (
|
|
49
|
-
<w type="STATIC"
|
|
50
|
-
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
51
|
-
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
52
|
-
<Button onClick={() => setTabIndex(0)}>Back to Tab 1</Button>
|
|
53
|
-
<Button onClick={() => setTabIndex(1)}>Back to Tab 2</Button>
|
|
54
|
-
</w>
|
|
55
|
-
),
|
|
56
|
-
},
|
|
57
|
-
]}
|
|
58
|
-
style={{ flexGrow: 1 }}
|
|
59
|
-
selectedIndex={tabIndex}
|
|
60
|
-
onChange={(i) => setTabIndex(i)}
|
|
61
|
-
/>
|
|
62
|
-
</w>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const hwnd = gui.CreateWindow(
|
|
67
|
-
'TabDemo', 'Tab Demo',
|
|
68
|
-
gui.WindowStyle.OVERLAPPEDWINDOW,
|
|
69
|
-
100, 100, 640, 480, null, null
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
if (hwnd) {
|
|
73
|
-
gui.ShowWindow(hwnd)
|
|
74
|
-
render(<App />, hwnd)
|
|
75
|
-
}
|
|
1
|
+
import '../lib/polyfill.js'
|
|
2
|
+
import * as gui from 'gui'
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { render, Button, Tab } from '../lib/react-qw/index.js'
|
|
5
|
+
|
|
6
|
+
gui.RegisterClass('TabDemo', (hwnd, msg, wParam, lParam) => {
|
|
7
|
+
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
8
|
+
if (msg === gui.WmMsg.DESTROY) {
|
|
9
|
+
gui.PostQuitMessage(0)
|
|
10
|
+
return 0
|
|
11
|
+
}
|
|
12
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
function App() {
|
|
16
|
+
const [tabIndex, setTabIndex] = useState(0)
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<w type="STATIC"
|
|
20
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
21
|
+
style={{ flexDirection: 'column', width: 600, height: 400, padding: 10 }}
|
|
22
|
+
>
|
|
23
|
+
<Tab
|
|
24
|
+
tabs={[
|
|
25
|
+
{
|
|
26
|
+
title: 'Counter',
|
|
27
|
+
content: (
|
|
28
|
+
<w type="STATIC"
|
|
29
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
30
|
+
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
31
|
+
<Button onClick={() => setTabIndex(1)}>Go to Tab 2</Button>
|
|
32
|
+
</w>
|
|
33
|
+
),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Buttons',
|
|
37
|
+
content: (
|
|
38
|
+
<w type="STATIC"
|
|
39
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
40
|
+
style={{ flexDirection: 'row', gap: 10, padding: 10, width: 580, height: 300, alignItems: 'stretch' }}>
|
|
41
|
+
<Button onClick={() => setTabIndex(2)}>Go to Tab 3</Button>
|
|
42
|
+
<Button onClick={() => setTabIndex(0)} style={{ width: 120 }}>Back</Button>
|
|
43
|
+
</w>
|
|
44
|
+
),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'Final',
|
|
48
|
+
content: (
|
|
49
|
+
<w type="STATIC"
|
|
50
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
51
|
+
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
52
|
+
<Button onClick={() => setTabIndex(0)}>Back to Tab 1</Button>
|
|
53
|
+
<Button onClick={() => setTabIndex(1)}>Back to Tab 2</Button>
|
|
54
|
+
</w>
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
]}
|
|
58
|
+
style={{ flexGrow: 1 }}
|
|
59
|
+
selectedIndex={tabIndex}
|
|
60
|
+
onChange={(i) => setTabIndex(i)}
|
|
61
|
+
/>
|
|
62
|
+
</w>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const hwnd = gui.CreateWindow(
|
|
67
|
+
'TabDemo', 'Tab Demo',
|
|
68
|
+
gui.WindowStyle.OVERLAPPEDWINDOW,
|
|
69
|
+
100, 100, 640, 480, null, null
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (hwnd) {
|
|
73
|
+
gui.ShowWindow(hwnd)
|
|
74
|
+
render(<App />, hwnd)
|
|
75
|
+
}
|
package/examples/tray_demo.tsx
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
import * as gui from 'gui'
|
|
2
|
-
import * as std from 'std'
|
|
3
|
-
|
|
4
|
-
const WM_TRAY = 0x8001
|
|
5
|
-
|
|
6
|
-
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
7
|
-
if (msg === WM_TRAY) {
|
|
8
|
-
const evt = lParam
|
|
9
|
-
if (evt === 0x0201) { // WM_LBUTTONDOWN
|
|
10
|
-
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
11
|
-
gui.SetForegroundWindow(hwnd)
|
|
12
|
-
} else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
|
|
13
|
-
gui.SetForegroundWindow(hwnd)
|
|
14
|
-
const pos = gui.GetCursorPos()
|
|
15
|
-
const x = pos ? pos[0] : 0
|
|
16
|
-
const y = pos ? pos[1] : 0
|
|
17
|
-
const hMenu = gui.CreatePopupMenu()
|
|
18
|
-
if (hMenu) {
|
|
19
|
-
gui.AppendMenu(hMenu, 0, 1, '显示窗口')
|
|
20
|
-
gui.AppendMenu(hMenu, 0x0800, 0, '')
|
|
21
|
-
gui.AppendMenu(hMenu, 0, 2, '退出')
|
|
22
|
-
const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd)
|
|
23
|
-
gui.DestroyMenu(hMenu)
|
|
24
|
-
if (cmd === 1) {
|
|
25
|
-
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
26
|
-
} else if (cmd === 2) {
|
|
27
|
-
gui.ShellNotifyIcon(gui.NotifyIconCmd.DELETE, { hwnd, uID: 1 })
|
|
28
|
-
gui.PostQuitMessage(0)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return 0
|
|
33
|
-
}
|
|
34
|
-
if (msg === gui.WmMsg.CLOSE) {
|
|
35
|
-
gui.ShowWindow(hwnd, 0) // SW_HIDE
|
|
36
|
-
return 0
|
|
37
|
-
}
|
|
38
|
-
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
// 创建窗口
|
|
42
|
-
const W = 500, H = 400
|
|
43
|
-
const scr = gui.GetScreenSize()
|
|
44
|
-
const x = (scr[0] - W) >> 1
|
|
45
|
-
const y = (scr[1] - H) >> 1
|
|
46
|
-
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', gui.WindowStyle.OVERLAPPEDWINDOW, x, y, W, H, null, null)
|
|
47
|
-
if (!hwnd) std.exit(0)
|
|
48
|
-
gui.ShowWindow(hwnd)
|
|
49
|
-
|
|
50
|
-
// 添加说明文字
|
|
51
|
-
const ES_MULTILINE = 0x0004
|
|
52
|
-
const ES_READONLY = 0x0800
|
|
53
|
-
const style = gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE | ES_MULTILINE | ES_READONLY
|
|
54
|
-
const text = gui.CreateWindow('EDIT',
|
|
55
|
-
'QuickWin 系统托盘示例\r\n'
|
|
56
|
-
+ '\r\n'
|
|
57
|
-
+ '右键点击托盘图标打开上下文菜单。\r\n'
|
|
58
|
-
+ '关闭此窗口将隐藏到托盘。\r\n'
|
|
59
|
-
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。',
|
|
60
|
-
style, 15, 15, W - 30, H - 70, hwnd, null)
|
|
61
|
-
if (text) {
|
|
62
|
-
const font = gui.CreateSystemDpiFont()
|
|
63
|
-
if (font)
|
|
64
|
-
gui.SendMessage(text, gui.WmMsg.SETFONT, font, 1)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let hIcon = gui.LoadAppIcon()
|
|
68
|
-
if (!hIcon) hIcon = gui.LoadImage(null, gui.IDI.APPLICATION, gui.ImageType.ICON, 0, 0, gui.LoadImageFlag.SHARED)
|
|
69
|
-
if (hIcon) {
|
|
70
|
-
const ok = gui.ShellNotifyIcon(gui.NotifyIconCmd.ADD, {
|
|
71
|
-
hwnd: hwnd, uID: 1,
|
|
72
|
-
flags: gui.NotifyIconFlag.MESSAGE | gui.NotifyIconFlag.ICON,
|
|
73
|
-
callbackMessage: WM_TRAY,
|
|
74
|
-
hIcon,
|
|
75
|
-
})
|
|
76
|
-
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED')
|
|
77
|
-
std.out.flush()
|
|
78
|
-
} else {
|
|
79
|
-
std.out.printf('failed to load icon\n')
|
|
80
|
-
std.out.flush()
|
|
81
|
-
}
|
|
1
|
+
import * as gui from 'gui'
|
|
2
|
+
import * as std from 'std'
|
|
3
|
+
|
|
4
|
+
const WM_TRAY = 0x8001
|
|
5
|
+
|
|
6
|
+
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
7
|
+
if (msg === WM_TRAY) {
|
|
8
|
+
const evt = lParam
|
|
9
|
+
if (evt === 0x0201) { // WM_LBUTTONDOWN
|
|
10
|
+
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
11
|
+
gui.SetForegroundWindow(hwnd)
|
|
12
|
+
} else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
|
|
13
|
+
gui.SetForegroundWindow(hwnd)
|
|
14
|
+
const pos = gui.GetCursorPos()
|
|
15
|
+
const x = pos ? pos[0] : 0
|
|
16
|
+
const y = pos ? pos[1] : 0
|
|
17
|
+
const hMenu = gui.CreatePopupMenu()
|
|
18
|
+
if (hMenu) {
|
|
19
|
+
gui.AppendMenu(hMenu, 0, 1, '显示窗口')
|
|
20
|
+
gui.AppendMenu(hMenu, 0x0800, 0, '')
|
|
21
|
+
gui.AppendMenu(hMenu, 0, 2, '退出')
|
|
22
|
+
const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd)
|
|
23
|
+
gui.DestroyMenu(hMenu)
|
|
24
|
+
if (cmd === 1) {
|
|
25
|
+
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
26
|
+
} else if (cmd === 2) {
|
|
27
|
+
gui.ShellNotifyIcon(gui.NotifyIconCmd.DELETE, { hwnd, uID: 1 })
|
|
28
|
+
gui.PostQuitMessage(0)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 0
|
|
33
|
+
}
|
|
34
|
+
if (msg === gui.WmMsg.CLOSE) {
|
|
35
|
+
gui.ShowWindow(hwnd, 0) // SW_HIDE
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// 创建窗口
|
|
42
|
+
const W = 500, H = 400
|
|
43
|
+
const scr = gui.GetScreenSize()
|
|
44
|
+
const x = (scr[0] - W) >> 1
|
|
45
|
+
const y = (scr[1] - H) >> 1
|
|
46
|
+
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', gui.WindowStyle.OVERLAPPEDWINDOW, x, y, W, H, null, null)
|
|
47
|
+
if (!hwnd) std.exit(0)
|
|
48
|
+
gui.ShowWindow(hwnd)
|
|
49
|
+
|
|
50
|
+
// 添加说明文字
|
|
51
|
+
const ES_MULTILINE = 0x0004
|
|
52
|
+
const ES_READONLY = 0x0800
|
|
53
|
+
const style = gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE | ES_MULTILINE | ES_READONLY
|
|
54
|
+
const text = gui.CreateWindow('EDIT',
|
|
55
|
+
'QuickWin 系统托盘示例\r\n'
|
|
56
|
+
+ '\r\n'
|
|
57
|
+
+ '右键点击托盘图标打开上下文菜单。\r\n'
|
|
58
|
+
+ '关闭此窗口将隐藏到托盘。\r\n'
|
|
59
|
+
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。',
|
|
60
|
+
style, 15, 15, W - 30, H - 70, hwnd, null)
|
|
61
|
+
if (text) {
|
|
62
|
+
const font = gui.CreateSystemDpiFont()
|
|
63
|
+
if (font)
|
|
64
|
+
gui.SendMessage(text, gui.WmMsg.SETFONT, font, 1)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let hIcon = gui.LoadAppIcon()
|
|
68
|
+
if (!hIcon) hIcon = gui.LoadImage(null, gui.IDI.APPLICATION, gui.ImageType.ICON, 0, 0, gui.LoadImageFlag.SHARED)
|
|
69
|
+
if (hIcon) {
|
|
70
|
+
const ok = gui.ShellNotifyIcon(gui.NotifyIconCmd.ADD, {
|
|
71
|
+
hwnd: hwnd, uID: 1,
|
|
72
|
+
flags: gui.NotifyIconFlag.MESSAGE | gui.NotifyIconFlag.ICON,
|
|
73
|
+
callbackMessage: WM_TRAY,
|
|
74
|
+
hIcon,
|
|
75
|
+
})
|
|
76
|
+
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED')
|
|
77
|
+
std.out.flush()
|
|
78
|
+
} else {
|
|
79
|
+
std.out.printf('failed to load icon\n')
|
|
80
|
+
std.out.flush()
|
|
81
|
+
}
|