mirror of
https://github.com/taigrr/wails.git
synced 2026-04-14 10:50:53 -07:00
Compare commits
36 Commits
419-better
...
443---ldfl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03200edd52 | ||
|
|
bbc16fe03a | ||
|
|
bdfc3ca631 | ||
|
|
490d66cf77 | ||
|
|
bce686d779 | ||
|
|
c0b0ef0200 | ||
|
|
8e869baed7 | ||
|
|
7522428d5c | ||
|
|
bc570999e8 | ||
|
|
393a4fceb2 | ||
|
|
da20bcc8d2 | ||
|
|
b091baa16f | ||
|
|
ecaaafa9d9 | ||
|
|
0009da9585 | ||
|
|
6235e83677 | ||
|
|
9f93e7d979 | ||
|
|
949bc40317 | ||
|
|
81777f29d8 | ||
|
|
5d35dd3105 | ||
|
|
ad034d3950 | ||
|
|
98337df92d | ||
|
|
9cc417cf04 | ||
|
|
030b954971 | ||
|
|
7a3ab27977 | ||
|
|
0e6265a9d7 | ||
|
|
b003a080b0 | ||
|
|
376ba743f4 | ||
|
|
aa8ffff68d | ||
|
|
613a44af5e | ||
|
|
2e15c4e045 | ||
|
|
421c13805d | ||
|
|
cc204ab1f7 | ||
|
|
a94a1a9fcb | ||
|
|
e860bd06ec | ||
|
|
a8ecc1e872 | ||
|
|
79188c503f |
@@ -27,3 +27,5 @@ Wails is what it is because of the time and effort given by these great people.
|
|||||||
* [Jarek](https://github.com/Jarek-SRT)
|
* [Jarek](https://github.com/Jarek-SRT)
|
||||||
* [Konez2k](https://github.com/konez2k)
|
* [Konez2k](https://github.com/konez2k)
|
||||||
* [msms](https://github.com/sayuthisobri)
|
* [msms](https://github.com/sayuthisobri)
|
||||||
|
* [dedo1911](https://github.com/dedo1911)
|
||||||
|
* [Florian Didron](https://github.com/fdidron)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ _Debian: 8, 9, 10_
|
|||||||
|
|
||||||
_Ubuntu: 16.04, 18.04, 19.04_
|
_Ubuntu: 16.04, 18.04, 19.04_
|
||||||
|
|
||||||
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_
|
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS
|
||||||
|
|
||||||
#### Arch Linux / ArchLabs
|
#### Arch Linux / ArchLabs
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -561,6 +561,11 @@ func ldFlags(po *ProjectOptions, buildMode string) string {
|
|||||||
|
|
||||||
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
||||||
|
|
||||||
|
// Add additional ldflags passed in via the `ldflags` cli flag
|
||||||
|
if len(po.LdFlags) > 0 {
|
||||||
|
ldflags += " " + po.LdFlags
|
||||||
|
}
|
||||||
|
|
||||||
// If we wish to generate typescript
|
// If we wish to generate typescript
|
||||||
if po.typescriptDefsFilename != "" {
|
if po.typescriptDefsFilename != "" {
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
|
|||||||
27
cmd/linux.go
27
cmd/linux.go
@@ -59,6 +59,10 @@ const (
|
|||||||
Leap
|
Leap
|
||||||
// ArchLabs distribution
|
// ArchLabs distribution
|
||||||
ArchLabs
|
ArchLabs
|
||||||
|
// PopOS distribution
|
||||||
|
PopOS
|
||||||
|
// Solus distribution
|
||||||
|
Solus
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistroInfo contains all the information relating to a linux distribution
|
// DistroInfo contains all the information relating to a linux distribution
|
||||||
@@ -107,7 +111,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
}
|
}
|
||||||
switch splitLine[0] {
|
switch splitLine[0] {
|
||||||
case "ID":
|
case "ID":
|
||||||
osID = strings.Trim(splitLine[1], "\"")
|
osID = strings.ToLower(strings.Trim(splitLine[1], "\""))
|
||||||
case "NAME":
|
case "NAME":
|
||||||
osNAME = strings.Trim(splitLine[1], "\"")
|
osNAME = strings.Trim(splitLine[1], "\"")
|
||||||
case "VERSION_ID":
|
case "VERSION_ID":
|
||||||
@@ -116,7 +120,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check distro name against list of distros
|
// Check distro name against list of distros
|
||||||
switch strings.ToLower(osID) {
|
switch osID {
|
||||||
case "fedora":
|
case "fedora":
|
||||||
result.Distribution = Fedora
|
result.Distribution = Fedora
|
||||||
case "centos":
|
case "centos":
|
||||||
@@ -159,6 +163,10 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
|||||||
result.Distribution = Tumbleweed
|
result.Distribution = Tumbleweed
|
||||||
case "opensuse-leap":
|
case "opensuse-leap":
|
||||||
result.Distribution = Leap
|
result.Distribution = Leap
|
||||||
|
case "pop":
|
||||||
|
result.Distribution = PopOS
|
||||||
|
case "solus":
|
||||||
|
result.Distribution = Solus
|
||||||
default:
|
default:
|
||||||
result.Distribution = Unknown
|
result.Distribution = Unknown
|
||||||
}
|
}
|
||||||
@@ -195,6 +203,17 @@ func DpkgInstalled(packageName string) (bool, error) {
|
|||||||
return exitCode == 0, nil
|
return exitCode == 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EOpkgInstalled uses dpkg to see if a package is installed
|
||||||
|
func EOpkgInstalled(packageName string) (bool, error) {
|
||||||
|
program := NewProgramHelper()
|
||||||
|
eopkg := program.FindProgram("eopkg")
|
||||||
|
if eopkg == nil {
|
||||||
|
return false, fmt.Errorf("cannot check dependencies: eopkg not found")
|
||||||
|
}
|
||||||
|
stdout, _, _, _ := eopkg.Run("info", packageName)
|
||||||
|
return strings.HasPrefix(stdout, "Installed"), nil
|
||||||
|
}
|
||||||
|
|
||||||
// PacmanInstalled uses pacman to see if a package is installed.
|
// PacmanInstalled uses pacman to see if a package is installed.
|
||||||
func PacmanInstalled(packageName string) (bool, error) {
|
func PacmanInstalled(packageName string) (bool, error) {
|
||||||
program := NewProgramHelper()
|
program := NewProgramHelper()
|
||||||
@@ -266,5 +285,9 @@ func RequestSupportForDistribution(distroInfo *DistroInfo) error {
|
|||||||
|
|
||||||
fmt.Println("Opening browser to file request.")
|
fmt.Println("Opening browser to file request.")
|
||||||
browser.OpenURL(fullURL + url.PathEscape(params))
|
browser.OpenURL(fullURL + url.PathEscape(params))
|
||||||
|
result = Prompt("We have a guide for adding support for your distribution. Would you like to view it?", "yes")
|
||||||
|
if strings.ToLower(result) == "yes" {
|
||||||
|
browser.OpenURL("https://wails.app/guides/distro/")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ distributions:
|
|||||||
gccversioncommand: &gccdumpfullversion -dumpfullversion
|
gccversioncommand: &gccdumpfullversion -dumpfullversion
|
||||||
programs: *debiandefaultprograms
|
programs: *debiandefaultprograms
|
||||||
libraries: *debiandefaultlibraries
|
libraries: *debiandefaultlibraries
|
||||||
|
pop:
|
||||||
|
id: pop
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Pop!_OS
|
||||||
|
gccversioncommand: &gccdumpfullversion -dumpfullversion
|
||||||
|
programs: *debiandefaultprograms
|
||||||
|
libraries: *debiandefaultlibraries
|
||||||
kali:
|
kali:
|
||||||
id: kali
|
id: kali
|
||||||
releases:
|
releases:
|
||||||
@@ -232,6 +241,25 @@ distributions:
|
|||||||
gccversioncommand: *gccdumpfullversion
|
gccversioncommand: *gccdumpfullversion
|
||||||
programs: *debiandefaultprograms
|
programs: *debiandefaultprograms
|
||||||
libraries: *debiandefaultlibraries
|
libraries: *debiandefaultlibraries
|
||||||
|
solus:
|
||||||
|
id: solus
|
||||||
|
releases:
|
||||||
|
default:
|
||||||
|
version: default
|
||||||
|
name: Solus
|
||||||
|
gccversioncommand: *gccdumpfullversion
|
||||||
|
programs: &solusdefaultprograms
|
||||||
|
- name: gcc
|
||||||
|
help: Please install with `sudo eopkg it -c system.devel` and try again
|
||||||
|
- name: pkg-config
|
||||||
|
help: Please install with `sudo eopkg it -c system.devel` and try again
|
||||||
|
- name: npm
|
||||||
|
help: Please install with `sudo eopkg it nodejs` and try again
|
||||||
|
libraries: &solusdefaultlibraries
|
||||||
|
- name: libgtk-3-devel
|
||||||
|
help: Please install with `sudo eopkg it libgtk-3-devel` and try again
|
||||||
|
- name: libwebkit-gtk-devel
|
||||||
|
help: Please install with `sudo eopkg it libwebkit-gtk-devel` and try again
|
||||||
|
|
||||||
opensuse-tumbleweed:
|
opensuse-tumbleweed:
|
||||||
id: opensuse-tumbleweed
|
id: opensuse-tumbleweed
|
||||||
|
|||||||
131
cmd/package.go
131
cmd/package.go
@@ -1,9 +1,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"image/png"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -14,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackmordaunt/icns"
|
"github.com/jackmordaunt/icns"
|
||||||
|
"golang.org/x/image/draw"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PackageHelper helps with the 'wails package' command
|
// PackageHelper helps with the 'wails package' command
|
||||||
@@ -55,6 +59,111 @@ func newPlistData(title, exe, packageID, version, author string) *plistData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type windowsIcoHeader struct {
|
||||||
|
_ uint16
|
||||||
|
imageType uint16
|
||||||
|
imageCount uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type windowsIcoDescriptor struct {
|
||||||
|
width uint8
|
||||||
|
height uint8
|
||||||
|
colours uint8
|
||||||
|
_ uint8
|
||||||
|
planes uint16
|
||||||
|
bpp uint16
|
||||||
|
size uint32
|
||||||
|
offset uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type windowsIcoContainer struct {
|
||||||
|
Header windowsIcoDescriptor
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateWindowsIcon(pngFilename string, iconfile string) error {
|
||||||
|
sizes := []int{256, 128, 64, 48, 32, 16}
|
||||||
|
|
||||||
|
pngfile, err := os.Open(pngFilename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer pngfile.Close()
|
||||||
|
|
||||||
|
pngdata, err := png.Decode(pngfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
icons := []windowsIcoContainer{}
|
||||||
|
|
||||||
|
for _, size := range sizes {
|
||||||
|
rect := image.Rect(0, 0, int(size), int(size))
|
||||||
|
rawdata := image.NewRGBA(rect)
|
||||||
|
scale := draw.CatmullRom
|
||||||
|
scale.Scale(rawdata, rect, pngdata, pngdata.Bounds(), draw.Over, nil)
|
||||||
|
|
||||||
|
icondata := new(bytes.Buffer)
|
||||||
|
writer := bufio.NewWriter(icondata)
|
||||||
|
err = png.Encode(writer, rawdata)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
writer.Flush()
|
||||||
|
|
||||||
|
imgSize := size
|
||||||
|
if imgSize >= 256 {
|
||||||
|
imgSize = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data := icondata.Bytes()
|
||||||
|
|
||||||
|
icn := windowsIcoContainer{
|
||||||
|
Header: windowsIcoDescriptor{
|
||||||
|
width: uint8(imgSize),
|
||||||
|
height: uint8(imgSize),
|
||||||
|
planes: 1,
|
||||||
|
bpp: 32,
|
||||||
|
size: uint32(len(data)),
|
||||||
|
},
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
icons = append(icons, icn)
|
||||||
|
}
|
||||||
|
|
||||||
|
outfile, err := os.Create(iconfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outfile.Close()
|
||||||
|
|
||||||
|
ico := windowsIcoHeader{
|
||||||
|
imageType: 1,
|
||||||
|
imageCount: uint16(len(sizes)),
|
||||||
|
}
|
||||||
|
err = binary.Write(outfile, binary.LittleEndian, ico)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := uint32(6 + 16*len(sizes))
|
||||||
|
for _, icon := range icons {
|
||||||
|
icon.Header.offset = offset
|
||||||
|
err = binary.Write(outfile, binary.LittleEndian, icon.Header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
offset += icon.Header.size
|
||||||
|
}
|
||||||
|
for _, icon := range icons {
|
||||||
|
_, err = outfile.Write(icon.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func defaultString(val string, defaultVal string) string {
|
func defaultString(val string, defaultVal string) string {
|
||||||
if val != "" {
|
if val != "" {
|
||||||
return val
|
return val
|
||||||
@@ -177,14 +286,16 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
|||||||
outputDir := b.fs.Cwd()
|
outputDir := b.fs.Cwd()
|
||||||
basename := strings.TrimSuffix(po.BinaryName, ".exe")
|
basename := strings.TrimSuffix(po.BinaryName, ".exe")
|
||||||
|
|
||||||
// Copy icon
|
// Copy default icon if needed
|
||||||
tgtIconFile := filepath.Join(outputDir, basename+".ico")
|
icon, err := b.copyIcon()
|
||||||
if !b.fs.FileExists(tgtIconFile) {
|
if err != nil {
|
||||||
srcIconfile := filepath.Join(b.getPackageFileBaseDir(), "wails.ico")
|
return err
|
||||||
err := b.fs.CopyFile(srcIconfile, tgtIconFile)
|
}
|
||||||
if err != nil {
|
|
||||||
return err
|
// Generate icon from PNG
|
||||||
}
|
err = generateWindowsIcon(icon, po.BinaryName+".ico")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy manifest
|
// Copy manifest
|
||||||
@@ -243,7 +354,7 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *PackageHelper) copyIcon(resourceDir string) (string, error) {
|
func (b *PackageHelper) copyIcon() (string, error) {
|
||||||
|
|
||||||
// TODO: Read this from project.json
|
// TODO: Read this from project.json
|
||||||
const appIconFilename = "appicon.png"
|
const appIconFilename = "appicon.png"
|
||||||
@@ -268,7 +379,7 @@ func (b *PackageHelper) copyIcon(resourceDir string) (string, error) {
|
|||||||
|
|
||||||
func (b *PackageHelper) packageIconOSX(resourceDir string) error {
|
func (b *PackageHelper) packageIconOSX(resourceDir string) error {
|
||||||
|
|
||||||
srcIcon, err := b.copyIcon(resourceDir)
|
srcIcon, err := b.copyIcon()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
100 ICON "$NAME$.ico"
|
100 ICON "$NAME$.ico"
|
||||||
100 24 "$NAME$.exe.manifest"
|
110 24 "$NAME$.exe.manifest"
|
||||||
@@ -161,6 +161,7 @@ type ProjectOptions struct {
|
|||||||
CrossCompile bool
|
CrossCompile bool
|
||||||
Platform string
|
Platform string
|
||||||
Architecture string
|
Architecture string
|
||||||
|
LdFlags string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults sets the default project template
|
// Defaults sets the default project template
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
|
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian:
|
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
|
||||||
libraryChecker = DpkgInstalled
|
libraryChecker = DpkgInstalled
|
||||||
case Arch, ArcoLinux, ArchLabs, Manjaro, ManjaroARM:
|
case Arch, ArcoLinux, ArchLabs, Manjaro, ManjaroARM:
|
||||||
libraryChecker = PacmanInstalled
|
libraryChecker = PacmanInstalled
|
||||||
@@ -284,6 +284,8 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
|||||||
libraryChecker = EqueryInstalled
|
libraryChecker = EqueryInstalled
|
||||||
case VoidLinux:
|
case VoidLinux:
|
||||||
libraryChecker = XbpsInstalled
|
libraryChecker = XbpsInstalled
|
||||||
|
case Solus:
|
||||||
|
libraryChecker = EOpkgInstalled
|
||||||
default:
|
default:
|
||||||
return false, RequestSupportForDistribution(distroInfo)
|
return false, RequestSupportForDistribution(distroInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
5
cmd/templates/vanilla/README.md
Normal file
5
cmd/templates/vanilla/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# README
|
||||||
|
|
||||||
|
This is an experimental template for vanilla HTML/JS/CSS.
|
||||||
|
|
||||||
|
The webpack rules may need to be adjusted to correctly embed all assets. Babel may also need to be setup correctly.
|
||||||
42
cmd/templates/vanilla/frontend/package.json.template
Normal file
42
cmd/templates/vanilla/frontend/package.json.template
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "vanilla",
|
||||||
|
"author": "Lea<l>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "webpack-dev-server",
|
||||||
|
"build": "npx webpack"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": "^3.6.4",
|
||||||
|
"regenerator-runtime": "^0.13.3",
|
||||||
|
"@wailsapp/runtime": "^1.0.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"copy-webpack-plugin": "^6.0.2",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"eventsource-polyfill": "^0.9.6",
|
||||||
|
"webpack": "^4.43.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-dev-server": "^3.11.0",
|
||||||
|
"webpack-hot-middleware": "^2.25.0"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
||||||
9
cmd/templates/vanilla/frontend/src/index.html
Normal file
9
cmd/templates/vanilla/frontend/src/index.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
cmd/templates/vanilla/frontend/src/main.css
Normal file
30
cmd/templates/vanilla/frontend/src/main.css
Normal file
File diff suppressed because one or more lines are too long
28
cmd/templates/vanilla/frontend/src/main.js
Normal file
28
cmd/templates/vanilla/frontend/src/main.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
const runtime = require('@wailsapp/runtime');
|
||||||
|
|
||||||
|
// We need to wait for runtime.Init to complete before
|
||||||
|
// running our JS
|
||||||
|
runtime.Init(() => {
|
||||||
|
|
||||||
|
// Ensure the default app div is 100% wide/high
|
||||||
|
var app = document.getElementById('app');
|
||||||
|
app.style.width = '100%';
|
||||||
|
app.style.height = '100%';
|
||||||
|
|
||||||
|
// Inject html
|
||||||
|
app.innerHTML = `
|
||||||
|
<div class='logo'></div>
|
||||||
|
<div class='container'>
|
||||||
|
<button id='button'>Click Me!</button>
|
||||||
|
<div id='result'/>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Connect button to Go method
|
||||||
|
document.getElementById('button').onclick = () => {
|
||||||
|
window.backend.basic().then((result) => {
|
||||||
|
document.getElementById('result').innerText = result;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
56
cmd/templates/vanilla/frontend/webpack.config.js
Normal file
56
cmd/templates/vanilla/frontend/webpack.config.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
|
let imageSizeLimit = 9007199254740991; // Number.MAX_SAFE_INTEGER
|
||||||
|
let sourceDir = path.resolve(__dirname, 'src');
|
||||||
|
let buildDir = path.resolve(__dirname, 'build');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
index: path.resolve(sourceDir, 'main.js')
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: buildDir,
|
||||||
|
filename: 'main.js'
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: false
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
disableHostCheck: true,
|
||||||
|
contentBase: path.join(__dirname, 'src'),
|
||||||
|
compress: true,
|
||||||
|
open: true,
|
||||||
|
port: 8090
|
||||||
|
},
|
||||||
|
mode: 'production',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(png|gif|jpg|woff2?|eot|ttf|otf|svg)(\?.*)?$/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: imageSizeLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
from: path.resolve(sourceDir, 'main.css'),
|
||||||
|
to: path.resolve(buildDir, 'main.css')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: path.resolve(sourceDir, 'index.html'),
|
||||||
|
to: path.resolve(buildDir, 'index.html')
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
5
cmd/templates/vanilla/go.mod.template
Normal file
5
cmd/templates/vanilla/go.mod.template
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module {{.BinaryName}}
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/wailsapp/wails {{.WailsVersion}}
|
||||||
|
)
|
||||||
27
cmd/templates/vanilla/main.go.template
Normal file
27
cmd/templates/vanilla/main.go.template
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails"
|
||||||
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "Hello World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
js := mewn.String("./frontend/build/main.js")
|
||||||
|
css := mewn.String("./frontend/build/main.css")
|
||||||
|
|
||||||
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
Title: "{{.Name}}",
|
||||||
|
JS: js,
|
||||||
|
CSS: css,
|
||||||
|
Colour: "#131313",
|
||||||
|
})
|
||||||
|
app.Bind(basic)
|
||||||
|
app.Run()
|
||||||
|
}
|
||||||
12
cmd/templates/vanilla/template.json
Normal file
12
cmd/templates/vanilla/template.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "Vanilla",
|
||||||
|
"shortdescription": "A Vanilla HTML/JS template",
|
||||||
|
"description": "A basic template using plain html/js and bundled using Webpack 4",
|
||||||
|
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
||||||
|
"created": "2020-06-14",
|
||||||
|
"frontenddir": "frontend",
|
||||||
|
"install": "npm install",
|
||||||
|
"build": "npm run build",
|
||||||
|
"serve": "npm run serve",
|
||||||
|
"bridge": "src"
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v1.6.0-pre2"
|
const Version = "v1.6.0"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ func init() {
|
|||||||
var typescriptFilename = ""
|
var typescriptFilename = ""
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var platform = ""
|
var platform = ""
|
||||||
|
var ldflags = ""
|
||||||
|
|
||||||
buildSpinner := spinner.NewSpinner()
|
buildSpinner := spinner.NewSpinner()
|
||||||
buildSpinner.SetSpinSpeed(50)
|
buildSpinner.SetSpinSpeed(50)
|
||||||
@@ -40,7 +41,8 @@ func init() {
|
|||||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||||
BoolFlag("d", "Build in Debug mode", &debugMode).
|
BoolFlag("d", "Build in Debug mode", &debugMode).
|
||||||
BoolFlag("verbose", "Verbose output", &verbose).
|
BoolFlag("verbose", "Verbose output", &verbose).
|
||||||
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename)
|
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
|
||||||
|
StringFlag("ldflags", "Extra options for -ldflags", &ldflags)
|
||||||
|
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, plat := range getSupportedPlatforms() {
|
for _, plat := range getSupportedPlatforms() {
|
||||||
@@ -84,7 +86,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !supported {
|
if !supported {
|
||||||
return fmt.Errorf("Unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options.", platform)
|
return fmt.Errorf("unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options", platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
projectOptions.CrossCompile = true
|
projectOptions.CrossCompile = true
|
||||||
@@ -93,6 +95,9 @@ func init() {
|
|||||||
projectOptions.Architecture = plat[1]
|
projectOptions.Architecture = plat[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add ldflags
|
||||||
|
projectOptions.LdFlags = ldflags
|
||||||
|
|
||||||
// Validate config
|
// Validate config
|
||||||
// Check if we have a frontend
|
// Check if we have a frontend
|
||||||
err = cmd.ValidateFrontendConfig(projectOptions)
|
err = cmd.ValidateFrontendConfig(projectOptions)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
"github.com/wailsapp/wails/cmd"
|
"github.com/wailsapp/wails/cmd"
|
||||||
@@ -34,7 +35,6 @@ func init() {
|
|||||||
|
|
||||||
// Project options
|
// Project options
|
||||||
projectOptions := &cmd.ProjectOptions{}
|
projectOptions := &cmd.ProjectOptions{}
|
||||||
projectOptions.Verbose = verbose
|
|
||||||
|
|
||||||
// Check we are in project directory
|
// Check we are in project directory
|
||||||
// Check project.json loads correctly
|
// Check project.json loads correctly
|
||||||
@@ -44,6 +44,10 @@ func init() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set project options
|
||||||
|
projectOptions.Verbose = verbose
|
||||||
|
projectOptions.Platform = runtime.GOOS
|
||||||
|
|
||||||
// Save project directory
|
// Save project directory
|
||||||
projectDir := fs.Cwd()
|
projectDir := fs.Cwd()
|
||||||
|
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -22,6 +22,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.3.0 // indirect
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
|
||||||
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
|
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862
|
||||||
golang.org/x/text v0.3.0
|
golang.org/x/text v0.3.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -70,6 +70,8 @@ golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
||||||
|
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak=
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak=
|
||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ type Renderer interface {
|
|||||||
NotifyEvent(eventData *messages.EventData) error
|
NotifyEvent(eventData *messages.EventData) error
|
||||||
|
|
||||||
// Dialog Runtime
|
// Dialog Runtime
|
||||||
SelectFile() string
|
SelectFile(title string, filter string) string
|
||||||
SelectDirectory() string
|
SelectDirectory() string
|
||||||
SelectSaveFile() string
|
SelectSaveFile(title string, filter string) string
|
||||||
|
|
||||||
// Window Runtime
|
// Window Runtime
|
||||||
SetColour(string) error
|
SetColour(string) error
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func (h *Bridge) NewBinding(methodName string) error {
|
|||||||
|
|
||||||
// SelectFile is unsupported for Bridge but required
|
// SelectFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Bridge) SelectFile() string {
|
func (h *Bridge) SelectFile(title string, filter string) string {
|
||||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ func (h *Bridge) SelectDirectory() string {
|
|||||||
|
|
||||||
// SelectSaveFile is unsupported for Bridge but required
|
// SelectSaveFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Bridge) SelectSaveFile() string {
|
func (h *Bridge) SelectSaveFile(title string, filter string) string {
|
||||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -245,7 +245,7 @@ func (w *WebView) NewBinding(methodName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile opens a dialog that allows the user to select a file
|
// SelectFile opens a dialog that allows the user to select a file
|
||||||
func (w *WebView) SelectFile() string {
|
func (w *WebView) SelectFile(title string, filter string) string {
|
||||||
var result string
|
var result string
|
||||||
|
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
@@ -255,7 +255,7 @@ func (w *WebView) SelectFile() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeOpen, 0, "Select File", "")
|
result = w.window.Dialog(wv.DialogTypeOpen, 0, title, "", filter)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -273,7 +273,7 @@ func (w *WebView) SelectDirectory() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "")
|
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "", "")
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
@@ -282,7 +282,7 @@ func (w *WebView) SelectDirectory() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
||||||
func (w *WebView) SelectSaveFile() string {
|
func (w *WebView) SelectSaveFile(title string, filter string) string {
|
||||||
var result string
|
var result string
|
||||||
// We need to run this on the main thread, however Dispatch is
|
// We need to run this on the main thread, however Dispatch is
|
||||||
// non-blocking so we launch this in a goroutine and wait for
|
// non-blocking so we launch this in a goroutine and wait for
|
||||||
@@ -291,7 +291,7 @@ func (w *WebView) SelectSaveFile() string {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
result = w.window.Dialog(wv.DialogTypeSave, 0, "Save file", "")
|
result = w.window.Dialog(wv.DialogTypeSave, 0, title, "", filter)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
||||||
char *title, char *arg, char *res, size_t ressz) {
|
char *title, char *arg, char *res, size_t ressz, char *filter) {
|
||||||
webview_dialog(w, dlgtype, flags,
|
webview_dialog(w, dlgtype, flags,
|
||||||
(const char*)title, (const char*) arg, res, ressz);
|
(const char*)title, (const char*) arg, res, ressz, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int CgoWebViewEval(void *w, char *js) {
|
static inline int CgoWebViewEval(void *w, char *js) {
|
||||||
@@ -186,7 +186,7 @@ type WebView interface {
|
|||||||
// Dialog() opens a system dialog of the given type and title. String
|
// Dialog() opens a system dialog of the given type and title. String
|
||||||
// argument can be provided for certain dialogs, such as alert boxes. For
|
// argument can be provided for certain dialogs, such as alert boxes. For
|
||||||
// alert boxes argument is a message inside the dialog box.
|
// alert boxes argument is a message inside the dialog box.
|
||||||
Dialog(dlgType DialogType, flags int, title string, arg string) string
|
Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string
|
||||||
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
||||||
// only. See Dispatch() for more details.
|
// only. See Dispatch() for more details.
|
||||||
Terminate()
|
Terminate()
|
||||||
@@ -311,7 +311,7 @@ func (w *webview) SetFullscreen(fullscreen bool) {
|
|||||||
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string {
|
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string {
|
||||||
const maxPath = 4096
|
const maxPath = 4096
|
||||||
titlePtr := C.CString(title)
|
titlePtr := C.CString(title)
|
||||||
defer C.free(unsafe.Pointer(titlePtr))
|
defer C.free(unsafe.Pointer(titlePtr))
|
||||||
@@ -319,8 +319,10 @@ func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string
|
|||||||
defer C.free(unsafe.Pointer(argPtr))
|
defer C.free(unsafe.Pointer(argPtr))
|
||||||
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
||||||
defer C.free(unsafe.Pointer(resultPtr))
|
defer C.free(unsafe.Pointer(resultPtr))
|
||||||
|
filterPtr := C.CString(filter)
|
||||||
|
defer C.free(unsafe.Pointer(filterPtr))
|
||||||
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
||||||
argPtr, resultPtr, C.size_t(maxPath))
|
argPtr, resultPtr, C.size_t(maxPath), filterPtr)
|
||||||
return C.GoString(resultPtr)
|
return C.GoString(resultPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz);
|
char *result, size_t resultsz, char *filter);
|
||||||
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
|
||||||
void *arg);
|
void *arg);
|
||||||
WEBVIEW_API void webview_terminate(struct webview *w);
|
WEBVIEW_API void webview_terminate(struct webview *w);
|
||||||
@@ -418,7 +418,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz)
|
char *result, size_t resultsz, char *filter)
|
||||||
{
|
{
|
||||||
GtkWidget *dlg;
|
GtkWidget *dlg;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
@@ -438,6 +438,16 @@ struct webview_priv
|
|||||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||||
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
|
||||||
GTK_RESPONSE_ACCEPT, NULL);
|
GTK_RESPONSE_ACCEPT, NULL);
|
||||||
|
if (filter[0] != '\0') {
|
||||||
|
GtkFileFilter *file_filter = gtk_file_filter_new();
|
||||||
|
gchar **filters = g_strsplit(filter, ",", -1);
|
||||||
|
gint i;
|
||||||
|
for(i = 0; filters && filters[i]; i++) {
|
||||||
|
gtk_file_filter_add_pattern(file_filter, filters[i]);
|
||||||
|
}
|
||||||
|
gtk_file_filter_set_name(file_filter, filter);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dlg), file_filter);
|
||||||
|
}
|
||||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||||
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||||
@@ -1410,6 +1420,8 @@ struct webview_priv
|
|||||||
wc.hInstance = hInstance;
|
wc.hInstance = hInstance;
|
||||||
wc.lpfnWndProc = wndproc;
|
wc.lpfnWndProc = wndproc;
|
||||||
wc.lpszClassName = classname;
|
wc.lpszClassName = classname;
|
||||||
|
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100));
|
||||||
|
wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(100));
|
||||||
RegisterClassEx(&wc);
|
RegisterClassEx(&wc);
|
||||||
|
|
||||||
style = WS_OVERLAPPEDWINDOW;
|
style = WS_OVERLAPPEDWINDOW;
|
||||||
@@ -1780,7 +1792,7 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz)
|
char *result, size_t resultsz, char *filter)
|
||||||
{
|
{
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
||||||
@@ -1820,6 +1832,32 @@ struct webview_priv
|
|||||||
FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
|
FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
|
||||||
FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
|
FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
|
||||||
}
|
}
|
||||||
|
if (filter[0] != '\0')
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
int i=0;
|
||||||
|
char* token;
|
||||||
|
char* filter_dup = strdup(filter);
|
||||||
|
for (count=1; filter[count]; filter[count]==',' ? count++ : *filter++);
|
||||||
|
COMDLG_FILTERSPEC rgSpec[count];
|
||||||
|
char* filters[count];
|
||||||
|
token = strtok(filter_dup, ",");
|
||||||
|
while(token != NULL)
|
||||||
|
{
|
||||||
|
filters[i] = token;
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (int i=0; i < count; i++) {
|
||||||
|
wchar_t *wFilter = (wchar_t *)malloc(4096);
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, filters[i], -1, wFilter, 4096);
|
||||||
|
rgSpec[i].pszName = wFilter;
|
||||||
|
rgSpec[i].pszSpec = wFilter;
|
||||||
|
}
|
||||||
|
if (dlg->lpVtbl->SetFileTypes(dlg, count, rgSpec) != S_OK) {
|
||||||
|
goto error_dlg;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK)
|
if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK)
|
||||||
{
|
{
|
||||||
goto error_dlg;
|
goto error_dlg;
|
||||||
@@ -1938,7 +1976,7 @@ struct webview_priv
|
|||||||
(struct webview *)objc_getAssociatedObject(self, "webview");
|
(struct webview *)objc_getAssociatedObject(self, "webview");
|
||||||
|
|
||||||
webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "",
|
webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "",
|
||||||
filename, 255);
|
filename, 255, "");
|
||||||
filename[255] = '\0';
|
filename[255] = '\0';
|
||||||
if (strlen(filename) > 0)
|
if (strlen(filename) > 0)
|
||||||
{
|
{
|
||||||
@@ -2201,12 +2239,16 @@ struct webview_priv
|
|||||||
WEBVIEW_API void webview_dialog(struct webview *w,
|
WEBVIEW_API void webview_dialog(struct webview *w,
|
||||||
enum webview_dialog_type dlgtype, int flags,
|
enum webview_dialog_type dlgtype, int flags,
|
||||||
const char *title, const char *arg,
|
const char *title, const char *arg,
|
||||||
char *result, size_t resultsz)
|
char *result, size_t resultsz, char *filter)
|
||||||
{
|
{
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
|
||||||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
|
||||||
{
|
{
|
||||||
NSSavePanel *panel;
|
NSSavePanel *panel;
|
||||||
|
NSString *filter_str = [NSString stringWithUTF8String:filter];
|
||||||
|
filter_str = [filter_str stringByReplacingOccurrencesOfString:@"*."
|
||||||
|
withString:@""];
|
||||||
|
NSArray *fileTypes = [filter_str componentsSeparatedByString:@","];
|
||||||
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN)
|
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN)
|
||||||
{
|
{
|
||||||
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
||||||
@@ -2219,6 +2261,10 @@ struct webview_priv
|
|||||||
{
|
{
|
||||||
[openPanel setCanChooseFiles:YES];
|
[openPanel setCanChooseFiles:YES];
|
||||||
[openPanel setCanChooseDirectories:NO];
|
[openPanel setCanChooseDirectories:NO];
|
||||||
|
if(filter[0] != NULL)
|
||||||
|
{
|
||||||
|
[openPanel setAllowedFileTypes:fileTypes];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[openPanel setResolvesAliases:NO];
|
[openPanel setResolvesAliases:NO];
|
||||||
[openPanel setAllowsMultipleSelection:NO];
|
[openPanel setAllowsMultipleSelection:NO];
|
||||||
@@ -2232,6 +2278,10 @@ struct webview_priv
|
|||||||
[panel setShowsHiddenFiles:YES];
|
[panel setShowsHiddenFiles:YES];
|
||||||
[panel setExtensionHidden:NO];
|
[panel setExtensionHidden:NO];
|
||||||
[panel setCanSelectHiddenExtension:NO];
|
[panel setCanSelectHiddenExtension:NO];
|
||||||
|
if(filter[0] != NULL)
|
||||||
|
{
|
||||||
|
[panel setAllowedFileTypes:fileTypes];
|
||||||
|
}
|
||||||
[panel setTreatsFilePackagesAsDirectories:YES];
|
[panel setTreatsFilePackagesAsDirectories:YES];
|
||||||
[panel beginSheetModalForWindow:w->priv.window
|
[panel beginSheetModalForWindow:w->priv.window
|
||||||
completionHandler:^(NSInteger result) {
|
completionHandler:^(NSInteger result) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "github.com/wailsapp/wails/lib/interfaces"
|
import "github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
import "strings"
|
||||||
|
|
||||||
// Dialog exposes an interface to native dialogs
|
// Dialog exposes an interface to native dialogs
|
||||||
type Dialog struct {
|
type Dialog struct {
|
||||||
@@ -15,8 +16,16 @@ func NewDialog(renderer interfaces.Renderer) *Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile prompts the user to select a file
|
// SelectFile prompts the user to select a file
|
||||||
func (r *Dialog) SelectFile() string {
|
func (r *Dialog) SelectFile(params ...string) string {
|
||||||
return r.renderer.SelectFile()
|
title := "Select File"
|
||||||
|
filter := ""
|
||||||
|
if len(params) > 0 {
|
||||||
|
title = params[0]
|
||||||
|
}
|
||||||
|
if len(params) > 1 {
|
||||||
|
filter = strings.Replace(params[1], " ", "", -1)
|
||||||
|
}
|
||||||
|
return r.renderer.SelectFile(title, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectDirectory prompts the user to select a directory
|
// SelectDirectory prompts the user to select a directory
|
||||||
@@ -25,6 +34,14 @@ func (r *Dialog) SelectDirectory() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile prompts the user to select a file for saving
|
// SelectSaveFile prompts the user to select a file for saving
|
||||||
func (r *Dialog) SelectSaveFile() string {
|
func (r *Dialog) SelectSaveFile(params ...string) string {
|
||||||
return r.renderer.SelectSaveFile()
|
title := "Select Save"
|
||||||
|
filter := ""
|
||||||
|
if len(params) > 0 {
|
||||||
|
title = params[0]
|
||||||
|
}
|
||||||
|
if len(params) > 1 {
|
||||||
|
filter = strings.Replace(params[1], " ", "", -1)
|
||||||
|
}
|
||||||
|
return r.renderer.SelectSaveFile(title, filter)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user