Gopher2600/gui/sdlimgui/win_tracker.go
JetSetIlly 28ffedbf11 removed emulation package. moved types to debugger/govern package
the emulation package has been unecessary since the amalgamation of the
debugger and play modes. in order to allow switching between the two
modes it was necessary to remove the playmode package and to move all
playmode loops and other considerations into the debugger package. as a
result the abstraction offered by the emulation package is uncessary
2022-08-31 14:37:00 +01:00

276 lines
8.6 KiB
Go

// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package sdlimgui
import (
"fmt"
"github.com/inkyblackness/imgui-go/v4"
"github.com/jetsetilly/gopher2600/debugger/govern"
"github.com/jetsetilly/gopher2600/gui/fonts"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
"github.com/jetsetilly/gopher2600/tracker"
)
const winTrackerID = "Audio Tracker"
type winTracker struct {
playmodeWin
debuggerWin
img *SdlImgui
contextMenu coords.TelevisionCoords
// piano keys
blackKeys imgui.PackedColor
whiteKeys imgui.PackedColor
whiteKeysGap imgui.PackedColor
pianoKeysHeight float32
}
func newWinTracker(img *SdlImgui) (window, error) {
win := &winTracker{
img: img,
blackKeys: imgui.PackedColorFromVec4(imgui.Vec4{0, 0, 0, 1.0}),
whiteKeys: imgui.PackedColorFromVec4(imgui.Vec4{1.0, 1.0, 0.90, 1.0}),
whiteKeysGap: imgui.PackedColorFromVec4(imgui.Vec4{0.2, 0.2, 0.2, 1.0}),
}
return win, nil
}
func (win *winTracker) init() {
// nominal value to stop scrollbar appearing for a frame (it takes a
// frame before we set the correct footerHeight value
win.pianoKeysHeight = imgui.FrameHeight() + imgui.CurrentStyle().FramePadding().Y
}
func (win *winTracker) id() string {
return winTrackerID
}
func (win *winTracker) playmodeDraw() {
if !win.playmodeIsOpen() {
return
}
imgui.SetNextWindowPosV(imgui.Vec2{494, 274}, imgui.ConditionFirstUseEver, imgui.Vec2{0, 0})
imgui.SetNextWindowSizeV(imgui.Vec2{658, 469}, imgui.ConditionFirstUseEver)
imgui.SetNextWindowSizeConstraints(imgui.Vec2{-1, 200}, imgui.Vec2{-1, 1000})
if imgui.BeginV(win.playmodeID(win.id()), &win.playmodeOpen, imgui.WindowFlagsNone) {
win.draw()
}
win.playmodeWin.playmodeGeom.update()
imgui.End()
}
const trackerContextMenuID = "trackerContextMenu"
func (win *winTracker) debuggerDraw() {
if !win.debuggerIsOpen() {
return
}
imgui.SetNextWindowPosV(imgui.Vec2{494, 274}, imgui.ConditionFirstUseEver, imgui.Vec2{0, 0})
imgui.SetNextWindowSizeV(imgui.Vec2{658, 469}, imgui.ConditionFirstUseEver)
imgui.SetNextWindowSizeConstraints(imgui.Vec2{-1, 200}, imgui.Vec2{-1, 1000})
if imgui.BeginV(win.debuggerID(win.id()), &win.debuggerOpen, imgui.WindowFlagsNone) {
win.draw()
}
win.debuggerWin.debuggerGeom.update()
imgui.End()
}
func (win *winTracker) draw() {
imgui.PushStyleColor(imgui.StyleColorHeaderHovered, win.img.cols.DisasmHover)
imgui.PushStyleColor(imgui.StyleColorHeaderActive, win.img.cols.DisasmHover)
defer imgui.PopStyleColorV(2)
imgui.PushStyleColor(imgui.StyleColorTableHeaderBg, win.img.cols.AudioTrackerHeader)
defer imgui.PopStyleColor()
tableFlags := imgui.TableFlagsNone
tableFlags |= imgui.TableFlagsSizingFixedFit
tableFlags |= imgui.TableFlagsBordersV
tableFlags |= imgui.TableFlagsBordersOuter
const tableColumns = 14
tableSetupColumns := func() {
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, 0, 0)
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, 15, 1)
imgui.TableSetupColumnV("AUDC0", imgui.TableColumnFlagsNone, 40, 2)
imgui.TableSetupColumnV("Description", imgui.TableColumnFlagsNone, 80, 2)
imgui.TableSetupColumnV("AUDF0", imgui.TableColumnFlagsNone, 40, 3)
imgui.TableSetupColumnV("Note", imgui.TableColumnFlagsNone, 30, 3)
imgui.TableSetupColumnV("AUDV0", imgui.TableColumnFlagsNone, 40, 4)
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, 0, 5)
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, 15, 6)
imgui.TableSetupColumnV("AUDC1", imgui.TableColumnFlagsNone, 40, 2)
imgui.TableSetupColumnV("Description", imgui.TableColumnFlagsNone, 80, 2)
imgui.TableSetupColumnV("AUDF1", imgui.TableColumnFlagsNone, 40, 8)
imgui.TableSetupColumnV("Note", imgui.TableColumnFlagsNone, 30, 3)
imgui.TableSetupColumnV("AUDV1", imgui.TableColumnFlagsNone, 40, 9)
}
// I can't get the header of the table to freeze in the scroller so I'm
// fudging the effect by having a separate table just for the header.
if !imgui.BeginTableV("trackerHeader", tableColumns, tableFlags, imgui.Vec2{}, 0) {
return
}
tableSetupColumns()
imgui.TableHeadersRow()
imgui.EndTable()
// new child that contains the main scrollable table
imgui.BeginChildV("##trackerscroller", imgui.Vec2{X: 0, Y: imguiRemainingWinHeight() - win.pianoKeysHeight}, false, 0)
numEntries := len(win.img.lz.Tracker.Entries)
if numEntries == 0 {
imgui.Spacing()
imgui.Text("No audio output/changes yet")
} else {
if !imgui.BeginTableV("tracker", tableColumns, tableFlags, imgui.Vec2{}, 0) {
return
}
tableSetupColumns()
// altenate row colors at change of frame number
var lastEntry tracker.Entry
var lastEntryChan0 tracker.Entry
var lastEntryChan1 tracker.Entry
var altRowCol bool
var clipper imgui.ListClipper
clipper.Begin(numEntries)
for clipper.Step() {
for i := clipper.DisplayStart; i < clipper.DisplayEnd; i++ {
entry := win.img.lz.Tracker.Entries[i]
imgui.TableNextRow()
// flip row color
if entry.Coords.Frame != lastEntry.Coords.Frame {
altRowCol = !altRowCol
}
if altRowCol {
imgui.TableSetBgColor(imgui.TableBgTargetRowBg0, win.img.cols.AudioTrackerRowAlt)
imgui.TableSetBgColor(imgui.TableBgTargetRowBg1, win.img.cols.AudioTrackerRowAlt)
} else {
imgui.TableSetBgColor(imgui.TableBgTargetRowBg0, win.img.cols.AudioTrackerRow)
imgui.TableSetBgColor(imgui.TableBgTargetRowBg1, win.img.cols.AudioTrackerRow)
}
imgui.TableNextColumn()
imgui.SelectableV("", false, imgui.SelectableFlagsSpanAllColumns, imgui.Vec2{0, 0})
imguiTooltip(func() {
imgui.Text(fmt.Sprintf("Frame: %d", entry.Coords.Frame))
imgui.Text(fmt.Sprintf("Scanline: %d", entry.Coords.Scanline))
imgui.Text(fmt.Sprintf("Clock: %d", entry.Coords.Clock))
}, true)
// context menu on right mouse button
if imgui.IsItemHovered() && imgui.IsMouseDown(1) {
imgui.OpenPopup(trackerContextMenuID)
win.contextMenu = entry.Coords
}
if entry.Coords == win.contextMenu {
if imgui.BeginPopup(trackerContextMenuID) {
if imgui.Selectable("Rewind to") {
win.img.dbg.GotoCoords(entry.Coords)
}
imgui.EndPopup()
}
}
if entry.Channel == 1 {
imgui.TableNextColumn()
imgui.TableNextColumn()
imgui.TableNextColumn()
imgui.TableNextColumn()
imgui.TableNextColumn()
imgui.TableNextColumn()
imgui.TableNextColumn()
}
// convert musical note into something worth showing
musicalNote := string(entry.MusicalNote)
imgui.TableNextColumn()
switch entry.MusicalNote {
case tracker.Noise:
musicalNote = ""
case tracker.Low:
musicalNote = ""
case tracker.Silence:
musicalNote = ""
default:
imgui.Text(fmt.Sprintf("%c", fonts.MusicNote))
}
imgui.TableNextColumn()
imgui.Text(fmt.Sprintf("%04b", entry.Registers.Control&0x0f))
imgui.TableNextColumn()
imgui.Text(fmt.Sprintf("%s", entry.Distortion))
imgui.TableNextColumn()
imgui.Text(fmt.Sprintf("%05b", entry.Registers.Freq&0x1f))
imgui.TableNextColumn()
imgui.Text(musicalNote)
imgui.TableNextColumn()
// volum column
var volumeArrow rune
// compare with previous entry for the channel
if entry.Channel == 0 {
if entry.Registers.Volume > lastEntryChan0.Registers.Volume {
volumeArrow = fonts.VolumeUp
} else if entry.Registers.Volume < lastEntryChan0.Registers.Volume {
volumeArrow = fonts.VolumeDown
}
lastEntryChan0 = entry
} else {
if entry.Registers.Volume > lastEntryChan1.Registers.Volume {
volumeArrow = fonts.VolumeUp
} else if entry.Registers.Volume < lastEntryChan1.Registers.Volume {
volumeArrow = fonts.VolumeDown
}
lastEntryChan1 = entry
}
imgui.Text(fmt.Sprintf("%02d %c", entry.Registers.Volume&0x4b, volumeArrow))
// record last entry for comparison purposes next iteration
lastEntry = entry
}
}
imgui.EndTable()
if win.img.dbg.State() == govern.Running {
imgui.SetScrollHereY(1.0)
}
}
imgui.EndChild()
win.pianoKeysHeight = win.drawPianoKeys()
}