Layer Selection Window for Doodad Editor

* When editing a doodad in the Editor Mode, the toolbar has a "Lyr."
  button that opens the Layers window.
* The Layers window allows switching the active doodad layer that you
  are drawing on, as well as create and rename layers.
* With this feature, Doodads may be fully drawn in-game, including
  adding alternate named layers for animations and multiple-state
  doodads.
* Update the Pager component to have a configurable MaxPageButtons.
  Controls that have more pages than this limit will stop having buttons
  drawn after the limit. The "Forward" and "Next" buttons can still
  navigate into the extra pages.
* Refactored and centralized the various popup windows in Editor Mode
  into editor_ui_popups.go; the SetupPopups() and various methods such
  as ShowPaletteWindow() and ShowDoodadDropper() make management of
  popups simple for the editor_ui!
* The Menu Bar in Editor Mode now has context-specific tools in the
  Tools menu: the Doodad Dropper for levels and Layers for doodads.
* Bugfix the Palette Editor window to work equally between Levels and
  Doodads, by only having it care about the Palette and not the Level
  that owns it.
This commit is contained in:
Noah 2020-11-16 23:20:24 -08:00
parent 336a949ed0
commit 190d4be1b6
15 changed files with 680 additions and 149 deletions

11
go.mod
View File

@ -3,24 +3,35 @@ module git.kirsle.net/apps/doodle
go 1.15 go 1.15
replace git.kirsle.net/go/render => /home/kirsle/SketchyMaze/render replace git.kirsle.net/go/render => /home/kirsle/SketchyMaze/render
replace git.kirsle.net/go/ui => /home/kirsle/SketchyMaze/ui replace git.kirsle.net/go/ui => /home/kirsle/SketchyMaze/ui
require ( require (
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a // indirect
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4 // indirect
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 // indirect
git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f
git.kirsle.net/go/log v0.0.0-20200902035305-70ac2848949b git.kirsle.net/go/log v0.0.0-20200902035305-70ac2848949b
git.kirsle.net/go/render v0.0.0-20200710023247-e5f4c3a16860 git.kirsle.net/go/render v0.0.0-20200710023247-e5f4c3a16860
git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 // indirect
github.com/google/uuid v1.1.2 github.com/google/uuid v1.1.2
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063 // indirect
github.com/jgautheron/goconst v0.0.0-20201108215931-f8e4fe8351cd // indirect
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
github.com/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0 // indirect
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac
github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e // indirect github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e // indirect
github.com/urfave/cli v1.22.5 github.com/urfave/cli v1.22.5
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
github.com/veandco/go-sdl2 v0.4.4 github.com/veandco/go-sdl2 v0.4.4
github.com/vmihailenco/msgpack v3.3.3+incompatible github.com/vmihailenco/msgpack v3.3.3+incompatible
github.com/walle/lll v1.0.1 // indirect
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 // indirect mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 // indirect
) )

42
go.sum
View File

@ -1,3 +1,9 @@
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a h1:wFEQiK85fRsEVF0CRrPAos5LoAryUsIX1kPW/WrIqFw=
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo=
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4 h1:bf5qocEKjrY58JO2GwywfLsb1199lIVs7qHkiplwHy0=
4d63.com/gochecknoinits v0.0.0-20200108094044-eb73b47b9fc4/go.mod h1:4o1i5aXtIF5tJFt3UD1knCVmWOXg7fLYdHVu6jeNcnM=
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as=
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8=
git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f h1:OTxRqv7JdRpmR4gm3pG7Mzv+GyG0ig2mJWluu5NOkro= git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f h1:OTxRqv7JdRpmR4gm3pG7Mzv+GyG0ig2mJWluu5NOkro=
git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f/go.mod h1:iESedHfXAOnbqiDDVs7Va+KQWkZG0Asc+452hw9TX9w= git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f/go.mod h1:iESedHfXAOnbqiDDVs7Va+KQWkZG0Asc+452hw9TX9w=
git.kirsle.net/go/log v0.0.0-20200902035305-70ac2848949b h1:TDxEEWOJqMzsu9JW8/QgmT1lgQ9WD2KWlb2lKN/Ql2o= git.kirsle.net/go/log v0.0.0-20200902035305-70ac2848949b h1:TDxEEWOJqMzsu9JW8/QgmT1lgQ9WD2KWlb2lKN/Ql2o=
@ -8,17 +14,29 @@ git.kirsle.net/go/render v0.0.0-20200710023247-e5f4c3a16860/go.mod h1:ss7pvZbGWr
git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c h1:8fvCXsFGK91WtiTIAdklAN3gHVNYD0hvFvWfznCLMGc= git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c h1:8fvCXsFGK91WtiTIAdklAN3gHVNYD0hvFvWfznCLMGc=
git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c/go.mod h1:Q93RpHNXvbGr3dQ9mmcEN8ZC3dtNQ4FwivSx53tKOVA= git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c/go.mod h1:Q93RpHNXvbGr3dQ9mmcEN8ZC3dtNQ4FwivSx53tKOVA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 h1:YI/8G3uLbYyowJeOPVL6BMKe2wbL54h0FdEKmncU6lU=
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214/go.mod h1:Ef5UOtJdJ5rVFObdOVsrNgKV/Wf4I+daTCSk8GTrHIk=
github.com/alexflint/go-arg v0.0.0-20160306200701-e71d6514f40a h1:Bc+P30eTWphhueyACA/fjiHJXRDq/kGiqO38nGxvml0=
github.com/alexflint/go-arg v0.0.0-20160306200701-e71d6514f40a/go.mod h1:PHxo6ZWOLVMZZgWSAqBynb/KhIqoGO6WKwOVX7rM9dg=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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=
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063 h1:dKprcOvlsvqfWn/iGvz+oYuC2axESeSMuF8dDrWMNsE=
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/jgautheron/goconst v0.0.0-20201108215931-f8e4fe8351cd h1:xfrCuNSOStubQgCjSKriU45JXwfj2Ew5PZgoPgWm6OQ=
github.com/jgautheron/goconst v0.0.0-20201108215931-f8e4fe8351cd/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU=
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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/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/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0 h1:+6XJvFZBYbNv/nSekNWFZyaGNMXcPnZ4n/HHoCXn+Ms=
github.com/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0/go.mod h1:3UB4iTzhLciyWcrrvXSkrtCIU+IJ5GCfEmnleHRsxL4=
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/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU=
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
@ -38,35 +56,55 @@ github.com/veandco/go-sdl2 v0.4.4 h1:coOJGftOdvNvGoUIZmm4XD+ZRQF4mg9ZVHmH3/42zFQ
github.com/veandco/go-sdl2 v0.4.4/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg= github.com/veandco/go-sdl2 v0.4.4/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/walle/lll v1.0.1 h1:lbK8008fOXbQNYt8daBGUrjvElvlwlE7D7N/9dLP5IQ=
github.com/walle/lll v1.0.1/go.mod h1:lYxcXzoPhiAHR9eaq+Yv7RYg1nIipLloBCIfPUzfaWQ=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo+ZZEYoYFYYDYdOrU7AaM= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo+ZZEYoYFYYDYdOrU7AaM=
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201030204249-4fc0492b8eca h1:KWfVIHfTHZf4IQhrLjrbG+kLyoSym7yYp0WgqtOVH9s=
golang.org/x/tools v0.0.0-20201030204249-4fc0492b8eca/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
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=
@ -77,5 +115,9 @@ gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
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=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 h1:kAREL6MPwpsk1/PQPFD3Eg7WAQR5mPTWZJaBiG5LDbY= mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 h1:kAREL6MPwpsk1/PQPFD3Eg7WAQR5mPTWZJaBiG5LDbY=
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc=

View File

@ -43,6 +43,9 @@ var (
PadX: 4, PadX: 4,
} }
// Modal backdrop color.
ModalBackdrop = render.RGBA(1, 1, 1, 42)
// StatusFont is the font for the status bar. // StatusFont is the font for the status bar.
StatusFont = render.Text{ StatusFont = render.Text{
Size: 12, Size: 12,

View File

@ -136,7 +136,6 @@ func (d *Doodle) Run() error {
} else { } else {
// Global event handlers. // Global event handlers.
if ev.Escape { if ev.Escape {
log.Error("Escape key pressed, shutting down")
d.ConfirmExit() d.ConfirmExit()
continue continue
} }

View File

@ -31,8 +31,9 @@ type EditorScene struct {
// The current level or doodad object being edited, based on the // The current level or doodad object being edited, based on the
// DrawingType. // DrawingType.
Level *level.Level Level *level.Level
Doodad *doodads.Doodad Doodad *doodads.Doodad
ActiveLayer int // which layer (of a doodad) is being edited now?
// Custom debug overlay values. // Custom debug overlay values.
debTool *string debTool *string
@ -170,8 +171,8 @@ func (s *EditorScene) ConfirmUnload(fn func()) {
} }
modal.Confirm( modal.Confirm(
"This level has unsaved changes. Are you sure you\nwant to continue and lose your changes?", "This drawing has unsaved changes. Are you sure you\nwant to continue and lose your changes?",
).WithTitle("Confirm Closing Level").Then(fn) ).WithTitle("Confirm Closing Drawing").Then(fn)
} }
// Loop the editor scene. // Loop the editor scene.
@ -322,7 +323,7 @@ func (s *EditorScene) SaveDoodad(filename string) error {
// TODO: is this copying necessary? // TODO: is this copying necessary?
d.Palette = s.UI.Canvas.Palette d.Palette = s.UI.Canvas.Palette
d.Layers[0].Chunker = s.UI.Canvas.Chunker() d.Layers[s.ActiveLayer].Chunker = s.UI.Canvas.Chunker()
// Clear the modified flag on the level. // Clear the modified flag on the level.
s.UI.Canvas.SetModified(false) s.UI.Canvas.SetModified(false)

View File

@ -48,6 +48,7 @@ type EditorUI struct {
aboutWindow *ui.Window aboutWindow *ui.Window
doodadWindow *ui.Window doodadWindow *ui.Window
paletteEditor *ui.Window paletteEditor *ui.Window
layersWindow *ui.Window
// Palette window. // Palette window.
Palette *ui.Window Palette *ui.Window
@ -481,7 +482,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
//////// ////////
// File menu // File menu
fileMenu := menu.AddMenu("File") fileMenu := menu.AddMenu("File")
fileMenu.AddItemAccel("New level", "Ctrl-N", func() { fileMenu.AddItemAccel("New level", "Ctrl-N*", func() {
u.Scene.ConfirmUnload(func() { u.Scene.ConfirmUnload(func() {
d.GotoNewMenu() d.GotoNewMenu()
}) })
@ -504,7 +505,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
}) })
}) })
} }
fileMenu.AddItemAccel("Save", "Ctrl-S", func() { fileMenu.AddItemAccel("Save", "Ctrl-S*", func() {
if u.Scene.filename != "" { if u.Scene.filename != "" {
saveFunc(u.Scene.filename) saveFunc(u.Scene.filename)
} else { } else {
@ -522,7 +523,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
} }
}) })
}) })
fileMenu.AddItemAccel("Open...", "Ctrl-O", func() { fileMenu.AddItemAccel("Open...", "Ctrl-O*", func() {
u.Scene.ConfirmUnload(func() { u.Scene.ConfirmUnload(func() {
d.GotoLoadMenu() d.GotoLoadMenu()
}) })
@ -533,7 +534,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
d.Goto(&MainScene{}) d.Goto(&MainScene{})
}) })
}) })
fileMenu.AddItemAccel("Quit", "Ctrl-Q", func() { fileMenu.AddItemAccel("Quit", "Escape", func() {
d.ConfirmExit() d.ConfirmExit()
}) })
@ -543,7 +544,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
editMenu.AddItemAccel("Undo", "Ctrl-Z", func() { editMenu.AddItemAccel("Undo", "Ctrl-Z", func() {
u.Canvas.UndoStroke() u.Canvas.UndoStroke()
}) })
editMenu.AddItemAccel("Redo", "Shift-Ctrl-Y", func() { editMenu.AddItemAccel("Redo", "Ctrl-Y", func() {
u.Canvas.RedoStroke() u.Canvas.RedoStroke()
}) })
editMenu.AddSeparator() editMenu.AddSeparator()
@ -559,7 +560,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
//////// ////////
// Level menu // Level menu
if drawingType == "level" { if u.Scene.DrawingType == enum.LevelDrawing {
levelMenu := menu.AddMenu("Level") levelMenu := menu.AddMenu("Level")
levelMenu.AddItemAccel("Playtest", "P", func() { levelMenu.AddItemAccel("Playtest", "P", func() {
u.Scene.Playtest() u.Scene.Playtest()
@ -578,10 +579,20 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
toolMenu.AddItemAccel("Command shell", "Enter", func() { toolMenu.AddItemAccel("Command shell", "Enter", func() {
d.shell.Open = true d.shell.Open = true
}) })
toolMenu.AddItemAccel("Doodads", "d", func() { toolMenu.AddSeparator()
log.Info("Open the DoodadDropper") toolMenu.AddItem("Edit Palette", func() {
u.doodadWindow.Show() u.OpenPaletteWindow()
}) })
if u.Scene.DrawingType == enum.LevelDrawing {
toolMenu.AddItemAccel("Doodads", "d", func() {
log.Info("Open the DoodadDropper")
u.doodadWindow.Show()
})
} else if u.Scene.DrawingType == enum.DoodadDrawing {
toolMenu.AddItem("Layers", func() {
u.OpenLayersWindow()
})
}
//////// ////////
// Help menu // Help menu
@ -615,96 +626,6 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
return menu return menu
} }
// SetupPopups preloads popup windows like the DoodadDropper.
func (u *EditorUI) SetupPopups(d *Doodle) {
// Common window configure function.
var configure = func(window *ui.Window) {
var size = window.Size()
window.Compute(d.Engine)
window.Supervise(u.Supervisor)
// Center the window.
window.MoveTo(render.Point{
X: (d.width / 2) - (size.W / 2),
Y: (d.height / 2) - (size.H / 2),
})
}
// Doodad Dropper.
if u.doodadWindow == nil {
u.doodadWindow = windows.NewDoodadDropper(windows.DoodadDropper{
Supervisor: u.Supervisor,
Engine: d.Engine,
OnStartDragActor: u.startDragActor,
OnCancel: func() {
u.doodadWindow.Hide()
},
})
configure(u.doodadWindow)
}
// Page Settings
if u.levelSettingsWindow == nil {
scene, _ := d.Scene.(*EditorScene)
u.levelSettingsWindow = windows.NewAddEditLevel(windows.AddEditLevel{
Supervisor: u.Supervisor,
Engine: d.Engine,
EditLevel: scene.Level,
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
scene.Level.PageType = pageType
scene.Level.Wallpaper = wallpaper
u.Canvas.LoadLevel(d.Engine, scene.Level)
},
OnCancel: func() {
u.levelSettingsWindow.Hide()
},
})
configure(u.levelSettingsWindow)
}
// Palette Editor.
if u.paletteEditor == nil {
scene, _ := d.Scene.(*EditorScene)
u.paletteEditor = windows.NewPaletteEditor(windows.PaletteEditor{
Supervisor: u.Supervisor,
Engine: d.Engine,
EditLevel: scene.Level,
OnChange: func() {
// Reload the level.
log.Warn("RELOAD LEVEL")
u.Canvas.LoadLevel(d.Engine, scene.Level)
scene.Level.Chunker.Redraw()
// Reload the palette frame to reflect the changed data.
u.Palette.Hide()
u.Palette = u.SetupPalette(d)
u.Resized(d)
},
OnAddColor: func() {
// Adding a new color to the palette.
sw := scene.Level.Palette.AddSwatch()
log.Info("Added new palette color: %+v", sw)
// Awkward but... reload this very same window.
u.paletteEditor.Hide()
u.paletteEditor = nil
u.SetupPopups(d)
u.paletteEditor.Show()
},
OnCancel: func() {
u.paletteEditor.Hide()
},
})
configure(u.paletteEditor)
}
}
// SetupStatusBar sets up the status bar widget along the bottom of the window. // SetupStatusBar sets up the status bar widget along the bottom of the window.
func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame { func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame {
frame := ui.NewFrame("Status Bar") frame := ui.NewFrame("Status Bar")

View File

@ -89,11 +89,7 @@ func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame {
Font: balance.MenuFont, Font: balance.MenuFont,
})) }))
btn.Handle(ui.Click, func(ed ui.EventData) error { btn.Handle(ui.Click, func(ed ui.EventData) error {
// TODO: recompute the window so the actual loaded level palette gets in u.OpenPaletteWindow()
u.paletteEditor.Hide()
u.paletteEditor = nil
u.SetupPopups(u.d)
u.paletteEditor.Show()
return nil return nil
}) })
u.Supervisor.Add(btn) u.Supervisor.Add(btn)

210
pkg/editor_ui_popups.go Normal file
View File

@ -0,0 +1,210 @@
package doodle
import (
"fmt"
"git.kirsle.net/apps/doodle/pkg/doodads"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/windows"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
/*
Functions to manage popup windows in the Editor Mode, such as:
* The Palette Editor
* The Layers Window
* etc.
*/
// Opens the "Layers" window (for editing doodads)
func (u *EditorUI) OpenLayersWindow() {
u.layersWindow.Hide()
u.layersWindow = nil
u.SetupPopups(u.d)
u.layersWindow.Show()
}
// OpenPaletteWindow opens the Palette Editor window.
func (u *EditorUI) OpenPaletteWindow() {
// TODO: recompute the window so the actual loaded level palette gets in
u.paletteEditor.Hide()
u.paletteEditor = nil
u.SetupPopups(u.d)
u.paletteEditor.Show()
}
// OpenDoodadDropper opens the Doodad Dropper window.
func (u *EditorUI) OpenDoodadDropper() {
// NOTE: most places in the code call this directly, nice
// and simple window :) but OpenDoodadDropper() added for consistency.
u.doodadWindow.Show()
}
// SetupPopups preloads popup windows like the DoodadDropper.
func (u *EditorUI) SetupPopups(d *Doodle) {
// Common window configure function.
var configure = func(window *ui.Window) {
var size = window.Size()
window.Compute(d.Engine)
window.Supervise(u.Supervisor)
// Center the window.
window.MoveTo(render.Point{
X: (d.width / 2) - (size.W / 2),
Y: (d.height / 2) - (size.H / 2),
})
}
// Doodad Dropper.
if u.doodadWindow == nil {
u.doodadWindow = windows.NewDoodadDropper(windows.DoodadDropper{
Supervisor: u.Supervisor,
Engine: d.Engine,
OnStartDragActor: u.startDragActor,
OnCancel: func() {
u.doodadWindow.Hide()
},
})
configure(u.doodadWindow)
}
// Page Settings
if u.levelSettingsWindow == nil {
scene, _ := d.Scene.(*EditorScene)
u.levelSettingsWindow = windows.NewAddEditLevel(windows.AddEditLevel{
Supervisor: u.Supervisor,
Engine: d.Engine,
EditLevel: scene.Level,
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
scene.Level.PageType = pageType
scene.Level.Wallpaper = wallpaper
u.Canvas.LoadLevel(d.Engine, scene.Level)
},
OnCancel: func() {
u.levelSettingsWindow.Hide()
},
})
configure(u.levelSettingsWindow)
}
// Palette Editor.
if u.paletteEditor == nil {
scene, _ := d.Scene.(*EditorScene)
// Which palette?
var pal *level.Palette
if scene.Level != nil {
pal = scene.Level.Palette
} else if scene.Doodad != nil {
pal = scene.Doodad.Palette
}
u.paletteEditor = windows.NewPaletteEditor(windows.PaletteEditor{
Supervisor: u.Supervisor,
Engine: d.Engine,
IsDoodad: scene.Doodad != nil,
EditPalette: pal,
OnChange: func() {
// Reload the level.
if scene.Level != nil {
log.Warn("RELOAD LEVEL")
u.Canvas.LoadLevel(d.Engine, scene.Level)
scene.Level.Chunker.Redraw()
} else if scene.Doodad != nil {
log.Warn("RELOAD DOODAD")
u.Canvas.LoadDoodadToLayer(u.Scene.Doodad, u.Scene.ActiveLayer)
u.Scene.Doodad.Layers[u.Scene.ActiveLayer].Chunker.Redraw()
}
// Reload the palette frame to reflect the changed data.
u.Palette.Hide()
u.Palette = u.SetupPalette(d)
u.Resized(d)
},
OnAddColor: func() {
// Adding a new color to the palette.
sw := pal.AddSwatch()
log.Info("Added new palette color: %+v", sw)
// Awkward but... reload this very same window.
u.paletteEditor.Hide()
u.paletteEditor = nil
u.SetupPopups(d)
u.paletteEditor.Show()
},
OnCancel: func() {
u.paletteEditor.Hide()
},
})
configure(u.paletteEditor)
}
// Layers window (doodad editor)
if u.layersWindow == nil {
scene, _ := d.Scene.(*EditorScene)
u.layersWindow = windows.NewLayerWindow(windows.Layers{
Supervisor: u.Supervisor,
Engine: d.Engine,
EditDoodad: scene.Doodad,
ActiveLayer: scene.ActiveLayer,
OnChange: func(self *doodads.Doodad) {
// Reload the level.
log.Warn("RELOAD LEVEL")
u.Canvas.LoadDoodad(u.Scene.Doodad)
for i := range self.Layers {
scene.Doodad.Layers[i] = self.Layers[i]
}
// Awkward but... reload this very same window.
// Otherwise, the window doesn't update to show the new
// layer having been added.
u.layersWindow.Hide()
u.layersWindow = nil
u.SetupPopups(d)
u.layersWindow.Show()
},
OnAddLayer: func() {
layer := doodads.Layer{
Name: fmt.Sprintf("layer %d", len(scene.Doodad.Layers)),
Chunker: level.NewChunker(scene.DoodadSize),
}
scene.Doodad.Layers = append(scene.Doodad.Layers, layer)
log.Info("Added new layer: %d %s",
len(scene.Doodad.Layers), layer.Name)
// Awkward but... reload this very same window.
// Otherwise, the window doesn't update to show the new
// layer having been added.
u.layersWindow.Hide()
u.layersWindow = nil
u.SetupPopups(d)
u.layersWindow.Show()
},
OnChangeLayer: func(index int) {
if index < 0 || index >= len(scene.Doodad.Layers) {
d.Flash("OnChangeLayer: layer %d out of range", index)
return
}
log.Info("CHANGE DOODAD LAYER TO %d", index)
u.Canvas.LoadDoodadToLayer(u.Scene.Doodad, index)
u.Scene.ActiveLayer = index
},
OnCancel: func() {
u.layersWindow.Hide()
},
})
configure(u.layersWindow)
}
}

View File

@ -3,6 +3,7 @@ package doodle
import ( import (
"git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/drawtool" "git.kirsle.net/apps/doodle/pkg/drawtool"
"git.kirsle.net/apps/doodle/pkg/enum"
"git.kirsle.net/apps/doodle/pkg/sprites" "git.kirsle.net/apps/doodle/pkg/sprites"
"git.kirsle.net/go/render" "git.kirsle.net/go/render"
"git.kirsle.net/go/ui" "git.kirsle.net/go/ui"
@ -33,6 +34,9 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
Icon string Icon string
Tooltip string Tooltip string
Click func() Click func()
// Optional fields.
NoDoodad bool // tool not available for Doodad editing (Levels only)
}{ }{
{ {
Value: drawtool.PencilTool.String(), Value: drawtool.PencilTool.String(),
@ -75,9 +79,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
}, },
{ {
Value: drawtool.ActorTool.String(), Value: drawtool.ActorTool.String(),
Icon: "assets/sprites/actor-tool.png", Icon: "assets/sprites/actor-tool.png",
Tooltip: "Doodad Tool\nDrag-and-drop objects into your map", Tooltip: "Doodad Tool\nDrag-and-drop objects into your map",
NoDoodad: true,
Click: func() { Click: func() {
u.Canvas.Tool = drawtool.ActorTool u.Canvas.Tool = drawtool.ActorTool
u.doodadWindow.Show() u.doodadWindow.Show()
@ -86,9 +91,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
}, },
{ {
Value: drawtool.LinkTool.String(), Value: drawtool.LinkTool.String(),
Icon: "assets/sprites/link-tool.png", Icon: "assets/sprites/link-tool.png",
Tooltip: "Link Tool\nConnect doodads to each other", Tooltip: "Link Tool\nConnect doodads to each other",
NoDoodad: true,
Click: func() { Click: func() {
u.Canvas.Tool = drawtool.LinkTool u.Canvas.Tool = drawtool.LinkTool
u.doodadWindow.Show() u.doodadWindow.Show()
@ -116,6 +122,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
} }
for _, button := range buttons { for _, button := range buttons {
button := button button := button
if button.NoDoodad && u.Scene.DrawingType == enum.DoodadDrawing {
continue
}
image, err := sprites.LoadImage(d.Engine, button.Icon) image, err := sprites.LoadImage(d.Engine, button.Icon)
if err != nil { if err != nil {
panic(err) panic(err)
@ -148,6 +158,23 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
}) })
} }
// Doodad Editor: show the Layers button.
if u.Scene.DrawingType == enum.DoodadDrawing {
btn := ui.NewButton("Layers Button", ui.NewLabel(ui.Label{
Text: "Lyr.",
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, func(ed ui.EventData) error {
u.OpenLayersWindow()
return nil
})
u.Supervisor.Add(btn)
btnFrame.Pack(btn, ui.Pack{
Side: ui.N,
PadY: 2,
})
}
// Spacer frame. // Spacer frame.
frame.Pack(ui.NewFrame("spacer"), ui.Pack{ frame.Pack(ui.NewFrame("spacer"), ui.Pack{
Side: ui.N, Side: ui.N,

View File

@ -95,7 +95,7 @@ func (p *Palette) AddSwatch() *Swatch {
var ( var (
index = len(p.Swatches) index = len(p.Swatches)
name = fmt.Sprintf("color %d", len(p.Swatches)+1) name = fmt.Sprintf("color %d", len(p.Swatches))
) )
p.Swatches = append(p.Swatches, &Swatch{ p.Swatches = append(p.Swatches, &Swatch{

View File

@ -2,6 +2,7 @@
package modal package modal
import ( import (
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/go/render" "git.kirsle.net/go/render"
"git.kirsle.net/go/render/event" "git.kirsle.net/go/render/event"
"git.kirsle.net/go/ui" "git.kirsle.net/go/ui"
@ -27,7 +28,7 @@ func Initialize(e render.Engine) {
window = render.NewRect(width, height) window = render.NewRect(width, height)
screen = ui.NewFrame("Modal Screen") screen = ui.NewFrame("Modal Screen")
screen.SetBackground(render.RGBA(1, 1, 1, 128)) screen.SetBackground(balance.ModalBackdrop)
screen.Resize(window) screen.Resize(window)
screen.Compute(e) screen.Compute(e)

View File

@ -175,6 +175,16 @@ func (w *Canvas) LoadDoodad(d *doodads.Doodad) {
w.Load(d.Palette, d.Layers[0].Chunker) w.Load(d.Palette, d.Layers[0].Chunker)
} }
// LoadDoodadToLayer initializes a Canvas from a Doodad object and picks
// a layer to load.
func (w *Canvas) LoadDoodadToLayer(d *doodads.Doodad, index int) {
if index < 0 || index > len(d.Layers) {
log.Error("LoadDoodadToLayer: index %d out of range", index)
return
}
w.Load(d.Palette, d.Layers[index].Chunker)
}
// SetSwatch changes the currently selected swatch for editing. // SetSwatch changes the currently selected swatch for editing.
func (w *Canvas) SetSwatch(s *level.Swatch) { func (w *Canvas) SetSwatch(s *level.Swatch) {
w.Palette.ActiveSwatch = s w.Palette.ActiveSwatch = s

View File

@ -41,9 +41,10 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window {
height = (buttonSize * rows) + 64 // account for button borders :( height = (buttonSize * rows) + 64 // account for button borders :(
// pagination values // pagination values
page = 1 page = 1
pages int pages int
perPage = 20 perPage = 20
maxPageButtons = 10
) )
window := ui.NewWindow(title) window := ui.NewWindow(title)
@ -180,10 +181,12 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window {
// Pager for the doodads. // Pager for the doodads.
pager := ui.NewPager(ui.Pager{ pager := ui.NewPager(ui.Pager{
Page: page, Name: "Doodad Dropper Pager",
Pages: pages, Page: page,
PerPage: perPage, Pages: pages,
Font: balance.MenuFont, PerPage: perPage,
MaxPageButtons: maxPageButtons,
Font: balance.MenuFont,
OnChange: func(newPage, perPage int) { OnChange: func(newPage, perPage int) {
page = newPage page = newPage
log.Info("Page: %d, %d", page, perPage) log.Info("Page: %d, %d", page, perPage)

View File

@ -0,0 +1,296 @@
package windows
import (
"fmt"
"math"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/doodads"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/shmem"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
// Layers shows the layers when editing a doodad file.
type Layers struct {
Supervisor *ui.Supervisor
Engine render.Engine
// Pointer to the currently edited level.
EditDoodad *doodads.Doodad
ActiveLayer int // pointer to selected layer
activeLayer string // cached string for radio button
// Callback functions.
OnChange func(*doodads.Doodad) // Doodad data was modified, reload the Canvas etc.
OnAddLayer func() // "Add Layer" button was clicked
OnCancel func() // Close button was clicked.
// Editor should change the active layer
OnChangeLayer func(index int)
}
// NewLayerWindow initializes the window.
func NewLayerWindow(config Layers) *ui.Window {
// Default options.
var (
title = "Layers"
rows = []*ui.Frame{}
// size of the popup window
width = 320
height = 300
// Column sizes of the palette table.
col1 = 40 // Index
col3 = 120 // Name
col4 = 60 // Edit button
// col5 = 150 // Delete
// pagination values
page = 1
perPage = 5
)
config.activeLayer = fmt.Sprintf("%d", config.ActiveLayer)
log.Warn("config.activeLayer=%s", config.activeLayer)
window := ui.NewWindow(title)
window.SetButtons(ui.CloseButton)
window.Configure(ui.Config{
Width: width,
Height: height,
Background: render.Grey,
})
frame := ui.NewFrame("Window Body Frame")
window.Pack(frame, ui.Pack{
Side: ui.N,
Fill: true,
Expand: true,
})
log.Info("SETUP PALETTE WINDOW")
// Draw the header row.
headers := []struct {
Name string
Size int
}{
{"Index", col1},
{"Name", col3},
{"Edit", col4},
}
header := ui.NewFrame("Header")
for _, col := range headers {
labelFrame := ui.NewFrame(col.Name)
labelFrame.Configure(ui.Config{
Width: col.Size,
Height: 24,
})
label := ui.NewLabel(ui.Label{
Text: col.Name,
Font: balance.MenuFontBold,
})
labelFrame.Pack(label, ui.Pack{
Side: ui.N,
})
header.Pack(labelFrame, ui.Pack{
Side: ui.W,
Padding: 2,
})
}
header.Compute(config.Engine)
frame.Pack(header, ui.Pack{
Side: ui.N,
})
// Draw the rows for each Layer in the given doodad.
if doodad := config.EditDoodad; doodad != nil {
for i, _ := range doodad.Layers {
i := i // rescope
var idStr = fmt.Sprintf("%d", i)
row := ui.NewFrame("Layer " + idStr)
rows = append(rows, row)
// Off the end of the first page?
if i >= perPage {
row.Hide()
}
// ID label.
idLabel := ui.NewLabel(ui.Label{
Text: idStr + ".",
Font: balance.MenuFont,
})
idLabel.Configure(ui.Config{
Width: col1,
Height: 24,
})
// Name button (click to rename the swatch)
btnName := ui.NewButton("Name", ui.NewLabel(ui.Label{
TextVariable: &doodad.Layers[i].Name,
}))
btnName.Configure(ui.Config{
Width: col3,
Height: 24,
})
btnName.Handle(ui.Click, func(ed ui.EventData) error {
shmem.Prompt("New layer name ["+doodad.Layers[i].Name+"]: ", func(answer string) {
log.Warn("Answer: %s", answer)
if answer != "" {
doodad.Layers[i].Name = answer
if config.OnChange != nil {
config.OnChange(config.EditDoodad)
}
}
})
return nil
})
config.Supervisor.Add(btnName)
// Edit button (open layer for editing)
// btnEdit := ui.NewButton("Edit", ui.NewLabel(ui.Label{
// Text: "Edit",
// }))
btnEdit := ui.NewRadioButton("Edit",
&config.activeLayer, idStr, ui.NewLabel(ui.Label{
Text: "Edit",
}))
btnEdit.Configure(ui.Config{
Width: col4,
Height: 24,
})
btnEdit.Handle(ui.Click, func(ed ui.EventData) error {
if config.OnChangeLayer != nil {
config.OnChangeLayer(i)
}
return nil
})
config.Supervisor.Add(btnEdit)
// Pack all the widgets.
row.Pack(idLabel, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Pack(btnName, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Pack(btnEdit, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Compute(config.Engine)
frame.Pack(row, ui.Pack{
Side: ui.N,
PadY: 2,
})
}
}
{
/******************
* Confirm/cancel buttons.
******************/
bottomFrame := ui.NewFrame("Button Frame")
frame.Pack(bottomFrame, ui.Pack{
Side: ui.S,
FillX: true,
})
// Pager for the doodads.
pager := ui.NewPager(ui.Pager{
Name: "Layers Window Pager",
Page: page,
Pages: int(math.Ceil(
float64(len(rows)) / float64(perPage),
)),
PerPage: perPage,
MaxPageButtons: 10,
Font: balance.MenuFont,
OnChange: func(newPage, perPage int) {
page = newPage
log.Info("Page: %d, %d", page, perPage)
// Re-evaluate which rows are shown/hidden for this page.
var (
minRow = (page - 1) * perPage
visible = 0
)
for i, row := range rows {
if visible >= perPage {
row.Hide()
continue
}
if i < minRow {
row.Hide()
} else {
row.Show()
visible++
}
}
},
})
pager.Compute(config.Engine)
pager.Supervise(config.Supervisor)
bottomFrame.Place(pager, ui.Place{
Top: 20,
Left: 20,
})
btnFrame := ui.NewFrame("Window Buttons")
var buttons = []struct {
Label string
F func(ui.EventData) error
}{
{"Add Layer", func(ed ui.EventData) error {
if config.OnAddLayer != nil {
config.OnAddLayer()
}
if config.OnChange != nil {
config.OnChange(config.EditDoodad)
}
return nil
}},
{"Close", func(ed ui.EventData) error {
if config.OnCancel != nil {
config.OnCancel()
}
return nil
}},
}
for _, t := range buttons {
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
Text: t.Label,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, t.F)
btn.Compute(config.Engine)
config.Supervisor.Add(btn)
btnFrame.Pack(btn, ui.Pack{
Side: ui.W,
PadX: 4,
})
}
bottomFrame.Place(btnFrame, ui.Place{
Top: 60,
Center: true,
})
}
window.Hide()
return window
}

View File

@ -17,9 +17,11 @@ import (
type PaletteEditor struct { type PaletteEditor struct {
Supervisor *ui.Supervisor Supervisor *ui.Supervisor
Engine render.Engine Engine render.Engine
IsDoodad bool // you're editing a doodad instead of a level?
// Pointer to the currently edited level. // Pointer to the currently edited palette, be it
EditLevel *level.Level // from a level or a doodad.
EditPalette *level.Palette
// Callback functions. // Callback functions.
OnChange func() OnChange func()
@ -44,7 +46,7 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
// Column sizes of the palette table. // Column sizes of the palette table.
col1 = 30 // ID no. col1 = 30 // ID no.
col2 = 24 // Color col2 = 24 // Color
col3 = 120 // Name col3 = 130 // Name
col4 = 140 // Attributes col4 = 140 // Attributes
// col5 = 150 // Delete // col5 = 150 // Delete
@ -52,6 +54,9 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
page = 1 page = 1
perPage = 5 perPage = 5
) )
if config.IsDoodad {
title = "Doodad Palette"
}
window := ui.NewWindow(title) window := ui.NewWindow(title)
window.SetButtons(ui.CloseButton) window.SetButtons(ui.CloseButton)
@ -109,8 +114,8 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
}) })
// Draw the main table of Palette rows. // Draw the main table of Palette rows.
if level := config.EditLevel; level != nil { if pal := config.EditPalette; pal != nil {
for i, swatch := range level.Palette.Swatches { for i, swatch := range pal.Swatches {
var idStr = fmt.Sprintf("%d", i) var idStr = fmt.Sprintf("%d", i)
swatch := swatch swatch := swatch
@ -201,7 +206,7 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
}) })
config.Supervisor.Add(btnColor) config.Supervisor.Add(btnColor)
// Attribute flags // Attribute flags.
attrFrame := ui.NewFrame("Attributes") attrFrame := ui.NewFrame("Attributes")
attrFrame.Configure(ui.Config{ attrFrame.Configure(ui.Config{
Width: col4, Width: col4,
@ -224,22 +229,26 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
Var: &swatch.Water, Var: &swatch.Water,
}, },
} }
for _, attr := range attributes {
attr := attr // Do not show in Doodad editing mode.
btn := ui.NewCheckButton(attr.Label, attr.Var, ui.NewLabel(ui.Label{ if !config.IsDoodad {
Text: attr.Label, for _, attr := range attributes {
Font: balance.MenuFont, attr := attr
})) btn := ui.NewCheckButton(attr.Label, attr.Var, ui.NewLabel(ui.Label{
btn.Handle(ui.Click, func(ed ui.EventData) error { Text: attr.Label,
if config.OnChange != nil { Font: balance.MenuFont,
config.OnChange() }))
} btn.Handle(ui.Click, func(ed ui.EventData) error {
return nil if config.OnChange != nil {
}) config.OnChange()
config.Supervisor.Add(btn) }
attrFrame.Pack(btn, ui.Pack{ return nil
Side: ui.W, })
}) config.Supervisor.Add(btn)
attrFrame.Pack(btn, ui.Pack{
Side: ui.W,
})
}
} }
// Pack all the widgets. // Pack all the widgets.
@ -281,12 +290,14 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
// Pager for the doodads. // Pager for the doodads.
pager := ui.NewPager(ui.Pager{ pager := ui.NewPager(ui.Pager{
Name: "Palette Editor Pager",
Page: page, Page: page,
Pages: int(math.Ceil( Pages: int(math.Ceil(
float64(len(rows)) / float64(perPage), float64(len(rows)) / float64(perPage),
)), )),
PerPage: perPage, PerPage: perPage,
Font: balance.MenuFont, MaxPageButtons: 6,
Font: balance.MenuFont,
OnChange: func(newPage, perPage int) { OnChange: func(newPage, perPage int) {
page = newPage page = newPage
log.Info("Page: %d, %d", page, perPage) log.Info("Page: %d, %d", page, perPage)