summaryrefslogtreecommitdiff
path: root/biome_info_editor.go
diff options
context:
space:
mode:
Diffstat (limited to 'biome_info_editor.go')
-rw-r--r--biome_info_editor.go415
1 files changed, 415 insertions, 0 deletions
diff --git a/biome_info_editor.go b/biome_info_editor.go
new file mode 100644
index 0000000..61a1d7e
--- /dev/null
+++ b/biome_info_editor.go
@@ -0,0 +1,415 @@
+package main
+
+import (
+ "fmt"
+ "github.com/kch42/gomcmap/mcmap"
+ "github.com/mattn/go-gtk/gdk"
+ "github.com/mattn/go-gtk/glib"
+ "github.com/mattn/go-gtk/gtk"
+ "os"
+ "strconv"
+)
+
+type biomeEditFrame struct {
+ *gtk.Frame
+ applyBtn *gtk.Button
+ idInput, snowLineInput, nameInput *gtk.Entry
+ colorInput *gtk.ColorButton
+ bList *biomeList
+}
+
+func newBiomeEditFrame() *biomeEditFrame {
+ frm := &biomeEditFrame{
+ Frame: gtk.NewFrame("Edit Biome"),
+ applyBtn: gtk.NewButtonWithLabel("Apply"),
+ idInput: gtk.NewEntry(),
+ snowLineInput: gtk.NewEntry(),
+ nameInput: gtk.NewEntry(),
+ colorInput: gtk.NewColorButton(),
+ }
+
+ frm.idInput.SetSizeRequest(40, -1)
+ frm.snowLineInput.SetSizeRequest(40, -1)
+
+ frm.idInput.Connect("changed", frm.unlockApply)
+ frm.nameInput.Connect("changed", frm.unlockApply)
+ frm.snowLineInput.Connect("changed", frm.unlockApply)
+ frm.applyBtn.SetSensitive(false)
+
+ vbox := gtk.NewVBox(false, 0)
+ hbox := gtk.NewHBox(false, 0)
+
+ frm.idInput.SetTooltipText("The data value of the Biome [0-255]")
+ frm.snowLineInput.SetTooltipText(fmt.Sprintf("Height (Y coordinate) at which snowfall starts (-1 or %d for no snowfall, 0 for always snowy)", mcmap.ChunkSizeY))
+
+ hbox.PackStart(gtk.NewLabel("Color:"), false, false, 0)
+ hbox.PackStart(frm.colorInput, false, false, 3)
+ hbox.PackStart(gtk.NewLabel("ID:"), false, false, 0)
+ hbox.PackStart(frm.idInput, false, false, 3)
+ hbox.PackStart(gtk.NewLabel("Snowline:"), false, false, 0)
+ hbox.PackStart(frm.snowLineInput, false, false, 3)
+ hbox.PackStart(gtk.NewLabel("Name:"), false, false, 0)
+ hbox.PackStart(frm.nameInput, true, true, 3)
+
+ vbox.PackStart(hbox, false, false, 0)
+ vbox.PackStart(frm.applyBtn, false, false, 3)
+ frm.Add(vbox)
+
+ frm.applyBtn.Connect("clicked", frm.doApply)
+
+ return frm
+}
+
+func (frm *biomeEditFrame) setBiomeInfo(info BiomeInfo) {
+ frm.colorInput.SetColor(gdk.NewColor(info.Color))
+ frm.idInput.SetText(strconv.FormatInt(int64(info.ID), 10))
+ frm.snowLineInput.SetText(strconv.FormatInt(int64(info.SnowLine), 10))
+ frm.nameInput.SetText(info.Name)
+}
+
+func (frm *biomeEditFrame) doApply() {
+ biome, ok := frm.getBiomeInfo()
+ if !ok {
+ return
+ }
+
+ frm.bList.setCurrentBiome(biome)
+}
+
+func (frm *biomeEditFrame) getBiomeInfo() (BiomeInfo, bool) {
+ id, err := strconv.ParseUint(frm.idInput.GetText(), 10, 8)
+ if err != nil {
+ return BiomeInfo{}, false
+ }
+
+ snow, err := strconv.ParseInt(frm.snowLineInput.GetText(), 10, 32)
+ if err != nil {
+ return BiomeInfo{}, false
+ }
+ if (snow > mcmap.ChunkSizeY) || (snow < 0) {
+ snow = mcmap.ChunkSizeY
+ }
+
+ name := frm.nameInput.GetText()
+ if name == "" {
+ return BiomeInfo{}, false
+ }
+
+ col := frm.colorInput.GetColor()
+
+ return BiomeInfo{
+ ID: mcmap.Biome(id),
+ SnowLine: int(snow),
+ Name: name,
+ Color: fmt.Sprintf("#%02x%02x%02x", col.Red()>>8, col.Green()>>8, col.Blue()>>8),
+ }, true
+}
+
+func (frm *biomeEditFrame) checkOK() bool {
+ _, ok := frm.getBiomeInfo()
+ return ok
+}
+
+func (frm *biomeEditFrame) unlockApply() {
+ frm.applyBtn.SetSensitive(frm.checkOK())
+}
+
+type biomeList struct {
+ *gtk.HBox
+ treeview *gtk.TreeView
+ lStore *gtk.ListStore
+ biomes []BiomeInfo
+ editfrm *biomeEditFrame
+ addBtn, delBtn, upBtn, downBtn *gtk.Button
+}
+
+func newBiomeList() *biomeList {
+ bl := &biomeList{
+ HBox: gtk.NewHBox(false, 0),
+ treeview: gtk.NewTreeView(),
+ lStore: gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_STRING),
+ addBtn: gtk.NewButton(),
+ delBtn: gtk.NewButton(),
+ upBtn: gtk.NewButton(),
+ downBtn: gtk.NewButton(),
+ }
+
+ scroll := gtk.NewScrolledWindow(nil, nil)
+ scroll.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ scroll.Add(bl.treeview)
+ bl.PackStart(scroll, true, true, 3)
+
+ bl.treeview.SetModel(bl.lStore)
+ bl.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Color", gtk.NewCellRendererText(), "background", 0))
+ bl.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("ID", gtk.NewCellRendererText(), "text", 1))
+ bl.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Snowline", gtk.NewCellRendererText(), "text", 2))
+ bl.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Name", gtk.NewCellRendererText(), "text", 3))
+
+ bl.treeview.GetSelection().SetMode(gtk.SELECTION_SINGLE)
+ bl.treeview.Connect("cursor-changed", bl.onCursorChanged)
+
+ vbox := gtk.NewVBox(false, 0)
+
+ bl.addBtn.Add(gtk.NewImageFromStock(gtk.STOCK_ADD, gtk.ICON_SIZE_SMALL_TOOLBAR))
+ bl.delBtn.Add(gtk.NewImageFromStock(gtk.STOCK_DELETE, gtk.ICON_SIZE_SMALL_TOOLBAR))
+ bl.upBtn.Add(gtk.NewImageFromStock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR))
+ bl.downBtn.Add(gtk.NewImageFromStock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR))
+
+ bl.addBtn.Connect("clicked", bl.onAdd)
+ bl.delBtn.Connect("clicked", bl.onDel)
+ bl.upBtn.Connect("clicked", bl.onUp)
+ bl.downBtn.Connect("clicked", bl.onDown)
+
+ bl.delBtn.SetSensitive(false)
+ bl.upBtn.SetSensitive(false)
+ bl.downBtn.SetSensitive(false)
+
+ vbox.PackStart(bl.addBtn, false, false, 3)
+ vbox.PackStart(bl.delBtn, false, false, 3)
+ vbox.PackStart(bl.upBtn, false, false, 3)
+ vbox.PackStart(bl.downBtn, false, false, 3)
+
+ bl.PackStart(vbox, false, false, 0)
+
+ return bl
+}
+
+func (bl *biomeList) setBiome(iter *gtk.TreeIter, biome BiomeInfo) {
+ bl.lStore.Set(iter, biome.Color, strconv.FormatInt(int64(biome.ID), 10), strconv.FormatInt(int64(biome.SnowLine), 10), biome.Name)
+}
+
+func (bl *biomeList) setCurrentBiome(biome BiomeInfo) {
+ idx, iter, _ := bl.treeviewIdx()
+ if idx < 0 {
+ return
+ }
+ bl.biomes[idx] = biome
+ bl.setBiome(iter, biome)
+}
+
+func (bl *biomeList) SetBiomes(biomes []BiomeInfo) {
+ bl.biomes = biomes
+
+ bl.lStore.Clear()
+ var iter gtk.TreeIter
+ for _, bio := range biomes {
+ bl.lStore.Append(&iter)
+ bl.setBiome(&iter, bio)
+ }
+}
+
+func (bl *biomeList) Biomes() []BiomeInfo { return bl.biomes }
+
+func (bl *biomeList) treeviewIdx() (int, *gtk.TreeIter, *gtk.TreePath) {
+ var path *gtk.TreePath
+ var column *gtk.TreeViewColumn
+ bl.treeview.GetCursor(&path, &column)
+
+ idxs := path.GetIndices()
+ if len(idxs) != 1 {
+ return -1, nil, nil
+ }
+ var iter gtk.TreeIter
+ bl.lStore.GetIter(&iter, path)
+
+ return idxs[0], &iter, path
+}
+
+func (bl *biomeList) onCursorChanged() {
+ idx, _, _ := bl.treeviewIdx()
+
+ bl.delBtn.SetSensitive(idx >= 0)
+ bl.upBtn.SetSensitive(idx >= 1)
+ bl.downBtn.SetSensitive((idx >= 0) && (idx < len(bl.biomes)-1))
+
+ if idx >= 0 {
+ bl.editfrm.setBiomeInfo(bl.biomes[idx])
+ }
+}
+
+func (bl *biomeList) onAdd() {
+ bio := BiomeInfo{
+ Color: "#000000",
+ ID: 0,
+ SnowLine: 255,
+ Name: "(new)",
+ }
+ bl.biomes = append(bl.biomes, bio)
+
+ var iter gtk.TreeIter
+ bl.lStore.Append(&iter)
+ bl.setBiome(&iter, bio)
+ path := gtk.NewTreePath()
+ path.AppendIndex(len(bl.biomes) - 1)
+ bl.treeview.SetCursor(path, nil, false)
+}
+
+func (bl *biomeList) onDel() {
+ idx, iter, path := bl.treeviewIdx()
+ if idx < 0 {
+ return
+ }
+
+ copy(bl.biomes[idx:], bl.biomes[idx+1:])
+ bl.biomes = bl.biomes[:len(bl.biomes)-1]
+
+ bl.lStore.Remove(iter)
+ if len(bl.biomes) > 0 {
+ bl.treeview.SetCursor(path, nil, false)
+ }
+}
+func (bl *biomeList) onUp() {
+ idx, iter, path := bl.treeviewIdx()
+ if idx <= 0 {
+ return
+ }
+
+ path.Prev()
+ var iter2 gtk.TreeIter
+ bl.lStore.GetIter(&iter2, path)
+
+ bl.lStore.MoveBefore(iter, &iter2)
+
+ bl.biomes[idx], bl.biomes[idx-1] = bl.biomes[idx-1], bl.biomes[idx]
+}
+
+func (bl *biomeList) onDown() {
+ idx, iter, path := bl.treeviewIdx()
+ if (idx < 0) || (idx >= len(bl.biomes)-1) {
+ return
+ }
+
+ path.Next()
+ var iter2 gtk.TreeIter
+ bl.lStore.GetIter(&iter2, path)
+
+ bl.lStore.MoveAfter(iter, &iter2)
+
+ bl.biomes[idx], bl.biomes[idx+1] = bl.biomes[idx+1], bl.biomes[idx]
+}
+
+func connectBiomeListEditFrame(bl *biomeList, frm *biomeEditFrame) {
+ bl.editfrm = frm
+ frm.bList = bl
+}
+
+type BiomeInfoEditor struct {
+ *gtk.Dialog
+ biolist *biomeList
+}
+
+func NewBiomeInfoEditor(biomes []BiomeInfo) *BiomeInfoEditor {
+ ed := &BiomeInfoEditor{
+ Dialog: gtk.NewDialog(),
+ biolist: newBiomeList(),
+ }
+
+ ed.SetModal(true)
+
+ vbox := ed.GetVBox()
+
+ btnHBox := gtk.NewHBox(true, 0)
+
+ resetBtn := gtk.NewButtonWithLabel("Reset to defaults")
+ resetBtn.Connect("clicked", ed.reset)
+ loadBtn := gtk.NewButtonWithLabel("Load from file ...")
+ loadBtn.Connect("clicked", ed.load)
+ saveBtn := gtk.NewButtonWithLabel("Save to file ...")
+ saveBtn.Connect("clicked", ed.save)
+
+ btnHBox.PackStart(resetBtn, true, true, 3)
+ btnHBox.PackStart(loadBtn, true, true, 3)
+ btnHBox.PackStart(saveBtn, true, true, 3)
+ vbox.PackStart(btnHBox, false, false, 3)
+
+ ed.biolist.SetBiomes(biomes)
+ vbox.PackStart(ed.biolist, true, true, 3)
+
+ editFrame := newBiomeEditFrame()
+ connectBiomeListEditFrame(ed.biolist, editFrame)
+ vbox.PackStart(editFrame, false, false, 3)
+
+ ed.AddButton("Cancel", gtk.RESPONSE_CANCEL)
+ ed.AddButton("OK", gtk.RESPONSE_OK)
+ ed.ShowAll()
+ return ed
+}
+
+func (ed *BiomeInfoEditor) reset() {
+ ed.biolist.SetBiomes(ReadDefaultBiomes())
+}
+
+func mkBioFFilters() (*gtk.FileFilter, *gtk.FileFilter) {
+ f1 := gtk.NewFileFilter()
+ f1.AddPattern("*.biomes")
+ f1.SetName("Biome Infos (.biomes)")
+
+ f2 := gtk.NewFileFilter()
+ f2.AddPattern("*")
+ f2.SetName("All files")
+
+ return f1, f2
+}
+
+func errdlg(msg string, params ...interface{}) {
+ dlg := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg, params...)
+ dlg.Run()
+ dlg.Destroy()
+}
+
+func (ed *BiomeInfoEditor) load() {
+ dlg := gtk.NewFileChooserDialog("Load", nil, gtk.FILE_CHOOSER_ACTION_OPEN, "OK", gtk.RESPONSE_OK, "Cancel", gtk.RESPONSE_CANCEL)
+ defer dlg.Destroy()
+askFilename:
+ if dlg.Run() == gtk.RESPONSE_OK {
+ path := dlg.GetFilename()
+
+ f, err := os.Open(path)
+ if err != nil {
+ errdlg("Could not load biome infos %s:\n%s", path, err.Error())
+ goto askFilename
+ }
+ defer f.Close()
+
+ infos, err := ReadBiomeInfos(f)
+ if err != nil {
+ errdlg("Could not load biome infos %s:\n%s", path, err.Error())
+ goto askFilename
+ }
+
+ ed.biolist.SetBiomes(infos)
+ }
+}
+
+func (ed *BiomeInfoEditor) save() {
+ dlg := gtk.NewFileChooserDialog("Save", nil, gtk.FILE_CHOOSER_ACTION_SAVE, "OK", gtk.RESPONSE_OK, "Cancel", gtk.RESPONSE_CANCEL)
+ defer dlg.Destroy()
+askFilename:
+ if dlg.Run() == gtk.RESPONSE_OK {
+ path := dlg.GetFilename()
+
+ if _, err := os.Stat(path); err == nil {
+ qdlg := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "File %s already exists. Overwrite?", path)
+ resp := qdlg.Run()
+ qdlg.Destroy()
+
+ if resp != gtk.RESPONSE_YES {
+ goto askFilename
+ }
+ }
+
+ f, err := os.Create(path)
+ if err != nil {
+ errdlg("Could not save biome infos %s:\n%s", path, err.Error())
+ goto askFilename
+ }
+ defer f.Close()
+
+ if err := WriteBiomeInfos(ed.biolist.Biomes(), f); err != nil {
+ errdlg("Could not save biome infos %s:\n%s", path, err.Error())
+ goto askFilename
+ }
+ }
+}
+
+func (ed *BiomeInfoEditor) Biomes() []BiomeInfo { return ed.biolist.Biomes() }