naffg.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package naffg
  2. import (
  3. "embed"
  4. "net/http"
  5. "strconv"
  6. webview2 "github.com/jchv/go-webview2"
  7. )
  8. type Application struct {
  9. viewport webview2.WebView
  10. options *Options
  11. backendMutex *http.ServeMux
  12. terminate chan bool
  13. }
  14. type Options struct {
  15. //Basic Settings
  16. Title string
  17. Width int
  18. Height int
  19. Resizable bool //Default is true
  20. InitiateAtCenter bool //Initiate the window at the center of the screen
  21. //WebApp Settings
  22. StartURI string //URI to be loaded in the webview on start, support data://, default is "http://localhost:36850"
  23. //Local App Settings
  24. UiRes *embed.FS //Go embed filesystem for UI resources (e.g. res/), leave empty to use external URI (webApp)
  25. UiResPreix string //Prefix for the UI resources, will trim the prefix before serving the resources (e.g. res/)
  26. //Advance Settings
  27. EventExchangePort int //Port for which the UI events will be exchanged with backend, default is 36850
  28. IconId int //Icon resource id
  29. Debug bool
  30. }
  31. // Create a new Application Window with the given options
  32. func NewApplication(options *Options) *Application {
  33. //Fill in the default values if not provided
  34. if options.Title == "" {
  35. options.Title = "New Application"
  36. }
  37. if options.Width == 0 {
  38. options.Width = 800
  39. }
  40. if options.Height == 0 {
  41. options.Height = 600
  42. }
  43. if options.EventExchangePort == 0 {
  44. options.EventExchangePort = 36850
  45. }
  46. if options.UiRes == nil && options.StartURI == "" {
  47. //Use a missing resource page
  48. options.StartURI = "data:text/html,<html><body><h1>Invalid Usage</h1></body></html>"
  49. }
  50. //Create the webview
  51. w := webview2.NewWithOptions(webview2.WebViewOptions{
  52. Debug: true,
  53. AutoFocus: true,
  54. WindowOptions: webview2.WindowOptions{
  55. Title: options.Title,
  56. Width: uint(options.Width),
  57. Height: uint(options.Height),
  58. IconId: 203, // icon resource id
  59. Center: options.InitiateAtCenter,
  60. },
  61. })
  62. //Create a http mux for backend
  63. mux := http.NewServeMux()
  64. app := &Application{
  65. viewport: w,
  66. options: options,
  67. backendMutex: mux,
  68. terminate: make(chan bool),
  69. }
  70. //Register the UI resources bundle if provided
  71. if options.UiRes != nil {
  72. mux.Handle("/", app.embedFsPrefixMiddleware(http.FileServer(http.FS(options.UiRes))))
  73. }
  74. return app
  75. }
  76. // Run the application
  77. // Note that this cannot be run in a goroutine. It will block the main thread
  78. // until the application is terminated
  79. func (app *Application) Run() {
  80. app.viewport.SetTitle(app.options.Title)
  81. if app.options.Resizable {
  82. app.viewport.SetSize(app.options.Width, app.options.Height, webview2.HintNone)
  83. } else {
  84. app.viewport.SetSize(app.options.Width, app.options.Height, webview2.HintFixed)
  85. }
  86. if app.options.StartURI != "" {
  87. app.viewport.Navigate(app.options.StartURI)
  88. } else {
  89. app.viewport.Navigate("http://localhost:36850")
  90. }
  91. //Start the backend server
  92. go func() {
  93. if err := http.ListenAndServe("localhost:"+strconv.Itoa(app.options.EventExchangePort), app.backendMutex); err != nil {
  94. panic(err)
  95. }
  96. }()
  97. //Run the webview
  98. defer app.viewport.Destroy()
  99. app.viewport.Run()
  100. }
  101. // Terminate the application
  102. func (app *Application) Terminate() {
  103. app.viewport.Destroy()
  104. }