mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-16 07:35:51 +01:00
Compare commits
66 commits
master
...
v3/website
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7670273d43 | ||
|
|
a15c0a5441 | ||
|
|
19be7f61ac | ||
|
|
bbf0e8cdad | ||
|
|
7e2d2a29a1 | ||
|
|
671dc2aa3a | ||
|
|
294a2c701e | ||
|
|
01f03c552d | ||
|
|
dc46154d94 | ||
|
|
87737c23eb | ||
|
|
6e6f099a99 | ||
|
|
4cb3321c39 | ||
|
|
6a2343a1a0 | ||
|
|
f2d6dba2cf | ||
|
|
dd1ef7fae9 | ||
|
|
527cff9ec3 | ||
|
|
ba150eccae | ||
|
|
fa74986f1e | ||
|
|
d1085b5bea | ||
|
|
4d0a14d2eb | ||
|
|
8c3439b733 | ||
|
|
a0534d527a | ||
|
|
a5b52f2795 | ||
|
|
b526ebd679 | ||
|
|
51b9315ae9 | ||
|
|
8edf44dc31 | ||
|
|
9b7626e59e | ||
|
|
6dd092c7a9 | ||
|
|
46a0d467c0 | ||
|
|
e3b164ae93 | ||
|
|
d8f58ab20f | ||
|
|
0de2bccd28 | ||
|
|
2eaf724710 | ||
|
|
58138ac09b | ||
|
|
143f090422 | ||
|
|
f8f466ba7e | ||
|
|
cb28de47f8 | ||
|
|
4ad2475ed6 | ||
|
|
0172078536 | ||
|
|
0bb1fb512a | ||
|
|
b6940d95a2 | ||
|
|
75f0457375 | ||
|
|
ffe31b6265 | ||
|
|
8963610722 | ||
|
|
66bfcf0e36 | ||
|
|
0b3559abfe | ||
|
|
773389ee5e | ||
|
|
4c04991d4d | ||
|
|
d56bb59b72 | ||
|
|
6e92a4f71e | ||
|
|
1f6217c0d8 | ||
|
|
17204bebd0 | ||
|
|
728e2019d8 | ||
|
|
7f3fdd6977 | ||
|
|
e8798f8371 | ||
|
|
402b743553 | ||
|
|
f08ae2fc62 | ||
|
|
178ea9c8c5 | ||
|
|
7c63cee9e8 | ||
|
|
4a60dfc373 | ||
|
|
829a829cb4 | ||
|
|
34896ccb4e | ||
|
|
5df5eb6a04 | ||
|
|
31ba36baf3 | ||
|
|
bf10f71760 | ||
|
|
8aa61fff6d |
203 changed files with 16244 additions and 1009 deletions
1
v3/.gitignore
vendored
1
v3/.gitignore
vendored
|
|
@ -6,3 +6,4 @@ cmd/wails/wails
|
|||
/examples/menu/menu
|
||||
/examples/clipboard/clipboard
|
||||
/examples/plain/plain
|
||||
/website/venv/
|
||||
|
|
|
|||
315
v3/STATUS.md
Normal file
315
v3/STATUS.md
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
# Status
|
||||
|
||||
Status of features in v3. Incomplete - please add as you see fit.
|
||||
|
||||
## Application
|
||||
|
||||
Application interface methods
|
||||
|
||||
| Method | Windows | Linux | Mac | Notes |
|
||||
|---------------------------------------------------------------|---------|-------|-----|-------|
|
||||
| run() error | | | Y | |
|
||||
| destroy() | | | Y | |
|
||||
| setApplicationMenu(menu *Menu) | | | Y | |
|
||||
| name() string | | | Y | |
|
||||
| getCurrentWindowID() uint | | | Y | |
|
||||
| showAboutDialog(name string, description string, icon []byte) | | | Y | |
|
||||
| setIcon(icon []byte) | | | Y | |
|
||||
| on(id uint) | | | Y | |
|
||||
| dispatchOnMainThread(fn func()) | Y | | Y | |
|
||||
| hide() | Y | | Y | |
|
||||
| show() | Y | | Y | |
|
||||
| getPrimaryScreen() (*Screen, error) | | | Y | |
|
||||
| getScreens() ([]*Screen, error) | | | Y | |
|
||||
|
||||
## Webview Window
|
||||
|
||||
Webview Window Interface Methods
|
||||
|
||||
| Method | Windows | Linux | Mac | Notes |
|
||||
|----------------------------------------------------|---------|-------|-----|------------------------------------------|
|
||||
| center() | Y | | Y | |
|
||||
| close() | | | Y | |
|
||||
| destroy() | | | Y | |
|
||||
| execJS(js string) | | | Y | |
|
||||
| focus() | Y | | Y | |
|
||||
| forceReload() | | | Y | |
|
||||
| fullscreen() | Y | | Y | |
|
||||
| getScreen() (*Screen, error) | | | Y | |
|
||||
| getZoom() float64 | | | Y | |
|
||||
| height() int | Y | | Y | |
|
||||
| hide() | Y | | Y | |
|
||||
| isFullscreen() bool | Y | | Y | |
|
||||
| isMaximised() bool | Y | | Y | |
|
||||
| isMinimised() bool | Y | | Y | |
|
||||
| maximise() | Y | | Y | |
|
||||
| minimise() | Y | | Y | |
|
||||
| nativeWindowHandle() (uintptr, error) | Y | | Y | |
|
||||
| on(eventID uint) | | | Y | |
|
||||
| openContextMenu(menu *Menu, data *ContextMenuData) | | | Y | |
|
||||
| position() (int, int) | Y | | Y | |
|
||||
| reload() | | | Y | |
|
||||
| run() | Y | | Y | |
|
||||
| setAlwaysOnTop(alwaysOnTop bool) | Y | | Y | |
|
||||
| setBackgroundColour(color RGBA) | Y | | Y | |
|
||||
| setFrameless(bool) | | | Y | |
|
||||
| setFullscreenButtonEnabled(enabled bool) | - | | Y | There is no fullscreen button in Windows |
|
||||
| setHTML(html string) | | | Y | |
|
||||
| setMaxSize(width, height int) | Y | | Y | |
|
||||
| setMinSize(width, height int) | Y | | Y | |
|
||||
| setPosition(x int, y int) | Y | | Y | |
|
||||
| setResizable(resizable bool) | Y | | Y | |
|
||||
| setSize(width, height int) | Y | | Y | |
|
||||
| setTitle(title string) | Y | | Y | |
|
||||
| setURL(url string) | | | Y | |
|
||||
| setZoom(zoom float64) | | | Y | |
|
||||
| show() | Y | | Y | |
|
||||
| size() (int, int) | Y | | Y | |
|
||||
| toggleDevTools() | | | Y | |
|
||||
| unfullscreen() | Y | | Y | |
|
||||
| unmaximise() | Y | | Y | |
|
||||
| unminimise() | Y | | Y | |
|
||||
| width() int | Y | | Y | |
|
||||
| zoom() | | | Y | |
|
||||
| zoomIn() | | | Y | |
|
||||
| zoomOut() | | | Y | |
|
||||
| zoomReset() | | | Y | |
|
||||
|
||||
## Runtime
|
||||
|
||||
### Application
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|-------|
|
||||
| Quit | | | Y | |
|
||||
| Hide | Y | | Y | |
|
||||
| Show | Y | | Y | |
|
||||
|
||||
### Dialogs
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|----------|---------|-------|-----|-------|
|
||||
| Info | Y | | Y | |
|
||||
| Warning | Y | | Y | |
|
||||
| Error | Y | | Y | |
|
||||
| Question | Y | | Y | |
|
||||
| OpenFile | Y | | Y | |
|
||||
| SaveFile | Y | | Y | |
|
||||
|
||||
### Clipboard
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|-------|
|
||||
| SetText | | | Y | |
|
||||
| Text | | | Y | |
|
||||
|
||||
### ContextMenu
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|-----------------|---------|-------|-----|-------|
|
||||
| OpenContextMenu | | | Y | |
|
||||
|
||||
### Screens
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|------------|---------|-------|-----|-------|
|
||||
| GetAll | Y | | Y | |
|
||||
| GetPrimary | | | Y | |
|
||||
| GetCurrent | | | Y | |
|
||||
|
||||
### Window
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------------------|---------|-------|-----|--------------------------------------------------------------------------------------|
|
||||
| SetTitle | Y | | Y | |
|
||||
| SetSize | Y | | Y | |
|
||||
| Size | Y | | Y | |
|
||||
| SetPosition | Y | | Y | |
|
||||
| Position | Y | | Y | |
|
||||
| Focus | Y | | Y | |
|
||||
| FullScreen | Y | | Y | |
|
||||
| UnFullscreen | Y | | Y | |
|
||||
| Minimise | Y | | Y | |
|
||||
| UnMinimise | Y | | Y | |
|
||||
| Maximise | Y | | Y | |
|
||||
| UnMaximise | Y | | Y | |
|
||||
| Show | Y | | Y | |
|
||||
| Hide | Y | | Y | |
|
||||
| Center | Y | | Y | |
|
||||
| SetBackgroundColour | Y | | Y | https://github.com/MicrosoftEdge/WebView2Feedback/issues/1621#issuecomment-938234294 |
|
||||
| SetAlwaysOnTop | Y | | Y | |
|
||||
| SetResizable | Y | | Y | |
|
||||
| SetMinSize | Y | | Y | |
|
||||
| SetMaxSize | Y | | Y | |
|
||||
| Width | Y | | Y | |
|
||||
| Height | Y | | Y | |
|
||||
| ZoomIn | | | Y | Increase view scale |
|
||||
| ZoomOut | | | Y | Decrease view scale |
|
||||
| ZoomReset | | | Y | Reset view scale |
|
||||
| GetZoom | | | Y | Get current view scale |
|
||||
| SetZoom | | | Y | Set view scale |
|
||||
| Screen | | | Y | Get screen for window |
|
||||
|
||||
### Window Options
|
||||
|
||||
A 'Y' in the table below indicates that the option has been tested and is applied when the window is created.
|
||||
An 'X' indicates that the option is not supported by the platform.
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------------------------------|---------|-------|-----|--------------------------------------------|
|
||||
| Name | Y | | | |
|
||||
| Title | Y | | | |
|
||||
| Width | Y | | | |
|
||||
| Height | Y | | | |
|
||||
| AlwaysOnTop | Y | | | |
|
||||
| URL | | | | |
|
||||
| DisableResize | Y | | | |
|
||||
| Frameless | Y | | | |
|
||||
| MinWidth | Y | | | |
|
||||
| MinHeight | Y | | | |
|
||||
| MaxWidth | Y | | | |
|
||||
| MaxHeight | Y | | | |
|
||||
| StartState | Y | | | |
|
||||
| Mac | - | - | | |
|
||||
| BackgroundType | | | | Acrylic seems to work but the others don't |
|
||||
| BackgroundColour | Y | | | |
|
||||
| HTML | | | | |
|
||||
| JS | | | | |
|
||||
| CSS | | | | |
|
||||
| X | Y | | | |
|
||||
| Y | Y | | | |
|
||||
| HideOnClose | Y | | | |
|
||||
| FullscreenButtonEnabled | Y | | | |
|
||||
| Hidden | Y | | | |
|
||||
| EnableFraudulentWebsiteWarnings | | | | |
|
||||
| Zoom | | | | |
|
||||
| ZoomControlEnabled | | | | |
|
||||
| OpenInspectorOnStartup | | | | |
|
||||
| EnableDragAndDrop | | | | |
|
||||
| Windows | Y | - | - | |
|
||||
| Focused | Y | | | |
|
||||
|
||||
### Log
|
||||
|
||||
To log or not to log? System logger vs custom logger.
|
||||
|
||||
## Menu
|
||||
|
||||
| Event | Windows | Linux | Mac | Notes |
|
||||
|--------------------------|---------|-------|-----|-------|
|
||||
| Default Application Menu | | | Y | |
|
||||
|
||||
## Tray Menus
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|--------------------|---------|-------|-----|----------------------------------------------------------------------|
|
||||
| Icon | Y | | Y | Windows has default icons for light/dark mode & supports PNG or ICO. |
|
||||
| Label | - | | Y | |
|
||||
| Label (ANSI Codes) | - | | | |
|
||||
| Menu | Y | | Y | |
|
||||
|
||||
## Cross Platform Events
|
||||
|
||||
Mapping native events to cross-platform events.
|
||||
|
||||
| Event | Windows | Linux | Mac | Notes |
|
||||
|--------------------------|---------|-------|-----------------|-------|
|
||||
| WindowWillClose | | | WindowWillClose | |
|
||||
| WindowDidClose | | | | |
|
||||
| WindowDidResize | | | | |
|
||||
| WindowDidHide | | | | |
|
||||
| ApplicationWillTerminate | | | | |
|
||||
|
||||
... Add more
|
||||
|
||||
## Bindings Generation
|
||||
|
||||
TBD
|
||||
|
||||
## Models Generation
|
||||
|
||||
TBD
|
||||
|
||||
## Task file
|
||||
|
||||
TBD
|
||||
|
||||
## Theme
|
||||
|
||||
| Mode | Windows | Linux | Mac | Notes |
|
||||
|--------|---------|-------|-----|-------|
|
||||
| Dark | Y | | | |
|
||||
| Light | Y | | | |
|
||||
| System | Y | | | |
|
||||
|
||||
## NSIS Installer
|
||||
|
||||
TBD
|
||||
|
||||
## Templates
|
||||
|
||||
TBD
|
||||
|
||||
## Plugins
|
||||
|
||||
Built-in plugin support:
|
||||
|
||||
| Plugin | Windows | Linux | Mac | Notes |
|
||||
|-----------------|---------|-------|-----|-------|
|
||||
| Browser | | | Y | |
|
||||
| KV Store | | | Y | |
|
||||
| Log | | | Y | |
|
||||
| Single Instance | | | Y | |
|
||||
| SQLite | | | Y | |
|
||||
| Start at login | | | Y | |
|
||||
| Server | | | | |
|
||||
|
||||
## Packaging
|
||||
|
||||
| | Windows | Linux | Mac | Notes |
|
||||
|-----------------|---------|-------|-----|-------|
|
||||
| Icon Generation | | | Y | |
|
||||
| Icon Embedding | | | Y | |
|
||||
| Info.plist | - | | Y | |
|
||||
| NSIS Installer | | | - | |
|
||||
| Mac bundle | | | Y | |
|
||||
| Windows exe | | | - | |
|
||||
|
||||
## Frameless Windows
|
||||
|
||||
| Feature | Windows | Linux | Mac | Notes |
|
||||
|---------|---------|-------|-----|-------|
|
||||
| Resize | | | | |
|
||||
| Drag | | | | |
|
||||
|
||||
## Mac Specific
|
||||
|
||||
- [x] Translucency
|
||||
|
||||
### Mac Options
|
||||
|
||||
| Feature | Default | Notes |
|
||||
|-------------------------|-------------------|------------------------------------------------------|
|
||||
| Backdrop | MacBackdropNormal | Standard solid window |
|
||||
| DisableShadow | false | |
|
||||
| TitleBar | | Standard window decorations by default |
|
||||
| Appearance | DefaultAppearance | |
|
||||
| InvisibleTitleBarHeight | 0 | Creates an invisible title bar for frameless windows |
|
||||
|
||||
## Windows Specific
|
||||
|
||||
- [x] Translucency
|
||||
- [x] Custom Themes
|
||||
|
||||
### Windows Options
|
||||
|
||||
| Feature | Default | Notes |
|
||||
|-----------------------------------|---------|---------------------------------------------|
|
||||
| BackdropType | | |
|
||||
| DisableIcon | | |
|
||||
| Theme | | |
|
||||
| CustomTheme | | |
|
||||
| DisableFramelessWindowDecorations | | |
|
||||
| WindowMask | nil | Makes the window the contents of the bitmap |
|
||||
|
||||
## Linux Specific
|
||||
49
v3/TODO.md
49
v3/TODO.md
|
|
@ -1,49 +0,0 @@
|
|||
# TODO
|
||||
|
||||
Informal and incomplete list of things needed in v3.
|
||||
|
||||
## General
|
||||
|
||||
- [x] Generate Bindings
|
||||
- [x] Generate TS Models
|
||||
- [ ] Dev Mode
|
||||
- [ ] Generate Info.Plist from `info.json`
|
||||
|
||||
- [ ] Windows Port
|
||||
- [ ] Linux Port
|
||||
|
||||
## Runtime
|
||||
|
||||
- [x] Pass window ID with window calls in JS
|
||||
- [x] Implement alias for `window` in JS
|
||||
- [x] Implement runtime dispatcher
|
||||
- [x] Log
|
||||
- [x] Same Window
|
||||
- [ ] Other Window
|
||||
- [x] Dialogs
|
||||
- [x] Info
|
||||
- [x] Warning
|
||||
- [x] Error
|
||||
- [x] Question
|
||||
- [x] OpenFile
|
||||
- [x] SaveFile
|
||||
- [x] Events
|
||||
- [x] Screens
|
||||
- [x] Clipboard
|
||||
- [x] Application
|
||||
- [ ] Create `.d.ts` file
|
||||
|
||||
## Templates
|
||||
|
||||
- [ ] Create plain template
|
||||
- [ ] Improve default template
|
||||
|
||||
## Runtime
|
||||
|
||||
- [ ] To log or not to log?
|
||||
- [ ] Unify cross-platform events, eg. `onClose`
|
||||
|
||||
## Plugins
|
||||
|
||||
- [ ] Move logins to `v3/plugins`
|
||||
- [ ] Expose application logger to plugins
|
||||
153
v3/Taskfile.yaml
153
v3/Taskfile.yaml
|
|
@ -3,124 +3,16 @@
|
|||
version: "3"
|
||||
|
||||
includes:
|
||||
runtime:
|
||||
taskfile: ./internal/runtime
|
||||
dir: ./internal/runtime
|
||||
|
||||
website:
|
||||
taskfile: ./website
|
||||
dir: ./website
|
||||
optional: true
|
||||
|
||||
tasks:
|
||||
build-runtime-debug:
|
||||
dir: internal/runtime
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_debug_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}}
|
||||
|
||||
build-runtime-debug-windows:
|
||||
cmds:
|
||||
- task: build-runtime-debug
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
|
||||
build-runtime-debug-linux:
|
||||
cmds:
|
||||
- task: build-runtime-debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
|
||||
build-runtime-debug-darwin:
|
||||
cmds:
|
||||
- task: build-runtime-debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
|
||||
build-runtime-production:
|
||||
dir: internal/runtime
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --minify --outfile=runtime_production_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}}
|
||||
|
||||
build-runtime-production-windows:
|
||||
cmds:
|
||||
- task: build-runtime-production
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
|
||||
build-runtime-production-linux:
|
||||
cmds:
|
||||
- task: build-runtime-production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
|
||||
build-runtime-production-darwin:
|
||||
cmds:
|
||||
- task: build-runtime-production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
|
||||
install-runtime-dev-deps:
|
||||
dir: internal/runtime/dev
|
||||
internal: true
|
||||
sources:
|
||||
- package.json
|
||||
cmds:
|
||||
- npm install
|
||||
|
||||
install-runtime-deps:
|
||||
dir: internal/runtime
|
||||
internal: true
|
||||
sources:
|
||||
- package.json
|
||||
cmds:
|
||||
- npm install
|
||||
|
||||
test-runtime:
|
||||
dir: internal/runtime
|
||||
cmds:
|
||||
- npx vitest run
|
||||
|
||||
update-runtime:
|
||||
dir: internal/runtime
|
||||
cmds:
|
||||
- npx npm-check-updates -u
|
||||
|
||||
build-runtime-all:
|
||||
dir: internal/runtime
|
||||
deps:
|
||||
- build-runtime-production-darwin
|
||||
- build-runtime-production-windows
|
||||
- build-runtime-production-linux
|
||||
- build-runtime-debug-darwin
|
||||
- build-runtime-debug-windows
|
||||
- build-runtime-debug-linux
|
||||
|
||||
cmds:
|
||||
- cmd: echo "build complete"
|
||||
|
||||
build-runtime:
|
||||
dir: internal/runtime
|
||||
deps:
|
||||
- install-runtime-deps
|
||||
cmds:
|
||||
- task: build-runtime-all
|
||||
|
||||
recreate-template-dir:
|
||||
dir: internal/templates
|
||||
internal: true
|
||||
|
|
@ -129,7 +21,7 @@ tasks:
|
|||
- rm -rf {{.TEMPLATE_DIR}}
|
||||
- mkdir -p {{.TEMPLATE_DIR}}
|
||||
|
||||
generate-template:
|
||||
generate:template:
|
||||
dir: internal/templates/{{.TEMPLATE}}
|
||||
deps:
|
||||
- task: recreate-template-dir
|
||||
|
|
@ -156,49 +48,54 @@ tasks:
|
|||
- go install
|
||||
- echo "Reinstalled wails CLI"
|
||||
|
||||
generate-templates:
|
||||
generate:events:
|
||||
dir: tasks/events
|
||||
cmds:
|
||||
- go run generate.go
|
||||
|
||||
generate:templates:
|
||||
dir: internal/templates/
|
||||
deps:
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: svelte
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: svelte-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: vue
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: vue-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: react
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: react-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: preact
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: preact-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: lit
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: lit-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: vanilla
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: vanilla-ts
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: react-swc
|
||||
- task: generate-template
|
||||
- task: generate:template
|
||||
vars:
|
||||
TEMPLATE: react-swc-ts
|
||||
cmds:
|
||||
|
|
|
|||
|
|
@ -59,6 +59,24 @@ TBD
|
|||
|
||||
Dialogs are now available in JavaScript!
|
||||
|
||||
### Windows
|
||||
|
||||
Dialog buttons in Windows are not configurable and are constant depending on the type of dialog. To trigger a callback when a button is pressed, create a button with the same name as the button you wish to have the callback attached to.
|
||||
Example: Create a button with the label `Ok` and use `OnClick()` to set the callback method:
|
||||
```go
|
||||
dialog := app.QuestionDialog().
|
||||
SetTitle("Update").
|
||||
SetMessage("The cancel button is selected when pressing escape")
|
||||
ok := dialog.AddButton("Ok")
|
||||
ok.OnClick(func() {
|
||||
// Do something
|
||||
})
|
||||
no := dialog.AddButton("Cancel")
|
||||
dialog.SetDefaultButton(ok)
|
||||
dialog.SetCancelButton(no)
|
||||
dialog.Show()
|
||||
```
|
||||
|
||||
## Drag and Drop
|
||||
|
||||
Native drag and drop can be enabled per-window. Simply set the `EnableDragAndDrop` window config option to `true` and the window will allow files to be dragged onto it. When this happens, the `events.FilesDropped` event will be emitted. The filenames can then be retrieved from the WindowEventContext using the `DroppedFiles()` method. This returns a slice of strings containing the filenames.
|
||||
|
|
@ -180,3 +198,39 @@ const MyEnum = {
|
|||
|
||||
- Why use `float64`? Can't we use `int`?
|
||||
- Because JavaScript doesn't have a concept of `int`. Everything is a `number`, which translates to `float64` in Go. There are also restrictions on casting types in Go's reflection package, which means using `int` doesn't work.
|
||||
|
||||
### BackgroundColour
|
||||
|
||||
In v2, this was a pointer to an `RGBA` struct. In v3, this is an `RGBA` struct value.
|
||||
|
||||
### WindowIsTranslucent
|
||||
|
||||
This flag has been removed. Now there is a `BackgroundType` flag that can be used to set the type of background the window should have.
|
||||
This flag can be set to any of the following values:
|
||||
- `BackgroundTypeSolid` - The window will have a solid background
|
||||
- `BackgroundTypeTransparent` - The window will have a transparent background
|
||||
- `BackgroundTypeTranslucent` - The window will have a translucent background
|
||||
|
||||
On Windows, if the `BackgroundType` is set to `BackgroundTypeTranslucent`, the type of translucency can be set using the
|
||||
`BackdropType` flag in the `WindowsWindow` options. This can be set to any of the following values:
|
||||
- `Auto` - The window will use an effect determined by the system
|
||||
- `None` - The window will have no background
|
||||
- `Mica` - The window will use the Mica effect
|
||||
- `Acrylic` - The window will use the acrylic effect
|
||||
- `Tabbed` - The window will use the tabbed effect
|
||||
|
||||
|
||||
## Windows Application Options
|
||||
|
||||
### WndProcInterceptor
|
||||
|
||||
If this is set, the WndProc will be intercepted and the function will be called. This allows you to handle Windows
|
||||
messages directly. The function should have the following signature:
|
||||
|
||||
```go
|
||||
func(hwnd uintptr, msg uint32, wParam, lParam uintptr) (returnValue uintptr, shouldReturn)
|
||||
```
|
||||
|
||||
The `shouldReturn` value should be set to `true` if the returnValue should be returned by the main wndProc method.
|
||||
If it is set to `false`, the return value will be ignored and the message will continue to be processed by the main
|
||||
wndProc method.
|
||||
|
|
@ -5,15 +5,20 @@ go 1.20
|
|||
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
|
||||
|
||||
require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leaanthony/slicer v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/samber/lo v1.37.0 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.1 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 // indirect
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/wailsapp/wails/v3 => ../..
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
|
|
@ -18,6 +24,8 @@ github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpo
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II=
|
||||
github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||
|
|
@ -25,8 +33,12 @@ golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p
|
|||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ func main() {
|
|||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
Assets: application.AssetOptions{
|
||||
FS: assets,
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
URL: "/",
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func main() {
|
|||
if runtime.GOOS == "darwin" {
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHiddenInset,
|
||||
InvisibleTitleBarHeight: 25,
|
||||
|
|
@ -81,7 +81,7 @@ func main() {
|
|||
})
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHiddenInsetUnified,
|
||||
InvisibleTitleBarHeight: 50,
|
||||
|
|
@ -95,7 +95,7 @@ func main() {
|
|||
})
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHidden,
|
||||
InvisibleTitleBarHeight: 25,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
mainWindow := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
mainWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Context Menu Demo",
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
|
|
@ -34,7 +34,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Context Menu Demo",
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/wailsapp/wails/v3/pkg/icons"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
|
@ -19,6 +20,7 @@ func main() {
|
|||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
})
|
||||
|
||||
// Create a custom menu
|
||||
menu := app.NewMenu()
|
||||
menu.AddRole(application.AppMenu)
|
||||
|
|
@ -45,7 +47,7 @@ func main() {
|
|||
dialog := app.InfoDialog()
|
||||
dialog.SetTitle("Custom Icon Example")
|
||||
dialog.SetMessage("Using a custom icon")
|
||||
dialog.SetIcon(application.DefaultApplicationIcon)
|
||||
dialog.SetIcon(icons.ApplicationDarkMode256)
|
||||
dialog.Show()
|
||||
})
|
||||
|
||||
|
|
@ -85,7 +87,7 @@ func main() {
|
|||
dialog := app.QuestionDialog()
|
||||
dialog.SetTitle("Custom Icon Example")
|
||||
dialog.SetMessage("Using a custom icon")
|
||||
dialog.SetIcon(application.WailsLogoWhiteTransparent)
|
||||
dialog.SetIcon(icons.WailsLogoWhiteTransparent)
|
||||
dialog.SetDefaultButton(dialog.AddButton("I like it!"))
|
||||
dialog.AddButton("Not so keen...")
|
||||
dialog.Show()
|
||||
|
|
@ -112,7 +114,7 @@ func main() {
|
|||
dialog := app.WarningDialog()
|
||||
dialog.SetTitle("Custom Icon Example")
|
||||
dialog.SetMessage("Using a custom icon")
|
||||
dialog.SetIcon(application.DefaultApplicationIcon)
|
||||
dialog.SetIcon(icons.ApplicationLightMode256)
|
||||
dialog.Show()
|
||||
})
|
||||
|
||||
|
|
@ -137,7 +139,7 @@ func main() {
|
|||
dialog := app.ErrorDialog()
|
||||
dialog.SetTitle("Custom Icon Example")
|
||||
dialog.SetMessage("Using a custom icon")
|
||||
dialog.SetIcon(application.WailsLogoWhite)
|
||||
dialog.SetIcon(icons.WailsLogoWhite)
|
||||
dialog.Show()
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
window := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
window := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Drag-n-drop Demo",
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
|
|
|
|||
|
|
@ -26,10 +26,12 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
// Custom event handling
|
||||
app.Events.On("myevent", func(e *application.WailsEvent) {
|
||||
log.Printf("[Go] WailsEvent received: %+v\n", e)
|
||||
})
|
||||
|
||||
// OS specific application events
|
||||
app.On(events.Mac.ApplicationDidFinishLaunching, func() {
|
||||
for {
|
||||
log.Println("Sending event")
|
||||
|
|
@ -41,7 +43,12 @@ func main() {
|
|||
}
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
// Platform agnostic events
|
||||
app.On(events.Common.ApplicationStarted, func() {
|
||||
println("events.Common.ApplicationStarted fired!")
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Events Demo",
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
|
|
@ -49,7 +56,7 @@ func main() {
|
|||
InvisibleTitleBarHeight: 50,
|
||||
},
|
||||
})
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Events Demo",
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
|
|
|
|||
32
v3/examples/frameless/assets/index.html
Normal file
32
v3/examples/frameless/assets/index.html
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.quarter {
|
||||
flex: 50%; /* This will cause elements to take up 50% of the container's width, causing them to wrap into 4 equal sections. */
|
||||
box-sizing: border-box; /* This makes the padding part of the element's total width and height, ensuring they don't exceed 50%. */
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="quarter" style="background-color: lightblue; --wails-draggable: drag">Draggable</div>
|
||||
<div class="quarter" style="background-color: lightgreen;">Not Draggable</div>
|
||||
<div class="quarter" style="background-color: lightpink;">Not Draggable</div>
|
||||
<div class="quarter" style="background-color: lightyellow; --wails-draggable: drag">Draggable</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
36
v3/examples/frameless/main.go
Normal file
36
v3/examples/frameless/main.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
|
||||
app := application.New(application.Options{
|
||||
Name: "Frameless Demo",
|
||||
Description: "A demo of frameless windows",
|
||||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
FS: assets,
|
||||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Frameless: true,
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"github.com/wailsapp/wails/v3/pkg/icons"
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
|
@ -62,9 +63,9 @@ func main() {
|
|||
mySystray := app.NewSystemTray()
|
||||
mySystray.SetLabel("Wails")
|
||||
if runtime.GOOS == "darwin" {
|
||||
mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
|
||||
mySystray.SetTemplateIcon(icons.SystrayMacTemplate)
|
||||
} else {
|
||||
mySystray.SetIcon(application.DefaultApplicationIcon)
|
||||
mySystray.SetIcon(icons.ApplicationDarkMode256)
|
||||
}
|
||||
myMenu := app.NewMenu()
|
||||
myMenu.Add("Item 1")
|
||||
|
|
@ -102,20 +103,20 @@ func main() {
|
|||
mySystray := app.NewSystemTray()
|
||||
mySystray.SetLabel("Wails is awesome")
|
||||
if runtime.GOOS == "darwin" {
|
||||
mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
|
||||
mySystray.SetTemplateIcon(icons.SystrayMacTemplate)
|
||||
} else {
|
||||
mySystray.SetIcon(application.DefaultApplicationIcon)
|
||||
mySystray.SetIcon(icons.ApplicationDarkMode256)
|
||||
}
|
||||
mySystray.SetMenu(myMenu)
|
||||
mySystray.SetIconPosition(application.NSImageLeading)
|
||||
|
||||
myWindow := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
myWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Kitchen Sink",
|
||||
Width: 600,
|
||||
Height: 400,
|
||||
AlwaysOnTop: true,
|
||||
DisableResize: false,
|
||||
BackgroundColour: &application.RGBA{
|
||||
BackgroundColour: application.RGBA{
|
||||
Red: 255,
|
||||
Green: 255,
|
||||
Blue: 255,
|
||||
|
|
@ -184,7 +185,7 @@ func main() {
|
|||
*/
|
||||
var myWindow2 *application.WebviewWindow
|
||||
var myWindow2Lock sync.RWMutex
|
||||
myWindow2 = app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
myWindow2 = app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "#2",
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ func main() {
|
|||
|
||||
// Click callbacks
|
||||
myMenu.Add("Click Me!").OnClick(func(ctx *application.Context) {
|
||||
ctx.ClickedMenuItem().SetLabel("Thanks mate!")
|
||||
switch ctx.ClickedMenuItem().Label() {
|
||||
case "Click Me!":
|
||||
ctx.ClickedMenuItem().SetLabel("Thanks mate!")
|
||||
case "Thanks mate!":
|
||||
ctx.ClickedMenuItem().SetLabel("Click Me!")
|
||||
}
|
||||
})
|
||||
|
||||
// You can control the current window from the menu
|
||||
|
|
@ -82,7 +87,15 @@ func main() {
|
|||
beatles.SetLabel("Hello")
|
||||
}
|
||||
})
|
||||
|
||||
myMenu.Add("Hide the beatles").OnClick(func(ctx *application.Context) {
|
||||
if beatles.Hidden() {
|
||||
ctx.ClickedMenuItem().SetLabel("Unhide the beatles!")
|
||||
beatles.SetHidden(false)
|
||||
} else {
|
||||
beatles.SetHidden(true)
|
||||
ctx.ClickedMenuItem().SetLabel("Hide the beatles!")
|
||||
}
|
||||
})
|
||||
app.SetMenu(menu)
|
||||
|
||||
app.NewWebviewWindow()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
_ "embed"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
|
@ -23,7 +24,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; user-select: none; -ms-user-select: none; -webkit-user-select: none; } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
@ -38,6 +39,21 @@ func main() {
|
|||
println("clicked")
|
||||
})
|
||||
|
||||
go func() {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle new Window from GoRoutine",
|
||||
Width: 500,
|
||||
Height: 500,
|
||||
Mac: application.MacWindow{
|
||||
Backdrop: application.MacBackdropTranslucent,
|
||||
TitleBar: application.MacTitleBarHiddenInsetUnified,
|
||||
InvisibleTitleBarHeight: 50,
|
||||
},
|
||||
})
|
||||
}()
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Screen Demo",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,21 @@ package main
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v3/pkg/icons"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
var counter int
|
||||
|
||||
func clickCount() int {
|
||||
counter++
|
||||
return counter
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := application.New(application.Options{
|
||||
Name: "Systray Demo",
|
||||
|
|
@ -17,26 +26,50 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
window := app.NewWebviewWindow().Hide()
|
||||
|
||||
systemTray := app.NewSystemTray()
|
||||
if runtime.GOOS == "darwin" {
|
||||
systemTray.SetIcon(application.DefaultMacTemplateIcon)
|
||||
systemTray.SetTemplateIcon(icons.SystrayMacTemplate)
|
||||
}
|
||||
|
||||
myMenu := app.NewMenu()
|
||||
myMenu.Add("Hello World!").OnClick(func(ctx *application.Context) {
|
||||
app.InfoDialog().SetTitle("Hello World!").SetMessage("Hello World!").Show()
|
||||
println("Hello World!")
|
||||
q := app.QuestionDialog().SetTitle("Ready?").SetMessage("Are you feeling ready?")
|
||||
q.AddButton("Yes").OnClick(func() {
|
||||
println("Awesome!")
|
||||
})
|
||||
q.AddButton("No").SetAsDefault().OnClick(func() {
|
||||
println("Boo!")
|
||||
})
|
||||
q.Show()
|
||||
})
|
||||
subMenu := myMenu.AddSubmenu("Submenu")
|
||||
subMenu.Add("Click me!").OnClick(func(ctx *application.Context) {
|
||||
ctx.ClickedMenuItem().SetLabel("Clicked!")
|
||||
})
|
||||
myMenu.AddSeparator()
|
||||
myMenu.AddCheckbox("Checked", true).OnClick(func(ctx *application.Context) {
|
||||
println("Checked: ", ctx.ClickedMenuItem().Checked())
|
||||
app.InfoDialog().SetTitle("Hello World!").SetMessage("Hello World!").Show()
|
||||
})
|
||||
myMenu.Add("Enabled").OnClick(func(ctx *application.Context) {
|
||||
println("Click me!")
|
||||
ctx.ClickedMenuItem().SetLabel("Disabled!").SetEnabled(false)
|
||||
})
|
||||
myMenu.AddSeparator()
|
||||
myMenu.Add("Quit").OnClick(func(ctx *application.Context) {
|
||||
app.Quit()
|
||||
})
|
||||
|
||||
systemTray.SetMenu(myMenu)
|
||||
|
||||
systemTray.OnClick(func() {
|
||||
window.SetTitle(fmt.Sprintf("Clicked %d times", clickCount()))
|
||||
window.Show().Focus()
|
||||
})
|
||||
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/events"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
|
@ -25,257 +19,261 @@ func main() {
|
|||
app.On(events.Mac.ApplicationDidFinishLaunching, func() {
|
||||
log.Println("ApplicationDidFinishLaunching")
|
||||
})
|
||||
|
||||
currentWindow := func(fn func(window *application.WebviewWindow)) {
|
||||
if app.CurrentWindow() != nil {
|
||||
fn(app.CurrentWindow())
|
||||
} else {
|
||||
println("Current WebviewWindow is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Create a custom menu
|
||||
menu := app.NewMenu()
|
||||
menu.AddRole(application.AppMenu)
|
||||
|
||||
windowCounter := 1
|
||||
|
||||
// Let's make a "Demo" menu
|
||||
myMenu := menu.AddSubmenu("New")
|
||||
|
||||
myMenu.Add("New WebviewWindow").
|
||||
SetAccelerator("CmdOrCtrl+N").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindow().
|
||||
SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
SetURL("https://wails.io").
|
||||
Show()
|
||||
windowCounter++
|
||||
})
|
||||
myMenu.Add("New WebviewWindow (Hide on Close").
|
||||
SetAccelerator("CmdOrCtrl+H").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{HideOnClose: true}).
|
||||
SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
SetURL("https://wails.io").
|
||||
Show()
|
||||
windowCounter++
|
||||
})
|
||||
myMenu.Add("New Frameless WebviewWindow").
|
||||
SetAccelerator("CmdOrCtrl+F").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
X: rand.Intn(1000),
|
||||
Y: rand.Intn(800),
|
||||
Frameless: true,
|
||||
Mac: application.MacWindow{
|
||||
InvisibleTitleBarHeight: 50,
|
||||
},
|
||||
}).Show()
|
||||
windowCounter++
|
||||
})
|
||||
if runtime.GOOS == "darwin" {
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHiddenInset,
|
||||
InvisibleTitleBarHeight: 25,
|
||||
},
|
||||
}).
|
||||
SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
SetHTML("<br/><br/><p>A MacTitleBarHiddenInset WebviewWindow example</p>").
|
||||
Show()
|
||||
windowCounter++
|
||||
})
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHiddenInsetUnified,
|
||||
InvisibleTitleBarHeight: 50,
|
||||
},
|
||||
}).
|
||||
SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
SetHTML("<br/><br/><p>A MacTitleBarHiddenInsetUnified WebviewWindow example</p>").
|
||||
Show()
|
||||
windowCounter++
|
||||
})
|
||||
myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
|
||||
OnClick(func(ctx *application.Context) {
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
TitleBar: application.MacTitleBarHidden,
|
||||
InvisibleTitleBarHeight: 25,
|
||||
},
|
||||
}).
|
||||
SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
SetHTML("<br/><br/><p>A MacTitleBarHidden WebviewWindow example</p>").
|
||||
Show()
|
||||
windowCounter++
|
||||
})
|
||||
}
|
||||
|
||||
sizeMenu := menu.AddSubmenu("Size")
|
||||
sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetSize(800, 600)
|
||||
})
|
||||
//
|
||||
//currentWindow := func(fn func(window *application.WebviewWindow)) {
|
||||
// if app.CurrentWindow() != nil {
|
||||
// fn(app.CurrentWindow())
|
||||
// } else {
|
||||
// println("Current WebviewWindow is nil")
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// Create a custom menu
|
||||
//menu := app.NewMenu()
|
||||
//menu.AddRole(application.AppMenu)
|
||||
//
|
||||
//windowCounter := 1
|
||||
//
|
||||
//// Let's make a "Demo" menu
|
||||
//myMenu := menu.AddSubmenu("New")
|
||||
//
|
||||
//myMenu.Add("New WebviewWindow").
|
||||
// SetAccelerator("CmdOrCtrl+N").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindow().
|
||||
// SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
// SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
// SetURL("https://wails.io").
|
||||
// Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
//myMenu.Add("New WebviewWindow (Hide on Close").
|
||||
// SetAccelerator("CmdOrCtrl+H").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{HideOnClose: true}).
|
||||
// SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
// SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
// SetURL("https://wails.io").
|
||||
// Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
//myMenu.Add("New Frameless WebviewWindow").
|
||||
// SetAccelerator("CmdOrCtrl+F").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
// X: rand.Intn(1000),
|
||||
// Y: rand.Intn(800),
|
||||
// Frameless: true,
|
||||
// Mac: application.MacWindow{
|
||||
// InvisibleTitleBarHeight: 50,
|
||||
// },
|
||||
// }).Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
//if runtime.GOOS == "darwin" {
|
||||
// myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
// Mac: application.MacWindow{
|
||||
// TitleBar: application.MacTitleBarHiddenInset,
|
||||
// InvisibleTitleBarHeight: 25,
|
||||
// },
|
||||
// }).
|
||||
// SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
// SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
// SetHTML("<br/><br/><p>A MacTitleBarHiddenInset WebviewWindow example</p>").
|
||||
// Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
// myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
// Mac: application.MacWindow{
|
||||
// TitleBar: application.MacTitleBarHiddenInsetUnified,
|
||||
// InvisibleTitleBarHeight: 50,
|
||||
// },
|
||||
// }).
|
||||
// SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
// SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
// SetHTML("<br/><br/><p>A MacTitleBarHiddenInsetUnified WebviewWindow example</p>").
|
||||
// Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
// myMenu.Add("New WebviewWindow (MacTitleBarHidden)").
|
||||
// OnClick(func(ctx *application.Context) {
|
||||
// app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
// Mac: application.MacWindow{
|
||||
// TitleBar: application.MacTitleBarHidden,
|
||||
// InvisibleTitleBarHeight: 25,
|
||||
// },
|
||||
// }).
|
||||
// SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)).
|
||||
// SetPosition(rand.Intn(1000), rand.Intn(800)).
|
||||
// SetHTML("<br/><br/><p>A MacTitleBarHidden WebviewWindow example</p>").
|
||||
// Show()
|
||||
// windowCounter++
|
||||
// })
|
||||
//}
|
||||
//
|
||||
//sizeMenu := menu.AddSubmenu("Size")
|
||||
//sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetSize(800, 600)
|
||||
// })
|
||||
//})
|
||||
//
|
||||
//sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200)
|
||||
// })
|
||||
//})
|
||||
//sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetMinSize(200, 200)
|
||||
// })
|
||||
//})
|
||||
//sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetFullscreenButtonEnabled(false)
|
||||
// w.SetMaxSize(600, 600)
|
||||
// })
|
||||
//})
|
||||
//sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// width, height := w.Size()
|
||||
// app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show()
|
||||
// })
|
||||
//})
|
||||
//
|
||||
//sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetMinSize(0, 0)
|
||||
// })
|
||||
//})
|
||||
//
|
||||
//sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetMaxSize(0, 0)
|
||||
// w.SetFullscreenButtonEnabled(true)
|
||||
// })
|
||||
//})
|
||||
//positionMenu := menu.AddSubmenu("Position")
|
||||
//positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetPosition(0, 0)
|
||||
// })
|
||||
//})
|
||||
//positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetPosition(rand.Intn(1000), rand.Intn(800))
|
||||
// })
|
||||
//})
|
||||
//
|
||||
//positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// x, y := w.Position()
|
||||
// app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show()
|
||||
// })
|
||||
//})
|
||||
//
|
||||
//positionMenu.Add("Center").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Center()
|
||||
// })
|
||||
//})
|
||||
//stateMenu := menu.AddSubmenu("State")
|
||||
//stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Minimise()
|
||||
// time.Sleep(2 * time.Second)
|
||||
// w.Restore()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Maximise()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Fullscreen()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.UnFullscreen()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Restore").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Restore()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.Hide()
|
||||
// time.Sleep(2 * time.Second)
|
||||
// w.Show()
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetAlwaysOnTop(true)
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetAlwaysOnTop(false)
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetURL("https://google.com")
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// w.SetURL("https://wails.io")
|
||||
// })
|
||||
//})
|
||||
//stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) {
|
||||
// screen, err := app.GetPrimaryScreen()
|
||||
// if err != nil {
|
||||
// app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
// return
|
||||
// }
|
||||
// msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
// app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show()
|
||||
//})
|
||||
//stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) {
|
||||
// screens, err := app.GetScreens()
|
||||
// if err != nil {
|
||||
// app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
// return
|
||||
// }
|
||||
// for _, screen := range screens {
|
||||
// msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
// app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
|
||||
// }
|
||||
//})
|
||||
//stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) {
|
||||
// currentWindow(func(w *application.WebviewWindow) {
|
||||
// screen, err := w.GetScreen()
|
||||
// if err != nil {
|
||||
// app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
// return
|
||||
// }
|
||||
// msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
// app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
|
||||
// })
|
||||
//})
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Mac: application.MacWindow{
|
||||
DisableShadow: true,
|
||||
},
|
||||
})
|
||||
|
||||
sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200)
|
||||
})
|
||||
})
|
||||
sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetMinSize(200, 200)
|
||||
})
|
||||
})
|
||||
sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetFullscreenButtonEnabled(false)
|
||||
w.SetMaxSize(600, 600)
|
||||
})
|
||||
})
|
||||
sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
width, height := w.Size()
|
||||
app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show()
|
||||
})
|
||||
})
|
||||
|
||||
sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetMinSize(0, 0)
|
||||
})
|
||||
})
|
||||
|
||||
sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetMaxSize(0, 0)
|
||||
w.SetFullscreenButtonEnabled(true)
|
||||
})
|
||||
})
|
||||
positionMenu := menu.AddSubmenu("Position")
|
||||
positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetPosition(0, 0)
|
||||
})
|
||||
})
|
||||
positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetPosition(rand.Intn(1000), rand.Intn(800))
|
||||
})
|
||||
})
|
||||
|
||||
positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
x, y := w.Position()
|
||||
app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show()
|
||||
})
|
||||
})
|
||||
|
||||
positionMenu.Add("Center").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Center()
|
||||
})
|
||||
})
|
||||
stateMenu := menu.AddSubmenu("State")
|
||||
stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Minimise()
|
||||
time.Sleep(2 * time.Second)
|
||||
w.Restore()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Maximise()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Fullscreen()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.UnFullscreen()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Restore").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Restore()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.Hide()
|
||||
time.Sleep(2 * time.Second)
|
||||
w.Show()
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetAlwaysOnTop(true)
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetAlwaysOnTop(false)
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetURL("https://google.com")
|
||||
})
|
||||
})
|
||||
stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
w.SetURL("https://wails.io")
|
||||
})
|
||||
})
|
||||
stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) {
|
||||
screen, err := app.GetPrimaryScreen()
|
||||
if err != nil {
|
||||
app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
return
|
||||
}
|
||||
msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show()
|
||||
})
|
||||
stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) {
|
||||
screens, err := app.GetScreens()
|
||||
if err != nil {
|
||||
app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
return
|
||||
}
|
||||
for _, screen := range screens {
|
||||
msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
|
||||
}
|
||||
})
|
||||
stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) {
|
||||
currentWindow(func(w *application.WebviewWindow) {
|
||||
screen, err := w.GetScreen()
|
||||
if err != nil {
|
||||
app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
|
||||
return
|
||||
}
|
||||
msg := fmt.Sprintf("Screen: %+v", screen)
|
||||
app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
|
||||
})
|
||||
})
|
||||
app.NewWebviewWindow()
|
||||
|
||||
app.SetMenu(menu)
|
||||
//app.SetMenu(menu)
|
||||
err := app.Run()
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func main() {
|
|||
|
||||
newWindow := func() {
|
||||
windowName := "WebviewWindow " + strconv.Itoa(windowCounter)
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Name: windowName,
|
||||
}).
|
||||
SetTitle(windowName).
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Wails ML Demo",
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ module github.com/wailsapp/wails/v3
|
|||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/bep/debounce v1.2.1
|
||||
github.com/go-ole/go-ole v1.2.6
|
||||
github.com/go-task/task/v3 v3.20.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/jackmordaunt/icns/v2 v2.2.1
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/leaanthony/clir v1.6.0
|
||||
|
|
@ -16,7 +19,9 @@ require (
|
|||
github.com/pterm/pterm v0.12.51
|
||||
github.com/samber/lo v1.37.0
|
||||
github.com/tc-hib/winres v0.1.6
|
||||
github.com/wailsapp/go-webview2 v1.0.1
|
||||
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6
|
||||
golang.org/x/sys v0.8.0
|
||||
modernc.org/sqlite v1.21.0
|
||||
)
|
||||
|
||||
|
|
@ -27,8 +32,8 @@ require (
|
|||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gookit/color v1.5.2 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/joho/godotenv v1.4.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/leaanthony/slicer v1.5.0 // indirect
|
||||
|
|
@ -53,7 +58,6 @@ require (
|
|||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
|
|
|
|||
14
v3/go.sum
14
v3/go.sum
|
|
@ -12,6 +12,8 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/
|
|||
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
|
||||
github.com/MarvinJWendt/testza v0.5.1 h1:a9Fqx6vQrHQ4CyiaLhktfTTelwGotmFWy8MNhyaohw8=
|
||||
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
|
|
@ -23,6 +25,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
|||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/task/v3 v3.20.0 h1:pTavuhP+AiEpKLzh5I6Lja9Ux7ypYO5QMsEPTbhYEDc=
|
||||
|
|
@ -39,6 +43,8 @@ github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
|
|||
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
|
||||
github.com/jackmordaunt/icns/v2 v2.2.1 h1:MGklwYP2yohKn2Bw7XxlF69LZe98S1vUfl5OvAulPwg=
|
||||
github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
|
@ -138,6 +144,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8=
|
||||
github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
|
||||
github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II=
|
||||
github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||
|
|
@ -167,8 +175,10 @@ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
|||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -182,8 +192,8 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -124,3 +126,39 @@ func generateWindowsIcon(iconData []byte, sizes []int, options *IconsOptions) er
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenerateTemplateIcon(data []byte, outputFilename string) error {
|
||||
// Decode the input file as a PNG
|
||||
buffer := bytes.NewBuffer(data)
|
||||
img, err := png.Decode(buffer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode input file as PNG: %w", err)
|
||||
}
|
||||
|
||||
// Create a new image with the same dimensions and RGBA color model
|
||||
bounds := img.Bounds()
|
||||
iconImg := image.NewRGBA(bounds)
|
||||
|
||||
// Iterate over each pixel of the input image
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
// Get the alpha of the pixel
|
||||
_, _, _, a := img.At(x, y).RGBA()
|
||||
iconImg.SetRGBA(x, y, color.RGBA{R: 0, G: 0, B: 0, A: uint8(a)})
|
||||
}
|
||||
}
|
||||
|
||||
// Create the output file
|
||||
outFile, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %w", err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
// Encode the template icon image as a PNG and write it to the output file
|
||||
if err := png.Encode(outFile, iconImg); err != nil {
|
||||
return fmt.Errorf("failed to encode output image as PNG: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package debug
|
||||
|
||||
import (
|
||||
"github.com/samber/lo"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
"runtime/debug"
|
||||
|
||||
import "runtime/debug"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// Why go doesn't provide this as a map already is beyond me.
|
||||
var buildSettings = map[string]string{}
|
||||
|
|
@ -20,7 +20,7 @@ func init() {
|
|||
buildSettings = lo.Associate(buildInfo.Settings, func(setting debug.BuildSetting) (string, string) {
|
||||
return setting.Key, setting.Value
|
||||
})
|
||||
if isLocalBuild() {
|
||||
if isLocalBuild() || buildInfo.Path == "" {
|
||||
modulePath := RelativePath("..", "..", "..")
|
||||
LocalModulePath, _ = filepath.Abs(modulePath)
|
||||
}
|
||||
|
|
|
|||
21
v3/internal/go-common-file-dialog/LICENSE
Normal file
21
v3/internal/go-common-file-dialog/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Harry Phillips
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
31
v3/internal/go-common-file-dialog/README.md
Normal file
31
v3/internal/go-common-file-dialog/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Common File Dialog bindings for Golang
|
||||
|
||||
[Project Home](https://github.com/harry1453/go-common-file-dialog)
|
||||
|
||||
This library contains bindings for Windows Vista and
|
||||
newer's [Common File Dialogs](https://docs.microsoft.com/en-us/windows/win32/shell/common-file-dialog), which is the
|
||||
standard system dialog for selecting files or folders to open or save.
|
||||
|
||||
The Common File Dialogs have to be accessed via
|
||||
the [COM Interface](https://en.wikipedia.org/wiki/Component_Object_Model), normally via C++ or via bindings (like in C#)
|
||||
.
|
||||
|
||||
This library contains bindings for Golang. **It does not require CGO**, and contains empty stubs for non-windows
|
||||
platforms (so is safe to compile and run on platforms other than windows, but will just return errors at runtime).
|
||||
|
||||
This can be very useful if you want to quickly get a file selector in your Golang application. The `cfdutil` package
|
||||
contains utility functions with a single call to open and configure a dialog, and then get the result from it. Examples
|
||||
for this are in [`_examples/usingutil`](_examples/usingutil). Or, if you want finer control over the dialog's operation,
|
||||
you can use the base package. Examples for this are in [`_examples/notusingutil`](_examples/notusingutil).
|
||||
|
||||
This library is available under the MIT license.
|
||||
|
||||
Currently supported features:
|
||||
|
||||
* Open File Dialog (to open a single file)
|
||||
* Open Multiple Files Dialog (to open multiple files)
|
||||
* Open Folder Dialog
|
||||
* Save File Dialog
|
||||
* Dialog "roles" to allow Windows to remember different "last locations" for different types of dialog
|
||||
* Set dialog Title, Default Folder and Initial Folder
|
||||
* Set dialog File Filters
|
||||
72
v3/internal/go-common-file-dialog/cfd/CommonFileDialog.go
Normal file
72
v3/internal/go-common-file-dialog/cfd/CommonFileDialog.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Cross-platform.
|
||||
|
||||
// Common File Dialogs
|
||||
package cfd
|
||||
|
||||
type Dialog interface {
|
||||
// Show the dialog to the user.
|
||||
// Blocks until the user has closed the dialog.
|
||||
Show() error
|
||||
// Sets the dialog's parent window. Use 0 to set the dialog to have no parent window.
|
||||
SetParentWindowHandle(hwnd uintptr)
|
||||
// Show the dialog to the user.
|
||||
// Blocks until the user has closed the dialog and returns their selection.
|
||||
// Returns an error if the user cancelled the dialog.
|
||||
// Do not use for the Open Multiple Files dialog. Use ShowAndGetResults instead.
|
||||
ShowAndGetResult() (string, error)
|
||||
// Sets the title of the dialog window.
|
||||
SetTitle(title string) error
|
||||
// Sets the "role" of the dialog. This is used to derive the dialog's GUID, which the
|
||||
// OS will use to differentiate it from dialogs that are intended for other purposes.
|
||||
// This means that, for example, a dialog with role "Import" will have a different
|
||||
// previous location that it will open to than a dialog with role "Open". Can be any string.
|
||||
SetRole(role string) error
|
||||
// Sets the folder used as a default if there is not a recently used folder value available
|
||||
SetDefaultFolder(defaultFolder string) error
|
||||
// Sets the folder that the dialog always opens to.
|
||||
// If this is set, it will override the "default folder" behaviour and the dialog will always open to this folder.
|
||||
SetFolder(folder string) error
|
||||
// Gets the selected file or folder path, as an absolute path eg. "C:\Folder\file.txt"
|
||||
// Do not use for the Open Multiple Files dialog. Use GetResults instead.
|
||||
GetResult() (string, error)
|
||||
// Sets the file name, I.E. the contents of the file name text box.
|
||||
// For Select Folder Dialog, sets folder name.
|
||||
SetFileName(fileName string) error
|
||||
// Release the resources allocated to this Dialog.
|
||||
// Should be called when the dialog is finished with.
|
||||
Release() error
|
||||
}
|
||||
|
||||
type FileDialog interface {
|
||||
Dialog
|
||||
// Set the list of file filters that the user can select.
|
||||
SetFileFilters(fileFilter []FileFilter) error
|
||||
// Set the selected item from the list of file filters (set using SetFileFilters) by its index. Defaults to 0 (the first item in the list) if not called.
|
||||
SetSelectedFileFilterIndex(index uint) error
|
||||
// Sets the default extension applied when a user does not provide one as part of the file name.
|
||||
// If the user selects a different file filter, the default extension will be automatically updated to match the new file filter.
|
||||
// For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists.
|
||||
// For Save File Dialog, this extension will be used whenever a user does not specify an extension.
|
||||
SetDefaultExtension(defaultExtension string) error
|
||||
}
|
||||
|
||||
type OpenFileDialog interface {
|
||||
FileDialog
|
||||
}
|
||||
|
||||
type OpenMultipleFilesDialog interface {
|
||||
FileDialog
|
||||
// Show the dialog to the user.
|
||||
// Blocks until the user has closed the dialog and returns the selected files.
|
||||
ShowAndGetResults() ([]string, error)
|
||||
// Gets the selected file paths, as absolute paths eg. "C:\Folder\file.txt"
|
||||
GetResults() ([]string, error)
|
||||
}
|
||||
|
||||
type SelectFolderDialog interface {
|
||||
Dialog
|
||||
}
|
||||
|
||||
type SaveFileDialog interface { // TODO Properties
|
||||
FileDialog
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cfd
|
||||
|
||||
import "fmt"
|
||||
|
||||
var unsupportedError = fmt.Errorf("common file dialogs are only available on windows")
|
||||
|
||||
// TODO doc
|
||||
func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) {
|
||||
return nil, unsupportedError
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) {
|
||||
return nil, unsupportedError
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) {
|
||||
return nil, unsupportedError
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) {
|
||||
return nil, unsupportedError
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import "github.com/go-ole/go-ole"
|
||||
|
||||
func initialize() {
|
||||
// Swallow error
|
||||
_ = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE)
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewOpenFileDialog(config DialogConfig) (OpenFileDialog, error) {
|
||||
initialize()
|
||||
|
||||
openDialog, err := newIFileOpenDialog()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = config.apply(openDialog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return openDialog, nil
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewOpenMultipleFilesDialog(config DialogConfig) (OpenMultipleFilesDialog, error) {
|
||||
initialize()
|
||||
|
||||
openDialog, err := newIFileOpenDialog()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = config.apply(openDialog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = openDialog.setIsMultiselect(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return openDialog, nil
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewSelectFolderDialog(config DialogConfig) (SelectFolderDialog, error) {
|
||||
initialize()
|
||||
|
||||
openDialog, err := newIFileOpenDialog()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = config.apply(openDialog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = openDialog.setPickFolders(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return openDialog, nil
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func NewSaveFileDialog(config DialogConfig) (SaveFileDialog, error) {
|
||||
initialize()
|
||||
|
||||
saveDialog, err := newIFileSaveDialog()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = config.apply(saveDialog)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return saveDialog, nil
|
||||
}
|
||||
120
v3/internal/go-common-file-dialog/cfd/DialogConfig.go
Normal file
120
v3/internal/go-common-file-dialog/cfd/DialogConfig.go
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Cross-platform.
|
||||
|
||||
package cfd
|
||||
|
||||
type FileFilter struct {
|
||||
// The display name of the filter (That is shown to the user)
|
||||
DisplayName string
|
||||
// The filter pattern. Eg. "*.txt;*.png" to select all txt and png files, "*.*" to select any files, etc.
|
||||
Pattern string
|
||||
}
|
||||
|
||||
type DialogConfig struct {
|
||||
// The title of the dialog
|
||||
Title string
|
||||
// The role of the dialog. This is used to derive the dialog's GUID, which the
|
||||
// OS will use to differentiate it from dialogs that are intended for other purposes.
|
||||
// This means that, for example, a dialog with role "Import" will have a different
|
||||
// previous location that it will open to than a dialog with role "Open". Can be any string.
|
||||
Role string
|
||||
// The default folder - the folder that is used the first time the user opens it
|
||||
// (after the first time their last used location is used).
|
||||
DefaultFolder string
|
||||
// The initial folder - the folder that the dialog always opens to if not empty.
|
||||
// If this is not empty, it will override the "default folder" behaviour and
|
||||
// the dialog will always open to this folder.
|
||||
Folder string
|
||||
// The file filters that restrict which types of files the dialog is able to choose.
|
||||
// Ignored by Select Folder Dialog.
|
||||
FileFilters []FileFilter
|
||||
// Sets the initially selected file filter. This is an index of FileFilters.
|
||||
// Ignored by Select Folder Dialog.
|
||||
SelectedFileFilterIndex uint
|
||||
// The initial name of the file (I.E. the text in the file name text box) when the user opens the dialog.
|
||||
// For the Select Folder Dialog, this sets the initial folder name.
|
||||
FileName string
|
||||
// The default extension applied when a user does not provide one as part of the file name.
|
||||
// If the user selects a different file filter, the default extension will be automatically updated to match the new file filter.
|
||||
// For Open / Open Multiple File Dialog, this only has an effect when the user specifies a file name with no extension and a file with the default extension exists.
|
||||
// For Save File Dialog, this extension will be used whenever a user does not specify an extension.
|
||||
// Ignored by Select Folder Dialog.
|
||||
DefaultExtension string
|
||||
// ParentWindowHandle is the handle (HWND) to the parent window of the dialog.
|
||||
// If left as 0 / nil, the dialog will have no parent window.
|
||||
ParentWindowHandle uintptr
|
||||
}
|
||||
|
||||
var defaultFilters = []FileFilter{
|
||||
{
|
||||
DisplayName: "All Files (*.*)",
|
||||
Pattern: "*.*",
|
||||
},
|
||||
}
|
||||
|
||||
func (config *DialogConfig) apply(dialog Dialog) (err error) {
|
||||
if config.Title != "" {
|
||||
err = dialog.SetTitle(config.Title)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if config.Role != "" {
|
||||
err = dialog.SetRole(config.Role)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if config.Folder != "" {
|
||||
err = dialog.SetFolder(config.Folder)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if config.DefaultFolder != "" {
|
||||
err = dialog.SetDefaultFolder(config.DefaultFolder)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if config.FileName != "" {
|
||||
err = dialog.SetFileName(config.FileName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
dialog.SetParentWindowHandle(config.ParentWindowHandle)
|
||||
|
||||
if dialog, ok := dialog.(FileDialog); ok {
|
||||
var fileFilters []FileFilter
|
||||
if config.FileFilters != nil && len(config.FileFilters) > 0 {
|
||||
fileFilters = config.FileFilters
|
||||
} else {
|
||||
fileFilters = defaultFilters
|
||||
}
|
||||
err = dialog.SetFileFilters(fileFilters)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if config.SelectedFileFilterIndex != 0 {
|
||||
err = dialog.SetSelectedFileFilterIndex(config.SelectedFileFilterIndex)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if config.DefaultExtension != "" {
|
||||
err = dialog.SetDefaultExtension(config.DefaultExtension)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
7
v3/internal/go-common-file-dialog/cfd/errors.go
Normal file
7
v3/internal/go-common-file-dialog/cfd/errors.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package cfd
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrorCancelled = errors.New("cancelled by user")
|
||||
)
|
||||
201
v3/internal/go-common-file-dialog/cfd/iFileOpenDialog.go
Normal file
201
v3/internal/go-common-file-dialog/cfd/iFileOpenDialog.go
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/google/uuid"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
fileOpenDialogCLSID = ole.NewGUID("{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}")
|
||||
fileOpenDialogIID = ole.NewGUID("{d57c7288-d4ad-4768-be02-9d969532d960}")
|
||||
)
|
||||
|
||||
type iFileOpenDialog struct {
|
||||
vtbl *iFileOpenDialogVtbl
|
||||
parentWindowHandle uintptr
|
||||
}
|
||||
|
||||
type iFileOpenDialogVtbl struct {
|
||||
iFileDialogVtbl
|
||||
|
||||
GetResults uintptr // func (ppenum **IShellItemArray) HRESULT
|
||||
GetSelectedItems uintptr
|
||||
}
|
||||
|
||||
func newIFileOpenDialog() (*iFileOpenDialog, error) {
|
||||
if unknown, err := ole.CreateInstance(fileOpenDialogCLSID, fileOpenDialogIID); err == nil {
|
||||
return (*iFileOpenDialog)(unsafe.Pointer(unknown)), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) Show() error {
|
||||
return fileOpenDialog.vtbl.show(unsafe.Pointer(fileOpenDialog), fileOpenDialog.parentWindowHandle)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetParentWindowHandle(hwnd uintptr) {
|
||||
fileOpenDialog.parentWindowHandle = hwnd
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) ShowAndGetResult() (string, error) {
|
||||
isMultiselect, err := fileOpenDialog.isMultiselect()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if isMultiselect {
|
||||
// We should panic as this error is caused by the developer using the library
|
||||
panic("use ShowAndGetResults for open multiple files dialog")
|
||||
}
|
||||
if err := fileOpenDialog.Show(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fileOpenDialog.GetResult()
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) ShowAndGetResults() ([]string, error) {
|
||||
isMultiselect, err := fileOpenDialog.isMultiselect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isMultiselect {
|
||||
// We should panic as this error is caused by the developer using the library
|
||||
panic("use ShowAndGetResult for open single file dialog")
|
||||
}
|
||||
if err := fileOpenDialog.Show(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fileOpenDialog.GetResults()
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetTitle(title string) error {
|
||||
return fileOpenDialog.vtbl.setTitle(unsafe.Pointer(fileOpenDialog), title)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) GetResult() (string, error) {
|
||||
isMultiselect, err := fileOpenDialog.isMultiselect()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if isMultiselect {
|
||||
// We should panic as this error is caused by the developer using the library
|
||||
panic("use GetResults for open multiple files dialog")
|
||||
}
|
||||
return fileOpenDialog.vtbl.getResultString(unsafe.Pointer(fileOpenDialog))
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) Release() error {
|
||||
return fileOpenDialog.vtbl.release(unsafe.Pointer(fileOpenDialog))
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetDefaultFolder(defaultFolderPath string) error {
|
||||
return fileOpenDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetFolder(defaultFolderPath string) error {
|
||||
return fileOpenDialog.vtbl.setFolder(unsafe.Pointer(fileOpenDialog), defaultFolderPath)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetFileFilters(filter []FileFilter) error {
|
||||
return fileOpenDialog.vtbl.setFileTypes(unsafe.Pointer(fileOpenDialog), filter)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetRole(role string) error {
|
||||
return fileOpenDialog.vtbl.setClientGuid(unsafe.Pointer(fileOpenDialog), StringToUUID(role))
|
||||
}
|
||||
|
||||
// This should only be callable when the user asks for a multi select because
|
||||
// otherwise they will be given the Dialog interface which does not expose this function.
|
||||
func (fileOpenDialog *iFileOpenDialog) GetResults() ([]string, error) {
|
||||
isMultiselect, err := fileOpenDialog.isMultiselect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isMultiselect {
|
||||
// We should panic as this error is caused by the developer using the library
|
||||
panic("use GetResult for open single file dialog")
|
||||
}
|
||||
return fileOpenDialog.vtbl.getResultsStrings(unsafe.Pointer(fileOpenDialog))
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetDefaultExtension(defaultExtension string) error {
|
||||
return fileOpenDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileOpenDialog), defaultExtension)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetFileName(initialFileName string) error {
|
||||
return fileOpenDialog.vtbl.setFileName(unsafe.Pointer(fileOpenDialog), initialFileName)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) SetSelectedFileFilterIndex(index uint) error {
|
||||
return fileOpenDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileOpenDialog), index)
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) setPickFolders(pickFolders bool) error {
|
||||
const FosPickfolders = 0x20
|
||||
if pickFolders {
|
||||
return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
|
||||
} else {
|
||||
return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosPickfolders)
|
||||
}
|
||||
}
|
||||
|
||||
const FosAllowMultiselect = 0x200
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) isMultiselect() (bool, error) {
|
||||
options, err := fileOpenDialog.vtbl.getOptions(unsafe.Pointer(fileOpenDialog))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return options&FosAllowMultiselect != 0, nil
|
||||
}
|
||||
|
||||
func (fileOpenDialog *iFileOpenDialog) setIsMultiselect(isMultiselect bool) error {
|
||||
if isMultiselect {
|
||||
return fileOpenDialog.vtbl.addOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
|
||||
} else {
|
||||
return fileOpenDialog.vtbl.removeOption(unsafe.Pointer(fileOpenDialog), FosAllowMultiselect)
|
||||
}
|
||||
}
|
||||
|
||||
func (vtbl *iFileOpenDialogVtbl) getResults(objPtr unsafe.Pointer) (*iShellItemArray, error) {
|
||||
var shellItemArray *iShellItemArray
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetResults,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(&shellItemArray)),
|
||||
0)
|
||||
return shellItemArray, hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileOpenDialogVtbl) getResultsStrings(objPtr unsafe.Pointer) ([]string, error) {
|
||||
shellItemArray, err := vtbl.getResults(objPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if shellItemArray == nil {
|
||||
return nil, ErrorCancelled
|
||||
}
|
||||
defer shellItemArray.vtbl.release(unsafe.Pointer(shellItemArray))
|
||||
count, err := shellItemArray.vtbl.getCount(unsafe.Pointer(shellItemArray))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var results []string
|
||||
for i := uintptr(0); i < count; i++ {
|
||||
newItem, err := shellItemArray.vtbl.getItemAt(unsafe.Pointer(shellItemArray), i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, newItem)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func StringToUUID(str string) *ole.GUID {
|
||||
return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String())
|
||||
}
|
||||
92
v3/internal/go-common-file-dialog/cfd/iFileSaveDialog.go
Normal file
92
v3/internal/go-common-file-dialog/cfd/iFileSaveDialog.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
saveFileDialogCLSID = ole.NewGUID("{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}")
|
||||
saveFileDialogIID = ole.NewGUID("{84bccd23-5fde-4cdb-aea4-af64b83d78ab}")
|
||||
)
|
||||
|
||||
type iFileSaveDialog struct {
|
||||
vtbl *iFileSaveDialogVtbl
|
||||
parentWindowHandle uintptr
|
||||
}
|
||||
|
||||
type iFileSaveDialogVtbl struct {
|
||||
iFileDialogVtbl
|
||||
|
||||
SetSaveAsItem uintptr
|
||||
SetProperties uintptr
|
||||
SetCollectedProperties uintptr
|
||||
GetProperties uintptr
|
||||
ApplyProperties uintptr
|
||||
}
|
||||
|
||||
func newIFileSaveDialog() (*iFileSaveDialog, error) {
|
||||
if unknown, err := ole.CreateInstance(saveFileDialogCLSID, saveFileDialogIID); err == nil {
|
||||
return (*iFileSaveDialog)(unsafe.Pointer(unknown)), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) Show() error {
|
||||
return fileSaveDialog.vtbl.show(unsafe.Pointer(fileSaveDialog), fileSaveDialog.parentWindowHandle)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetParentWindowHandle(hwnd uintptr) {
|
||||
fileSaveDialog.parentWindowHandle = hwnd
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) ShowAndGetResult() (string, error) {
|
||||
if err := fileSaveDialog.Show(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fileSaveDialog.GetResult()
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetTitle(title string) error {
|
||||
return fileSaveDialog.vtbl.setTitle(unsafe.Pointer(fileSaveDialog), title)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) GetResult() (string, error) {
|
||||
return fileSaveDialog.vtbl.getResultString(unsafe.Pointer(fileSaveDialog))
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) Release() error {
|
||||
return fileSaveDialog.vtbl.release(unsafe.Pointer(fileSaveDialog))
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetDefaultFolder(defaultFolderPath string) error {
|
||||
return fileSaveDialog.vtbl.setDefaultFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetFolder(defaultFolderPath string) error {
|
||||
return fileSaveDialog.vtbl.setFolder(unsafe.Pointer(fileSaveDialog), defaultFolderPath)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetFileFilters(filter []FileFilter) error {
|
||||
return fileSaveDialog.vtbl.setFileTypes(unsafe.Pointer(fileSaveDialog), filter)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetRole(role string) error {
|
||||
return fileSaveDialog.vtbl.setClientGuid(unsafe.Pointer(fileSaveDialog), StringToUUID(role))
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetDefaultExtension(defaultExtension string) error {
|
||||
return fileSaveDialog.vtbl.setDefaultExtension(unsafe.Pointer(fileSaveDialog), defaultExtension)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetFileName(initialFileName string) error {
|
||||
return fileSaveDialog.vtbl.setFileName(unsafe.Pointer(fileSaveDialog), initialFileName)
|
||||
}
|
||||
|
||||
func (fileSaveDialog *iFileSaveDialog) SetSelectedFileFilterIndex(index uint) error {
|
||||
return fileSaveDialog.vtbl.setSelectedFileFilterIndex(unsafe.Pointer(fileSaveDialog), index)
|
||||
}
|
||||
53
v3/internal/go-common-file-dialog/cfd/iShellItem.go
Normal file
53
v3/internal/go-common-file-dialog/cfd/iShellItem.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
procSHCreateItemFromParsingName = syscall.NewLazyDLL("Shell32.dll").NewProc("SHCreateItemFromParsingName")
|
||||
iidShellItem = ole.NewGUID("43826d1e-e718-42ee-bc55-a1e261c37bfe")
|
||||
)
|
||||
|
||||
type iShellItem struct {
|
||||
vtbl *iShellItemVtbl
|
||||
}
|
||||
|
||||
type iShellItemVtbl struct {
|
||||
iUnknownVtbl
|
||||
BindToHandler uintptr
|
||||
GetParent uintptr
|
||||
GetDisplayName uintptr // func (sigdnName SIGDN, ppszName *LPWSTR) HRESULT
|
||||
GetAttributes uintptr
|
||||
Compare uintptr
|
||||
}
|
||||
|
||||
func newIShellItem(path string) (*iShellItem, error) {
|
||||
var shellItem *iShellItem
|
||||
pathPtr := ole.SysAllocString(path)
|
||||
ret, _, _ := procSHCreateItemFromParsingName.Call(
|
||||
uintptr(unsafe.Pointer(pathPtr)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(iidShellItem)),
|
||||
uintptr(unsafe.Pointer(&shellItem)))
|
||||
return shellItem, hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iShellItemVtbl) getDisplayName(objPtr unsafe.Pointer) (string, error) {
|
||||
var ptr *uint16
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetDisplayName,
|
||||
2,
|
||||
uintptr(objPtr),
|
||||
0x80058000, // SIGDN_FILESYSPATH
|
||||
uintptr(unsafe.Pointer(&ptr)))
|
||||
if err := hresultToError(ret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(ptr)))
|
||||
return ole.LpOleStrToString(ptr), nil
|
||||
}
|
||||
67
v3/internal/go-common-file-dialog/cfd/iShellItemArray.go
Normal file
67
v3/internal/go-common-file-dialog/cfd/iShellItemArray.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
iidShellItemArrayGUID = "{b63ea76d-1f85-456f-a19c-48159efa858b}"
|
||||
)
|
||||
|
||||
var (
|
||||
iidShellItemArray *ole.GUID
|
||||
)
|
||||
|
||||
func init() {
|
||||
iidShellItemArray, _ = ole.IIDFromString(iidShellItemArrayGUID)
|
||||
}
|
||||
|
||||
type iShellItemArray struct {
|
||||
vtbl *iShellItemArrayVtbl
|
||||
}
|
||||
|
||||
type iShellItemArrayVtbl struct {
|
||||
iUnknownVtbl
|
||||
BindToHandler uintptr
|
||||
GetPropertyStore uintptr
|
||||
GetPropertyDescriptionList uintptr
|
||||
GetAttributes uintptr
|
||||
GetCount uintptr // func (pdwNumItems *DWORD) HRESULT
|
||||
GetItemAt uintptr // func (dwIndex DWORD, ppsi **IShellItem) HRESULT
|
||||
EnumItems uintptr
|
||||
}
|
||||
|
||||
func (vtbl *iShellItemArrayVtbl) getCount(objPtr unsafe.Pointer) (uintptr, error) {
|
||||
var count uintptr
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetCount,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(&count)),
|
||||
0)
|
||||
if err := hresultToError(ret); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (vtbl *iShellItemArrayVtbl) getItemAt(objPtr unsafe.Pointer, index uintptr) (string, error) {
|
||||
var shellItem *iShellItem
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetItemAt,
|
||||
2,
|
||||
uintptr(objPtr),
|
||||
index,
|
||||
uintptr(unsafe.Pointer(&shellItem)))
|
||||
if err := hresultToError(ret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if shellItem == nil {
|
||||
return "", ErrorCancelled
|
||||
}
|
||||
defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
|
||||
return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem))
|
||||
}
|
||||
48
v3/internal/go-common-file-dialog/cfd/vtblCommon.go
Normal file
48
v3/internal/go-common-file-dialog/cfd/vtblCommon.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
type comDlgFilterSpec struct {
|
||||
pszName *int16
|
||||
pszSpec *int16
|
||||
}
|
||||
|
||||
type iUnknownVtbl struct {
|
||||
QueryInterface uintptr
|
||||
AddRef uintptr
|
||||
Release uintptr
|
||||
}
|
||||
|
||||
type iModalWindowVtbl struct {
|
||||
iUnknownVtbl
|
||||
Show uintptr // func (hwndOwner HWND) HRESULT
|
||||
}
|
||||
|
||||
type iFileDialogVtbl struct {
|
||||
iModalWindowVtbl
|
||||
SetFileTypes uintptr // func (cFileTypes UINT, rgFilterSpec *COMDLG_FILTERSPEC) HRESULT
|
||||
SetFileTypeIndex uintptr // func(iFileType UINT) HRESULT
|
||||
GetFileTypeIndex uintptr
|
||||
Advise uintptr
|
||||
Unadvise uintptr
|
||||
SetOptions uintptr // func (fos FILEOPENDIALOGOPTIONS) HRESULT
|
||||
GetOptions uintptr // func (pfos *FILEOPENDIALOGOPTIONS) HRESULT
|
||||
SetDefaultFolder uintptr // func (psi *IShellItem) HRESULT
|
||||
SetFolder uintptr // func (psi *IShellItem) HRESULT
|
||||
GetFolder uintptr
|
||||
GetCurrentSelection uintptr
|
||||
SetFileName uintptr // func (pszName LPCWSTR) HRESULT
|
||||
GetFileName uintptr
|
||||
SetTitle uintptr // func(pszTitle LPCWSTR) HRESULT
|
||||
SetOkButtonLabel uintptr
|
||||
SetFileNameLabel uintptr
|
||||
GetResult uintptr // func (ppsi **IShellItem) HRESULT
|
||||
AddPlace uintptr
|
||||
SetDefaultExtension uintptr // func (pszDefaultExtension LPCWSTR) HRESULT
|
||||
// This can only be used from a callback.
|
||||
Close uintptr
|
||||
SetClientGuid uintptr // func (guid REFGUID) HRESULT
|
||||
ClearClientData uintptr
|
||||
SetFilter uintptr
|
||||
}
|
||||
227
v3/internal/go-common-file-dialog/cfd/vtblCommonFunc.go
Normal file
227
v3/internal/go-common-file-dialog/cfd/vtblCommonFunc.go
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cfd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-ole/go-ole"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func hresultToError(hr uintptr) error {
|
||||
if hr < 0 {
|
||||
return ole.NewError(hr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vtbl *iUnknownVtbl) release(objPtr unsafe.Pointer) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.Release,
|
||||
0,
|
||||
uintptr(objPtr),
|
||||
0,
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iModalWindowVtbl) show(objPtr unsafe.Pointer, hwnd uintptr) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.Show,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
hwnd,
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setFileTypes(objPtr unsafe.Pointer, filters []FileFilter) error {
|
||||
cFileTypes := len(filters)
|
||||
if cFileTypes < 0 {
|
||||
return fmt.Errorf("must specify at least one filter")
|
||||
}
|
||||
comDlgFilterSpecs := make([]comDlgFilterSpec, cFileTypes)
|
||||
for i := 0; i < cFileTypes; i++ {
|
||||
filter := &filters[i]
|
||||
comDlgFilterSpecs[i] = comDlgFilterSpec{
|
||||
pszName: ole.SysAllocString(filter.DisplayName),
|
||||
pszSpec: ole.SysAllocString(filter.Pattern),
|
||||
}
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetFileTypes,
|
||||
2,
|
||||
uintptr(objPtr),
|
||||
uintptr(cFileTypes),
|
||||
uintptr(unsafe.Pointer(&comDlgFilterSpecs[0])))
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
// Options are:
|
||||
// FOS_OVERWRITEPROMPT = 0x2,
|
||||
// FOS_STRICTFILETYPES = 0x4,
|
||||
// FOS_NOCHANGEDIR = 0x8,
|
||||
// FOS_PICKFOLDERS = 0x20,
|
||||
// FOS_FORCEFILESYSTEM = 0x40,
|
||||
// FOS_ALLNONSTORAGEITEMS = 0x80,
|
||||
// FOS_NOVALIDATE = 0x100,
|
||||
// FOS_ALLOWMULTISELECT = 0x200,
|
||||
// FOS_PATHMUSTEXIST = 0x800,
|
||||
// FOS_FILEMUSTEXIST = 0x1000,
|
||||
// FOS_CREATEPROMPT = 0x2000,
|
||||
// FOS_SHAREAWARE = 0x4000,
|
||||
// FOS_NOREADONLYRETURN = 0x8000,
|
||||
// FOS_NOTESTFILECREATE = 0x10000,
|
||||
// FOS_HIDEMRUPLACES = 0x20000,
|
||||
// FOS_HIDEPINNEDPLACES = 0x40000,
|
||||
// FOS_NODEREFERENCELINKS = 0x100000,
|
||||
// FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
|
||||
// FOS_DONTADDTORECENT = 0x2000000,
|
||||
// FOS_FORCESHOWHIDDEN = 0x10000000,
|
||||
// FOS_DEFAULTNOMINIMODE = 0x20000000,
|
||||
// FOS_FORCEPREVIEWPANEON = 0x40000000,
|
||||
// FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
|
||||
func (vtbl *iFileDialogVtbl) setOptions(objPtr unsafe.Pointer, options uint32) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetOptions,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(options),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) getOptions(objPtr unsafe.Pointer) (uint32, error) {
|
||||
var options uint32
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetOptions,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(&options)),
|
||||
0)
|
||||
return options, hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) addOption(objPtr unsafe.Pointer, option uint32) error {
|
||||
if options, err := vtbl.getOptions(objPtr); err == nil {
|
||||
return vtbl.setOptions(objPtr, options|option)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) removeOption(objPtr unsafe.Pointer, option uint32) error {
|
||||
if options, err := vtbl.getOptions(objPtr); err == nil {
|
||||
return vtbl.setOptions(objPtr, options&^option)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setDefaultFolder(objPtr unsafe.Pointer, path string) error {
|
||||
shellItem, err := newIShellItem(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetDefaultFolder,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(shellItem)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setFolder(objPtr unsafe.Pointer, path string) error {
|
||||
shellItem, err := newIShellItem(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetFolder,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(shellItem)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setTitle(objPtr unsafe.Pointer, title string) error {
|
||||
titlePtr := ole.SysAllocString(title)
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetTitle,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(titlePtr)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) close(objPtr unsafe.Pointer) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.Close,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
0,
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) getResult(objPtr unsafe.Pointer) (*iShellItem, error) {
|
||||
var shellItem *iShellItem
|
||||
ret, _, _ := syscall.Syscall(vtbl.GetResult,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(&shellItem)),
|
||||
0)
|
||||
return shellItem, hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) getResultString(objPtr unsafe.Pointer) (string, error) {
|
||||
shellItem, err := vtbl.getResult(objPtr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if shellItem == nil {
|
||||
return "", ErrorCancelled
|
||||
}
|
||||
defer shellItem.vtbl.release(unsafe.Pointer(shellItem))
|
||||
return shellItem.vtbl.getDisplayName(unsafe.Pointer(shellItem))
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setClientGuid(objPtr unsafe.Pointer, guid *ole.GUID) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetClientGuid,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(guid)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setDefaultExtension(objPtr unsafe.Pointer, defaultExtension string) error {
|
||||
if defaultExtension[0] == '.' {
|
||||
defaultExtension = strings.TrimPrefix(defaultExtension, ".")
|
||||
}
|
||||
defaultExtensionPtr := ole.SysAllocString(defaultExtension)
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetDefaultExtension,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(defaultExtensionPtr)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setFileName(objPtr unsafe.Pointer, fileName string) error {
|
||||
fileNamePtr := ole.SysAllocString(fileName)
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetFileName,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(unsafe.Pointer(fileNamePtr)),
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
|
||||
func (vtbl *iFileDialogVtbl) setSelectedFileFilterIndex(objPtr unsafe.Pointer, index uint) error {
|
||||
ret, _, _ := syscall.Syscall(vtbl.SetFileTypeIndex,
|
||||
1,
|
||||
uintptr(objPtr),
|
||||
uintptr(index+1), // SetFileTypeIndex counts from 1
|
||||
0)
|
||||
return hresultToError(ret)
|
||||
}
|
||||
45
v3/internal/go-common-file-dialog/cfdutil/CFDUtil.go
Normal file
45
v3/internal/go-common-file-dialog/cfdutil/CFDUtil.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package cfdutil
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v3/internal/go-common-file-dialog/cfd"
|
||||
)
|
||||
|
||||
// TODO doc
|
||||
func ShowOpenFileDialog(config cfd.DialogConfig) (string, error) {
|
||||
dialog, err := cfd.NewOpenFileDialog(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer dialog.Release()
|
||||
return dialog.ShowAndGetResult()
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func ShowOpenMultipleFilesDialog(config cfd.DialogConfig) ([]string, error) {
|
||||
dialog, err := cfd.NewOpenMultipleFilesDialog(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dialog.Release()
|
||||
return dialog.ShowAndGetResults()
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func ShowPickFolderDialog(config cfd.DialogConfig) (string, error) {
|
||||
dialog, err := cfd.NewSelectFolderDialog(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer dialog.Release()
|
||||
return dialog.ShowAndGetResult()
|
||||
}
|
||||
|
||||
// TODO doc
|
||||
func ShowSaveFileDialog(config cfd.DialogConfig) (string, error) {
|
||||
dialog, err := cfd.NewSaveFileDialog(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer dialog.Release()
|
||||
return dialog.ShowAndGetResult()
|
||||
}
|
||||
10
v3/internal/go-common-file-dialog/util/util.go
Normal file
10
v3/internal/go-common-file-dialog/util/util.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func StringToUUID(str string) *ole.GUID {
|
||||
return ole.NewGUID(uuid.NewSHA1(uuid.Nil, []byte(str)).String())
|
||||
}
|
||||
14
v3/internal/go-common-file-dialog/util/util_test.go
Normal file
14
v3/internal/go-common-file-dialog/util/util_test.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"github.com/go-ole/go-ole"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringToUUID(t *testing.T) {
|
||||
generated := *StringToUUID("TestTestTest")
|
||||
expected := *ole.NewGUID("7933985F-2C87-5A5B-A26E-5D0326829AC2")
|
||||
if generated != expected {
|
||||
t.Errorf("not equal. expected %s, found %s", expected.String(), generated.String())
|
||||
}
|
||||
}
|
||||
2
v3/internal/runtime/.gitignore
vendored
Normal file
2
v3/internal/runtime/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
.task
|
||||
108
v3/internal/runtime/Taskfile.yaml
Normal file
108
v3/internal/runtime/Taskfile.yaml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# https://taskfile.dev
|
||||
|
||||
version: "3"
|
||||
|
||||
tasks:
|
||||
install-deps:
|
||||
internal: true
|
||||
sources:
|
||||
- package.json
|
||||
cmds:
|
||||
- npm install
|
||||
|
||||
test:
|
||||
cmds:
|
||||
- npx vitest run
|
||||
|
||||
update:
|
||||
cmds:
|
||||
- npx npm-check-updates -u
|
||||
|
||||
build:debug:
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --tree-shaking=true --sourcemap=inline --outfile=runtime_debug_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
|
||||
|
||||
build:debug:windows:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
INVOKE: "chrome.webview.postMessage"
|
||||
|
||||
build:debug:linux:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:debug:darwin:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:production:
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --tree-shaking=true --minify --outfile=runtime_production_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
|
||||
|
||||
build:production:windows:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
INVOKE: "chrome.webview.postMessage"
|
||||
|
||||
build:production:linux:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:production:darwin:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:all:
|
||||
internal: true
|
||||
deps:
|
||||
- build:debug:windows
|
||||
- build:debug:linux
|
||||
- build:debug:darwin
|
||||
- build:production:windows
|
||||
- build:production:linux
|
||||
- build:production:darwin
|
||||
|
||||
cmds:
|
||||
- cmd: echo "Build Complete."
|
||||
|
||||
build:
|
||||
deps:
|
||||
- install-deps
|
||||
cmds:
|
||||
- task: build:all
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
# README
|
||||
|
||||
After updating any files in this directory, you must run `wails task build-runtime` to regenerate the compiled JS.
|
||||
After updating any files in this directory, you must run `wails task build:runtime` to regenerate the compiled JS.
|
||||
69
v3/internal/runtime/desktop/drag.js
Normal file
69
v3/internal/runtime/desktop/drag.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {invoke} from "./invoke";
|
||||
|
||||
let shouldDrag = false;
|
||||
|
||||
export function dragTest(e) {
|
||||
let val = window.getComputedStyle(e.target).getPropertyValue("--wails-draggable");
|
||||
if (val) {
|
||||
val = val.trim();
|
||||
}
|
||||
|
||||
if (val !== "drag") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only process the primary button
|
||||
if (e.buttons !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return e.detail === 1;
|
||||
}
|
||||
|
||||
export function setupDrag() {
|
||||
window.addEventListener('mousedown', onMouseDown);
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
if (dragTest(e)) {
|
||||
// Ignore drag on scrollbars
|
||||
if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
|
||||
return;
|
||||
}
|
||||
shouldDrag = true;
|
||||
} else {
|
||||
shouldDrag = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
document.body.style.cursor = window.wails.previousCursor || 'auto';
|
||||
shouldDrag = false;
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
if (shouldDrag) {
|
||||
shouldDrag = false;
|
||||
let mousePressed = e.buttons !== undefined ? e.buttons : e.which;
|
||||
if (mousePressed > 0) {
|
||||
window.wails.previousCursor = document.body.style.cursor;
|
||||
document.body.style.cursor = 'grab';
|
||||
invoke("drag");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
v3/internal/runtime/desktop/invoke.js
Normal file
14
v3/internal/runtime/desktop/invoke.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
// defined in the Taskfile
|
||||
export let invoke = (WINDOWS?chrome.webview.postMessage:window.webkit.messageHandlers.external.postMessage);
|
||||
|
|
@ -20,6 +20,7 @@ import {dispatchWailsEvent, Emit, Off, OffAll, On, Once, OnMultiple} from "./eve
|
|||
import {dialogCallback, dialogErrorCallback, Error, Info, OpenFile, Question, SaveFile, Warning,} from "./dialogs";
|
||||
import {enableContextMenus} from "./contextmenu";
|
||||
import {reloadWML} from "./wml";
|
||||
import {setupDrag} from "./drag";
|
||||
|
||||
window.wails = {
|
||||
...newRuntime(null),
|
||||
|
|
@ -78,6 +79,8 @@ if (DEBUG) {
|
|||
|
||||
enableContextMenus(true);
|
||||
|
||||
setupDrag();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
reloadWML();
|
||||
});
|
||||
366
v3/internal/runtime/package-lock.json
generated
366
v3/internal/runtime/package-lock.json
generated
|
|
@ -9,7 +9,7 @@
|
|||
"version": "3.0.0",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"happy-dom": "^8.1.5",
|
||||
"nanoid": "^4.0.0",
|
||||
"npm-check-updates": "^16.6.3",
|
||||
|
|
@ -18,9 +18,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.5.tgz",
|
||||
"integrity": "sha512-crmPUzgCmF+qZXfl1YkiFoUta2XAfixR1tEnr/gXIixE+WL8Z0BGqfydP5oox0EUOgQMMRgtATtakyAcClQVqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
|
||||
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -34,9 +34,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-KHWkDqYAMmKZjY4RAN1PR96q6UOtfkWlTS8uEwWxdLtkRt/0F/csUhXIrVfaSIFxnscIBMPynGfhsMwQDRIBQw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -50,9 +50,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-8fI/AnIdmWz/+1iza2WrCw8kwXK9wZp/yZY/iS8ioC+U37yJCeppi9EHY05ewJKN64ASoBIseufZROtcFnX5GA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -66,9 +66,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-EAvaoyIySV6Iif3NQCglUNpnMfHSUgC5ugt2efl3+QDntucJe5spn0udNZjTgNi6tKVqSceOw9tQ32liNZc1Xw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -82,9 +82,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-ha7QCJh1fuSwwCgoegfdaljowwWozwTDjBgjD3++WAy/qwee5uUi1gvOg2WENJC6EUyHBOkcd3YmLDYSZ2TPPA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -98,9 +98,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-VbdXJkn2aI2pQ/wxNEjEcnEDwPpxt3CWWMFYmO7CcdFBoOsABRy2W8F3kjbF9F/pecEUDcI3b5i2w+By4VQFPg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -114,9 +114,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-olgGYND1/XnnWxwhjtY3/ryjOG/M4WfcA6XH8dBTH1cxMeBemMODXSFhkw71Kf4TeZFFTN25YOomaNh0vq2iXg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -130,9 +130,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.5.tgz",
|
||||
"integrity": "sha512-YBdCyQwA3OQupi6W2/WO4FnI+NWFWe79cZEtlbqSESOHEg7a73htBIRiE6uHPQe7Yp5E4aALv+JxkRLGEUL7tw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
|
||||
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -146,9 +146,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-8a0bqSwu3OlLCfu2FBbDNgQyBYdPJh1B9PvNX7jMaKGC9/KopgHs37t+pQqeMLzcyRqG6z55IGNQAMSlCpBuqg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -162,9 +162,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.5.tgz",
|
||||
"integrity": "sha512-uCwm1r/+NdP7vndctgq3PoZrnmhmnecWAr114GWMRwg2QMFFX+kIWnp7IO220/JLgnXK/jP7VKAFBGmeOYBQYQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
|
||||
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
|
@ -178,9 +178,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.5.tgz",
|
||||
"integrity": "sha512-3YxhSBl5Sb6TtBjJu+HP93poBruFzgXmf3PVfIe4xOXMj1XpxboYZyw3W8BhoX/uwxzZz4K1I99jTE/5cgDT1g==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
|
||||
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
|
|
@ -194,9 +194,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.5.tgz",
|
||||
"integrity": "sha512-Hy5Z0YVWyYHdtQ5mfmfp8LdhVwGbwVuq8mHzLqrG16BaMgEmit2xKO+iDakHs+OetEx0EN/2mUzDdfdktI+Nmg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
|
||||
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
|
|
@ -210,9 +210,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.5.tgz",
|
||||
"integrity": "sha512-5dbQvBLbU/Y3Q4ABc9gi23hww1mQcM7KZ9KBqabB7qhJswYMf8WrDDOSw3gdf3p+ffmijMd28mfVMvFucuECyg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
|
||||
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
|
@ -226,9 +226,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.5.tgz",
|
||||
"integrity": "sha512-fp/KUB/ZPzEWGTEUgz9wIAKCqu7CjH1GqXUO2WJdik1UNBQ7Xzw7myIajpxztE4Csb9504ERiFMxZg5KZ6HlZQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
|
||||
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
|
@ -242,9 +242,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.5.tgz",
|
||||
"integrity": "sha512-kRV3yw19YDqHTp8SfHXfObUFXlaiiw4o2lvT1XjsPZ++22GqZwSsYWJLjMi1Sl7j9qDlDUduWDze/nQx0d6Lzw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
|
||||
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
|
@ -258,9 +258,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-vnxuhh9e4pbtABNLbT2ANW4uwQ/zvcHRCm1JxaYkzSehugoFd5iXyC4ci1nhXU13mxEwCnrnTIiiSGwa/uAF1g==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -274,9 +274,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-cigBpdiSx/vPy7doUyImsQQBnBjV5f1M99ZUlaJckDAJjgXWl6y9W17FIfJTy8TxosEF6MXq+fpLsitMGts2nA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -290,9 +290,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-VdqRqPVIjjZfkf40LrqOaVuhw9EQiAZ/GNCSM2UplDkaIzYVsSnycxcFfAnHdWI8Gyt6dO15KHikbpxwx+xHbw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -306,9 +306,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-ItxPaJ3MBLtI4nK+mALLEoUs6amxsx+J1ibnfcYMkqaCqHST1AkF4aENpBehty3czqw64r/XqL+W9WqU6kc2Qw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -322,9 +322,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-4u2Q6qsJTYNFdS9zHoAi80spzf78C16m2wla4eJPh4kSbRv+BpXIfl6TmBSWupD8e47B1NrTfrOlEuco7mYQtg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -338,9 +338,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.5.tgz",
|
||||
"integrity": "sha512-KYlm+Xu9TXsfTWAcocLuISRtqxKp/Y9ZBVg6CEEj0O5J9mn7YvBKzAszo2j1ndyzUPk+op+Tie2PJeN+BnXGqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
|
||||
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
|
@ -354,9 +354,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-XgA9qWRqby7xdYXuF6KALsn37QGBMHsdhmnpjfZtYxKxbTOwfnDM6MYi2WuUku5poNaX2n9XGVr20zgT/2QwCw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1451,9 +1451,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.5.tgz",
|
||||
"integrity": "sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
||||
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
|
|
@ -1463,28 +1463,28 @@
|
|||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/android-arm": "0.17.5",
|
||||
"@esbuild/android-arm64": "0.17.5",
|
||||
"@esbuild/android-x64": "0.17.5",
|
||||
"@esbuild/darwin-arm64": "0.17.5",
|
||||
"@esbuild/darwin-x64": "0.17.5",
|
||||
"@esbuild/freebsd-arm64": "0.17.5",
|
||||
"@esbuild/freebsd-x64": "0.17.5",
|
||||
"@esbuild/linux-arm": "0.17.5",
|
||||
"@esbuild/linux-arm64": "0.17.5",
|
||||
"@esbuild/linux-ia32": "0.17.5",
|
||||
"@esbuild/linux-loong64": "0.17.5",
|
||||
"@esbuild/linux-mips64el": "0.17.5",
|
||||
"@esbuild/linux-ppc64": "0.17.5",
|
||||
"@esbuild/linux-riscv64": "0.17.5",
|
||||
"@esbuild/linux-s390x": "0.17.5",
|
||||
"@esbuild/linux-x64": "0.17.5",
|
||||
"@esbuild/netbsd-x64": "0.17.5",
|
||||
"@esbuild/openbsd-x64": "0.17.5",
|
||||
"@esbuild/sunos-x64": "0.17.5",
|
||||
"@esbuild/win32-arm64": "0.17.5",
|
||||
"@esbuild/win32-ia32": "0.17.5",
|
||||
"@esbuild/win32-x64": "0.17.5"
|
||||
"@esbuild/android-arm": "0.17.19",
|
||||
"@esbuild/android-arm64": "0.17.19",
|
||||
"@esbuild/android-x64": "0.17.19",
|
||||
"@esbuild/darwin-arm64": "0.17.19",
|
||||
"@esbuild/darwin-x64": "0.17.19",
|
||||
"@esbuild/freebsd-arm64": "0.17.19",
|
||||
"@esbuild/freebsd-x64": "0.17.19",
|
||||
"@esbuild/linux-arm": "0.17.19",
|
||||
"@esbuild/linux-arm64": "0.17.19",
|
||||
"@esbuild/linux-ia32": "0.17.19",
|
||||
"@esbuild/linux-loong64": "0.17.19",
|
||||
"@esbuild/linux-mips64el": "0.17.19",
|
||||
"@esbuild/linux-ppc64": "0.17.19",
|
||||
"@esbuild/linux-riscv64": "0.17.19",
|
||||
"@esbuild/linux-s390x": "0.17.19",
|
||||
"@esbuild/linux-x64": "0.17.19",
|
||||
"@esbuild/netbsd-x64": "0.17.19",
|
||||
"@esbuild/openbsd-x64": "0.17.19",
|
||||
"@esbuild/sunos-x64": "0.17.19",
|
||||
"@esbuild/win32-arm64": "0.17.19",
|
||||
"@esbuild/win32-ia32": "0.17.19",
|
||||
"@esbuild/win32-x64": "0.17.19"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
|
|
@ -5127,156 +5127,156 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@esbuild/android-arm": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.5.tgz",
|
||||
"integrity": "sha512-crmPUzgCmF+qZXfl1YkiFoUta2XAfixR1tEnr/gXIixE+WL8Z0BGqfydP5oox0EUOgQMMRgtATtakyAcClQVqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
|
||||
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/android-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-KHWkDqYAMmKZjY4RAN1PR96q6UOtfkWlTS8uEwWxdLtkRt/0F/csUhXIrVfaSIFxnscIBMPynGfhsMwQDRIBQw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/android-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-8fI/AnIdmWz/+1iza2WrCw8kwXK9wZp/yZY/iS8ioC+U37yJCeppi9EHY05ewJKN64ASoBIseufZROtcFnX5GA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/darwin-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-EAvaoyIySV6Iif3NQCglUNpnMfHSUgC5ugt2efl3+QDntucJe5spn0udNZjTgNi6tKVqSceOw9tQ32liNZc1Xw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/darwin-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-ha7QCJh1fuSwwCgoegfdaljowwWozwTDjBgjD3++WAy/qwee5uUi1gvOg2WENJC6EUyHBOkcd3YmLDYSZ2TPPA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/freebsd-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-VbdXJkn2aI2pQ/wxNEjEcnEDwPpxt3CWWMFYmO7CcdFBoOsABRy2W8F3kjbF9F/pecEUDcI3b5i2w+By4VQFPg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/freebsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-olgGYND1/XnnWxwhjtY3/ryjOG/M4WfcA6XH8dBTH1cxMeBemMODXSFhkw71Kf4TeZFFTN25YOomaNh0vq2iXg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-arm": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.5.tgz",
|
||||
"integrity": "sha512-YBdCyQwA3OQupi6W2/WO4FnI+NWFWe79cZEtlbqSESOHEg7a73htBIRiE6uHPQe7Yp5E4aALv+JxkRLGEUL7tw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
|
||||
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-8a0bqSwu3OlLCfu2FBbDNgQyBYdPJh1B9PvNX7jMaKGC9/KopgHs37t+pQqeMLzcyRqG6z55IGNQAMSlCpBuqg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-ia32": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.5.tgz",
|
||||
"integrity": "sha512-uCwm1r/+NdP7vndctgq3PoZrnmhmnecWAr114GWMRwg2QMFFX+kIWnp7IO220/JLgnXK/jP7VKAFBGmeOYBQYQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
|
||||
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-loong64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.5.tgz",
|
||||
"integrity": "sha512-3YxhSBl5Sb6TtBjJu+HP93poBruFzgXmf3PVfIe4xOXMj1XpxboYZyw3W8BhoX/uwxzZz4K1I99jTE/5cgDT1g==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
|
||||
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-mips64el": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.5.tgz",
|
||||
"integrity": "sha512-Hy5Z0YVWyYHdtQ5mfmfp8LdhVwGbwVuq8mHzLqrG16BaMgEmit2xKO+iDakHs+OetEx0EN/2mUzDdfdktI+Nmg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
|
||||
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-ppc64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.5.tgz",
|
||||
"integrity": "sha512-5dbQvBLbU/Y3Q4ABc9gi23hww1mQcM7KZ9KBqabB7qhJswYMf8WrDDOSw3gdf3p+ffmijMd28mfVMvFucuECyg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
|
||||
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-riscv64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.5.tgz",
|
||||
"integrity": "sha512-fp/KUB/ZPzEWGTEUgz9wIAKCqu7CjH1GqXUO2WJdik1UNBQ7Xzw7myIajpxztE4Csb9504ERiFMxZg5KZ6HlZQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
|
||||
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-s390x": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.5.tgz",
|
||||
"integrity": "sha512-kRV3yw19YDqHTp8SfHXfObUFXlaiiw4o2lvT1XjsPZ++22GqZwSsYWJLjMi1Sl7j9qDlDUduWDze/nQx0d6Lzw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
|
||||
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-vnxuhh9e4pbtABNLbT2ANW4uwQ/zvcHRCm1JxaYkzSehugoFd5iXyC4ci1nhXU13mxEwCnrnTIiiSGwa/uAF1g==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/netbsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-cigBpdiSx/vPy7doUyImsQQBnBjV5f1M99ZUlaJckDAJjgXWl6y9W17FIfJTy8TxosEF6MXq+fpLsitMGts2nA==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/openbsd-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-VdqRqPVIjjZfkf40LrqOaVuhw9EQiAZ/GNCSM2UplDkaIzYVsSnycxcFfAnHdWI8Gyt6dO15KHikbpxwx+xHbw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/sunos-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-ItxPaJ3MBLtI4nK+mALLEoUs6amxsx+J1ibnfcYMkqaCqHST1AkF4aENpBehty3czqw64r/XqL+W9WqU6kc2Qw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-arm64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.5.tgz",
|
||||
"integrity": "sha512-4u2Q6qsJTYNFdS9zHoAi80spzf78C16m2wla4eJPh4kSbRv+BpXIfl6TmBSWupD8e47B1NrTfrOlEuco7mYQtg==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
|
||||
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-ia32": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.5.tgz",
|
||||
"integrity": "sha512-KYlm+Xu9TXsfTWAcocLuISRtqxKp/Y9ZBVg6CEEj0O5J9mn7YvBKzAszo2j1ndyzUPk+op+Tie2PJeN+BnXGqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
|
||||
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-x64": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.5.tgz",
|
||||
"integrity": "sha512-XgA9qWRqby7xdYXuF6KALsn37QGBMHsdhmnpjfZtYxKxbTOwfnDM6MYi2WuUku5poNaX2n9XGVr20zgT/2QwCw==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
|
||||
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
|
@ -6088,33 +6088,33 @@
|
|||
"dev": true
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.5.tgz",
|
||||
"integrity": "sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==",
|
||||
"version": "0.17.19",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
||||
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@esbuild/android-arm": "0.17.5",
|
||||
"@esbuild/android-arm64": "0.17.5",
|
||||
"@esbuild/android-x64": "0.17.5",
|
||||
"@esbuild/darwin-arm64": "0.17.5",
|
||||
"@esbuild/darwin-x64": "0.17.5",
|
||||
"@esbuild/freebsd-arm64": "0.17.5",
|
||||
"@esbuild/freebsd-x64": "0.17.5",
|
||||
"@esbuild/linux-arm": "0.17.5",
|
||||
"@esbuild/linux-arm64": "0.17.5",
|
||||
"@esbuild/linux-ia32": "0.17.5",
|
||||
"@esbuild/linux-loong64": "0.17.5",
|
||||
"@esbuild/linux-mips64el": "0.17.5",
|
||||
"@esbuild/linux-ppc64": "0.17.5",
|
||||
"@esbuild/linux-riscv64": "0.17.5",
|
||||
"@esbuild/linux-s390x": "0.17.5",
|
||||
"@esbuild/linux-x64": "0.17.5",
|
||||
"@esbuild/netbsd-x64": "0.17.5",
|
||||
"@esbuild/openbsd-x64": "0.17.5",
|
||||
"@esbuild/sunos-x64": "0.17.5",
|
||||
"@esbuild/win32-arm64": "0.17.5",
|
||||
"@esbuild/win32-ia32": "0.17.5",
|
||||
"@esbuild/win32-x64": "0.17.5"
|
||||
"@esbuild/android-arm": "0.17.19",
|
||||
"@esbuild/android-arm64": "0.17.19",
|
||||
"@esbuild/android-x64": "0.17.19",
|
||||
"@esbuild/darwin-arm64": "0.17.19",
|
||||
"@esbuild/darwin-x64": "0.17.19",
|
||||
"@esbuild/freebsd-arm64": "0.17.19",
|
||||
"@esbuild/freebsd-x64": "0.17.19",
|
||||
"@esbuild/linux-arm": "0.17.19",
|
||||
"@esbuild/linux-arm64": "0.17.19",
|
||||
"@esbuild/linux-ia32": "0.17.19",
|
||||
"@esbuild/linux-loong64": "0.17.19",
|
||||
"@esbuild/linux-mips64el": "0.17.19",
|
||||
"@esbuild/linux-ppc64": "0.17.19",
|
||||
"@esbuild/linux-riscv64": "0.17.19",
|
||||
"@esbuild/linux-s390x": "0.17.19",
|
||||
"@esbuild/linux-x64": "0.17.19",
|
||||
"@esbuild/netbsd-x64": "0.17.19",
|
||||
"@esbuild/openbsd-x64": "0.17.19",
|
||||
"@esbuild/sunos-x64": "0.17.19",
|
||||
"@esbuild/win32-arm64": "0.17.19",
|
||||
"@esbuild/win32-ia32": "0.17.19",
|
||||
"@esbuild/win32-x64": "0.17.19"
|
||||
}
|
||||
},
|
||||
"esbuild-android-64": {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"happy-dom": "^8.1.5",
|
||||
"nanoid": "^4.0.0",
|
||||
"npm-check-updates": "^16.6.3",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ require (
|
|||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ package templates
|
|||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/wailsapp/wails/v3/internal/debug"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/wailsapp/wails/v3/internal/flags"
|
||||
|
||||
|
|
@ -154,7 +156,7 @@ func Install(options *flags.Init) error {
|
|||
|
||||
templateData := TemplateOptions{
|
||||
options,
|
||||
debug.LocalModulePath,
|
||||
filepath.FromSlash(debug.LocalModulePath + "/"),
|
||||
}
|
||||
template, found := lo.Find(defaultTemplates, func(template TemplateData) bool {
|
||||
return template.Name == options.TemplateName
|
||||
|
|
@ -167,7 +169,7 @@ func Install(options *flags.Init) error {
|
|||
templateData.ProjectDir = lo.Must(os.Getwd())
|
||||
}
|
||||
templateData.ProjectDir = fmt.Sprintf("%s/%s", options.ProjectDir, options.ProjectName)
|
||||
fmt.Printf("Installing template '%s' into '%s'\n", options.TemplateName, options.ProjectDir)
|
||||
pterm.Printf("Installing template '%s' into '%s'\n", options.TemplateName, filepath.FromSlash(options.ProjectDir))
|
||||
tfs, err := fs.Sub(template.FS, options.TemplateName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ require (
|
|||
golang.org/x/net v0.7.0 // indirect
|
||||
)
|
||||
{{if gt (len .LocalModulePath) 0}}
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}/v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}/v2
|
||||
replace github.com/wailsapp/wails/v3 => {{.LocalModulePath}}v3
|
||||
replace github.com/wailsapp/wails/v2 => {{.LocalModulePath}}v2
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func main() {
|
|||
},
|
||||
})
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Plain Bundle",
|
||||
CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`,
|
||||
Mac: application.MacWindow{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package application
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
|
@ -9,6 +8,10 @@ import (
|
|||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/icons"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/assetserver"
|
||||
"github.com/wailsapp/wails/v2/pkg/assetserver/webview"
|
||||
assetserveroptions "github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
|
|
@ -20,10 +23,17 @@ import (
|
|||
|
||||
var globalApplication *App
|
||||
|
||||
// isDebugMode is true if the application is running in debug mode
|
||||
var isDebugMode func() bool
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
type EventListener struct {
|
||||
callback func()
|
||||
}
|
||||
|
||||
func New(appOptions Options) *App {
|
||||
if globalApplication != nil {
|
||||
return globalApplication
|
||||
|
|
@ -33,7 +43,8 @@ func New(appOptions Options) *App {
|
|||
|
||||
result := &App{
|
||||
options: appOptions,
|
||||
applicationEventListeners: make(map[uint][]func()),
|
||||
applicationEventListeners: make(map[uint][]*EventListener),
|
||||
windows: make(map[uint]*WebviewWindow),
|
||||
systemTrays: make(map[uint]*SystemTray),
|
||||
log: logger.New(appOptions.Logger.CustomLoggers...),
|
||||
contextMenus: make(map[string]*Menu),
|
||||
|
|
@ -45,6 +56,13 @@ func New(appOptions Options) *App {
|
|||
result.log.AddOutput(&logger.Console{})
|
||||
}
|
||||
|
||||
// Patch isDebug if we aren't in prod mode
|
||||
if isDebugMode == nil {
|
||||
isDebugMode = func() bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
result.Events = NewWailsEventProcessor(result.dispatchEventToWindows)
|
||||
|
||||
opts := assetserveroptions.Options{
|
||||
|
|
@ -92,24 +110,32 @@ func mergeApplicationDefaults(o *Options) {
|
|||
o.Description = "An application written using Wails"
|
||||
}
|
||||
if o.Icon == nil {
|
||||
o.Icon = DefaultApplicationIcon
|
||||
o.Icon = icons.ApplicationLightMode256
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type platformApp interface {
|
||||
run() error
|
||||
destroy()
|
||||
setApplicationMenu(menu *Menu)
|
||||
name() string
|
||||
getCurrentWindowID() uint
|
||||
showAboutDialog(name string, description string, icon []byte)
|
||||
setIcon(icon []byte)
|
||||
on(id uint)
|
||||
dispatchOnMainThread(id uint)
|
||||
hide()
|
||||
show()
|
||||
}
|
||||
type (
|
||||
platformApp interface {
|
||||
run() error
|
||||
destroy()
|
||||
setApplicationMenu(menu *Menu)
|
||||
name() string
|
||||
getCurrentWindowID() uint
|
||||
showAboutDialog(name string, description string, icon []byte)
|
||||
setIcon(icon []byte)
|
||||
on(id uint)
|
||||
dispatchOnMainThread(id uint)
|
||||
hide()
|
||||
show()
|
||||
getPrimaryScreen() (*Screen, error)
|
||||
getScreens() ([]*Screen, error)
|
||||
}
|
||||
|
||||
runnable interface {
|
||||
run()
|
||||
}
|
||||
)
|
||||
|
||||
// Messages sent from javascript get routed here
|
||||
type windowMessage struct {
|
||||
|
|
@ -152,7 +178,7 @@ var webviewRequests = make(chan *webViewAssetRequest)
|
|||
|
||||
type App struct {
|
||||
options Options
|
||||
applicationEventListeners map[uint][]func()
|
||||
applicationEventListeners map[uint][]*EventListener
|
||||
applicationEventListenersLock sync.RWMutex
|
||||
|
||||
// Windows
|
||||
|
|
@ -170,7 +196,10 @@ type App struct {
|
|||
menuItemsLock sync.Mutex
|
||||
|
||||
// Running
|
||||
running bool
|
||||
running bool
|
||||
runLock sync.Mutex
|
||||
pendingRun []runnable
|
||||
|
||||
bindings *Bindings
|
||||
plugins *PluginManager
|
||||
|
||||
|
|
@ -187,7 +216,8 @@ type App struct {
|
|||
contextMenus map[string]*Menu
|
||||
contextMenusLock sync.Mutex
|
||||
|
||||
assets *assetserver.AssetServer
|
||||
assets *assetserver.AssetServer
|
||||
startURL string
|
||||
|
||||
// Hooks
|
||||
windowCreatedCallbacks []func(window *WebviewWindow)
|
||||
|
|
@ -213,17 +243,28 @@ func (a *App) deleteWindowByID(id uint) {
|
|||
delete(a.windows, id)
|
||||
}
|
||||
|
||||
func (a *App) On(eventType events.ApplicationEventType, callback func()) {
|
||||
func (a *App) On(eventType events.ApplicationEventType, callback func()) func() {
|
||||
eventID := uint(eventType)
|
||||
a.applicationEventListenersLock.Lock()
|
||||
defer a.applicationEventListenersLock.Unlock()
|
||||
a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], callback)
|
||||
listener := &EventListener{
|
||||
callback: callback,
|
||||
}
|
||||
a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], listener)
|
||||
if a.impl != nil {
|
||||
go a.impl.on(eventID)
|
||||
}
|
||||
|
||||
return func() {
|
||||
// lock the map
|
||||
a.applicationEventListenersLock.Lock()
|
||||
defer a.applicationEventListenersLock.Unlock()
|
||||
// Remove listener
|
||||
a.applicationEventListeners[eventID] = lo.Without(a.applicationEventListeners[eventID], listener)
|
||||
}
|
||||
}
|
||||
func (a *App) NewWebviewWindow() *WebviewWindow {
|
||||
return a.NewWebviewWindowWithOptions(&WebviewWindowOptions{})
|
||||
return a.NewWebviewWindowWithOptions(WebviewWindowOptions{})
|
||||
}
|
||||
|
||||
func (a *App) GetPID() int {
|
||||
|
|
@ -264,16 +305,10 @@ func (a *App) error(message string, args ...any) {
|
|||
})
|
||||
}
|
||||
|
||||
func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *WebviewWindow {
|
||||
// Ensure we have sane defaults
|
||||
if windowOptions == nil {
|
||||
windowOptions = WebviewWindowDefaults
|
||||
}
|
||||
func (a *App) NewWebviewWindowWithOptions(windowOptions WebviewWindowOptions) *WebviewWindow {
|
||||
newWindow := NewWindow(windowOptions)
|
||||
id := newWindow.id
|
||||
if a.windows == nil {
|
||||
a.windows = make(map[uint]*WebviewWindow)
|
||||
}
|
||||
|
||||
a.windowsLock.Lock()
|
||||
a.windows[id] = newWindow
|
||||
a.windowsLock.Unlock()
|
||||
|
|
@ -283,9 +318,7 @@ func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *
|
|||
hook(newWindow)
|
||||
}
|
||||
|
||||
if a.running {
|
||||
newWindow.run()
|
||||
}
|
||||
a.runOrDeferToAppRun(newWindow)
|
||||
|
||||
return newWindow
|
||||
}
|
||||
|
|
@ -293,13 +326,13 @@ func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *
|
|||
func (a *App) NewSystemTray() *SystemTray {
|
||||
id := a.getSystemTrayID()
|
||||
newSystemTray := NewSystemTray(id)
|
||||
|
||||
a.systemTraysLock.Lock()
|
||||
a.systemTrays[id] = newSystemTray
|
||||
a.systemTraysLock.Unlock()
|
||||
|
||||
if a.running {
|
||||
newSystemTray.Run()
|
||||
}
|
||||
a.runOrDeferToAppRun(newSystemTray)
|
||||
|
||||
return newSystemTray
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +340,6 @@ func (a *App) Run() error {
|
|||
a.info("Starting application")
|
||||
a.impl = newPlatformApp(a)
|
||||
|
||||
a.running = true
|
||||
go func() {
|
||||
for {
|
||||
event := <-applicationEvents
|
||||
|
|
@ -346,21 +378,21 @@ func (a *App) Run() error {
|
|||
}
|
||||
}()
|
||||
|
||||
// run windows
|
||||
for _, window := range a.windows {
|
||||
go window.run()
|
||||
}
|
||||
a.runLock.Lock()
|
||||
a.running = true
|
||||
|
||||
// run system trays
|
||||
for _, systray := range a.systemTrays {
|
||||
go systray.Run()
|
||||
for _, systray := range a.pendingRun {
|
||||
go systray.run()
|
||||
}
|
||||
a.pendingRun = nil
|
||||
|
||||
a.runLock.Unlock()
|
||||
|
||||
// set the application menu
|
||||
a.impl.setApplicationMenu(a.ApplicationMenu)
|
||||
|
||||
// set the application Icon
|
||||
a.impl.setIcon(a.options.Icon)
|
||||
if runtime.GOOS == "darwin" {
|
||||
a.impl.setApplicationMenu(a.ApplicationMenu)
|
||||
a.impl.setIcon(a.options.Icon)
|
||||
}
|
||||
|
||||
err := a.impl.run()
|
||||
if err != nil {
|
||||
|
|
@ -380,7 +412,7 @@ func (a *App) handleApplicationEvent(event uint) {
|
|||
return
|
||||
}
|
||||
for _, listener := range listeners {
|
||||
go listener()
|
||||
go listener.callback()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,11 +546,11 @@ func (a *App) SaveFileDialog() *SaveFileDialog {
|
|||
}
|
||||
|
||||
func (a *App) GetPrimaryScreen() (*Screen, error) {
|
||||
return getPrimaryScreen()
|
||||
return a.impl.getPrimaryScreen()
|
||||
}
|
||||
|
||||
func (a *App) GetScreens() ([]*Screen, error) {
|
||||
return getScreens()
|
||||
return a.impl.getScreens()
|
||||
}
|
||||
|
||||
func (a *App) Clipboard() *Clipboard {
|
||||
|
|
@ -599,3 +631,48 @@ func (a *App) GetWindowByName(name string) *WebviewWindow {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) runOrDeferToAppRun(r runnable) {
|
||||
a.runLock.Lock()
|
||||
running := a.running
|
||||
if !running {
|
||||
a.pendingRun = append(a.pendingRun, r)
|
||||
}
|
||||
a.runLock.Unlock()
|
||||
|
||||
if running {
|
||||
r.run()
|
||||
}
|
||||
}
|
||||
|
||||
func invokeSync(fn func()) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
globalApplication.dispatchOnMainThread(func() {
|
||||
fn()
|
||||
wg.Done()
|
||||
})
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func invokeSyncWithResult[T any](fn func() T) (res T) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
globalApplication.dispatchOnMainThread(func() {
|
||||
res = fn()
|
||||
wg.Done()
|
||||
})
|
||||
wg.Wait()
|
||||
return res
|
||||
}
|
||||
|
||||
func invokeSyncWithResultAndError[T any](fn func() (T, error)) (res T, err error) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
globalApplication.dispatchOnMainThread(func() {
|
||||
res, err = fn()
|
||||
wg.Done()
|
||||
})
|
||||
wg.Wait()
|
||||
return res, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ package application
|
|||
#cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c
|
||||
#cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.13
|
||||
|
||||
#include "application.h"
|
||||
#include "app_delegate.h"
|
||||
#include "webview_window.h"
|
||||
#include "application_darwin.h"
|
||||
#include "application_darwin_delegate.h"
|
||||
#include "webview_window_darwin.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void registerListener(unsigned int event);
|
||||
|
|
@ -137,6 +137,10 @@ type macosApp struct {
|
|||
parent *App
|
||||
}
|
||||
|
||||
func getNativeApplication() *macosApp {
|
||||
return globalApplication.impl.(*macosApp)
|
||||
}
|
||||
|
||||
func (m *macosApp) hide() {
|
||||
C.hide()
|
||||
}
|
||||
|
|
@ -182,6 +186,7 @@ func (m *macosApp) run() error {
|
|||
C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy))
|
||||
C.activateIgnoringOtherApps()
|
||||
})
|
||||
m.setupCommonEvents()
|
||||
// setup event listeners
|
||||
for eventID := range m.parent.applicationEventListeners {
|
||||
m.on(eventID)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//go:build darwin
|
||||
#import "app_delegate.h"
|
||||
#import "application_darwin_delegate.h"
|
||||
#import "../events/events.h"
|
||||
extern bool hasListeners(unsigned int);
|
||||
@implementation AppDelegate
|
||||
10
v3/pkg/application/application_production.go
Normal file
10
v3/pkg/application/application_production.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//go:build production
|
||||
|
||||
package application
|
||||
|
||||
// We use this to patch the application to production mode.
|
||||
func init() {
|
||||
isDebugMode = func() bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
246
v3/pkg/application/application_windows.go
Normal file
246
v3/pkg/application/application_windows.go
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
//go:build windows
|
||||
|
||||
package application
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/events"
|
||||
"github.com/wailsapp/wails/v3/pkg/w32"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
var windowClassName = lo.Must(syscall.UTF16PtrFromString("WailsWebviewWindow"))
|
||||
|
||||
type windowsApp struct {
|
||||
parent *App
|
||||
|
||||
instance w32.HINSTANCE
|
||||
|
||||
windowMap map[w32.HWND]*windowsWebviewWindow
|
||||
systrayMap map[w32.HMENU]*windowsSystemTray
|
||||
|
||||
mainThreadID w32.HANDLE
|
||||
mainThreadWindowHWND w32.HWND
|
||||
|
||||
// Windows hidden by application.Hide()
|
||||
hiddenWindows []*windowsWebviewWindow
|
||||
focusedWindow w32.HWND
|
||||
|
||||
// system theme
|
||||
isDarkMode bool
|
||||
}
|
||||
|
||||
func getNativeApplication() *windowsApp {
|
||||
return globalApplication.impl.(*windowsApp)
|
||||
}
|
||||
|
||||
func (m *windowsApp) getPrimaryScreen() (*Screen, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *windowsApp) getScreens() ([]*Screen, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *windowsApp) hide() {
|
||||
// Get the current focussed window
|
||||
m.focusedWindow = w32.GetForegroundWindow()
|
||||
|
||||
// Iterate over all windows and hide them if they aren't already hidden
|
||||
for _, window := range m.windowMap {
|
||||
if window.isVisible() {
|
||||
// Add to hidden windows
|
||||
m.hiddenWindows = append(m.hiddenWindows, window)
|
||||
window.hide()
|
||||
}
|
||||
}
|
||||
// Switch focus to the next application
|
||||
hwndNext := w32.GetWindow(m.mainThreadWindowHWND, w32.GW_HWNDNEXT)
|
||||
w32.SetForegroundWindow(hwndNext)
|
||||
}
|
||||
|
||||
func (m *windowsApp) show() {
|
||||
// Iterate over all windows and show them if they were previously hidden
|
||||
for _, window := range m.hiddenWindows {
|
||||
window.show()
|
||||
}
|
||||
// Show the foreground window
|
||||
w32.SetForegroundWindow(m.focusedWindow)
|
||||
}
|
||||
|
||||
func (m *windowsApp) on(eventID uint) {
|
||||
//C.registerListener(C.uint(eventID))
|
||||
}
|
||||
|
||||
func (m *windowsApp) setIcon(icon []byte) {
|
||||
//C.setApplicationIcon(unsafe.Pointer(&icon[0]), C.int(len(icon)))
|
||||
}
|
||||
|
||||
func (m *windowsApp) name() string {
|
||||
//appName := C.getAppName()
|
||||
//defer C.free(unsafe.Pointer(appName))
|
||||
//return C.GoString(appName)
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *windowsApp) getCurrentWindowID() uint {
|
||||
//return uint(C.getCurrentWindowID())
|
||||
return uint(0)
|
||||
}
|
||||
|
||||
func (m *windowsApp) setApplicationMenu(menu *Menu) {
|
||||
if menu == nil {
|
||||
// Create a default menu for windows
|
||||
menu = defaultApplicationMenu()
|
||||
}
|
||||
menu.Update()
|
||||
|
||||
// Convert impl to macosMenu object
|
||||
//m.applicationMenu = (menu.impl).(*macosMenu).nsMenu
|
||||
//C.setApplicationMenu(m.applicationMenu)
|
||||
}
|
||||
|
||||
func (m *windowsApp) run() error {
|
||||
// Add a hook to the ApplicationDidFinishLaunching event
|
||||
//m.parent.On(events.Mac.ApplicationDidFinishLaunching, func() {
|
||||
// C.setApplicationShouldTerminateAfterLastWindowClosed(C.bool(m.parent.options.Mac.ApplicationShouldTerminateAfterLastWindowClosed))
|
||||
// C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy))
|
||||
// C.activateIgnoringOtherApps()
|
||||
//})
|
||||
// setup event listeners
|
||||
for eventID := range m.parent.applicationEventListeners {
|
||||
m.on(eventID)
|
||||
}
|
||||
|
||||
_ = m.runMainLoop()
|
||||
|
||||
//C.run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *windowsApp) destroy() {
|
||||
//C.destroyApp()
|
||||
}
|
||||
|
||||
func (m *windowsApp) init() {
|
||||
// Register the window class
|
||||
|
||||
icon := w32.LoadIconWithResourceID(m.instance, w32.IDI_APPLICATION)
|
||||
|
||||
var wc w32.WNDCLASSEX
|
||||
wc.Size = uint32(unsafe.Sizeof(wc))
|
||||
wc.Style = w32.CS_HREDRAW | w32.CS_VREDRAW
|
||||
wc.WndProc = syscall.NewCallback(m.wndProc)
|
||||
wc.Instance = m.instance
|
||||
wc.Background = w32.COLOR_BTNFACE + 1
|
||||
wc.Icon = icon
|
||||
wc.Cursor = w32.LoadCursorWithResourceID(0, w32.IDC_ARROW)
|
||||
wc.ClassName = windowClassName
|
||||
wc.MenuName = nil
|
||||
wc.IconSm = icon
|
||||
|
||||
if ret := w32.RegisterClassEx(&wc); ret == 0 {
|
||||
panic(syscall.GetLastError())
|
||||
}
|
||||
|
||||
m.isDarkMode = w32.IsCurrentlyDarkMode()
|
||||
}
|
||||
|
||||
func (m *windowsApp) wndProc(hwnd w32.HWND, msg uint32, wParam, lParam uintptr) uintptr {
|
||||
|
||||
// Handle the invoke callback
|
||||
if msg == wmInvokeCallback {
|
||||
m.invokeCallback(wParam, lParam)
|
||||
return 0
|
||||
}
|
||||
|
||||
// If the WndProcInterceptor is set in options, pass the message on
|
||||
if m.parent.options.Windows.WndProcInterceptor != nil {
|
||||
returnValue, shouldReturn := m.parent.options.Windows.WndProcInterceptor(hwnd, msg, wParam, lParam)
|
||||
if shouldReturn {
|
||||
return returnValue
|
||||
}
|
||||
}
|
||||
|
||||
switch msg {
|
||||
case w32.WM_SETTINGCHANGE:
|
||||
settingChanged := w32.UTF16PtrToString((*uint16)(unsafe.Pointer(lParam)))
|
||||
if settingChanged == "ImmersiveColorSet" {
|
||||
isDarkMode := w32.IsCurrentlyDarkMode()
|
||||
if isDarkMode != m.isDarkMode {
|
||||
applicationEvents <- uint(events.Windows.SystemThemeChanged)
|
||||
m.isDarkMode = isDarkMode
|
||||
}
|
||||
}
|
||||
return 0
|
||||
case w32.WM_POWERBROADCAST:
|
||||
switch wParam {
|
||||
case w32.PBT_APMPOWERSTATUSCHANGE:
|
||||
applicationEvents <- uint(events.Windows.APMPowerStatusChange)
|
||||
case w32.PBT_APMSUSPEND:
|
||||
applicationEvents <- uint(events.Windows.APMSuspend)
|
||||
case w32.PBT_APMRESUMEAUTOMATIC:
|
||||
applicationEvents <- uint(events.Windows.APMResumeAutomatic)
|
||||
case w32.PBT_APMRESUMESUSPEND:
|
||||
applicationEvents <- uint(events.Windows.APMResumeSuspend)
|
||||
case w32.PBT_POWERSETTINGCHANGE:
|
||||
applicationEvents <- uint(events.Windows.APMPowerSettingChange)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
if window, ok := m.windowMap[hwnd]; ok {
|
||||
return window.WndProc(msg, wParam, lParam)
|
||||
}
|
||||
|
||||
if systray, ok := m.systrayMap[hwnd]; ok {
|
||||
return systray.wndProc(msg, wParam, lParam)
|
||||
}
|
||||
|
||||
// Dispatch the message to the appropriate window
|
||||
|
||||
return w32.DefWindowProc(hwnd, msg, wParam, lParam)
|
||||
}
|
||||
|
||||
func (m *windowsApp) registerWindow(result *windowsWebviewWindow) {
|
||||
m.windowMap[result.hwnd] = result
|
||||
}
|
||||
|
||||
func (m *windowsApp) registerSystemTray(result *windowsSystemTray) {
|
||||
m.systrayMap[result.hwnd] = result
|
||||
}
|
||||
|
||||
func (m *windowsApp) unregisterWindow(w *windowsWebviewWindow) {
|
||||
delete(m.windowMap, w.hwnd)
|
||||
|
||||
// If this was the last window...
|
||||
if len(m.windowMap) == 0 && !m.parent.options.Windows.DisableQuitOnLastWindowClosed {
|
||||
w32.PostQuitMessage(0)
|
||||
}
|
||||
}
|
||||
|
||||
func newPlatformApp(app *App) *windowsApp {
|
||||
err := w32.SetProcessDPIAware()
|
||||
if err != nil {
|
||||
println("Fatal error in application initialisation: ", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result := &windowsApp{
|
||||
parent: app,
|
||||
instance: w32.GetModuleHandle(""),
|
||||
windowMap: make(map[w32.HWND]*windowsWebviewWindow),
|
||||
systrayMap: make(map[w32.HWND]*windowsSystemTray),
|
||||
}
|
||||
|
||||
result.init()
|
||||
result.initMainLoop()
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
package application
|
||||
|
||||
import "C"
|
||||
|
||||
type clipboardImpl interface {
|
||||
setText(text string) bool
|
||||
text() string
|
||||
|
|
|
|||
28
v3/pkg/application/clipboard_windows.go
Normal file
28
v3/pkg/application/clipboard_windows.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//go:build windows
|
||||
|
||||
package application
|
||||
|
||||
type windowsClipboard struct{}
|
||||
|
||||
func (m windowsClipboard) setText(text string) bool {
|
||||
//clipboardLock.Lock()
|
||||
//defer clipboardLock.Unlock()
|
||||
//cText := C.CString(text)
|
||||
//success := C.setClipboardText(cText)
|
||||
//C.free(unsafe.Pointer(cText))
|
||||
//return bool(success)
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m windowsClipboard) text() string {
|
||||
//clipboardLock.RLock()
|
||||
//defer clipboardLock.RUnlock()
|
||||
//clipboardText := C.getClipboardText()
|
||||
//result := C.GoString(clipboardText)
|
||||
//return result
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func newClipboardImpl() *windowsClipboard {
|
||||
return &windowsClipboard{}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package application
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -49,11 +48,22 @@ type Button struct {
|
|||
Label string
|
||||
IsCancel bool
|
||||
IsDefault bool
|
||||
callback func()
|
||||
Callback func()
|
||||
}
|
||||
|
||||
func (b *Button) OnClick(callback func()) {
|
||||
b.callback = callback
|
||||
func (b *Button) OnClick(callback func()) *Button {
|
||||
b.Callback = callback
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Button) SetAsDefault() *Button {
|
||||
b.IsDefault = true
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Button) SetAsCancel() *Button {
|
||||
b.IsCancel = true
|
||||
return b
|
||||
}
|
||||
|
||||
type messageDialogImpl interface {
|
||||
|
|
@ -86,7 +96,6 @@ func newMessageDialog(dialogType DialogType) *MessageDialog {
|
|||
return &MessageDialog{
|
||||
MessageDialogOptions: MessageDialogOptions{
|
||||
DialogType: dialogType,
|
||||
Title: defaultTitles[dialogType],
|
||||
},
|
||||
impl: nil,
|
||||
}
|
||||
|
|
@ -101,7 +110,7 @@ func (d *MessageDialog) Show() {
|
|||
if d.impl == nil {
|
||||
d.impl = newDialogImpl(d)
|
||||
}
|
||||
d.impl.show()
|
||||
invokeSync(d.impl.show)
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog {
|
||||
|
|
@ -249,7 +258,7 @@ func (d *OpenFileDialog) PromptForSingleSelection() (string, error) {
|
|||
if d.impl == nil {
|
||||
d.impl = newOpenFileDialogImpl(d)
|
||||
}
|
||||
selection, err := d.impl.show()
|
||||
selection, err := invokeSyncWithResultAndError(d.impl.show)
|
||||
var result string
|
||||
if len(selection) > 0 {
|
||||
result = selection[0]
|
||||
|
|
@ -273,7 +282,7 @@ func (d *OpenFileDialog) PromptForMultipleSelection() ([]string, error) {
|
|||
if d.impl == nil {
|
||||
d.impl = newOpenFileDialogImpl(d)
|
||||
}
|
||||
return d.impl.show()
|
||||
return invokeSyncWithResultAndError(d.impl.show)
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) SetMessage(message string) *OpenFileDialog {
|
||||
|
|
@ -338,10 +347,12 @@ type SaveFileDialogOptions struct {
|
|||
AllowOtherFileTypes bool
|
||||
HideExtension bool
|
||||
TreatsFilePackagesAsDirectories bool
|
||||
Title string
|
||||
Message string
|
||||
Directory string
|
||||
Filename string
|
||||
ButtonText string
|
||||
Filters []FileFilter
|
||||
}
|
||||
|
||||
type SaveFileDialog struct {
|
||||
|
|
@ -356,10 +367,12 @@ type SaveFileDialog struct {
|
|||
directory string
|
||||
filename string
|
||||
buttonText string
|
||||
filters []FileFilter
|
||||
|
||||
window *WebviewWindow
|
||||
|
||||
impl saveFileDialogImpl
|
||||
impl saveFileDialogImpl
|
||||
title string
|
||||
}
|
||||
|
||||
type saveFileDialogImpl interface {
|
||||
|
|
@ -367,6 +380,7 @@ type saveFileDialogImpl interface {
|
|||
}
|
||||
|
||||
func (d *SaveFileDialog) SetOptions(options *SaveFileDialogOptions) {
|
||||
d.title = options.Title
|
||||
d.canCreateDirectories = options.CanCreateDirectories
|
||||
d.showHiddenFiles = options.ShowHiddenFiles
|
||||
d.canSelectHiddenExtension = options.CanSelectHiddenExtension
|
||||
|
|
@ -379,6 +393,16 @@ func (d *SaveFileDialog) SetOptions(options *SaveFileDialogOptions) {
|
|||
d.buttonText = options.ButtonText
|
||||
}
|
||||
|
||||
// AddFilter adds a filter to the dialog. The filter is a display name and a semicolon separated list of extensions.
|
||||
// EG: AddFilter("Image Files", "*.jpg;*.png")
|
||||
func (d *SaveFileDialog) AddFilter(displayName, pattern string) *SaveFileDialog {
|
||||
d.filters = append(d.filters, FileFilter{
|
||||
DisplayName: strings.TrimSpace(displayName),
|
||||
Pattern: strings.TrimSpace(pattern),
|
||||
})
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *SaveFileDialog) CanCreateDirectories(canCreateDirectories bool) *SaveFileDialog {
|
||||
d.canCreateDirectories = canCreateDirectories
|
||||
return d
|
||||
|
|
@ -413,7 +437,7 @@ func (d *SaveFileDialog) PromptForSingleSelection() (string, error) {
|
|||
if d.impl == nil {
|
||||
d.impl = newSaveFileDialogImpl(d)
|
||||
}
|
||||
return d.impl.show()
|
||||
return invokeSyncWithResultAndError(d.impl.show)
|
||||
}
|
||||
|
||||
func (d *SaveFileDialog) SetButtonText(text string) *SaveFileDialog {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ package application
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import <UniformTypeIdentifiers/UTType.h>
|
||||
#import "dialogs_delegate.h"
|
||||
#import "dialogs_darwin_delegate.h"
|
||||
|
||||
extern void openFileDialogCallback(uint id, char* path);
|
||||
extern void openFileDialogCallbackEnd(uint id);
|
||||
|
|
@ -364,8 +364,8 @@ func (m *macosDialog) show() {
|
|||
buttonPressed := int(C.dialogRunModal(m.nsDialog))
|
||||
if len(m.dialog.Buttons) > buttonPressed {
|
||||
button := reversedButtons[buttonPressed]
|
||||
if button.callback != nil {
|
||||
button.callback()
|
||||
if button.Callback != nil {
|
||||
button.Callback()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue