Adding modding folder with a hacked build.
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/inkyblackness/imgui-go/v3"
|
||||
|
||||
"github.com/inkyblackness/hacked/ss1/edit"
|
||||
"github.com/inkyblackness/hacked/ss1/edit/undoable/cmd"
|
||||
"github.com/inkyblackness/hacked/ss1/world"
|
||||
"github.com/inkyblackness/hacked/ui/gui"
|
||||
)
|
||||
|
||||
// View handles the project display.
|
||||
type View struct {
|
||||
service *edit.ProjectService
|
||||
|
||||
modalStateMachine gui.ModalStateMachine
|
||||
guiScale float32
|
||||
commander cmd.Registry
|
||||
|
||||
model viewModel
|
||||
}
|
||||
|
||||
// NewView creates a new instance for the project display.
|
||||
func NewView(service *edit.ProjectService, modalStateMachine gui.ModalStateMachine, guiScale float32, commander cmd.Registry) *View {
|
||||
return &View{
|
||||
service: service,
|
||||
|
||||
modalStateMachine: modalStateMachine,
|
||||
guiScale: guiScale,
|
||||
commander: commander,
|
||||
|
||||
model: freshViewModel(),
|
||||
}
|
||||
}
|
||||
|
||||
// WindowOpen returns the flag address, to be used with the main menu.
|
||||
func (view *View) WindowOpen() *bool {
|
||||
return &view.model.windowOpen
|
||||
}
|
||||
|
||||
// Render requests to render the view.
|
||||
func (view *View) Render() {
|
||||
if view.model.restoreFocus {
|
||||
imgui.SetNextWindowFocus()
|
||||
view.model.restoreFocus = false
|
||||
view.model.windowOpen = true
|
||||
}
|
||||
title := "Project"
|
||||
saveStatus := view.service.SaveStatus()
|
||||
if saveStatus.FilesModified > 0 {
|
||||
title += fmt.Sprintf(" - %d file(s) pending save", saveStatus.FilesModified)
|
||||
if saveStatus.SavePending && (saveStatus.SaveIn.Seconds() < 4) {
|
||||
title += fmt.Sprintf(" - auto-save in %d", int(saveStatus.SaveIn.Seconds()))
|
||||
}
|
||||
}
|
||||
if view.model.windowOpen {
|
||||
imgui.SetNextWindowSizeV(imgui.Vec2{X: 400 * view.guiScale, Y: 300 * view.guiScale}, imgui.ConditionFirstUseEver)
|
||||
if imgui.BeginV(title+"###Project", view.WindowOpen(), 0) {
|
||||
view.renderContent()
|
||||
}
|
||||
imgui.End()
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) renderContent() {
|
||||
imgui.Text("Mod Location")
|
||||
imgui.PushStyleVarVec2(imgui.StyleVarWindowPadding, imgui.Vec2{X: 1, Y: 0})
|
||||
imgui.BeginChildV("ModLocation", imgui.Vec2{X: -200*view.guiScale - 10*view.guiScale, Y: imgui.TextLineHeight() * 1.5}, true,
|
||||
imgui.WindowFlagsNoScrollbar|imgui.WindowFlagsNoScrollWithMouse)
|
||||
modPath := view.service.ModPath()
|
||||
if len(modPath) > 0 {
|
||||
imgui.Text(modPath)
|
||||
} else {
|
||||
imgui.PushStyleColor(imgui.StyleColorText, imgui.Vec4{X: 1.0, Y: 1.0, Z: 1.0, W: 0.5})
|
||||
imgui.Text("(new mod)")
|
||||
imgui.PopStyleColor()
|
||||
}
|
||||
imgui.EndChild()
|
||||
imgui.PopStyleVar()
|
||||
imgui.BeginGroup()
|
||||
imgui.SameLine()
|
||||
if imgui.ButtonV("Save", imgui.Vec2{X: 100 * view.guiScale, Y: 0}) {
|
||||
view.StartSavingMod()
|
||||
}
|
||||
imgui.SameLine()
|
||||
if imgui.ButtonV("Load...", imgui.Vec2{X: 100 * view.guiScale, Y: 0}) {
|
||||
view.startLoadingMod()
|
||||
}
|
||||
imgui.EndGroup()
|
||||
|
||||
imgui.Text("Static World Data")
|
||||
imgui.BeginChildV("ManifestEntries", imgui.Vec2{X: -100 * view.guiScale, Y: 0}, true, 0)
|
||||
manifest := view.service.Mod().World()
|
||||
entries := manifest.EntryCount()
|
||||
for i := entries - 1; i >= 0; i-- {
|
||||
entry, _ := manifest.Entry(i)
|
||||
if imgui.SelectableV(entry.ID, view.model.selectedManifestEntry == i, 0, imgui.Vec2{}) {
|
||||
view.model.selectedManifestEntry = i
|
||||
}
|
||||
}
|
||||
imgui.EndChild()
|
||||
imgui.SameLine()
|
||||
imgui.BeginGroup()
|
||||
if imgui.ButtonV("Add...", imgui.Vec2{X: -1, Y: 0}) {
|
||||
view.startAddingManifestEntry()
|
||||
}
|
||||
if imgui.ButtonV("Up", imgui.Vec2{X: -1, Y: 0}) {
|
||||
view.requestMoveManifestEntryUp()
|
||||
}
|
||||
if imgui.ButtonV("Down", imgui.Vec2{X: -1, Y: 0}) {
|
||||
view.requestMoveManifestEntryDown()
|
||||
}
|
||||
if imgui.ButtonV("Remove", imgui.Vec2{X: -1, Y: 0}) {
|
||||
view.requestRemoveManifestEntry()
|
||||
}
|
||||
imgui.EndGroup()
|
||||
}
|
||||
|
||||
func (view *View) startLoadingMod() {
|
||||
view.modalStateMachine.SetState(&loadModStartState{
|
||||
machine: view.modalStateMachine,
|
||||
view: view,
|
||||
})
|
||||
}
|
||||
|
||||
// StartSavingMod initiates to save the mod.
|
||||
// It either opens the save-as dialog, or simply saves under the current folder.
|
||||
func (view *View) StartSavingMod() {
|
||||
if view.service.ModHasStorageLocation() {
|
||||
err := view.service.SaveMod()
|
||||
if err != nil {
|
||||
view.handleSaveModFailure(err)
|
||||
}
|
||||
} else {
|
||||
view.modalStateMachine.SetState(&saveModAsStartState{
|
||||
machine: view.modalStateMachine,
|
||||
view: view,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) startAddingManifestEntry() {
|
||||
view.modalStateMachine.SetState(&addManifestEntryStartState{
|
||||
machine: view.modalStateMachine,
|
||||
view: view,
|
||||
})
|
||||
}
|
||||
|
||||
func (view *View) requestMoveManifestEntryUp() {
|
||||
manifest := view.service.Mod().World()
|
||||
entries := manifest.EntryCount()
|
||||
if (view.model.selectedManifestEntry >= 0) && (view.model.selectedManifestEntry < (entries - 1)) {
|
||||
view.requestMoveManifestEntry(view.model.selectedManifestEntry+1, view.model.selectedManifestEntry)
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) requestMoveManifestEntryDown() {
|
||||
if view.model.selectedManifestEntry > 0 {
|
||||
view.requestMoveManifestEntry(view.model.selectedManifestEntry-1, view.model.selectedManifestEntry)
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) requestMoveManifestEntry(to, from int) {
|
||||
_ = view.commander.Register(
|
||||
cmd.Named("moveManifestEntry"),
|
||||
cmd.Reverse(view.taskToRestoreFocus()),
|
||||
cmd.Reverse(view.taskToSelectEntry(from)),
|
||||
cmd.Nested(func() error { return view.service.MoveManifestEntry(to, from) }),
|
||||
cmd.Forward(view.taskToSelectEntry(to)),
|
||||
cmd.Forward(view.taskToRestoreFocus()),
|
||||
)
|
||||
}
|
||||
|
||||
func (view *View) tryAddManifestEntryFrom(names []string) error {
|
||||
entry, err := world.NewManifestEntryFrom(names)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
view.requestAddManifestEntry(entry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (view *View) requestAddManifestEntry(entry *world.ManifestEntry) {
|
||||
at := view.model.selectedManifestEntry + 1
|
||||
_ = view.commander.Register(
|
||||
cmd.Named("addManifestEntry"),
|
||||
cmd.Reverse(view.taskToRestoreFocus()),
|
||||
cmd.Reverse(view.taskToSelectEntry(view.model.selectedManifestEntry)),
|
||||
cmd.Nested(func() error { return view.service.AddManifestEntry(at, entry) }),
|
||||
cmd.Forward(view.taskToSelectEntry(at)),
|
||||
cmd.Forward(view.taskToRestoreFocus()),
|
||||
)
|
||||
}
|
||||
|
||||
func (view *View) requestRemoveManifestEntry() {
|
||||
manifest := view.service.Mod().World()
|
||||
at := view.model.selectedManifestEntry
|
||||
if (at < 0) || (at >= manifest.EntryCount()) {
|
||||
return
|
||||
}
|
||||
|
||||
_ = view.commander.Register(
|
||||
cmd.Named("removeManifestEntry"),
|
||||
cmd.Reverse(view.taskToRestoreFocus()),
|
||||
cmd.Reverse(view.taskToSelectEntry(view.model.selectedManifestEntry)),
|
||||
cmd.Nested(func() error { return view.service.RemoveManifestEntry(at) }),
|
||||
cmd.Forward(view.taskToSelectEntry(view.model.selectedManifestEntry-1)),
|
||||
cmd.Forward(view.taskToRestoreFocus()),
|
||||
)
|
||||
}
|
||||
|
||||
func (view *View) tryLoadModFrom(names []string) error {
|
||||
return view.service.TryLoadModFrom(names)
|
||||
}
|
||||
|
||||
func (view *View) requestSaveMod(modPath string) {
|
||||
err := view.service.SaveModUnder(modPath)
|
||||
if err != nil {
|
||||
view.handleSaveModFailure(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) handleSaveModFailure(err error) {
|
||||
view.modalStateMachine.SetState(&saveModFailedState{
|
||||
machine: view.modalStateMachine,
|
||||
view: view,
|
||||
errorInfo: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
func (view *View) taskToRestoreFocus() cmd.Task {
|
||||
return func(modder world.Modder) error {
|
||||
view.model.restoreFocus = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (view *View) taskToSelectEntry(index int) cmd.Task {
|
||||
return func(modder world.Modder) error {
|
||||
view.model.selectedManifestEntry = index
|
||||
return nil
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user