termtab-0.1.0.0: TUI guitar tablature and score editor
Safe HaskellNone
LanguageGHC2021

Termtab.UI.Types

Description

The editor's state (AppState) and the pure functions that transform it: cursor navigation (move*/goTo*), zoom, and display-mode cycling. Kept separate from Termtab.UI.Editing (which mutates the Song itself) and from Termtab.UI.Keybindings (which decides which of these functions a keypress calls) — this module only knows how to move the cursor and answer questions about where it is, not how to edit notes.

Synopsis

Documentation

data AppState Source #

The entire mutable state of the running editor: the document itself (asSong) plus cursor position, input mode, undo/redo history, playback status, and resolved graphics capabilities. This is the sole state threaded through Brick's event loop — every keybinding and rendering function takes and/or produces one of these.

data DisplayMode Source #

What a single track's viewport renders: ASCII tab, the rasterized Bravura staff notation, or both stacked. Stored per-track in asDisplayModes since a mixed Standard + Guitar song may want different modes per track (see initAppState's defaultModeFor).

Instances

Instances details
Show DisplayMode Source # 
Instance details

Defined in Termtab.UI.Types

Eq DisplayMode Source # 
Instance details

Defined in Termtab.UI.Types

data InputMode Source #

Which set of keybindings Termtab.UI.Keybindings is currently interpreting input as. CommandMode carries the command line typed so far; MenuMode carries the path of menu keys pressed so far ([] is the root menu, ["s"] is the subdivide submenu, etc), since menus nest.

Instances

Instances details
Show InputMode Source # 
Instance details

Defined in Termtab.UI.Types

Eq InputMode Source # 
Instance details

Defined in Termtab.UI.Types

data ResourceName Source #

Brick widget-name identifiers, used to address specific viewports/ regions for scrolling and extent lookups (e.g. lookupExtent).

data AppEvent Source #

Custom Brick events delivered through asBChan. PlaybackTick drives UI redraws while a song plays; GraphicsRefresh is posted once at startup to (re-)blit notation images after the terminal has reported real widget extents (which aren't known on the very first frame).

Instances

Instances details
Show AppEvent Source # 
Instance details

Defined in Termtab.UI.Types

Eq AppEvent Source # 
Instance details

Defined in Termtab.UI.Types

initAppState :: Maybe FilePath -> Song -> BChan AppEvent -> AppState Source #

Build the starting AppState for song (loaded from mPath, or Nothing for a brand-new document), with the cursor at measure 0 beat 0, no undo history, and a per-track default DisplayMode (fretted instruments start as TabAndNotation, Standard tracks as NotationOnly since they have no tab to show). Graphics fields (asProtocol, asGlyphFont, etc) start at their no-graphics defaults — the caller resolves and fills those in separately once terminal capabilities are detected.

moveBeatRight :: AppState -> AppState Source #

Move the cursor one beat right, wrapping to beat 0 of the next measure if already at the last beat (unless already in the last measure, in which case the cursor doesn't move here — auto-creating a new measure at the end is handled by the caller in Termtab.UI.Keybindings, not by this pure navigation function).

moveBeatLeft :: AppState -> AppState Source #

Move the cursor one beat left, wrapping to the last beat of the previous measure if already at beat 0 (computed by temporarily moving the cursor there and re-running currentMeasureBeatCount, since that count depends on which measure/track is current).

moveMeasureForward :: AppState -> AppState Source #

Jump the cursor to beat 0 of the next measure, clamped at the last measure (does not wrap or auto-create).

moveMeasureBack :: AppState -> AppState Source #

Jump the cursor to beat 0 of the previous measure, clamped at measure 0.

moveStringUp :: AppState -> AppState Source #

Move the cursor's string index up (toward index 0), clamped there.

moveStringDown :: AppState -> AppState Source #

Move the cursor's string index down, clamped to the current track's last string (0 for a Standard track, since it has no strings).

goToStart :: AppState -> AppState Source #

Jump the cursor to measure 0, beat 0.

goToEnd :: AppState -> AppState Source #

Jump the cursor to the last beat of the last measure, per that measure's own time signature (not currentMeasureBeatCount, which would also account for empty padding slots — this uses the raw numerator instead).

goToMeasureStart :: AppState -> AppState Source #

Jump to beat 0 of the current measure.

goToMeasureEnd :: AppState -> AppState Source #

Jump to the last beat of the current measure, per its time signature numerator (see goToEnd for the same caveat about padding slots).

goToFirstString :: AppState -> AppState Source #

Jump the cursor to string index 0.

goToLastString :: AppState -> AppState Source #

Jump the cursor to the current track's last string.

cycleDisplayMode :: AppState -> AppState Source #

Advance the current track's DisplayMode to the next in the cycle TabOnly -> NotationOnly -> TabAndNotation -> TabOnly.

zoomIn :: AppState -> AppState Source #

Increase asZoom, clamped to a maximum of 12.

zoomOut :: AppState -> AppState Source #

Decrease asZoom, clamped to a minimum of 2.

currentTrack :: AppState -> Maybe Track Source #

The Track at asCurrentTrack, or Nothing if the cursor's track index is out of range (e.g. the last track was just deleted).

currentMeasureBeatCount :: AppState -> Int Source #

Number of navigable beats in the current measure. Accounts for actual beats plus empty slots that fill the remaining duration from the time signature.

atLastBeat :: AppState -> Bool Source #

Are we at the last beat of the current measure?

atLastMeasure :: AppState -> Bool Source #

Are we at the last measure?

atFirstBeat :: AppState -> Bool Source #

Are we at the first beat of the current measure?

atFirstMeasure :: AppState -> Bool Source #

Are we at the first measure?

isMeasureEmpty :: MeasureIndex -> AppState -> Bool Source #

A measure is empty if no track has any notes in it. Empty beat lists or beats with no notes all count as empty.

isTrailingEmpty :: MeasureIndex -> AppState -> Bool Source #

A measure is trailing-empty if it and all measures after it are empty. Only trailing-empty measures should be auto-deleted on backward navigation.

beatsForTrackMeasure :: Track -> MeasureIndex -> [Beat] Source #

The beats a track has for one measure, or [] if it has none there.

stringCountForTrack :: Track -> Int Source #

Number of fretboard strings for a track, or 0 for a Standard (non-fretted) instrument.

measureCount :: AppState -> Int Source #

Total number of measures in the current song.