Karya, built on 2022-03-21T01:30:44 (patch 89d1651424c35e564138d93424a157ff87457245)
Safe HaskellSafe-Inferred



Commands dealing with selection and cursor movement.

As is typical, when it comes to selecting events, the selection represents a half-open range. However, reflecting the orientation of events, a negative event at the start of the range won't be included, and a negative event at he end of the range will be included. This is natural for events with negative duration, since they are weighted at the end.

This behaviour is actually implemented in the low level Ui.Events functions.



set :: Cmd.M m => ViewId -> Maybe Sel.Selection -> m () Source #

Set or unset the selection.

This is the Cmd level of Ui.set_selection and should be called by any Cmd that wants to set the selection.

The insert selnum always has an orientation, so if Sel.orientation is Sel.None, default to Cmd.state_note_orientation. Otherwise, update the note orientation, so the visible orientation and actual orientation stay in sync.

set_current :: Cmd.M m => Sel.Num -> Maybe Sel.Selection -> m () Source #

Set a selection in the current view.

set_subs :: Cmd.M m => ViewId -> Sel.Selection -> m () Source #

For point selections, set a play position selection on the equivalent time in sub-blocks. This makes it easier to edit the super-block relative to the sub-block.

TODO if multiple calls overlap, I should draw multiple selections, but Ui.set_selection doesn't support that, even though the underlying BlockC.set_selection does.

modify existing selection

update_orientation :: Cmd.M m => m () Source #

Update the selection's orientation to match Cmd.state_note_orientation.

to_point :: Cmd.M m => Bool -> m () Source #

Collapse the selection to a point at its (cur_track, cur_pos).

find_at_before :: Ord a => a -> [a] -> Maybe a Source #

advance :: Cmd.M m => m () Source #

Advance the insert selection by the current step, which is a popular thing to do.

data Move Source #

How to move a selection.



Extend the existing selection.


Move the existing selection by the step amount.


Replace the existing selection with a point selection.


Instances details
Show Move Source # 
Instance details

Defined in Cmd.Selection


showsPrec :: Int -> Move -> ShowS #

show :: Move -> String #

showList :: [Move] -> ShowS #

default_move :: Move Source #

Use this Move mode when you don't have a more specific idea.

step :: Cmd.M m => TimeStep.Direction -> Move -> m () Source #

Advance the given selection by the current step.

The selection will maintain its current track span, be set to a point, and advance to the next relevant mark. "next relevant mark" is the next visible mark in the ruler to the left.

shift :: Cmd.M m => Bool -> Move -> Int -> m () Source #

Move the selection across tracks by shift, possibly skipping non-event tracks and collapsed tracks.

jump_to_track :: Cmd.M m => Move -> Types.TrackNum -> m () Source #

Unlike shift, this uses Sel.union, which means that the selection will always expand, instead of only expanding if the current track is moving away from the start track. This is because I use this as a way to expand the selection rather than move it.

data Direction Source #




Instances details
Show Direction Source # 
Instance details

Defined in Cmd.Selection

Eq Direction Source # 
Instance details

Defined in Cmd.Selection

find_before :: (a -> Bool) -> [a] -> Maybe a Source #

Find the element before the predicate matches, or the last element if it never matches.

get_tracks_from_selection Source #


:: Cmd.M m 
=> Bool

If True, start from the R or L edge of the selection, rather than Sel.cur_track.

-> Direction 
-> m [Ui.TrackInfo] 

Get tracks either starting from the right of the selection, or the left. Unselectable tracks are omitted.

cmd_track_all :: Cmd.M m => m () Source #

Progressive selection: select the rest of the track, then the entire track, then the whole block.

TrackNum 0, assumed to be a ruler, is omitted, since selecting the ruler is not only not useful, it tends to make cmds that want to get a TrackId abort.

cmd_toggle_extend_tracks :: Cmd.M m => m () Source #

Extend the selection horizontally to encompass all tracks. If it already does, reset the track selection to the previous one.

set selection from clicks

cmd_select_track :: Cmd.M m => Types.MouseButton -> Msg.Msg -> m () Source #

Select clicked on track.

select_until_end :: ScoreTime.TrackTime -> Sel.Selection -> Sel.Selection Source #

Extend the selection to the end of then block. This sets Sel.start_pos, with the assumption that Sel.cur_pos is onscreen. This is so auto_scroll won't jump to the bottom of the block.

cmd_mouse_selection :: Cmd.M m => Types.MouseButton -> Bool -> Msg.Msg -> m () Source #

Set the selection based on a click or drag.

cmd_snap_selection :: Cmd.M m => Types.MouseButton -> Bool -> Msg.Msg -> m () Source #

Like cmd_mouse_selection, but snap the selection to the current time step.

mouse_drag Source #


:: Cmd.M m 
=> Types.MouseButton 
-> Msg.Msg 
-> m ((Types.TrackNum, UiMsg.Track), (Types.TrackNum, UiMsg.Track))

(mouse down at, mouse currently at)

Get the clicked or dragged range, or abort if this isn't a drag Msg. This accepts clicks as well, and considers them an empty range.


auto scroll

set_and_scroll :: Cmd.M m => ViewId -> Sel.Selection -> m () Source #

Figure out how much to scroll to keep the selection visible and with reasonable space around it.

Anyone who wants to set a selection and automatically scroll the window to follow the selection should use this function.

auto_scroll :: Cmd.M m => ViewId -> Maybe Sel.Selection -> Sel.Selection -> m () Source #

If the selection has scrolled off the edge of the window, automatically scroll it so that the "current" end of the selection is in view.

auto_track_scroll :: Block.Block -> Block.View -> Sel.Selection -> Types.Width Source #

Find the track scroll that would put the given selection into view.


mouse_mod :: Msg.Msg -> Maybe (Bool, Cmd.Modifier, (Types.TrackNum, UiMsg.Track)) Source #

(mouse_down, mouse_modifier, (mouse_track, mouse_pos))


relevant_ruler :: Block.Block -> Types.TrackNum -> Maybe RulerId Source #

Get the ruler that applies to the given track. Search left for the closest ruler that has all the given marklist names. This includes ruler tracks and the rulers of event tracks.

get selection info

sel_point :: Sel.Selection -> ScoreTime.TrackTime Source #

Get the "point" position of a Selection.

sel_point_track :: Sel.Selection -> Types.TrackNum Source #

When multiple tracks are selected, only one can be the point. This is Sel.cur_track, and in fact must be, because Sel.start_track may be an invalid tracknum. That is so a selection can maintain its shape even if it momentarily goes out of bounds.

get_insert :: Cmd.M m => m Point Source #

Get the "insert position", which is the start track and position of the insert selection. Abort if it's not an event track.

get_any_insert :: Cmd.M m => m (ViewId, AnyPoint) Source #

Return the leftmost tracknum and trackpos, even if it's not an event track.

lookup_any_selnum_insert :: Cmd.M m => Sel.Num -> m (Maybe (ViewId, AnyPoint)) Source #

The most general insertion point function.

lookup_block_insert :: Ui.M m => BlockId -> m (Maybe Point) Source #

Given a block, get the selection on it, if any. If there are multiple views, take the one with the alphabetically first ViewId.

I'm not sure how to choose, but the first one seems reasonable for now.

sel_track :: Ui.M m => BlockId -> Sel.Selection -> m (Maybe TrackId) Source #

Get the point track of a selection.

plain Selection

data Context Source #

The selection is in the Ui.State, but focused view is in Cmd.State. Extracting it out lets me depend only on Ui.M, not Cmd.M. Also it decouples selection functions from the current Ui.State and Cmd.State.


Instances details
Show Context Source # 
Instance details

Defined in Cmd.Selection

selections in RealTime

realtime :: Cmd.M m => m (BlockId, RealTime.RealTime, RealTime.RealTime) Source #

Get the real time range of the focused selection. If there's a root block, then it will be in relative to that root, otherwise it's equivalent to local_realtime.

root_realtime :: Cmd.M m => BlockId -> Maybe TrackId -> ScoreTime.ScoreTime -> m (Maybe RealTime.RealTime) Source #

RealTime of the given ScoreTime, relative to the root block. This is the closest we get to an absolute real time.

get_root_insert :: Cmd.M m => m Point Source #

This is like get_insert, except get the selection on the root block, falling back to the current one if there is none.

relative_realtime :: Cmd.M m => BlockId -> m (RealTime.RealTime, RealTime.RealTime) Source #

Get the current selection in RealTime relative to another block.

If a block is called in multiple places, a score time on it may occur at multiple real times. Pick the real time from the given selection which is closest to the real time of the selection on the given root block.

If there's no selection on the root block then return the RealTime from the block's first occurrance.

local_realtime :: Cmd.M m => m (BlockId, RealTime.RealTime, RealTime.RealTime) Source #

Get the RealTime range of the current selection, as derived from current selection's block. This means that the top should be 0.

relative_realtime_point :: Msg.Performance -> Maybe Point -> Point -> RealTime.RealTime Source #

This is like relative_realtime but gets a RealTime relative to a Point, not a range.

select events

type SelectedAround = [(TrackId, ([Event.Event], [Event.Event], [Event.Event]))] Source #

Selected events per track. Gives events before, within, and after the selection. As usual, previous events are in descending order.

events :: Cmd.M m => m SelectedEvents Source #

All selected events. events_around is the default selection behaviour.

track_events :: Cmd.M m => m (TrackId, [Event.Event]) Source #

Like events, but only for the sel_point_track.

events_at_point :: Cmd.M m => m SelectedEvents Source #

Get events exactly at the point. This gets both positive and negative events, so each track may have up to 2 events.

ctx_events_around :: Ui.M m => Context -> m SelectedAround Source #

Get events in the selection, but if no events are selected, expand it to include a neighboring event, as documented in select_neighbor.

Normally the range is half-open by event orientation, so a positive event at the end of the selection won't be included. But there's a special hack where if the end of the selection happens to be the end of the block, a positive event there will be included anyway. Otherwise it's annoying to select a final event (unless it's negative).

This is the standard definition of a selection, and should be used in all standard selection using commands.

opposite_neighbor :: Cmd.M m => m [(TrackId, Event.Event)] Source #

This is similar to events_around, except that the direction is reversed: it favors the next positive event, or the previous negative one. Also this assumes a point selection and only selects one event per track.

select tracks

type Tracks = (BlockId, [Types.TrackNum], [TrackId], Events.Range) Source #

Per-track selection info.

The TrackNums are sorted, and the TrackIds are likewise in left-to-right order. Only TrackNums for event tracks are returned, so both lists should have the same length and correspond if you zip them up.

tracks :: Cmd.M m => m Tracks Source #

Get selected event tracks along with the selection. The tracks are returned in ascending order. Only event tracks are returned, and tracks merged into the selected tracks are included.

track_ids :: Cmd.M m => m [TrackId] Source #

Just the TrackIds part of tracks.

ctx_tracks :: Ui.M m => Context -> m Tracks Source #

Selected tracks, including merged tracks.

ctx_strict_tracks :: Ui.M m => Context -> m Tracks Source #

Selected tracks, not including merged tracks.


keep_history :: Int Source #

Keep only this many selection history entries. This is hardcoded and low since I'm probably not interested in ancient selections.

next_selection :: Cmd.M m => Bool -> m () Source #