From 63f3da9141e9fcb7e1b56e756f756a62d9d9d925 Mon Sep 17 00:00:00 2001 From: sathya-pramodh Date: Tue, 20 Feb 2024 22:03:10 +0530 Subject: [PATCH] feat: Add support for multiple alternate resolutions. --- internal/cfg/binds.go | 35 +++++++++++++++++++++++++++++++++++ internal/cfg/cfg.go | 8 +++++--- internal/ctl/ctl.go | 4 ++-- internal/ctl/moving.go | 10 +++++++++- internal/ctl/multi.go | 10 +++++++++- internal/ctl/wall.go | 10 +++++++++- internal/mc/instance.go | 4 ++-- internal/res/default.toml | 3 +++ 8 files changed, 74 insertions(+), 10 deletions(-) diff --git a/internal/cfg/binds.go b/internal/cfg/binds.go index 74cd555..e920d9f 100644 --- a/internal/cfg/binds.go +++ b/internal/cfg/binds.go @@ -69,6 +69,9 @@ type Bind struct { str string } +// AltRes represents a list of alternate resolutions. +type AltRes []Rectangle + // UnmarshalTOML implements toml.Unmarshaler. func (a *ActionList) UnmarshalTOML(value any) error { actionsRaw, ok := value.([]any) @@ -110,6 +113,9 @@ func (a *ActionList) UnmarshalTOML(value any) error { if typ >= ActionWallLock && typ <= ActionWallResetOthers { a.WallActions = append(a.WallActions, Action{typ, &num}) uniqueWall[Action{typ, &num}] = true + } else if typ == ActionIngameRes { + a.IngameActions = append(a.IngameActions, Action{typ, &num}) + uniqueGame[Action{typ, &num}] = true } else { return fmt.Errorf("action %q cannot have number", actionStr) } @@ -177,6 +183,35 @@ func (b *Bind) UnmarshalTOML(value any) error { return nil } +// UnmarshalTOML implements toml.Unmarshaler. +func (a *AltRes) UnmarshalTOML(value any) error { + str, ok := value.(string) + if !ok { + resListRaw, ok := value.([]any) + if !ok { + return errors.New("parse alt_res as a single resolution or a list of resolutions") + } + for _, raw := range resListRaw { + var res Rectangle + resStr, ok := raw.(string) + if !ok { + return errors.New("parse alt_res as a list of resolutions") + } + if err := res.UnmarshalTOML(resStr); err != nil { + return fmt.Errorf("parse alternate resolution: %w", err) + } + *a = append(*a, res) + } + } else { + var res Rectangle + if err := res.UnmarshalTOML(str); err != nil { + return fmt.Errorf("parse alternate resolution: %w", err) + } + *a = append(*a, res) + } + return nil +} + // UnmarshalTOML implements toml.Unmarshaler. func (k *Keybinds) UnmarshalTOML(value any) error { m, ok := value.(map[string]any) diff --git a/internal/cfg/cfg.go b/internal/cfg/cfg.go index 5a28d94..ed8ccc0 100644 --- a/internal/cfg/cfg.go +++ b/internal/cfg/cfg.go @@ -127,7 +127,7 @@ type Profile struct { UnpauseFocus bool `toml:"unpause_focus"` // Whether to unpause on focus PollRate int `toml:"poll_rate"` // Polling rate for input handling NormalRes *Rectangle `toml:"play_res"` // Normal resolution - AltRes *Rectangle `toml:"alt_res"` // Alternate ingame resolution + AltRes AltRes `toml:"alt_res"` // Alternate ingame resolution Delay Delays `toml:"delay"` Hooks Hooks `toml:"hooks"` @@ -279,8 +279,10 @@ func validateProfile(conf *Profile) error { if !validateRectangle(conf.NormalRes) { return errors.New("invalid playing resolution") } - if !validateRectangle(conf.AltRes) { - return errors.New("invalid alternate resolution") + for idx, res := range conf.AltRes { + if !validateRectangle(&res) { + return fmt.Errorf("invalid alternate resolution at index %d", idx) + } } alt := conf.AltRes != nil normal := conf.NormalRes != nil diff --git a/internal/ctl/ctl.go b/internal/ctl/ctl.go index 7a97ba1..c29f998 100644 --- a/internal/ctl/ctl.go +++ b/internal/ctl/ctl.go @@ -312,8 +312,8 @@ func (c *Controller) FocusInstance(id int) { // ToggleResolution switches the given instance between the normal and alternate // resolution. -func (c *Controller) ToggleResolution(id int) { - if c.manager.ToggleResolution(id) { +func (c *Controller) ToggleResolution(id int, resId int) { + if c.manager.ToggleResolution(id, resId) { c.RunHook(HookAltRes) } else { c.RunHook(HookNormalRes) diff --git a/internal/ctl/moving.go b/internal/ctl/moving.go index cc3a3ca..e50c653 100644 --- a/internal/ctl/moving.go +++ b/internal/ctl/moving.go @@ -100,7 +100,15 @@ func (m *MovingWall) Input(input Input) { case cfg.ActionIngameFocus: m.host.FocusInstance(m.active) case cfg.ActionIngameRes: - m.host.ToggleResolution(m.active) + if action.Extra != nil { + resId := *action.Extra + if resId < 0 || resId > len(m.conf.AltRes)-1 { + continue + } + m.host.ToggleResolution(m.active, resId) + } else { + m.host.ToggleResolution(m.active, 0) + } } } } else { diff --git a/internal/ctl/multi.go b/internal/ctl/multi.go index 1bcfbe6..536fc03 100644 --- a/internal/ctl/multi.go +++ b/internal/ctl/multi.go @@ -62,7 +62,15 @@ func (m *Multi) Input(input Input) { m.host.RunHook(HookReset) } case cfg.ActionIngameRes: - m.host.ToggleResolution(m.active) + if action.Extra != nil { + resId := *action.Extra + if resId < 0 || resId > len(m.conf.AltRes)-1 { + continue + } + m.host.ToggleResolution(m.active, resId) + } else { + m.host.ToggleResolution(m.active, 0) + } } } } diff --git a/internal/ctl/wall.go b/internal/ctl/wall.go index 87cde35..db5ab56 100644 --- a/internal/ctl/wall.go +++ b/internal/ctl/wall.go @@ -90,7 +90,15 @@ func (w *Wall) Input(input Input) { case cfg.ActionIngameFocus: w.host.FocusInstance(w.active) case cfg.ActionIngameRes: - w.host.ToggleResolution(w.active) + if action.Extra != nil { + resId := *action.Extra + if resId < 0 || resId > len(w.conf.AltRes)-1 { + continue + } + w.host.ToggleResolution(w.active, resId) + } else { + w.host.ToggleResolution(w.active, 0) + } } } } else { diff --git a/internal/mc/instance.go b/internal/mc/instance.go index 8edc740..11a93e6 100644 --- a/internal/mc/instance.go +++ b/internal/mc/instance.go @@ -240,11 +240,11 @@ func (m *Manager) Focus(id int) { // ToggleResolution switches the given instance between the normal and alternate // resolution and returns whether or not it is now on the alternate resolution. -func (m *Manager) ToggleResolution(id int) bool { +func (m *Manager) ToggleResolution(id int, resId int) bool { if m.instances[id].altRes { m.setResolution(id, m.conf.NormalRes) } else { - m.setResolution(id, m.conf.AltRes) + m.setResolution(id, &m.conf.AltRes[resId]) } m.instances[id].altRes = !m.instances[id].altRes m.Focus(id) diff --git a/internal/res/default.toml b/internal/res/default.toml index 8250783..5e831e7 100644 --- a/internal/res/default.toml +++ b/internal/res/default.toml @@ -18,6 +18,8 @@ play_res = "1920x1080+0,0" # An alternate resolution that can be toggled to while ingame. Delete this if # you do not want to use e.g. thin or tall window. +# You can even declare this as a list of resolutions. +# Eg: alt_res = ["400x1080+810,0", "1920x300+0,390"] alt_res = "400x1080+810,0" # The delay section contains delays (in milliseconds) before performing various @@ -82,6 +84,7 @@ wall_reset = "" # - ingame_focus Focus active instance. # - ingame_reset Reset active instance. # - ingame_toggle_res Toggle the resolution for active instance. +# - ingame_toggle_res(n) Toggle the resolution N for active instance. # - wall_focus Focus wall projector. # - wall_reset_all Reset all unlocked instances. # - wall_lock Lock hovered instance.