diff --git a/go.mod b/go.mod index b5ad25be..c7bf25ea 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/sqweek/dialog v0.0.0-20220809060634-e981b270ebbf github.com/stretchr/testify v1.8.4 + golang.design/x/clipboard v0.7.0 ) require ( @@ -24,7 +25,9 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.8.0 // indirect + golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect golang.org/x/image v0.7.0 // indirect + golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c // indirect golang.org/x/sys v0.12.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 647d8d47..0da63bab 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk= aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/SpaiR/imgui-go v1.12.1-0.20220214190844-a0bad21e1c5d h1:QajPUffv+BBqNu54DrL/YrO8RP1BGTfGhPNnoPt1ERk= github.com/SpaiR/imgui-go v1.12.1-0.20220214190844-a0bad21e1c5d/go.mod h1:bzOQqDbRE58xRB4EGTlUrIhCTWxNvU7YtJckrFf+HpM= github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I= @@ -42,17 +43,28 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.design/x/clipboard v0.7.0 h1:4Je8M/ys9AJumVnl8m+rZnIvstSnYj1fvzqYrU3TXvo= +golang.design/x/clipboard v0.7.0/go.mod h1:PQIvqYO9GP29yINEfsEn5zSQKAz3UgXmZKzDA6dnq2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c h1:Gk61ECugwEHL6IiyyNLXNzmu8XslmRP2dS0xjIYhbb4= +golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -63,6 +75,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -86,6 +99,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= diff --git a/internal/app/ui/cpwsarea/wsmap/pmap/psettings/config.go b/internal/app/ui/cpwsarea/wsmap/pmap/psettings/config.go index c723a7fd..22df4790 100644 --- a/internal/app/ui/cpwsarea/wsmap/pmap/psettings/config.go +++ b/internal/app/ui/cpwsarea/wsmap/pmap/psettings/config.go @@ -15,6 +15,9 @@ type psettingsConfig struct { Version uint ScreenshotDir string + + InSelectionMode bool + ToClipboardMode bool } func (psettingsConfig) Name() string { @@ -35,7 +38,8 @@ func loadConfig(app App) *psettingsConfig { cfg := &psettingsConfig{ Version: configVersion, - ScreenshotDir: u.HomeDir, + ScreenshotDir: u.HomeDir, + ToClipboardMode: true, } app.ConfigRegister(cfg) return cfg diff --git a/internal/app/ui/cpwsarea/wsmap/pmap/psettings/screenshot.go b/internal/app/ui/cpwsarea/wsmap/pmap/psettings/screenshot.go index 9a53d267..158d96a7 100644 --- a/internal/app/ui/cpwsarea/wsmap/pmap/psettings/screenshot.go +++ b/internal/app/ui/cpwsarea/wsmap/pmap/psettings/screenshot.go @@ -20,30 +20,36 @@ import ( "github.com/SpaiR/imgui-go" "github.com/rs/zerolog/log" "github.com/sqweek/dialog" + "golang.design/x/clipboard" ) type sessionScreenshot struct { - saving bool - inSelectionMode bool + saving bool } func (p *Panel) showScreenshot() { if imgui.CollapsingHeader("Screenshot") { + imgui.BeginDisabledV(cfg.ToClipboardMode) + if imgui.Button(icon.FolderOpen) { p.selectScreenshotDir() } - imguiext.SetItemHoveredTooltip("Screenshot Folder") imgui.SameLine() imgui.SetNextItemWidth(-1) imgui.InputText("##screenshot_dir", &cfg.ScreenshotDir) + imguiext.SetItemHoveredTooltip(cfg.ScreenshotDir) + + imgui.EndDisabled() - if imgui.Checkbox("Screenshot in Selection", &p.sessionScreenshot.inSelectionMode) { + if imgui.Checkbox("Screenshot in Selection", &cfg.InSelectionMode) { tools.SetSelected(tools.TNGrab) } + imgui.Checkbox("To Clipboard", &cfg.ToClipboardMode) + var createBtnLabel string if p.sessionScreenshot.saving { createBtnLabel = "Creating" + []string{".", "..", "...", "...."}[int(imgui.Time()/.25)&3] + "###create" @@ -64,22 +70,24 @@ func (p *Panel) showScreenshot() { func (p *Panel) createScreenshot() { p.sessionScreenshot.saving = true selectedTool := tools.Selected() - grabCurrentlySelected := selectedTool.Name() == tools.TNGrab + boundX, boundY := float32(0), float32(0) + var width, height int - if p.sessionScreenshot.inSelectionMode { - if !grabCurrentlySelected || !selectedTool.(*tools.ToolGrab).HasSelectedArea() { + if cfg.InSelectionMode { + hasSelectedArea := selectedTool.Name() == tools.TNGrab && selectedTool.(*tools.ToolGrab).HasSelectedArea() + if hasSelectedArea { + bounds := selectedTool.(*tools.ToolGrab).Bounds() //get grab tool bounds, so we can calculate boundX and boundY + width, height = (int(bounds.X2-bounds.X1)+1)*dmmap.WorldIconSize, (int(bounds.Y2-bounds.Y1)+1)*dmmap.WorldIconSize + boundX = -float32((int(bounds.X1) - 1) * dmmap.WorldIconSize) //now change bounds so we can use them in Translate + boundY = -float32((int(bounds.Y1) - 1) * dmmap.WorldIconSize) + } else { appdialog.Open(appdialog.TypeInformation{ Title: "Nothing selected!", Information: "Screenshot in Selection is on, but you have nothing selected. Use the grab tool!", }) p.sessionScreenshot.saving = false return - } else { - bounds := selectedTool.(*tools.ToolGrab).Bounds() //get grab tool bounds so we can calculate boundX and boundY - width, height = (int(bounds.X2-bounds.X1)+1)*dmmap.WorldIconSize, (int(bounds.Y2-bounds.Y1)+1)*dmmap.WorldIconSize - boundX = -float32((int(bounds.X1) - 1) * dmmap.WorldIconSize) //now change bounds so we can use them in Translate - boundY = -float32((int(bounds.Y1) - 1) * dmmap.WorldIconSize) } } else { width, height = p.editor.Dmm().MaxX*dmmap.WorldIconSize, p.editor.Dmm().MaxY*dmmap.WorldIconSize @@ -99,7 +107,7 @@ func (p *Panel) createScreenshot() { var pixels = c.ReadPixels() go func() { - if err := saveScreenshot(pixels, width, height); err != nil { + if err := p.saveScreenshot(pixels, width, height); err != nil { appdialog.Open(appdialog.TypeInformation{ Title: "Error: Screenshot Creation", Information: fmt.Sprint("Unable to create screenshot:", err), @@ -124,14 +132,68 @@ func (p *Panel) ProcessUnit(u unit.Unit) bool { return p.app.PathsFilter().IsVisiblePath(u.Instance().Prefab().Path()) } -func saveScreenshot(pixels []byte, w, h int) error { - if err := os.MkdirAll(cfg.ScreenshotDir, os.ModeDir); err != nil { - log.Print("unable to create screenshot directory:", err) +func (p *Panel) saveScreenshot(pixels []byte, w, h int) error { + if !cfg.ToClipboardMode { + if err := os.MkdirAll(cfg.ScreenshotDir, os.ModeDir); err != nil { + log.Print("unable to create screenshot directory:", err) + return err + } + } + + var directory string + if cfg.ToClipboardMode { + directory = os.TempDir() + } else { + directory = cfg.ScreenshotDir + } + + dstFilePath := directory + "/StrongDMM-" + time.Now().Format(util.TimeFormat) + ".png" + + if err := saveScreenshotToFile(dstFilePath, pixels, w, h); err != nil { + log.Print("unable to save screenshot to file:", err) + return err + } + + if cfg.ToClipboardMode { + if err := saveScreenshotToClipboard(dstFilePath); err != nil { + log.Print("unable to save screenshot to clipboard:", err) + return err + } + } + + return nil +} + +func saveScreenshotToFile(dstFilePath string, pixels []byte, w, h int) error { + out, err := os.Create(dstFilePath) + if err != nil { + log.Print("unable to create screenshot file:", dstFilePath, err) return err } - out, _ := os.Create(cfg.ScreenshotDir + "/" + time.Now().Format(util.TimeFormat) + ".png") + err = png.Encode(out, util.PixelsToRGBA(pixels, w, h)) defer out.Close() + return err +} + +func saveScreenshotToClipboard(srcFilePath string) error { + if err := clipboard.Init(); err != nil { + log.Print("unable to init clipboard:", err) + return err + } + + contents, err := os.ReadFile(srcFilePath) + if err != nil { + log.Print("unable to read resulting screenshot file:", err) + return err + } + + clipboard.Write(clipboard.FmtImage, contents) + + if err := os.Remove(srcFilePath); err != nil { + log.Print("unable to delete clipboard screenshot file:", err) + return err + } - return png.Encode(out, util.PixelsToRGBA(pixels, w, h)) + return nil }