# Annotation marker sample

The Annotation sample provides a marker that can be used as a bookmark for your timeline.

![Annotation](images/smpl_annotation.png)

Here are the options available on an annotation:
Field | Description
--- | ---
Title | The annotation's title. This will be displayed as a tooltip, when hovering the mouse on the annotation.
Color | The annotation's color in the Timeline window.
Show line overlay | Use this option to show a vertical line that spans the full height of the Timeline window.

## Custom marker workflow example

This example will demonstrate how to:

* create a custom marker;
* customize a marker with `MarkerEditor`;
* use a custom USS style to draw a marker;
* add additional commands with `Actions`;

### 1. Create an annotation marker

A marker is an item that can be added to a Timeline Asset and is used to represent a point in time.
Markers also have a specialization, just like clips (Activation clip, Audio clip, Animation clip, etc).

In order to add a new type of marker, all we need to do is to create a class that inherits the `Marker` class:

``` c#
public class AnnotationMarker : UnityEngine.Timeline.Marker {}
```

This custom marker can now be added to any track or on the timeline marker area:

![New marker added to a timeline](images/smpl_annotation_newMarker.png)

We can add a title, description and color to the annotation:

``` c#
public class AnnotationMarker : Marker
{
    public string title;
    public Color color;
    public string description;
    public bool showLineOverlay;
}
```

The annotation marker itself is now complete. But the customization work is not done yet. Timeline offers many customization abilities.

## 2. Customize the marker's appearance

A marker's appearance can be customized using a USS style or with `MarkerEditor`. Both paths have their advantages and drawbacks.

### Custom USS style

A marker can use a USS style to specify its appearance. For more information on how to create custom USS styles, see [how to define custom USS styles](uss_styles.md).

The [CustomStyle](xref:UnityEngine.Timeline.CustomStyleAttribute) attribute can be used to specify a style for a given marker:

``` c#
[CustomStyle("AnnotationStyle")]
public class AnnotationMarker : Marker
{
    //...
}
```

`AnnotationStyle` is defined in a USS stylesheet and will be used when a marker is displayed on screen:

![Custom style](images/smpl_annotation_customStyle.png)

USS styles are useful if the desired appearance is simple (i.e. when only using a texture icon). For more complex stuff (i.e. dynamically changing a marker's color), a `MarkerEditor` will be needed.

### Custom editor

`MarkerEditor` can be used to augment the capabilities of a marker in the editor. It works like a custom [Inspector](https://docs.unity3d.com/ScriptReference/CustomEditor.html); the [CustomTimelineEditor attribute](xref:UnityEditor.Timeline.CustomTimelineEditorAttribute) is used to tell Timeline that a [MarkerEditor](xref:UnityEditor.Timeline.MarkerEditor) class should be associated to a given marker.

``` c#
[CustomTimelineEditor(typeof(AnnotationMarker))]
public class AnnotationMarkerEditor : MarkerEditor
{
   //...
}
```

#### Marker information

`MarkerEditor` lets us provide information about the marker by overriding the [GetMarkerOptions](xref:UnityEditor.Timeline.MarkerEditor#UnityEditor_Timeline_MarkerEditor_GetMarkerOptions_UnityEngine_Timeline_IMarker_) method.

``` c#
public override MarkerDrawOptions GetMarkerOptions(IMarker marker)
{
   var annotation = marker as AnnotationMarker;
   if (annotation != null)
   {
      return new MarkerDrawOptions { tooltip = annotation.title };
   }
   return base.GetMarkerOptions(marker);
}
```

Here the tooltip of an `Annotation` has been set to use the annotation's `title` variable.

![Marker tooltip](images/smpl_annotation_markerTooltip.png)

[MarkerDrawOptions](xref:UnityEditor.Timeline.MarkerDrawOptions) can also set the error text on a marker, which can be useful if a variable has been incorrectly set and needs attention.

#### Overlay

An overlay can be drawn on top of a marker by overriding the [DrawOverlay](xref:UnityEditor.Timeline.MarkerEditor#UnityEditor_Timeline_MarkerEditor_DrawOverlay_UnityEngine_Timeline_IMarker_UnityEditor_Timeline_MarkerUIStates_UnityEditor_Timeline_MarkerOverlayRegion_) method:

``` c#
public override void DrawOverlay(IMarker marker, MarkerUIStates uiState, MarkerOverlayRegion region)
{
    var annotation = marker as AnnotationMarker;
    if (annotation != null)
    {
        //Draw overlay code...
    }
}
```

An overlay is drawn on top of the marker; the [USS style](uss_styles.md) is drawn first and `DrawOverlay` is called afterwards. For an `Annotation`, we can use `DrawOverlay` to change the color of the marker and to draw a line that spans the full Timeline window's height. To do this, we can use the information given in `region`. Along with the visible time range, [MarkerOverlayRegion](xref:UnityEditor.Timeline.MarkerOverlayRegion) provides two rectangles that can be used to know where to draw:

* `markerRegion`

`markerRegion` is the rectangle that encompasses the marker. This is useful to draw something directly on the marker itself. For `Annotation`, this rectangle is used to draw the color overlay.

![marker region](images/smpl_annotation_markerOverlayRegion.png)

* `timelineRegion`

`timelineRegion` is the rectangle that encompasses the clips and markers region of the timeline window. This is useful to draw something out of the marker's region, like the `Annotation`'s line overlay.

![timeline region](images/smpl_annotation_timelineOverlayRegion.png)

``` c#
const float k_LineOverlayWidth = 6.0f;
float markerRegionCenter = markerRegion.xMin + (markerRegion.width - k_LineOverlayWidth) / 2.0f;
Rect lineRect = new Rect(markerRegionCenter,
    timelineRegion.y,
    k_LineOverlayWidth,
    timelineRegion.height);
```

## 3. Create custom Actions

### Timeline Action

Actions can be used to add new menu entries in Timeline's context menus. For an Annotation, we want to add a menu item available in all context menus to create an `Annotation` with the clipboard's contents. To do this, a [TimelineAction](xref:UnityEditor.Timeline.Actions.TimelineAction) is needed, along with the [MenuEntry attribute](xref:UnityEditor.Timeline.Actions.MenuEntryAttribute).

``` c#
[MenuEntry("Create Annotation from clipboard contents")]
public class CreateAnnotationFromClipboardContents : TimelineAction
{
    //...
}
```

`MenuEntry` lets Timeline know that this action can be added in context menus. Classes inheriting from `TimelineAction` need to override two methods: `Execute` and `Validate`.

#### Validate

`Validate` is used to specify that the action's prerequisites are fulfilled. In the case of `CreateAnnotationFromClipboardContents`, the action is only valid if there actually is contents in the clipboard. `ActionValidity` is used to describe the validity state of an action:

``` c#
public override ActionValidity Validate(ActionContext context)
{
    if (!markers.All(marker => marker is AnnotationMarker))
        return ActionValidity.NotApplicable;

    string buffer = EditorGUIUtility.systemCopyBuffer;
    return buffer.Length == 0 ?  ActionValidity.Invalid : ActionValidity.Valid;
}
```

* `ActionValidity.Valid` : The action can be executed.
* `ActionValidity.Invalid` : The action cannot be executed given the current context and will appear grayed out in context menus.
* `ActionValidity.NotApplicable` : The action does not apply to the current context and will not show up in menus.

#### Execute

`Execute` should run the code necessary to execute the action's purpose.

``` c#
 public override bool Execute(ActionContext context)
{
    string buffer = EditorGUIUtility.systemCopyBuffer;
    TrackAsset track = context.tracks.FirstOrDefault();

    if (buffer.Length != 0)
    {
        // Create the new annotation and add it to the track
        //...
        return true;
    }

    return false;
}
```

The return value should specify if the execution succeeded or not.

### Marker Action

It is also possible to write custom actions that apply only to markers, instead of all Timeline items. This is the purpose of the `MarkerEditor` class. It works just like `TimelineAction`, except that action applies to a list of markers.

A shortcut can also be assigned to an action. A static method with the `TimelineShortcut` attribute is needed. `Invoker` can be used to easily execute a given action:

``` c#
[TimelineShortcut("Replace annotation description with clipboard", KeyCode.G)]
public static void InvokeAction()
{
    Invoker.InvokeWithSelectedMarkers<ReplaceAnnotationDescriptionAction>();
}
```

## Notes

## Runtime considerations

`AnnotationMarker` is available at runtime; it can be queried using, for example, `TrackAsset.GetMarkers()`. However, `AnnotationMarkerEditor` and custom actions are not available at runtime, since it depends on classes that are not part of the runtime assembly.