quickwin 1.2.1 → 1.3.0
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 +2 -1
- package/README.md +2 -1
- package/examples/PdfCanvas.js +3 -3
- package/examples/PdfCanvas.tsx +3 -3
- package/examples/pdf_preview2.js +34 -19
- package/examples/pdf_preview2.ts +34 -20
- package/examples/pdf_viewer.js +959 -219
- package/examples/pdf_viewer.tsx +29 -19
- package/examples/test_gallery.js +925 -198
- package/examples/test_react_lazy.js +908 -181
- package/examples/test_react_listbox.js +908 -181
- package/examples/test_root_window.js +908 -181
- package/examples/test_tab.js +908 -181
- package/lib/ffi-bind.js +85 -0
- package/lib/ffi-bind.ts +170 -0
- package/lib/ffi-struct.js +224 -0
- package/lib/ffi-struct.ts +239 -0
- package/lib/react-qw/components/DateTimePicker.js +21 -15
- package/lib/react-qw/components/Link.js +4 -6
- package/lib/react-qw/components/ListView.js +84 -40
- package/lib/react-qw/components/PathPicker.js +40 -24
- package/lib/react-qw/components/Tab.js +21 -10
- package/lib/react-qw/components/Tooltip.js +27 -15
- package/lib/react-qw/components/TreeView.js +23 -33
- package/lib/react-qw/nmhdr.js +26 -0
- package/lib/react-qw/nmhdr.ts +32 -0
- package/lib/text-measure.js +14 -26
- package/lib/text-measure.ts +14 -26
- package/lib/win-common-structs.js +39 -0
- package/lib/win-common-structs.ts +41 -0
- package/package.json +1 -1
- package/quickwin.d.ts +6 -2
- 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.js +2 -0
- package/test/run.ts +2 -0
- package/test/test_ffi.js +12 -8
- package/test/test_ffi.ts +12 -12
- package/test/test_ffi_bind.js +42 -0
- package/test/test_ffi_bind.ts +46 -0
- package/test/test_ffi_struct.js +201 -0
- package/test/test_ffi_struct.ts +223 -0
- package/test/test_react_complex.js +911 -184
- package/test/test_react_counter.js +908 -181
- package/test/test_react_flex.js +908 -181
- package/test/test_react_hidden.js +910 -183
- package/test/test_react_listview_link.js +908 -181
- package/test/test_react_render.js +908 -181
package/README.en.md
CHANGED
|
@@ -13,10 +13,11 @@ Install:
|
|
|
13
13
|
```bash
|
|
14
14
|
# Option 1: npm local install (recommended)
|
|
15
15
|
npm install quickwin
|
|
16
|
-
npx quickwin script.js
|
|
16
|
+
npx quickwin node_modules/quickwin/main.js # bundled main.js demo; use npx quickwin script.js for your own scripts
|
|
17
17
|
|
|
18
18
|
# Option 2: download directly from GitHub Release
|
|
19
19
|
iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
|
|
20
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
|
|
20
21
|
.\qwin.exe main.js
|
|
21
22
|
```
|
|
22
23
|
|
package/README.md
CHANGED
|
@@ -13,10 +13,11 @@ Windows 平台上的 QuickJS 运行时,支持原生 GUI、网络、WASM、FFI
|
|
|
13
13
|
```bash
|
|
14
14
|
# 方式一:npm 本地安装(推荐)
|
|
15
15
|
npm install quickwin
|
|
16
|
-
npx quickwin script.js
|
|
16
|
+
npx quickwin node_modules/quickwin/main.js # 包自带 main.js 示例;用 npx quickwin script.js 运行你自己的脚本
|
|
17
17
|
|
|
18
18
|
# 方式二:直接从 GitHub Release 下载
|
|
19
19
|
iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
|
|
20
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
|
|
20
21
|
.\qwin.exe main.js
|
|
21
22
|
```
|
|
22
23
|
|
package/examples/PdfCanvas.js
CHANGED
|
@@ -46,11 +46,11 @@ export const PdfCanvas = forwardRef(({ pixmap, style }, ref) => {
|
|
|
46
46
|
const pm = pixmapRef.current;
|
|
47
47
|
if (!pm)
|
|
48
48
|
return 0;
|
|
49
|
-
const hdc = ffi.ffiCall(GetDC_, [ffi.
|
|
49
|
+
const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
|
|
50
50
|
if (hdc) {
|
|
51
51
|
const bmi = makeBitmapInfo(pm.w, pm.h);
|
|
52
52
|
ffi.ffiCall(SetDIBitsToDevice_, [
|
|
53
|
-
ffi.
|
|
53
|
+
ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
54
54
|
FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
55
55
|
FFI_PTR, FFI_PTR, FFI_U32
|
|
56
56
|
], [
|
|
@@ -58,7 +58,7 @@ export const PdfCanvas = forwardRef(({ pixmap, style }, ref) => {
|
|
|
58
58
|
0, 0, 0, pm.h,
|
|
59
59
|
pm.data, bmi, 0
|
|
60
60
|
], FFI_S32);
|
|
61
|
-
ffi.ffiCall(ReleaseDC_, [ffi.
|
|
61
|
+
ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
|
|
62
62
|
}
|
|
63
63
|
return 0;
|
|
64
64
|
}
|
package/examples/PdfCanvas.tsx
CHANGED
|
@@ -59,11 +59,11 @@ export const PdfCanvas = forwardRef<gui.HWND, PdfCanvasProps>(
|
|
|
59
59
|
if (e.msg === gui.WmMsg.PAINT) {
|
|
60
60
|
const pm = pixmapRef.current
|
|
61
61
|
if (!pm) return 0
|
|
62
|
-
const hdc = ffi.ffiCall(GetDC_, [ffi.
|
|
62
|
+
const hdc = ffi.ffiCall(GetDC_, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
|
|
63
63
|
if (hdc) {
|
|
64
64
|
const bmi = makeBitmapInfo(pm.w, pm.h)
|
|
65
65
|
ffi.ffiCall(SetDIBitsToDevice_, [
|
|
66
|
-
ffi.
|
|
66
|
+
ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
67
67
|
FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
68
68
|
FFI_PTR, FFI_PTR, FFI_U32
|
|
69
69
|
], [
|
|
@@ -71,7 +71,7 @@ export const PdfCanvas = forwardRef<gui.HWND, PdfCanvasProps>(
|
|
|
71
71
|
0, 0, 0, pm.h,
|
|
72
72
|
pm.data, bmi, 0
|
|
73
73
|
], FFI_S32)
|
|
74
|
-
ffi.ffiCall(ReleaseDC_, [ffi.
|
|
74
|
+
ffi.ffiCall(ReleaseDC_, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
|
|
75
75
|
}
|
|
76
76
|
return 0
|
|
77
77
|
}
|
package/examples/pdf_preview2.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as gui from 'gui';
|
|
|
4
4
|
import * as win from 'win';
|
|
5
5
|
import * as ffi from 'ffi';
|
|
6
6
|
import { assertNonNullable } from '../lib/assert.js';
|
|
7
|
+
import { OPENFILENAMEW } from '../lib/win-common-structs.js';
|
|
7
8
|
const FFI_PTR = ffi.FFI_TYPE_POINTER;
|
|
8
9
|
const FFI_U32 = ffi.FFI_TYPE_UINT32;
|
|
9
10
|
const FFI_S32 = ffi.FFI_TYPE_SINT32;
|
|
@@ -50,10 +51,6 @@ function wideToStr(buf) {
|
|
|
50
51
|
}
|
|
51
52
|
return String.fromCharCode(...chars);
|
|
52
53
|
}
|
|
53
|
-
function setPtr(dv, off, ptr) {
|
|
54
|
-
dv.setUint32(off, ptr & 0xFFFFFFFF, true);
|
|
55
|
-
dv.setUint32(off + 4, Math.floor(ptr / 0x100000000), true);
|
|
56
|
-
}
|
|
57
54
|
let hwndMain = null;
|
|
58
55
|
let hwndEdit = null;
|
|
59
56
|
let hwndCanvas = null;
|
|
@@ -172,17 +169,35 @@ function renderPdfPage(mupdf, filePath, pageIndex) {
|
|
|
172
169
|
}
|
|
173
170
|
function openPdfFileDialog() {
|
|
174
171
|
assertNonNullable(hwndMain);
|
|
175
|
-
const structBuf = new ArrayBuffer(152), sv = new DataView(structBuf);
|
|
176
172
|
const fileBuf = new ArrayBuffer(260 * 2);
|
|
177
173
|
const filterWide = strToWide('PDF Files\0*.pdf\0All Files\0*.*\0\0');
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
174
|
+
const ofn = OPENFILENAMEW.write({
|
|
175
|
+
lStructSize: OPENFILENAMEW.size,
|
|
176
|
+
hwndOwner: hwndMain,
|
|
177
|
+
hInstance: 0,
|
|
178
|
+
lpstrFilter: ffi.bufferPtr(filterWide),
|
|
179
|
+
lpstrCustomFilter: 0,
|
|
180
|
+
nMaxCustFilter: 0,
|
|
181
|
+
nFilterIndex: 0,
|
|
182
|
+
lpstrFile: ffi.bufferPtr(fileBuf),
|
|
183
|
+
nMaxFile: 260,
|
|
184
|
+
lpstrFileTitle: 0,
|
|
185
|
+
nMaxFileTitle: 0,
|
|
186
|
+
lpstrInitialDir: 0,
|
|
187
|
+
lpstrTitle: 0,
|
|
188
|
+
Flags: 0x1000 | 0x0800 | 0x0004,
|
|
189
|
+
nFileOffset: 0,
|
|
190
|
+
nFileExtension: 0,
|
|
191
|
+
lpstrDefExt: 0,
|
|
192
|
+
lCustData: 0,
|
|
193
|
+
lpfnHook: 0,
|
|
194
|
+
lpTemplateName: 0,
|
|
195
|
+
pvReserved: 0,
|
|
196
|
+
dwReserved: 0,
|
|
197
|
+
FlagsEx: 0,
|
|
198
|
+
});
|
|
199
|
+
ofn.__keep = [fileBuf, filterWide];
|
|
200
|
+
const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [ofn], FFI_U32);
|
|
186
201
|
return ret ? wideToStr(fileBuf) : null;
|
|
187
202
|
}
|
|
188
203
|
function updateScrollRange() {
|
|
@@ -344,15 +359,15 @@ async function main() {
|
|
|
344
359
|
const pm = currentPixmap;
|
|
345
360
|
if (!pm)
|
|
346
361
|
return 0;
|
|
347
|
-
const hdc = ffi.ffiCall(GetDC, [ffi.
|
|
362
|
+
const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
|
|
348
363
|
if (hdc) {
|
|
349
364
|
const bmi = makeBitmapInfo(pm.w, pm.h);
|
|
350
365
|
ffi.ffiCall(SetDIBitsToDevice, [
|
|
351
|
-
ffi.
|
|
366
|
+
ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
352
367
|
FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
353
368
|
FFI_PTR, FFI_PTR, FFI_U32
|
|
354
369
|
], [hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0], FFI_S32);
|
|
355
|
-
ffi.ffiCall(ReleaseDC, [ffi.
|
|
370
|
+
ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
|
|
356
371
|
}
|
|
357
372
|
return 0;
|
|
358
373
|
}
|
|
@@ -366,10 +381,10 @@ async function main() {
|
|
|
366
381
|
const cr = gui.GetClientRect(hwnd);
|
|
367
382
|
if (cr) {
|
|
368
383
|
const cw = cr.right - cr.left, ch = cr.bottom - cr.top;
|
|
369
|
-
const hdc = ffi.ffiCall(GetDC, [ffi.
|
|
384
|
+
const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER);
|
|
370
385
|
if (hdc) {
|
|
371
|
-
ffi.ffiCall(PatBlt, [ffi.
|
|
372
|
-
ffi.ffiCall(ReleaseDC, [ffi.
|
|
386
|
+
ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32], [hdc, 0, 0, cw, ch, WHITENESS], FFI_U32);
|
|
387
|
+
ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32);
|
|
373
388
|
}
|
|
374
389
|
}
|
|
375
390
|
gui.DefWindowProc(hwnd, msg, wParam, lParam);
|
package/examples/pdf_preview2.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as win from 'win'
|
|
|
5
5
|
import * as ffi from 'ffi'
|
|
6
6
|
import type { Document, Page, Pixmap } from '../vendor/mupdf-wasm/mupdf.js'
|
|
7
7
|
import { assertNonNullable } from '../lib/assert.js'
|
|
8
|
+
import { OPENFILENAMEW } from '../lib/win-common-structs.js'
|
|
8
9
|
|
|
9
10
|
const FFI_PTR = ffi.FFI_TYPE_POINTER
|
|
10
11
|
const FFI_U32 = ffi.FFI_TYPE_UINT32
|
|
@@ -55,11 +56,6 @@ function wideToStr(buf: ArrayBuffer): string {
|
|
|
55
56
|
return String.fromCharCode(...chars)
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
function setPtr(dv: DataView, off: number, ptr: number): void {
|
|
59
|
-
dv.setUint32(off, ptr & 0xFFFFFFFF, true)
|
|
60
|
-
dv.setUint32(off + 4, Math.floor(ptr / 0x100000000), true)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
59
|
interface PixmapInfo {
|
|
64
60
|
data: ArrayBuffer; w: number; h: number
|
|
65
61
|
}
|
|
@@ -133,17 +129,35 @@ function renderPdfPage(mupdf: MuPdf, filePath: string, pageIndex: number): Pixma
|
|
|
133
129
|
|
|
134
130
|
function openPdfFileDialog(): string | null {
|
|
135
131
|
assertNonNullable(hwndMain)
|
|
136
|
-
const structBuf = new ArrayBuffer(152), sv = new DataView(structBuf)
|
|
137
132
|
const fileBuf = new ArrayBuffer(260 * 2)
|
|
138
133
|
const filterWide = strToWide('PDF Files\0*.pdf\0All Files\0*.*\0\0')
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
134
|
+
const ofn: ArrayBuffer & { __keep?: ArrayBuffer[] } = OPENFILENAMEW.write({
|
|
135
|
+
lStructSize: OPENFILENAMEW.size,
|
|
136
|
+
hwndOwner: hwndMain,
|
|
137
|
+
hInstance: 0,
|
|
138
|
+
lpstrFilter: ffi.bufferPtr(filterWide),
|
|
139
|
+
lpstrCustomFilter: 0,
|
|
140
|
+
nMaxCustFilter: 0,
|
|
141
|
+
nFilterIndex: 0,
|
|
142
|
+
lpstrFile: ffi.bufferPtr(fileBuf),
|
|
143
|
+
nMaxFile: 260,
|
|
144
|
+
lpstrFileTitle: 0,
|
|
145
|
+
nMaxFileTitle: 0,
|
|
146
|
+
lpstrInitialDir: 0,
|
|
147
|
+
lpstrTitle: 0,
|
|
148
|
+
Flags: 0x1000 | 0x0800 | 0x0004,
|
|
149
|
+
nFileOffset: 0,
|
|
150
|
+
nFileExtension: 0,
|
|
151
|
+
lpstrDefExt: 0,
|
|
152
|
+
lCustData: 0,
|
|
153
|
+
lpfnHook: 0,
|
|
154
|
+
lpTemplateName: 0,
|
|
155
|
+
pvReserved: 0,
|
|
156
|
+
dwReserved: 0,
|
|
157
|
+
FlagsEx: 0,
|
|
158
|
+
})
|
|
159
|
+
ofn.__keep = [fileBuf, filterWide]
|
|
160
|
+
const ret = ffi.ffiCall(GetOpenFileNameW, [FFI_PTR], [ofn], FFI_U32)
|
|
147
161
|
return ret ? wideToStr(fileBuf) : null
|
|
148
162
|
}
|
|
149
163
|
|
|
@@ -299,15 +313,15 @@ let hwndBtnNext: gui.HWND | null = null
|
|
|
299
313
|
gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
300
314
|
const pm = currentPixmap
|
|
301
315
|
if (!pm) return 0
|
|
302
|
-
const hdc = ffi.ffiCall(GetDC, [ffi.
|
|
316
|
+
const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
|
|
303
317
|
if (hdc) {
|
|
304
318
|
const bmi = makeBitmapInfo(pm.w, pm.h)
|
|
305
319
|
ffi.ffiCall(SetDIBitsToDevice, [
|
|
306
|
-
ffi.
|
|
320
|
+
ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
307
321
|
FFI_S32, FFI_S32, FFI_U32, FFI_U32,
|
|
308
322
|
FFI_PTR, FFI_PTR, FFI_U32
|
|
309
323
|
], [hdc, 0, 0, pm.w, pm.h, 0, 0, 0, pm.h, pm.data, bmi, 0], FFI_S32)
|
|
310
|
-
ffi.ffiCall(ReleaseDC, [ffi.
|
|
324
|
+
ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
|
|
311
325
|
}
|
|
312
326
|
return 0
|
|
313
327
|
}
|
|
@@ -321,11 +335,11 @@ let hwndBtnNext: gui.HWND | null = null
|
|
|
321
335
|
const cr = gui.GetClientRect(hwnd)
|
|
322
336
|
if (cr) {
|
|
323
337
|
const cw = cr.right - cr.left, ch = cr.bottom - cr.top
|
|
324
|
-
const hdc = ffi.ffiCall(GetDC, [ffi.
|
|
338
|
+
const hdc = ffi.ffiCall(GetDC, [ffi.FFI_TYPE_POINTER], [hwnd], ffi.FFI_TYPE_POINTER)
|
|
325
339
|
if (hdc) {
|
|
326
|
-
ffi.ffiCall(PatBlt, [ffi.
|
|
340
|
+
ffi.ffiCall(PatBlt, [ffi.FFI_TYPE_POINTER, FFI_S32, FFI_S32, FFI_S32, FFI_S32, FFI_U32],
|
|
327
341
|
[hdc, 0, 0, cw, ch, WHITENESS], FFI_U32)
|
|
328
|
-
ffi.ffiCall(ReleaseDC, [ffi.
|
|
342
|
+
ffi.ffiCall(ReleaseDC, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_POINTER], [hwnd, hdc], FFI_S32)
|
|
329
343
|
}
|
|
330
344
|
}
|
|
331
345
|
gui.DefWindowProc(hwnd, msg, wParam, lParam)
|