-- Copyright 2013 Evan Laforge
-- This program is distributed under the terms of the GNU General Public
-- License 3.0, see COPYING or http://www.gnu.org/licenses/gpl-3.0.txt

-- | Infrastructure for dealing with rulers in a higher level way.
module Cmd.Ruler.RulerUtil where
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe

import qualified Util.Lists as Lists
import qualified Ui.Block as Block
import qualified Ui.Id as Id
import qualified Ui.Meter.Mark as Mark
import qualified Ui.Meter.Meter as Meter
import qualified Ui.Ruler as Ruler
import qualified Ui.Ui as Ui

import           Global
import           Types


-- * generate

-- | Make a ruler of a single meter until the given end time.
meter_until :: Meter.AbstractMeter -> TrackTime -> Int -> TrackTime
    -> Meter.Meter
meter_until :: AbstractMeter -> TrackTime -> Int -> TrackTime -> Meter
meter_until AbstractMeter
meter TrackTime
measure_dur Int
per_section TrackTime
end = TrackTime -> Meter -> Meter
meter_take TrackTime
end forall a b. (a -> b) -> a -> b
$
    Config -> [MSection] -> Meter
Meter.meter Config
Meter.default_config forall a b. (a -> b) -> a -> b
$
    forall a. Int -> a -> [a]
replicate Int
sections (Int -> TrackTime -> AbstractMeter -> MSection
Meter.MSection Int
per_section TrackTime
measure_dur AbstractMeter
meter)
        forall a. [a] -> [a] -> [a]
++ [Int -> TrackTime -> AbstractMeter -> MSection
Meter.MSection Int
left TrackTime
measure_dur AbstractMeter
meter]
    where
    (Int
sections, Int
left) = Int
measures forall a. Integral a => a -> a -> (a, a)
`divMod` Int
per_section
    measures :: Int
measures = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (TrackTime
end forall a. Fractional a => a -> a -> a
/ TrackTime
measure_dur)

-- * by marklist

-- | Copy a marklist from one ruler to another.  If it already exists in
-- the destination ruler, it will be replaced.
copy_marklist :: Ui.M m => Ruler.Name -> RulerId -> RulerId -> m ()
copy_marklist :: forall (m :: * -> *). M m => Name -> RulerId -> RulerId -> m ()
copy_marklist Name
name RulerId
from_ruler_id RulerId
to_ruler_id = do
    Ruler
from_ruler <- forall (m :: * -> *). M m => RulerId -> m Ruler
Ui.get_ruler RulerId
from_ruler_id
    let mlist :: Marklist
mlist = Name -> Ruler -> Marklist
Ruler.get_marklist Name
name Ruler
from_ruler
    forall (m :: * -> *). M m => RulerId -> Name -> Marklist -> m ()
set_marklist RulerId
to_ruler_id Name
name Marklist
mlist

-- | Replace or add a marklist with the given name.
set_marklist :: Ui.M m => RulerId -> Ruler.Name -> Mark.Marklist -> m ()
set_marklist :: forall (m :: * -> *). M m => RulerId -> Name -> Marklist -> m ()
set_marklist RulerId
ruler_id Name
name Marklist
mlist =
    forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
ruler_id (forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Marklist -> Ruler -> Ruler
Ruler.set_marklist Name
name Marklist
mlist)

-- * by Meter

get_meter :: Ui.M m => RulerId -> m Meter.Meter
get_meter :: forall (m :: * -> *). M m => RulerId -> m Meter
get_meter = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Ruler -> Meter
Ruler.get_meter forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). M m => RulerId -> m Ruler
Ui.get_ruler

set_meter :: Ui.M m => RulerId -> Meter.Meter -> m ()
set_meter :: forall (m :: * -> *). M m => RulerId -> Meter -> m ()
set_meter RulerId
ruler_id Meter
meter = forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
ruler_id forall a b. (a -> b) -> a -> b
$
    forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. Meter -> Ruler -> Ruler
Ruler.set_meter Meter
meter

meter_take :: TrackTime -> Meter.Meter -> Meter.Meter
meter_take :: TrackTime -> Meter -> Meter
meter_take = ([MSection] -> [MSection]) -> Meter -> Meter
Meter.modify_sections forall b c a. (b -> c) -> (a -> b) -> a -> c
. TrackTime -> [MSection] -> [MSection]
Meter.sections_take

meter_drop :: TrackTime -> Meter.Meter -> Meter.Meter
meter_drop :: TrackTime -> Meter -> Meter
meter_drop = ([MSection] -> [MSection]) -> Meter -> Meter
Meter.modify_sections forall b c a. (b -> c) -> (a -> b) -> a -> c
. TrackTime -> [MSection] -> [MSection]
Meter.sections_drop

extract :: TrackTime -> TrackTime -> [Meter.MSection] -> [Meter.MSection]
extract :: TrackTime -> TrackTime -> [MSection] -> [MSection]
extract TrackTime
start TrackTime
end = TrackTime -> [MSection] -> [MSection]
Meter.sections_drop TrackTime
start forall b c a. (b -> c) -> (a -> b) -> a -> c
. TrackTime -> [MSection] -> [MSection]
Meter.sections_take TrackTime
end

delete :: TrackTime -> TrackTime -> [Meter.MSection] -> [Meter.MSection]
delete :: TrackTime -> TrackTime -> [MSection] -> [MSection]
delete TrackTime
start TrackTime
end [MSection]
ss = TrackTime -> [MSection] -> [MSection]
Meter.sections_take TrackTime
start [MSection]
ss forall a. Semigroup a => a -> a -> a
<> TrackTime -> [MSection] -> [MSection]
Meter.sections_drop TrackTime
end [MSection]
ss

-- * ModifyRuler

type ModifyRuler = Ruler.Ruler -> Either Text Ruler.Ruler

-- | The scope of a ruler modification.
data Scope =
    -- | Modify all rulers on the block.
    Block
    -- | Modify the 'section_ruler_id'.  Section 0 is the 'Ui.block_ruler'.
    | Section !TrackNum
    -- | Modify the given tracks.
    | Tracks ![TrackNum]
    deriving (Scope -> Scope -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Scope -> Scope -> Bool
$c/= :: Scope -> Scope -> Bool
== :: Scope -> Scope -> Bool
$c== :: Scope -> Scope -> Bool
Eq, Int -> Scope -> ShowS
[Scope] -> ShowS
Scope -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Scope] -> ShowS
$cshowList :: [Scope] -> ShowS
show :: Scope -> String
$cshow :: Scope -> String
showsPrec :: Int -> Scope -> ShowS
$cshowsPrec :: Int -> Scope -> ShowS
Show)

-- | Create or replace a ruler for the given block.
replace :: Ui.M m => BlockId -> ModifyRuler -> m RulerId
replace :: forall (m :: * -> *).
M m =>
BlockId -> (Ruler -> Either Name Ruler) -> m RulerId
replace BlockId
block_id Ruler -> Either Name Ruler
modify = do
    forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM (forall a. Maybe a -> Bool
Maybe.isNothing forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). M m => RulerId -> m (Maybe Ruler)
Ui.lookup_ruler RulerId
ruler_id) forall a b. (a -> b) -> a -> b
$
        forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). M m => Id -> Ruler -> m RulerId
Ui.create_ruler (forall a. Ident a => a -> Id
Id.unpack_id RulerId
ruler_id) Ruler
Ruler.empty
    forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
ruler_id Ruler -> Either Name Ruler
modify
    forall (m :: * -> *) a. Monad m => a -> m a
return RulerId
ruler_id
    where
    ruler_id :: RulerId
ruler_id = Id -> RulerId
Id.RulerId forall a b. (a -> b) -> a -> b
$ forall a. Ident a => a -> Id
Id.unpack_id BlockId
block_id

-- ** local

-- | Modify a ruler or rulers, making copies if they're shared outside of
-- the Scope.
local :: Ui.M m => Scope -> BlockId -> ModifyRuler -> m [RulerId]
local :: forall (m :: * -> *).
M m =>
Scope -> BlockId -> (Ruler -> Either Name Ruler) -> m [RulerId]
local Scope
scope BlockId
block_id Ruler -> Either Name Ruler
modify = case Scope
scope of
    Scope
Block -> forall (m :: * -> *).
M m =>
BlockId -> (Ruler -> Either Name Ruler) -> m [RulerId]
local_block BlockId
block_id Ruler -> Either Name Ruler
modify
    Section Int
tracknum -> (forall a. a -> [a] -> [a]
:[]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
M m =>
BlockId -> Int -> (Ruler -> Either Name Ruler) -> m RulerId
local_section BlockId
block_id Int
tracknum Ruler -> Either Name Ruler
modify
    Tracks [Int]
tracknums -> forall (m :: * -> *).
M m =>
BlockId -> [Int] -> (Ruler -> Either Name Ruler) -> m [RulerId]
local_tracks BlockId
block_id [Int]
tracknums Ruler -> Either Name Ruler
modify

-- | Like 'local', but specialized to modify the meter.
local_meter :: Ui.M m => Scope -> BlockId -> (Meter.Meter -> Meter.Meter)
    -> m [RulerId]
local_meter :: forall (m :: * -> *).
M m =>
Scope -> BlockId -> (Meter -> Meter) -> m [RulerId]
local_meter Scope
scope BlockId
block_id Meter -> Meter
modify =
    forall (m :: * -> *).
M m =>
Scope -> BlockId -> (Ruler -> Either Name Ruler) -> m [RulerId]
local Scope
scope BlockId
block_id (forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Meter -> Meter) -> Ruler -> Ruler
Ruler.modify_meter Meter -> Meter
modify)

local_block :: Ui.M m => BlockId -> ModifyRuler -> m [RulerId]
local_block :: forall (m :: * -> *).
M m =>
BlockId -> (Ruler -> Either Name Ruler) -> m [RulerId]
local_block BlockId
block_id Ruler -> Either Name Ruler
modify =
    forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\RulerId
ruler_id -> forall (m :: * -> *).
M m =>
Scope
-> BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
local_ruler Scope
Block BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify)
        forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). M m => BlockId -> m [RulerId]
Ui.rulers_of BlockId
block_id

local_section :: Ui.M m => BlockId -> TrackNum
    -- ^ Modify the 'section_ruler_id' of this track.
    -> ModifyRuler -> m RulerId
local_section :: forall (m :: * -> *).
M m =>
BlockId -> Int -> (Ruler -> Either Name Ruler) -> m RulerId
local_section BlockId
block_id Int
tracknum Ruler -> Either Name Ruler
modify = do
    RulerId
ruler_id <- forall (m :: * -> *). M m => BlockId -> Int -> m RulerId
section_ruler_id BlockId
block_id Int
tracknum
    forall (m :: * -> *).
M m =>
Scope
-> BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
local_ruler (Int -> Scope
Section Int
tracknum) BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify

-- | Modify the given tracks, making copies if they're shared with other
-- tracks.
local_tracks :: Ui.M m => BlockId -> [TrackNum] -> ModifyRuler -> m [RulerId]
local_tracks :: forall (m :: * -> *).
M m =>
BlockId -> [Int] -> (Ruler -> Either Name Ruler) -> m [RulerId]
local_tracks BlockId
block_id [Int]
tracknums Ruler -> Either Name Ruler
modify = do
    [RulerId]
ruler_ids <- forall (m :: * -> *). M m => BlockId -> [Int] -> m [RulerId]
rulers_of BlockId
block_id [Int]
tracknums
    forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [RulerId]
ruler_ids forall a b. (a -> b) -> a -> b
$ \RulerId
ruler_id ->
        forall (m :: * -> *).
M m =>
Scope
-> BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
local_ruler ([Int] -> Scope
Tracks [Int]
tracknums) BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify

-- | Modify the given RulerId, making a copy if it's shared with another block.
local_ruler :: Ui.M m => Scope -> BlockId -> RulerId -> ModifyRuler
    -> m RulerId
local_ruler :: forall (m :: * -> *).
M m =>
Scope
-> BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
local_ruler Scope
scope BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify = do
    ([Int]
in_scope, Bool
out_scope) <- forall (m :: * -> *).
M m =>
Scope -> BlockId -> RulerId -> m ([Int], Bool)
rulers_in_scope Scope
scope BlockId
block_id RulerId
ruler_id
    if RulerId
ruler_id forall a. Eq a => a -> a -> Bool
/= RulerId
Ui.no_ruler Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
out_scope
        then do
            forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
ruler_id Ruler -> Either Name Ruler
modify
            forall (m :: * -> *) a. Monad m => a -> m a
return RulerId
ruler_id
        else do
            RulerId
new_ruler_id <- forall (m :: * -> *).
M m =>
BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
modify_copy BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify
            forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int]
in_scope forall a b. (a -> b) -> a -> b
$ \Int
tracknum ->
                forall (m :: * -> *). M m => BlockId -> Int -> RulerId -> m ()
Ui.set_track_ruler BlockId
block_id Int
tracknum RulerId
new_ruler_id
            forall (m :: * -> *) a. Monad m => a -> m a
return RulerId
new_ruler_id

rulers_in_scope :: Ui.M m => Scope -> BlockId -> RulerId
    -> m ([TrackNum], Bool) -- ^ (tracknums with the RulerId and in the scope,
    -- True if there are ones out of scope)
rulers_in_scope :: forall (m :: * -> *).
M m =>
Scope -> BlockId -> RulerId -> m ([Int], Bool)
rulers_in_scope Scope
scope BlockId
block_id RulerId
ruler_id = do
    [(BlockId, [(Int, TracklikeId)])]
blocks <- forall (m :: * -> *).
M m =>
RulerId -> m [(BlockId, [(Int, TracklikeId)])]
Ui.blocks_with_ruler_id RulerId
ruler_id
    let in_block :: [TrackNum]
        ([Int]
in_block, Bool
out_block) = (forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a b. (a, b) -> b
snd) (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null)) forall a b. (a -> b) -> a -> b
$
            forall a. (a -> Bool) -> [a] -> ([a], [a])
List.partition ((forall a. Eq a => a -> a -> Bool
==BlockId
block_id) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) [(BlockId, [(Int, TracklikeId)])]
blocks
    case Scope
scope of
        Scope
Block -> forall (m :: * -> *) a. Monad m => a -> m a
return ([Int]
in_block, Bool
out_block)
        Section Int
tracknum -> do
            [Int]
section <- forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
M m =>
BlockId -> Int -> m [(Int, TracklikeId)]
get_section BlockId
block_id Int
tracknum
            let ([Int]
in_section, [Int]
out_section) = forall a. (a -> Bool) -> [a] -> ([a], [a])
List.partition
                    (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
section) [Int]
in_block
            forall (m :: * -> *) a. Monad m => a -> m a
return ([Int]
in_section, Bool
out_block Bool -> Bool -> Bool
|| Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
out_section))
        Tracks [Int]
tracknums ->
            forall (m :: * -> *) a. Monad m => a -> m a
return ([Int]
in_track, Bool
out_block Bool -> Bool -> Bool
|| Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
out_track))
            where
            ([Int]
in_track, [Int]
out_track) = forall a. (a -> Bool) -> [a] -> ([a], [a])
List.partition (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
tracknums) [Int]
in_block

-- | Copy the ruler and modify the copy.
modify_copy :: Ui.M m => BlockId -> RulerId -> ModifyRuler -> m RulerId
modify_copy :: forall (m :: * -> *).
M m =>
BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
modify_copy BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify = do
    -- Try to the ruler the same name as the block, since it's now
    -- local to that block, appending numbers if the name is taken.
    -- This can happen if this block is a copy of another with a local
    -- RulerId.
    Id
new_ruler_id <- forall a. Map RulerId a -> BlockId -> Id
block_id_to_free_ruler forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
        forall (m :: * -> *) a. M m => (State -> a) -> m a
Ui.gets State -> Map RulerId Ruler
Ui.state_rulers forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (m :: * -> *) a. Monad m => a -> m a
return BlockId
block_id
    RulerId
new_ruler_id <- forall (m :: * -> *). M m => Id -> RulerId -> m RulerId
copy Id
new_ruler_id RulerId
ruler_id
    forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
new_ruler_id Ruler -> Either Name Ruler
modify
    forall (m :: * -> *) a. Monad m => a -> m a
return RulerId
new_ruler_id

-- ** modify

-- | Modify the ruler on the focused block.  Other blocks with the same ruler
-- will also be modified.
modify :: Ui.M m => Scope -> BlockId -> ModifyRuler -> m ()
modify :: forall (m :: * -> *).
M m =>
Scope -> BlockId -> (Ruler -> Either Name Ruler) -> m ()
modify Scope
scope BlockId
block_id Ruler -> Either Name Ruler
modify = case Scope
scope of
    Scope
Block -> forall (m :: * -> *).
M m =>
BlockId -> (Ruler -> Either Name Ruler) -> m ()
modify_block BlockId
block_id Ruler -> Either Name Ruler
modify
    Section Int
tracknum -> forall (m :: * -> *).
M m =>
BlockId -> Int -> (Ruler -> Either Name Ruler) -> m ()
modify_section BlockId
block_id Int
tracknum Ruler -> Either Name Ruler
modify
    Tracks [Int]
tracknums -> forall (m :: * -> *).
M m =>
BlockId -> [Int] -> (Ruler -> Either Name Ruler) -> m ()
modify_tracks BlockId
block_id [Int]
tracknums Ruler -> Either Name Ruler
modify

-- | Modify all rulers in the block.
modify_block :: Ui.M m => BlockId -> ModifyRuler -> m ()
modify_block :: forall (m :: * -> *).
M m =>
BlockId -> (Ruler -> Either Name Ruler) -> m ()
modify_block BlockId
block_id Ruler -> Either Name Ruler
modify = do
    Int
tracks <- forall (m :: * -> *). M m => BlockId -> m Int
Ui.track_count BlockId
block_id
    forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\RulerId
ruler_id -> forall (m :: * -> *).
M m =>
BlockId -> [Int] -> RulerId -> (Ruler -> Either Name Ruler) -> m ()
modify_ruler BlockId
block_id [Int
0 .. Int
tracksforall a. Num a => a -> a -> a
-Int
1] RulerId
ruler_id Ruler -> Either Name Ruler
modify)
        forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). M m => BlockId -> m [RulerId]
Ui.rulers_of BlockId
block_id

-- | Modify all rulers on the block in this 'section_ruler_id'.
modify_section :: Ui.M m => BlockId -> TrackNum -> ModifyRuler -> m ()
modify_section :: forall (m :: * -> *).
M m =>
BlockId -> Int -> (Ruler -> Either Name Ruler) -> m ()
modify_section BlockId
block_id Int
tracknum Ruler -> Either Name Ruler
modify = do
    RulerId
ruler_id <- forall (m :: * -> *). M m => BlockId -> Int -> m RulerId
section_ruler_id BlockId
block_id Int
tracknum
    [Int]
tracknums <- if RulerId
ruler_id forall a. Eq a => a -> a -> Bool
== RulerId
Ui.no_ruler
        then forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
M m =>
BlockId -> Int -> m [(Int, TracklikeId)]
get_section BlockId
block_id Int
tracknum
        else forall (m :: * -> *) a. Monad m => a -> m a
return [Int
tracknum]
    forall (m :: * -> *).
M m =>
BlockId -> [Int] -> RulerId -> (Ruler -> Either Name Ruler) -> m ()
modify_ruler BlockId
block_id [Int]
tracknums RulerId
ruler_id Ruler -> Either Name Ruler
modify

modify_tracks :: Ui.M m => BlockId -> [TrackNum] -> ModifyRuler -> m ()
modify_tracks :: forall (m :: * -> *).
M m =>
BlockId -> [Int] -> (Ruler -> Either Name Ruler) -> m ()
modify_tracks BlockId
block_id [Int]
tracknums Ruler -> Either Name Ruler
modify = do
    [RulerId]
ruler_ids <- forall (m :: * -> *). M m => BlockId -> [Int] -> m [RulerId]
rulers_of BlockId
block_id [Int]
tracknums
    forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [RulerId]
ruler_ids forall a b. (a -> b) -> a -> b
$ \RulerId
ruler_id ->
        forall (m :: * -> *).
M m =>
BlockId -> [Int] -> RulerId -> (Ruler -> Either Name Ruler) -> m ()
modify_ruler BlockId
block_id [Int]
tracknums RulerId
ruler_id Ruler -> Either Name Ruler
modify

modify_ruler :: Ui.M m => BlockId -> [TrackNum]
    -- ^ If given, these are the TrackIds that were intended to be modified.
    -- This is necessary if you try to modify Ui.no_ruler.
    -> RulerId -> ModifyRuler -> m ()
modify_ruler :: forall (m :: * -> *).
M m =>
BlockId -> [Int] -> RulerId -> (Ruler -> Either Name Ruler) -> m ()
modify_ruler BlockId
block_id [Int]
tracknums RulerId
ruler_id Ruler -> Either Name Ruler
modify
    | RulerId
ruler_id forall a. Eq a => a -> a -> Bool
== RulerId
Ui.no_ruler = do
        RulerId
new_ruler_id <- forall (m :: * -> *).
M m =>
BlockId -> RulerId -> (Ruler -> Either Name Ruler) -> m RulerId
modify_copy BlockId
block_id RulerId
ruler_id Ruler -> Either Name Ruler
modify
        forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int]
tracknums forall a b. (a -> b) -> a -> b
$ \Int
tracknum ->
            forall (m :: * -> *). M m => BlockId -> Int -> RulerId -> m ()
Ui.set_track_ruler BlockId
block_id Int
tracknum RulerId
new_ruler_id
    | Bool
otherwise = forall (m :: * -> *).
M m =>
RulerId -> (Ruler -> Either Name Ruler) -> m ()
Ui.modify_ruler RulerId
ruler_id Ruler -> Either Name Ruler
modify

-- ** util

-- | The section RulerId is the first ruler of the section.  A section is
-- defined by 'get_section', but in a normal block with one ruler track at
-- tracknum 0, it will be tracknum 0.
section_ruler_id :: Ui.M m => BlockId -> TrackNum -> m RulerId
section_ruler_id :: forall (m :: * -> *). M m => BlockId -> Int -> m RulerId
section_ruler_id BlockId
block_id Int
tracknum =
    forall (m :: * -> *) a. (Stack, M m) => Name -> Maybe a -> m a
Ui.require (Name
"no rulers in " forall a. Semigroup a => a -> a -> a
<> forall a. Pretty a => a -> Name
pretty (BlockId
block_id, Int
tracknum))
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> Maybe a
Lists.head forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TracklikeId] -> [RulerId]
Block.ruler_ids_of forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd
        forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *).
M m =>
BlockId -> Int -> m [(Int, TracklikeId)]
get_section BlockId
block_id Int
tracknum

-- | Get the tracks of the section of the given track.  A section extends
-- from a ruler track until the next ruler track.
get_section :: Ui.M m => BlockId -> TrackNum
    -> m [(TrackNum, Block.TracklikeId)]
get_section :: forall (m :: * -> *).
M m =>
BlockId -> Int -> m [(Int, TracklikeId)]
get_section BlockId
block_id Int
tracknum = do
    [TracklikeId]
tracks <- forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). M m => BlockId -> m [(Int, TracklikeId)]
block_tracks BlockId
block_id
    let sections :: [[(Int, TracklikeId)]]
sections = forall a. (a -> Bool) -> [a] -> [[a]]
Lists.splitBefore (forall a. Maybe a -> Bool
Maybe.isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. TracklikeId -> Maybe RulerId
ruler_id_of forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)
            (forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [TracklikeId]
tracks)
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a -> a
fromMaybe [] forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
List.find ((Int
tracknum `elem`) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst) [[(Int, TracklikeId)]]
sections
    where
    ruler_id_of :: TracklikeId -> Maybe RulerId
ruler_id_of (Block.RId RulerId
rid) = forall a. a -> Maybe a
Just RulerId
rid
    ruler_id_of TracklikeId
_ = forall a. Maybe a
Nothing

-- | Create a block-local RulerId.  It gets the exact same name as the block,
-- but is defined as a function so it's clear where this conversion is done.
block_id_to_ruler :: BlockId -> Id.Id
block_id_to_ruler :: BlockId -> Id
block_id_to_ruler = forall a. Ident a => a -> Id
Id.unpack_id

block_id_to_free_ruler :: Map RulerId a -> BlockId -> Id.Id
block_id_to_free_ruler :: forall a. Map RulerId a -> BlockId -> Id
block_id_to_free_ruler Map RulerId a
rulers BlockId
block_id = Id
ident
    where
    -- Always just since the list is infinite.
    Just Id
ident = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
List.find (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Map RulerId a
rulers) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> RulerId
Id.RulerId) forall a b. (a -> b) -> a -> b
$
        forall a b. (a -> b) -> [a] -> [b]
map (Namespace -> Name -> Id
Id.id Namespace
ns) forall a b. (a -> b) -> a -> b
$ Name
name forall a. a -> [a] -> [a]
: [Name
name forall a. Semigroup a => a -> a -> a
<> Name
"-" forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Name
showt Integer
n | Integer
n <- [Integer
1..]]
    (Namespace
ns, Name
name) = Id -> (Namespace, Name)
Id.un_id forall a b. (a -> b) -> a -> b
$ forall a. Ident a => a -> Id
Id.unpack_id BlockId
block_id

copy :: Ui.M m => Id.Id -> RulerId -> m RulerId
copy :: forall (m :: * -> *). M m => Id -> RulerId -> m RulerId
copy Id
ident RulerId
ruler_id = forall (m :: * -> *). M m => Id -> Ruler -> m RulerId
Ui.create_ruler Id
ident forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). M m => RulerId -> m Ruler
Ui.get_ruler RulerId
ruler_id

rulers_of :: Ui.M m => BlockId -> [TrackNum] -> m [RulerId]
rulers_of :: forall (m :: * -> *). M m => BlockId -> [Int] -> m [RulerId]
rulers_of BlockId
block_id [Int]
tracknums = forall a. Ord a => [a] -> [a]
Lists.unique forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TracklikeId] -> [RulerId]
Block.ruler_ids_of forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter ((forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Int]
tracknums) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). M m => BlockId -> m [(Int, TracklikeId)]
block_tracks BlockId
block_id

block_tracks :: Ui.M m => BlockId -> m [(TrackNum, Block.TracklikeId)]
block_tracks :: forall (m :: * -> *). M m => BlockId -> m [(Int, TracklikeId)]
block_tracks = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Track -> TracklikeId
Block.tracklike_id forall b c a. (b -> c) -> (a -> b) -> a -> c
. Block -> [Track]
Block.block_tracks)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *). M m => BlockId -> m Block
Ui.get_block