diff --git a/Taskfile.yml b/Taskfile.yml index f741f1a..a63c9a7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -23,12 +23,30 @@ tasks: resources: desc: Compile resource file cmds: - - rsrc -manifest ./cmd/abyss-blackbox/main.manifest -ico ./trig_96x96.ico,./images/plus.ico,./images/switch-char.ico -o ./cmd/abyss-blackbox/rsrc.syso + - rsrc -manifest ./cmd/abyss-blackbox/main.manifest -ico ./trig_96x96.ico,./images/plus.ico,./images/switch-char.ico,./images/select-area.ico -o ./cmd/abyss-blackbox/rsrc.syso + debug: + desc: Builds artifacts for release + deps: [install-deps, resources] + cmds: + - go generate ./... + - go build -trimpath -ldflags "-s -w -X github.com/shivas/abyss-blackbox/internal/version.RecorderVersion={{.GIT_VERSION}} -X github.com/shivas/abyss-blackbox/internal/version.GoVersion={{.GO_VERSION}}" -o abyss-blackbox.exe ./cmd/abyss-blackbox + - go build -trimpath -ldflags="-s -w" ./cmd/extract/ + vars: + GIT_VERSION: + sh: git describe --tags --always + GO_VERSION: + sh: go env GOVERSION + release: desc: Builds artifacts for release deps: [install-deps, resources] cmds: - go generate ./... - - go build -trimpath -ldflags="-H windowsgui -s -w" -o abyss-blackbox.exe ./cmd/abyss-blackbox + - go build -trimpath -ldflags="-H windowsgui -s -w -X github.com/shivas/abyss-blackbox/internal/version.RecorderVersion={{.GIT_VERSION}} -X github.com/shivas/abyss-blackbox/internal/version.GoVersion={{.GO_VERSION}}" -o abyss-blackbox.exe ./cmd/abyss-blackbox - go build -trimpath -ldflags="-s -w" ./cmd/extract/ + vars: + GIT_VERSION: + sh: git describe --tags --always + GO_VERSION: + sh: go env GOVERSION diff --git a/cmd/abyss-blackbox/main.go b/cmd/abyss-blackbox/main.go index be381ec..5af760e 100644 --- a/cmd/abyss-blackbox/main.go +++ b/cmd/abyss-blackbox/main.go @@ -14,6 +14,7 @@ import ( "github.com/lxn/win" "github.com/shivas/abyss-blackbox/combatlog" "github.com/shivas/abyss-blackbox/internal/charmanager" + "github.com/shivas/abyss-blackbox/internal/config" "github.com/shivas/abyss-blackbox/internal/mainwindow" "github.com/shivas/abyss-blackbox/internal/uploader" "github.com/shivas/abyss-blackbox/screen" @@ -26,17 +27,10 @@ var recordingChannel chan *image.Paletted var notificationChannel chan NotificationMessage var recorder *Recorder -const ( - hotkeyRecoder = iota + 1 - hotkeyWeather30 - hotkeyWeather50 - hotkeyWeather70 -) - func main() { var err error - currentSettings, err := readConfig() + currentSettings, err := config.Read() if err != nil { log.Fatal(err) } @@ -60,9 +54,6 @@ func main() { comboModel = append(comboModel, &mainwindow.WindowComboBoxItem{WindowTitle: title, WindowHandle: handle}) } - logFiles, _ := clr.GetLogFiles(time.Now(), time.Duration(24)*time.Hour) - charMap := clr.MapCharactersToFiles(logFiles) - charManager := charmanager.New(func(s1, s2 string) { notificationChannel <- NotificationMessage{Title: s1, Message: s2} }) @@ -70,12 +61,10 @@ func main() { actions := make(map[string]walk.EventHandler) actions["add_character"] = charManager.EventHandlerCharAdd - armw := mainwindow.NewAbyssRecorderWindow(currentSettings, drawStuff, comboModel, actions) + armw := mainwindow.NewAbyssRecorderWindow(currentSettings, drawStuff, comboModel, actions, clr) _ = charManager.MainWindow(armw).LoadCache() // assign window to control widgets charManager.RefreshUI() - mainwindow.BuildSettingsWidget(charMap, armw.CombatLogCharacterGroup) - charManager.OnActivateCharacter = func(char charmanager.Character) { if char.CharacterID > 0 { @@ -87,7 +76,7 @@ func main() { currentSettings.ActiveCharacter = char.CharacterID armw.AutoUploadCheckbox.SetEnabled(char.CharacterID > 0) - _ = writeConfig(currentSettings) + _ = config.Write(currentSettings) } _ = charManager.SetActiveCharacter(currentSettings.ActiveCharacter) @@ -96,21 +85,6 @@ func main() { walk.MsgBox(armw.MainWindow, "No signed in EVE clients detected", "Please login with atleast one character and then restart this application", walk.MsgBoxIconWarning) } - armw.ChooseLogDirButton.Clicked().Attach(func() { - fd := walk.FileDialog{} - accepted, _ := fd.ShowBrowseFolder(armw.MainWindow) - if accepted { - _ = armw.EVEGameLogsFolderLabel.SetText(fd.FilePath) - clr.SetLogFolder(fd.FilePath) - logFiles, err = clr.GetLogFiles(time.Now(), time.Duration(24)*time.Hour) - if err != nil { - return - } - charMap := clr.MapCharactersToFiles(logFiles) - mainwindow.BuildSettingsWidget(charMap, armw.CombatLogCharacterGroup) - } - }) - notificationIcon := CreateNotificationIcon(armw.MainWindow) defer func() { @@ -146,21 +120,22 @@ func main() { } recorder.Start(charsChecked) + + _ = armw.MainWindow.Menu().Actions().At(0).SetVisible(false) armw.CombatLogCharacterGroup.SetEnabled(false) armw.CaptureSettingsGroup.SetEnabled(false) - armw.ChooseLogDirButton.SetEnabled(false) - armw.LootRecordDiscriminatorEdit.SetEnabled(false) armw.TestServer.SetEnabled(false) + _ = armw.Toolbar.Actions().At(3).SetEnabled(false) _ = armw.RecordingButton.SetText("Stop recording") } else { filename, errr := recorder.Stop() if errr != nil { - walk.MsgBox(armw.MainWindow, "Error writing recording", err.Error(), walk.MsgBoxIconWarning) + walk.MsgBox(armw.MainWindow, "Error writing recording", errr.Error(), walk.MsgBoxIconWarning) } char := charManager.ActiveCharacter() - if armw.AutoUploadCheckbox.Checked() && char != nil { + if armw.AutoUploadCheckbox.Checked() && char != nil && errr == nil { go func(fn string, t string) { uploadFile, uploadErr := uploader.Upload(fn, t) if uploadErr != nil { @@ -171,74 +146,42 @@ func main() { }(filename, char.CharacterToken) } + _ = armw.MainWindow.Menu().Actions().At(0).SetVisible(true) armw.CombatLogCharacterGroup.SetEnabled(true) armw.CaptureSettingsGroup.SetEnabled(true) - armw.ChooseLogDirButton.SetEnabled(true) armw.TestServer.SetEnabled(true) - armw.LootRecordDiscriminatorEdit.SetEnabled(true) + _ = armw.Toolbar.Actions().At(3).SetEnabled(true) _ = armw.RecordingButton.SetText("Start recording") } } armw.RecordingButton.Clicked().Attach(recordingButtonHandler) + armw.PresetSaveButton.Clicked().Attach(func() { + p := config.Preset{X: currentSettings.X, Y: currentSettings.Y, H: currentSettings.H} + _, _ = mainwindow.RunNewPresetDialog(armw.MainWindow, p, currentSettings) + _ = config.Write(currentSettings) + armw.RefreshPresets(currentSettings) + }) + + armw.RefreshPresets(currentSettings) + armw.MainWindow.Hotkey().Attach(func(hkid int) { switch hkid { - case hotkeyRecoder: + case config.HotkeyRecoder: recordingButtonHandler() - case hotkeyWeather30: + case config.HotkeyWeather30: recorder.GetWeatherStrengthListener(30)() - case hotkeyWeather50: + case config.HotkeyWeather50: recorder.GetWeatherStrengthListener(50)() - case hotkeyWeather70: + case config.HotkeyWeather70: recorder.GetWeatherStrengthListener(70)() } }) - walk.RegisterGlobalHotKey(armw.MainWindow, hotkeyRecoder, currentSettings.RecorderShortcut) - walk.RegisterGlobalHotKey(armw.MainWindow, hotkeyWeather30, currentSettings.Weather30Shortcut) - walk.RegisterGlobalHotKey(armw.MainWindow, hotkeyWeather50, currentSettings.Weather50Shortcut) - walk.RegisterGlobalHotKey(armw.MainWindow, hotkeyWeather70, currentSettings.Weather70Shortcut) - - shortcutRecorderHandler := GetShortcutRecordingHandler( - armw.RecorderShortcutEdit, - armw.RecorderShortcutRecordButton, - armw.MainWindow, - hotkeyRecoder, - currentSettings, - currentSettings.RecorderShortcut, - ) - - shortcutWeather30Handler := GetShortcutRecordingHandler( - armw.Weather30ShortcutEdit, - armw.Weather30ShortcutRecordButton, - armw.MainWindow, - hotkeyWeather30, - currentSettings, - currentSettings.Weather30Shortcut, - ) - - shortcutWeather50Handler := GetShortcutRecordingHandler( - armw.Weather50ShortcutEdit, - armw.Weather50ShortcutRecordButton, - armw.MainWindow, - hotkeyWeather50, - currentSettings, - currentSettings.Weather50Shortcut, - ) - - shortcutWeather70Handler := GetShortcutRecordingHandler( - armw.Weather70ShortcutEdit, - armw.Weather70ShortcutRecordButton, - armw.MainWindow, - hotkeyWeather70, - currentSettings, - currentSettings.Weather70Shortcut, - ) - - armw.RecorderShortcutRecordButton.Clicked().Attach(shortcutRecorderHandler) - armw.Weather30ShortcutRecordButton.Clicked().Attach(shortcutWeather30Handler) - armw.Weather50ShortcutRecordButton.Clicked().Attach(shortcutWeather50Handler) - armw.Weather70ShortcutRecordButton.Clicked().Attach(shortcutWeather70Handler) + walk.RegisterGlobalHotKey(armw.MainWindow, config.HotkeyRecoder, currentSettings.RecorderShortcut) + walk.RegisterGlobalHotKey(armw.MainWindow, config.HotkeyWeather30, currentSettings.Weather30Shortcut) + walk.RegisterGlobalHotKey(armw.MainWindow, config.HotkeyWeather50, currentSettings.Weather50Shortcut) + walk.RegisterGlobalHotKey(armw.MainWindow, config.HotkeyWeather70, currentSettings.Weather70Shortcut) go func(cw *walk.CustomWidget) { t := time.NewTicker(time.Second) @@ -285,7 +228,7 @@ func main() { walk.Clipboard().ContentsChanged().Attach(recorder.ClipboardListener) defer func() { - err = writeConfig(currentSettings) + err = config.Write(currentSettings) if err != nil { log.Fatalf("failed to save settings after main window close: %v", err) } diff --git a/cmd/abyss-blackbox/recorder.go b/cmd/abyss-blackbox/recorder.go index bf13888..39a1b1c 100644 --- a/cmd/abyss-blackbox/recorder.go +++ b/cmd/abyss-blackbox/recorder.go @@ -15,6 +15,8 @@ import ( "github.com/lxn/walk" "github.com/shivas/abyss-blackbox/combatlog" "github.com/shivas/abyss-blackbox/encoding" + "github.com/shivas/abyss-blackbox/internal/config" + "github.com/shivas/abyss-blackbox/internal/version" ) const ( @@ -28,7 +30,7 @@ type Recorder struct { state int frameChan chan *image.Paletted loot chan string - config *captureConfig + config *config.CaptureConfig done chan bool frames []*image.Paletted delays []int @@ -41,7 +43,7 @@ type Recorder struct { } // NewRecorder constructs Recorder -func NewRecorder(frameChan chan *image.Paletted, c *captureConfig, nc chan NotificationMessage, clr *combatlog.Reader) *Recorder { +func NewRecorder(frameChan chan *image.Paletted, c *config.CaptureConfig, nc chan NotificationMessage, clr *combatlog.Reader) *Recorder { return &Recorder{ frameChan: frameChan, loot: make(chan string, 2), @@ -121,6 +123,10 @@ func (r *Recorder) StartLoop() { if r.state == RecorderRunning { // append to buffer r.frames = append(r.frames, frame) r.delays = append(r.delays, 10) + + if r.weatherStrength == 0 && (len(r.frames)%180 == 0) { // remind every 3 minutes skipping initial frame + r.notificationChannel <- NotificationMessage{"Reminder", "Please record weather strength!"} + } } r.Unlock() default: @@ -218,6 +224,14 @@ func (r *Recorder) Stop() (string, error) { TestServer: r.config.TestServer, WeatherStrength: int32(r.weatherStrength), LootRecordDiscriminator: r.config.LootRecordDiscriminator, + RecorderVersion: version.RecorderVersion, + ManualAbyssTypeOverride: r.config.AbyssTypeOverride, + } + + if r.config.AbyssTypeOverride { + abyssFile.AbyssShipType = encoding.AbyssRecording_AbyssShipType(r.config.AbyssShipType) + abyssFile.AbyssTier = int32(r.config.AbyssTier) + abyssFile.AbyssWheather = r.config.AbyssWeather } err = abyssFile.Encode(file) diff --git a/cmd/abyss-blackbox/rsrc.syso b/cmd/abyss-blackbox/rsrc.syso index 8a3d5f0..7d454d4 100644 Binary files a/cmd/abyss-blackbox/rsrc.syso and b/cmd/abyss-blackbox/rsrc.syso differ diff --git a/cmd/abyss-blackbox/shortcuts.go b/cmd/abyss-blackbox/shortcuts.go deleted file mode 100644 index 0573f00..0000000 --- a/cmd/abyss-blackbox/shortcuts.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "github.com/lxn/walk" - "github.com/lxn/win" -) - -// GetShortcutRecordingHandler creates handler for shortcut recording. -func GetShortcutRecordingHandler( - e *walk.LineEdit, - b *walk.PushButton, - m *walk.MainWindow, - id int, - settings *captureConfig, - shortcut walk.Shortcut, -) func() { - return func() { - if !e.Enabled() { // start recording - e.SetEnabled(true) - _ = e.SetFocus() - _ = b.SetText("Save") - - if !win.UnregisterHotKey(m.Handle(), id) { - walk.MsgBox(m, "Failed unregistering hotkey", "failed unregistering key, please restart application", walk.MsgBoxIconWarning) - return - } - } else { // persist new shortcut and rebind - e.SetEnabled(false) - _ = b.SetText("Record shortcut") - if !walk.RegisterGlobalHotKey(m, id, shortcut) { - walk.MsgBox(m, "Failed registering new hotkey", "failed registering new shortcut key, please restart application", walk.MsgBoxIconWarning) - return - } - _ = writeConfig(settings) - } - } -} diff --git a/go.mod b/go.mod index 16f32ae..909e359 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/shivas/abyss-blackbox -go 1.13 +go 1.16 require ( github.com/disintegration/gift v1.2.1 diff --git a/images/select-area.ico b/images/select-area.ico new file mode 100644 index 0000000..503b922 Binary files /dev/null and b/images/select-area.ico differ diff --git a/cmd/abyss-blackbox/config.go b/internal/config/config.go similarity index 79% rename from cmd/abyss-blackbox/config.go rename to internal/config/config.go index 11e4a2b..c4bef5c 100644 --- a/cmd/abyss-blackbox/config.go +++ b/internal/config/config.go @@ -1,4 +1,4 @@ -package main +package config import ( "encoding/json" @@ -8,12 +8,23 @@ import ( "sync" "github.com/lxn/walk" - "github.com/shivas/abyss-blackbox/internal/mainwindow" ) -type captureConfig struct { +const ( + HotkeyRecoder = iota + 1 + HotkeyWeather30 + HotkeyWeather50 + HotkeyWeather70 +) + +type Preset struct { + X, Y, H int +} + +type CaptureConfig struct { sync.Mutex X, Y, H int + Presets map[string]Preset AppRoot string Recordings string FilterThreshold int @@ -32,37 +43,41 @@ type captureConfig struct { LootRecordDiscriminator string ActiveCharacter int32 AutoUpload bool + AbyssTypeOverride bool + AbyssShipType int + AbyssTier int + AbyssWeather string } // SetRecorderShortcut satisfies ShortcutSetter interface. -func (c *captureConfig) SetRecorderShortcut(shorcutType int, s walk.Shortcut) { +func (c *CaptureConfig) SetRecorderShortcut(shorcutType int, s walk.Shortcut) { switch shorcutType { - case mainwindow.ShortcutRecorder: + case HotkeyRecoder: c.RecorderShortcut = s c.RecorderShortcutText = s.String() - case mainwindow.ShortcutWeather30: + case HotkeyWeather30: c.Weather30Shortcut = s c.Weather30ShortcutText = s.String() - case mainwindow.ShortcutWeather50: + case HotkeyWeather50: c.Weather50Shortcut = s c.Weather50ShortcutText = s.String() - case mainwindow.ShortcutWeather70: + case HotkeyWeather70: c.Weather70Shortcut = s c.Weather70ShortcutText = s.String() } } -// readConfig reads configuration from json file, or creates one if file doesn't exist -func readConfig() (*captureConfig, error) { +// Read reads configuration from json file, or creates one if file doesn't exist +func Read() (*CaptureConfig, error) { appDir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { return nil, err } - var c *captureConfig + var c *CaptureConfig load := true settingsFilename := filepath.Join(appDir, "settings.json") @@ -82,14 +97,16 @@ func readConfig() (*captureConfig, error) { eveGameLogsFolder := filepath.Join(usr.HomeDir, "Documents", "EVE", "logs", "Gamelogs") - c = &captureConfig{ + c = &CaptureConfig{ AppRoot: appDir, X: 10, Y: 10, H: 400, + Presets: make(map[string]Preset), Recordings: filepath.Join(appDir, "recordings"), FilterThreshold: 110, FilteredPreview: false, + AbyssTypeOverride: false, EVEGameLogsFolder: eveGameLogsFolder, RecorderShortcutText: defaultRecorderShortcut.String(), RecorderShortcut: defaultRecorderShortcut, @@ -100,6 +117,9 @@ func readConfig() (*captureConfig, error) { Weather70ShortcutText: defaultWeather70Shortcut.String(), Weather70Shortcut: defaultWeather70Shortcut, LootRecordDiscriminator: "Quafe", + AbyssShipType: 1, + AbyssTier: 0, + AbyssWeather: "Dark", } load = false } else if err != nil { @@ -141,13 +161,21 @@ func readConfig() (*captureConfig, error) { if c.LootRecordDiscriminator == "" { c.LootRecordDiscriminator = "Quafe" } + + if c.AbyssShipType == 0 { + c.AbyssShipType = 1 + } + + if c.AbyssWeather == "" { + c.AbyssWeather = "Dark" + } } return c, nil } -// writeConfig saves configuration to json file -func writeConfig(c *captureConfig) error { +// Write saves configuration to json file +func Write(c *CaptureConfig) error { settingsFilename := filepath.Join(c.AppRoot, "settings.json") f, err := os.Create(settingsFilename) diff --git a/internal/mainwindow/aboutdialog.go b/internal/mainwindow/aboutdialog.go new file mode 100644 index 0000000..8f91071 --- /dev/null +++ b/internal/mainwindow/aboutdialog.go @@ -0,0 +1,92 @@ +package mainwindow + +import ( + "bytes" + + "github.com/lxn/walk" + . "github.com/lxn/walk/declarative" // nolint:stylecheck,revive // we needs side effects + "github.com/pkg/browser" + + _ "embed" + "image" + _ "image/png" + + "github.com/shivas/abyss-blackbox/internal/version" +) + +//go:embed triglogo.png +var logo []byte + +func RunAboutDialog(owner walk.Form) (int, error) { + var ( + dlg *walk.Dialog + acceptPB *walk.PushButton + appLogo *walk.ImageView + ) + + png, _, _ := image.Decode(bytes.NewReader(logo)) + img, _ := walk.NewBitmapFromImage(png) + + return (Dialog{ + AssignTo: &dlg, + Title: "About", + DefaultButton: &acceptPB, + Layout: VBox{}, + Children: []Widget{ + Composite{ + Layout: HBox{}, + Children: []Widget{ + ImageView{ + AssignTo: &appLogo, + Image: img, + }, + Composite{ + Layout: VBox{}, + Children: []Widget{ + TextLabel{ + Text: "Version: " + version.RecorderVersion, + }, + TextLabel{ + Text: "Go: " + version.GoVersion, + }, + LinkLabel{ + Alignment: AlignHNearVCenter, + Text: `Telemetry site: https://abyssal.space`, + OnLinkActivated: func(link *walk.LinkLabelLink) { + _ = browser.OpenURL(link.URL()) + }, + }, + LinkLabel{ + Alignment: AlignHNearVCenter, + Text: `Recorder releases: https://github.com/shivas/abyss-blackbox`, + OnLinkActivated: func(link *walk.LinkLabelLink) { + _ = browser.OpenURL(link.URL()) + }, + }, + LinkLabel{ + Alignment: AlignHNearVCenter, + Text: `For help join Abyssal Lurkers Discord #abyss-telemetry channel.`, + OnLinkActivated: func(link *walk.LinkLabelLink) { + _ = browser.OpenURL(link.URL()) + }, + }, + }, + }, + }, + }, + Composite{ + Layout: HBox{}, + Children: []Widget{ + HSpacer{}, + PushButton{ + AssignTo: &acceptPB, + Text: "OK", + OnClicked: func() { + dlg.Accept() + }, + }, + }, + }, + }, + }).Run(owner) +} diff --git a/internal/mainwindow/abysstypechooser.go b/internal/mainwindow/abysstypechooser.go new file mode 100644 index 0000000..64c41ef --- /dev/null +++ b/internal/mainwindow/abysstypechooser.go @@ -0,0 +1,132 @@ +package mainwindow + +import ( + "bytes" + "embed" + "image" + _ "image/png" + + "github.com/lxn/walk" + "github.com/shivas/abyss-blackbox/internal/config" +) + +//go:embed images/* +var abyssIcons embed.FS + +type AbyssTypeChooser struct { + toolbar *walk.ToolBar + cfg *config.CaptureConfig + shipTypes []abyssToolbarOption + tiers []abyssToolbarOption + weathers []abyssToolbarOption +} + +type abyssToolbarOption struct { + Title string + Icon *walk.Icon +} + +func NewAbyssTypeChooser(t *walk.ToolBar, c *config.CaptureConfig) *AbyssTypeChooser { + return &AbyssTypeChooser{toolbar: t, cfg: c} +} + +func (a *AbyssTypeChooser) Init() { + a.shipTypes = make([]abyssToolbarOption, 0) + a.shipTypes = append(a.shipTypes, + abyssToolbarOption{Title: "Cruiser", Icon: embededIcon("images/Ship.png")}, + abyssToolbarOption{Title: "Destroyers", Icon: embededIcon("images/Ship.png")}, + abyssToolbarOption{Title: "Frigates", Icon: embededIcon("images/Ship.png")}, + ) + + a.tiers = make([]abyssToolbarOption, 0) + a.tiers = append(a.tiers, + abyssToolbarOption{Title: "Tier 0", Icon: embededIcon("images/0.png")}, + abyssToolbarOption{Title: "Tier 1", Icon: embededIcon("images/1.png")}, + abyssToolbarOption{Title: "Tier 2", Icon: embededIcon("images/2.png")}, + abyssToolbarOption{Title: "Tier 3", Icon: embededIcon("images/3.png")}, + abyssToolbarOption{Title: "Tier 4", Icon: embededIcon("images/4.png")}, + abyssToolbarOption{Title: "Tier 5", Icon: embededIcon("images/5.png")}, + abyssToolbarOption{Title: "Tier 6", Icon: embededIcon("images/6.png")}, + ) + + a.weathers = make([]abyssToolbarOption, 0) + a.weathers = append(a.weathers, + abyssToolbarOption{Title: "Dark", Icon: embededIcon("images/Dark.png")}, + abyssToolbarOption{Title: "Electrical", Icon: embededIcon("images/Electrical.png")}, + abyssToolbarOption{Title: "Exotic", Icon: embededIcon("images/Exotic.png")}, + abyssToolbarOption{Title: "Firestorm", Icon: embededIcon("images/Firestorm.png")}, + abyssToolbarOption{Title: "Gamma", Icon: embededIcon("images/Gamma.png")}, + ) + + for i, s := range a.shipTypes { + s := s + shipType := i + 1 + if shipType == a.cfg.AbyssShipType { + a.toolbar.Actions().At(0).SetText(s.Title) + a.toolbar.Actions().At(0).SetImage(s.Icon) + } + a.toolbar.Actions().At(0).Menu().Actions().At(i).SetText(s.Title) + a.toolbar.Actions().At(0).Menu().Actions().At(i).SetImage(s.Icon) + a.toolbar.Actions().At(0).Menu().Actions().At(i).Triggered().Attach(func() { + a.toolbar.Actions().At(0).SetText(s.Title) + a.toolbar.Actions().At(0).SetImage(s.Icon) + a.cfg.AbyssShipType = shipType + config.Write(a.cfg) + }) + } + + for i, s := range a.tiers { + s := s + tier := i + if i == a.cfg.AbyssTier { + a.toolbar.Actions().At(1).SetText(s.Title) + a.toolbar.Actions().At(1).SetImage(s.Icon) + } + a.toolbar.Actions().At(1).Menu().Actions().At(i).SetText(s.Title) + a.toolbar.Actions().At(1).Menu().Actions().At(i).SetImage(s.Icon) + a.toolbar.Actions().At(1).Menu().Actions().At(i).Triggered().Attach(func() { + a.toolbar.Actions().At(1).SetText(s.Title) + a.toolbar.Actions().At(1).SetImage(s.Icon) + a.cfg.AbyssTier = tier + config.Write(a.cfg) + }) + } + + for i, s := range a.weathers { + s := s + weather := s.Title + + if weather == a.cfg.AbyssWeather { + a.toolbar.Actions().At(2).SetText(s.Title) + a.toolbar.Actions().At(2).SetImage(s.Icon) + } + a.toolbar.Actions().At(2).Menu().Actions().At(i).SetText(s.Title) + a.toolbar.Actions().At(2).Menu().Actions().At(i).SetImage(s.Icon) + a.toolbar.Actions().At(2).Menu().Actions().At(i).Triggered().Attach(func() { + a.toolbar.Actions().At(2).SetText(s.Title) + a.toolbar.Actions().At(2).SetImage(s.Icon) + a.cfg.AbyssWeather = s.Title + config.Write(a.cfg) + }) + + } +} + +func embededIcon(name string) *walk.Icon { + data, err := abyssIcons.ReadFile(name) + if err != nil { + panic(err) + } + + img, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + panic(err) + } + + icon, err := walk.NewIconFromImageForDPI(img, 92) + if err != nil { + panic(err) + } + + return icon +} diff --git a/internal/mainwindow/characters.go b/internal/mainwindow/characters.go deleted file mode 100644 index d44a69a..0000000 --- a/internal/mainwindow/characters.go +++ /dev/null @@ -1,21 +0,0 @@ -package mainwindow - -import ( - "github.com/lxn/walk" - "github.com/shivas/abyss-blackbox/combatlog" -) - -func BuildSettingsWidget(characters map[string]combatlog.CombatLogFile, parent walk.Container) { - for i := 0; i < parent.Children().Len(); i++ { - parent.Children().At(i).Dispose() - } - - for charName := range characters { - cb, _ := walk.NewCheckBox(parent) - _ = cb.SetText(charName) - _ = cb.SetMinMaxSize(walk.Size{Width: 400}, walk.Size{Width: 800}) - _ = cb.SetAlignment(walk.AlignHNearVCenter) - cb.SetChecked(false) - _ = parent.Children().Add(cb) - } -} diff --git a/internal/mainwindow/images/0.png b/internal/mainwindow/images/0.png new file mode 100644 index 0000000..180230a Binary files /dev/null and b/internal/mainwindow/images/0.png differ diff --git a/internal/mainwindow/images/1.png b/internal/mainwindow/images/1.png new file mode 100644 index 0000000..73c1f4a Binary files /dev/null and b/internal/mainwindow/images/1.png differ diff --git a/internal/mainwindow/images/2.png b/internal/mainwindow/images/2.png new file mode 100644 index 0000000..79445a6 Binary files /dev/null and b/internal/mainwindow/images/2.png differ diff --git a/internal/mainwindow/images/3.png b/internal/mainwindow/images/3.png new file mode 100644 index 0000000..5d4b30b Binary files /dev/null and b/internal/mainwindow/images/3.png differ diff --git a/internal/mainwindow/images/4.png b/internal/mainwindow/images/4.png new file mode 100644 index 0000000..867bdf6 Binary files /dev/null and b/internal/mainwindow/images/4.png differ diff --git a/internal/mainwindow/images/5.png b/internal/mainwindow/images/5.png new file mode 100644 index 0000000..7365273 Binary files /dev/null and b/internal/mainwindow/images/5.png differ diff --git a/internal/mainwindow/images/6.png b/internal/mainwindow/images/6.png new file mode 100644 index 0000000..96926a2 Binary files /dev/null and b/internal/mainwindow/images/6.png differ diff --git a/internal/mainwindow/images/Dark.png b/internal/mainwindow/images/Dark.png new file mode 100644 index 0000000..ee4e264 Binary files /dev/null and b/internal/mainwindow/images/Dark.png differ diff --git a/internal/mainwindow/images/Electrical.png b/internal/mainwindow/images/Electrical.png new file mode 100644 index 0000000..fefb1f8 Binary files /dev/null and b/internal/mainwindow/images/Electrical.png differ diff --git a/internal/mainwindow/images/Exotic.png b/internal/mainwindow/images/Exotic.png new file mode 100644 index 0000000..1395ab9 Binary files /dev/null and b/internal/mainwindow/images/Exotic.png differ diff --git a/internal/mainwindow/images/Firestorm.png b/internal/mainwindow/images/Firestorm.png new file mode 100644 index 0000000..078e4dd Binary files /dev/null and b/internal/mainwindow/images/Firestorm.png differ diff --git a/internal/mainwindow/images/Gamma.png b/internal/mainwindow/images/Gamma.png new file mode 100644 index 0000000..1b28bdb Binary files /dev/null and b/internal/mainwindow/images/Gamma.png differ diff --git a/internal/mainwindow/images/Ship.png b/internal/mainwindow/images/Ship.png new file mode 100644 index 0000000..ea72638 Binary files /dev/null and b/internal/mainwindow/images/Ship.png differ diff --git a/internal/mainwindow/mainwindow.go b/internal/mainwindow/mainwindow.go index 7451b22..fec5565 100644 --- a/internal/mainwindow/mainwindow.go +++ b/internal/mainwindow/mainwindow.go @@ -7,18 +7,12 @@ import ( "github.com/lxn/walk" . "github.com/lxn/walk/declarative" // nolint:stylecheck,revive // we needs side effects + "github.com/lxn/win" + "github.com/shivas/abyss-blackbox/combatlog" + "github.com/shivas/abyss-blackbox/internal/config" ) -const ( - ShortcutRecorder = iota - ShortcutWeather30 - ShortcutWeather50 - ShortcutWeather70 -) - -type ShortcutSetter interface { - SetRecorderShortcut(int, walk.Shortcut) -} +const presetToolbarAction = 3 type WindowComboBoxItem struct { WindowTitle string @@ -26,47 +20,49 @@ type WindowComboBoxItem struct { } type AbyssRecorderWindow struct { - MainWindow *walk.MainWindow - FilteredPreview *walk.CheckBox - DataBinder *walk.DataBinder - CaptureWidget *walk.CustomWidget - HSetting *walk.NumberEdit - RecordingButton *walk.PushButton - CaptureWindowComboBox *walk.ComboBox - CombatLogCharacterGroup *walk.GroupBox - CaptureSettingsGroup *walk.GroupBox - EVEGameLogsFolderLabel *walk.TextLabel - ChooseLogDirButton *walk.PushButton - TestServer *walk.CheckBox - RecorderShortcutEdit *walk.LineEdit - RecorderShortcutRecordButton *walk.PushButton - Weather30ShortcutEdit *walk.LineEdit - Weather30ShortcutRecordButton *walk.PushButton - Weather50ShortcutEdit *walk.LineEdit - Weather50ShortcutRecordButton *walk.PushButton - Weather70ShortcutEdit *walk.LineEdit - Weather70ShortcutRecordButton *walk.PushButton - LootRecordDiscriminatorEdit *walk.LineEdit - CharacterSwitcherMenu *walk.Menu - Toolbar *walk.ToolBar - AutoUploadCheckbox *walk.CheckBox + MainWindow *walk.MainWindow + FilteredPreview *walk.CheckBox + DataBinder *walk.DataBinder + CaptureWidget *walk.CustomWidget + XSetting *walk.NumberEdit + YSetting *walk.NumberEdit + HSetting *walk.NumberEdit + RecordingButton *walk.PushButton + CaptureWindowComboBox *walk.ComboBox + CombatLogCharacterGroup *walk.GroupBox + CaptureSettingsGroup *walk.GroupBox + CapturePreviewGroupBox *walk.GroupBox + TestServer *walk.CheckBox + CharacterSwitcherMenu *walk.Menu + Toolbar *walk.ToolBar + AutoUploadCheckbox *walk.CheckBox + SettingsAction *walk.Action + PresetSwitcherMenu *walk.Menu + PresetSaveButton *walk.PushButton + PreviewScrollView *walk.ScrollView + AbyssTypeToolbar *walk.ToolBar } // NewAbyssRecorderWindow creates new main window of recorder. -func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.PaintFunc, comboBoxModel []*WindowComboBoxItem, actions map[string]walk.EventHandler) *AbyssRecorderWindow { +func NewAbyssRecorderWindow( + c interface{}, + customWidgetPaintFunc walk.PaintFunc, + comboBoxModel []*WindowComboBoxItem, + actions map[string]walk.EventHandler, + clr *combatlog.Reader, +) *AbyssRecorderWindow { obj := AbyssRecorderWindow{} if err := (MainWindow{ AssignTo: &obj.MainWindow, Title: "Abyssal.Space Blackbox Recorder", - MinSize: Size{Width: 320, Height: 240}, - Size: Size{Width: 400, Height: 600}, - Layout: HBox{MarginsZero: false}, + MinSize: Size{Width: 480, Height: 480}, + Size: Size{Width: 480, Height: 480}, + Layout: HBox{MarginsZero: true, Alignment: AlignHNearVNear}, DataBinder: DataBinder{ - AssignTo: &obj.DataBinder, - DataSource: config, - AutoSubmit: true, - AutoSubmitDelay: 1 * time.Second, + AssignTo: &obj.DataBinder, + DataSource: c, + AutoSubmit: true, }, ToolBar: ToolBar{ ButtonStyle: ToolBarButtonImageBeforeText, @@ -79,12 +75,32 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint Items: []MenuItem{}, Enabled: false, }, - Separator{}, Action{ Text: "Add character", Image: 14, OnTriggered: actions["add_character"], }, + Separator{}, + Menu{ + Text: "Presets", + Image: 28, + AssignTo: &obj.PresetSwitcherMenu, + Items: []MenuItem{}, + Enabled: false, + }, + Separator{}, + }, + }, + MenuItems: []MenuItem{ + Action{ + AssignTo: &obj.SettingsAction, + Text: "Settings", + }, + Action{ + Text: "About", + OnTriggered: func() { + _, _ = RunAboutDialog(obj.MainWindow) + }, }, }, Children: []Widget{ @@ -92,24 +108,20 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint Layout: HBox{}, Children: []Widget{ Composite{ - Layout: VBox{}, + Layout: VBox{MarginsZero: true}, Alignment: AlignHNearVNear, Children: []Widget{ GroupBox{ - Title: "Overview settings", - Layout: VBox{}, + Title: "Capture region", + Layout: VBox{SpacingZero: true}, + AssignTo: &obj.CaptureSettingsGroup, Children: []Widget{ - CheckBox{ - AssignTo: &obj.FilteredPreview, - Text: "show filtered preview", - Alignment: AlignHNearVNear, - Checked: Bind("FilteredPreview"), - }, - GroupBox{ - Title: "Capture region", - Layout: HBox{}, - AssignTo: &obj.CaptureSettingsGroup, + Composite{ + Layout: HBox{}, Children: []Widget{ + TextLabel{ + Text: "EVE window:", + }, ComboBox{ AssignTo: &obj.CaptureWindowComboBox, Model: comboBoxModel, @@ -119,17 +131,33 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint Value: Bind("EVEClientWindowTitle"), Editable: false, }, + CheckBox{ + AssignTo: &obj.FilteredPreview, + Text: "show filtered preview", + Alignment: AlignHNearVNear, + Checked: Bind("FilteredPreview"), + }, + HSpacer{}, + }, + }, + Composite{ + Layout: HBox{}, + Children: []Widget{ TextLabel{ Text: "X:", }, NumberEdit{ - Value: Bind("X"), + AssignTo: &obj.XSetting, + MinSize: Size{Width: 50, Height: 10}, + Value: Bind("X"), }, TextLabel{ Text: "Y:", }, NumberEdit{ - Value: Bind("Y"), + AssignTo: &obj.YSetting, + MinSize: Size{Width: 50, Height: 10}, + Value: Bind("Y"), }, TextLabel{ Text: "Height:", @@ -137,6 +165,7 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint NumberEdit{ AssignTo: &obj.HSetting, Value: Bind("H"), + MinSize: Size{Width: 50, Height: 10}, OnValueChanged: func() { if obj.CaptureWidget != nil { _ = obj.CaptureWidget.SetMinMaxSizePixels(walk.Size{Height: int(obj.HSetting.Value()), Width: 255}, walk.Size{}) @@ -144,207 +173,153 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint } }, }, + PushButton{ + AssignTo: &obj.PresetSaveButton, + Text: "Save as preset", + }, + HSpacer{}, }, }, }, }, - GroupBox{ - Title: "Server flag:", - Layout: VBox{}, - Alignment: AlignHNearVNear, - Children: []Widget{ - CheckBox{ - AssignTo: &obj.TestServer, - Text: "Test Server (Singularity)", - Alignment: AlignHNearVNear, - Checked: Bind("TestServer"), - }, - }, - }, - GroupBox{ - Title: "Loot recording settings:", - Layout: VBox{}, - Alignment: AlignHNearVNear, - Children: []Widget{ - TextLabel{ - Text: "Ship loot record discriminator item: (quantity in each ship should be different)", - }, - LineEdit{ - Text: Bind("LootRecordDiscriminator"), - AssignTo: &obj.LootRecordDiscriminatorEdit, - OnEditingFinished: func() { - _ = obj.DataBinder.Submit() - }, - }, - }, - }, - GroupBox{ - Title: "Shortcut configuration:", - Layout: VBox{}, + Composite{ + Layout: HBox{MarginsZero: true}, Alignment: AlignHNearVNear, Children: []Widget{ - Composite{ - Layout: HBox{}, - Alignment: AlignHNearVNear, - Children: []Widget{ - TextLabel{ - Text: "Start/Stop shortcut", - }, - LineEdit{ - Text: Bind("RecorderShortcutText"), - AssignTo: &obj.RecorderShortcutEdit, - OnKeyPress: func(key walk.Key) { - shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} - _ = obj.RecorderShortcutEdit.SetText(shortcut.String()) - c, ok := config.(ShortcutSetter) - if ok { - c.SetRecorderShortcut(ShortcutRecorder, shortcut) - } - }, - Enabled: false, - ReadOnly: true, - }, - PushButton{ - AssignTo: &obj.RecorderShortcutRecordButton, - MinSize: Size{Height: 20}, - Text: "Record shortcut", - }, - }, - }, - Composite{ - Layout: HBox{}, - Alignment: AlignHNearVNear, - Children: []Widget{ - TextLabel{ - Text: "Weather strength 30%", - }, - LineEdit{ - Text: Bind("Weather30ShortcutText"), - AssignTo: &obj.Weather30ShortcutEdit, - OnKeyPress: func(key walk.Key) { - shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} - _ = obj.Weather30ShortcutEdit.SetText(shortcut.String()) - c, ok := config.(ShortcutSetter) - if ok { - c.SetRecorderShortcut(ShortcutWeather30, shortcut) - } - }, - Enabled: false, - ReadOnly: true, - }, - PushButton{ - AssignTo: &obj.Weather30ShortcutRecordButton, - MinSize: Size{Height: 20}, - Text: "Record shortcut", - }, - }, - }, - Composite{ - Layout: HBox{}, - Alignment: AlignHNearVNear, + GroupBox{ + Title: "Manual abyss type override", + Checkable: true, + Checked: Bind("AbyssTypeOverride"), + Layout: VBox{}, + AlwaysConsumeSpace: true, + Alignment: AlignHNearVNear, Children: []Widget{ - TextLabel{ - Text: "Weather strength 50%", - }, - LineEdit{ - Text: Bind("Weather50ShortcutText"), - AssignTo: &obj.Weather50ShortcutEdit, - OnKeyPress: func(key walk.Key) { - shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} - _ = obj.Weather50ShortcutEdit.SetText(shortcut.String()) - c, ok := config.(ShortcutSetter) - if ok { - c.SetRecorderShortcut(ShortcutWeather50, shortcut) - } + ToolBar{ + AssignTo: &obj.AbyssTypeToolbar, + ButtonStyle: ToolBarButtonImageBeforeText, + Items: []MenuItem{ + Menu{ + Text: "Ship", + Items: []MenuItem{ + Action{ + Text: "Cruiser", + }, + Action{ + Text: "Destroyers", + }, + Action{ + Text: "Frigates", + }, + }, + }, + Menu{ + Text: "Tier", + Items: []MenuItem{ + Action{ + Text: "T0", + }, + Action{ + Text: "T1", + }, + Action{ + Text: "T2", + }, + Action{ + Text: "T3", + }, + Action{ + Text: "T4", + }, + Action{ + Text: "T5", + }, + Action{ + Text: "T6", + }, + }, + }, + Menu{ + Text: "Weather", + Items: []MenuItem{ + Action{ + Text: "Gamma", + }, + Action{ + Text: "Exotic", + }, + Action{ + Text: "Dark", + }, + Action{ + Text: "Firestorm", + }, + Action{ + Text: "Electrical", + }, + }, + }, }, - Enabled: false, - ReadOnly: true, - }, - PushButton{ - AssignTo: &obj.Weather50ShortcutRecordButton, - MinSize: Size{Height: 20}, - Text: "Record shortcut", }, }, }, - Composite{ - Layout: HBox{}, + HSpacer{}, + GroupBox{ + Title: "Server flag:", + Layout: VBox{}, Alignment: AlignHNearVNear, Children: []Widget{ - TextLabel{ - Text: "Weather strength 70%", - }, - LineEdit{ - Text: Bind("Weather70ShortcutText"), - AssignTo: &obj.Weather70ShortcutEdit, - OnKeyPress: func(key walk.Key) { - shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} - _ = obj.Weather70ShortcutEdit.SetText(shortcut.String()) - c, ok := config.(ShortcutSetter) - if ok { - c.SetRecorderShortcut(ShortcutWeather70, shortcut) - } - }, - Enabled: false, - ReadOnly: true, - }, - PushButton{ - AssignTo: &obj.Weather70ShortcutRecordButton, - MinSize: Size{Height: 20}, - Text: "Record shortcut", + CheckBox{ + AssignTo: &obj.TestServer, + Text: "Test Server (Singularity)", + Alignment: AlignHNearVNear, + Checked: Bind("TestServer"), }, }, }, + // HSpacer{}, }, + }, + GroupBox{ + Title: "Capture combatlog of characters:", + Layout: VBox{}, + Alignment: AlignHNearVNear, + AssignTo: &obj.CombatLogCharacterGroup, + Children: []Widget{}, AlwaysConsumeSpace: true, MinSize: Size{Height: 20}, }, - GroupBox{ - Title: "Combat log capture", - Layout: VBox{}, - Alignment: AlignHNearVNear, - Children: []Widget{ - TextLabel{ - Text: Bind("EVEGameLogsFolder"), - AssignTo: &obj.EVEGameLogsFolderLabel, - }, - PushButton{ - Text: "Choose", - AssignTo: &obj.ChooseLogDirButton, - }, - GroupBox{ - Title: "Capture combatlog of characters:", - Layout: VBox{}, - Alignment: AlignHNearVNear, - AssignTo: &obj.CombatLogCharacterGroup, - Children: []Widget{}, - AlwaysConsumeSpace: true, - MinSize: Size{Height: 20}, - }, - CheckBox{ - Text: "Upload file after recording complete", - AssignTo: &obj.AutoUploadCheckbox, - Alignment: AlignHNearVCenter, - Enabled: false, - Checked: Bind("AutoUpload"), - ToolTipText: "Automatically uploads recorded file to active character account.", - }, - PushButton{ - AssignTo: &obj.RecordingButton, - MinSize: Size{Height: 40}, - Text: "Start recording", - }, - }, + CheckBox{ + Text: "Upload file after recording complete", + AssignTo: &obj.AutoUploadCheckbox, + Alignment: AlignHNearVCenter, + Enabled: false, + Checked: Bind("AutoUpload"), + ToolTipText: "Automatically uploads recorded file to active character account.", + }, + PushButton{ + AssignTo: &obj.RecordingButton, + MinSize: Size{Height: 40}, + Text: "Start recording", }, }, }, GroupBox{ - Title: "Captured region:", - Layout: VBox{}, + Title: "Captured region:", + Layout: VBox{}, + AssignTo: &obj.CapturePreviewGroupBox, + OnSizeChanged: func() { + h := obj.MainWindow.AsContainerBase().MinSizeHint() + c := obj.MainWindow.AsContainerBase().Size() + _ = obj.MainWindow.SetMinMaxSize(h, walk.Size{}) + if c.Height > h.Height { + _ = obj.MainWindow.AsFormBase().WindowBase.SetSize(h) + } + + }, Children: []Widget{ CustomWidget{ AssignTo: &obj.CaptureWidget, - MinSize: Size{Width: 255, Height: 800}, + MinSize: Size{Width: 255, Height: 1}, Paint: customWidgetPaintFunc, InvalidatesOnResize: true, ClearsBackground: true, @@ -359,5 +334,87 @@ func NewAbyssRecorderWindow(config interface{}, customWidgetPaintFunc walk.Paint log.Fatal(err) } + logFiles, _ := clr.GetLogFiles(time.Now(), time.Duration(24)*time.Hour) + + charMap := clr.MapCharactersToFiles(logFiles) + buildRunnerList(charMap, obj.CombatLogCharacterGroup) + + settingsChangedHandler := func(c *config.CaptureConfig) { + _ = config.Write(c) + clr.SetLogFolder(c.EVEGameLogsFolder) + logFiles, err := clr.GetLogFiles(time.Now(), time.Duration(24)*time.Hour) + + if err != nil { + return + } + + buildRunnerList(clr.MapCharactersToFiles(logFiles), obj.CombatLogCharacterGroup) + + // rebind hotkeys + win.UnregisterHotKey(obj.MainWindow.Handle(), config.HotkeyRecoder) + win.UnregisterHotKey(obj.MainWindow.Handle(), config.HotkeyWeather30) + win.UnregisterHotKey(obj.MainWindow.Handle(), config.HotkeyWeather50) + win.UnregisterHotKey(obj.MainWindow.Handle(), config.HotkeyWeather70) + + walk.RegisterGlobalHotKey(obj.MainWindow, config.HotkeyRecoder, c.RecorderShortcut) + walk.RegisterGlobalHotKey(obj.MainWindow, config.HotkeyWeather30, c.Weather30Shortcut) + walk.RegisterGlobalHotKey(obj.MainWindow, config.HotkeyWeather50, c.Weather50Shortcut) + walk.RegisterGlobalHotKey(obj.MainWindow, config.HotkeyWeather70, c.Weather70Shortcut) + } + + obj.SettingsAction.Triggered().Attach(func() { + _, _ = RunAnimalDialog(obj.MainWindow, c, settingsChangedHandler) + }) + + chooser := NewAbyssTypeChooser(obj.AbyssTypeToolbar, c.(*config.CaptureConfig)) + chooser.Init() + return &obj } + +func (m *AbyssRecorderWindow) RefreshPresets(c *config.CaptureConfig) { + _ = m.PresetSwitcherMenu.Actions().Clear() + + for presetName := range c.Presets { + presetName := presetName + action := walk.NewAction() + _ = action.SetText(presetName) + _ = action.Triggered().Attach(func() { + modifiers := walk.ModifiersDown() + if modifiers == walk.ModControl { + delete(c.Presets, presetName) + _ = config.Write(c) + m.RefreshPresets(c) + } else { + p := c.Presets[presetName] + _ = m.XSetting.SetValue(float64(p.X)) + _ = m.YSetting.SetValue(float64(p.Y)) + _ = m.HSetting.SetValue(float64(p.H)) + } + }) + + _ = m.PresetSwitcherMenu.Actions().Add(action) + } + + if len(c.Presets) > 0 { + _ = m.Toolbar.Actions().At(presetToolbarAction).SetEnabled(true) + } else { + _ = m.Toolbar.Actions().At(presetToolbarAction).SetEnabled(false) + } +} + +func buildRunnerList(characters map[string]combatlog.CombatLogFile, parent walk.Container) { + for i := 0; i < parent.Children().Len(); i++ { + w := parent.Children().At(i) + w.SetVisible(false) + } + + for charName := range characters { + cb, _ := walk.NewCheckBox(parent) + _ = cb.SetText(charName) + _ = cb.SetMinMaxSize(walk.Size{Width: 400}, walk.Size{Width: 800}) + _ = cb.SetAlignment(walk.AlignHNearVCenter) + cb.SetChecked(false) + _ = parent.Children().Add(cb) + } +} diff --git a/internal/mainwindow/newpresetdialog.go b/internal/mainwindow/newpresetdialog.go new file mode 100644 index 0000000..de40e7a --- /dev/null +++ b/internal/mainwindow/newpresetdialog.go @@ -0,0 +1,73 @@ +package mainwindow + +import ( + "log" + + "github.com/shivas/abyss-blackbox/internal/config" + + "github.com/lxn/walk" + . "github.com/lxn/walk/declarative" // nolint:stylecheck,revive // we needs side effects +) + +func RunNewPresetDialog(owner walk.Form, presetValue config.Preset, c *config.CaptureConfig) (int, error) { + var ( + dlg *walk.Dialog + db *walk.DataBinder + acceptPB, cancelPB *walk.PushButton + PresetNameEdit *walk.LineEdit + ) + + data := map[string]interface{}{"Name": ""} + + return Dialog{ + AssignTo: &dlg, + Title: "New preset", + DefaultButton: &acceptPB, + CancelButton: &cancelPB, + DataBinder: DataBinder{ + AssignTo: &db, + DataSource: data, + OnSubmitted: func() { + log.Printf("new preset saving: %#v with values: %v", data, presetValue) + if c.Presets == nil { + c.Presets = make(map[string]config.Preset) + } + + c.Presets[data["Name"].(string)] = presetValue + }, + }, + Layout: VBox{}, + Children: []Widget{ + TextLabel{ + Text: "Preset name:", + }, + LineEdit{ + Text: Bind("Name"), + AssignTo: &PresetNameEdit, + }, + Composite{ + Layout: HBox{}, + Children: []Widget{ + HSpacer{}, + PushButton{ + AssignTo: &acceptPB, + Text: "OK", + OnClicked: func() { + if err := db.Submit(); err != nil { + log.Print(err) + return + } + + dlg.Accept() + }, + }, + PushButton{ + AssignTo: &cancelPB, + Text: "Cancel", + OnClicked: func() { dlg.Cancel() }, + }, + }, + }, + }, + }.Run(owner) +} diff --git a/internal/mainwindow/settings.go b/internal/mainwindow/settings.go new file mode 100644 index 0000000..d8a1ee5 --- /dev/null +++ b/internal/mainwindow/settings.go @@ -0,0 +1,280 @@ +package mainwindow + +import ( + "log" + + "github.com/shivas/abyss-blackbox/internal/config" + + "github.com/lxn/walk" + . "github.com/lxn/walk/declarative" // nolint:stylecheck,revive // we needs side effects +) + +type ShortcutSetter interface { + SetRecorderShortcut(int, walk.Shortcut) +} + +func RunAnimalDialog(owner walk.Form, conf interface{}, onSettingsSubmit func(c *config.CaptureConfig)) (int, error) { + var ( + dlg *walk.Dialog + db *walk.DataBinder + acceptPB, cancelPB *walk.PushButton + RecorderShortcutEdit *walk.LineEdit + RecorderShortcutRecordButton *walk.PushButton + Weather30ShortcutEdit *walk.LineEdit + Weather30ShortcutRecordButton *walk.PushButton + Weather50ShortcutEdit *walk.LineEdit + Weather50ShortcutRecordButton *walk.PushButton + Weather70ShortcutEdit *walk.LineEdit + Weather70ShortcutRecordButton *walk.PushButton + LootRecordDiscriminatorEdit *walk.LineEdit + EVEGameLogsFolderLabel *walk.TextLabel + ChooseLogDirButton *walk.PushButton + ) + + shortcutStringToKey := make(map[string]walk.Shortcut) + + return Dialog{ + AssignTo: &dlg, + Title: "Settings", + DefaultButton: &acceptPB, + CancelButton: &cancelPB, + DataBinder: DataBinder{ + AssignTo: &db, + DataSource: conf, + OnSubmitted: func() { + if c, ok := conf.(*config.CaptureConfig); ok { + if setter, ok2 := conf.(ShortcutSetter); ok2 { + if key, exists := shortcutStringToKey[c.RecorderShortcutText]; exists { + setter.SetRecorderShortcut(config.HotkeyRecoder, key) + } + if key, exists := shortcutStringToKey[c.Weather30ShortcutText]; exists { + setter.SetRecorderShortcut(config.HotkeyWeather30, key) + } + if key, exists := shortcutStringToKey[c.Weather50ShortcutText]; exists { + setter.SetRecorderShortcut(config.HotkeyWeather50, key) + } + if key, exists := shortcutStringToKey[c.Weather70ShortcutText]; exists { + setter.SetRecorderShortcut(config.HotkeyWeather70, key) + } + } + onSettingsSubmit(c) + } + }, + }, + MinSize: Size{Width: 500, Height: 300}, + Layout: VBox{}, + Children: []Widget{ + GroupBox{ + Title: "Combat log capture", + Layout: VBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: Bind("EVEGameLogsFolder"), + AssignTo: &EVEGameLogsFolderLabel, + }, + PushButton{ + Text: "Choose", + AssignTo: &ChooseLogDirButton, + OnClicked: func() { + fd := walk.FileDialog{} + accepted, _ := fd.ShowBrowseFolder(owner) + if accepted { + _ = EVEGameLogsFolderLabel.SetText(fd.FilePath) + } + }, + }, + }, + }, + GroupBox{ + Title: "Loot recording settings:", + Layout: VBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: "Ship loot record discriminator item: (quantity in each ship should be different)", + }, + LineEdit{ + Text: Bind("LootRecordDiscriminator"), + AssignTo: &LootRecordDiscriminatorEdit, + }, + TextLabel{ + Text: "Only used when multiboxing destroyer or frigate runs.", + }, + }, + }, + GroupBox{ + Title: "Shortcut configuration:", + Layout: VBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + Composite{ + Layout: HBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: "Start/Stop shortcut", + }, + LineEdit{ + Text: Bind("RecorderShortcutText"), + AssignTo: &RecorderShortcutEdit, + OnKeyPress: func(key walk.Key) { + shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} + _ = RecorderShortcutEdit.SetText(shortcut.String()) + shortcutStringToKey[shortcut.String()] = shortcut + }, + Enabled: false, + ReadOnly: true, + }, + PushButton{ + AssignTo: &RecorderShortcutRecordButton, + MinSize: Size{Height: 20}, + Text: "Record shortcut", + OnClicked: func() { + if !RecorderShortcutEdit.Enabled() { // start recording + RecorderShortcutEdit.SetEnabled(true) + _ = RecorderShortcutEdit.SetFocus() + _ = RecorderShortcutRecordButton.SetText("Save") + } else { // persist new shortcut and rebind + RecorderShortcutEdit.SetEnabled(false) + _ = RecorderShortcutRecordButton.SetText("Record shortcut") + } + }, + }, + }, + }, + Composite{ + Layout: HBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: "Weather strength 30%", + }, + LineEdit{ + Text: Bind("Weather30ShortcutText"), + AssignTo: &Weather30ShortcutEdit, + OnKeyPress: func(key walk.Key) { + shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} + _ = Weather30ShortcutEdit.SetText(shortcut.String()) + shortcutStringToKey[shortcut.String()] = shortcut + }, + Enabled: false, + ReadOnly: true, + }, + PushButton{ + AssignTo: &Weather30ShortcutRecordButton, + MinSize: Size{Height: 20}, + Text: "Record shortcut", + OnClicked: func() { + if !Weather30ShortcutEdit.Enabled() { // start recording + Weather30ShortcutEdit.SetEnabled(true) + _ = Weather30ShortcutEdit.SetFocus() + _ = Weather30ShortcutRecordButton.SetText("Save") + } else { // persist new shortcut and rebind + Weather30ShortcutEdit.SetEnabled(false) + _ = Weather30ShortcutRecordButton.SetText("Record shortcut") + } + }, + }, + }, + }, + Composite{ + Layout: HBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: "Weather strength 50%", + }, + LineEdit{ + Text: Bind("Weather50ShortcutText"), + AssignTo: &Weather50ShortcutEdit, + OnKeyPress: func(key walk.Key) { + shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} + _ = Weather50ShortcutEdit.SetText(shortcut.String()) + shortcutStringToKey[shortcut.String()] = shortcut + }, + Enabled: false, + ReadOnly: true, + }, + PushButton{ + AssignTo: &Weather50ShortcutRecordButton, + MinSize: Size{Height: 20}, + Text: "Record shortcut", + OnClicked: func() { + if !Weather50ShortcutEdit.Enabled() { // start recording + Weather50ShortcutEdit.SetEnabled(true) + _ = Weather50ShortcutEdit.SetFocus() + _ = Weather50ShortcutRecordButton.SetText("Save") + } else { // persist new shortcut and rebind + Weather50ShortcutEdit.SetEnabled(false) + _ = Weather50ShortcutRecordButton.SetText("Record shortcut") + } + }, + }, + }, + }, + Composite{ + Layout: HBox{}, + Alignment: AlignHNearVNear, + Children: []Widget{ + TextLabel{ + Text: "Weather strength 70%", + }, + LineEdit{ + Text: Bind("Weather70ShortcutText"), + AssignTo: &Weather70ShortcutEdit, + OnKeyPress: func(key walk.Key) { + shortcut := walk.Shortcut{Modifiers: walk.ModifiersDown(), Key: key} + _ = Weather70ShortcutEdit.SetText(shortcut.String()) + shortcutStringToKey[shortcut.String()] = shortcut + }, + Enabled: false, + ReadOnly: true, + }, + PushButton{ + AssignTo: &Weather70ShortcutRecordButton, + MinSize: Size{Height: 20}, + Text: "Record shortcut", + OnClicked: func() { + if !Weather70ShortcutEdit.Enabled() { // start recording + Weather70ShortcutEdit.SetEnabled(true) + _ = Weather70ShortcutEdit.SetFocus() + _ = Weather70ShortcutRecordButton.SetText("Save") + } else { // persist new shortcut and rebind + Weather70ShortcutEdit.SetEnabled(false) + _ = Weather70ShortcutRecordButton.SetText("Record shortcut") + } + }, + }, + }, + }, + }, + AlwaysConsumeSpace: true, + MinSize: Size{Height: 20}, + }, + Composite{ + Layout: HBox{}, + Children: []Widget{ + HSpacer{}, + PushButton{ + AssignTo: &acceptPB, + Text: "OK", + OnClicked: func() { + if err := db.Submit(); err != nil { + log.Print(err) + return + } + + dlg.Accept() + }, + }, + PushButton{ + AssignTo: &cancelPB, + Text: "Cancel", + OnClicked: func() { dlg.Cancel() }, + }, + }, + }, + }, + }.Run(owner) +} diff --git a/internal/mainwindow/triglogo.png b/internal/mainwindow/triglogo.png new file mode 100644 index 0000000..b53c8d7 Binary files /dev/null and b/internal/mainwindow/triglogo.png differ diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..38ba06c --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,4 @@ +package version + +var RecorderVersion string +var GoVersion string