quickwin 2.3.1 → 3.0.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.
Files changed (172) hide show
  1. package/README.en.md +1 -2
  2. package/README.md +1 -2
  3. package/constants.ts +15 -0
  4. package/enum_map.d.ts +3 -0
  5. package/examples/PdfCanvas.js +1 -1
  6. package/examples/PdfCanvas.tsx +2 -2
  7. package/examples/execd/main.js +334 -188
  8. package/examples/pdf_preview2.js +76 -67
  9. package/examples/pdf_preview2.ts +84 -64
  10. package/examples/pdf_viewer.js +4932 -1029
  11. package/examples/pdf_viewer.tsx +11 -22
  12. package/examples/test_gallery.js +308 -143
  13. package/examples/test_gallery.tsx +12 -7
  14. package/examples/test_react_lazy.js +295 -133
  15. package/examples/test_react_lazy.tsx +4 -3
  16. package/examples/test_react_listbox.js +293 -132
  17. package/examples/test_react_listbox.tsx +3 -2
  18. package/examples/test_root_window.js +283 -126
  19. package/examples/test_tab.js +295 -133
  20. package/examples/test_tab.tsx +4 -3
  21. package/examples/tray_demo.js +37 -30
  22. package/examples/tray_demo.tsx +39 -32
  23. package/lib/abort.d.ts +21 -0
  24. package/lib/assert.d.ts +2 -0
  25. package/lib/bitmap.d.ts +7 -0
  26. package/lib/bitmap.js +40 -0
  27. package/lib/cache-utils.d.ts +6 -0
  28. package/lib/certs.d.ts +1 -0
  29. package/lib/certs.js +31 -3
  30. package/lib/dpi.d.ts +9 -0
  31. package/lib/dpi.js +30 -0
  32. package/lib/dumpRects.d.ts +2 -0
  33. package/lib/dumpRects.js +14 -7
  34. package/lib/exec-log.d.ts +23 -0
  35. package/lib/fetch.d.ts +4 -0
  36. package/lib/ffi/bind.d.ts +70 -0
  37. package/lib/ffi/bind.js +5 -4
  38. package/lib/ffi/ctype.d.ts +117 -0
  39. package/lib/ffi/index.d.ts +2 -0
  40. package/lib/ffi/struct.d.ts +174 -0
  41. package/lib/http-common.d.ts +143 -0
  42. package/lib/http-server.d.ts +59 -0
  43. package/lib/polyfill.d.ts +22 -0
  44. package/lib/react-qw/components/Button.d.ts +9 -0
  45. package/lib/react-qw/components/CheckBox.d.ts +11 -0
  46. package/lib/react-qw/components/ComboBox.d.ts +11 -0
  47. package/lib/react-qw/components/DateTimePicker.d.ts +15 -0
  48. package/lib/react-qw/components/DateTimePicker.js +6 -7
  49. package/lib/react-qw/components/Input.d.ts +15 -0
  50. package/lib/react-qw/components/Input.js +5 -1
  51. package/lib/react-qw/components/Link.d.ts +12 -0
  52. package/lib/react-qw/components/ListBox.d.ts +13 -0
  53. package/lib/react-qw/components/ListView.d.ts +37 -0
  54. package/lib/react-qw/components/ListView.js +8 -6
  55. package/lib/react-qw/components/PathPicker.d.ts +23 -0
  56. package/lib/react-qw/components/ProgressBar.d.ts +9 -0
  57. package/lib/react-qw/components/RadioButton.d.ts +11 -0
  58. package/lib/react-qw/components/ScrollView.d.ts +9 -0
  59. package/lib/react-qw/components/ScrollView.js +28 -22
  60. package/lib/react-qw/components/Slider.d.ts +12 -0
  61. package/lib/react-qw/components/Tab.d.ts +14 -0
  62. package/lib/react-qw/components/Tooltip.d.ts +7 -0
  63. package/lib/react-qw/components/TreeView.d.ts +18 -0
  64. package/lib/react-qw/components/index.d.ts +16 -0
  65. package/lib/react-qw/index.d.ts +24 -0
  66. package/lib/react-qw/index.js +7 -5
  67. package/lib/react-qw/layout.d.ts +29 -0
  68. package/lib/react-qw/nmhdr.d.ts +1 -0
  69. package/lib/react-qw/props.d.ts +2 -0
  70. package/lib/react-qw/props.js +3 -3
  71. package/lib/react-qw/reconciler.d.ts +21 -0
  72. package/lib/react-qw/reconciler.js +12 -17
  73. package/lib/stream.d.ts +20 -0
  74. package/lib/text-codec.d.ts +39 -0
  75. package/lib/text-measure.d.ts +14 -0
  76. package/lib/text-measure.js +9 -6
  77. package/lib/url.d.ts +54 -0
  78. package/lib/websocket.d.ts +73 -0
  79. package/lib/windows/{advapi32.ts → advapi32.d.ts} +6 -21
  80. package/lib/windows/comctl32.d.ts +14 -0
  81. package/lib/windows/comctl32.js +3 -2
  82. package/lib/windows/comdlg32.d.ts +4 -0
  83. package/lib/windows/{gdi32.ts → gdi32.d.ts} +184 -97
  84. package/lib/windows/gdi32.js +28 -6
  85. package/lib/windows/{kernel32.ts → kernel32.d.ts} +145 -113
  86. package/lib/windows/kernel32.js +9 -0
  87. package/lib/windows/{msimg32.ts → msimg32.d.ts} +11 -14
  88. package/lib/windows/ntdll.d.ts +5 -0
  89. package/lib/windows/ole32.d.ts +3 -0
  90. package/lib/windows/{psapi.ts → psapi.d.ts} +9 -18
  91. package/lib/windows/shell32.d.ts +51 -0
  92. package/lib/windows/shell32.js +11 -2
  93. package/lib/windows/structs.d.ts +3141 -0
  94. package/lib/windows/structs.js +51 -0
  95. package/lib/windows/user32.d.ts +623 -0
  96. package/lib/windows/user32.js +6 -5
  97. package/lib/windows/version.d.ts +27 -0
  98. package/lib/windows/{winspool.ts → winspool.d.ts} +18 -32
  99. package/main.js +13 -5
  100. package/package.json +16 -7
  101. package/quickwin.d.ts +13 -115
  102. package/qwin-nowasm-x86.exe +0 -0
  103. package/qwin-nowasm.exe +0 -0
  104. package/qwin-x86.exe +0 -0
  105. package/qwin.exe +0 -0
  106. package/test/bench_ffi_callraw.js +3 -4
  107. package/test/bench_ffi_callraw.ts +3 -4
  108. package/test/debug/mupdf_debug.js +4 -22
  109. package/test/debug/wasm_export_debug.js +2 -12
  110. package/test/debug/wasm_names.js +3 -13
  111. package/test/example.pdf +0 -0
  112. package/test/mupdf-cdn.js +40 -0
  113. package/test/mupdf-cdn.ts +43 -0
  114. package/test/test_ffi.js +8 -9
  115. package/test/test_ffi.ts +8 -9
  116. package/test/test_ffi_abi.js +6 -6
  117. package/test/test_ffi_abi.ts +8 -8
  118. package/test/test_ffi_windows.js +82 -11
  119. package/test/test_ffi_windows.ts +85 -11
  120. package/test/test_gdi_draw.js +3 -3
  121. package/test/test_gdi_draw.ts +4 -4
  122. package/test/test_mupdf_render.js +4 -22
  123. package/test/test_mupdf_render.ts +4 -23
  124. package/test/test_mupdf_twice.js +4 -19
  125. package/test/test_mupdf_twice.ts +4 -20
  126. package/test/test_mupdf_wasm.js +10 -4
  127. package/test/test_mupdf_wasm.ts +6 -4
  128. package/test/test_react_complex.js +316 -140
  129. package/test/test_react_counter.js +295 -133
  130. package/test/test_react_flex.js +297 -138
  131. package/test/test_react_hidden.js +296 -134
  132. package/test/test_react_listview_link.js +288 -131
  133. package/test/test_react_notify.js +290 -133
  134. package/test/test_react_render.js +295 -133
  135. package/lib/abort.ts +0 -69
  136. package/lib/assert.ts +0 -7
  137. package/lib/cache-utils.ts +0 -40
  138. package/lib/certs.ts +0 -229
  139. package/lib/dumpRects.ts +0 -26
  140. package/lib/exec-log.ts +0 -30
  141. package/lib/fetch.ts +0 -589
  142. package/lib/ffi/bind.ts +0 -539
  143. package/lib/ffi/ctype.ts +0 -371
  144. package/lib/ffi/index.ts +0 -6
  145. package/lib/ffi/struct.ts +0 -780
  146. package/lib/http-common.ts +0 -441
  147. package/lib/http-server.ts +0 -604
  148. package/lib/polyfill.ts +0 -171
  149. package/lib/react-qw/components/index.ts +0 -17
  150. package/lib/react-qw/index.ts +0 -96
  151. package/lib/react-qw/layout.ts +0 -111
  152. package/lib/react-qw/nmhdr.ts +0 -7
  153. package/lib/react-qw/props.ts +0 -41
  154. package/lib/react-qw/reconciler.ts +0 -383
  155. package/lib/stream.ts +0 -22
  156. package/lib/text-codec.ts +0 -171
  157. package/lib/text-measure.ts +0 -41
  158. package/lib/url.ts +0 -201
  159. package/lib/websocket.ts +0 -600
  160. package/lib/windows/comctl32.ts +0 -19
  161. package/lib/windows/comdlg32.ts +0 -10
  162. package/lib/windows/ntdll.ts +0 -11
  163. package/lib/windows/ole32.ts +0 -9
  164. package/lib/windows/shell32.ts +0 -39
  165. package/lib/windows/structs.ts +0 -752
  166. package/lib/windows/user32.ts +0 -619
  167. package/lib/windows/version.ts +0 -35
  168. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +0 -571
  169. package/vendor/mupdf-wasm/mupdf-wasm.js +0 -2749
  170. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  171. package/vendor/mupdf-wasm/mupdf.d.ts +0 -939
  172. package/vendor/mupdf-wasm/mupdf.js +0 -3317
@@ -0,0 +1,13 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface ListBoxProps {
4
+ items: string[];
5
+ selectedIndex?: number;
6
+ defaultSelectedIndex?: number;
7
+ onChange?: (index: number) => void;
8
+ style?: WStyle;
9
+ disabled?: boolean;
10
+ sort?: boolean;
11
+ scrollToBottom?: boolean;
12
+ }
13
+ export declare const ListBox: import("react").ForwardRefExoticComponent<ListBoxProps & import("react").RefAttributes<gui.HWND>>;
@@ -0,0 +1,37 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ import { StandardCursor } from '../../../constants';
4
+ export declare function makeColorBlock(size: number, bgra: number): ArrayBuffer;
5
+ export type Align = 'left' | 'center' | 'right';
6
+ export interface CellStyle {
7
+ color?: number;
8
+ background?: number;
9
+ bold?: boolean;
10
+ underline?: boolean;
11
+ italic?: boolean;
12
+ cursor?: StandardCursor;
13
+ }
14
+ export interface Column<D> {
15
+ name: string;
16
+ dataIndex?: keyof D;
17
+ width?: number;
18
+ align?: Align;
19
+ render?: (record: D, index: number) => string;
20
+ cellStyle?: CellStyle | ((record: D, index: number) => CellStyle);
21
+ onCellClick?: (record: D, index: number) => void;
22
+ }
23
+ export interface ListViewProps<D extends object> {
24
+ columns: Column<D>[];
25
+ data: D[];
26
+ style?: WStyle;
27
+ /** 图标像素数据数组,每个元素为 iconSize*iconSize*4 的 BGRA 像素 ArrayBuffer(色块/程序生成) */
28
+ icons?: ArrayBuffer[];
29
+ /** 图标尺寸,默认 32 */
30
+ iconSize?: number;
31
+ /** 返回记录使用的图标在 icons 中的下标 */
32
+ getIcon?: (record: D, index: number) => number;
33
+ }
34
+ declare const ListView: <D extends object>(props: ListViewProps<D> & {
35
+ ref?: React.Ref<gui.HWND>;
36
+ }) => React.ReactElement;
37
+ export { ListView };
@@ -7,6 +7,8 @@ import { WCHAR } from '../../ffi/bind.js';
7
7
  import { nmCode } from '../nmhdr.js';
8
8
  import { LoadCursor, SetCursor, ScreenToClient, GetCursorPos } from '../../windows/user32.js';
9
9
  import { CreateFontIndirect, DeleteObject, GetObject, SelectObject } from '../../windows/gdi32.js';
10
+ import { createBitmapFromPixels } from '../../bitmap.js';
11
+ import { ImageListCreate, ImageListAdd, ImageListDestroy } from '../../windows/comctl32.js';
10
12
  import { LOGFONTW, POINT, NMCUSTOMDRAW, NMLVCUSTOMDRAW, NMLISTVIEW, LVHITTESTINFO, LVITEMW, LVCOLUMNW, } from '../../windows/structs.js';
11
13
  export function makeColorBlock(size, bgra) {
12
14
  const n = size * size;
@@ -134,27 +136,27 @@ function makeLVItem(i, sub, text, image) {
134
136
  }
135
137
  const ListView = forwardRef(function ListViewInner({ columns, data, style, icons, iconSize, getIcon }, ref) {
136
138
  const lvRef = useRef(null);
137
- const iconListRef = useRef(0);
139
+ const iconListRef = useRef(NULL);
138
140
  useEffect(() => {
139
141
  const h = lvRef.current;
140
142
  if (!h)
141
143
  return;
142
144
  const il = iconListRef.current;
143
- iconListRef.current = 0;
145
+ iconListRef.current = NULL;
144
146
  if (il) {
145
147
  gui.SendMessage(h, 4099 /* LvMsg.SETIMAGELIST */, 1 /* LvImageList.SMALL */, 0);
146
- gui.ImageListDestroy(il);
148
+ ImageListDestroy(il);
147
149
  }
148
150
  if (!icons || icons.length === 0)
149
151
  return;
150
152
  const size = iconSize ?? 32;
151
- const img = gui.ImageListCreate(size, size, 32 /* ImageListFlag.COLOR32 */, icons.length, 1);
153
+ const img = ImageListCreate(size, size, 32 /* ImageListFlag.COLOR32 */, icons.length, 1);
152
154
  if (!img)
153
155
  return;
154
156
  for (const p of icons) {
155
- const hbm = gui.CreateBitmapFromPixels(size, size, p);
157
+ const hbm = createBitmapFromPixels(size, size, p);
156
158
  if (hbm) {
157
- gui.ImageListAdd(img, hbm);
159
+ ImageListAdd(img, hbm, NULL);
158
160
  DeleteObject(hbm);
159
161
  }
160
162
  }
@@ -0,0 +1,23 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ interface PathPickerBase {
4
+ type?: 'file' | 'folder';
5
+ filter?: string;
6
+ title?: string;
7
+ placeholder?: string;
8
+ disabled?: boolean;
9
+ style?: WStyle;
10
+ }
11
+ export type PathPickerProps = PathPickerBase & ({
12
+ multiple: true;
13
+ value?: string[];
14
+ defaultValue?: string[];
15
+ onChange?: (v: string[]) => void;
16
+ } | {
17
+ multiple?: false;
18
+ value?: string;
19
+ defaultValue?: string;
20
+ onChange?: (v: string) => void;
21
+ });
22
+ export declare const PathPicker: import("react").ForwardRefExoticComponent<PathPickerProps & import("react").RefAttributes<gui.HWND>>;
23
+ export {};
@@ -0,0 +1,9 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface ProgressBarProps {
4
+ value?: number;
5
+ max?: number;
6
+ style?: WStyle;
7
+ smooth?: boolean;
8
+ }
9
+ export declare const ProgressBar: import("react").ForwardRefExoticComponent<ProgressBarProps & import("react").RefAttributes<gui.HWND>>;
@@ -0,0 +1,11 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface RadioButtonProps {
4
+ checked?: boolean;
5
+ defaultChecked?: boolean;
6
+ onChange?: (checked: boolean) => void;
7
+ label?: string;
8
+ style?: WStyle;
9
+ disabled?: boolean;
10
+ }
11
+ export declare const RadioButton: import("react").ForwardRefExoticComponent<RadioButtonProps & import("react").RefAttributes<gui.HWND>>;
@@ -0,0 +1,9 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface ScrollViewProps {
4
+ children?: React.ReactNode;
5
+ style?: WStyle;
6
+ contentWidth?: number;
7
+ contentHeight?: number;
8
+ }
9
+ export declare const ScrollView: import("react").ForwardRefExoticComponent<ScrollViewProps & import("react").RefAttributes<gui.HWND>>;
@@ -1,10 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useLayoutEffect, useRef } from 'react';
3
- import * as gui from 'gui';
4
- import { DefWindowProc, SetWindowPos, ShowScrollBar, GetDC, ReleaseDC } from '../../windows/user32.js';
5
- import { NULL } from '../../ffi/ctype.js';
6
- import { GetDeviceCaps } from '../../windows/gdi32.js';
3
+ import { DefWindowProc, GetClientRect, GetScrollInfo, SetScrollInfo, SetWindowPos, ShowScrollBar } from '../../windows/user32.js';
4
+ import { RECT, SCROLLINFO } from '../../windows/structs.js';
7
5
  import { forceFlexLayout } from '../reconciler.js';
6
+ import { getScaleFactor } from '../../dpi.js';
8
7
  export const ScrollView = forwardRef(({ children, style, contentWidth, contentHeight }, ref) => {
9
8
  const svRef = useRef(null);
10
9
  const contentRef = useRef(null);
@@ -16,16 +15,13 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
16
15
  // page = viewportSize(可见行数)
17
16
  // nPos = 0 … max - page + 1(即 0 … contentSize - viewportSize)
18
17
  function updateScroll(sv, content) {
19
- const svRect = gui.GetClientRect(sv);
20
- if (!svRect)
18
+ const svBuf = RECT.alloc();
19
+ if (!GetClientRect(sv, svBuf.ptr))
21
20
  return;
22
- const svW = svRect.right - svRect.left;
23
- const svH = svRect.bottom - svRect.top;
24
- // GetScaleFactor 等价内联:GetDC → GetDeviceCaps(LOGPIXELSX=88) → ReleaseDC 配对
25
- const hdc = GetDC(NULL);
26
- const scale = hdc ? GetDeviceCaps(hdc, 88) / 96 : 1;
27
- if (hdc)
28
- ReleaseDC(NULL, hdc);
21
+ const { left, top, right, bottom } = RECT.decode(svBuf);
22
+ const svW = right - left;
23
+ const svH = bottom - top;
24
+ const scale = getScaleFactor();
29
25
  const natW = Math.round((contentWidth ?? (svW / scale)) * scale);
30
26
  const natH = Math.round((contentHeight ?? (svH / scale)) * scale);
31
27
  scrollXRef.current = Math.max(0, Math.min(scrollXRef.current, natW - svW));
@@ -33,7 +29,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
33
29
  SetWindowPos(content, 0 /* SetWindowPosHwnd.TOP */, -scrollXRef.current, -scrollYRef.current, natW, natH, 4 /* SetWindowPosFlag.SWP_NOZORDER */);
34
30
  forceFlexLayout(content);
35
31
  if (natW > svW) {
36
- gui.SetScrollInfo(sv, 0 /* ScrollBar.HORZ */, { min: 0, max: natW - 1, page: svW, pos: scrollXRef.current }, true);
32
+ SetScrollInfo(sv, 0 /* ScrollBar.HORZ */, {
33
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
34
+ nMin: 0, nMax: natW - 1, nPage: svW, nPos: scrollXRef.current,
35
+ }, 1);
37
36
  ShowScrollBar(sv, 0 /* ScrollBar.HORZ */, 1);
38
37
  }
39
38
  else {
@@ -41,7 +40,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
41
40
  ShowScrollBar(sv, 0 /* ScrollBar.HORZ */, 0);
42
41
  }
43
42
  if (natH > svH) {
44
- gui.SetScrollInfo(sv, 1 /* ScrollBar.VERT */, { min: 0, max: natH - 1, page: svH, pos: scrollYRef.current }, true);
43
+ SetScrollInfo(sv, 1 /* ScrollBar.VERT */, {
44
+ cbSize: SCROLLINFO.size, fMask: 1 /* ScrollInfoFlag.RANGE */ | 2 /* ScrollInfoFlag.PAGE */ | 4 /* ScrollInfoFlag.POS */,
45
+ nMin: 0, nMax: natH - 1, nPage: svH, nPos: scrollYRef.current,
46
+ }, 1);
45
47
  ShowScrollBar(sv, 1 /* ScrollBar.VERT */, 1);
46
48
  }
47
49
  else {
@@ -64,15 +66,17 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
64
66
  scrollXRef.current = newPos;
65
67
  }
66
68
  SetWindowPos(content, 0 /* SetWindowPosHwnd.TOP */, -scrollXRef.current, -scrollYRef.current, 0, 0, 1 /* SetWindowPosFlag.SWP_NOSIZE */ | 4 /* SetWindowPosFlag.SWP_NOZORDER */);
67
- gui.SetScrollInfo(sv, bar, { pos: newPos }, true);
69
+ SetScrollInfo(sv, bar, { cbSize: SCROLLINFO.size, fMask: 4 /* ScrollInfoFlag.POS */, nPos: newPos }, 1);
68
70
  }
69
71
  function handleScroll(e, bar) {
70
72
  const sv = svRef.current;
71
73
  const content = contentRef.current;
72
74
  if (!sv || !content)
73
75
  return;
74
- const info = gui.GetScrollInfo(sv, bar);
75
- const maxPos = info.max - info.page + 1;
76
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
77
+ GetScrollInfo(sv, bar, si.ptr);
78
+ const info = SCROLLINFO.decode(si);
79
+ const maxPos = info.nMax - info.nPage + 1;
76
80
  const code = e.wParam & 0xFFFF;
77
81
  const ref_ = bar === 1 /* ScrollBar.VERT */ ? scrollYRef : scrollXRef;
78
82
  let newPos = ref_.current;
@@ -84,9 +88,9 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
84
88
  else if (code === 1 /* ScrollCmd.LINEDOWN */)
85
89
  newPos += 20;
86
90
  else if (code === 2 /* ScrollCmd.PAGEUP */)
87
- newPos -= info.page;
91
+ newPos -= info.nPage;
88
92
  else if (code === 3 /* ScrollCmd.PAGEDOWN */)
89
- newPos += info.page;
93
+ newPos += info.nPage;
90
94
  else
91
95
  return;
92
96
  newPos = Math.max(0, Math.min(maxPos, newPos));
@@ -106,8 +110,10 @@ export const ScrollView = forwardRef(({ children, style, contentWidth, contentHe
106
110
  if (!isHorz && contentHeight === undefined)
107
111
  return;
108
112
  const bar = isHorz ? 0 /* ScrollBar.HORZ */ : 1 /* ScrollBar.VERT */;
109
- const info = gui.GetScrollInfo(sv, bar);
110
- const maxPos = info.max - info.page + 1;
113
+ const si = SCROLLINFO.encode({ cbSize: SCROLLINFO.size, fMask: 23 /* ScrollInfoFlag.ALL */ });
114
+ GetScrollInfo(sv, bar, si.ptr);
115
+ const info = SCROLLINFO.decode(si);
116
+ const maxPos = info.nMax - info.nPage + 1;
111
117
  const ref_ = isHorz ? scrollXRef : scrollYRef;
112
118
  let newPos = ref_.current + dy;
113
119
  newPos = Math.max(0, Math.min(maxPos, newPos));
@@ -0,0 +1,12 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface SliderProps {
4
+ value: number;
5
+ onChange?: (value: number) => void;
6
+ min?: number;
7
+ max?: number;
8
+ vertical?: boolean;
9
+ disabled?: boolean;
10
+ style?: WStyle;
11
+ }
12
+ export declare const Slider: import("react").ForwardRefExoticComponent<SliderProps & import("react").RefAttributes<gui.HWND>>;
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ import * as gui from 'gui';
3
+ import type { WStyle } from '../jsx.d.ts';
4
+ export interface TabProps {
5
+ tabs: {
6
+ title: string;
7
+ content: ReactNode;
8
+ }[];
9
+ selectedIndex?: number;
10
+ defaultSelectedIndex?: number;
11
+ onChange?: (index: number) => void;
12
+ style?: WStyle;
13
+ }
14
+ export declare const Tab: import("react").ForwardRefExoticComponent<TabProps & import("react").RefAttributes<gui.HWND>>;
@@ -0,0 +1,7 @@
1
+ export interface TooltipProps {
2
+ text: string;
3
+ children: React.ReactElement;
4
+ balloon?: boolean;
5
+ }
6
+ declare function Tooltip({ text, children, balloon }: TooltipProps): import("react").ReactElement<Record<string, unknown>, string | import("react").JSXElementConstructor<any>>;
7
+ export { Tooltip };
@@ -0,0 +1,18 @@
1
+ import * as gui from 'gui';
2
+ import type { WStyle } from '../jsx.d.ts';
3
+ export interface TreeNode<D = unknown> {
4
+ key?: string;
5
+ label: string;
6
+ children?: TreeNode<D>[];
7
+ }
8
+ export interface TreeViewProps<D> {
9
+ data: TreeNode<D>[];
10
+ onSelect?: (node: TreeNode<D> | null) => void;
11
+ defaultSelectedKey?: string;
12
+ selectedKey?: string;
13
+ style?: WStyle;
14
+ }
15
+ declare const TreeView: <D = unknown>(props: TreeViewProps<D> & {
16
+ ref?: React.Ref<gui.HWND>;
17
+ }) => React.ReactElement;
18
+ export { TreeView };
@@ -0,0 +1,16 @@
1
+ export { Button, type ButtonProps } from './Button.js';
2
+ export { CheckBox, type CheckBoxProps } from './CheckBox.js';
3
+ export { ComboBox, type ComboBoxProps } from './ComboBox.js';
4
+ export { DateTimePicker, type DateTimePickerProps } from './DateTimePicker.js';
5
+ export { Input, type InputProps } from './Input.js';
6
+ export { Link, type LinkProps } from './Link.js';
7
+ export { ListBox, type ListBoxProps } from './ListBox.js';
8
+ export { ListView, makeColorBlock, type ListViewProps, type Column, type CellStyle, type Align } from './ListView.js';
9
+ export { ProgressBar, type ProgressBarProps } from './ProgressBar.js';
10
+ export { RadioButton, type RadioButtonProps } from './RadioButton.js';
11
+ export { ScrollView, type ScrollViewProps } from './ScrollView.js';
12
+ export { Slider, type SliderProps } from './Slider.js';
13
+ export { Tab, type TabProps } from './Tab.js';
14
+ export { Tooltip, type TooltipProps } from './Tooltip.js';
15
+ export { TreeView, type TreeViewProps, type TreeNode } from './TreeView.js';
16
+ export { PathPicker, type PathPickerProps } from './PathPicker.js';
@@ -0,0 +1,24 @@
1
+ import * as gui from 'gui';
2
+ import React from 'react';
3
+ export interface RootWindowConfig {
4
+ text?: string;
5
+ ws?: number;
6
+ x?: number;
7
+ y?: number;
8
+ width?: number;
9
+ height?: number;
10
+ noShowWindow?: boolean;
11
+ onEvent?: (e: {
12
+ hwnd: gui.HWND;
13
+ msg: number;
14
+ wParam: number;
15
+ lParam: number;
16
+ }) => number | void;
17
+ }
18
+ export declare function createRoot(container: gui.HWND | RootWindowConfig): {
19
+ hwnd: gui.HWND;
20
+ render(element: React.ReactNode): void;
21
+ unmount(): void;
22
+ };
23
+ export * from './components/index.js';
24
+ export declare function render(element: React.ReactNode, containerOrConfig?: gui.HWND | RootWindowConfig | null, _callback?: () => void): void;
@@ -1,5 +1,5 @@
1
1
  import * as gui from 'gui';
2
- import { DefWindowProc, GetSystemMetrics } from '../windows/user32.js';
2
+ import { DefWindowProc, GetSystemMetrics, ShowWindow, UpdateWindow } from '../windows/user32.js';
3
3
  import reconciler, { scaleFactor, instancesByHwnd, forceFlexLayout } from './reconciler.js';
4
4
  const noop = () => { };
5
5
  let defaultClassRegistered = false;
@@ -34,8 +34,7 @@ export function createRoot(container) {
34
34
  const ws = (cfg.ws ?? 0) | 13565952 /* WindowStyle.OVERLAPPEDWINDOW */;
35
35
  const w = (cfg.width ?? 800) * scaleFactor;
36
36
  const h = (cfg.height ?? 600) * scaleFactor;
37
- // GetScreenSize 等价内联:SM_CXSCREEN=0 / SM_CYSCREEN=1
38
- const [sw, sh] = [GetSystemMetrics(0), GetSystemMetrics(1)];
37
+ const [sw, sh] = [GetSystemMetrics(0 /* SysMetrics.CXSCREEN */), GetSystemMetrics(1 /* SysMetrics.CYSCREEN */)];
39
38
  const x = cfg.x === undefined ? ((sw - w) / 2) | 0
40
39
  : cfg.x === -2147483648 /* CreatePos.USEDEFAULT */ ? -2147483648 /* CreatePos.USEDEFAULT */ : cfg.x * scaleFactor;
41
40
  const y = cfg.y === undefined ? ((sh - h) / 2) | 0
@@ -44,8 +43,11 @@ export function createRoot(container) {
44
43
  if (!hwin)
45
44
  throw new Error('CreateWindow failed');
46
45
  hwnd = hwin;
47
- if (!cfg.noShowWindow)
48
- gui.ShowWindow(hwnd);
46
+ // 启动首帧:ShowWindow 后立即 WM_PAINT,不留白(原 gui.ShowWindow 复合语义)
47
+ if (!cfg.noShowWindow) {
48
+ ShowWindow(hwnd, 1 /* ShowWindowCmd.SHOWNORMAL */);
49
+ UpdateWindow(hwnd);
50
+ }
49
51
  }
50
52
  else {
51
53
  hwnd = container;
@@ -0,0 +1,29 @@
1
+ export type JustifyContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
2
+ export interface FlexStyle {
3
+ flexDirection?: 'row' | 'column';
4
+ justifyContent?: JustifyContent;
5
+ alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch';
6
+ gap?: number;
7
+ padding?: number;
8
+ paddingTop?: number;
9
+ paddingRight?: number;
10
+ paddingBottom?: number;
11
+ paddingLeft?: number;
12
+ }
13
+ interface ChildStyle {
14
+ width?: number | 'auto';
15
+ height?: number | 'auto';
16
+ flexGrow?: number;
17
+ alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch';
18
+ }
19
+ interface ChildInfo {
20
+ style: ChildStyle;
21
+ }
22
+ export interface LayoutResult {
23
+ x: number;
24
+ y: number;
25
+ width: number;
26
+ height: number;
27
+ }
28
+ export declare function calculateFlexLayout(flex: FlexStyle, parentW: number, parentH: number, children: ChildInfo[]): LayoutResult[];
29
+ export {};
@@ -0,0 +1 @@
1
+ export declare function nmCode(lParam: number): number;
@@ -0,0 +1,2 @@
1
+ import type { Instance, Props } from './reconciler.js';
2
+ export declare function applyProps(instance: Instance, newProps: Props, _oldProps: Props): void;
@@ -1,5 +1,5 @@
1
1
  import * as gui from 'gui';
2
- import { SetWindowText, EnableWindow } from '../windows/user32.js';
2
+ import { SetWindowText, EnableWindow, ShowWindow } from '../windows/user32.js';
3
3
  export function applyProps(instance, newProps, _oldProps) {
4
4
  const hwnd = instance.hwnd;
5
5
  instance.props = newProps;
@@ -24,9 +24,9 @@ export function applyProps(instance, newProps, _oldProps) {
24
24
  EnableWindow(hwnd, !newProps.disabled ? 1 : 0);
25
25
  }
26
26
  if ('hidden' in newProps) {
27
- gui.ShowWindow(hwnd, newProps.hidden ? 0 /* ShowWindowCmd.HIDE */ : 5 /* ShowWindowCmd.SHOW */);
27
+ ShowWindow(hwnd, newProps.hidden ? 0 /* ShowWindowCmd.HIDE */ : 5 /* ShowWindowCmd.SHOW */);
28
28
  }
29
29
  if ('visible' in newProps) {
30
- gui.ShowWindow(hwnd, newProps.visible ? 5 /* ShowWindowCmd.SHOW */ : 0 /* ShowWindowCmd.HIDE */);
30
+ ShowWindow(hwnd, newProps.visible ? 5 /* ShowWindowCmd.SHOW */ : 0 /* ShowWindowCmd.HIDE */);
31
31
  }
32
32
  }
@@ -0,0 +1,21 @@
1
+ import ReactReconciler from 'react-reconciler';
2
+ import * as gui from 'gui';
3
+ import type { WIntrinsicProps } from './jsx.js';
4
+ export declare const scaleFactor: number;
5
+ export type Props = WIntrinsicProps;
6
+ export interface Instance {
7
+ hwnd: gui.HWND | null;
8
+ type: string;
9
+ props: Props;
10
+ children: Instance[];
11
+ lastRect?: {
12
+ x: number;
13
+ y: number;
14
+ w: number;
15
+ h: number;
16
+ };
17
+ }
18
+ export declare const instancesByHwnd: Map<gui.HWND, Instance>;
19
+ export declare function forceFlexLayout(hwnd: gui.HWND): void;
20
+ declare const reconciler: ReactReconciler.Reconciler<gui.HWND, Instance, Instance, never, never, gui.HWND>;
21
+ export default reconciler;
@@ -3,21 +3,15 @@ import { createContext } from 'react';
3
3
  import { DefaultEventPriority, NoEventPriority } from 'react-reconciler/constants';
4
4
  import * as gui from 'gui';
5
5
  import * as os from 'os';
6
- import { GetDC, ReleaseDC, GetWindowLongPtr, CallWindowProc, SetWindowPos, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js';
7
- import { GetDeviceCaps } from '../windows/gdi32.js';
6
+ import { GetClientRect, GetWindowLongPtr, CallWindowProc, SetWindowPos, ShowWindow, InvalidateRect, SetParent, SetWindowText } from '../windows/user32.js';
7
+ import { createSystemDpiFont, getScaleFactor } from '../dpi.js';
8
+ import { RECT } from '../windows/structs.js';
8
9
  import { NULL } from '../ffi/ctype.js';
9
10
  import { applyProps } from './props.js';
10
11
  import { calculateFlexLayout } from './layout.js';
11
12
  import { getButtonIdealSize, measureTextForHwnd } from '../text-measure.js';
12
- const dpiFont = gui.CreateSystemDpiFont();
13
- // GetScaleFactor 等价内联:GetDC → GetDeviceCaps(LOGPIXELSX=88) → ReleaseDC 配对
14
- export const scaleFactor = (() => {
15
- const hdc = GetDC(NULL);
16
- const dpi = hdc ? GetDeviceCaps(hdc, 88) : 96;
17
- if (hdc)
18
- ReleaseDC(NULL, hdc);
19
- return dpi / 96;
20
- })();
13
+ const dpiFont = createSystemDpiFont();
14
+ export const scaleFactor = getScaleFactor();
21
15
  const DELAYED_CONTROLS = new Set(['SysListView32', 'SysTreeView32', 'LISTBOX', 'COMBOBOX', 'msctls_trackbar32', 'SysDateTimePick32', 'SysLink']);
22
16
  function isDelayedControl(winClass) {
23
17
  return DELAYED_CONTROLS.has(winClass);
@@ -59,11 +53,12 @@ function runFlexLayout(inst) {
59
53
  const visible = children.filter(c => !c.props.hidden);
60
54
  if (visible.length === 0)
61
55
  return;
62
- const rect = gui.GetClientRect(inst.hwnd);
63
- if (!rect) {
56
+ const rcBuf = RECT.alloc();
57
+ if (!GetClientRect(inst.hwnd, rcBuf.ptr)) {
64
58
  console.log('flex: no rect for', inst.hwnd, inst.type);
65
59
  return;
66
60
  }
61
+ const rect = RECT.decode(rcBuf);
67
62
  const pw = (rect.right - rect.left) / scaleFactor;
68
63
  const ph = (rect.bottom - rect.top) / scaleFactor;
69
64
  if (pw <= 0 || ph <= 0) {
@@ -260,19 +255,19 @@ const hostConfig = {
260
255
  },
261
256
  hideInstance(instance) {
262
257
  if (instance.hwnd !== null)
263
- gui.ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
258
+ ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
264
259
  },
265
260
  hideTextInstance(instance) {
266
261
  if (instance.hwnd !== null)
267
- gui.ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
262
+ ShowWindow(instance.hwnd, 0 /* ShowWindowCmd.HIDE */);
268
263
  },
269
264
  unhideInstance(instance, _props) {
270
265
  if (instance.hwnd !== null)
271
- gui.ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
266
+ ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
272
267
  },
273
268
  unhideTextInstance(instance, _text) {
274
269
  if (instance.hwnd !== null)
275
- gui.ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
270
+ ShowWindow(instance.hwnd, 5 /* ShowWindowCmd.SHOW */);
276
271
  },
277
272
  shouldSetTextContent(_type, props) {
278
273
  return typeof props.children === 'string' || typeof props.children === 'number';
@@ -0,0 +1,20 @@
1
+ export {};
2
+ import { ReadableStream as ReadableStreamImpl, ReadableStreamDefaultController as ReadableStreamDefaultControllerImpl, ReadableStreamDefaultReader as ReadableStreamDefaultReaderImpl } from './vendor/web-streams/ponyfill.mjs';
3
+ declare global {
4
+ type ReadableStreamReadResult<R = any> = {
5
+ done: false;
6
+ value: R;
7
+ } | {
8
+ done: true;
9
+ value?: undefined;
10
+ };
11
+ interface ReadableStreamReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {
12
+ }
13
+ interface ReadableStreamDefaultReader<R = any> extends ReadableStreamDefaultReaderImpl<R> {
14
+ }
15
+ interface ReadableStream<R = any> extends ReadableStreamImpl<R> {
16
+ }
17
+ interface ReadableStreamDefaultController<R = any> extends ReadableStreamDefaultControllerImpl<R> {
18
+ }
19
+ var ReadableStream: typeof ReadableStreamImpl;
20
+ }
@@ -0,0 +1,39 @@
1
+ export {};
2
+ declare global {
3
+ interface TextDecoder<T extends _Label | undefined = _Label | undefined> extends TextDecoderImpl<T> {
4
+ }
5
+ var TextDecoder: typeof TextDecoderImpl;
6
+ interface TextEncoder<T extends _Label | undefined = _Label | undefined> extends TextEncoderImpl<T> {
7
+ }
8
+ var TextEncoder: typeof TextEncoderImpl;
9
+ }
10
+ declare const _labelMap: {
11
+ readonly 'utf-8': 'utf-8';
12
+ readonly utf8: 'utf-8';
13
+ readonly 'unicode-1-1-utf-8': 'utf-8';
14
+ readonly 'utf-16': 'utf-16le';
15
+ readonly 'utf-16le': 'utf-16le';
16
+ readonly 'utf-16be': 'utf-16be';
17
+ };
18
+ type _Label = keyof typeof _labelMap;
19
+ type _Encoding = typeof _labelMap[_Label];
20
+ type _Result<T> = T extends _Label ? typeof _labelMap[T] : 'utf-8';
21
+ declare class TextDecoderImpl<T extends _Label | undefined = _Label | undefined> {
22
+ _encoding: _Encoding;
23
+ _fatal: boolean;
24
+ _ignoreBOM: boolean;
25
+ constructor(label?: T, options?: {
26
+ fatal?: boolean;
27
+ ignoreBOM?: boolean;
28
+ });
29
+ get encoding(): _Result<T>;
30
+ get fatal(): boolean;
31
+ get ignoreBOM(): boolean;
32
+ decode(buffer?: ArrayBufferView | ArrayBuffer | null): string;
33
+ }
34
+ declare class TextEncoderImpl<T extends _Label | undefined = _Label | undefined> {
35
+ _encoding: _Encoding;
36
+ constructor(label?: T);
37
+ get encoding(): _Result<T>;
38
+ encode(input?: string): Uint8Array<ArrayBuffer>;
39
+ }
@@ -0,0 +1,14 @@
1
+ import { type Ptr } from './ffi/ctype.js';
2
+ import * as gui from 'gui';
3
+ export declare function measureText(hdc: Ptr<'HDC'>, text: string, maxWidth: number): {
4
+ width: number;
5
+ height: number;
6
+ };
7
+ export declare function getButtonIdealSize(hwnd: gui.HWND): {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ export declare function measureTextForHwnd(hwnd: gui.HWND, text: string): {
12
+ width: number;
13
+ height: number;
14
+ };
@@ -1,6 +1,6 @@
1
1
  import { NULL } from './ffi/ctype.js';
2
2
  import * as gui from 'gui';
3
- import { DrawText, GetDC, ReleaseDC } from './windows/user32.js';
3
+ import { DrawText, GetDC, GetClientRect, GetWindowRect, ReleaseDC } from './windows/user32.js';
4
4
  import { SelectObject } from './windows/gdi32.js';
5
5
  import { RECT, SIZE } from './windows/structs.js';
6
6
  export function measureText(hdc, text, maxWidth) {
@@ -29,11 +29,14 @@ export function measureTextForHwnd(hwnd, text) {
29
29
  if (hFont)
30
30
  SelectObject(hdc, oldFont);
31
31
  ReleaseDC(hwnd, hdc);
32
- const wr = gui.GetWindowRect(hwnd);
33
- const cr = gui.GetClientRect(hwnd);
34
- if (wr && cr) {
35
- result.width += (wr.right - wr.left) - (cr.right - cr.left);
36
- result.height += (wr.bottom - wr.top) - (cr.bottom - cr.top);
32
+ const wr = RECT.alloc();
33
+ const cr = RECT.alloc();
34
+ const okWr = GetWindowRect(hwnd, wr.ptr);
35
+ const okCr = GetClientRect(hwnd, cr.ptr);
36
+ if (okWr && okCr) {
37
+ const w = RECT.decode(wr), c = RECT.decode(cr);
38
+ result.width += (w.right - w.left) - (c.right - c.left);
39
+ result.height += (w.bottom - w.top) - (c.bottom - c.top);
37
40
  }
38
41
  return result;
39
42
  }