From 190d4be1b62c825b0e6616d6750614e0d8117a46 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Mon, 16 Nov 2020 23:20:24 -0800 Subject: [PATCH] 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. --- go.mod | 11 ++ go.sum | 42 +++++ pkg/balance/theme.go | 3 + pkg/doodle.go | 1 - pkg/editor_scene.go | 11 +- pkg/editor_ui.go | 119 +++----------- pkg/editor_ui_palette.go | 6 +- pkg/editor_ui_popups.go | 210 ++++++++++++++++++++++++ pkg/editor_ui_toolbar.go | 39 ++++- pkg/level/palette.go | 2 +- pkg/modal/modal.go | 3 +- pkg/uix/canvas.go | 10 ++ pkg/windows/doodad_dropper.go | 17 +- pkg/windows/layers_window.go | 296 ++++++++++++++++++++++++++++++++++ pkg/windows/palette_editor.go | 59 ++++--- 15 files changed, 680 insertions(+), 149 deletions(-) create mode 100644 pkg/editor_ui_popups.go create mode 100644 pkg/windows/layers_window.go diff --git a/go.mod b/go.mod index 8cb4800..814796f 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,35 @@ module git.kirsle.net/apps/doodle go 1.15 replace git.kirsle.net/go/render => /home/kirsle/SketchyMaze/render + replace git.kirsle.net/go/ui => /home/kirsle/SketchyMaze/ui 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/log v0.0.0-20200902035305-70ac2848949b git.kirsle.net/go/render v0.0.0-20200710023247-e5f4c3a16860 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/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/mdempsky/maligned v0.0.0-20201101000000-d73c43cb16d0 // indirect github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e // indirect github.com/urfave/cli v1.22.5 github.com/urfave/cli/v2 v2.3.0 github.com/veandco/go-sdl2 v0.4.4 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/image v0.0.0-20200927104501-e162460cd6b5 google.golang.org/appengine v1.6.7 // 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 ) diff --git a/go.sum b/go.sum index 27f7c6f..636d3c9 100644 --- a/go.sum +++ b/go.sum @@ -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/go.mod h1:iESedHfXAOnbqiDDVs7Va+KQWkZG0Asc+452hw9TX9w= 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/go.mod h1:Q93RpHNXvbGr3dQ9mmcEN8ZC3dtNQ4FwivSx53tKOVA= 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/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/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/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/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/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/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/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= @@ -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/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= 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.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-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/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-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= 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.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-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-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-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-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-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-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.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-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/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-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/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/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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/yaml.v2 v2.2.2/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/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= diff --git a/pkg/balance/theme.go b/pkg/balance/theme.go index be1b308..1c42677 100644 --- a/pkg/balance/theme.go +++ b/pkg/balance/theme.go @@ -43,6 +43,9 @@ var ( PadX: 4, } + // Modal backdrop color. + ModalBackdrop = render.RGBA(1, 1, 1, 42) + // StatusFont is the font for the status bar. StatusFont = render.Text{ Size: 12, diff --git a/pkg/doodle.go b/pkg/doodle.go index 7efd65d..3f1a437 100644 --- a/pkg/doodle.go +++ b/pkg/doodle.go @@ -136,7 +136,6 @@ func (d *Doodle) Run() error { } else { // Global event handlers. if ev.Escape { - log.Error("Escape key pressed, shutting down") d.ConfirmExit() continue } diff --git a/pkg/editor_scene.go b/pkg/editor_scene.go index bda6e1d..3a4818d 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -31,8 +31,9 @@ type EditorScene struct { // The current level or doodad object being edited, based on the // DrawingType. - Level *level.Level - Doodad *doodads.Doodad + Level *level.Level + Doodad *doodads.Doodad + ActiveLayer int // which layer (of a doodad) is being edited now? // Custom debug overlay values. debTool *string @@ -170,8 +171,8 @@ func (s *EditorScene) ConfirmUnload(fn func()) { } modal.Confirm( - "This level has unsaved changes. Are you sure you\nwant to continue and lose your changes?", - ).WithTitle("Confirm Closing Level").Then(fn) + "This drawing has unsaved changes. Are you sure you\nwant to continue and lose your changes?", + ).WithTitle("Confirm Closing Drawing").Then(fn) } // Loop the editor scene. @@ -322,7 +323,7 @@ func (s *EditorScene) SaveDoodad(filename string) error { // TODO: is this copying necessary? 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. s.UI.Canvas.SetModified(false) diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index e572fbc..ad9a286 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -48,6 +48,7 @@ type EditorUI struct { aboutWindow *ui.Window doodadWindow *ui.Window paletteEditor *ui.Window + layersWindow *ui.Window // Palette window. Palette *ui.Window @@ -481,7 +482,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { //////// // File menu fileMenu := menu.AddMenu("File") - fileMenu.AddItemAccel("New level", "Ctrl-N", func() { + fileMenu.AddItemAccel("New level", "Ctrl-N*", func() { u.Scene.ConfirmUnload(func() { 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 != "" { saveFunc(u.Scene.filename) } 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() { d.GotoLoadMenu() }) @@ -533,7 +534,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { d.Goto(&MainScene{}) }) }) - fileMenu.AddItemAccel("Quit", "Ctrl-Q", func() { + fileMenu.AddItemAccel("Quit", "Escape", func() { d.ConfirmExit() }) @@ -543,7 +544,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { editMenu.AddItemAccel("Undo", "Ctrl-Z", func() { u.Canvas.UndoStroke() }) - editMenu.AddItemAccel("Redo", "Shift-Ctrl-Y", func() { + editMenu.AddItemAccel("Redo", "Ctrl-Y", func() { u.Canvas.RedoStroke() }) editMenu.AddSeparator() @@ -559,7 +560,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { //////// // Level menu - if drawingType == "level" { + if u.Scene.DrawingType == enum.LevelDrawing { levelMenu := menu.AddMenu("Level") levelMenu.AddItemAccel("Playtest", "P", func() { u.Scene.Playtest() @@ -578,10 +579,20 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { toolMenu.AddItemAccel("Command shell", "Enter", func() { d.shell.Open = true }) - toolMenu.AddItemAccel("Doodads", "d", func() { - log.Info("Open the DoodadDropper") - u.doodadWindow.Show() + toolMenu.AddSeparator() + toolMenu.AddItem("Edit Palette", func() { + 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 @@ -615,96 +626,6 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { 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. func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame { frame := ui.NewFrame("Status Bar") diff --git a/pkg/editor_ui_palette.go b/pkg/editor_ui_palette.go index 77b2d00..37d7e6e 100644 --- a/pkg/editor_ui_palette.go +++ b/pkg/editor_ui_palette.go @@ -89,11 +89,7 @@ func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame { Font: balance.MenuFont, })) btn.Handle(ui.Click, func(ed ui.EventData) error { - // 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() + u.OpenPaletteWindow() return nil }) u.Supervisor.Add(btn) diff --git a/pkg/editor_ui_popups.go b/pkg/editor_ui_popups.go new file mode 100644 index 0000000..2697d01 --- /dev/null +++ b/pkg/editor_ui_popups.go @@ -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) + } +} diff --git a/pkg/editor_ui_toolbar.go b/pkg/editor_ui_toolbar.go index 0c71b91..55ee7da 100644 --- a/pkg/editor_ui_toolbar.go +++ b/pkg/editor_ui_toolbar.go @@ -3,6 +3,7 @@ package doodle import ( "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/drawtool" + "git.kirsle.net/apps/doodle/pkg/enum" "git.kirsle.net/apps/doodle/pkg/sprites" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" @@ -33,6 +34,9 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { Icon string Tooltip string Click func() + + // Optional fields. + NoDoodad bool // tool not available for Doodad editing (Levels only) }{ { Value: drawtool.PencilTool.String(), @@ -75,9 +79,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { }, { - Value: drawtool.ActorTool.String(), - Icon: "assets/sprites/actor-tool.png", - Tooltip: "Doodad Tool\nDrag-and-drop objects into your map", + Value: drawtool.ActorTool.String(), + Icon: "assets/sprites/actor-tool.png", + Tooltip: "Doodad Tool\nDrag-and-drop objects into your map", + NoDoodad: true, Click: func() { u.Canvas.Tool = drawtool.ActorTool u.doodadWindow.Show() @@ -86,9 +91,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { }, { - Value: drawtool.LinkTool.String(), - Icon: "assets/sprites/link-tool.png", - Tooltip: "Link Tool\nConnect doodads to each other", + Value: drawtool.LinkTool.String(), + Icon: "assets/sprites/link-tool.png", + Tooltip: "Link Tool\nConnect doodads to each other", + NoDoodad: true, Click: func() { u.Canvas.Tool = drawtool.LinkTool u.doodadWindow.Show() @@ -116,6 +122,10 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { } for _, button := range buttons { button := button + if button.NoDoodad && u.Scene.DrawingType == enum.DoodadDrawing { + continue + } + image, err := sprites.LoadImage(d.Engine, button.Icon) if err != nil { 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. frame.Pack(ui.NewFrame("spacer"), ui.Pack{ Side: ui.N, diff --git a/pkg/level/palette.go b/pkg/level/palette.go index eb85ff4..bd9300a 100644 --- a/pkg/level/palette.go +++ b/pkg/level/palette.go @@ -95,7 +95,7 @@ func (p *Palette) AddSwatch() *Swatch { var ( 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{ diff --git a/pkg/modal/modal.go b/pkg/modal/modal.go index 704df3f..8160475 100644 --- a/pkg/modal/modal.go +++ b/pkg/modal/modal.go @@ -2,6 +2,7 @@ package modal import ( + "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/go/render" "git.kirsle.net/go/render/event" "git.kirsle.net/go/ui" @@ -27,7 +28,7 @@ func Initialize(e render.Engine) { window = render.NewRect(width, height) screen = ui.NewFrame("Modal Screen") - screen.SetBackground(render.RGBA(1, 1, 1, 128)) + screen.SetBackground(balance.ModalBackdrop) screen.Resize(window) screen.Compute(e) diff --git a/pkg/uix/canvas.go b/pkg/uix/canvas.go index e17e024..a4cde0b 100644 --- a/pkg/uix/canvas.go +++ b/pkg/uix/canvas.go @@ -175,6 +175,16 @@ func (w *Canvas) LoadDoodad(d *doodads.Doodad) { 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. func (w *Canvas) SetSwatch(s *level.Swatch) { w.Palette.ActiveSwatch = s diff --git a/pkg/windows/doodad_dropper.go b/pkg/windows/doodad_dropper.go index ff78b5a..5ef5fc8 100644 --- a/pkg/windows/doodad_dropper.go +++ b/pkg/windows/doodad_dropper.go @@ -41,9 +41,10 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { height = (buttonSize * rows) + 64 // account for button borders :( // pagination values - page = 1 - pages int - perPage = 20 + page = 1 + pages int + perPage = 20 + maxPageButtons = 10 ) window := ui.NewWindow(title) @@ -180,10 +181,12 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { // Pager for the doodads. pager := ui.NewPager(ui.Pager{ - Page: page, - Pages: pages, - PerPage: perPage, - Font: balance.MenuFont, + Name: "Doodad Dropper Pager", + Page: page, + Pages: pages, + PerPage: perPage, + MaxPageButtons: maxPageButtons, + Font: balance.MenuFont, OnChange: func(newPage, perPage int) { page = newPage log.Info("Page: %d, %d", page, perPage) diff --git a/pkg/windows/layers_window.go b/pkg/windows/layers_window.go new file mode 100644 index 0000000..d163bc7 --- /dev/null +++ b/pkg/windows/layers_window.go @@ -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 +} diff --git a/pkg/windows/palette_editor.go b/pkg/windows/palette_editor.go index 2ebba97..bcd90a0 100644 --- a/pkg/windows/palette_editor.go +++ b/pkg/windows/palette_editor.go @@ -17,9 +17,11 @@ import ( type PaletteEditor struct { Supervisor *ui.Supervisor Engine render.Engine + IsDoodad bool // you're editing a doodad instead of a level? - // Pointer to the currently edited level. - EditLevel *level.Level + // Pointer to the currently edited palette, be it + // from a level or a doodad. + EditPalette *level.Palette // Callback functions. OnChange func() @@ -44,7 +46,7 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { // Column sizes of the palette table. col1 = 30 // ID no. col2 = 24 // Color - col3 = 120 // Name + col3 = 130 // Name col4 = 140 // Attributes // col5 = 150 // Delete @@ -52,6 +54,9 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { page = 1 perPage = 5 ) + if config.IsDoodad { + title = "Doodad Palette" + } window := ui.NewWindow(title) window.SetButtons(ui.CloseButton) @@ -109,8 +114,8 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { }) // Draw the main table of Palette rows. - if level := config.EditLevel; level != nil { - for i, swatch := range level.Palette.Swatches { + if pal := config.EditPalette; pal != nil { + for i, swatch := range pal.Swatches { var idStr = fmt.Sprintf("%d", i) swatch := swatch @@ -201,7 +206,7 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { }) config.Supervisor.Add(btnColor) - // Attribute flags + // Attribute flags. attrFrame := ui.NewFrame("Attributes") attrFrame.Configure(ui.Config{ Width: col4, @@ -224,22 +229,26 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { Var: &swatch.Water, }, } - for _, attr := range attributes { - attr := attr - btn := ui.NewCheckButton(attr.Label, attr.Var, ui.NewLabel(ui.Label{ - Text: attr.Label, - Font: balance.MenuFont, - })) - btn.Handle(ui.Click, func(ed ui.EventData) error { - if config.OnChange != nil { - config.OnChange() - } - return nil - }) - config.Supervisor.Add(btn) - attrFrame.Pack(btn, ui.Pack{ - Side: ui.W, - }) + + // Do not show in Doodad editing mode. + if !config.IsDoodad { + for _, attr := range attributes { + attr := attr + btn := ui.NewCheckButton(attr.Label, attr.Var, ui.NewLabel(ui.Label{ + Text: attr.Label, + Font: balance.MenuFont, + })) + btn.Handle(ui.Click, func(ed ui.EventData) error { + if config.OnChange != nil { + config.OnChange() + } + return nil + }) + config.Supervisor.Add(btn) + attrFrame.Pack(btn, ui.Pack{ + Side: ui.W, + }) + } } // Pack all the widgets. @@ -281,12 +290,14 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window { // Pager for the doodads. pager := ui.NewPager(ui.Pager{ + Name: "Palette Editor Pager", Page: page, Pages: int(math.Ceil( float64(len(rows)) / float64(perPage), )), - PerPage: perPage, - Font: balance.MenuFont, + PerPage: perPage, + MaxPageButtons: 6, + Font: balance.MenuFont, OnChange: func(newPage, perPage int) { page = newPage log.Info("Page: %d, %d", page, perPage)