// Command mpckit is the desktop kit editor for the MPC Sample. package main import ( "embed" "log" "path/filepath" "strconv" "strings" "github.com/wailsapp/wails/v3/pkg/application" "github.com/wailsapp/wails/v3/pkg/events" "git.monoexp.com/bajdev/mpckit/internal/app" ) // The built Svelte app (frontend/dist), embedded in the binary. // //go:embed all:frontend/dist var assets embed.FS // Window sizes are in device-independent pixels, 16:9 like most displays. const ( maxWidth, maxHeight = 1280, 720 // largest default size minWidth, minHeight = 960, 540 // smallest the layout is designed for screenShare = 0.9 // default size: this share of the screen's work area ) // Events Go sends to the frontend. const ( eventState = "state" // a new app.State after a change the frontend did not ask for eventError = "error" // a message to show ) func init() { application.RegisterEvent[app.State](eventState) application.RegisterEvent[string](eventError) } func main() { d := &dialogs{} svc := app.NewService(d) a := application.New(application.Options{ Name: "mpckit", Description: "Desktop kit editor for the MPC Sample", Services: []application.Service{ application.NewService(svc), }, Assets: application.AssetOptions{ Handler: application.AssetFileServerFS(assets), Middleware: svc.AudioMiddleware, }, Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, }, }) d.a = a // Start hidden and size the window once the screens are known, so it // fits the display instead of being clamped by it. w := a.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "mpckit", Width: maxWidth, Height: maxHeight, MinWidth: minWidth, MinHeight: minHeight, Hidden: true, EnableFileDrop: true, BackgroundColour: application.NewRGB(0x15, 0x17, 0x1A), URL: "/", }) a.Event.OnApplicationEvent(events.Common.ApplicationStarted, func(*application.ApplicationEvent) { if s := a.Screen.GetPrimary(); s != nil { width, height := fitSize(s.WorkArea.Width, s.WorkArea.Height) w.SetSize(width, height) } w.Center() w.Show() }) // A WAV dropped on a pad (an element with data-file-drop-target and // data-slot) is assigned to that pad. w.OnWindowEvent(events.Common.WindowFilesDropped, func(e *application.WindowEvent) { ctx := e.Context() target := ctx.DropTargetDetails() if target == nil { return } slot, err := strconv.Atoi(target.Attributes["data-slot"]) if err != nil { return } for _, f := range ctx.DroppedFiles() { if strings.EqualFold(filepath.Ext(f), ".wav") { st, err := svc.AssignSamplePath(slot, f) a.Event.Emit(eventState, st) if err != nil { a.Event.Emit(eventError, err.Error()) } return } } a.Event.Emit(eventError, "Only WAV files can be assigned to a pad.") }) if err := a.Run(); err != nil { log.Fatal(err) } } // fitSize returns a 16:9 window size that takes screenShare of the work // area (areaW x areaH), capped at maxWidth x maxHeight and no smaller than // minWidth x minHeight. func fitSize(areaW, areaH int) (int, int) { width := min(maxWidth, int(float64(areaW)*screenShare)) height := width * 9 / 16 if limit := int(float64(areaH) * screenShare); height > limit { height = limit width = height * 16 / 9 } return max(width, minWidth), max(height, minHeight) }