Compare commits
74 Commits
develop
...
930_-_defa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c678ab7d01 | ||
|
|
56ef4ddd47 | ||
|
|
bad9ad3dd7 | ||
|
|
36570645ff | ||
|
|
3711bdc41e | ||
|
|
cbdcd9f63e | ||
|
|
a9268bc56e | ||
|
|
f489347fca | ||
|
|
663925f9e8 | ||
|
|
cc2651c377 | ||
|
|
e651b9c7ff | ||
|
|
bcad236fb6 | ||
|
|
0af8d506c1 | ||
|
|
0b65a0f508 | ||
|
|
b03a758747 | ||
|
|
44597f2fbc | ||
|
|
0844113f3a | ||
|
|
79e99b68d6 | ||
|
|
c64b7bb79c | ||
|
|
e72b438ad2 | ||
|
|
3e4a112a3d | ||
|
|
a020b67f67 | ||
|
|
fa958e7a07 | ||
|
|
1a3e81a3f8 | ||
|
|
0eb7a8a771 | ||
|
|
2fa004808f | ||
|
|
cc5fd30256 | ||
|
|
c90bfc310a | ||
|
|
62d1d621aa | ||
|
|
6e8cbb8e8f | ||
|
|
32fa543164 | ||
|
|
04f93ac54e | ||
|
|
3c87d13b21 | ||
|
|
0949eab72e | ||
|
|
aab67b416f | ||
|
|
83a575e43f | ||
|
|
333949ee53 | ||
|
|
1d1238cea3 | ||
|
|
bd7b436631 | ||
|
|
c136df48b9 | ||
|
|
a090a689cf | ||
|
|
5ef2448a0c | ||
|
|
06ab4c88ad | ||
|
|
48efdea11a | ||
|
|
43cc55cb0a | ||
|
|
71f2436562 | ||
|
|
4653c77a81 | ||
|
|
72b05c6b44 | ||
|
|
b5f68e24d6 | ||
|
|
3948c8ca61 | ||
|
|
cf3a868e3a | ||
|
|
43c29abb23 | ||
|
|
7ef445f526 | ||
|
|
f6c2d4ae6b | ||
|
|
8f9fae6ad9 | ||
|
|
b45f264e2a | ||
|
|
986f8f48c7 | ||
|
|
bbc2e86286 | ||
|
|
2dc126bf19 | ||
|
|
86cbcdc089 | ||
|
|
1dd957f461 | ||
|
|
4be4946756 | ||
|
|
65979cbc75 | ||
|
|
6a7118ff6d | ||
|
|
a88b3553ba | ||
|
|
fd5348d26d | ||
|
|
569569f1fc | ||
|
|
489b9b358b | ||
|
|
71cfdfc7c8 | ||
|
|
6ebf4ed428 | ||
|
|
5be0739c5d | ||
|
|
6721e59277 | ||
|
|
77775d85ab | ||
|
|
6de0865c3e |
108
README.md
@@ -18,42 +18,57 @@
|
|||||||
|
|
||||||
## Internationalization
|
## Internationalization
|
||||||
|
|
||||||
English | [简体中文](README.zh-Hans.md)
|
[English](README.md) | [简体中文](README.zh-Hans.md)
|
||||||
|
|
||||||
|
<span id="nav-2"></span>
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click me to Open/Close the directory listing</summary>
|
||||||
|
|
||||||
|
- [1. Internationalization](#nav-1)
|
||||||
|
- [2. Table of Contents](#nav-2)
|
||||||
|
- [3. Introduction](#nav-3)
|
||||||
|
- [3.1 Official Website](#nav-3-1)
|
||||||
|
- [4. Features](#nav-4)
|
||||||
|
- [5. Sponsors](#nav-5)
|
||||||
|
- [6. Installation](#nav-6)
|
||||||
|
- [6.1 MacOS](#nav-6-1)
|
||||||
|
- [6.2 Linux](#nav-6-2)
|
||||||
|
- [6.2.1 Debian/Ubuntu](#nav-6-2-1)
|
||||||
|
- [6.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-6-2-2)
|
||||||
|
- [6.2.3 Centos](#nav-6-2-3)
|
||||||
|
- [6.2.4 Fedora](#nav-6-2-4)
|
||||||
|
- [6.2.5 VoidLinux & VoidLinux-musl](#nav-6-2-5)
|
||||||
|
- [6.2.6 Gentoo](#nav-6-2-6)
|
||||||
|
- [6.3 Windows](#nav-6-3)
|
||||||
|
- [7. Usage](#nav-7)
|
||||||
|
- [7.1 Next Steps](#nav-7-1)
|
||||||
|
- [8. FAQ](#nav-8)
|
||||||
|
- [9. Contributors](#nav-9)
|
||||||
|
- [10. Special Mentions](#nav-10)
|
||||||
|
- [12. Special Thanks](#nav-11)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<span id="nav-3"></span>
|
||||||
|
|
||||||
|
## Introductions
|
||||||
|
|
||||||
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different
|
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different
|
||||||
approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to
|
approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to
|
||||||
make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
||||||
|
|
||||||
|
<span id="nav-3-1"></span>
|
||||||
|
|
||||||
|
### Official Website
|
||||||
|
|
||||||
The official docs can be found at [https://wails.app](https://wails.app).
|
The official docs can be found at [https://wails.app](https://wails.app).
|
||||||
|
|
||||||
Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows.
|
Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows.
|
||||||
|
|
||||||
<span id="nav-2"></span>
|
<span id="nav-4"></span>
|
||||||
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
- [1. Internationalization](#nav-1)
|
|
||||||
- [2. Contents](#nav-2)
|
|
||||||
- [3. Features](#nav-3)
|
|
||||||
- [4. Sponsors](#nav-4)
|
|
||||||
- [5. Installation](#nav-5)
|
|
||||||
- [5.1 MacOS](#nav-5-1)
|
|
||||||
- [5.2 Linux](#nav-5-2)
|
|
||||||
- [5.2.1 Debian/Ubuntu](#nav-5-2-1)
|
|
||||||
- [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2)
|
|
||||||
- [5.2.3 Centos](#nav-5-2-3)
|
|
||||||
- [5.2.4 Fedora](#nav-5-2-4)
|
|
||||||
- [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5)
|
|
||||||
- [5.2.6 Gentoo](#nav-5-2-6)
|
|
||||||
- [5.3 Windows](#nav-5-3)
|
|
||||||
- [6. Installation](#nav-6)
|
|
||||||
- [7. Next Steps](#nav-7)
|
|
||||||
- [8. FAQ](#nav-8)
|
|
||||||
- [9. Contributors](#nav-9)
|
|
||||||
- [10. Special Mentions](#nav-10)
|
|
||||||
- [11. Special Thanks](#nav-11)
|
|
||||||
|
|
||||||
<span id="nav-3"></span>
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -67,7 +82,7 @@ Click [here](https://wails.io) if you are interested in trying out v2 Beta for W
|
|||||||
- Powerful cli tool
|
- Powerful cli tool
|
||||||
- Multiplatform
|
- Multiplatform
|
||||||
|
|
||||||
<span id="nav-4"></span>
|
<span id="nav-5"></span>
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
@@ -82,6 +97,9 @@ This project is supported by these kind people / companies:
|
|||||||
<a href="https://github.com/codydbentley" style="width:100px">
|
<a href="https://github.com/codydbentley" style="width:100px">
|
||||||
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/CrackDavid" style="width:100px">
|
||||||
|
<img src="https://github.com/CrackDavid.png?size=100" width="100"/>
|
||||||
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://github.com/matryer" style="width:100px">
|
<a href="https://github.com/matryer" style="width:100px">
|
||||||
@@ -142,7 +160,7 @@ This project is supported by these kind people / companies:
|
|||||||
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<span id="nav-5"></span>
|
<span id="nav-6"></span>
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -152,7 +170,7 @@ an installation of Go. The basic requirements are:
|
|||||||
- Go 1.16
|
- Go 1.16
|
||||||
- npm
|
- npm
|
||||||
|
|
||||||
<span id="nav-5-1"></span>
|
<span id="nav-6-1"></span>
|
||||||
|
|
||||||
### MacOS
|
### MacOS
|
||||||
|
|
||||||
@@ -160,11 +178,11 @@ Make sure you have the xcode command line tools installed. This can be done by r
|
|||||||
|
|
||||||
`xcode-select --install`
|
`xcode-select --install`
|
||||||
|
|
||||||
<span id="nav-5-2"></span>
|
<span id="nav-6-2"></span>
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
<span id="nav-5-2-1"></span>
|
<span id="nav-6-2-1"></span>
|
||||||
|
|
||||||
#### Debian/Ubuntu
|
#### Debian/Ubuntu
|
||||||
|
|
||||||
@@ -176,7 +194,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
|
|||||||
|
|
||||||
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
||||||
|
|
||||||
<span id="nav-5-2-2"></span>
|
<span id="nav-6-2-2"></span>
|
||||||
|
|
||||||
#### Arch Linux / ArchLabs / Ctlos Linux
|
#### Arch Linux / ArchLabs / Ctlos Linux
|
||||||
|
|
||||||
@@ -184,7 +202,7 @@ _Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, K
|
|||||||
|
|
||||||
_Also succesfully test on: Manjaro & ArcoLinux_
|
_Also succesfully test on: Manjaro & ArcoLinux_
|
||||||
|
|
||||||
<span id="nav-5-2-3"></span>
|
<span id="nav-6-2-3"></span>
|
||||||
|
|
||||||
#### Centos
|
#### Centos
|
||||||
|
|
||||||
@@ -192,7 +210,7 @@ _Also succesfully test on: Manjaro & ArcoLinux_
|
|||||||
|
|
||||||
_CentOS 6, 7_
|
_CentOS 6, 7_
|
||||||
|
|
||||||
<span id="nav-5-2-4"></span>
|
<span id="nav-6-2-4"></span>
|
||||||
|
|
||||||
#### Fedora
|
#### Fedora
|
||||||
|
|
||||||
@@ -200,19 +218,19 @@ _CentOS 6, 7_
|
|||||||
|
|
||||||
_Fedora 29, 30_
|
_Fedora 29, 30_
|
||||||
|
|
||||||
<span id="nav-5-2-5"></span>
|
<span id="nav-6-2-5"></span>
|
||||||
|
|
||||||
#### VoidLinux & VoidLinux-musl
|
#### VoidLinux & VoidLinux-musl
|
||||||
|
|
||||||
`xbps-install gtk+3-devel webkit2gtk-devel`
|
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||||
|
|
||||||
<span id="nav-5-2-6"></span>
|
<span id="nav-6-2-6"></span>
|
||||||
|
|
||||||
#### Gentoo
|
#### Gentoo
|
||||||
|
|
||||||
`sudo emerge gtk+:3 webkit-gtk`
|
`sudo emerge gtk+:3 webkit-gtk`
|
||||||
|
|
||||||
<span id="nav-5-3"></span>
|
<span id="nav-6-3"></span>
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
@@ -220,21 +238,21 @@ Windows requires gcc and related tooling. The recommended download is
|
|||||||
from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to
|
from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to
|
||||||
go.
|
go.
|
||||||
|
|
||||||
<span id="nav-6"></span>
|
<span id="nav-7"></span>
|
||||||
|
|
||||||
## Installation
|
## Usage
|
||||||
|
|
||||||
**Ensure Go modules are enabled: GO111MODULE=on and go/bin is in your PATH variable.**
|
**Ensure Go modules are enabled: GO111MODULE=on and go/bin is in your PATH variable.**
|
||||||
|
|
||||||
Installation is as simple as running the following command:
|
Installation is as simple as running the following command:
|
||||||
|
|
||||||
<pre style='color:white'>
|
```
|
||||||
go get -u github.com/wailsapp/wails/cmd/wails
|
go get -u github.com/wailsapp/wails/cmd/wails
|
||||||
</pre>
|
```
|
||||||
|
|
||||||
<span id="nav-7"></span>
|
<span id="nav-7-1"></span>
|
||||||
|
|
||||||
## Next Steps
|
### Next Steps
|
||||||
|
|
||||||
It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app).
|
It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app).
|
||||||
|
|
||||||
@@ -345,7 +363,7 @@ This project was mainly coded to the following albums:
|
|||||||
|
|
||||||
<p align="center" style="text-align: center">
|
<p align="center" style="text-align: center">
|
||||||
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
||||||
A <i>huge<i/> thanks to <a href="https://pace.dev">Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
|
A <i>huge</i> thanks to <a href="https://pace.dev">Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
|
||||||
If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!<br/><br/>
|
If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!<br/><br/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<p align="center" style="text-align: center">
|
<p align="center" style="text-align: center">
|
||||||
<img src="logo.png" width="40%"><br/>
|
<img src="logo.png" width="55%"><br/>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
使用 Go 和 Web 技术构建桌面应用程序。<br/><br/>
|
使用 Go 和 Web 技术构建桌面应用程序。<br/><br/>
|
||||||
@@ -18,44 +18,62 @@
|
|||||||
|
|
||||||
## 国际化
|
## 国际化
|
||||||
|
|
||||||
[English](README.md) | 简体中文
|
[English](README.md) | [简体中文](README.zh-Hans.md)
|
||||||
|
|
||||||
向 Go 程序提供 Web 接口的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web
|
|
||||||
前端都包装成单个二进制文件的能力。通过提供工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥创意!
|
|
||||||
|
|
||||||
官方文档可以在 [https://wails.app](https://wails.app) 中找到。
|
|
||||||
|
|
||||||
国内镜像站点 [https://wails.top](https://wails.top)。
|
|
||||||
|
|
||||||
<span id="nav-2"></span>
|
<span id="nav-2"></span>
|
||||||
|
|
||||||
## 内容目录
|
## 内容目录
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>点我 打开/关闭 目录列表</summary>
|
||||||
|
|
||||||
- [1. 国际化](#nav-1)
|
- [1. 国际化](#nav-1)
|
||||||
- [2. 内容目录](#nav-2)
|
- [2. 内容目录](#nav-2)
|
||||||
- [3. 特征](#nav-3)
|
- [3. 项目介绍](#nav-3)
|
||||||
- [4. 赞助商](#nav-4)
|
- [3.1 官方网站](#nav-3-1)
|
||||||
- [5. 安装](#nav-5)
|
- [4. 功能](#nav-4)
|
||||||
- [5.1 MacOS](#nav-5-1)
|
- [5. 赞助商](#nav-5)
|
||||||
- [5.2 Linux](#nav-5-2)
|
|
||||||
- [5.2.1 Debian/Ubuntu](#nav-5-2-1)
|
|
||||||
- [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2)
|
|
||||||
- [5.2.3 Centos](#nav-5-2-3)
|
|
||||||
- [5.2.4 Fedora](#nav-5-2-4)
|
|
||||||
- [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5)
|
|
||||||
- [5.2.6 Gentoo](#nav-5-2-6)
|
|
||||||
- [5.3 Windows](#nav-5-3)
|
|
||||||
- [6. 安装](#nav-6)
|
- [6. 安装](#nav-6)
|
||||||
- [7. 下一步](#nav-7)
|
- [6.1 MacOS](#nav-6-1)
|
||||||
|
- [6.2 Linux](#nav-6-2)
|
||||||
|
- [6.2.1 Debian/Ubuntu](#nav-6-2-1)
|
||||||
|
- [6.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-6-2-2)
|
||||||
|
- [6.2.3 Centos](#nav-6-2-3)
|
||||||
|
- [6.2.4 Fedora](#nav-6-2-4)
|
||||||
|
- [6.2.5 VoidLinux & VoidLinux-musl](#nav-6-2-5)
|
||||||
|
- [6.2.6 Gentoo](#nav-6-2-6)
|
||||||
|
- [6.3 Windows](#nav-6-3)
|
||||||
|
- [7. 使用方法](#nav-7)
|
||||||
|
- [7.1 下一步](#nav-7-1)
|
||||||
- [8. 常见问题](#nav-8)
|
- [8. 常见问题](#nav-8)
|
||||||
- [9. 贡献者](#nav-9)
|
- [9. 贡献者](#nav-9)
|
||||||
- [10. 特别提及](#nav-10)
|
- [10. 特别提及](#nav-10)
|
||||||
- [11. 许可协议](#nav-11)
|
- [12. 特别感谢](#nav-11)
|
||||||
- [12. 特别感谢](#nav-12)
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<span id="nav-3"></span>
|
<span id="nav-3"></span>
|
||||||
|
|
||||||
## 特征
|
## 项目介绍
|
||||||
|
|
||||||
|
为 Go 程序提供 Web 界面的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web
|
||||||
|
前端一起打包成单个二进制文件的能力。通过提供的工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥想象力!
|
||||||
|
|
||||||
|
<span id="nav-3-1"></span>
|
||||||
|
|
||||||
|
### 官方网站
|
||||||
|
|
||||||
|
官方文档可以在 [https://wails.app](https://wails.app) 中找到。
|
||||||
|
|
||||||
|
如果您对适用于 Windows 的 v2 测试版感兴趣,可以点击[此处](https://wails.io)查看。
|
||||||
|
|
||||||
|
镜像网站:
|
||||||
|
|
||||||
|
- [中国大陆镜像站点 - https://wails.top](https://wails.top)
|
||||||
|
|
||||||
|
<span id="nav-4"></span>
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
- 后端使用标准 Go
|
- 后端使用标准 Go
|
||||||
- 使用任意前端技术构建 UI 界面
|
- 使用任意前端技术构建 UI 界面
|
||||||
@@ -67,13 +85,12 @@
|
|||||||
- 强大的命令行工具
|
- 强大的命令行工具
|
||||||
- 跨多个平台
|
- 跨多个平台
|
||||||
|
|
||||||
<span id="nav-4"></span>
|
<span id="nav-5"></span>
|
||||||
|
|
||||||
## 赞助商
|
## 赞助商
|
||||||
|
|
||||||
这个项目由以下这些人或者公司支持:
|
这个项目由以下这些人或者公司支持:
|
||||||
|
|
||||||
|
|
||||||
<a href="https://github.com/sponsors/leaanthony" style="width:100px;">
|
<a href="https://github.com/sponsors/leaanthony" style="width:100px;">
|
||||||
<img src="sponsors/bronze%20sponsor.png" width="100"/>
|
<img src="sponsors/bronze%20sponsor.png" width="100"/>
|
||||||
</a>
|
</a>
|
||||||
@@ -83,6 +100,9 @@
|
|||||||
<a href="https://github.com/codydbentley" style="width:100px">
|
<a href="https://github.com/codydbentley" style="width:100px">
|
||||||
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/CrackDavid" style="width:100px">
|
||||||
|
<img src="https://github.com/CrackDavid.png?size=100" width="100"/>
|
||||||
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://github.com/matryer" style="width:100px">
|
<a href="https://github.com/matryer" style="width:100px">
|
||||||
@@ -143,7 +163,7 @@
|
|||||||
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<span id="nav-5"></span>
|
<span id="nav-6"></span>
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
@@ -152,7 +172,7 @@ Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的
|
|||||||
- Go 1.16
|
- Go 1.16
|
||||||
- npm
|
- npm
|
||||||
|
|
||||||
<span id="nav-5-1"></span>
|
<span id="nav-6-1"></span>
|
||||||
|
|
||||||
### MacOS
|
### MacOS
|
||||||
|
|
||||||
@@ -160,11 +180,11 @@ Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的
|
|||||||
|
|
||||||
`xcode-select --install`
|
`xcode-select --install`
|
||||||
|
|
||||||
<span id="nav-5-2"></span>
|
<span id="nav-6-2"></span>
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
<span id="nav-5-2-1"></span>
|
<span id="nav-6-2-1"></span>
|
||||||
|
|
||||||
#### Debian/Ubuntu
|
#### Debian/Ubuntu
|
||||||
|
|
||||||
@@ -176,7 +196,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
|
|||||||
|
|
||||||
_也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
_也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
||||||
|
|
||||||
<span id="nav-5-2-2"></span>
|
<span id="nav-6-2-2"></span>
|
||||||
|
|
||||||
#### Arch Linux / ArchLabs / Ctlos Linux
|
#### Arch Linux / ArchLabs / Ctlos Linux
|
||||||
|
|
||||||
@@ -184,7 +204,7 @@ _也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neo
|
|||||||
|
|
||||||
_也成功测试了: Manjaro & ArcoLinux_
|
_也成功测试了: Manjaro & ArcoLinux_
|
||||||
|
|
||||||
<span id="nav-5-2-3"></span>
|
<span id="nav-6-2-3"></span>
|
||||||
|
|
||||||
#### Centos
|
#### Centos
|
||||||
|
|
||||||
@@ -192,7 +212,7 @@ _也成功测试了: Manjaro & ArcoLinux_
|
|||||||
|
|
||||||
_CentOS 6, 7_
|
_CentOS 6, 7_
|
||||||
|
|
||||||
<span id="nav-5-2-4"></span>
|
<span id="nav-6-2-4"></span>
|
||||||
|
|
||||||
#### Fedora
|
#### Fedora
|
||||||
|
|
||||||
@@ -200,39 +220,39 @@ _CentOS 6, 7_
|
|||||||
|
|
||||||
_Fedora 29, 30_
|
_Fedora 29, 30_
|
||||||
|
|
||||||
<span id="nav-5-2-5"></span>
|
<span id="nav-6-2-5"></span>
|
||||||
|
|
||||||
#### VoidLinux & VoidLinux-musl
|
#### VoidLinux & VoidLinux-musl
|
||||||
|
|
||||||
`xbps-install gtk+3-devel webkit2gtk-devel`
|
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||||
|
|
||||||
<span id="nav-5-2-6"></span>
|
<span id="nav-6-2-6"></span>
|
||||||
|
|
||||||
#### Gentoo
|
#### Gentoo
|
||||||
|
|
||||||
`sudo emerge gtk+:3 webkit-gtk`
|
`sudo emerge gtk+:3 webkit-gtk`
|
||||||
|
|
||||||
<span id="nav-5-3"></span>
|
<span id="nav-6-3"></span>
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
Windows 需要 GCC 和相关工具。 建议从 [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download) 下载, 安装完成,您就可以开始了。
|
Windows 需要 GCC 和相关工具。 建议从 [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download) 下载, 安装完成,您就可以开始了。
|
||||||
|
|
||||||
<span id="nav-6"></span>
|
<span id="nav-7"></span>
|
||||||
|
|
||||||
## 安装
|
## 使用方法
|
||||||
|
|
||||||
**确保 Go modules 是开启的:GO111MODULE=on 并且 go/bin 在您的 PATH 变量中。**
|
**确保 Go modules 是开启的:GO111MODULE=on 并且 go/bin 在您的 PATH 变量中。**
|
||||||
|
|
||||||
安装很简单,运行以下命令:
|
安装很简单,运行以下命令:
|
||||||
|
|
||||||
<pre style='color:white'>
|
```
|
||||||
go get -u github.com/wailsapp/wails/cmd/wails
|
go get -u github.com/wailsapp/wails/cmd/wails
|
||||||
</pre>
|
```
|
||||||
|
|
||||||
<span id="nav-7"></span>
|
<span id="nav-7-1"></span>
|
||||||
|
|
||||||
## 下一步
|
### 下一步
|
||||||
|
|
||||||
建议在此时阅读 [https://wails.app](https://wails.app) 上面的文档.
|
建议在此时阅读 [https://wails.app](https://wails.app) 上面的文档.
|
||||||
|
|
||||||
@@ -244,14 +264,14 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
|||||||
|
|
||||||
取决于您的要求。它旨在使 Go 程序员可以轻松制作轻量级桌面应用程序或在其现有应用程序中添加前端。尽管 Wails 当前不提供对诸如菜单之类的原生元素的钩子,但将来可能会改变。
|
取决于您的要求。它旨在使 Go 程序员可以轻松制作轻量级桌面应用程序或在其现有应用程序中添加前端。尽管 Wails 当前不提供对诸如菜单之类的原生元素的钩子,但将来可能会改变。
|
||||||
|
|
||||||
- 这个项目针对的是谁?
|
- 这个项目针对的是哪些人?
|
||||||
|
|
||||||
希望将 HTML / JS / CSS 前端与其应用程序捆绑在一起的程序员,而不是借助创建服务并打开浏览器进行查看的方式。
|
希望将 HTML / JS / CSS 前端与其应用程序捆绑在一起的程序员,而不是借助创建服务并打开浏览器进行查看的方式。
|
||||||
|
|
||||||
- 名字怎么来的?
|
- 名字怎么来的?
|
||||||
|
|
||||||
当我看到 WebView 时,我想"我真正想要的是围绕构建 WebView 应用程序工作,有点像 Rails 对于 Ruby"。因此,最初它是一个文字游戏(Webview on
|
当我看到 WebView 时,我想"我真正想要的是围绕构建 WebView 应用程序工作,有点像 Rails 对于 Ruby"。因此,最初它是一个文字游戏(Webview on
|
||||||
Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是他了。
|
Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是它了。
|
||||||
|
|
||||||
<span id="nav-9"></span>
|
<span id="nav-9"></span>
|
||||||
|
|
||||||
@@ -302,6 +322,7 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
|||||||
<a href="https://github.com/Igogrek"><img src="https://github.com/Igogrek.png?size=40" width="40"/></a></a>
|
<a href="https://github.com/Igogrek"><img src="https://github.com/Igogrek.png?size=40" width="40"/></a></a>
|
||||||
<a href="https://github.com/aschey"><img src="https://github.com/aschey.png?size=40" width="40"/></a></a>
|
<a href="https://github.com/aschey"><img src="https://github.com/aschey.png?size=40" width="40"/></a></a>
|
||||||
<a href="https://github.com/akhudek"><img src="https://github.com/akhudek.png?size=40" width="40"/></a></a>
|
<a href="https://github.com/akhudek"><img src="https://github.com/akhudek.png?size=40" width="40"/></a></a>
|
||||||
|
<a href="https://github.com/s12chung"><img src="https://github.com/s12chung.png?size=40" width="40"/></a></a>
|
||||||
|
|
||||||
<span id="nav-10"></span>
|
<span id="nav-10"></span>
|
||||||
|
|
||||||
@@ -311,9 +332,9 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
|||||||
|
|
||||||
- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - 他的支持和反馈是巨大的。
|
- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - 他的支持和反馈是巨大的。
|
||||||
- [Serge Zaitsev](https://github.com/zserge) - Wails 窗口所使用的 [Webview](https://github.com/zserge/webview) 的作者。
|
- [Serge Zaitsev](https://github.com/zserge) - Wails 窗口所使用的 [Webview](https://github.com/zserge/webview) 的作者。
|
||||||
- [Byron](https://github.com/bh90210) - 有时,Byron 单枪匹马地保持这个项目活着。没有他令人难以置信的投入,我们永远不会得到 v1 。
|
- [Byron](https://github.com/bh90210) - 有时,Byron 一个人保持这个项目活跃着。没有他令人难以置信的投入,我们永远不会得到 v1 。
|
||||||
|
|
||||||
This project was mainly coded to the following albums:
|
编写项目代码时伴随着以下专辑:
|
||||||
|
|
||||||
- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA)
|
- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA)
|
||||||
- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN)
|
- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN)
|
||||||
@@ -331,17 +352,11 @@ This project was mainly coded to the following albums:
|
|||||||
|
|
||||||
<span id="nav-11"></span>
|
<span id="nav-11"></span>
|
||||||
|
|
||||||
## 许可协议
|
|
||||||
|
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
|
||||||
|
|
||||||
<span id="nav-12"></span>
|
|
||||||
|
|
||||||
## 特别感谢
|
## 特别感谢
|
||||||
|
|
||||||
<p align="center" style="text-align: center">
|
<p align="center" style="text-align: center">
|
||||||
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
||||||
<i>非常<i/>感谢<a href="https://pace.dev">Pace</a>对项目的赞助,并帮助将 Wails 移植到 Apple Silicon !<br/><br/>
|
<i>非常</i> 感谢<a href="https://pace.dev">Pace</a>对项目的赞助,并帮助将 Wails 移植到 Apple Silicon !<br/><br/>
|
||||||
如果您正在寻找一个强大并且快速和易于使用的项目管理工具,可以看看他们!<br/><br/>
|
如果您正在寻找一个强大并且快速和易于使用的项目管理工具,可以看看他们!<br/><br/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v1.16.7"
|
const Version = "v1.16.8"
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/system"
|
"github.com/wailsapp/wails/v2/internal/system"
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
"github.com/leaanthony/clir"
|
||||||
@@ -42,7 +46,7 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
|
|
||||||
// Setup Platform flag
|
// Setup Platform flag
|
||||||
platform := runtime.GOOS
|
platform := runtime.GOOS
|
||||||
//command.StringFlag("platform", "Platform to target", &platform)
|
command.StringFlag("platform", "Platform to target", &platform)
|
||||||
|
|
||||||
// Verbosity
|
// Verbosity
|
||||||
verbosity := 1
|
verbosity := 1
|
||||||
@@ -95,14 +99,14 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
"darwin/amd64",
|
"darwin/amd64",
|
||||||
"darwin/arm64",
|
"darwin/arm64",
|
||||||
"darwin/universal",
|
"darwin/universal",
|
||||||
"linux",
|
//"linux",
|
||||||
//"linux/amd64",
|
//"linux/amd64",
|
||||||
//"linux/arm-7",
|
//"linux/arm-7",
|
||||||
"windows",
|
"windows",
|
||||||
"windows/amd64",
|
"windows/amd64",
|
||||||
})
|
})
|
||||||
if !validPlatformArch.Contains(platform) {
|
if !validPlatformArch.Contains(platform) {
|
||||||
return fmt.Errorf("platform %s is not supported", platform)
|
return fmt.Errorf("platform %s is not supported. Platforms supported: %s", platform, validPlatformArch.Join(","))
|
||||||
}
|
}
|
||||||
|
|
||||||
if compress && platform == "darwin/universal" {
|
if compress && platform == "darwin/universal" {
|
||||||
@@ -129,8 +133,8 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" && !experimental {
|
if runtime.GOOS == "linux" && !experimental {
|
||||||
return fmt.Errorf("MacOS version coming soon!")
|
return fmt.Errorf("Linux version coming soon!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Webview2 installer strategy (download by default)
|
// Webview2 installer strategy (download by default)
|
||||||
@@ -205,6 +209,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
|
||||||
|
err = checkGoModVersion(logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return doBuild(buildOptions)
|
return doBuild(buildOptions)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -228,3 +237,29 @@ func doBuild(buildOptions *build.Options) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkGoModVersion(logger *clilogger.CLILogger) error {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gomodFilename := filepath.Join(cwd, "go.mod")
|
||||||
|
gomodData, err := os.ReadFile(gomodFilename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !outOfSync {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
gomodversion, err := gomod.GetWailsVersionFromModFile(gomodData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Println("Warning: go.mod is using Wails '%s' but the CLI is '%s'. Consider updating it.\n", gomodversion.String(), internal.Version)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||||
"github.com/wailsapp/wails/v2/internal/gomod"
|
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
|
|
||||||
"github.com/pkg/browser"
|
"github.com/pkg/browser"
|
||||||
@@ -72,6 +72,7 @@ type devFlags struct {
|
|||||||
forceBuild bool
|
forceBuild bool
|
||||||
debounceMS int
|
debounceMS int
|
||||||
devServerURL string
|
devServerURL string
|
||||||
|
appargs string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSubcommand adds the `dev` command for the Wails application
|
// AddSubcommand adds the `dev` command for the Wails application
|
||||||
@@ -93,6 +94,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
command.BoolFlag("f", "Force build application", &flags.forceBuild)
|
command.BoolFlag("f", "Force build application", &flags.forceBuild)
|
||||||
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
|
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
|
||||||
command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL)
|
command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL)
|
||||||
|
command.StringFlag("appargs", "arguments to pass to the underlying app (quoted and space searated)", &flags.appargs)
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
// Create logger
|
// Create logger
|
||||||
@@ -111,8 +113,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" && !experimental {
|
if runtime.GOOS == "linux" && !experimental {
|
||||||
return fmt.Errorf("MacOS version coming soon!")
|
return fmt.Errorf("Linux version coming soon!")
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
@@ -353,6 +355,10 @@ func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, e
|
|||||||
shouldSaveConfig = true
|
shouldSaveConfig = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flags.appargs == "" && projectConfig.AppArgs != "" {
|
||||||
|
flags.appargs = projectConfig.AppArgs
|
||||||
|
}
|
||||||
|
|
||||||
if shouldSaveConfig {
|
if shouldSaveConfig {
|
||||||
err = projectConfig.Save()
|
err = projectConfig.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -463,16 +469,20 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
|||||||
debugBinaryProcess = nil
|
debugBinaryProcess = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse appargs if any
|
||||||
|
args, err := shlex.Split(flags.appargs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set environment variables accordingly
|
||||||
|
os.Setenv("loglevel", flags.loglevel)
|
||||||
|
os.Setenv("assetdir", flags.assetDir)
|
||||||
|
os.Setenv("devserverurl", flags.devServerURL)
|
||||||
|
|
||||||
// Start up new binary with correct args
|
// Start up new binary with correct args
|
||||||
args := slicer.StringSlicer{}
|
newProcess := process.NewProcess(appBinary, args...)
|
||||||
args.Add("-loglevel", flags.loglevel)
|
|
||||||
if flags.assetDir != "" {
|
|
||||||
args.Add("-assetdir", flags.assetDir)
|
|
||||||
}
|
|
||||||
if flags.devServerURL != "" {
|
|
||||||
args.Add("-devserverurl", flags.devServerURL)
|
|
||||||
}
|
|
||||||
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
|
|
||||||
err = newProcess.Start(exitCodeChannel)
|
err = newProcess.Start(exitCodeChannel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Remove binary
|
// Remove binary
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
html {
|
html {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: rgba(0, 0, 0, 255);
|
background-color: rgba(33, 37, 43, 0.2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
@@ -13,6 +15,9 @@ import (
|
|||||||
//go:embed frontend/dist
|
//go:embed frontend/dist
|
||||||
var assets embed.FS
|
var assets embed.FS
|
||||||
|
|
||||||
|
//go:embed build/appicon.png
|
||||||
|
var icon []byte
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create an instance of the app structure
|
// Create an instance of the app structure
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
@@ -31,7 +36,7 @@ func main() {
|
|||||||
Frameless: false,
|
Frameless: false,
|
||||||
StartHidden: false,
|
StartHidden: false,
|
||||||
HideWindowOnClose: false,
|
HideWindowOnClose: false,
|
||||||
RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
RGBA: &options.RGBA{R: 33, G: 37, B: 43, A: 255},
|
||||||
Assets: assets,
|
Assets: assets,
|
||||||
LogLevel: logger.DEBUG,
|
LogLevel: logger.DEBUG,
|
||||||
OnStartup: app.startup,
|
OnStartup: app.startup,
|
||||||
@@ -46,6 +51,17 @@ func main() {
|
|||||||
WindowIsTranslucent: false,
|
WindowIsTranslucent: false,
|
||||||
DisableWindowIcon: false,
|
DisableWindowIcon: false,
|
||||||
},
|
},
|
||||||
|
Mac: &mac.Options{
|
||||||
|
TitleBar: mac.TitleBarHiddenInset(),
|
||||||
|
Appearance: mac.NSAppearanceNameDarkAqua,
|
||||||
|
WebviewIsTransparent: true,
|
||||||
|
WindowIsTranslucent: true,
|
||||||
|
About: &mac.AboutInfo{
|
||||||
|
Title: "My Application",
|
||||||
|
Message: "© 2021 Me",
|
||||||
|
Icon: icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"assetdir": "frontend/dist",
|
"assetdir": "frontend/dist",
|
||||||
"frontend:install": "npm install",
|
"frontend:install": "npm install",
|
||||||
"frontend:build": "npm run build",
|
"frontend:build": "npm run build",
|
||||||
|
"wailsjsdir": "./frontend",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "{{.AuthorName}}",
|
"name": "{{.AuthorName}}",
|
||||||
"email": "{{.AuthorEmail}}"
|
"email": "{{.AuthorEmail}}"
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
html {
|
html {
|
||||||
background-color: rgba(33, 37, 43, 1);
|
background-color: rgba(33, 37, 43, 0.2);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: white;
|
|
||||||
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
sans-serif;
|
sans-serif;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
@@ -13,6 +15,9 @@ import (
|
|||||||
//go:embed frontend/src
|
//go:embed frontend/src
|
||||||
var assets embed.FS
|
var assets embed.FS
|
||||||
|
|
||||||
|
//go:embed build/appicon.png
|
||||||
|
var icon []byte
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create an instance of the app structure
|
// Create an instance of the app structure
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
@@ -31,7 +36,7 @@ func main() {
|
|||||||
Frameless: false,
|
Frameless: false,
|
||||||
StartHidden: false,
|
StartHidden: false,
|
||||||
HideWindowOnClose: false,
|
HideWindowOnClose: false,
|
||||||
RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
RGBA: &options.RGBA{R: 33, G: 37, B: 43, A: 255},
|
||||||
Assets: assets,
|
Assets: assets,
|
||||||
LogLevel: logger.DEBUG,
|
LogLevel: logger.DEBUG,
|
||||||
OnStartup: app.startup,
|
OnStartup: app.startup,
|
||||||
@@ -46,6 +51,16 @@ func main() {
|
|||||||
WindowIsTranslucent: false,
|
WindowIsTranslucent: false,
|
||||||
DisableWindowIcon: false,
|
DisableWindowIcon: false,
|
||||||
},
|
},
|
||||||
|
Mac: &mac.Options{
|
||||||
|
TitleBar: mac.TitleBarHiddenInset(),
|
||||||
|
WebviewIsTransparent: true,
|
||||||
|
WindowIsTranslucent: true,
|
||||||
|
About: &mac.AboutInfo{
|
||||||
|
Title: "Vanilla Template",
|
||||||
|
Message: "Part of the Wails projects",
|
||||||
|
Icon: icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "{{.ProjectName}}",
|
"name": "{{.ProjectName}}",
|
||||||
"outputfilename": "{{.BinaryName}}",
|
"outputfilename": "{{.BinaryName}}",
|
||||||
"assetdir": "frontend/src",
|
"assetdir": "frontend/src",
|
||||||
|
"wailsjsdir": "./frontend",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "{{.AuthorName}}",
|
"name": "{{.AuthorName}}",
|
||||||
"email": "{{.AuthorEmail}}"
|
"email": "{{.AuthorEmail}}"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
var Version = "v2.0.0-beta.15"
|
var Version = "v2.0.0-beta.20"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ require (
|
|||||||
github.com/gofiber/fiber/v2 v2.17.0
|
github.com/gofiber/fiber/v2 v2.17.0
|
||||||
github.com/gofiber/websocket/v2 v2.0.8
|
github.com/gofiber/websocket/v2 v2.0.8
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
github.com/gorilla/websocket v1.4.1
|
github.com/gorilla/websocket v1.4.1
|
||||||
github.com/imdario/mergo v0.3.12
|
github.com/imdario/mergo v0.3.12
|
||||||
@@ -60,6 +61,7 @@ require (
|
|||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||||
github.com/klauspost/compress v1.12.2 // indirect
|
github.com/klauspost/compress v1.12.2 // indirect
|
||||||
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
|
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@@ -101,8 +103,9 @@ github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
|
|||||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
@@ -159,6 +162,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
|
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
|
||||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
|
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
@@ -280,10 +285,12 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ func generateBindings(bindings *binding.Bindings) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if projectConfig.WailsJSDir == "" {
|
||||||
|
projectConfig.WailsJSDir = filepath.Join(cwd, "frontend")
|
||||||
|
}
|
||||||
wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime")
|
wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime")
|
||||||
_ = os.RemoveAll(wrapperDir)
|
_ = os.RemoveAll(wrapperDir)
|
||||||
extractor := gosod.New(wrapper.RuntimeWrapper)
|
extractor := gosod.New(wrapper.RuntimeWrapper)
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ package appng
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||||
@@ -16,18 +19,14 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
"github.com/wailsapp/wails/v2/internal/signal"
|
|
||||||
pkglogger "github.com/wailsapp/wails/v2/pkg/logger"
|
pkglogger "github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// App defines a Wails application structure
|
// App defines a Wails application structure
|
||||||
type App struct {
|
type App struct {
|
||||||
frontend frontend.Frontend
|
frontend frontend.Frontend
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
signal *signal.Manager
|
|
||||||
options *options.App
|
options *options.App
|
||||||
|
|
||||||
menuManager *menumanager.Manager
|
menuManager *menumanager.Manager
|
||||||
@@ -60,19 +59,47 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||||
|
|
||||||
// Check for CLI Flags
|
// Check for CLI Flags
|
||||||
assetdir := flag.String("assetdir", "", "Directory to serve assets")
|
var assetdirFlag *string
|
||||||
devServerURL := flag.String("devserverurl", "", "URL of development server")
|
var devServerURLFlag *string
|
||||||
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
var loglevelFlag *string
|
||||||
flag.Parse()
|
|
||||||
if devServerURL != nil && *devServerURL != "" {
|
assetdir := os.Getenv("assetdir")
|
||||||
ctx = context.WithValue(ctx, "devserverurl", *devServerURL)
|
if assetdir == "" {
|
||||||
|
assetdirFlag = flag.String("assetdir", "", "Directory to serve assets")
|
||||||
}
|
}
|
||||||
if assetdir != nil && *assetdir != "" {
|
devServerURL := os.Getenv("devserverurl")
|
||||||
ctx = context.WithValue(ctx, "assetdir", *assetdir)
|
if devServerURL == "" {
|
||||||
|
devServerURLFlag = flag.String("devserverurl", "", "URL of development server")
|
||||||
}
|
}
|
||||||
|
|
||||||
if loglevel != nil && *loglevel != "" {
|
loglevel := os.Getenv("loglevel")
|
||||||
level, err := pkglogger.StringToLogLevel(*loglevel)
|
if loglevel == "" {
|
||||||
|
loglevelFlag = flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we weren't given the assetdir in the environment variables
|
||||||
|
if assetdir == "" {
|
||||||
|
flag.Parse()
|
||||||
|
if assetdirFlag != nil {
|
||||||
|
assetdir = *assetdirFlag
|
||||||
|
}
|
||||||
|
if devServerURLFlag != nil {
|
||||||
|
devServerURL = *devServerURLFlag
|
||||||
|
}
|
||||||
|
if loglevelFlag != nil {
|
||||||
|
loglevel = *loglevelFlag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if devServerURL != "" {
|
||||||
|
ctx = context.WithValue(ctx, "devserverurl", devServerURL)
|
||||||
|
}
|
||||||
|
if assetdir != "" {
|
||||||
|
ctx = context.WithValue(ctx, "assetdir", assetdir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if loglevel != "" {
|
||||||
|
level, err := pkglogger.StringToLogLevel(loglevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package appng
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||||
"github.com/wailsapp/wails/v2/internal/signal"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
type App struct {
|
type App struct {
|
||||||
frontend frontend.Frontend
|
frontend frontend.Frontend
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
signal *signal.Manager
|
|
||||||
options *options.App
|
options *options.App
|
||||||
|
|
||||||
menuManager *menumanager.Manager
|
menuManager *menumanager.Manager
|
||||||
@@ -36,9 +35,6 @@ type App struct {
|
|||||||
|
|
||||||
func (a *App) Run() error {
|
func (a *App) Run() error {
|
||||||
err := a.frontend.Run(a.ctx)
|
err := a.frontend.Run(a.ctx)
|
||||||
if a.shutdownCallback != nil {
|
|
||||||
a.shutdownCallback(a.ctx)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,13 @@
|
|||||||
#define AppDelegate_h
|
#define AppDelegate_h
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
@interface AppDelegate : NSResponder <NSTouchBarProvider>
|
@interface AppDelegate : NSResponder <NSTouchBarProvider>
|
||||||
|
|
||||||
@property bool alwaysOnTop;
|
@property bool alwaysOnTop;
|
||||||
@property (retain) NSWindow* mainWindow;
|
@property bool startHidden;
|
||||||
|
@property (retain) WailsWindow* mainWindow;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -16,37 +16,21 @@
|
|||||||
}
|
}
|
||||||
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
|
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
|
||||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
[self.mainWindow makeKeyAndOrderFront:self];
|
|
||||||
if (self.alwaysOnTop) {
|
if (self.alwaysOnTop) {
|
||||||
[self.mainWindow setLevel:NSStatusWindowLevel];
|
[self.mainWindow setLevel:NSStatusWindowLevel];
|
||||||
}
|
}
|
||||||
|
if ( !self.startHidden ) {
|
||||||
|
[self.mainWindow makeKeyAndOrderFront:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
}
|
}
|
||||||
//
|
|
||||||
//- (void) CreateMenu {
|
- (void)dealloc {
|
||||||
// [NSApplication sharedApplication];
|
[super dealloc];
|
||||||
// menubar = [[NSMenu new] autorelease];
|
}
|
||||||
// id appMenuItem = [[NSMenuItem new] autorelease];
|
|
||||||
// [menubar addItem:appMenuItem];
|
|
||||||
// [NSApp setMainMenu:menubar];
|
|
||||||
// id appMenu = [[NSMenu new] autorelease];
|
|
||||||
// id appName = [[NSProcessInfo processInfo] processName];
|
|
||||||
// id quitTitle = [@"Quit " stringByAppendingString:appName];
|
|
||||||
// id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
|
|
||||||
// action:@selector(terminate:) keyEquivalent:@"q"]
|
|
||||||
// autorelease];
|
|
||||||
// [appMenu addItem:quitMenuItem];
|
|
||||||
// [appMenuItem setSubmenu:appMenu];
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//- (void) dealloc {
|
|
||||||
// [super dealloc];
|
|
||||||
// window = nil;
|
|
||||||
// menubar = nil;
|
|
||||||
//}
|
|
||||||
|
|
||||||
@synthesize touchBar;
|
@synthesize touchBar;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,12 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "WailsContext.h"
|
#import "WailsContext.h"
|
||||||
|
|
||||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug);
|
#define WindowStartsNormal 0
|
||||||
|
#define WindowStartsMaximised 1
|
||||||
|
#define WindowStartsMinimised 2
|
||||||
|
#define WindowStartsFullscreen 3
|
||||||
|
|
||||||
|
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden);
|
||||||
void Run(void*);
|
void Run(void*);
|
||||||
|
|
||||||
void SetTitle(void* ctx, const char *title);
|
void SetTitle(void* ctx, const char *title);
|
||||||
@@ -36,9 +41,26 @@ void Quit(void*);
|
|||||||
const char* GetSize(void *ctx);
|
const char* GetSize(void *ctx);
|
||||||
const char* GetPos(void *ctx);
|
const char* GetPos(void *ctx);
|
||||||
|
|
||||||
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char *data, int datalength);
|
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength);
|
||||||
|
|
||||||
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton);
|
/* Dialogs */
|
||||||
|
|
||||||
|
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength);
|
||||||
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters);
|
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters);
|
||||||
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters);
|
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters);
|
||||||
|
|
||||||
|
/* Application Menu */
|
||||||
|
void* NewMenu(const char* name);
|
||||||
|
void AppendSubmenu(void* parent, void* child);
|
||||||
|
void AppendRole(void *inctx, void *inMenu, int role);
|
||||||
|
void SetAsApplicationMenu(void *inctx, void *inMenu);
|
||||||
|
void UpdateApplicationMenu(void *inctx);
|
||||||
|
|
||||||
|
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen);
|
||||||
|
void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID);
|
||||||
|
void AppendSeparator(void* inMenu);
|
||||||
|
void UpdateMenuItem(void* nsmenuitem, int checked);
|
||||||
|
|
||||||
|
NSString* safeInit(const char* input);
|
||||||
|
|
||||||
#endif /* Application_h */
|
#endif /* Application_h */
|
||||||
|
|||||||
@@ -9,27 +9,48 @@
|
|||||||
#import "WailsContext.h"
|
#import "WailsContext.h"
|
||||||
#import "Application.h"
|
#import "Application.h"
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
#import "WailsMenu.h"
|
||||||
|
#import "WailsMenuItem.h"
|
||||||
|
|
||||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug) {
|
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden) {
|
||||||
|
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
|
||||||
WailsContext *result = [WailsContext new];
|
WailsContext *result = [WailsContext new];
|
||||||
|
|
||||||
result.debug = debug;
|
result.debug = debug;
|
||||||
|
|
||||||
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :appearance :windowIsTranslucent];
|
if ( windowStartState == WindowStartsFullscreen ) {
|
||||||
[result SetTitle:title];
|
fullscreen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent];
|
||||||
|
[result SetTitle:safeInit(title)];
|
||||||
[result Center];
|
[result Center];
|
||||||
|
|
||||||
|
switch( windowStartState ) {
|
||||||
|
case WindowStartsMaximised:
|
||||||
|
[result.mainWindow zoom:nil];
|
||||||
|
break;
|
||||||
|
case WindowStartsMinimised:
|
||||||
|
//TODO: Can you start a mac app minimised?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( startsHidden == 1 ) {
|
||||||
|
result.startHidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
result.alwaysOnTop = alwaysOnTop;
|
result.alwaysOnTop = alwaysOnTop;
|
||||||
result.hideOnClose = hideWindowOnClose;
|
result.hideOnClose = hideWindowOnClose;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char* data, int datalength) {
|
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
NSString *nsurl = [[NSString alloc] initWithUTF8String:url];
|
NSString *nsurl = safeInit(url);
|
||||||
NSString *nsContentType = [[NSString alloc] initWithUTF8String:contentType];
|
NSString *nsContentType = safeInit(contentType);
|
||||||
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
|
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
|
||||||
|
|
||||||
[ctx processURLResponse:nsurl :nsContentType :nsdata];
|
[ctx processURLResponse:nsurl :nsContentType :nsdata];
|
||||||
@@ -37,15 +58,17 @@ void ProcessURLResponse(void *inctx, const char *url, const char *contentType, c
|
|||||||
|
|
||||||
void ExecJS(void* inctx, const char *script) {
|
void ExecJS(void* inctx, const char *script) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
NSString *nsscript = safeInit(script);
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx ExecJS:script];
|
[ctx ExecJS:nsscript];
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTitle(void* inctx, const char *title) {
|
void SetTitle(void* inctx, const char *title) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
NSString *_title = safeInit(title);
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx SetTitle:title];
|
[ctx SetTitle:_title];
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +104,7 @@ void SetMaxSize(void* inctx, int width, int height) {
|
|||||||
void SetPosition(void* inctx, int x, int y) {
|
void SetPosition(void* inctx, int x, int y) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx SetSize:x :y];
|
[ctx SetPosition:x :y];
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,42 +196,137 @@ void Show(void *inctx) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton) {
|
NSString* safeInit(const char* input) {
|
||||||
|
NSString *result = nil;
|
||||||
|
if (input != nil) {
|
||||||
|
result = [NSString stringWithUTF8String:input];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
|
||||||
|
NSString *_dialogType = safeInit(dialogType);
|
||||||
|
NSString *_title = safeInit(title);
|
||||||
|
NSString *_message = safeInit(message);
|
||||||
|
NSString *_button1 = safeInit(button1);
|
||||||
|
NSString *_button2 = safeInit(button2);
|
||||||
|
NSString *_button3 = safeInit(button3);
|
||||||
|
NSString *_button4 = safeInit(button4);
|
||||||
|
NSString *_defaultButton = safeInit(defaultButton);
|
||||||
|
NSString *_cancelButton = safeInit(cancelButton);
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx MessageDialog:dialogType :title :message :button1 :button2 :button3 :button4 :defaultButton :cancelButton];
|
[ctx MessageDialog:_dialogType :_title :_message :_button1 :_button2 :_button3 :_button4 :_defaultButton :_cancelButton :iconData :iconDataLength];
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) {
|
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) {
|
||||||
|
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
NSString *_title = safeInit(title);
|
||||||
|
NSString *_defaultFilename = safeInit(defaultFilename);
|
||||||
|
NSString *_defaultDirectory = safeInit(defaultDirectory);
|
||||||
|
NSString *_filters = safeInit(filters);
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx OpenFileDialog:title :defaultFilename :defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :filters];
|
[ctx OpenFileDialog:_title :_defaultFilename :_defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :_filters];
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) {
|
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) {
|
||||||
|
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
NSString *_title = safeInit(title);
|
||||||
|
NSString *_defaultFilename = safeInit(defaultFilename);
|
||||||
|
NSString *_defaultDirectory = safeInit(defaultDirectory);
|
||||||
|
NSString *_filters = safeInit(filters);
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
[ctx SaveFileDialog:title :defaultFilename :defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :filters];
|
[ctx SaveFileDialog:_title :_defaultFilename :_defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :_filters];
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppendRole(void *inctx, void *inMenu, int role) {
|
||||||
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||||
|
[menu appendRole :ctx :role];
|
||||||
|
}
|
||||||
|
|
||||||
|
void* NewMenu(const char *name) {
|
||||||
|
NSString *title = @"";
|
||||||
|
if (name != nil) {
|
||||||
|
title = [NSString stringWithUTF8String:name];
|
||||||
|
}
|
||||||
|
WailsMenu *result = [[WailsMenu new] initWithNSTitle:title];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendSubmenu(void* inparent, void* inchild) {
|
||||||
|
WailsMenu *parent = (__bridge WailsMenu*) inparent;
|
||||||
|
WailsMenu *child = (__bridge WailsMenu*) inchild;
|
||||||
|
[parent appendSubmenu:child];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAsApplicationMenu(void *inctx, void *inMenu) {
|
||||||
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||||
|
ctx.applicationMenu = menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateApplicationMenu(void *inctx) {
|
||||||
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
NSApplication *app = [NSApplication sharedApplication];
|
||||||
|
[app setMainMenu:ctx.applicationMenu];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen) {
|
||||||
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
NSString *_title = safeInit(title);
|
||||||
|
NSString *_description = safeInit(description);
|
||||||
|
|
||||||
|
[ctx SetAbout :_title :_description :imagedata :datalen];
|
||||||
|
}
|
||||||
|
|
||||||
|
void* AppendMenuItem(void* inctx, void* inMenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID) {
|
||||||
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
|
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||||
|
NSString *_label = safeInit(label);
|
||||||
|
NSString *_shortcutKey = safeInit(shortcutKey);
|
||||||
|
|
||||||
|
return [menu AppendMenuItem:ctx :_label :_shortcutKey :modifiers :disabled :checked :menuItemID];
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateMenuItem(void* nsmenuitem, int checked) {
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem;
|
||||||
|
[menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AppendSeparator(void* inMenu) {
|
||||||
|
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||||
|
[menu AppendSeparator];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Run(void *inctx) {
|
void Run(void *inctx) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
[NSApplication sharedApplication];
|
NSApplication *app = [NSApplication sharedApplication];
|
||||||
AppDelegate* delegate = [AppDelegate new];
|
AppDelegate* delegate = [AppDelegate new];
|
||||||
[NSApp setDelegate:(id)delegate];
|
[app setDelegate:(id)delegate];
|
||||||
ctx.appdelegate = delegate;
|
ctx.appdelegate = delegate;
|
||||||
delegate.mainWindow = ctx.mainWindow;
|
delegate.mainWindow = ctx.mainWindow;
|
||||||
delegate.alwaysOnTop = ctx.alwaysOnTop;
|
delegate.alwaysOnTop = ctx.alwaysOnTop;
|
||||||
|
delegate.startHidden = ctx.startHidden;
|
||||||
|
|
||||||
[ctx loadRequest:@"wails://wails/"];
|
[ctx loadRequest:@"wails://wails/"];
|
||||||
|
[app setMainMenu:ctx.applicationMenu];
|
||||||
[NSApp run];
|
[app run];
|
||||||
[ctx release];
|
[ctx release];
|
||||||
NSLog(@"Here");
|
|
||||||
}
|
}
|
||||||
|
|||||||
16
v2/internal/frontend/desktop/darwin/Role.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Role.h
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// Created by Lea Anthony on 24/10/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef Role_h
|
||||||
|
#define Role_h
|
||||||
|
|
||||||
|
typedef int Role;
|
||||||
|
|
||||||
|
static const Role AppMenu = 1;
|
||||||
|
static const Role EditMenu = 2;
|
||||||
|
|
||||||
|
#endif /* Role_h */
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface WailsAlert : NSAlert
|
@interface WailsAlert : NSAlert
|
||||||
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton;
|
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@
|
|||||||
|
|
||||||
@implementation WailsAlert
|
@implementation WailsAlert
|
||||||
|
|
||||||
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton {
|
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton {
|
||||||
if( text == nil ) {
|
if( text == nil ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSButton *button = [self addButtonWithTitle:[NSString stringWithUTF8String:text]];
|
NSButton *button = [self addButtonWithTitle:text];
|
||||||
if( defaultButton != nil && strcmp(text, defaultButton) == 0) {
|
if( defaultButton != nil && [text isEqualToString:defaultButton]) {
|
||||||
[button setKeyEquivalent:@"\r"];
|
[button setKeyEquivalent:@"\r"];
|
||||||
} else if( cancelButton != nil && strcmp(text, cancelButton) == 0) {
|
} else if( cancelButton != nil && [text isEqualToString:cancelButton]) {
|
||||||
[button setKeyEquivalent:@"\033"];
|
[button setKeyEquivalent:@"\033"];
|
||||||
} else {
|
} else {
|
||||||
[button setKeyEquivalent:@""];
|
[button setKeyEquivalent:@""];
|
||||||
|
|||||||
@@ -12,12 +12,13 @@
|
|||||||
#import <WebKit/WebKit.h>
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
#define ON_MAIN_THREAD(str) dispatch_async(dispatch_get_main_queue(), ^{ str; });
|
#define ON_MAIN_THREAD(str) dispatch_async(dispatch_get_main_queue(), ^{ str; });
|
||||||
|
#define unicode(input) [NSString stringWithFormat:@"%C", input]
|
||||||
|
|
||||||
@interface WailsWindow : NSWindow
|
@interface WailsWindow : NSWindow
|
||||||
- (BOOL)canBecomeKeyWindow;
|
- (BOOL)canBecomeKeyWindow;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface WailsContext : NSObject <WKURLSchemeHandler,WKScriptMessageHandler>
|
@interface WailsContext : NSObject <WKURLSchemeHandler,WKScriptMessageHandler,WKNavigationDelegate>
|
||||||
|
|
||||||
@property (retain) WailsWindow* mainWindow;
|
@property (retain) WailsWindow* mainWindow;
|
||||||
@property (retain) WKWebView* webview;
|
@property (retain) WKWebView* webview;
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
|
|
||||||
@property bool hideOnClose;
|
@property bool hideOnClose;
|
||||||
@property bool shuttingDown;
|
@property bool shuttingDown;
|
||||||
|
@property bool startHidden;
|
||||||
|
|
||||||
@property NSSize maxSize;
|
@property NSSize maxSize;
|
||||||
@property NSSize minSize;
|
@property NSSize minSize;
|
||||||
@@ -32,20 +34,24 @@
|
|||||||
@property (retain) NSEvent* mouseEvent;
|
@property (retain) NSEvent* mouseEvent;
|
||||||
|
|
||||||
@property bool alwaysOnTop;
|
@property bool alwaysOnTop;
|
||||||
@property bool maximised;
|
|
||||||
|
|
||||||
@property bool debug;
|
@property bool debug;
|
||||||
|
|
||||||
@property (retain) WKUserContentController* userContentController;
|
@property (retain) WKUserContentController* userContentController;
|
||||||
|
|
||||||
@property (retain) NSMutableDictionary *urlRequests;
|
@property (retain) NSMutableDictionary *urlRequests;
|
||||||
|
|
||||||
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent;
|
@property (retain) NSMenu* applicationMenu;
|
||||||
|
|
||||||
|
@property (retain) NSImage* aboutImage;
|
||||||
|
@property (retain) NSString* aboutTitle;
|
||||||
|
@property (retain) NSString* aboutDescription;
|
||||||
|
|
||||||
|
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString *)appearance :(bool)windowIsTranslucent;
|
||||||
- (void) SetSize:(int)width :(int)height;
|
- (void) SetSize:(int)width :(int)height;
|
||||||
- (void) SetPosition:(int)x :(int) y;
|
- (void) SetPosition:(int)x :(int) y;
|
||||||
- (void) SetMinSize:(int)minWidth :(int)minHeight;
|
- (void) SetMinSize:(int)minWidth :(int)minHeight;
|
||||||
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight;
|
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight;
|
||||||
- (void) SetTitle:(const char*)title;
|
- (void) SetTitle:(NSString*)title;
|
||||||
- (void) Center;
|
- (void) Center;
|
||||||
- (void) Fullscreen;
|
- (void) Fullscreen;
|
||||||
- (void) UnFullscreen;
|
- (void) UnFullscreen;
|
||||||
@@ -58,16 +64,19 @@
|
|||||||
- (void) ShowMouse;
|
- (void) ShowMouse;
|
||||||
- (void) Hide;
|
- (void) Hide;
|
||||||
- (void) Show;
|
- (void) Show;
|
||||||
|
- (void) Quit;
|
||||||
|
|
||||||
-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton;
|
-(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength;
|
||||||
-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters;
|
- (void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters;
|
||||||
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters;
|
- (void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters;
|
||||||
|
|
||||||
- (void) loadRequest:(NSString*)url;
|
- (void) loadRequest:(NSString*)url;
|
||||||
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData*)data;
|
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData*)data;
|
||||||
- (void) ExecJS:(const char*)script;
|
- (void) ExecJS:(NSString*)script;
|
||||||
- (NSScreen*) getCurrentScreen;
|
- (NSScreen*) getCurrentScreen;
|
||||||
|
|
||||||
|
- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,10 @@
|
|||||||
#import <WebKit/WebKit.h>
|
#import <WebKit/WebKit.h>
|
||||||
#import "WailsContext.h"
|
#import "WailsContext.h"
|
||||||
#import "WailsAlert.h"
|
#import "WailsAlert.h"
|
||||||
|
#import "WailsMenu.h"
|
||||||
#import "WindowDelegate.h"
|
#import "WindowDelegate.h"
|
||||||
#import "message.h"
|
#import "message.h"
|
||||||
|
#import "Role.h"
|
||||||
|
|
||||||
@implementation WailsWindow
|
@implementation WailsWindow
|
||||||
|
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
frame.origin.y += frame.size.height - height;
|
frame.origin.y += frame.size.height - height;
|
||||||
frame.size.width = width;
|
frame.size.width = width;
|
||||||
frame.size.height = height;
|
frame.size.height = height;
|
||||||
[self.mainWindow setFrame:frame display:TRUE animate:FALSE];
|
ON_MAIN_THREAD([self.mainWindow setFrame:frame display:TRUE animate:FALSE];);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) SetPosition:(int)x :(int)y {
|
- (void) SetPosition:(int)x :(int)y {
|
||||||
@@ -40,11 +42,11 @@
|
|||||||
|
|
||||||
NSScreen* screen = [self getCurrentScreen];
|
NSScreen* screen = [self getCurrentScreen];
|
||||||
NSRect windowFrame = [self.mainWindow frame];
|
NSRect windowFrame = [self.mainWindow frame];
|
||||||
NSRect screenFrame = [screen visibleFrame];
|
NSRect screenFrame = [screen frame];
|
||||||
windowFrame.origin.x += screenFrame.origin.x + (float)x;
|
windowFrame.origin.x = screenFrame.origin.x + (float)x;
|
||||||
windowFrame.origin.y += (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y;
|
windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y;
|
||||||
|
|
||||||
[self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE];
|
ON_MAIN_THREAD([self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE]; );
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) SetMinSize:(int)minWidth :(int)minHeight {
|
- (void) SetMinSize:(int)minWidth :(int)minHeight {
|
||||||
@@ -54,10 +56,11 @@
|
|||||||
NSSize size = { minWidth, minHeight };
|
NSSize size = { minWidth, minHeight };
|
||||||
|
|
||||||
self.minSize = size;
|
self.minSize = size;
|
||||||
|
|
||||||
[self.mainWindow setMinSize:size];
|
ON_MAIN_THREAD(
|
||||||
|
[self.mainWindow setMinSize:size];
|
||||||
[self adjustWindowSize];
|
[self adjustWindowSize];
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,10 +74,11 @@
|
|||||||
size.height = maxHeight > 0 ? maxHeight : FLT_MAX;
|
size.height = maxHeight > 0 ? maxHeight : FLT_MAX;
|
||||||
|
|
||||||
self.maxSize = size;
|
self.maxSize = size;
|
||||||
|
|
||||||
[self.mainWindow setMinSize:size];
|
ON_MAIN_THREAD(
|
||||||
|
[self.mainWindow setMaxSize:size];
|
||||||
[self adjustWindowSize];
|
[self adjustWindowSize];
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -88,8 +92,8 @@
|
|||||||
if ( currentFrame.size.width < self.minSize.width ) currentFrame.size.width = self.minSize.width;
|
if ( currentFrame.size.width < self.minSize.width ) currentFrame.size.width = self.minSize.width;
|
||||||
if ( currentFrame.size.height > self.maxSize.height ) currentFrame.size.height = self.maxSize.height;
|
if ( currentFrame.size.height > self.maxSize.height ) currentFrame.size.height = self.maxSize.height;
|
||||||
if ( currentFrame.size.height < self.minSize.height ) currentFrame.size.height = self.minSize.height;
|
if ( currentFrame.size.height < self.minSize.height ) currentFrame.size.height = self.minSize.height;
|
||||||
|
|
||||||
[self.mainWindow setFrame:currentFrame display:TRUE animate:FALSE];
|
[self.mainWindow setFrame:currentFrame display:YES animate:FALSE];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +104,7 @@
|
|||||||
[self.mouseEvent release];
|
[self.mouseEvent release];
|
||||||
[self.userContentController release];
|
[self.userContentController release];
|
||||||
[self.urlRequests release];
|
[self.urlRequests release];
|
||||||
|
[self.applicationMenu release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSScreen*) getCurrentScreen {
|
- (NSScreen*) getCurrentScreen {
|
||||||
@@ -110,55 +115,66 @@
|
|||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) SetTitle:(const char *)title {
|
- (void) SetTitle:(NSString*)title {
|
||||||
NSString *_title = [NSString stringWithUTF8String:title];
|
ON_MAIN_THREAD([self.mainWindow setTitle:title];)
|
||||||
[self.mainWindow setTitle:_title];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) Center {
|
- (void) Center {
|
||||||
[self.mainWindow center];
|
ON_MAIN_THREAD( [self.mainWindow center]; );
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent {
|
- (BOOL) isFullscreen {
|
||||||
|
NSWindowStyleMask masks = [self.mainWindow styleMask];
|
||||||
|
if ( masks & NSWindowStyleMaskFullScreen ) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString*)appearance :(bool)windowIsTranslucent {
|
||||||
|
|
||||||
self.urlRequests = [NSMutableDictionary new];
|
self.urlRequests = [NSMutableDictionary new];
|
||||||
|
|
||||||
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
NSWindowStyleMask styleMask = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||||
|
|
||||||
if (frameless) {
|
if (frameless) {
|
||||||
styleMask = NSWindowStyleMaskBorderless;
|
styleMask = NSWindowStyleMaskBorderless;
|
||||||
|
titlebarAppearsTransparent = true;
|
||||||
|
hideTitle = true;
|
||||||
} else {
|
} else {
|
||||||
if (resizable) {
|
if (!hideTitleBar) {
|
||||||
styleMask |= NSWindowStyleMaskResizable;
|
styleMask |= NSWindowStyleMaskTitled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullscreen) {
|
||||||
|
styleMask |= NSWindowStyleMaskFullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fullSizeContent || frameless || titlebarAppearsTransparent ) {
|
||||||
|
styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fullscreen) {
|
|
||||||
styleMask |= NSWindowStyleMaskFullScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fullSizeContent || frameless || titlebarAppearsTransparent ) {
|
if (resizable) {
|
||||||
styleMask |= NSWindowStyleMaskFullSizeContentView;
|
styleMask |= NSWindowStyleMaskResizable;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mainWindow = [[[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
|
self.mainWindow = [[[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
|
||||||
styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]
|
styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]
|
||||||
autorelease];
|
autorelease];
|
||||||
|
|
||||||
if (frameless) {
|
if (!frameless && useToolbar) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useToolbar) {
|
|
||||||
NSLog(@"Using Toolbar");
|
|
||||||
id toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"];
|
id toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"];
|
||||||
[toolbar autorelease];
|
[toolbar autorelease];
|
||||||
[toolbar setShowsBaselineSeparator:!hideToolbarSeparator];
|
[toolbar setShowsBaselineSeparator:!hideToolbarSeparator];
|
||||||
[self.mainWindow setToolbar:toolbar];
|
[self.mainWindow setToolbar:toolbar];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.mainWindow setTitleVisibility:hideTitle];
|
[self.mainWindow setTitleVisibility:hideTitle];
|
||||||
[self.mainWindow setTitlebarAppearsTransparent:titlebarAppearsTransparent];
|
[self.mainWindow setTitlebarAppearsTransparent:titlebarAppearsTransparent];
|
||||||
[self.mainWindow canBecomeKeyWindow];
|
|
||||||
|
// [self.mainWindow canBecomeKeyWindow];
|
||||||
|
|
||||||
id contentView = [self.mainWindow contentView];
|
id contentView = [self.mainWindow contentView];
|
||||||
if (windowIsTranslucent) {
|
if (windowIsTranslucent) {
|
||||||
@@ -172,8 +188,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (appearance != nil) {
|
if (appearance != nil) {
|
||||||
NSString *name = [NSString stringWithUTF8String:appearance];
|
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:appearance];
|
||||||
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:name];
|
|
||||||
[self.mainWindow setAppearance:nsAppearance];
|
[self.mainWindow setAppearance:nsAppearance];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +208,7 @@
|
|||||||
config.suppressesIncrementalRendering = true;
|
config.suppressesIncrementalRendering = true;
|
||||||
[config setURLSchemeHandler:self forURLScheme:@"wails"];
|
[config setURLSchemeHandler:self forURLScheme:@"wails"];
|
||||||
|
|
||||||
[config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
|
// [config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
|
||||||
|
|
||||||
WKUserContentController* userContentController = [WKUserContentController new];
|
WKUserContentController* userContentController = [WKUserContentController new];
|
||||||
[userContentController addScriptMessageHandler:self name:@"external"];
|
[userContentController addScriptMessageHandler:self name:@"external"];
|
||||||
@@ -223,6 +238,8 @@
|
|||||||
[self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"];
|
[self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self.webview setNavigationDelegate:self];
|
||||||
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
[defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"];
|
[defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"];
|
||||||
|
|
||||||
@@ -244,6 +261,30 @@
|
|||||||
return event;
|
return event;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
self.applicationMenu = [NSMenu new];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||||
|
NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease];
|
||||||
|
if( flags != 0 ) {
|
||||||
|
[result setKeyEquivalentModifierMask:flags];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key {
|
||||||
|
return [self newMenuItem :title :selector :key :0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMenu*) newMenu :(NSString*)title {
|
||||||
|
WailsMenu *result = [[[WailsMenu new] initWithTitle:title] autorelease];
|
||||||
|
[result setAutoenablesItems:NO];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) Quit {
|
||||||
|
processMessage("Q");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) loadRequest :(NSString*)url {
|
- (void) loadRequest :(NSString*)url {
|
||||||
@@ -260,7 +301,7 @@
|
|||||||
|
|
||||||
id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ];
|
id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ];
|
||||||
|
|
||||||
[self.mainWindow setBackgroundColor:colour];
|
ON_MAIN_THREAD([self.mainWindow setBackgroundColor:colour];);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) HideMouse {
|
- (void) HideMouse {
|
||||||
@@ -276,52 +317,60 @@
|
|||||||
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (bool) isMaximised {
|
||||||
|
long mask = [self.mainWindow styleMask];
|
||||||
|
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
// Fullscreen sets the main window to be fullscreen
|
// Fullscreen sets the main window to be fullscreen
|
||||||
- (void) Fullscreen {
|
- (void) Fullscreen {
|
||||||
if( ! [self isFullScreen] ) {
|
if( ! [self isFullScreen] ) {
|
||||||
[self.mainWindow toggleFullScreen:nil];
|
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnFullscreen resets the main window after a fullscreen
|
// UnFullscreen resets the main window after a fullscreen
|
||||||
- (void) UnFullscreen {
|
- (void) UnFullscreen {
|
||||||
if( [self isFullScreen] ) {
|
if( [self isFullScreen] ) {
|
||||||
[self.mainWindow toggleFullScreen:nil];
|
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) Minimise {
|
- (void) Minimise {
|
||||||
[self.mainWindow miniaturize:nil];
|
ON_MAIN_THREAD([self.mainWindow miniaturize:nil];)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) UnMinimise {
|
- (void) UnMinimise {
|
||||||
[self.mainWindow deminiaturize:nil];
|
ON_MAIN_THREAD([self.mainWindow deminiaturize:nil];)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) Hide {
|
- (void) Hide {
|
||||||
[self.mainWindow orderOut:nil];
|
ON_MAIN_THREAD([self.mainWindow orderOut:nil];)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) Show {
|
- (void) Show {
|
||||||
[self.mainWindow makeKeyAndOrderFront:nil];
|
ON_MAIN_THREAD(
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[self.mainWindow makeKeyAndOrderFront:nil];
|
||||||
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) Maximise {
|
- (void) Maximise {
|
||||||
if (! self.maximised) {
|
if (![self.mainWindow isZoomed]) {
|
||||||
[self.mainWindow zoom:nil];
|
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) UnMaximise {
|
- (void) UnMaximise {
|
||||||
if (self.maximised) {
|
if ([self.mainWindow isZoomed]) {
|
||||||
[self.mainWindow zoom:nil];
|
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) ExecJS:(const char*)script {
|
- (void) ExecJS:(NSString*)script {
|
||||||
NSString *nsscript = [NSString stringWithUTF8String:script];
|
ON_MAIN_THREAD(
|
||||||
[self.webview evaluateJavaScript:nsscript completionHandler:nil];
|
[self.webview evaluateJavaScript:script completionHandler:nil];
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data {
|
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data {
|
||||||
@@ -348,6 +397,10 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||||
|
processMessage("DomReady");
|
||||||
|
}
|
||||||
|
|
||||||
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
|
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
|
||||||
NSString *m = message.body;
|
NSString *m = message.body;
|
||||||
|
|
||||||
@@ -371,25 +424,25 @@
|
|||||||
|
|
||||||
|
|
||||||
/***** Dialogs ******/
|
/***** Dialogs ******/
|
||||||
-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton {
|
-(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength {
|
||||||
|
|
||||||
WailsAlert *alert = [WailsAlert new];
|
WailsAlert *alert = [WailsAlert new];
|
||||||
|
|
||||||
int style = NSAlertStyleInformational;
|
int style = NSAlertStyleInformational;
|
||||||
if (dialogType != nil ) {
|
if (dialogType != nil ) {
|
||||||
if( strcmp(dialogType, "warning") == 0 ) {
|
if( [dialogType isEqualToString:@"warning"] ) {
|
||||||
style = NSAlertStyleWarning;
|
style = NSAlertStyleWarning;
|
||||||
}
|
}
|
||||||
if( strcmp(dialogType, "error") == 0) {
|
if( [dialogType isEqualToString:@"error"] ) {
|
||||||
style = NSAlertStyleCritical;
|
style = NSAlertStyleCritical;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[alert setAlertStyle:style];
|
[alert setAlertStyle:style];
|
||||||
if( strlen(title) > 0 ) {
|
if( title != nil ) {
|
||||||
[alert setMessageText:[NSString stringWithUTF8String:title]];
|
[alert setMessageText:title];
|
||||||
}
|
}
|
||||||
if( strlen(message) > 0 ) {
|
if( message != nil ) {
|
||||||
[alert setInformativeText:[NSString stringWithUTF8String:message]];
|
[alert setInformativeText:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
[alert addButton:button1 :defaultButton :cancelButton];
|
[alert addButton:button1 :defaultButton :cancelButton];
|
||||||
@@ -397,47 +450,59 @@
|
|||||||
[alert addButton:button3 :defaultButton :cancelButton];
|
[alert addButton:button3 :defaultButton :cancelButton];
|
||||||
[alert addButton:button4 :defaultButton :cancelButton];
|
[alert addButton:button4 :defaultButton :cancelButton];
|
||||||
|
|
||||||
long response = [alert runModal];
|
NSImage *icon = nil;
|
||||||
int result;
|
if (iconData != nil) {
|
||||||
|
NSData *imageData = [NSData dataWithBytes:iconData length:iconDataLength];
|
||||||
if( response == NSAlertFirstButtonReturn ) {
|
icon = [[NSImage alloc] initWithData:imageData];
|
||||||
result = 0;
|
|
||||||
}
|
}
|
||||||
else if( response == NSAlertSecondButtonReturn ) {
|
ON_MAIN_THREAD(
|
||||||
result = 1;
|
if( icon != nil) {
|
||||||
}
|
[alert setIcon:icon];
|
||||||
else if( response == NSAlertThirdButtonReturn ) {
|
}
|
||||||
result = 2;
|
[alert.window setLevel:NSFloatingWindowLevel];
|
||||||
} else {
|
|
||||||
result = 3;
|
long response = [alert runModal];
|
||||||
}
|
int result;
|
||||||
processMessageDialogResponse(result);
|
|
||||||
|
if( response == NSAlertFirstButtonReturn ) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if( response == NSAlertSecondButtonReturn ) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else if( response == NSAlertThirdButtonReturn ) {
|
||||||
|
result = 2;
|
||||||
|
} else {
|
||||||
|
result = 3;
|
||||||
|
}
|
||||||
|
processMessageDialogResponse(result);
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters {
|
-(void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters {
|
||||||
|
|
||||||
|
|
||||||
// Create the dialog
|
// Create the dialog
|
||||||
NSOpenPanel *dialog = [NSOpenPanel openPanel];
|
NSOpenPanel *dialog = [NSOpenPanel openPanel];
|
||||||
|
|
||||||
// Valid but appears to do nothing.... :/
|
// Valid but appears to do nothing.... :/
|
||||||
if( strlen(title) > 0 ) {
|
if( title != nil ) {
|
||||||
[dialog setTitle:[NSString stringWithUTF8String:title]];
|
[dialog setTitle:title];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters - semicolon delimited list of file extensions
|
// Filters - semicolon delimited list of file extensions
|
||||||
if( allowFiles ) {
|
if( allowFiles ) {
|
||||||
if( filters != nil && strlen(filters) > 0) {
|
if( filters != nil ) {
|
||||||
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
||||||
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
|
filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||||
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
|
NSArray *filterList = [filters componentsSeparatedByString:@";"];
|
||||||
[dialog setAllowedFileTypes:filterList];
|
[dialog setAllowedFileTypes:filterList];
|
||||||
} else {
|
} else {
|
||||||
[dialog setAllowsOtherFileTypes:true];
|
[dialog setAllowsOtherFileTypes:true];
|
||||||
}
|
}
|
||||||
// Default Filename
|
// Default Filename
|
||||||
if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) {
|
if( defaultFilename != nil ) {
|
||||||
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
|
[dialog setNameFieldStringValue:defaultFilename];
|
||||||
}
|
}
|
||||||
|
|
||||||
[dialog setAllowsMultipleSelection: allowMultipleSelection];
|
[dialog setAllowsMultipleSelection: allowMultipleSelection];
|
||||||
@@ -446,8 +511,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default Directory
|
// Default Directory
|
||||||
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
|
if( defaultDirectory != nil ) {
|
||||||
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
|
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
|
||||||
[dialog setDirectoryURL:url];
|
[dialog setDirectoryURL:url];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,42 +533,41 @@
|
|||||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil];
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil];
|
||||||
NSString *nsjson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
NSString *nsjson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||||
processOpenFileDialogResponse([nsjson UTF8String]);
|
processOpenFileDialogResponse([nsjson UTF8String]);
|
||||||
|
[nsjson release];
|
||||||
|
[arr release];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
[dialog runModal];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters; {
|
-(void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters; {
|
||||||
|
|
||||||
|
|
||||||
// Create the dialog
|
// Create the dialog
|
||||||
NSSavePanel *dialog = [NSOpenPanel savePanel];
|
NSSavePanel *dialog = [NSOpenPanel savePanel];
|
||||||
|
|
||||||
// Valid but appears to do nothing.... :/
|
// Valid but appears to do nothing.... :/
|
||||||
if( strlen(title) > 0 ) {
|
if( title != nil ) {
|
||||||
[dialog setTitle:[NSString stringWithUTF8String:title]];
|
[dialog setTitle:title];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters - semicolon delimited list of file extensions
|
// Filters - semicolon delimited list of file extensions
|
||||||
if( filters != nil && strlen(filters) > 0) {
|
if( filters != nil ) {
|
||||||
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
||||||
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
|
filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||||
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
|
NSArray *filterList = [filters componentsSeparatedByString:@";"];
|
||||||
[dialog setAllowedFileTypes:filterList];
|
[dialog setAllowedFileTypes:filterList];
|
||||||
} else {
|
} else {
|
||||||
[dialog setAllowsOtherFileTypes:true];
|
[dialog setAllowsOtherFileTypes:true];
|
||||||
}
|
}
|
||||||
// Default Filename
|
// Default Filename
|
||||||
if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) {
|
if( defaultFilename != nil ) {
|
||||||
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
|
[dialog setNameFieldStringValue:defaultFilename];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default Directory
|
// Default Directory
|
||||||
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
|
if( defaultDirectory != nil ) {
|
||||||
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
|
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
|
||||||
[dialog setDirectoryURL:url];
|
[dialog setDirectoryURL:url];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,13 +579,43 @@
|
|||||||
// Setup callback handler
|
// Setup callback handler
|
||||||
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
|
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
|
||||||
NSURL *url = [dialog URL];
|
NSURL *url = [dialog URL];
|
||||||
processSaveFileDialogResponse([url.path UTF8String]);
|
if ( url != nil ) {
|
||||||
|
processSaveFileDialogResponse([url.path UTF8String]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processSaveFileDialogResponse("");
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen {
|
||||||
|
self.aboutTitle = title;
|
||||||
|
self.aboutDescription = description;
|
||||||
|
|
||||||
|
NSData *imageData = [NSData dataWithBytes:imagedata length:datalen];
|
||||||
|
self.aboutImage = [[NSImage alloc] initWithData:imageData];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) About {
|
||||||
|
|
||||||
[dialog runModal];
|
WailsAlert *alert = [WailsAlert new];
|
||||||
|
[alert setAlertStyle:NSAlertStyleInformational];
|
||||||
|
if( self.aboutTitle != nil ) {
|
||||||
|
[alert setMessageText:self.aboutTitle];
|
||||||
|
}
|
||||||
|
if( self.aboutDescription != nil ) {
|
||||||
|
[alert setInformativeText:self.aboutDescription];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[alert.window setLevel:NSFloatingWindowLevel];
|
||||||
|
if ( self.aboutImage != nil) {
|
||||||
|
[alert setIcon:self.aboutImage];
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_MAIN_THREAD([alert runModal];)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
30
v2/internal/frontend/desktop/darwin/WailsMenu.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// WailsMenu.h
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// Created by Lea Anthony on 25/10/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WailsMenu_h
|
||||||
|
#define WailsMenu_h
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import "Role.h"
|
||||||
|
#import "WailsMenu.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
|
@interface WailsMenu : NSMenu
|
||||||
|
|
||||||
|
//- (void) AddMenuByRole :(Role)role;
|
||||||
|
- (WailsMenu*) initWithNSTitle :(NSString*)title;
|
||||||
|
- (void) appendSubmenu :(WailsMenu*)child;
|
||||||
|
- (void) appendRole :(WailsContext*)ctx :(Role)role;
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags;
|
||||||
|
- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID;
|
||||||
|
- (void) AppendSeparator;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* WailsMenu_h */
|
||||||
318
v2/internal/frontend/desktop/darwin/WailsMenu.m
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
//
|
||||||
|
// WailsMenu.m
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// Created by Lea Anthony on 25/10/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "WailsMenu.h"
|
||||||
|
#import "WailsMenuItem.h"
|
||||||
|
#import "Role.h"
|
||||||
|
|
||||||
|
@implementation WailsMenu
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||||
|
NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease];
|
||||||
|
[result setKeyEquivalentModifierMask:flags];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||||
|
NSMenuItem *result = [NSMenuItem new];
|
||||||
|
if ( title != nil ) {
|
||||||
|
[result setTitle:title];
|
||||||
|
}
|
||||||
|
if (selector != nil) {
|
||||||
|
[result setAction:selector];
|
||||||
|
}
|
||||||
|
if (key) {
|
||||||
|
[result setKeyEquivalent:key];
|
||||||
|
}
|
||||||
|
if( flags != 0 ) {
|
||||||
|
[result setKeyEquivalentModifierMask:flags];
|
||||||
|
}
|
||||||
|
result.target = ctx;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key {
|
||||||
|
return [self newMenuItem :title :selector :key :0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (WailsMenu*) initWithNSTitle:(NSString *)title {
|
||||||
|
if( title != nil ) {
|
||||||
|
[super initWithTitle:title];
|
||||||
|
}
|
||||||
|
[self setAutoenablesItems:NO];
|
||||||
|
return [self init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) appendSubmenu :(WailsMenu*)child {
|
||||||
|
NSMenuItem *childMenuItem = [[NSMenuItem new] autorelease];
|
||||||
|
[childMenuItem setTitle:[child title]];
|
||||||
|
[self addItem:childMenuItem];
|
||||||
|
[childMenuItem setSubmenu:child];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) appendRole :(WailsContext*)ctx :(Role)role {
|
||||||
|
|
||||||
|
switch(role) {
|
||||||
|
case AppMenu:
|
||||||
|
{
|
||||||
|
NSString *appName = [NSRunningApplication currentApplication].localizedName;
|
||||||
|
if( appName == nil ) {
|
||||||
|
appName = [[NSProcessInfo processInfo] processName];
|
||||||
|
}
|
||||||
|
WailsMenu *appMenu = [[WailsMenu new] initWithNSTitle:appName];
|
||||||
|
id quitTitle = [@"Quit " stringByAppendingString:appName];
|
||||||
|
NSMenuItem* quitMenuItem = [self newMenuItem:quitTitle :@selector(Quit) :@"q" :NSEventModifierFlagCommand];
|
||||||
|
quitMenuItem.target = ctx;
|
||||||
|
if (ctx.aboutTitle != nil) {
|
||||||
|
[appMenu addItem:[self newMenuItemWithContext :ctx :[@"About " stringByAppendingString:appName] :@selector(About) :nil :0]];
|
||||||
|
}
|
||||||
|
[appMenu addItem:quitMenuItem];
|
||||||
|
[self appendSubmenu:appMenu];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EditMenu:
|
||||||
|
{
|
||||||
|
WailsMenu *editMenu = [[WailsMenu new] initWithNSTitle:@"Edit"];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Undo" :@selector(undoActionName) :@"z" :NSEventModifierFlagCommand]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Redo" :@selector(redoActionName) :@"z" :(NSEventModifierFlagShift | NSEventModifierFlagCommand)]];
|
||||||
|
[editMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Cut" :@selector(cut:) :@"x" :NSEventModifierFlagCommand]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Copy" :@selector(copy:) :@"c" :NSEventModifierFlagCommand]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Paste" :@selector(paste:) :@"v" :NSEventModifierFlagCommand]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Paste and Match Style" :@selector(pasteAsRichText:) :@"v" :(NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagCommand)]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Delete" :@selector(delete:) :[self accel:@"backspace"] :0]];
|
||||||
|
[editMenu addItem:[self newMenuItem:@"Select All" :@selector(selectAll:) :@"a" :NSEventModifierFlagCommand]];
|
||||||
|
[editMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
// NSMenuItem *speechMenuItem = [[NSMenuItem new] autorelease];
|
||||||
|
// [speechMenuItem setTitle:@"Speech"];
|
||||||
|
// [editMenu addItem:speechMenuItem];
|
||||||
|
WailsMenu *speechMenu = [[WailsMenu new] initWithNSTitle:@"Speech"];
|
||||||
|
[speechMenu addItem:[self newMenuItem:@"Start Speaking" :@selector(startSpeaking:) :@""]];
|
||||||
|
[speechMenu addItem:[self newMenuItem:@"Stop Speaking" :@selector(stopSpeaking:) :@""]];
|
||||||
|
[editMenu appendSubmenu:speechMenu];
|
||||||
|
[self appendSubmenu:editMenu];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID {
|
||||||
|
|
||||||
|
NSString *nslabel = @"";
|
||||||
|
if (label != nil ) {
|
||||||
|
nslabel = label;
|
||||||
|
}
|
||||||
|
WailsMenuItem *menuItem = [WailsMenuItem new];
|
||||||
|
|
||||||
|
// Label
|
||||||
|
menuItem.title = nslabel;
|
||||||
|
|
||||||
|
// Process callback
|
||||||
|
menuItem.menuItemID = menuItemID;
|
||||||
|
menuItem.action = @selector(handleClick);
|
||||||
|
menuItem.target = menuItem;
|
||||||
|
|
||||||
|
// Shortcut
|
||||||
|
if (shortcutKey != nil) {
|
||||||
|
[menuItem setKeyEquivalent:[self accel:shortcutKey]];
|
||||||
|
[menuItem setKeyEquivalentModifierMask:modifiers];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled/Disabled
|
||||||
|
[menuItem setEnabled:!disabled];
|
||||||
|
|
||||||
|
// Checked
|
||||||
|
[menuItem setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)];
|
||||||
|
|
||||||
|
[self addItem:menuItem];
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) AppendSeparator {
|
||||||
|
[self addItem:[NSMenuItem separatorItem]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (NSString*) accel :(NSString*)key {
|
||||||
|
|
||||||
|
// Guard against no accelerator key
|
||||||
|
if( key == NULL ) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( [key isEqualToString:@"backspace"] ) {
|
||||||
|
return unicode(0x0008);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"tab"] ) {
|
||||||
|
return unicode(0x0009);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"return"] ) {
|
||||||
|
return unicode(0x000d);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"enter"] ) {
|
||||||
|
return unicode(0x000d);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"escape"] ) {
|
||||||
|
return unicode(0x001b);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"left"] ) {
|
||||||
|
return unicode(0x001c);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"right"] ) {
|
||||||
|
return unicode(0x001d);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"up"] ) {
|
||||||
|
return unicode(0x001e);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"down"] ) {
|
||||||
|
return unicode(0x001f);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"space"] ) {
|
||||||
|
return unicode(0x0020);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"delete"] ) {
|
||||||
|
return unicode(0x007f);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"home"] ) {
|
||||||
|
return unicode(0x2196);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"end"] ) {
|
||||||
|
return unicode(0x2198);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"page up"] ) {
|
||||||
|
return unicode(0x21de);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"page down"] ) {
|
||||||
|
return unicode(0x21df);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f1"] ) {
|
||||||
|
return unicode(0xf704);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f2"] ) {
|
||||||
|
return unicode(0xf705);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f3"] ) {
|
||||||
|
return unicode(0xf706);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f4"] ) {
|
||||||
|
return unicode(0xf707);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f5"] ) {
|
||||||
|
return unicode(0xf708);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f6"] ) {
|
||||||
|
return unicode(0xf709);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f7"] ) {
|
||||||
|
return unicode(0xf70a);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f8"] ) {
|
||||||
|
return unicode(0xf70b);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f9"] ) {
|
||||||
|
return unicode(0xf70c);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f10"] ) {
|
||||||
|
return unicode(0xf70d);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f11"] ) {
|
||||||
|
return unicode(0xf70e);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f12"] ) {
|
||||||
|
return unicode(0xf70f);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f13"] ) {
|
||||||
|
return unicode(0xf710);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f14"] ) {
|
||||||
|
return unicode(0xf711);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f15"] ) {
|
||||||
|
return unicode(0xf712);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f16"] ) {
|
||||||
|
return unicode(0xf713);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f17"] ) {
|
||||||
|
return unicode(0xf714);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f18"] ) {
|
||||||
|
return unicode(0xf715);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f19"] ) {
|
||||||
|
return unicode(0xf716);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f20"] ) {
|
||||||
|
return unicode(0xf717);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f21"] ) {
|
||||||
|
return unicode(0xf718);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f22"] ) {
|
||||||
|
return unicode(0xf719);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f23"] ) {
|
||||||
|
return unicode(0xf71a);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f24"] ) {
|
||||||
|
return unicode(0xf71b);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f25"] ) {
|
||||||
|
return unicode(0xf71c);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f26"] ) {
|
||||||
|
return unicode(0xf71d);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f27"] ) {
|
||||||
|
return unicode(0xf71e);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f28"] ) {
|
||||||
|
return unicode(0xf71f);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f29"] ) {
|
||||||
|
return unicode(0xf720);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f30"] ) {
|
||||||
|
return unicode(0xf721);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f31"] ) {
|
||||||
|
return unicode(0xf722);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f32"] ) {
|
||||||
|
return unicode(0xf723);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f33"] ) {
|
||||||
|
return unicode(0xf724);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f34"] ) {
|
||||||
|
return unicode(0xf725);
|
||||||
|
}
|
||||||
|
if( [key isEqualToString:@"f35"] ) {
|
||||||
|
return unicode(0xf726);
|
||||||
|
}
|
||||||
|
// if( [key isEqualToString:@"Insert"] ) {
|
||||||
|
// return unicode(0xf727);
|
||||||
|
// }
|
||||||
|
// if( [key isEqualToString:@"PrintScreen"] ) {
|
||||||
|
// return unicode(0xf72e);
|
||||||
|
// }
|
||||||
|
// if( [key isEqualToString:@"ScrollLock"] ) {
|
||||||
|
// return unicode(0xf72f);
|
||||||
|
// }
|
||||||
|
if( [key isEqualToString:@"numLock"] ) {
|
||||||
|
return unicode(0xf739);
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
22
v2/internal/frontend/desktop/darwin/WailsMenuItem.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// WailsMenuItem.h
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// Created by Lea Anthony on 27/10/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WailsMenuItem_h
|
||||||
|
#define WailsMenuItem_h
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface WailsMenuItem : NSMenuItem
|
||||||
|
|
||||||
|
@property int menuItemID;
|
||||||
|
|
||||||
|
- (void) handleClick;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* WailsMenuItem_h */
|
||||||
20
v2/internal/frontend/desktop/darwin/WailsMenuItem.m
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// WailsMenuItem.m
|
||||||
|
// test
|
||||||
|
//
|
||||||
|
// Created by Lea Anthony on 27/10/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "WailsMenuItem.h"
|
||||||
|
#include "message.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation WailsMenuItem
|
||||||
|
|
||||||
|
- (void) handleClick {
|
||||||
|
processCallback(self.menuItemID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -9,10 +9,11 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "WindowDelegate.h"
|
#import "WindowDelegate.h"
|
||||||
#import "message.h"
|
#import "message.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
@implementation WindowDelegate
|
@implementation WindowDelegate
|
||||||
|
|
||||||
- (BOOL)windowShouldClose:(NSWindow *)sender {
|
- (BOOL)windowShouldClose:(WailsWindow *)sender {
|
||||||
[sender orderOut:nil];
|
[sender orderOut:nil];
|
||||||
if( self.hideOnClose == false ) {
|
if( self.hideOnClose == false ) {
|
||||||
processMessage("Q");
|
processMessage("Q");
|
||||||
|
|||||||
51
v2/internal/frontend/desktop/darwin/callbacks.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package darwin
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Application.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *Frontend) handleCallback(menuItemID uint) error {
|
||||||
|
|
||||||
|
menuItem := getMenuItemForID(menuItemID)
|
||||||
|
if menuItem == nil {
|
||||||
|
return errors.New("unknown menuItem ID: " + strconv.Itoa(int(menuItemID)))
|
||||||
|
}
|
||||||
|
|
||||||
|
wailsMenuItem := menuItem.wailsMenuItem
|
||||||
|
if wailsMenuItem.Type == menu.CheckboxType {
|
||||||
|
wailsMenuItem.Checked = !wailsMenuItem.Checked
|
||||||
|
C.UpdateMenuItem(menuItem.nsmenuitem, bool2Cint(wailsMenuItem.Checked))
|
||||||
|
}
|
||||||
|
if wailsMenuItem.Type == menu.RadioType {
|
||||||
|
// Ignore if we clicked the item that is already checked
|
||||||
|
if !wailsMenuItem.Checked {
|
||||||
|
for _, item := range menuItem.radioGroupMembers {
|
||||||
|
if item.wailsMenuItem.Checked {
|
||||||
|
item.wailsMenuItem.Checked = false
|
||||||
|
C.UpdateMenuItem(item.nsmenuitem, C.int(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wailsMenuItem.Checked = true
|
||||||
|
C.UpdateMenuItem(menuItem.nsmenuitem, C.int(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wailsMenuItem.Click != nil {
|
||||||
|
go wailsMenuItem.Click(&menu.CallbackData{MenuItem: wailsMenuItem})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
@@ -155,7 +156,14 @@ func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string,
|
|||||||
buttons[index] = c.String(buttonText)
|
buttons[index] = c.String(buttonText)
|
||||||
}
|
}
|
||||||
|
|
||||||
C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton)
|
var iconData unsafe.Pointer
|
||||||
|
var iconDataLength C.int
|
||||||
|
if options.Icon != nil {
|
||||||
|
iconData = unsafe.Pointer(&options.Icon[0])
|
||||||
|
iconDataLength = C.int(len(options.Icon))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton, iconData, iconDataLength)
|
||||||
|
|
||||||
var result = <-messageDialogResponse
|
var result = <-messageDialogResponse
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type request struct {
|
|||||||
|
|
||||||
var messageBuffer = make(chan string, 100)
|
var messageBuffer = make(chan string, 100)
|
||||||
var requestBuffer = make(chan *request, 100)
|
var requestBuffer = make(chan *request, 100)
|
||||||
|
var callbackBuffer = make(chan uint, 10)
|
||||||
|
|
||||||
type Frontend struct {
|
type Frontend struct {
|
||||||
|
|
||||||
@@ -65,10 +66,6 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
|||||||
bindings: appBindings,
|
bindings: appBindings,
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
minHeight: appoptions.MinHeight,
|
|
||||||
minWidth: appoptions.MinWidth,
|
|
||||||
maxHeight: appoptions.MaxHeight,
|
|
||||||
maxWidth: appoptions.MaxWidth,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have been given a directory to serve assets from.
|
// Check if we have been given a directory to serve assets from.
|
||||||
@@ -92,6 +89,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
|||||||
|
|
||||||
go result.startMessageProcessor()
|
go result.startMessageProcessor()
|
||||||
go result.startRequestProcessor()
|
go result.startRequestProcessor()
|
||||||
|
go result.startCallbackProcessor()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -106,6 +104,14 @@ func (f *Frontend) startRequestProcessor() {
|
|||||||
f.processRequest(request)
|
f.processRequest(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (f *Frontend) startCallbackProcessor() {
|
||||||
|
for callback := range callbackBuffer {
|
||||||
|
err := f.handleCallback(callback)
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Frontend) WindowReload() {
|
func (f *Frontend) WindowReload() {
|
||||||
f.ExecJS("runtime.WindowReload();")
|
f.ExecJS("runtime.WindowReload();")
|
||||||
@@ -208,6 +214,9 @@ func (f *Frontend) WindowSetRGBA(col *options.RGBA) {
|
|||||||
|
|
||||||
func (f *Frontend) Quit() {
|
func (f *Frontend) Quit() {
|
||||||
f.mainWindow.Quit()
|
f.mainWindow.Quit()
|
||||||
|
if f.frontendOptions.OnShutdown != nil {
|
||||||
|
f.frontendOptions.OnShutdown(f.ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventNotify struct {
|
type EventNotify struct {
|
||||||
@@ -229,13 +238,14 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) processMessage(message string) {
|
func (f *Frontend) processMessage(message string) {
|
||||||
if message == "drag" {
|
|
||||||
err := f.startDrag()
|
if message == "DomReady" {
|
||||||
if err != nil {
|
if f.frontendOptions.OnDomReady != nil {
|
||||||
f.logger.Error(err.Error())
|
f.frontendOptions.OnDomReady(f.ctx)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := f.dispatcher.ProcessMessage(message, f)
|
result, err := f.dispatcher.ProcessMessage(message, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.logger.Error(err.Error())
|
f.logger.Error(err.Error())
|
||||||
@@ -259,14 +269,6 @@ func (f *Frontend) Callback(message string) {
|
|||||||
f.ExecJS(`window.wails.Callback(` + strconv.Quote(message) + `);`)
|
f.ExecJS(`window.wails.Callback(` + strconv.Quote(message) + `);`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) startDrag() error {
|
|
||||||
//if !w32.ReleaseCapture() {
|
|
||||||
// return fmt.Errorf("unable to release mouse capture")
|
|
||||||
//}
|
|
||||||
//w32.SendMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Frontend) ExecJS(js string) {
|
func (f *Frontend) ExecJS(js string) {
|
||||||
f.mainWindow.ExecJS(js)
|
f.mainWindow.ExecJS(js)
|
||||||
}
|
}
|
||||||
@@ -283,8 +285,10 @@ func (f *Frontend) processRequest(r *request) {
|
|||||||
//TODO: Handle errors
|
//TODO: Handle errors
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := C.CString(string(_contents))
|
var data unsafe.Pointer
|
||||||
defer C.free(unsafe.Pointer(data))
|
if _contents != nil {
|
||||||
|
data = unsafe.Pointer(&_contents[0])
|
||||||
|
}
|
||||||
mimetype := C.CString(_mimetype)
|
mimetype := C.CString(_mimetype)
|
||||||
defer C.free(unsafe.Pointer(mimetype))
|
defer C.free(unsafe.Pointer(mimetype))
|
||||||
|
|
||||||
@@ -304,3 +308,8 @@ func processURLRequest(ctx unsafe.Pointer, url *C.char) {
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export processCallback
|
||||||
|
func processCallback(callbackID uint) {
|
||||||
|
callbackBuffer <- callbackID
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
void processMessage(const char*t) {
|
void processMessage(const char*t) {
|
||||||
NSLog(@"processMessage called");
|
NSLog(@"processMessage called");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void processMessageDialogResponse(int t) {
|
void processMessageDialogResponse(int t) {
|
||||||
@@ -22,33 +21,215 @@ void processMessageDialogResponse(int t) {
|
|||||||
void processOpenFileDialogResponse(const char *t) {
|
void processOpenFileDialogResponse(const char *t) {
|
||||||
NSLog(@"processMessage called %s", t);
|
NSLog(@"processMessage called %s", t);
|
||||||
}
|
}
|
||||||
|
void processSaveFileDialogResponse(const char *t) {
|
||||||
|
NSLog(@"processMessage called %s", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void processCallback(int callbackID) {
|
||||||
|
NSLog(@"Process callback %d", callbackID);
|
||||||
|
}
|
||||||
|
|
||||||
void processURLRequest(void *ctx, const char* url) {
|
void processURLRequest(void *ctx, const char* url) {
|
||||||
NSLog(@"processURLRequest called");
|
NSLog(@"processURLRequest called");
|
||||||
const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e };
|
const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e };
|
||||||
ProcessURLResponse(ctx, url, "text/html", myByteArray, 21);
|
ProcessURLResponse(ctx, url, "text/html", (void*)myByteArray, 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char _Users_username_Pictures_SaltBae_png[] = {
|
||||||
|
|
||||||
|
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||||
|
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14,
|
||||||
|
0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x89, 0x1d, 0x0d, 0x00, 0x00, 0x00,
|
||||||
|
0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61,
|
||||||
|
0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a,
|
||||||
|
0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80,
|
||||||
|
0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a,
|
||||||
|
0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00,
|
||||||
|
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b,
|
||||||
|
0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x01, 0xd5, 0x69, 0x54,
|
||||||
|
0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64,
|
||||||
|
0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78,
|
||||||
|
0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62,
|
||||||
|
0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20,
|
||||||
|
0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, 0x4d, 0x50,
|
||||||
|
0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x22,
|
||||||
|
0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44,
|
||||||
|
0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d,
|
||||||
|
0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
|
||||||
|
0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f,
|
||||||
|
0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79,
|
||||||
|
0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x0a, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65,
|
||||||
|
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64,
|
||||||
|
0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x0a, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78,
|
||||||
|
0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68,
|
||||||
|
0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f,
|
||||||
|
0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f,
|
||||||
|
0x31, 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f,
|
||||||
|
0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c,
|
||||||
|
0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65,
|
||||||
|
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72,
|
||||||
|
0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c,
|
||||||
|
0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74,
|
||||||
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68,
|
||||||
|
0x6f, 0x74, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74,
|
||||||
|
0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
|
||||||
|
0x32, 0x3c, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68, 0x6f, 0x74,
|
||||||
|
0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72,
|
||||||
|
0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44,
|
||||||
|
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
|
||||||
|
0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46,
|
||||||
|
0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74,
|
||||||
|
0x61, 0x3e, 0x0a, 0x02, 0xd8, 0x80, 0x05, 0x00, 0x00, 0x04, 0xdc, 0x49,
|
||||||
|
0x44, 0x41, 0x54, 0x38, 0x11, 0x1d, 0x94, 0x49, 0x6c, 0x1b, 0x65, 0x18,
|
||||||
|
0x86, 0x9f, 0x99, 0xf9, 0x67, 0xc6, 0x6b, 0xbc, 0x26, 0xce, 0xda, 0xa4,
|
||||||
|
0x25, 0x69, 0x0b, 0x2d, 0x28, 0x34, 0x2c, 0x95, 0x00, 0x89, 0x45, 0x08,
|
||||||
|
0x5a, 0x95, 0x03, 0x08, 0x09, 0x21, 0xe0, 0x80, 0x38, 0xc3, 0x85, 0x03,
|
||||||
|
0xe2, 0x00, 0x47, 0xc4, 0x1d, 0x38, 0x70, 0xe3, 0xc6, 0x01, 0x01, 0x42,
|
||||||
|
0x20, 0x54, 0x7a, 0x2a, 0x6b, 0x0b, 0x94, 0xd2, 0xd2, 0x25, 0x69, 0x9b,
|
||||||
|
0xa4, 0x0d, 0x2d, 0xa9, 0xb3, 0x78, 0x89, 0x9d, 0xf1, 0x2c, 0x9e, 0x85,
|
||||||
|
0x2f, 0xb5, 0x35, 0xb6, 0x35, 0x96, 0xde, 0x79, 0xdf, 0xef, 0x7f, 0x9f,
|
||||||
|
0x4f, 0xfb, 0xe0, 0xad, 0x37, 0x12, 0xfd, 0xf0, 0xb3, 0x9c, 0xfb, 0xb7,
|
||||||
|
0xc5, 0x8d, 0x46, 0x9b, 0x71, 0x5b, 0xf1, 0xd0, 0xf4, 0x18, 0xdb, 0xeb,
|
||||||
|
0x4b, 0x1c, 0xff, 0xf1, 0x57, 0x98, 0xdc, 0x87, 0x72, 0x3a, 0x8c, 0x3a,
|
||||||
|
0xcb, 0x8c, 0xea, 0x31, 0x35, 0xb7, 0xc3, 0x99, 0xba, 0xc3, 0xd7, 0xab,
|
||||||
|
0x3e, 0x87, 0x2a, 0x8a, 0xb3, 0xff, 0xdc, 0xe0, 0x9b, 0x8f, 0x5f, 0xa2,
|
||||||
|
0x1c, 0xc5, 0xfc, 0x72, 0xc9, 0x41, 0x99, 0x71, 0x48, 0xca, 0x84, 0x3c,
|
||||||
|
0x3e, 0xda, 0xd2, 0x05, 0x9a, 0xb1, 0xc7, 0x35, 0x67, 0x1c, 0xdd, 0x4c,
|
||||||
|
0x68, 0xeb, 0x26, 0xd9, 0x30, 0x26, 0x09, 0x23, 0x5c, 0x3f, 0xc2, 0xd3,
|
||||||
|
0x43, 0xc2, 0x24, 0x21, 0x4e, 0x34, 0x40, 0x27, 0x89, 0x13, 0xf9, 0x1e,
|
||||||
|
0x22, 0x6e, 0xd5, 0x45, 0x43, 0x63, 0xc6, 0xd2, 0x50, 0xa9, 0xc4, 0x67,
|
||||||
|
0x24, 0x15, 0x72, 0xa9, 0x7e, 0x95, 0xfa, 0x4f, 0x27, 0x78, 0x64, 0x76,
|
||||||
|
0x86, 0x23, 0x61, 0xc0, 0xf0, 0x58, 0x15, 0xc3, 0x29, 0x71, 0x06, 0x45,
|
||||||
|
0x2e, 0xa5, 0x48, 0xbb, 0x0a, 0x3d, 0x89, 0xa0, 0x8f, 0x08, 0x8a, 0x8e,
|
||||||
|
0x08, 0xbb, 0xc1, 0x8e, 0xb0, 0x8d, 0xdd, 0x0f, 0xc9, 0x84, 0x06, 0x65,
|
||||||
|
0x34, 0xf4, 0xed, 0x8d, 0xff, 0x58, 0xbd, 0xfc, 0x27, 0x17, 0x2f, 0x9e,
|
||||||
|
0xe3, 0xf0, 0x81, 0x49, 0x5e, 0xde, 0x5f, 0xe1, 0x9e, 0x82, 0xcd, 0xdc,
|
||||||
|
0x78, 0x8d, 0xd9, 0xb2, 0xc9, 0x56, 0x12, 0x32, 0x94, 0x4f, 0x91, 0xcb,
|
||||||
|
0x88, 0x68, 0xda, 0x42, 0x13, 0x77, 0x11, 0xa2, 0xa8, 0xc3, 0x5a, 0x5f,
|
||||||
|
0x46, 0x30, 0x65, 0x52, 0x29, 0xe4, 0x24, 0x4d, 0x8e, 0xcc, 0x68, 0x19,
|
||||||
|
0xe5, 0x76, 0xbb, 0xac, 0x5c, 0x98, 0xa7, 0xb3, 0xed, 0xd0, 0x37, 0x62,
|
||||||
|
0xa2, 0xb0, 0xc7, 0x89, 0xe5, 0x2e, 0x03, 0x0d, 0x97, 0x95, 0x46, 0x8f,
|
||||||
|
0x31, 0xd7, 0xa6, 0x63, 0x81, 0x65, 0x25, 0x84, 0xba, 0x45, 0x5f, 0x65,
|
||||||
|
0x31, 0x2c, 0x71, 0x6b, 0x77, 0x69, 0xf5, 0x7a, 0xbc, 0xb0, 0x3b, 0xcd,
|
||||||
|
0xf9, 0xa5, 0x90, 0xd1, 0xb0, 0xcd, 0xd4, 0xb0, 0xdc, 0xd7, 0xc4, 0xfa,
|
||||||
|
0xf0, 0x78, 0x95, 0x7b, 0x27, 0xab, 0x5c, 0x5e, 0x6e, 0xd2, 0xee, 0x05,
|
||||||
|
0xdc, 0xd8, 0xea, 0xf1, 0xf7, 0xe2, 0x1a, 0xc7, 0xee, 0x1a, 0x62, 0x2e,
|
||||||
|
0x1f, 0xe3, 0xe8, 0xb6, 0xc4, 0x4c, 0xd3, 0x6d, 0x6e, 0xd0, 0x6b, 0xfc,
|
||||||
|
0x4c, 0xe3, 0xd4, 0x1f, 0xc4, 0x4b, 0xf3, 0x1c, 0x2c, 0x65, 0x29, 0x67,
|
||||||
|
0x4d, 0xbe, 0xfb, 0xad, 0x45, 0x65, 0x0c, 0xea, 0x7e, 0x1f, 0x15, 0x6b,
|
||||||
|
0x09, 0x0b, 0x8b, 0xb7, 0x19, 0xc9, 0xa5, 0x78, 0x75, 0x6e, 0x18, 0xdf,
|
||||||
|
0xf5, 0x79, 0x72, 0xd0, 0xa2, 0x2d, 0xb3, 0x3a, 0xbb, 0xb4, 0x41, 0x3e,
|
||||||
|
0x53, 0xe6, 0xf4, 0xca, 0x3c, 0xa5, 0x7c, 0x86, 0xe9, 0xfd, 0x47, 0x18,
|
||||||
|
0x2e, 0xbd, 0xce, 0xd1, 0x97, 0x26, 0x78, 0xbc, 0x7e, 0x1d, 0xff, 0xcc,
|
||||||
|
0xa7, 0x5c, 0x71, 0x74, 0x16, 0xe3, 0x18, 0xd7, 0x1e, 0x23, 0xe8, 0xac,
|
||||||
|
0xa3, 0x0c, 0xcd, 0x60, 0x22, 0x6f, 0x43, 0x36, 0x43, 0x3b, 0x19, 0xc6,
|
||||||
|
0x08, 0x7a, 0xe0, 0x6c, 0xe3, 0x27, 0x8a, 0xdb, 0x4e, 0xc0, 0xd4, 0xa0,
|
||||||
|
0xcd, 0x27, 0xaf, 0xbd, 0xcb, 0x86, 0x36, 0xc6, 0xcc, 0xfe, 0x59, 0xd2,
|
||||||
|
0xca, 0x90, 0x93, 0x36, 0x70, 0xaf, 0x9c, 0xe4, 0xcb, 0x6f, 0x65, 0x54,
|
||||||
|
0xd9, 0x47, 0x59, 0x70, 0xbb, 0x74, 0x1b, 0x0e, 0x89, 0xe7, 0xa3, 0xc7,
|
||||||
|
0x12, 0x39, 0x63, 0xea, 0x68, 0x12, 0x6b, 0x53, 0x5c, 0x9e, 0xef, 0x76,
|
||||||
|
0xf0, 0x55, 0x86, 0x0d, 0x17, 0x56, 0x9a, 0x4d, 0x94, 0x95, 0x65, 0xe6,
|
||||||
|
0xbe, 0x67, 0x98, 0xbe, 0xfb, 0x21, 0x52, 0xd2, 0x43, 0xaf, 0x5d, 0x47,
|
||||||
|
0x6b, 0x5c, 0xa3, 0x59, 0xbf, 0xc2, 0x62, 0xdd, 0x26, 0xa5, 0x12, 0x6a,
|
||||||
|
0x41, 0x44, 0xdf, 0xbd, 0xcd, 0x92, 0x17, 0xa0, 0xb6, 0x03, 0x43, 0xba,
|
||||||
|
0x66, 0x91, 0xe9, 0xdc, 0xc2, 0xce, 0xed, 0xa1, 0xfc, 0xc0, 0x2b, 0x14,
|
||||||
|
0xff, 0xfd, 0x1e, 0x4b, 0xb3, 0xa9, 0x29, 0x87, 0x81, 0xd2, 0x04, 0x8e,
|
||||||
|
0x66, 0x89, 0x58, 0x00, 0x7e, 0x07, 0xaf, 0xdb, 0xa4, 0xbb, 0xb5, 0x49,
|
||||||
|
0xb9, 0xaa, 0x18, 0xb9, 0x77, 0x8e, 0xcd, 0xdb, 0x6d, 0x1e, 0x1c, 0xb5,
|
||||||
|
0x38, 0x7d, 0xa5, 0xcf, 0xaa, 0x08, 0xeb, 0x77, 0x3f, 0x35, 0xc7, 0xda,
|
||||||
|
0xfc, 0x02, 0xaa, 0xf6, 0x1c, 0xbb, 0x9f, 0x78, 0x9f, 0x89, 0x43, 0x47,
|
||||||
|
0xa4, 0x6f, 0x3d, 0x06, 0xed, 0x90, 0x92, 0x79, 0x95, 0xd4, 0xe4, 0xfd,
|
||||||
|
0x98, 0x66, 0x4a, 0x6a, 0xd7, 0xc7, 0x0b, 0x62, 0xa4, 0xe3, 0x8c, 0x4d,
|
||||||
|
0xc4, 0xe8, 0x85, 0x98, 0xe5, 0x46, 0x44, 0x26, 0x97, 0x21, 0xe9, 0xf7,
|
||||||
|
0xf9, 0x61, 0xc5, 0xe3, 0xd4, 0x66, 0x84, 0xd2, 0x70, 0xc9, 0xee, 0x79,
|
||||||
|
0x98, 0x43, 0xc7, 0x5e, 0x27, 0xb6, 0x8a, 0xd2, 0x5a, 0x1f, 0xf3, 0xa9,
|
||||||
|
0xf7, 0x88, 0xce, 0x7d, 0x85, 0x71, 0xe0, 0x79, 0x98, 0x7a, 0x90, 0x9e,
|
||||||
|
0x1b, 0xd0, 0x13, 0x52, 0x4a, 0x66, 0x97, 0x7d, 0x33, 0x1e, 0xed, 0xae,
|
||||||
|
0xc7, 0x87, 0x1f, 0x7d, 0xce, 0xc2, 0xd5, 0x3a, 0xe6, 0xde, 0x02, 0xcb,
|
||||||
|
0xdb, 0x3e, 0xbe, 0xa6, 0x91, 0x95, 0x62, 0x6b, 0x2f, 0xce, 0x90, 0x3c,
|
||||||
|
0xfd, 0xce, 0x71, 0x0e, 0xcc, 0x3e, 0x82, 0x13, 0xf4, 0x09, 0xd5, 0x00,
|
||||||
|
0x16, 0x82, 0x98, 0xb3, 0x49, 0x24, 0xb1, 0x83, 0xc8, 0xc0, 0xd6, 0x3a,
|
||||||
|
0x54, 0x33, 0xab, 0x14, 0x8c, 0x16, 0x4e, 0x38, 0xcc, 0xe5, 0xeb, 0x4d,
|
||||||
|
0x5e, 0x7b, 0xfb, 0x4d, 0xaa, 0x79, 0xa1, 0x45, 0x1c, 0x9b, 0xd2, 0x94,
|
||||||
|
0xcc, 0x0e, 0x8c, 0x52, 0x7a, 0x65, 0x17, 0xc7, 0xa9, 0x0c, 0x8e, 0xe2,
|
||||||
|
0xf7, 0xba, 0xa8, 0xc8, 0x13, 0x87, 0x32, 0x87, 0x0b, 0x27, 0x30, 0x36,
|
||||||
|
0x57, 0xe8, 0xea, 0x15, 0xce, 0x06, 0x65, 0x5e, 0x3d, 0x5a, 0x94, 0x53,
|
||||||
|
0xb7, 0x59, 0x58, 0xdf, 0x25, 0xc4, 0xe4, 0xc9, 0x65, 0x3d, 0xb4, 0xb4,
|
||||||
|
0x4e, 0x37, 0x0c, 0x29, 0x98, 0x4a, 0xe8, 0x11, 0xde, 0x85, 0x42, 0x43,
|
||||||
|
0x1c, 0xaa, 0x38, 0x55, 0xc4, 0xb4, 0x2c, 0x22, 0x3d, 0xcd, 0xfa, 0xea,
|
||||||
|
0x0d, 0xf4, 0x8d, 0x1f, 0xc9, 0x5f, 0xfa, 0x82, 0x6d, 0xc7, 0xe1, 0xa6,
|
||||||
|
0x57, 0xe3, 0x56, 0x6e, 0x96, 0xbf, 0x16, 0x1f, 0xa3, 0x54, 0xaa, 0x91,
|
||||||
|
0x16, 0x5a, 0xb2, 0xa9, 0x04, 0xaf, 0x67, 0xc9, 0xac, 0x6c, 0xfa, 0x32,
|
||||||
|
0x9e, 0x48, 0xea, 0xa5, 0x0b, 0x89, 0x3b, 0x54, 0x47, 0xf2, 0xa1, 0xf2,
|
||||||
|
0x2a, 0x4d, 0xeb, 0xf4, 0x17, 0xdc, 0xd4, 0x72, 0x6c, 0xb5, 0x36, 0x28,
|
||||||
|
0xb6, 0x7e, 0x17, 0x04, 0xd3, 0xac, 0x7a, 0x42, 0xc1, 0xf4, 0x6e, 0x9e,
|
||||||
|
0xbf, 0x6b, 0xb7, 0x3c, 0x3a, 0x21, 0x67, 0xcb, 0x41, 0x48, 0x07, 0x91,
|
||||||
|
0xde, 0x1a, 0xe2, 0xaa, 0x9c, 0xb1, 0x59, 0xdb, 0x12, 0x25, 0xc1, 0x32,
|
||||||
|
0x92, 0xea, 0xc9, 0xaf, 0x3b, 0x97, 0xca, 0xca, 0xfe, 0x5b, 0xfe, 0xe5,
|
||||||
|
0x33, 0x29, 0xeb, 0x16, 0x95, 0xd2, 0x24, 0xeb, 0xda, 0x30, 0xeb, 0x95,
|
||||||
|
0x1a, 0xd3, 0xf7, 0x0f, 0x51, 0x1c, 0xd9, 0x0b, 0x99, 0x12, 0x7a, 0x4a,
|
||||||
|
0xd0, 0xd3, 0x25, 0x9a, 0x88, 0x45, 0xb1, 0x04, 0x33, 0x2c, 0x8a, 0x99,
|
||||||
|
0x34, 0x6b, 0x75, 0x19, 0x91, 0x9d, 0x92, 0x29, 0x89, 0xa0, 0x2c, 0x8b,
|
||||||
|
0x9d, 0xd8, 0x7a, 0x5e, 0x04, 0x07, 0x87, 0x66, 0x28, 0x56, 0x67, 0xb9,
|
||||||
|
0xd6, 0xd2, 0x39, 0xd9, 0xec, 0x33, 0x30, 0xb2, 0x8b, 0xea, 0xae, 0x83,
|
||||||
|
0x18, 0xb9, 0x31, 0x34, 0xbb, 0x42, 0x22, 0x0b, 0x21, 0x96, 0x3c, 0x61,
|
||||||
|
0xac, 0xcb, 0x95, 0x60, 0x2a, 0xe9, 0x68, 0x79, 0x08, 0x36, 0x56, 0x65,
|
||||||
|
0x27, 0x4a, 0xd9, 0x83, 0x00, 0xcf, 0x0b, 0xf1, 0xfc, 0x10, 0x15, 0x0a,
|
||||||
|
0x6a, 0x75, 0x77, 0x8b, 0x86, 0xdc, 0x58, 0x57, 0x45, 0x52, 0xe9, 0x84,
|
||||||
|
0x81, 0x7c, 0x91, 0x28, 0x55, 0x23, 0x96, 0x13, 0xd7, 0x24, 0xbe, 0xac,
|
||||||
|
0x17, 0xfa, 0xf2, 0x78, 0x63, 0xc7, 0x82, 0x08, 0xda, 0xa6, 0xc5, 0x50,
|
||||||
|
0x55, 0x04, 0xe5, 0x65, 0x5b, 0x06, 0xde, 0xce, 0xf0, 0x24, 0xf3, 0x4e,
|
||||||
|
0x70, 0xb5, 0x15, 0x6a, 0x34, 0x7b, 0x11, 0x9d, 0xbe, 0x10, 0x53, 0xd0,
|
||||||
|
0xa8, 0x86, 0x2e, 0x76, 0xb6, 0x2a, 0x9d, 0x2c, 0x48, 0x3c, 0x5b, 0xa2,
|
||||||
|
0xc8, 0x3a, 0x37, 0xd4, 0x9d, 0xed, 0x6c, 0x4a, 0xab, 0x95, 0x6e, 0x08,
|
||||||
|
0x66, 0x3d, 0x5a, 0xad, 0x4d, 0x18, 0xc8, 0xca, 0xfa, 0xd5, 0x85, 0x6f,
|
||||||
|
0xf9, 0x5f, 0xde, 0x02, 0x30, 0xff, 0x03, 0x8c, 0x47, 0x35, 0xad, 0xbc,
|
||||||
|
0xbf, 0x26, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
|
||||||
|
0x42, 0x60, 0x82
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int _Users_username_Pictures_SaltBae_png_len = 1863;
|
||||||
|
|
||||||
int main(int argc, const char * argv[]) {
|
int main(int argc, const char * argv[]) {
|
||||||
// insert code here...
|
// insert code here...
|
||||||
int frameless = 0;
|
int frameless = 1;
|
||||||
int resizable = 1;
|
int resizable = 0;
|
||||||
int fullscreen = 0;
|
int fullscreen = 0;
|
||||||
int fullSizeContent = 1;
|
int fullSizeContent = 1;
|
||||||
int hideTitleBar = 0;
|
int hideTitleBar = 0;
|
||||||
int titlebarAppearsTransparent = 1;
|
int titlebarAppearsTransparent = 0;
|
||||||
int hideTitle = 0;
|
int hideTitle = 0;
|
||||||
int useToolbar = 1;
|
int useToolbar = 0;
|
||||||
int hideToolbarSeparator = 1;
|
int hideToolbarSeparator = 0;
|
||||||
int webviewIsTransparent = 0;
|
int webviewIsTransparent = 1;
|
||||||
int alwaysOnTop = 1;
|
int alwaysOnTop = 0;
|
||||||
int hideWindowOnClose = 0;
|
int hideWindowOnClose = 0;
|
||||||
const char* appearance = "NSAppearanceNameDarkAqua";
|
const char* appearance = "NSAppearanceNameDarkAqua";
|
||||||
int windowIsTranslucent = 1;
|
int windowIsTranslucent = 1;
|
||||||
int debug = 1;
|
int debug = 1;
|
||||||
WailsContext *result = Create("OI OI!",400,400, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug);
|
WailsContext *result = Create("OI OI!",400,400, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug);
|
||||||
SetRGBA(result, 255, 0, 0, 255);
|
SetRGBA(result, 255, 0, 0, 255);
|
||||||
|
void *m = NewMenu("");
|
||||||
|
SetAbout(result, "Fake title", "I am a description", _Users_username_Pictures_SaltBae_png, _Users_username_Pictures_SaltBae_png_len);
|
||||||
|
// AddMenuByRole(result, 1);
|
||||||
|
|
||||||
|
AppendRole(result, m, 1);
|
||||||
|
AppendRole(result, m, 2);
|
||||||
|
void* submenu = NewMenu("test");
|
||||||
|
void* menuITem = AppendMenuItem(result, submenu, "Woohoo", "p", 0, 0, 0, 470);
|
||||||
|
AppendSubmenu(m, submenu);
|
||||||
|
UpdateMenuItem(menuITem, 1);
|
||||||
|
SetAsApplicationMenu(result, m);
|
||||||
|
SetPosition(result, 100, 100);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Run((void*)CFBridgingRetain(result));
|
Run((void*)CFBridgingRetain(result));
|
||||||
|
|||||||
@@ -3,96 +3,133 @@
|
|||||||
|
|
||||||
package darwin
|
package darwin
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Application.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NSMenu struct {
|
||||||
|
context unsafe.Pointer
|
||||||
|
nsmenu unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNSMenu(context unsafe.Pointer, name string) *NSMenu {
|
||||||
|
c := NewCalloc()
|
||||||
|
defer c.Free()
|
||||||
|
title := c.String(name)
|
||||||
|
nsmenu := C.NewMenu(title)
|
||||||
|
return &NSMenu{
|
||||||
|
context: context,
|
||||||
|
nsmenu: nsmenu,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *NSMenu) AddSubMenu(label string) *NSMenu {
|
||||||
|
result := NewNSMenu(m.context, label)
|
||||||
|
C.AppendSubmenu(m.nsmenu, result.nsmenu)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *NSMenu) AppendRole(role menu.Role) {
|
||||||
|
C.AppendRole(m.context, m.nsmenu, C.int(role))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MenuItem struct {
|
||||||
|
id uint
|
||||||
|
nsmenuitem unsafe.Pointer
|
||||||
|
wailsMenuItem *menu.MenuItem
|
||||||
|
radioGroupMembers []*MenuItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
|
||||||
|
c := NewCalloc()
|
||||||
|
defer c.Free()
|
||||||
|
var modifier C.int
|
||||||
|
var key *C.char
|
||||||
|
if menuItem.Accelerator != nil {
|
||||||
|
modifier = C.int(keys.ToMacModifier(menuItem.Accelerator))
|
||||||
|
key = c.String(menuItem.Accelerator.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &MenuItem{
|
||||||
|
wailsMenuItem: menuItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.id = createMenuItemID(result)
|
||||||
|
result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
//func (w *Window) SetApplicationMenu(menu *menu.Menu) {
|
//func (w *Window) SetApplicationMenu(menu *menu.Menu) {
|
||||||
//w.applicationMenu = menu
|
//w.applicationMenu = menu
|
||||||
//processMenu(w, menu)
|
//processMenu(w, menu)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//func processMenu(window *Window, menu *menu.Menu) {
|
func processMenu(parent *NSMenu, wailsMenu *menu.Menu) {
|
||||||
//mainMenu := window.NewMenu()
|
var radioGroups []*MenuItem
|
||||||
//for _, menuItem := range menu.Items {
|
|
||||||
// submenu := mainMenu.AddSubMenu(menuItem.Label)
|
|
||||||
// for _, menuItem := range menuItem.SubMenu.Items {
|
|
||||||
// processMenuItem(submenu, menuItem)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//mainMenu.Show()
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
for _, menuItem := range wailsMenu.Items {
|
||||||
// if menuItem.Hidden {
|
if menuItem.SubMenu != nil {
|
||||||
// return
|
if len(radioGroups) > 0 {
|
||||||
// }
|
processRadioGroups(radioGroups)
|
||||||
// switch menuItem.Type {
|
radioGroups = []*MenuItem{}
|
||||||
// case menu.SeparatorType:
|
}
|
||||||
// parent.AddSeparator()
|
submenu := parent.AddSubMenu(menuItem.Label)
|
||||||
// case menu.TextType:
|
processMenu(submenu, menuItem.SubMenu)
|
||||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
} else {
|
||||||
// newItem := parent.AddItem(menuItem.Label, shortcut)
|
lastMenuItem := processMenuItem(parent, menuItem)
|
||||||
// if menuItem.Tooltip != "" {
|
if menuItem.Type == menu.RadioType {
|
||||||
// newItem.SetToolTip(menuItem.Tooltip)
|
radioGroups = append(radioGroups, lastMenuItem)
|
||||||
// }
|
} else {
|
||||||
// if menuItem.Click != nil {
|
if len(radioGroups) > 0 {
|
||||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
processRadioGroups(radioGroups)
|
||||||
// menuItem.Click(&menu.CallbackData{
|
radioGroups = []*MenuItem{}
|
||||||
// MenuItem: menuItem,
|
}
|
||||||
// })
|
}
|
||||||
// })
|
}
|
||||||
// }
|
}
|
||||||
// newItem.SetEnabled(!menuItem.Disabled)
|
}
|
||||||
//
|
|
||||||
// case menu.CheckboxType:
|
func processRadioGroups(groups []*MenuItem) {
|
||||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
for _, item := range groups {
|
||||||
// newItem := parent.AddItem(menuItem.Label, shortcut)
|
item.radioGroupMembers = groups
|
||||||
// newItem.SetCheckable(true)
|
}
|
||||||
// newItem.SetChecked(menuItem.Checked)
|
}
|
||||||
// if menuItem.Tooltip != "" {
|
|
||||||
// newItem.SetToolTip(menuItem.Tooltip)
|
func processMenuItem(parent *NSMenu, menuItem *menu.MenuItem) *MenuItem {
|
||||||
// }
|
if menuItem.Hidden {
|
||||||
// if menuItem.Click != nil {
|
return nil
|
||||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
}
|
||||||
// toggleCheckBox(menuItem)
|
if menuItem.Role != 0 {
|
||||||
// menuItem.Click(&menu.CallbackData{
|
parent.AppendRole(menuItem.Role)
|
||||||
// MenuItem: menuItem,
|
return nil
|
||||||
// })
|
}
|
||||||
// })
|
if menuItem.Type == menu.SeparatorType {
|
||||||
// }
|
C.AppendSeparator(parent.nsmenu)
|
||||||
// newItem.SetEnabled(!menuItem.Disabled)
|
return nil
|
||||||
// addCheckBoxToMap(menuItem, newItem)
|
}
|
||||||
// case menu.RadioType:
|
|
||||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
return parent.AddMenuItem(menuItem)
|
||||||
// newItem := parent.AddItemRadio(menuItem.Label, shortcut)
|
|
||||||
// newItem.SetCheckable(true)
|
}
|
||||||
// newItem.SetChecked(menuItem.Checked)
|
|
||||||
// if menuItem.Tooltip != "" {
|
|
||||||
// newItem.SetToolTip(menuItem.Tooltip)
|
|
||||||
// }
|
|
||||||
// if menuItem.Click != nil {
|
|
||||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
|
||||||
// toggleRadioItem(menuItem)
|
|
||||||
// menuItem.Click(&menu.CallbackData{
|
|
||||||
// MenuItem: menuItem,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// newItem.SetEnabled(!menuItem.Disabled)
|
|
||||||
// addRadioItemToMap(menuItem, newItem)
|
|
||||||
// case menu.SubmenuType:
|
|
||||||
// submenu := parent.AddSubMenu(menuItem.Label)
|
|
||||||
// for _, menuItem := range menuItem.SubMenu.Items {
|
|
||||||
// processMenuItem(submenu, menuItem)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
|
func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
|
||||||
//f.mainWindow.SetApplicationMenu(menu)
|
f.mainWindow.SetApplicationMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) MenuUpdateApplicationMenu() {
|
func (f *Frontend) MenuUpdateApplicationMenu() {
|
||||||
//processMenu(f.mainWindow, f.mainWindow.applicationMenu)
|
f.MenuSetApplicationMenu(f.frontendOptions.Menu)
|
||||||
|
f.mainWindow.UpdateApplicationMenu()
|
||||||
}
|
}
|
||||||
|
|||||||
51
v2/internal/frontend/desktop/darwin/menuitem.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package darwin
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Application.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var menuItemToID = make(map[*MenuItem]uint)
|
||||||
|
var idToMenuItem = make(map[uint]*MenuItem)
|
||||||
|
var menuItemLock sync.Mutex
|
||||||
|
var menuItemIDCounter uint = 0
|
||||||
|
|
||||||
|
func createMenuItemID(item *MenuItem) uint {
|
||||||
|
menuItemLock.Lock()
|
||||||
|
defer menuItemLock.Unlock()
|
||||||
|
counter := 0
|
||||||
|
for {
|
||||||
|
menuItemIDCounter++
|
||||||
|
value := idToMenuItem[menuItemIDCounter]
|
||||||
|
if value == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
counter++
|
||||||
|
if counter == math.MaxInt {
|
||||||
|
log.Fatal("insane amounts of menuitems detected! Aborting before the collapse of the world!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idToMenuItem[menuItemIDCounter] = item
|
||||||
|
menuItemToID[item] = menuItemIDCounter
|
||||||
|
return menuItemIDCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMenuItemForID(id uint) *MenuItem {
|
||||||
|
menuItemLock.Lock()
|
||||||
|
defer menuItemLock.Unlock()
|
||||||
|
return idToMenuItem[id]
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ void processURLRequest(void*, const char *);
|
|||||||
void processMessageDialogResponse(int);
|
void processMessageDialogResponse(int);
|
||||||
void processOpenFileDialogResponse(const char*);
|
void processOpenFileDialogResponse(const char*);
|
||||||
void processSaveFileDialogResponse(const char*);
|
void processSaveFileDialogResponse(const char*);
|
||||||
|
void processCallback(int);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,11 +47,8 @@ func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
|||||||
fullscreen := bool2Cint(frontendOptions.Fullscreen)
|
fullscreen := bool2Cint(frontendOptions.Fullscreen)
|
||||||
alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop)
|
alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop)
|
||||||
hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose)
|
hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose)
|
||||||
|
startsHidden := bool2Cint(frontendOptions.StartHidden)
|
||||||
debug := bool2Cint(debugMode)
|
debug := bool2Cint(debugMode)
|
||||||
alpha := C.int(frontendOptions.RGBA.A)
|
|
||||||
red := C.int(frontendOptions.RGBA.R)
|
|
||||||
green := C.int(frontendOptions.RGBA.G)
|
|
||||||
blue := C.int(frontendOptions.RGBA.B)
|
|
||||||
|
|
||||||
var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int
|
var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int
|
||||||
var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int
|
var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int
|
||||||
@@ -57,6 +56,7 @@ func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
|||||||
|
|
||||||
width := C.int(frontendOptions.Width)
|
width := C.int(frontendOptions.Width)
|
||||||
height := C.int(frontendOptions.Height)
|
height := C.int(frontendOptions.Height)
|
||||||
|
windowStartState := C.int(int(frontendOptions.WindowStartState))
|
||||||
|
|
||||||
title = c.String(frontendOptions.Title)
|
title = c.String(frontendOptions.Title)
|
||||||
|
|
||||||
@@ -75,13 +75,39 @@ func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
|||||||
|
|
||||||
appearance = c.String(string(mac.Appearance))
|
appearance = c.String(string(mac.Appearance))
|
||||||
}
|
}
|
||||||
var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug)
|
var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent,
|
||||||
|
hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent,
|
||||||
|
alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug, windowStartState, startsHidden)
|
||||||
|
|
||||||
C.SetRGBA(unsafe.Pointer(context), red, green, blue, alpha)
|
// Create menu
|
||||||
|
result := &Window{
|
||||||
return &Window{
|
|
||||||
context: unsafe.Pointer(context),
|
context: unsafe.Pointer(context),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if frontendOptions.RGBA != nil {
|
||||||
|
result.SetRGBA(frontendOptions.RGBA.R, frontendOptions.RGBA.G, frontendOptions.RGBA.B, frontendOptions.RGBA.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frontendOptions.Mac != nil && frontendOptions.Mac.About != nil {
|
||||||
|
title := c.String(frontendOptions.Mac.About.Title)
|
||||||
|
description := c.String(frontendOptions.Mac.About.Message)
|
||||||
|
var icon unsafe.Pointer
|
||||||
|
var length C.int
|
||||||
|
if frontendOptions.Mac.About.Icon != nil {
|
||||||
|
icon = unsafe.Pointer(&frontendOptions.Mac.About.Icon[0])
|
||||||
|
length = C.int(len(frontendOptions.Mac.About.Icon))
|
||||||
|
}
|
||||||
|
C.SetAbout(result.context, title, description, icon, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frontendOptions.Menu != nil {
|
||||||
|
result.SetApplicationMenu(frontendOptions.Menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.SetMinSize(frontendOptions.MinWidth, frontendOptions.MinHeight)
|
||||||
|
result.SetMaxSize(frontendOptions.MaxWidth, frontendOptions.MaxHeight)
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) Center() {
|
func (w *Window) Center() {
|
||||||
@@ -90,7 +116,6 @@ func (w *Window) Center() {
|
|||||||
|
|
||||||
func (w *Window) Run() {
|
func (w *Window) Run() {
|
||||||
C.Run(w.context)
|
C.Run(w.context)
|
||||||
println("I exited!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) Quit() {
|
func (w *Window) Quit() {
|
||||||
@@ -138,10 +163,16 @@ func (w *Window) UnMinimise() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) SetMinSize(width int, height int) {
|
func (w *Window) SetMinSize(width int, height int) {
|
||||||
|
if width == 0 && height == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
C.SetMinSize(w.context, C.int(width), C.int(height))
|
C.SetMinSize(w.context, C.int(width), C.int(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) SetMaxSize(width int, height int) {
|
func (w *Window) SetMaxSize(width int, height int) {
|
||||||
|
if width == 0 && height == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
C.SetMaxSize(w.context, C.int(width), C.int(height))
|
C.SetMaxSize(w.context, C.int(width), C.int(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,3 +216,13 @@ func (w *Window) Size() (int, int) {
|
|||||||
temp := C.GoString(_result)
|
temp := C.GoString(_result)
|
||||||
return parseIntDuo(temp)
|
return parseIntDuo(temp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Window) SetApplicationMenu(inMenu *menu.Menu) {
|
||||||
|
mainMenu := NewNSMenu(w.context, "")
|
||||||
|
processMenu(mainMenu, inMenu)
|
||||||
|
C.SetAsApplicationMenu(w.context, mainMenu.nsmenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Window) UpdateApplicationMenu() {
|
||||||
|
C.UpdateApplicationMenu(w.context)
|
||||||
|
}
|
||||||
|
|||||||
@@ -130,10 +130,6 @@ func (f *Frontend) Run(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if f.frontendOptions.Fullscreen {
|
|
||||||
mainWindow.Fullscreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
mainWindow.Run()
|
mainWindow.Run()
|
||||||
mainWindow.Close()
|
mainWindow.Close()
|
||||||
return nil
|
return nil
|
||||||
@@ -412,11 +408,6 @@ func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.IC
|
|||||||
go f.frontendOptions.OnDomReady(f.ctx)
|
go f.frontendOptions.OnDomReady(f.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you want to start hidden, return
|
|
||||||
if f.frontendOptions.StartHidden {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
|
// Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
|
||||||
err := f.chromium.Hide()
|
err := f.chromium.Hide()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -426,6 +417,24 @@ func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.IC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
f.mainWindow.Show()
|
|
||||||
|
if f.frontendOptions.StartHidden {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch f.frontendOptions.WindowStartState {
|
||||||
|
case options.Maximised:
|
||||||
|
f.mainWindow.Maximise()
|
||||||
|
case options.Minimised:
|
||||||
|
f.mainWindow.Minimise()
|
||||||
|
case options.Fullscreen:
|
||||||
|
f.mainWindow.Fullscreen()
|
||||||
|
f.mainWindow.Show()
|
||||||
|
default:
|
||||||
|
if f.frontendOptions.Fullscreen {
|
||||||
|
f.mainWindow.Fullscreen()
|
||||||
|
}
|
||||||
|
f.mainWindow.Show()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,24 +18,24 @@ type Window struct {
|
|||||||
dispatchq []func()
|
dispatchq []func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWindow(parent winc.Controller, options *options.App) *Window {
|
func NewWindow(parent winc.Controller, appoptions *options.App) *Window {
|
||||||
result := new(Window)
|
result := new(Window)
|
||||||
result.frontendOptions = options
|
result.frontendOptions = appoptions
|
||||||
result.SetIsForm(true)
|
result.SetIsForm(true)
|
||||||
|
|
||||||
var exStyle int
|
var exStyle int
|
||||||
if options.Windows != nil {
|
if appoptions.Windows != nil {
|
||||||
exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
|
exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
|
||||||
if options.Windows.WindowIsTranslucent {
|
if appoptions.Windows.WindowIsTranslucent {
|
||||||
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
|
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.AlwaysOnTop {
|
if appoptions.AlwaysOnTop {
|
||||||
exStyle |= w32.WS_EX_TOPMOST
|
exStyle |= w32.WS_EX_TOPMOST
|
||||||
}
|
}
|
||||||
|
|
||||||
var dwStyle = w32.WS_OVERLAPPEDWINDOW
|
var dwStyle = w32.WS_OVERLAPPEDWINDOW
|
||||||
if options.Frameless {
|
if appoptions.Frameless {
|
||||||
dwStyle = w32.WS_POPUP
|
dwStyle = w32.WS_POPUP
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
|
|||||||
result.SetParent(parent)
|
result.SetParent(parent)
|
||||||
|
|
||||||
loadIcon := true
|
loadIcon := true
|
||||||
if options.Windows != nil && options.Windows.DisableWindowIcon == true {
|
if appoptions.Windows != nil && appoptions.Windows.DisableWindowIcon == true {
|
||||||
loadIcon = false
|
loadIcon = false
|
||||||
}
|
}
|
||||||
if loadIcon {
|
if loadIcon {
|
||||||
@@ -53,21 +53,21 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.SetSize(options.Width, options.Height)
|
result.SetSize(appoptions.Width, appoptions.Height)
|
||||||
result.SetText(options.Title)
|
result.SetText(appoptions.Title)
|
||||||
if options.Frameless == false && !options.Fullscreen {
|
if appoptions.Frameless == false && !appoptions.Fullscreen {
|
||||||
result.EnableMaxButton(!options.DisableResize)
|
result.EnableMaxButton(!appoptions.DisableResize)
|
||||||
result.EnableSizable(!options.DisableResize)
|
result.EnableSizable(!appoptions.DisableResize)
|
||||||
result.SetMinSize(options.MinWidth, options.MinHeight)
|
result.SetMinSize(appoptions.MinWidth, appoptions.MinHeight)
|
||||||
result.SetMaxSize(options.MaxWidth, options.MaxHeight)
|
result.SetMaxSize(appoptions.MaxWidth, appoptions.MaxHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Windows != nil {
|
if appoptions.Windows != nil {
|
||||||
if options.Windows.WindowIsTranslucent {
|
if appoptions.Windows.WindowIsTranslucent {
|
||||||
result.SetTranslucentBackground()
|
result.SetTranslucentBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Windows.DisableWindowIcon {
|
if appoptions.Windows.DisableWindowIcon {
|
||||||
result.DisableIcon()
|
result.DisableIcon()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,8 +78,8 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
|
|||||||
|
|
||||||
result.SetFont(winc.DefaultFont)
|
result.SetFont(winc.DefaultFont)
|
||||||
|
|
||||||
if options.Menu != nil {
|
if appoptions.Menu != nil {
|
||||||
result.SetApplicationMenu(options.Menu)
|
result.SetApplicationMenu(appoptions.Menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ type MessageDialogOptions struct {
|
|||||||
Buttons []string
|
Buttons []string
|
||||||
DefaultButton string
|
DefaultButton string
|
||||||
CancelButton string
|
CancelButton string
|
||||||
Icon string
|
Icon []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Frontend interface {
|
type Frontend interface {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package gomod
|
package gomod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Masterminds/semver"
|
|
||||||
"github.com/matryer/is"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/matryer/is"
|
||||||
)
|
)
|
||||||
|
|
||||||
const basic string = `module changeme
|
const basic string = `module changeme
|
||||||
@@ -75,7 +76,7 @@ const basicUpdated string = `module changeme
|
|||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
require github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||||
@@ -330,7 +331,7 @@ const multilineRequireUpdated = `module changeme
|
|||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -381,12 +382,12 @@ func TestUpdateGoModVersion(t *testing.T) {
|
|||||||
want []byte
|
want []byte
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, []byte(basicUpdated), false},
|
{"basic", args{[]byte(basic), "v2.0.0-beta.20"}, []byte(basicUpdated), false},
|
||||||
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, []byte(multilineRequireUpdated), false},
|
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.20"}, []byte(multilineRequireUpdated), false},
|
||||||
{"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.15"}, []byte(multilineReplaceUpdated), false},
|
{"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.20"}, []byte(multilineReplaceUpdated), false},
|
||||||
{"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceBlockUpdated), false},
|
{"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.20"}, []byte(multilineReplaceBlockUpdated), false},
|
||||||
{"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionUpdated), false},
|
{"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.20"}, []byte(multilineReplaceNoVersionUpdated), false},
|
||||||
{"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionBlockUpdated), false},
|
{"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.20"}, []byte(multilineReplaceNoVersionBlockUpdated), false},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -413,8 +414,8 @@ func TestGoModOutOfSync(t *testing.T) {
|
|||||||
want bool
|
want bool
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, true, false},
|
{"basic", args{[]byte(basic), "v2.0.0-beta.20"}, true, false},
|
||||||
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, true, false},
|
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.20"}, true, false},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -433,7 +434,7 @@ const multilineReplaceUpdated = `module changeme
|
|||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -468,14 +469,14 @@ require (
|
|||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
replace github.com/wailsapp/wails/v2 v2.0.0-beta.20 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||||
`
|
`
|
||||||
const multilineReplaceNoVersionUpdated = `module changeme
|
const multilineReplaceNoVersionUpdated = `module changeme
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -517,7 +518,7 @@ const multilineReplaceNoVersionBlockUpdated = `module changeme
|
|||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -562,7 +563,7 @@ const multilineReplaceBlockUpdated = `module changeme
|
|||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -598,6 +599,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
github.com/wailsapp/wails/v2 v2.0.0-beta.20 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package menumanager
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ type Project struct {
|
|||||||
|
|
||||||
// The url to use to server assets. Default "https://localhost:34115"
|
// The url to use to server assets. Default "https://localhost:34115"
|
||||||
DevServerURL string `json:"devserverurl"`
|
DevServerURL string `json:"devserverurl"`
|
||||||
|
|
||||||
|
// Arguments that are forwared to the application in dev mode
|
||||||
|
AppArgs string `json:"appargs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Project) Save() error {
|
func (p *Project) Save() error {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.
|
|||||||
|
|
||||||
result := &Manager{
|
result := &Manager{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
logger: logger.CustomLogger("Event Manager"),
|
logger: logger.CustomLogger("Signal Manager"),
|
||||||
signalchannel: make(chan os.Signal, 2),
|
signalchannel: make(chan os.Signal, 2),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
@@ -49,7 +49,7 @@ func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.
|
|||||||
func (m *Manager) Start() {
|
func (m *Manager) Start() {
|
||||||
|
|
||||||
// Hook into interrupts
|
// Hook into interrupts
|
||||||
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM)
|
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
|
||||||
m.wg.Add(1)
|
m.wg.Add(1)
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package buildassets
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/leaanthony/debme"
|
|
||||||
"github.com/leaanthony/gosod"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/leaanthony/debme"
|
||||||
|
"github.com/leaanthony/gosod"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed build
|
//go:embed build
|
||||||
@@ -50,3 +51,17 @@ func RegenerateAppIcon(target string) error {
|
|||||||
}
|
}
|
||||||
return a.CopyFile("appicon.png", target, 0644)
|
return a.CopyFile("appicon.png", target, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegeneratePlist(targetDir string, projectName string) error {
|
||||||
|
darwinAssets, err := debme.FS(assets, "build/darwin")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templateDir := gosod.New(darwinAssets)
|
||||||
|
err = templateDir.Extract(targetDir, &assetData{Name: projectName})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ package build
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/leaanthony/gosod"
|
|
||||||
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -13,6 +10,10 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leaanthony/gosod"
|
||||||
|
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
@@ -215,8 +216,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
commands.Add(`"all=-N -l"`)
|
commands.Add(`"all=-N -l"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
//commands.Add("-a")
|
|
||||||
|
|
||||||
var tags slicer.StringSlicer
|
var tags slicer.StringSlicer
|
||||||
tags.Add(options.OutputType)
|
tags.Add(options.OutputType)
|
||||||
tags.AddSlice(options.UserTags)
|
tags.AddSlice(options.UserTags)
|
||||||
@@ -299,7 +298,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
if v != "" {
|
if v != "" {
|
||||||
v += " "
|
v += " "
|
||||||
}
|
}
|
||||||
v += "-I" + buildBaseDir
|
v += "-mmacosx-version-min=10.13"
|
||||||
return v
|
return v
|
||||||
})
|
})
|
||||||
// Use upsertEnv so we don't overwrite user's CGO_CXXFLAGS
|
// Use upsertEnv so we don't overwrite user's CGO_CXXFLAGS
|
||||||
@@ -314,6 +313,17 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
cmd.Env = upsertEnv(cmd.Env, "CGO_ENABLED", func(v string) string {
|
cmd.Env = upsertEnv(cmd.Env, "CGO_ENABLED", func(v string) string {
|
||||||
return "1"
|
return "1"
|
||||||
})
|
})
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
// Set the minimum Mac SDK to 10.13
|
||||||
|
cmd.Env = upsertEnv(cmd.Env, "CGO_LDFLAGS", func(v string) string {
|
||||||
|
if v != "" {
|
||||||
|
v += " "
|
||||||
|
}
|
||||||
|
v += "-mmacosx-version-min=10.13"
|
||||||
|
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Env = upsertEnv(cmd.Env, "GOOS", func(v string) string {
|
cmd.Env = upsertEnv(cmd.Env, "GOOS", func(v string) string {
|
||||||
@@ -337,8 +347,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Done.")
|
|
||||||
|
|
||||||
if !options.Compress {
|
if !options.Compress {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -524,6 +532,9 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
|
|||||||
switch b.projectData.OutputType {
|
switch b.projectData.OutputType {
|
||||||
case "dev":
|
case "dev":
|
||||||
buildCommand = b.projectData.DevCommand
|
buildCommand = b.projectData.DevCommand
|
||||||
|
if buildCommand == "" {
|
||||||
|
buildCommand = b.projectData.BuildCommand
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
buildCommand = b.projectData.BuildCommand
|
buildCommand = b.projectData.BuildCommand
|
||||||
}
|
}
|
||||||
@@ -534,10 +545,10 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
outputLogger.Print("Compiling frontend: ")
|
outputLogger.Print("Compiling frontend: ")
|
||||||
cmd := strings.Split(b.projectData.BuildCommand, " ")
|
cmd := strings.Split(buildCommand, " ")
|
||||||
if verbose {
|
if verbose {
|
||||||
outputLogger.Println("")
|
outputLogger.Println("")
|
||||||
outputLogger.Println(" Build command: '" + strings.Join(cmd, " ") + "'")
|
outputLogger.Println(" Build command: '" + buildCommand + "'")
|
||||||
}
|
}
|
||||||
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
|
||||||
if verbose || err != nil {
|
if verbose || err != nil {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
|
|
||||||
@@ -111,17 +112,11 @@ func Build(options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the base assets
|
|
||||||
//err = builder.BuildAssets(options)
|
|
||||||
//if err != nil {
|
|
||||||
// return "", err
|
|
||||||
//}
|
|
||||||
|
|
||||||
// If we are building for windows, we will need to generate the asset bundle before
|
// If we are building for windows, we will need to generate the asset bundle before
|
||||||
// compilation. This will be a .syso file in the project root
|
// compilation. This will be a .syso file in the project root
|
||||||
if options.Pack && options.Platform == "windows" {
|
if options.Pack && options.Platform == "windows" {
|
||||||
outputLogger.Print("Generating bundle assets: ")
|
outputLogger.Print("Generating bundle assets: ")
|
||||||
err := packageApplication(options)
|
err := packageApplicationForWindows(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -149,10 +144,10 @@ func Build(options *Options) (string, error) {
|
|||||||
options.OutputFile = amd64Filename
|
options.OutputFile = amd64Filename
|
||||||
options.CleanBuildDirectory = false
|
options.CleanBuildDirectory = false
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
println()
|
outputLogger.Println("\nBuilding AMD64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
|
||||||
println(" Building AMD64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
|
|
||||||
}
|
}
|
||||||
err = builder.CompileProject(options)
|
err = builder.CompileProject(options)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -161,15 +156,16 @@ func Build(options *Options) (string, error) {
|
|||||||
options.OutputFile = arm64Filename
|
options.OutputFile = arm64Filename
|
||||||
options.CleanBuildDirectory = false
|
options.CleanBuildDirectory = false
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
println(" Building ARM64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
|
outputLogger.Println("Building ARM64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
|
||||||
}
|
}
|
||||||
err = builder.CompileProject(options)
|
err = builder.CompileProject(options)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Run lipo
|
// Run lipo
|
||||||
if options.Verbosity == VERBOSE {
|
if options.Verbosity == VERBOSE {
|
||||||
println(" Running lipo: ", "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
outputLogger.Println(" Running lipo: ", "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
||||||
}
|
}
|
||||||
_, stderr, err := shell.RunCommand(options.BuildDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
_, stderr, err := shell.RunCommand(options.BuildDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -193,6 +189,8 @@ func Build(options *Options) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outputLogger.Println("Done.")
|
||||||
|
|
||||||
// Do we need to pack the app for non-windows?
|
// Do we need to pack the app for non-windows?
|
||||||
if options.Pack && options.Platform != "windows" {
|
if options.Pack && options.Platform != "windows" {
|
||||||
|
|
||||||
@@ -212,6 +210,18 @@ func Build(options *Options) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.CompiledBinary, nil
|
result := options.CompiledBinary
|
||||||
|
|
||||||
|
if options.Pack && options.Platform == "darwin" {
|
||||||
|
sr := strings.Split(result, "/")
|
||||||
|
for i := len(sr) - 1; i >= 0; i-- {
|
||||||
|
if strings.Contains(sr[i], ".app") {
|
||||||
|
result = strings.Join(sr[:i+1], "/")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,19 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/leaanthony/winicon"
|
||||||
|
"github.com/tc-hib/winres"
|
||||||
|
|
||||||
|
"github.com/jackmordaunt/icns"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
"github.com/wailsapp/wails/v2/internal/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,8 +23,10 @@ func packageProject(options *Options, platform string) error {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch platform {
|
switch platform {
|
||||||
case "darwin", "windows":
|
case "darwin":
|
||||||
err = packageApplication(options)
|
err = packageApplicationForDarwin(options)
|
||||||
|
case "windows":
|
||||||
|
err = packageApplicationForWindows(options)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("packing not supported for %s yet", platform)
|
err = fmt.Errorf("packing not supported for %s yet", platform)
|
||||||
}
|
}
|
||||||
@@ -65,3 +76,225 @@ func getBuildBaseDirectory(options *Options) (string, error) {
|
|||||||
func getPackageAssetsDirectory() string {
|
func getPackageAssetsDirectory() string {
|
||||||
return fs.RelativePath("internal/packager", runtime.GOOS)
|
return fs.RelativePath("internal/packager", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func packageApplicationForDarwin(options *Options) error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Create directory structure
|
||||||
|
bundlename := options.ProjectData.Name + ".app"
|
||||||
|
|
||||||
|
contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents")
|
||||||
|
exeDir := filepath.Join(contentsDirectory, "/MacOS")
|
||||||
|
err = fs.MkDirs(exeDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resourceDir := filepath.Join(contentsDirectory, "/Resources")
|
||||||
|
err = fs.MkDirs(resourceDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Copy binary
|
||||||
|
packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name)
|
||||||
|
err = fs.MoveFile(options.CompiledBinary, packedBinaryPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Cannot move file: "+options.ProjectData.OutputFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Info.plist
|
||||||
|
err = processPList(options, contentsDirectory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Icons
|
||||||
|
err = processApplicationIcon(resourceDir, options.ProjectData.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
options.CompiledBinary = packedBinaryPath
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processPList(options *Options, contentsDirectory string) error {
|
||||||
|
|
||||||
|
// Check if plist already exists in project dir
|
||||||
|
plistFileDir := filepath.Join(options.ProjectData.Path, "build", "darwin")
|
||||||
|
plistFile := filepath.Join(plistFileDir, "Info.plist")
|
||||||
|
// If the file doesn't exist, generate it
|
||||||
|
if !fs.FileExists(plistFile) {
|
||||||
|
err := buildassets.RegeneratePlist(plistFileDir, options.ProjectData.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy it to the contents directory
|
||||||
|
targetFile := filepath.Join(contentsDirectory, "Info.plist")
|
||||||
|
return fs.CopyFile(plistFile, targetFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
|
||||||
|
|
||||||
|
appIcon := filepath.Join(iconsDir, "appicon.png")
|
||||||
|
|
||||||
|
// Install default icon if one doesn't exist
|
||||||
|
if !fs.FileExists(appIcon) {
|
||||||
|
// No - Install default icon
|
||||||
|
err = buildassets.RegenerateAppIcon(appIcon)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tgtBundle := path.Join(resourceDir, "iconfile.icns")
|
||||||
|
imageFile, err := os.Open(appIcon)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err = imageFile.Close()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
srcImg, _, err := image.Decode(imageFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
dest, err := os.Create(tgtBundle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
err = dest.Close()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return icns.Encode(dest, srcImg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func packageApplicationForWindows(options *Options) error {
|
||||||
|
// Generate icon
|
||||||
|
var err error
|
||||||
|
err = generateIcoFile(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure Manifest is present
|
||||||
|
err = generateManifest(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create syso file
|
||||||
|
err = compileResources(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateManifest(options *Options) error {
|
||||||
|
filename := options.ProjectData.Name + ".exe.manifest"
|
||||||
|
manifestFile := filepath.Join(options.ProjectData.Path, "build", "windows", filename)
|
||||||
|
if !fs.FileExists(manifestFile) {
|
||||||
|
return buildassets.RegenerateManifest(manifestFile)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateIcoFile(options *Options) error {
|
||||||
|
// Check ico file exists already
|
||||||
|
icoFile := filepath.Join(options.ProjectData.Path, "build", "windows", "icon.ico")
|
||||||
|
if !fs.FileExists(icoFile) {
|
||||||
|
// Check icon exists
|
||||||
|
appicon := filepath.Join(options.ProjectData.Path, "build", "appicon.png")
|
||||||
|
if !fs.FileExists(appicon) {
|
||||||
|
return fmt.Errorf("application icon missing: %s", appicon)
|
||||||
|
}
|
||||||
|
// Load icon
|
||||||
|
input, err := os.Open(appicon)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
output, err := os.OpenFile(icoFile, os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = winicon.GenerateIcon(input, output, []int{256, 128, 64, 48, 32, 16})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileResources(options *Options) error {
|
||||||
|
|
||||||
|
currentDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
os.Chdir(currentDir)
|
||||||
|
}()
|
||||||
|
windowsDir := filepath.Join(options.ProjectData.Path, "build", "windows")
|
||||||
|
err = os.Chdir(windowsDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs := winres.ResourceSet{}
|
||||||
|
icon := filepath.Join(windowsDir, "icon.ico")
|
||||||
|
iconFile, err := os.Open(icon)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer iconFile.Close()
|
||||||
|
ico, err := winres.LoadICO(iconFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = rs.SetIcon(winres.RT_ICON, ico)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ManifestFilename := options.ProjectData.Name + ".exe.manifest"
|
||||||
|
manifestData, err := os.ReadFile(ManifestFilename)
|
||||||
|
xmlData, err := winres.AppManifestFromXML(manifestData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.SetManifest(xmlData)
|
||||||
|
|
||||||
|
targetFile := filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso")
|
||||||
|
fout, err := os.Create(targetFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fout.Close()
|
||||||
|
|
||||||
|
archs := map[string]winres.Arch{
|
||||||
|
"amd64": winres.ArchAMD64,
|
||||||
|
}
|
||||||
|
targetArch, supported := archs[options.Arch]
|
||||||
|
if !supported {
|
||||||
|
return fmt.Errorf("arch '%s' not supported", options.Arch)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rs.WriteObject(fout, targetArch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"image"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
|
||||||
|
|
||||||
"github.com/jackmordaunt/icns"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
func packageApplication(options *Options) error {
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Create directory structure
|
|
||||||
bundlename := options.ProjectData.Name + ".app"
|
|
||||||
|
|
||||||
contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents")
|
|
||||||
exeDir := filepath.Join(contentsDirectory, "/MacOS")
|
|
||||||
err = fs.MkDirs(exeDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resourceDir := filepath.Join(contentsDirectory, "/Resources")
|
|
||||||
err = fs.MkDirs(resourceDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Copy binary
|
|
||||||
packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name)
|
|
||||||
err = fs.MoveFile(options.CompiledBinary, packedBinaryPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Cannot move file: "+options.ProjectData.OutputFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate Info.plist
|
|
||||||
err = processPList(options, contentsDirectory)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate Icons
|
|
||||||
err = processApplicationIcon(resourceDir, options.ProjectData.BuildDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
options.CompiledBinary = packedBinaryPath
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func processPList(options *Options, contentsDirectory string) error {
|
|
||||||
|
|
||||||
// Check if plist already exists in project dir
|
|
||||||
plistFile := filepath.Join(options.ProjectData.BuildDir, "darwin", "Info.plist")
|
|
||||||
|
|
||||||
// If the file doesn't exist, generate it
|
|
||||||
if !fs.FileExists(plistFile) {
|
|
||||||
err := generateDefaultPlist(options, plistFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy it to the contents directory
|
|
||||||
targetFile := filepath.Join(contentsDirectory, "Info.plist")
|
|
||||||
return fs.CopyFile(plistFile, targetFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateDefaultPlist(options *Options, targetPlistFile string) error {
|
|
||||||
name := defaultString(options.ProjectData.Name, "WailsTest")
|
|
||||||
exe := defaultString(options.OutputFile, name)
|
|
||||||
version := "1.0.0"
|
|
||||||
author := defaultString(options.ProjectData.Author.Name, "Anonymous")
|
|
||||||
packageID := strings.Join([]string{"wails", name}, ".")
|
|
||||||
plistData := newPlistData(name, exe, packageID, version, author)
|
|
||||||
|
|
||||||
tmpl := template.New("infoPlist")
|
|
||||||
plistTemplate := fs.RelativePath("./internal/packager/darwin/Info.plist")
|
|
||||||
infoPlist, err := ioutil.ReadFile(plistTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "Cannot open plist template")
|
|
||||||
}
|
|
||||||
_, err = tmpl.Parse(string(infoPlist))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Write the template to a buffer
|
|
||||||
var tpl bytes.Buffer
|
|
||||||
err = tmpl.Execute(&tpl, plistData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the directory if it doesn't exist
|
|
||||||
err = fs.MkDirs(filepath.Dir(targetPlistFile))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Save the file
|
|
||||||
return ioutil.WriteFile(targetPlistFile, tpl.Bytes(), 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultString(val string, defaultVal string) string {
|
|
||||||
if val != "" {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return defaultVal
|
|
||||||
}
|
|
||||||
|
|
||||||
type plistData struct {
|
|
||||||
Title string
|
|
||||||
Exe string
|
|
||||||
PackageID string
|
|
||||||
Version string
|
|
||||||
Author string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPlistData(title, exe, packageID, version, author string) *plistData {
|
|
||||||
return &plistData{
|
|
||||||
Title: title,
|
|
||||||
Exe: exe,
|
|
||||||
Version: version,
|
|
||||||
PackageID: packageID,
|
|
||||||
Author: author,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
|
|
||||||
|
|
||||||
appIcon := filepath.Join(iconsDir, "appicon.png")
|
|
||||||
|
|
||||||
// Install default icon if one doesn't exist
|
|
||||||
if !fs.FileExists(appIcon) {
|
|
||||||
// No - Install default icon
|
|
||||||
err = buildassets.RegenerateAppIcon(appIcon)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tgtBundle := path.Join(resourceDir, "iconfile.icns")
|
|
||||||
imageFile, err := os.Open(appIcon)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err = imageFile.Close()
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
srcImg, _, err := image.Decode(imageFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
|
|
||||||
}
|
|
||||||
dest, err := os.Create(tgtBundle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = dest.Close()
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return icns.Encode(dest, srcImg)
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/leaanthony/winicon"
|
|
||||||
"github.com/tc-hib/winres"
|
|
||||||
"github.com/wailsapp/wails/v2/internal/fs"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/buildassets"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func packageApplication(options *Options) error {
|
|
||||||
// Generate icon
|
|
||||||
var err error
|
|
||||||
err = generateIcoFile(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure Manifest is present
|
|
||||||
err = generateManifest(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create syso file
|
|
||||||
err = compileResources(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateManifest(options *Options) error {
|
|
||||||
filename := options.ProjectData.Name + ".exe.manifest"
|
|
||||||
manifestFile := filepath.Join(options.ProjectData.Path, "build", "windows", filename)
|
|
||||||
if !fs.FileExists(manifestFile) {
|
|
||||||
return buildassets.RegenerateManifest(manifestFile)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateIcoFile(options *Options) error {
|
|
||||||
// Check ico file exists already
|
|
||||||
icoFile := filepath.Join(options.ProjectData.Path, "build", "windows", "icon.ico")
|
|
||||||
if !fs.FileExists(icoFile) {
|
|
||||||
// Check icon exists
|
|
||||||
appicon := filepath.Join(options.ProjectData.Path, "build", "appicon.png")
|
|
||||||
if !fs.FileExists(appicon) {
|
|
||||||
return fmt.Errorf("application icon missing: %s", appicon)
|
|
||||||
}
|
|
||||||
// Load icon
|
|
||||||
input, err := os.Open(appicon)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
output, err := os.OpenFile(icoFile, os.O_CREATE, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = winicon.GenerateIcon(input, output, []int{256, 128, 64, 48, 32, 16})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compileResources(options *Options) error {
|
|
||||||
|
|
||||||
currentDir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
os.Chdir(currentDir)
|
|
||||||
}()
|
|
||||||
windowsDir := filepath.Join(options.ProjectData.Path, "build", "windows")
|
|
||||||
err = os.Chdir(windowsDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rs := winres.ResourceSet{}
|
|
||||||
icon := filepath.Join(windowsDir, "icon.ico")
|
|
||||||
iconFile, err := os.Open(icon)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer iconFile.Close()
|
|
||||||
ico, err := winres.LoadICO(iconFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = rs.SetIcon(winres.RT_ICON, ico)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ManifestFilename := options.ProjectData.Name + ".exe.manifest"
|
|
||||||
manifestData, err := os.ReadFile(ManifestFilename)
|
|
||||||
xmlData, err := winres.AppManifestFromXML(manifestData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rs.SetManifest(xmlData)
|
|
||||||
|
|
||||||
targetFile := filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso")
|
|
||||||
fout, err := os.Create(targetFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer fout.Close()
|
|
||||||
|
|
||||||
archs := map[string]winres.Arch{
|
|
||||||
"amd64": winres.ArchAMD64,
|
|
||||||
}
|
|
||||||
targetArch, supported := archs[options.Arch]
|
|
||||||
if !supported {
|
|
||||||
return fmt.Errorf("arch '%s' not supported", options.Arch)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rs.WriteObject(fout, targetArch)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
26
v2/pkg/menu/keys/macmodifiers.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package keys
|
||||||
|
|
||||||
|
const (
|
||||||
|
NSEventModifierFlagShift = 1 << 17 // Set if Shift key is pressed.
|
||||||
|
NSEventModifierFlagControl = 1 << 18 // Set if Control key is pressed.
|
||||||
|
NSEventModifierFlagOption = 1 << 19 // Set if Option or Alternate key is pressed.
|
||||||
|
NSEventModifierFlagCommand = 1 << 20 // Set if Command key is pressed.
|
||||||
|
)
|
||||||
|
|
||||||
|
var macModifierMap = map[Modifier]int{
|
||||||
|
CmdOrCtrlKey: NSEventModifierFlagCommand,
|
||||||
|
ControlKey: NSEventModifierFlagControl,
|
||||||
|
OptionOrAltKey: NSEventModifierFlagOption,
|
||||||
|
ShiftKey: NSEventModifierFlagShift,
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToMacModifier(accelerator *Accelerator) int {
|
||||||
|
if accelerator == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
result := 0
|
||||||
|
for _, modifier := range accelerator.Modifiers {
|
||||||
|
result |= macModifierMap[modifier]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
31
v2/pkg/menu/keys/macmodifiers_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package keys
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestToMacModifier(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
accelerator *Accelerator
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
{"nil", nil, 0},
|
||||||
|
{"empty", &Accelerator{}, 0},
|
||||||
|
{"key", &Accelerator{Key: "p"}, 0},
|
||||||
|
{"cmd", CmdOrCtrl(""), NSEventModifierFlagCommand},
|
||||||
|
{"ctrl", Control(""), NSEventModifierFlagControl},
|
||||||
|
{"shift", Shift(""), NSEventModifierFlagShift},
|
||||||
|
{"option", OptionOrAlt(""), NSEventModifierFlagOption},
|
||||||
|
{"cmd+ctrl", Combo("", CmdOrCtrlKey, ControlKey), NSEventModifierFlagCommand | NSEventModifierFlagControl},
|
||||||
|
{"cmd+ctrl+shift", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift},
|
||||||
|
{"cmd+ctrl+shift+option", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey, OptionOrAltKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift | NSEventModifierFlagOption},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ToMacModifier(tt.accelerator); got != tt.want {
|
||||||
|
t.Errorf("ToMacModifier() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,9 +11,9 @@ type MenuItem struct {
|
|||||||
// Label is what appears as the menu text
|
// Label is what appears as the menu text
|
||||||
Label string
|
Label string
|
||||||
// Role is a predefined menu type
|
// Role is a predefined menu type
|
||||||
//Role Role `json:"Role,omitempty"`
|
Role Role
|
||||||
// Accelerator holds a representation of a key binding
|
// Accelerator holds a representation of a key binding
|
||||||
Accelerator *keys.Accelerator `json:"Accelerator,omitempty"`
|
Accelerator *keys.Accelerator
|
||||||
// Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu
|
// Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu
|
||||||
Type Type
|
Type Type
|
||||||
// Disabled makes the item unselectable
|
// Disabled makes the item unselectable
|
||||||
@@ -24,10 +24,10 @@ type MenuItem struct {
|
|||||||
Checked bool
|
Checked bool
|
||||||
// Submenu contains a list of menu items that will be shown as a submenu
|
// Submenu contains a list of menu items that will be shown as a submenu
|
||||||
//SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
//SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
||||||
SubMenu *Menu `json:"SubMenu,omitempty"`
|
SubMenu *Menu
|
||||||
|
|
||||||
// Callback function when menu clicked
|
// Callback function when menu clicked
|
||||||
Click Callback `json:"-"`
|
Click Callback
|
||||||
/*
|
/*
|
||||||
// Text Colour
|
// Text Colour
|
||||||
RGBA string
|
RGBA string
|
||||||
@@ -267,16 +267,3 @@ func SubMenu(label string, menu *Menu) *MenuItem {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubMenuWithID is a helper to create Submenus with an ID
|
|
||||||
func SubMenuWithID(label string, menu *Menu) *MenuItem {
|
|
||||||
result := &MenuItem{
|
|
||||||
Label: label,
|
|
||||||
SubMenu: menu,
|
|
||||||
Type: SubmenuType,
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.setParent(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,37 +3,39 @@
|
|||||||
// Electron License: https://github.com/electron/electron/blob/master/LICENSE
|
// Electron License: https://github.com/electron/electron/blob/master/LICENSE
|
||||||
package menu
|
package menu
|
||||||
|
|
||||||
/*
|
// Role is a type to identify menu roles
|
||||||
type Role string
|
type Role int
|
||||||
|
|
||||||
|
// These constants need to be kept in sync with `v2/internal/frontend/desktop/darwin/Role.h`
|
||||||
const (
|
const (
|
||||||
AboutRole Role = "about"
|
AppMenuRole Role = 1
|
||||||
UndoRole Role = "undo"
|
EditMenuRole = 2
|
||||||
RedoRole Role = "redo"
|
//AboutRole Role = "about"
|
||||||
CutRole Role = "cut"
|
//UndoRole Role = "undo"
|
||||||
CopyRole Role = "copy"
|
//RedoRole Role = "redo"
|
||||||
PasteRole Role = "paste"
|
//CutRole Role = "cut"
|
||||||
PasteAndMatchStyleRole Role = "pasteAndMatchStyle"
|
//CopyRole Role = "copy"
|
||||||
SelectAllRole Role = "selectAll"
|
//PasteRole Role = "paste"
|
||||||
DeleteRole Role = "delete"
|
//PasteAndMatchStyleRole Role = "pasteAndMatchStyle"
|
||||||
MinimizeRole Role = "minimize"
|
//SelectAllRole Role = "selectAll"
|
||||||
QuitRole Role = "quit"
|
//DeleteRole Role = "delete"
|
||||||
TogglefullscreenRole Role = "togglefullscreen"
|
//MinimizeRole Role = "minimize"
|
||||||
FileMenuRole Role = "fileMenu"
|
//QuitRole Role = "quit"
|
||||||
EditMenuRole Role = "editMenu"
|
//TogglefullscreenRole Role = "togglefullscreen"
|
||||||
ViewMenuRole Role = "viewMenu"
|
//FileMenuRole Role = "fileMenu"
|
||||||
WindowMenuRole Role = "windowMenu"
|
//ViewMenuRole Role = "viewMenu"
|
||||||
AppMenuRole Role = "appMenu"
|
//WindowMenuRole Role = "windowMenu"
|
||||||
HideRole Role = "hide"
|
//HideRole Role = "hide"
|
||||||
HideOthersRole Role = "hideOthers"
|
//HideOthersRole Role = "hideOthers"
|
||||||
UnhideRole Role = "unhide"
|
//UnhideRole Role = "unhide"
|
||||||
FrontRole Role = "front"
|
//FrontRole Role = "front"
|
||||||
ZoomRole Role = "zoom"
|
//ZoomRole Role = "zoom"
|
||||||
WindowSubMenuRole Role = "windowSubMenu"
|
//WindowSubMenuRole Role = "windowSubMenu"
|
||||||
HelpSubMenuRole Role = "helpSubMenu"
|
//HelpSubMenuRole Role = "helpSubMenu"
|
||||||
SeparatorItemRole Role = "separatorItem"
|
//SeparatorItemRole Role = "separatorItem"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
// About provides a MenuItem with the About role
|
// About provides a MenuItem with the About role
|
||||||
func About() *MenuItem {
|
func About() *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
@@ -111,8 +113,8 @@ func Quit() *MenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Togglefullscreen provides a MenuItem with the Togglefullscreen role
|
// ToggleFullscreen provides a MenuItem with the ToggleFullscreen role
|
||||||
func Togglefullscreen() *MenuItem {
|
func ToggleFullscreen() *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
Role: TogglefullscreenRole,
|
Role: TogglefullscreenRole,
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,7 @@ func FileMenu() *MenuItem {
|
|||||||
Role: FileMenuRole,
|
Role: FileMenuRole,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// EditMenu provides a MenuItem with the whole default "Edit" menu (Undo, Copy, etc.).
|
// EditMenu provides a MenuItem with the whole default "Edit" menu (Undo, Copy, etc.).
|
||||||
func EditMenu() *MenuItem {
|
func EditMenu() *MenuItem {
|
||||||
@@ -132,6 +135,7 @@ func EditMenu() *MenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// ViewMenu provides a MenuItem with the whole default "View" menu (Reload, Toggle Developer Tools, etc.)
|
// ViewMenu provides a MenuItem with the whole default "View" menu (Reload, Toggle Developer Tools, etc.)
|
||||||
func ViewMenu() *MenuItem {
|
func ViewMenu() *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
@@ -145,7 +149,7 @@ func WindowMenu() *MenuItem {
|
|||||||
Role: WindowMenuRole,
|
Role: WindowMenuRole,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// These roles are Mac only
|
// These roles are Mac only
|
||||||
|
|
||||||
// AppMenu provides a MenuItem with the whole default "App" menu (About, Services, etc.)
|
// AppMenu provides a MenuItem with the whole default "App" menu (About, Services, etc.)
|
||||||
@@ -155,6 +159,7 @@ func AppMenu() *MenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Hide provides a MenuItem that maps to the hide action.
|
// Hide provides a MenuItem that maps to the hide action.
|
||||||
func Hide() *MenuItem {
|
func Hide() *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
@@ -169,8 +174,8 @@ func HideOthers() *MenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unhide provides a MenuItem that maps to the unhideAllApplications action.
|
// UnHide provides a MenuItem that maps to the unHideAllApplications action.
|
||||||
func Unhide() *MenuItem {
|
func UnHide() *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
Role: UnhideRole,
|
Role: UnhideRole,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package options
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default options for creating the App
|
// Default options for creating the App
|
||||||
@@ -11,3 +12,8 @@ var Default = &App{
|
|||||||
Logger: logger.NewDefaultLogger(),
|
Logger: logger.NewDefaultLogger(),
|
||||||
LogLevel: logger.INFO,
|
LogLevel: logger.INFO,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultMacMenu = menu.NewMenuFromItems(
|
||||||
|
menu.AppMenu(),
|
||||||
|
menu.EditMenu(),
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
package mac
|
package mac
|
||||||
|
|
||||||
type ActivationPolicy int
|
//type ActivationPolicy int
|
||||||
|
//
|
||||||
|
//const (
|
||||||
|
// NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
||||||
|
// NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
||||||
|
// NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
||||||
|
//)
|
||||||
|
|
||||||
const (
|
type AboutInfo struct {
|
||||||
NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
Title string
|
||||||
NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
Message string
|
||||||
NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
Icon []byte
|
||||||
)
|
}
|
||||||
|
|
||||||
// Options are options specific to Mac
|
// Options are options specific to Mac
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@@ -14,6 +20,7 @@ type Options struct {
|
|||||||
Appearance AppearanceType
|
Appearance AppearanceType
|
||||||
WebviewIsTransparent bool
|
WebviewIsTransparent bool
|
||||||
WindowIsTranslucent bool
|
WindowIsTranslucent bool
|
||||||
ActivationPolicy ActivationPolicy
|
//ActivationPolicy ActivationPolicy
|
||||||
|
About *AboutInfo
|
||||||
//URLHandlers map[string]func(string)
|
//URLHandlers map[string]func(string)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"log"
|
"log"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||||
@@ -14,6 +15,15 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type WindowStartState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Normal WindowStartState = 0
|
||||||
|
Maximised WindowStartState = 1
|
||||||
|
Minimised WindowStartState = 2
|
||||||
|
Fullscreen WindowStartState = 3
|
||||||
|
)
|
||||||
|
|
||||||
// App contains options for creating the App
|
// App contains options for creating the App
|
||||||
type App struct {
|
type App struct {
|
||||||
Title string
|
Title string
|
||||||
@@ -38,6 +48,7 @@ type App struct {
|
|||||||
OnDomReady func(ctx context.Context) `json:"-"`
|
OnDomReady func(ctx context.Context) `json:"-"`
|
||||||
OnShutdown func(ctx context.Context) `json:"-"`
|
OnShutdown func(ctx context.Context) `json:"-"`
|
||||||
Bind []interface{}
|
Bind []interface{}
|
||||||
|
WindowStartState WindowStartState
|
||||||
|
|
||||||
//ContextMenus []*menu.ContextMenu
|
//ContextMenus []*menu.ContextMenu
|
||||||
//TrayMenus []*menu.TrayMenu
|
//TrayMenus []*menu.TrayMenu
|
||||||
@@ -94,4 +105,11 @@ func MergeDefaults(appoptions *App) {
|
|||||||
appoptions.Height = appoptions.MaxHeight
|
appoptions.Height = appoptions.MaxHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
if appoptions.Menu == nil {
|
||||||
|
appoptions.Menu = defaultMacMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
161
website/blog/2021-11-08-v2-beta2-release-notes.mdx
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
---
|
||||||
|
slug: wails-v2-beta-for-mac
|
||||||
|
title: Wails v2 Beta for MacOS
|
||||||
|
authors: [leaanthony]
|
||||||
|
tags: [wails, v2]
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/wails-mac.png" width="60%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Today marks the first beta release of Wails v2 for Mac! It's taken quite a while to get to this point and I'm hoping
|
||||||
|
that today's release will give you something that's reasonably useful. There have been a number of twists and turns
|
||||||
|
to get to this point and I'm hoping, with your help, to iron out the crinkles and get the Mac port polished for the
|
||||||
|
final v2 release.
|
||||||
|
|
||||||
|
You mean this isn't ready for production? For your use case, it may well be ready, but there are still a number of
|
||||||
|
known issues so keep your eye on [this project board](https://github.com/wailsapp/wails/projects/7) and if you would
|
||||||
|
like to contribute, you'd be very welcome!
|
||||||
|
|
||||||
|
So what's new for Wails v2 for Mac vs v1? Hint: It's pretty similar to the Windows Beta :wink:
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/wails-menus-mac.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
There were a lot of requests for native menu support. Wails has finally got you covered. Application menus are now available
|
||||||
|
and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus
|
||||||
|
and separators.
|
||||||
|
|
||||||
|
There were a huge number of requests in v1 for the ability to have greater control of the window itself.
|
||||||
|
I'm happy to announce that there's new runtime APIs specifically for this.
|
||||||
|
It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native
|
||||||
|
dialogs with rich configuration to cater for all your dialog needs.
|
||||||
|
|
||||||
|
### Mac Specific Options
|
||||||
|
|
||||||
|
In addition to the normal application options, Wails v2 for Mac also brings some Mac extras:
|
||||||
|
|
||||||
|
- Make your window all funky and translucent, like all the pretty swift apps!
|
||||||
|
- Highly customisable titlebar
|
||||||
|
- We support the NSAppearance options for the application
|
||||||
|
- Simple config to auto-create an "About" menu
|
||||||
|
|
||||||
|
### No requirement to bundle assets
|
||||||
|
|
||||||
|
A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to
|
||||||
|
announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an
|
||||||
|
`<img>` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS.
|
||||||
|
|
||||||
|
> Wow, that sounds like a webserver...
|
||||||
|
|
||||||
|
Yes, it works just like a webserver, except it isn't.
|
||||||
|
|
||||||
|
> So how do I include my assets?
|
||||||
|
|
||||||
|
You just pass a single `embed.FS` that contains all your assets into your application configuration.
|
||||||
|
They don't even need to be in the top directory - Wails will just work it out for you.
|
||||||
|
|
||||||
|
### New Development Experience
|
||||||
|
|
||||||
|
Now that assets don't need to be bundled, it's enabled a whole new development experience. The new `wails dev`
|
||||||
|
command will build and run your application, but instead of using the assets in the `embed.FS`, it loads them directly
|
||||||
|
from disk.
|
||||||
|
|
||||||
|
It also provides the additional features:
|
||||||
|
|
||||||
|
- Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend
|
||||||
|
- Auto rebuild - Any changes to your Go code will rebuild and relaunch your application
|
||||||
|
|
||||||
|
In addition to this, a webserver will start on port 34115. This will serve your application to any browser that
|
||||||
|
connects to it. All connected web browsers will respond to system events like hot reload on asset change.
|
||||||
|
|
||||||
|
In Go, we are used to dealing with structs in our applications. It's often useful to send structs to our frontend
|
||||||
|
and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the
|
||||||
|
developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate Typescript
|
||||||
|
models for all structs that are input or output parameters to bound methods. This enables seamless interchange of data
|
||||||
|
models between the two worlds.
|
||||||
|
|
||||||
|
In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides
|
||||||
|
JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models
|
||||||
|
auto-imported when hitting tab in an auto-generated module wrapping your Go code!
|
||||||
|
|
||||||
|
### Remote Templates
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/remote-mac.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Getting an application up and running quickly was always a key goal for the Wails project. When we launched, we tried
|
||||||
|
to cover a lot of the modern frameworks at the time: react, vue and angular. The world of frontend development is very
|
||||||
|
opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty
|
||||||
|
quickly and this caused a maintenance headache. It also meant that we didn't have cool modern templates for the latest
|
||||||
|
and greatest tech stacks.
|
||||||
|
|
||||||
|
With v2, I wanted to empower the community by giving you the ability to create and host templates yourselves, rather
|
||||||
|
than rely on the Wails project. So now you can create projects using community supported templates! I hope this will
|
||||||
|
inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer
|
||||||
|
community can create!
|
||||||
|
|
||||||
|
### Native M1 Support
|
||||||
|
|
||||||
|
Thanks to the amazing support of [Mat Ryer](https://github.com/matryer/), the Wails project now supports M1 native
|
||||||
|
builds:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/build-darwin-arm.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
You can also specify `darwin/amd64` as a target too:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/build-darwin-amd.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Oh, I almost forgot.... you can also do `darwin/universal`.... :wink:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/build-darwin-universal.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
### Cross Compilation to Windows
|
||||||
|
|
||||||
|
Because Wails v2 for Windows is pure Go, you can target Windows builds without docker.
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/build-cross-windows.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
### WKWebView Renderer
|
||||||
|
|
||||||
|
V1 relied on a (now deprecated) WebView component. V2 uses the most recent WKWebKit component so expect the latest and greatest from Apple.
|
||||||
|
|
||||||
|
### In Conclusion
|
||||||
|
|
||||||
|
As I'd said in the Windows release notes, Wails v2 represents a new foundation for the project.
|
||||||
|
The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release.
|
||||||
|
Your input would be most welcome! Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828)
|
||||||
|
discussion board.
|
||||||
|
|
||||||
|
And finally, I'd like to give a special thank you to all the [project sponsors](/docs/credits#sponsors), including [JetBrains](https://www.jetbrains.com?from=Wails),
|
||||||
|
whose support drive the project in many ways behind the scenes.
|
||||||
|
|
||||||
|
I look forward to seeing what people build with Wails in this next exciting phase of the project!
|
||||||
|
|
||||||
|
Lea.
|
||||||
|
|
||||||
|
PS: Linux users, you're next!
|
||||||
|
|
||||||
|
PPS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks!
|
||||||
@@ -23,6 +23,9 @@ sidebar_position: 99
|
|||||||
<a href="https://github.com/codydbentley" style="width:100px">
|
<a href="https://github.com/codydbentley" style="width:100px">
|
||||||
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/CrackDavid" style="width:100px">
|
||||||
|
<img src="https://github.com/CrackDavid.png?size=100" width="100"/>
|
||||||
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://github.com/matryer" style="width:100px">
|
<a href="https://github.com/matryer" style="width:100px">
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ sidebar_position: 1
|
|||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
|
|
||||||
- Windows 10
|
- Windows 10
|
||||||
- MacOS x64 & arm64 (due October '21)
|
- MacOS 10.13+ (amd64)
|
||||||
- Linux (due December '21)
|
- MacOS 11.0+ (arm64)
|
||||||
|
- Linux (due Jan '22)
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
@@ -47,7 +48,11 @@ import TabItem from "@theme/TabItem";
|
|||||||
{ label: "Linux", value: "Linux" },
|
{ label: "Linux", value: "Linux" },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<TabItem value="MacOS">Coming Soon...</TabItem>
|
<TabItem value="MacOS">
|
||||||
|
Wails requires that the xcode command line tools are installed. This can be done by running:<br/>
|
||||||
|
|
||||||
|
<code>xcode-select --install</code>
|
||||||
|
</TabItem>
|
||||||
<TabItem value="Windows">
|
<TabItem value="Windows">
|
||||||
Wails requires that the <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">WebView2</a>{" "}
|
Wails requires that the <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">WebView2</a>{" "}
|
||||||
runtime is installed. Some Windows installations will already have this installed. You can check using the{" "}
|
runtime is installed. Some Windows installations will already have this installed. You can check using the{" "}
|
||||||
@@ -62,7 +67,7 @@ import TabItem from "@theme/TabItem";
|
|||||||
|
|
||||||
## Installing Wails
|
## Installing Wails
|
||||||
|
|
||||||
Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.15` to install the Wails CLI.
|
Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.20` to install the Wails CLI.
|
||||||
|
|
||||||
## System Check
|
## System Check
|
||||||
|
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ The format of the file is slightly different. Here is a comparison:
|
|||||||
| frontend / serve | | Removed |
|
| frontend / serve | | Removed |
|
||||||
| tags | | Removed |
|
| tags | | Removed |
|
||||||
| | wailsjsdir | The directory to generate wailsjs modules |
|
| | wailsjsdir | The directory to generate wailsjs modules |
|
||||||
| | assetdir | The directory of the frontend assets for `dev` mode |
|
| | assetdir | The directory of the compiled frontend assets for `dev` mode |
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,12 @@ Example:
|
|||||||
|
|
||||||
`wails build -clean -o myproject.exe`
|
`wails build -clean -o myproject.exe`
|
||||||
|
|
||||||
|
:::info UPX on Apple Silicon
|
||||||
|
|
||||||
|
There are [issues](https://github.com/upx/upx/issues/446) with using UPX with Apple Silicon.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## doctor
|
## doctor
|
||||||
|
|
||||||
`wails doctor` will run diagnostics to ensure that your system is ready for development.
|
`wails doctor` will run diagnostics to ensure that your system is ready for development.
|
||||||
@@ -134,6 +140,8 @@ Your system is ready for Wails development!
|
|||||||
| -wailsjsdir | The directory to generate the generated Wails JS modules | Value in `wails.json` |
|
| -wailsjsdir | The directory to generate the generated Wails JS modules | Value in `wails.json` |
|
||||||
| -debounce | The time to wait for reload after an asset change is detected | 100 (milliseconds) |
|
| -debounce | The time to wait for reload after an asset change is detected | 100 (milliseconds) |
|
||||||
| -devserverurl "url" | Use 3rd party dev server url, EG Vite | "http://localhost:34115" |
|
| -devserverurl "url" | Use 3rd party dev server url, EG Vite | "http://localhost:34115" |
|
||||||
|
| -appargs "args" | Arguments passed to the application in shell style | |
|
||||||
|
| -platform "platform" | Platform/Arch to target | `runtime.GOOS` |
|
||||||
|
|
||||||
If the `assetdir`, `wailsjsdir`, `debounce` or `devserverurl` flags are provided on the command line, they are saved in
|
If the `assetdir`, `wailsjsdir`, `debounce` or `devserverurl` flags are provided on the command line, they are saved in
|
||||||
`wails.json`, and become the defaults for subsequent invocations.
|
`wails.json`, and become the defaults for subsequent invocations.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ sidebar_position: 4
|
|||||||
# Menus
|
# Menus
|
||||||
|
|
||||||
It is possible to add an application menu to Wails projects. This is achieved by defining a [Menu](#menu) struct and
|
It is possible to add an application menu to Wails projects. This is achieved by defining a [Menu](#menu) struct and
|
||||||
calling the runtime method [MenuSetApplicationMenu](/docs/reference/runtime/menu#menusetapplicationmenu).
|
setting the [`Menu`](/docs/reference/options#menu) option, or by calling the runtime method [MenuSetApplicationMenu](/docs/reference/runtime/menu#menusetapplicationmenu).
|
||||||
|
|
||||||
It is also possible to dynamically update the menu, by updating the menu struct and calling
|
It is also possible to dynamically update the menu, by updating the menu struct and calling
|
||||||
[MenuUpdateApplicationMenu](/docs/reference/runtime/menu#menuupdateapplicationmenu).
|
[MenuUpdateApplicationMenu](/docs/reference/runtime/menu#menuupdateapplicationmenu).
|
||||||
@@ -79,6 +79,7 @@ type MenuItem struct {
|
|||||||
| Checked | bool | Adds check to item (Checkbox & Radio types) |
|
| Checked | bool | Adds check to item (Checkbox & Radio types) |
|
||||||
| SubMenu | [\*Menu](#menu) | Sets the submenu |
|
| SubMenu | [\*Menu](#menu) | Sets the submenu |
|
||||||
| Click | [Callback](#callback) | Callback function when menu clicked |
|
| Click | [Callback](#callback) | Callback function when menu clicked |
|
||||||
|
| Role | string | Defines a [role](#roles) for this menu item. Mac only for now. |
|
||||||
|
|
||||||
### Accelerator
|
### Accelerator
|
||||||
|
|
||||||
@@ -231,3 +232,19 @@ type CallbackData struct {
|
|||||||
|
|
||||||
The function is given a `CallbackData` struct which indicates which menu item triggered the callback. This is useful when
|
The function is given a `CallbackData` struct which indicates which menu item triggered the callback. This is useful when
|
||||||
using radio groups that may share a callback.
|
using radio groups that may share a callback.
|
||||||
|
|
||||||
|
### Role
|
||||||
|
|
||||||
|
:::info Roles
|
||||||
|
|
||||||
|
Roles are currently supported on Mac only.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
A menu item may have a role, which is essentially a pre-defined menu item. We currently support the following roles:
|
||||||
|
|
||||||
|
| Role | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
| AppMenuRole | The standard Mac application menu. Can be created using `menu.AppMenu()` |
|
||||||
|
| EditMenuRole | The standard Mac edit menu. Can be created using `menu.EditMenu()` |
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ func main() {
|
|||||||
StartHidden: false,
|
StartHidden: false,
|
||||||
HideWindowOnClose: false,
|
HideWindowOnClose: false,
|
||||||
RGBA: &options.RGBA{R: 0, G: 0, B: 0, A: 255},
|
RGBA: &options.RGBA{R: 0, G: 0, B: 0, A: 255},
|
||||||
|
AlwaysOnTop: false,
|
||||||
Assets: assets,
|
Assets: assets,
|
||||||
Menu: app.applicationMenu(),
|
Menu: app.applicationMenu(),
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
@@ -43,6 +44,24 @@ func main() {
|
|||||||
WindowIsTranslucent: false,
|
WindowIsTranslucent: false,
|
||||||
DisableWindowIcon: false,
|
DisableWindowIcon: false,
|
||||||
},
|
},
|
||||||
|
Mac: &mac.Options{
|
||||||
|
TitleBar: &mac.TitleBar{
|
||||||
|
TitlebarAppearsTransparent: true,
|
||||||
|
HideTitle: false,
|
||||||
|
HideTitleBar: false,
|
||||||
|
FullSizeContent: false,
|
||||||
|
UseToolbar: false,
|
||||||
|
HideToolbarSeparator: true,
|
||||||
|
},
|
||||||
|
Appearance: mac.NSAppearanceNameDarkAqua,
|
||||||
|
WebviewIsTransparent: true,
|
||||||
|
WindowIsTranslucent: false,
|
||||||
|
About: &mac.AboutInfo{
|
||||||
|
Title: "My Application",
|
||||||
|
Message: "© 2021 Me",
|
||||||
|
Icon: icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -192,6 +211,8 @@ Type: \*menu.Menu
|
|||||||
|
|
||||||
The menu to be used by the application. More details about Menus in the [Menu Reference](/docs/reference/runtime/menu).
|
The menu to be used by the application. More details about Menus in the [Menu Reference](/docs/reference/runtime/menu).
|
||||||
|
|
||||||
|
NOTE: On Mac, if no menu is specified, a default menu will be created.
|
||||||
|
|
||||||
### Logger
|
### Logger
|
||||||
|
|
||||||
Name: Logger
|
Name: Logger
|
||||||
@@ -281,3 +302,153 @@ Name: DisableWindowIcon
|
|||||||
Type: bool
|
Type: bool
|
||||||
|
|
||||||
Setting this to true will remove the icon in the top left corner of the title bar.
|
Setting this to true will remove the icon in the top left corner of the title bar.
|
||||||
|
|
||||||
|
|
||||||
|
## Mac Specific Options
|
||||||
|
|
||||||
|
### TitleBar
|
||||||
|
|
||||||
|
Name: TitleBar
|
||||||
|
|
||||||
|
Type: [*mac.TitleBar](#titlebar-struct)
|
||||||
|
|
||||||
|
The TitleBar struct provides the ability to configure the look and feel of the title bar.
|
||||||
|
|
||||||
|
### Appearance
|
||||||
|
|
||||||
|
Name: Appearance
|
||||||
|
|
||||||
|
Type: [AppearanceType](#appearance-type)
|
||||||
|
|
||||||
|
Appearance is used to set the style of your app in accordance with Apple's [NSAppearance](https://developer.apple.com/documentation/appkit/nsappearancename?language=objc) names.
|
||||||
|
|
||||||
|
### WebviewIsTransparent
|
||||||
|
|
||||||
|
Name: WebviewIsTransparent
|
||||||
|
|
||||||
|
Type: bool
|
||||||
|
|
||||||
|
Setting this to `true` will make the webview background transparent when an alpha value of `0` is used.
|
||||||
|
This means that if you use `rgba(0,0,0,0)`, the host window will show through.
|
||||||
|
Often combined with [WindowIsTranslucent](#WindowIsTranslucent) to make frosty-looking applications.
|
||||||
|
|
||||||
|
### WindowIsTranslucent
|
||||||
|
|
||||||
|
Name: WindowIsTranslucent
|
||||||
|
|
||||||
|
Type: bool
|
||||||
|
|
||||||
|
Setting this to `true` will make the window background translucent. Often combined
|
||||||
|
with [WebviewIsTransparent](#WebviewIsTransparent) to make frosty-looking applications.
|
||||||
|
|
||||||
|
### About
|
||||||
|
|
||||||
|
Name: About
|
||||||
|
|
||||||
|
Type: [About](#about-struct)
|
||||||
|
|
||||||
|
This configuration lets you set the title, message and icon for the "About" menu item in the app menu created by the "AppMenu" role.
|
||||||
|
|
||||||
|
#### Titlebar struct
|
||||||
|
|
||||||
|
The titlebar of the application can be customised by using the TitleBar options:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TitleBar struct {
|
||||||
|
TitlebarAppearsTransparent bool
|
||||||
|
HideTitle bool
|
||||||
|
HideTitleBar bool
|
||||||
|
FullSizeContent bool
|
||||||
|
UseToolbar bool
|
||||||
|
HideToolbarSeparator bool
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
| TitlebarAppearsTransparent | Makes the titlebar transparent. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindow/1419167-titlebarappearstransparent?language=objc) |
|
||||||
|
| HideTitle | Hides the title of the window. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindowtitlevisibility?language=objc) |
|
||||||
|
| HideTitleBar | Removes [NSWindowStyleMaskTitled](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemasktitled/) from the style mask |
|
||||||
|
| FullSizeContent | Makes the webview fill the entire window. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemaskfullsizecontentview)|
|
||||||
|
| UseToolbar | Adds a default toolbar to the window. [Apple Docs](https://developer.apple.com/documentation/appkit/nstoolbar?language=objc) |
|
||||||
|
| HideToolbarSeparator | Removes the line beneath the toolbar. [Apple Docs](https://developer.apple.com/documentation/appkit/nstoolbar/1516954-showsbaselineseparator?language=objc) |
|
||||||
|
|
||||||
|
Preconfigured titlebar settings are available:
|
||||||
|
|
||||||
|
| Setting | Example |
|
||||||
|
| ------- | ------- |
|
||||||
|
|`mac.TitleBarDefault()` |  |
|
||||||
|
|`mac.TitleBarHidden()` |  |
|
||||||
|
|`mac.TitleBarHiddenInset()` |  |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```go
|
||||||
|
Mac: &mac.Options{
|
||||||
|
TitleBar: mac.TitleBarHiddenInset(),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Click [here](https://github.com/lukakerr/NSWindowStyles) for some inspiration on customising the titlebar.
|
||||||
|
|
||||||
|
#### Appearance type
|
||||||
|
|
||||||
|
You can specify the application's [appearance](https://developer.apple.com/documentation/appkit/nsappearance?language=objc).
|
||||||
|
|
||||||
|
| Value | Description |
|
||||||
|
| --------------- | ------------------ |
|
||||||
|
| DefaultAppearance | DefaultAppearance uses the default system value |
|
||||||
|
| NSAppearanceNameAqua | The standard light system appearance |
|
||||||
|
| NSAppearanceNameDarkAqua | The standard dark system appearance |
|
||||||
|
| NSAppearanceNameVibrantLight | The light vibrant appearance |
|
||||||
|
| NSAppearanceNameAccessibilityHighContrastAqua | A high-contrast version of the standard light system appearance |
|
||||||
|
| NSAppearanceNameAccessibilityHighContrastDarkAqua | A high-contrast version of the standard dark system appearance |
|
||||||
|
| NSAppearanceNameAccessibilityHighContrastVibrantLight | A high-contrast version of the light vibrant appearance |
|
||||||
|
| NSAppearanceNameAccessibilityHighContrastVibrantDark | A high-contrast version of the dark vibrant appearance |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```go
|
||||||
|
Mac: &mac.Options{
|
||||||
|
Appearance: mac.NSAppearanceNameDarkAqua,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### About struct
|
||||||
|
|
||||||
|
```go
|
||||||
|
type AboutInfo struct {
|
||||||
|
Title string
|
||||||
|
Message string
|
||||||
|
Icon []byte
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If these settings are provided, an "About" menu item will appear in the app menu (when using the `AppMenu` role).
|
||||||
|
Given this configuration:
|
||||||
|
```go
|
||||||
|
//go:embed build/appicon.png
|
||||||
|
var icon []byte
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := wails.Run(&options.App{
|
||||||
|
...
|
||||||
|
Mac: &mac.Options{
|
||||||
|
About: &mac.AboutInfo{
|
||||||
|
Title: "My Application",
|
||||||
|
Message: "© 2021 Me",
|
||||||
|
Icon: icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
The "About" menu item will appear in the app menu:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/reference/about-menu.png" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
When clicked, that will open an about message box:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img src="/img/reference/about-dialog.png" width="40%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ The project config resides in the `wails.json` file in the project directory. Th
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "[The project name]",
|
"name": "[The project name]",
|
||||||
"assetdir": "[Relative path to your assets directory]",
|
"assetdir": "[Relative path to the directory containing the compiled assets]",
|
||||||
"frontend:install": "[The command to install node dependencies, run in the frontend directory - often `npm install`]",
|
"frontend:install": "[The command to install node dependencies, run in the frontend directory - often `npm install`]",
|
||||||
"frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]",
|
"frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]",
|
||||||
"frontend:dev": "[This command is run in a separate process on `wails dev`. Useful for 3rd party watchers]",
|
"frontend:dev": "[This command is run in a separate process on `wails dev`. Useful for 3rd party watchers]",
|
||||||
@@ -17,7 +17,9 @@ The project config resides in the `wails.json` file in the project directory. Th
|
|||||||
"version": "[Project config version]",
|
"version": "[Project config version]",
|
||||||
"outputfilename": "[The name of the binary]",
|
"outputfilename": "[The name of the binary]",
|
||||||
"debounceMS": 100, // The default time the dev server waits to reload when it detects a vhange in assets
|
"debounceMS": 100, // The default time the dev server waits to reload when it detects a vhange in assets
|
||||||
"devserverurl": "[URL to the dev server serving local assets. Default: http://localhost:34115]"
|
"devserverurl": "[URL to the dev server serving local assets. Default: http://localhost:34115]",
|
||||||
|
"appargs": "[Arguments passed to the application in shell style when in dev mode]"
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const darkCodeTheme = require('prism-react-renderer/themes/palenight');
|
|||||||
({
|
({
|
||||||
announcementBar: {
|
announcementBar: {
|
||||||
id: 'beta-message',
|
id: 'beta-message',
|
||||||
content: 'Wails v2 is currently Beta for Windows. Mac & Linux in progress.',
|
content: 'Wails v2 is currently Beta for Windows & Mac. Linux in progress.',
|
||||||
backgroundColor: '#b00',
|
backgroundColor: '#b00',
|
||||||
textColor: '#FFF',
|
textColor: '#FFF',
|
||||||
isCloseable: false,
|
isCloseable: false,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ sidebar_position: 1
|
|||||||
|
|
||||||
Wails 是一个可让您使用 Go 和 Web 技术编写桌面应用的项目。
|
Wails 是一个可让您使用 Go 和 Web 技术编写桌面应用的项目。
|
||||||
|
|
||||||
将它看作为轻量快速的 “Electron for Go”。 您可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。
|
将它看作为 Go 的轻量级和快速的 Electron 替代品。 您可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。
|
||||||
|
|
||||||
Wails 一点也不弱!这是 [xbar](https://xbarapp.com) - 一个使用 Wails 编写的 MacOS 桌面应用。它使用 Mac 的系统原生菜单,支持浅色和深色桌面主题,主窗口使用半透明,使其具有原生应用的
|
Wails 一点也不弱!这是 [xbar](https://xbarapp.com) - 一个使用 Wails 编写的 MacOS 桌面应用。它使用 Mac 的系统原生菜单,支持浅色和深色桌面主题,主窗口使用半透明,使其具有原生应用的
|
||||||
“冰霜” 效果。
|
“冰霜” 效果。
|
||||||
@@ -31,13 +31,13 @@ Wails 自动使您的 Go 方法可用于 Javascript,因此您可以从前端
|
|||||||
|
|
||||||
## 运行时库
|
## 运行时库
|
||||||
|
|
||||||
Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应用程序需要的很多东西,比如事件、日志记录、对话框等。
|
Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应用程序需要的很多东西,比如事件、日志、对话框等。
|
||||||
|
|
||||||
## 实时开发体验
|
## 实时开发体验
|
||||||
|
|
||||||
### 自动重新构建
|
### 自动重新构建
|
||||||
|
|
||||||
当您在“dev”模式下运行您的应用程序时,Wails 会将您的应用程序构建为原生桌面应用程序,但会从磁盘读取您的资源。它将检测您的 Go 代码的任何更改,并自动重新构建和重新启动您的应用程序。
|
当您在“dev“模式下运行您的应用程序时,Wails 会将您的应用程序构建为原生桌面应用程序,但会从磁盘读取您的资源。它将检测您的 Go 代码的任何更改,并自动重新构建和重新启动您的应用程序。
|
||||||
|
|
||||||
### 自动重新加载
|
### 自动重新加载
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应
|
|||||||
|
|
||||||
如果您更喜欢在浏览器中调试和开发,那么 Wails 可以满足您的需求。正在运行的应用程序还有一个网络服务器,它将在连接到它的任何浏览器中运行您的应用程序。当您的资源在磁盘上发生变化时,它会刷新。
|
如果您更喜欢在浏览器中调试和开发,那么 Wails 可以满足您的需求。正在运行的应用程序还有一个网络服务器,它将在连接到它的任何浏览器中运行您的应用程序。当您的资源在磁盘上发生变化时,它会刷新。
|
||||||
|
|
||||||
## 生成原生二进制文件
|
## 可用于生产的原生二进制文件
|
||||||
|
|
||||||
当您准备好完成应用程序的最终构建时,CLI 会将其编译为单个可执行文件,并将所有资源打包到其中。在 Windows 和 MacOS
|
当您准备好完成应用程序的最终构建时,CLI 会将其编译为单个可执行文件,并将所有资源打包到其中。在 Windows 和 MacOS
|
||||||
上,可以创建用于分发的原生包。使用打包工具后生成的资源(图标、info.plist、清单文件等)是您项目的一部分,可以自定义,让您完全控制应用程序的构建方式。
|
上,可以创建用于分发的原生包。使用打包工具后生成的资源(图标、info.plist、清单文件等)是您项目的一部分,可以自定义,让您完全控制应用程序的构建方式。
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ sidebar_position: 2
|
|||||||
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
|
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
|
||||||
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
|
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
|
||||||
- [Github Issues](https://github.com/wailsapp/wails/issues)
|
- [Github Issues](https://github.com/wailsapp/wails/issues)
|
||||||
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828)
|
- [v2 测试版讨论板](https://github.com/wailsapp/wails/discussions/828)
|
||||||
|
|
||||||
## 社交媒体
|
## 社交媒体
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,7 @@ sidebar_position: 1
|
|||||||
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - 基于 Vue 和 Vue-Router 的 Wails 模板
|
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - 基于 Vue 和 Vue-Router 的 Wails 模板
|
||||||
- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - 使用 Vite 的 Vue 3 TypeScript(以及添加功能的说明)
|
- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - 使用 Vite 的 Vue 3 TypeScript(以及添加功能的说明)
|
||||||
- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - 使用 Vite, Vuex, Vue Router, Sass, 和 ESLint + Prettier 的 Vue 3 TypeScript
|
- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - 使用 Vite, Vuex, Vue Router, Sass, 和 ESLint + Prettier 的 Vue 3 TypeScript
|
||||||
|
|
||||||
|
## Angular
|
||||||
|
|
||||||
|
- [wails-angular-template](https://github.com/TAINCER/wails-angular-template) - 带有 TypeScript, Sass, 热重载, 代码拆分和 i18n 的 Angular
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ sidebar_position: 99
|
|||||||
<a href="https://github.com/snider" style="width:100px;">
|
<a href="https://github.com/snider" style="width:100px;">
|
||||||
<img src="https://github.com/snider.png?size=100" width="100"/>
|
<img src="https://github.com/snider.png?size=100" width="100"/>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/codydbentley" style="width:100px">
|
||||||
|
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||||
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://github.com/matryer" style="width:100px">
|
<a href="https://github.com/matryer" style="width:100px">
|
||||||
@@ -58,15 +61,27 @@ sidebar_position: 99
|
|||||||
<a href="https://github.com/jugglingjsons" style="width:50px">
|
<a href="https://github.com/jugglingjsons" style="width:50px">
|
||||||
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
|
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/marcus-crane" style="width:50px">
|
<a href="https://github.com/marcus-crane" style="width:65px">
|
||||||
<img src="https://github.com/marcus-crane.png?size=50" width="50"/>
|
<img src="https://github.com/marcus-crane.png?size=65" width="65"/>
|
||||||
</a>
|
|
||||||
<a href="https://github.com/codydbentley" style="width:65px">
|
|
||||||
<img src="https://github.com/codydbentley.png?size=65" width="65"/>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/bbergshaven" style="width:45px">
|
<a href="https://github.com/bbergshaven" style="width:45px">
|
||||||
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/Gilgames000" style="width:45px">
|
||||||
|
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/ilgityildirim" style="width:50px">
|
||||||
|
<img src="https://github.com/ilgityildirim.png?size=50" width="50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/ondoki" style="width:65px">
|
||||||
|
<img src="https://github.com/ondoki.png?size=65" width="65"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/questrail" style="width:50px">
|
||||||
|
<img src="https://github.com/questrail.png?size=50" width="50"/>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/DonTomato" style="width:45px">
|
||||||
|
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
||||||
|
</a>
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -46,6 +46,6 @@ Wails 项目具有以下布局:
|
|||||||
|
|
||||||
`frontend`目录没有特定于 Wails 的内容,可以是您选择的任何前端项目。
|
`frontend`目录没有特定于 Wails 的内容,可以是您选择的任何前端项目。
|
||||||
|
|
||||||
`build`目录在构建过程中使用。这些文件可以更新以自定义您的构建。如果文件从构建目录中删除,将重新生成默认版本。
|
`build`目录在构建过程中使用。这些文件可以修改以自定义您的构建。如果文件从构建目录中删除,将重新生成默认版本。
|
||||||
|
|
||||||
`go.mod`中的默认模块名称是“changeme”。您应该将其更改为更合适的内容。
|
`go.mod`中的默认模块名称是“changeme”。您应该将其更改为更合适的内容。
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Wails 有许多安装前需要的常见依赖项:
|
|||||||
|
|
||||||
从[Node 下载页面](https://nodejs.org/en/download/)下载 Npm。最好使用最新版本,因为这是我们通常会测试的版本。
|
从[Node 下载页面](https://nodejs.org/en/download/)下载 Npm。最好使用最新版本,因为这是我们通常会测试的版本。
|
||||||
|
|
||||||
运行 `npm --version` 进行校验。
|
运行 `npm --version` 进行验证。
|
||||||
|
|
||||||
## 平台指定依赖关系
|
## 平台指定依赖关系
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ import TabItem from "@theme/TabItem";
|
|||||||
|
|
||||||
## 安装 Wails
|
## 安装 Wails
|
||||||
|
|
||||||
运行 `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.15` 安装 Wails CLI。
|
运行 `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.20` 安装 Wails CLI。
|
||||||
|
|
||||||
## 系统检查
|
## 系统检查
|
||||||
|
|
||||||
|
|||||||
@@ -146,3 +146,20 @@ Wails v2 处理资源的方式的伟大之处在于它没有!您唯一需要
|
|||||||
第一个,如果有给定,将在`frontend`目录中执行以安装 node 模块。第二个,如果有给定,将在`frontend`目录中执行以构建前端项目。
|
第一个,如果有给定,将在`frontend`目录中执行以安装 node 模块。第二个,如果有给定,将在`frontend`目录中执行以构建前端项目。
|
||||||
|
|
||||||
如果没有给出这两个字段,那么 Wails 不会对前端做任何操作。它仅仅被用作`embed.FS`。
|
如果没有给出这两个字段,那么 Wails 不会对前端做任何操作。它仅仅被用作`embed.FS`。
|
||||||
|
|
||||||
|
## 内置开发服务器
|
||||||
|
|
||||||
|
运行`wails dev`将启动内置的开发服务器,它将在您的项目目录中启动一个文件监听器。
|
||||||
|
默认情况下,如果有任何文件更改,wails 会检查它是否是应用程序文件(默认:.go,可使用`-e`标志配置)。如果是,那么它将重新构建您的应用程序并重新启动它。如果更改的文件在`assetdir`目录中,它会在很短的时间后重新加载。
|
||||||
|
|
||||||
|
开发服务器使用一种称为“防抖”的技术,这意味着它不会立即重新加载,因为可能会在短时间内更改多个文件。当触发发生时,它会在发出重新加载之前等待一定的时间。
|
||||||
|
如果发生另一个触发,它会再次重置为等待时间。默认情况下,此值为 100ms。如果此值不适用于您的项目,则可以使用`-debounce`标志进行配置。如果使用,此值将保存到您的项目配置中并成为默认值。
|
||||||
|
|
||||||
|
## 外部开发服务器
|
||||||
|
|
||||||
|
一些框架带有自己的实时重新加载服务器,但是它们将无法利用 Wails Go 绑定。在这种情况下,最好运行一个监听脚本,将项目重新构建到构建目录中,Wails 将监视该目录。
|
||||||
|
有关示例,请参阅使用[rollup](https://rollupjs.org/guide/en/)的默认 svelte 模板。对于[create-react-app](https://create-react-app.dev/),可以使用[此脚本](https://gist.github.com/int128/e0cdec598c5b3db728ff35758abdbafd)来实现类似的结果。
|
||||||
|
|
||||||
|
## Go 模块
|
||||||
|
|
||||||
|
默认的 Wails 模板会生成一个包含模块名称“changeme”的`go.mod`文件。您应该在项目生成后将其更改为更合适的内容。
|
||||||
|
|||||||
@@ -25,3 +25,7 @@ Wails 为拖动窗口提供了一个简单的解决方案:任何具有“data-
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::info 全屏
|
||||||
|
如果您允许应用程序全屏显示,则此拖动功能将被禁用。
|
||||||
|
:::
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# 滚动超出
|
||||||
|
|
||||||
|
[Overscroll](https://developer.mozilla.org/zh-CN/docs/Web/CSS/overscroll-behavior) 是当您滚动超出页面内容边界时有时会获得的“弹跳效果”。这在移动应用程序中很常见。这可以使用 CSS 禁用:
|
||||||
|
|
||||||
|
```css
|
||||||
|
body {
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -89,3 +89,4 @@ Renaming package-lock.json -> package-lock.tmpl.json...
|
|||||||
- 确保`template.json`完整,尤其是`helpurl`
|
- 确保`template.json`完整,尤其是`helpurl`
|
||||||
- 将文件推送到 GitHub
|
- 将文件推送到 GitHub
|
||||||
- 在[社区模板](/docs/community/templates)页面上创建 PR
|
- 在[社区模板](/docs/community/templates)页面上创建 PR
|
||||||
|
- 在[模板公告](https://github.com/wailsapp/wails/discussions/825)讨论板上发布模板
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
通过在构建时使用`-webview2`标志,您可以决定在未检测到合适的运行时的时候(包括安装的运行时是否太旧)应用程序将执行的操作。四个选项是:
|
通过在构建时使用`-webview2`标志,您可以决定在未检测到合适的运行时的时候(包括安装的运行时是否太旧)应用程序将执行的操作。四个选项是:
|
||||||
|
|
||||||
1. 下载
|
1. Download(下载)
|
||||||
2. 内嵌
|
2. Embed(内嵌)
|
||||||
3. 浏览器
|
3. Browser(浏览器)
|
||||||
4. 错误
|
4. Error(错误)
|
||||||
|
|
||||||
### 下载
|
### 下载
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Wails 应用程序是一个带有一个 webkit 前端的标准的 Go 应用程
|
|||||||
|
|
||||||
### 概述
|
### 概述
|
||||||
|
|
||||||
主应用程序由对`wails.Run()`的调用组成. 它接受描述应用程序窗口大小、窗口标题、要使用的资源等的应用程序配置。基本应用程序可能如下所示:
|
主应用程序由对`wails.Run()`的调用组成. 它接受描述应用程序窗口大小、窗口标题、要使用的资源等应用程序配置。基本应用程序可能如下所示:
|
||||||
|
|
||||||
```go title="main.go"
|
```go title="main.go"
|
||||||
package main
|
package main
|
||||||
@@ -85,7 +85,7 @@ func (b *App) Greet(name string) string {
|
|||||||
#### 资源
|
#### 资源
|
||||||
|
|
||||||
`Assets` 选项是必须的,因为您不能拥有没有前端资源的 Wails 应用程序。这些资源可以是您希望在 Web 应用程序中找到的任何文件 - html、js、css、svg、png 等。
|
`Assets` 选项是必须的,因为您不能拥有没有前端资源的 Wails 应用程序。这些资源可以是您希望在 Web 应用程序中找到的任何文件 - html、js、css、svg、png 等。
|
||||||
**不需要生成资源包**- 纯文件即可。当应用程序启动时,它将尝试从您的资源中加载`index.html`,并且那时起前端基本上将作为浏览器工作。值得注意的是 embed.FS,
|
**不需要生成资源包**- 纯文件即可。当应用程序启动时,它将尝试从您的资源中加载`index.html`,并且那时起前端基本上将作为浏览器工作。值得注意的是`embed.FS`,
|
||||||
文件所在的位置没有要求。嵌入路径很可能使用了相对于您的主应用程序代码的嵌套目录,例如 `frontend/dist`:
|
文件所在的位置没有要求。嵌入路径很可能使用了相对于您的主应用程序代码的嵌套目录,例如 `frontend/dist`:
|
||||||
|
|
||||||
```go title="main.go"
|
```go title="main.go"
|
||||||
@@ -95,10 +95,12 @@ var assets embed.FS
|
|||||||
|
|
||||||
启动时,Wails 将遍历嵌入的文件,寻找包含的`index.html`. 所有其他资源将相对于该目录加载。
|
启动时,Wails 将遍历嵌入的文件,寻找包含的`index.html`. 所有其他资源将相对于该目录加载。
|
||||||
|
|
||||||
由于生产二进制文件使用中包含在`embed.FS`的文件,因此应用程序不需要附带任何外部文件。
|
由于可用于生产的二进制文件使用包含在`embed.FS`中的文件,因此应用程序不需要附带任何外部文件。
|
||||||
|
|
||||||
当使用`wails dev`命令在”dev“模式下,资源从磁盘加载,任何更改都会导致“实时重新加载”。资源的位置需要使用`-assetdir`传递给`wails dev`命令,并且很可能与嵌入路径相同。
|
当使用`wails dev`命令在”dev“模式下,资源从磁盘加载,任何更改都会导致“实时重新加载”。资源的位置需要使用`-assetdir`传递给`wails dev`命令,并且很可能与嵌入路径相同。
|
||||||
希望`embed.FS`将来我们可以从它本身计算出来。更多细节可以在[应用程序开发指南](/docs/guides/application-development)中找到。
|
希望将来我们可以从`embed.FS`本身计算出来。
|
||||||
|
|
||||||
|
更多细节可以在[应用程序开发指南](/docs/guides/application-development)中找到。
|
||||||
|
|
||||||
#### 应用程序生命周期回调
|
#### 应用程序生命周期回调
|
||||||
|
|
||||||
|
|||||||
@@ -13,25 +13,27 @@ Wails CLI 有许多用于管理项目的命令。所有命令都以此方式运
|
|||||||
|
|
||||||
`wails init` 用于生成项目。
|
`wails init` 用于生成项目。
|
||||||
|
|
||||||
| 标志 | 描述 | 默认 |
|
| 标志 | 描述 | 默认 |
|
||||||
| :----------------- | :------------------------------------------------------------------ | :------ |
|
| :----------------- | :---------------------------------------------------------------------------------- | :------ |
|
||||||
| -n "project name" | 项目名. **强制必填**. | |
|
| -n "project name" | 项目名. **强制必填**. | |
|
||||||
| -d "project dir" | 要创建的项目目录 | 项目名 |
|
| -d "project dir" | 要创建的项目目录 | 项目名 |
|
||||||
| -g | 初始化 git 存储库 | |
|
| -g | 初始化 git 存储库 | |
|
||||||
| -l | 可用项目模板列表 | |
|
| -l | 可用项目模板列表 | |
|
||||||
| -q | 禁止输出到控制台 | |
|
| -q | 禁止输出到控制台 | |
|
||||||
| -t "template name" | 要使用的项目模板。这可能是在 github 上托管的远程模板的 URL 的名称。 | vanilla |
|
| -t "template name" | 要使用的项目模板。这可能是默认模板的名称或在 github 上托管的远程模板的 URL 的名称。 | vanilla |
|
||||||
| -ide | 生成 IDE 项目文件 | |
|
| -ide | 生成 IDE 项目文件 | |
|
||||||
| -f | 强制构建应用 | false |
|
| -f | 强制构建应用 | false |
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
`wails init -n test -d mytestproject -g -ide vscode -q`
|
`wails init -n test -d mytestproject -g -ide vscode -q`
|
||||||
|
|
||||||
这将在 "mytestproject" 目录生成一个名为 "test" 的项目,初始化 git,生成 vscode 项目文件并静默执行。
|
这将在 "mytestproject" 目录生成一个名为 "test" 的项目,初始化 git,生成 vscode 项目文件并静默执行。
|
||||||
|
|
||||||
|
可以在[此处](/docs/guides/ides)找到有关在 Wails 中使用 IDE 的更多信息。
|
||||||
|
|
||||||
### 远程模板
|
### 远程模板
|
||||||
|
|
||||||
支持远程模板(托管在 GitHub 上)并且可以使用模板的项目 URL 进行安装。
|
支持远程模板(托管在 GitHub 上)并且可以使用模板项目的 URL 进行安装。
|
||||||
|
|
||||||
示例: `wails init -n test -t https://github.com/leaanthony/testtemplate`
|
示例: `wails init -n test -t https://github.com/leaanthony/testtemplate`
|
||||||
|
|
||||||
@@ -66,6 +68,10 @@ Wails CLI 有许多用于管理项目的命令。所有命令都以此方式运
|
|||||||
|
|
||||||
如果您更喜欢使用标准 Go 工具进行构建,请参阅[手动构建](/docs/guides/manual-builds)指南。
|
如果您更喜欢使用标准 Go 工具进行构建,请参阅[手动构建](/docs/guides/manual-builds)指南。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
`wails build -clean -o myproject.exe`
|
||||||
|
|
||||||
## 诊断检查
|
## 诊断检查
|
||||||
|
|
||||||
`wails doctor` 将运行诊断程序以确保您的系统已准备好进行开发。
|
`wails doctor` 将运行诊断程序以确保您的系统已准备好进行开发。
|
||||||
@@ -111,23 +117,25 @@ Your system is ready for Wails development!
|
|||||||
- 所有应用程序资源都从磁盘加载。如果它们被更改,应用程序将自动重新加载(而不是重新构建)。所有连接的浏览器也将重新加载
|
- 所有应用程序资源都从磁盘加载。如果它们被更改,应用程序将自动重新加载(而不是重新构建)。所有连接的浏览器也将重新加载
|
||||||
- 生成的 JS 模块提供以下内容:
|
- 生成的 JS 模块提供以下内容:
|
||||||
- 带有自动生成的 JSDoc 的 Go 方法的 Javascript 包装器,提供代码提示
|
- 带有自动生成的 JSDoc 的 Go 方法的 Javascript 包装器,提供代码提示
|
||||||
- 的 Go 结构体的 TypeScript 版本,可以构造并传递给您的后端方法
|
- 您的 Go 结构体的 TypeScript 版本,可以构造并传递给您的 Go 方法
|
||||||
- 生成第二个 JS 模块,为运行时提供包装器 + TS 声明
|
- 生成第二个 JS 模块,为运行时提供包装器 + TS 声明
|
||||||
|
|
||||||
| 标志 | 描述 | 默认 |
|
| 标志 | 描述 | 默认 |
|
||||||
| :--------------------------- | :---------------------------------------------------- | :-------------------------- |
|
| :--------------------------- | :---------------------------------------------------- | :----------------------- |
|
||||||
| -assetdir "./path/to/assets" | 编译资源的路径 | Value in `wails.json` |
|
| -assetdir "./path/to/assets" | 编译资源的路径 | `wails.json`中的值 |
|
||||||
| -browser | `http://localhost:34115`在启动时打开浏览器 | |
|
| -browser | 在启动时打开浏览器到`http://localhost:34115` | |
|
||||||
| -compiler "compiler" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go |
|
| -compiler "compiler" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go |
|
||||||
| -e | 触发重建的扩展(逗号分隔) | go |
|
| -e | 触发重新构建的扩展(逗号分隔) | go |
|
||||||
| -ldflags "flags" | 传递给编译器的额外 ldflags | |
|
| -ldflags "flags" | 传递给编译器的额外 ldflags | |
|
||||||
| -tags "extra tags" | 构建标签以传递给编译器(引号和空格分隔) | |
|
| -tags "extra tags" | 构建标签以传递给编译器(引号和空格分隔) | |
|
||||||
| -loglevel "loglevel" | 要使用的日志级别 - Trace, Debug, Info, Warning, Error | Debug |
|
| -loglevel "loglevel" | 要使用的日志级别 - Trace, Debug, Info, Warning, Error | Debug |
|
||||||
| -noreload | 资源更改时禁用自动重新加载 | |
|
| -noreload | 资源更改时禁用自动重新加载 | |
|
||||||
| -v | 详细级别 (0 - silent, 1 - standard, 2 - verbose) | 1 |
|
| -v | 详细级别 (0 - silent, 1 - standard, 2 - verbose) | 1 |
|
||||||
| -wailsjsdir | 生成生成的 Wails JS 模块的目录 | Value store in `wails.json` |
|
| -wailsjsdir | 生成生成的 Wails JS 模块的目录 | `wails.json`中的值 |
|
||||||
|
| -debounce | 检测到资源更改后等待重新加载的时间 | 100 (毫秒) |
|
||||||
|
| -devserverurl "url" | 使用第 3 方开发服务器 url, 例如 Vite | "http://localhost:34115" |
|
||||||
|
|
||||||
如果在命令行上提供了`-assetdir`或`-wailsjsdir`标志,它们将保存在`wails.json`中,并成为后续调用的默认值。
|
如果在命令行上提供了`-assetdir`,`-wailsjsdir`,`debounce`或`devserverurl`标志,它们将保存在`wails.json`中,并成为后续调用的默认值。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
@@ -136,10 +144,12 @@ Your system is ready for Wails development!
|
|||||||
此命令将执行以下操作:
|
此命令将执行以下操作:
|
||||||
|
|
||||||
- 构建应用程序并运行它(更多细节在[这里](/docs/guides/manual-builds))
|
- 构建应用程序并运行它(更多细节在[这里](/docs/guides/manual-builds))
|
||||||
- 生成 Wails JS 模块 ``./frontend/src`
|
- 在`./frontend/src`中生成 Wails JS 模块
|
||||||
- 注意文件的更新`./frontend/dist`并在任何更改时重新加载
|
- 监听`./frontend/dist`中文件的更新并在更改时重新加载
|
||||||
- 打开浏览器并连接到应用程序
|
- 打开浏览器并连接到应用程序
|
||||||
|
|
||||||
|
[此处](/docs/guides/application-development)提供了有关将此功能与现有框架脚本一起使用的更多信息。
|
||||||
|
|
||||||
## 生成
|
## 生成
|
||||||
|
|
||||||
### 模板
|
### 模板
|
||||||
|
|||||||
@@ -155,6 +155,14 @@ func main() {
|
|||||||
|
|
||||||
该值是默认设置窗口的 RGBA 值。默认值:0xFFFFFFFF。
|
该值是默认设置窗口的 RGBA 值。默认值:0xFFFFFFFF。
|
||||||
|
|
||||||
|
### 窗口固定在最顶层
|
||||||
|
|
||||||
|
名称:AlwaysOnTop
|
||||||
|
|
||||||
|
类型:bool
|
||||||
|
|
||||||
|
窗口在失去焦点时应保持在其他窗口之上。
|
||||||
|
|
||||||
### 资源
|
### 资源
|
||||||
|
|
||||||
名称:Assets
|
名称:Assets
|
||||||
@@ -219,7 +227,7 @@ func main() {
|
|||||||
|
|
||||||
定义需要绑定到前端的方法的一部分结构实例。
|
定义需要绑定到前端的方法的一部分结构实例。
|
||||||
|
|
||||||
### 窗口
|
### Windows
|
||||||
|
|
||||||
名称:Windows
|
名称:Windows
|
||||||
|
|
||||||
@@ -235,7 +243,7 @@ func main() {
|
|||||||
|
|
||||||
类型:bool
|
类型:bool
|
||||||
|
|
||||||
将此设置为 true 将使 webview 背景透明,其中没有其他颜色呈现。通常与[窗口半透明](#窗口半透明)结合使用 以制作外观现代的应用程序。
|
当 alpha 值为 0 时,设置为 true 将使 WebView 背景透明。这意味着如果你使用`rgba(0,0,0,0)`,主窗口将显示。通常与[窗口半透明](#窗口半透明)结合使用以制作冰霜效果的应用程序。
|
||||||
|
|
||||||
### 窗口半透明
|
### 窗口半透明
|
||||||
|
|
||||||
@@ -243,7 +251,7 @@ func main() {
|
|||||||
|
|
||||||
类型:bool
|
类型:bool
|
||||||
|
|
||||||
将此设置为 true 将使窗口半透明。通常与[网页透明](#网页透明) 结合使用以制作外观现代的应用程序。
|
将此设置为 true 将使窗口半透明。通常与[网页透明](#网页透明) 结合使用以制作冰霜效果的应用程序。
|
||||||
|
|
||||||
### 禁用窗口图标
|
### 禁用窗口图标
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,16 @@ sidebar_position: 5
|
|||||||
"name": "[项目名称]",
|
"name": "[项目名称]",
|
||||||
"assetdir": "[资源目录的相对路径]",
|
"assetdir": "[资源目录的相对路径]",
|
||||||
"frontend:install": "[安装node依赖的命令,在frontend目录下运行 - 通常是 `npm install`]",
|
"frontend:install": "[安装node依赖的命令,在frontend目录下运行 - 通常是 `npm install`]",
|
||||||
|
"frontend:dev": "[此命令在“Wails dev”上的单独进程中运行。适用于第三方观察者]",
|
||||||
"frontend:build": "[构建资源的命令,在frontend目录下运行 - 通常是 `npm run build`]",
|
"frontend:build": "[构建资源的命令,在frontend目录下运行 - 通常是 `npm run build`]",
|
||||||
"wailsjsdir": "[自动生成的JS模块将被创建的目录的相对路径]",
|
"wailsjsdir": "[自动生成的JS模块将被创建的目录的相对路径]",
|
||||||
"version": "[项目配置版本]",
|
"version": "[项目配置版本]",
|
||||||
"outputfilename": "[二进制文件的名称]"
|
"outputfilename": "[二进制文件的名称]",
|
||||||
|
"debounceMS": 100, // 在检测到资源更改时,开发服务器等待重新加载的时间
|
||||||
|
"devserverurl": "[用于服务本地资源的开发服务器URL。默认:http://localhost:34115]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
该文件将在运行`wails build`或`wails dev`时,由 Wails CLI 读取。
|
该文件将在运行`wails build`或`wails dev`时,由 Wails CLI 读取。
|
||||||
|
|
||||||
`wails build/dev`命令中的`assetdir`和`wailsjsdir`标志将覆盖项目配置并作为后续运行的默认值。
|
`wails build/dev`命令中的`assetdir`,`wailsjsdir`,`debounceMS`和`devserverurl`标志将覆盖项目配置并作为后续运行的默认值。
|
||||||
|
|||||||
@@ -15,44 +15,44 @@ JS 运行时当前不支持 Dialog。
|
|||||||
|
|
||||||
### 打开选择目录对话框
|
### 打开选择目录对话框
|
||||||
|
|
||||||
|
打开一个对话框,提示用户选择目录。可以使用 [打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
||||||
|
|
||||||
Go 方法签名: `OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
|
Go 方法签名: `OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
|
||||||
|
|
||||||
返回值: 所选目录(如果用户取消则为空白)或错误
|
返回值: 所选目录(如果用户取消则为空白)或错误
|
||||||
|
|
||||||
打开一个对话框,提示用户选择目录。可以使用 [打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
|
||||||
|
|
||||||
### 打开选择文件对话框
|
### 打开选择文件对话框
|
||||||
|
|
||||||
|
打开一个对话框,提示用户选择文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
||||||
|
|
||||||
Go 方法签名: `OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
|
Go 方法签名: `OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
|
||||||
|
|
||||||
返回值: 所选文件(如果用户取消则为空白)或错误
|
返回值: 所选文件(如果用户取消则为空白)或错误
|
||||||
|
|
||||||
打开一个对话框,提示用户选择文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
|
||||||
|
|
||||||
### 打开选择多个文件对话框
|
### 打开选择多个文件对话框
|
||||||
|
|
||||||
|
打开一个对话框,提示用户选择多个文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
||||||
|
|
||||||
Go 方法签名: `OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error)`
|
Go 方法签名: `OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error)`
|
||||||
|
|
||||||
返回值: 选定的文件(如果用户取消则为零)或错误
|
返回值: 选定的文件(如果用户取消则为零)或错误
|
||||||
|
|
||||||
打开一个对话框,提示用户选择多个文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
|
|
||||||
|
|
||||||
### 保存文件对话框
|
### 保存文件对话框
|
||||||
|
|
||||||
|
打开一个对话框,提示用户选择文件名以进行保存。可以使用[保存文件对话框参数选项](#保存文件对话框参数选项)自定义。
|
||||||
|
|
||||||
Go 方法签名: `SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error)`
|
Go 方法签名: `SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error)`
|
||||||
|
|
||||||
返回值: 所选文件(如果用户取消则为空白)或错误
|
返回值: 所选文件(如果用户取消则为空白)或错误
|
||||||
|
|
||||||
打开一个对话框,提示用户选择文件名以进行保存。可以使用[保存文件对话框参数选项](#保存文件对话框参数选项)自定义。
|
|
||||||
|
|
||||||
### 消息对话框
|
### 消息对话框
|
||||||
|
|
||||||
|
使用消息对话框显示消息。可以使用[消息对话框参数选项](#消息对话框参数选项)进行自定义。
|
||||||
|
|
||||||
Go 方法签名: `MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error)`
|
Go 方法签名: `MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error)`
|
||||||
|
|
||||||
返回值: 所选按钮的文本或错误
|
返回值: 所选按钮的文本或错误
|
||||||
|
|
||||||
使用消息对话框显示消息。可以使用[消息对话框参数选项](#消息对话框参数选项)进行自定义。
|
|
||||||
|
|
||||||
## 参数选项
|
## 参数选项
|
||||||
|
|
||||||
### 打开选择文件对话框参数选项
|
### 打开选择文件对话框参数选项
|
||||||
@@ -63,15 +63,28 @@ type OpenDialogOptions struct {
|
|||||||
DefaultFilename string
|
DefaultFilename string
|
||||||
Title string
|
Title string
|
||||||
Filters []FileFilter
|
Filters []FileFilter
|
||||||
AllowFiles bool // Mac Only
|
AllowFiles bool
|
||||||
AllowDirectories bool // Mac Only
|
AllowDirectories bool
|
||||||
ShowHiddenFiles bool // Mac Only
|
ShowHiddenFiles bool
|
||||||
CanCreateDirectories bool // Mac Only
|
CanCreateDirectories bool
|
||||||
ResolvesAliases bool // Mac Only
|
ResolvesAliases bool
|
||||||
TreatPackagesAsDirectories bool // Mac Only
|
TreatPackagesAsDirectories bool
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| 字段 | 描述 | Win | Mac |
|
||||||
|
| -------------------------- | --------------------------------- | --- | --- |
|
||||||
|
| DefaultDirectory | 对话框打开时显示的目录 | ✅ | ✅ |
|
||||||
|
| DefaultFilename | 默认文件名 | ✅ | ✅ |
|
||||||
|
| Title | 对话框的标题 | ✅ | ✅ |
|
||||||
|
| [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ |
|
||||||
|
| AllowFiles | 允许选择文件 | | ✅ |
|
||||||
|
| AllowDirectories | 允许选择目录 | | ✅ |
|
||||||
|
| ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ |
|
||||||
|
| CanCreateDirectories | 允许用户创建目录 | | ✅ |
|
||||||
|
| ResolvesAliases | 如果为 true,则返回文件而不是别名 | | ✅ |
|
||||||
|
| TreatPackagesAsDirectories | 允许导航到包 | | ✅ |
|
||||||
|
|
||||||
### 保存文件对话框参数选项
|
### 保存文件对话框参数选项
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -80,12 +93,22 @@ type SaveDialogOptions struct {
|
|||||||
DefaultFilename string
|
DefaultFilename string
|
||||||
Title string
|
Title string
|
||||||
Filters []FileFilter
|
Filters []FileFilter
|
||||||
ShowHiddenFiles bool // Mac Only
|
ShowHiddenFiles bool
|
||||||
CanCreateDirectories bool // Mac Only
|
CanCreateDirectories bool
|
||||||
TreatPackagesAsDirectories bool // Mac Only
|
TreatPackagesAsDirectories bool
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| 字段 | 描述 | Win | Mac |
|
||||||
|
| -------------------------- | ---------------------- | --- | --- |
|
||||||
|
| DefaultDirectory | 对话框打开时显示的目录 | ✅ | ✅ |
|
||||||
|
| DefaultFilename | 默认文件名 | ✅ | ✅ |
|
||||||
|
| Title | 对话框的标题 | ✅ | ✅ |
|
||||||
|
| [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ |
|
||||||
|
| ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ |
|
||||||
|
| CanCreateDirectories | 允许用户创建目录 | | ✅ |
|
||||||
|
| TreatPackagesAsDirectories | 允许导航到包 | | ✅ |
|
||||||
|
|
||||||
### 消息对话框参数选项
|
### 消息对话框参数选项
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@@ -94,30 +117,96 @@ type MessageDialogOptions struct {
|
|||||||
Title string
|
Title string
|
||||||
Message string
|
Message string
|
||||||
Buttons []string
|
Buttons []string
|
||||||
DefaultButton string // Mac Only
|
DefaultButton string
|
||||||
CancelButton string // Mac Only
|
CancelButton string
|
||||||
Icon string // Mac Only
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
import Tabs from "@theme/Tabs";
|
| 字段 | 描述 | Win | Mac |
|
||||||
import TabItem from "@theme/TabItem";
|
| ------------- | ---------------------------------------------------- | --- | --- |
|
||||||
|
| Type | 消息对话框的类型,例如问题、信息... | ✅ | ✅ |
|
||||||
|
| Title | 对话框的标题 | ✅ | ✅ |
|
||||||
|
| Message | 向用户显示的消息 | ✅ | ✅ |
|
||||||
|
| Buttons | 按钮标题列表 | | ✅ |
|
||||||
|
| DefaultButton | 带有此文本的按钮应被视为默认按钮。 Bound to `return` | | ✅ |
|
||||||
|
| CancelButton | 带有此文本的按钮应被视为取消。Bound to `escape` | | ✅ |
|
||||||
|
|
||||||
<Tabs
|
#### Windows
|
||||||
defaultValue="Windows"
|
|
||||||
values={[
|
Windows 具有标准对话框类型,其中的按钮不可自定义。
|
||||||
{ label: "Windows", value: "Windows" },
|
返回的值将是以下之一:"Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "Try Again" or "Continue"
|
||||||
{ label: "MacOS", value: "MacOS" },
|
|
||||||
{ label: "Linux", value: "Linux" },
|
#### Mac
|
||||||
]}
|
|
||||||
>
|
Mac 上的消息对话框最多可以指定 4 个按钮。如果没有`DefaultButton`或`CancelButton`给出,第一个按钮被认为是默认的并绑定到`return`键。
|
||||||
<TabItem value="Windows">
|
|
||||||
Windows
|
对于以下代码:
|
||||||
具有标准对话框类型并且按钮不可定制。返回的值将是以下之一:“确定”、“取消”、“中止”、“重试”、“忽略”、“是”、“否”、“再试一次”或“继续”
|
|
||||||
</TabItem>
|
```go
|
||||||
<TabItem value="MacOS">“DefaultButton”和“CancelButton”都应与“Buttons”中的值匹配。</TabItem>
|
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
|
||||||
<TabItem value="Linux">即将推出...</TabItem>
|
Title: "It's your turn!",
|
||||||
</Tabs>
|
Message: "Select a number",
|
||||||
|
Buttons: []string{"one", "two", "three", "four"},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
第一个按钮显示为默认值:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img
|
||||||
|
src="/img/runtime/dialog_no_defaults.png"
|
||||||
|
width="30%"
|
||||||
|
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
如果我们指定`DefaultButton`为“two”:
|
||||||
|
|
||||||
|
```go
|
||||||
|
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
|
||||||
|
Title: "It's your turn!",
|
||||||
|
Message: "Select a number",
|
||||||
|
Buttons: []string{"one", "two", "three", "four"},
|
||||||
|
DefaultButton: "two",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
第二个按钮显示为默认值。当 `return` 被按下时,则返回数值“two”。
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img
|
||||||
|
src="/img/runtime/dialog_default_button.png"
|
||||||
|
width="30%"
|
||||||
|
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
如果我们现在指定`CancelButton`为“three”:
|
||||||
|
|
||||||
|
```go
|
||||||
|
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
|
||||||
|
Title: "It's your turn!",
|
||||||
|
Message: "Select a number",
|
||||||
|
Buttons: []string{"one", "two", "three", "four"},
|
||||||
|
DefaultButton: "two",
|
||||||
|
CancelButton: "three",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
带有“three”的按钮显示在对话框的底部。当`escape`被按下时,则返回值“three”:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img
|
||||||
|
src="/img/runtime/dialog_default_cancel.png"
|
||||||
|
width="30%"
|
||||||
|
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
#### 对话框类型
|
#### 对话框类型
|
||||||
|
|
||||||
@@ -138,3 +227,41 @@ type FileFilter struct {
|
|||||||
Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png"
|
Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
Windows 允许您在对话框中使用多个文件过滤器。每个 FileFilter 将在对话框中显示为一个单独的条目:
|
||||||
|
|
||||||
|
<div class="text--center">
|
||||||
|
<img
|
||||||
|
src="/img/runtime/dialog_win_filters.png"
|
||||||
|
width="50%"
|
||||||
|
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
#### Mac
|
||||||
|
|
||||||
|
Mac 对话框只有一组模式来过滤文件的概念。如果提供了多个 FileFilters,Wails 将使用所有定义的模式。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```go
|
||||||
|
selection, err := runtime.OpenFileDialog(b.ctx, runtime.OpenDialogOptions{
|
||||||
|
Title: "Select File",
|
||||||
|
Filters: []runtime.FileFilter{
|
||||||
|
{
|
||||||
|
DisplayName: "Images (*.png;*.jpg)",
|
||||||
|
Pattern: "*.png;*.jpg",
|
||||||
|
}, {
|
||||||
|
DisplayName: "Videos (*.mov;*.mp4)",
|
||||||
|
Pattern: "*.mov;*.mp4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
这将导致使用`*.png,*.jpg,*.mov,*.mp4`作为过滤器打开文件对话框。
|
||||||
|
|||||||
BIN
website/static/img/build-cross-windows.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
website/static/img/build-darwin-amd.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
website/static/img/build-darwin-arm.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
website/static/img/build-darwin-universal.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<svg width="50%" height="50%" viewBox="0 0 150 124" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
<svg width="50%" height="50%" viewBox="0 0 150 150" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
<g transform="matrix(1.2207,0,0,1.21688,0,0)">
|
<g transform="matrix(1.2207,0,0,1.21688,0,0)">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<svg width="50%" height="50%" viewBox="0 0 150 125" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
<svg width="50%" height="50%" viewBox="0 0 150 150" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
<g transform="matrix(1.2207,0,0,1.21688,0,0)">
|
<g transform="matrix(1.2207,0,0,1.21688,0,0)">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
BIN
website/static/img/reference/about-dialog.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
website/static/img/reference/about-menu.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
website/static/img/reference/titlebar-default.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
website/static/img/reference/titlebar-hidden-inset.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
website/static/img/reference/titlebar-hidden.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
website/static/img/remote-mac.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
website/static/img/wails-mac.png
Normal file
|
After Width: | Height: | Size: 514 KiB |
BIN
website/static/img/wails-menus-mac.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |