@startuml
class AppTitleBox {
    - titleTarget : TextMeshProUGUI = null
    Start() : void
}

class BringToFront {
    - OnEnable() : void
}

class CameraRig {
    + cameraConstraints : BoxCollider = null
    + targetCamera : Camera = null
}

class CellChangedEvent {
}

object Transform
object GameObject
GameObject *-- Transform

class Cell {
    changed : CellChangedEvent
    graphicSprite : Sprite
    position : Vector2
    text : string
    reverseText : string
    reversed : bool
    tags : string
    graphicSource : string
    container : ContainerId
    << Unity >> Awake() : void
    << Unity >> OnDestroy() : void
    << Unity >> Start() : void
    {static} RemoveTag(tagString:string, tagToRemove:string) : string
    {static} AddTag(tagString:string, tagToAdd:string) : string
    {static} HasTag(tagString:string, searchTag:string) : bool
    BoxSize() : float
    RemoveTag(t:string) : void
    AddTag(t:string) : void
    HasTag(t:string) : bool
    Delete() : void
}
Cell *-- CellChangedEvent
Cell ..> Periscope

class CameraRig {
    + cameraConstraints : BoxCollider = null
    + targetCamera : Camera = null
}


class CellAttachmentTrigger {
    - targetButton : Button = null
    - cell : Cell = null
    - cellSelectHandler : CellSelectHandler = null
    - targetGraphic : Image = null
    - addPicture : Sprite = null
    - removePicture : Sprite = null
    - Awake() : void
    - Start() : void
    - TogglePicture() : void
    - Update() : void
}
CellAttachmentTrigger --> Cell
CellAttachmentTrigger --> CellSelectHandler

class CellBookmarkTrigger {
    - cell : Cell = null
    - cellSelectHandler : CellSelectHandler = null
    - targetGroup : CanvasGroup = null
    - targetButton : Button = null
    - targetGraphic : Image = null
    - addBookmark : Sprite = null
    - removeBookmark : Sprite = null
    - _isOn : bool
    - <<const>> Bookmarked : string = "Bookmarked"
    - Awake() : void
    - Start() : void
    - Toggle() : void
    - Off() : void
    - On() : void
    - Update() : void
}
CellBookmarkTrigger --> CellSelectHandler
CellBookmarkTrigger --> Cell


class CellCenterWidget {
}


class CellController {
    Awake() : void
}
CellController --> CellDetail
CellController --> Cell
CellController --> CellSelectHandler
CellController --> CellDragHandler
CellController --> CellHotkeyHandler
CellController --> CellPresenter


class CellDeleteTrigger {
    cell : Cell
    targetButton : Button
    << Unity >> Awake() : void
    << Unity >> Start() : void
    << Unity >> Delete() : void
}
CellDeleteTrigger --> Cell


class CellDetail {
}
CellDetail --> Cell


class CellDivideTrigger {
    - divideButton : Button = null
    - duplicateButton : Button = null
    - cellSelectHandler : CellSelectHandler = null
    - cell : Cell = null
    - Awake() : void
    - Start() : void
    - CreateEmptyCell() : void
    - CreateDuplicateCell() : void
    - Update() : void
}
CellDivideTrigger --> CellSelectHandler


class CellDragHandler {
    + dragGizmo : DragGizmo
    - dragColor : Color
    - defaultColor : Color
    - graphicTarget : Image = null
    - _canDropHere : bool = false
    - _dragStartPos : Vector3
    - _dragInterrupted : bool = false
    - BlockDrag : bool <<get>>
    - Start() : void
    + OnBeginDrag(data:PointerEventData) : void
    + OnDrag(eventData:PointerEventData) : void
    + OnEndDrag(eventData:PointerEventData) : void
    + OnPointerEnter(eventData:PointerEventData) : void
    + OnPointerExit(eventData:PointerEventData) : void
}
CellDragHandler --> DragGizmo

IBeginDragHandler <|-- CellDragHandler
IDragHandler <|-- CellDragHandler
IEndDragHandler <|-- CellDragHandler
IPointerEnterHandler <|-- CellDragHandler
IPointerExitHandler <|-- CellDragHandler

class CellEditHandler {
    - data : Cell = null
    - selectHandler : CellSelectHandler = null
    - inputField : TMP_InputField = null
    Awake() : void
    - Update() : void
    - ActivateInputFiled() : void
    - DeactivateInputField(arg:string) : void
    - UpdateDataSource(text:string) : void
    + {static} CopyToClipboard() : void
    + PasteIntoCell() : void
    + OnPointerClick(eventData:PointerEventData) : void
}
CellEditHandler --> Cell
CellEditHandler --> CellSelectHandler

IPointerClickHandler <|-- CellEditHandler

class CellHotkeyHandler {
    - cell : Cell = null
    - cellSelectHandler : CellSelectHandler = null
    - Awake() : void
    Update() : void
    - {static} ObserveNavigation() : void
    - ObserveCancel() : void
    - ObserveMoveToTrash() : void
    - ObserveDeleteCell() : void
    - ObserveSendToStack() : void
}
CellHotkeyHandler --> Cell
CellHotkeyHandler --> CellSelectHandler


class CellEvent {
}
class CellSelectHandler {
    - _frameOfLastSelect : int
    + cellData : Cell = null
    - markedTargetGraphic : Image = null
    - isSelected : bool = false
    + selected : CellEvent
    + deselected : CellEvent
    + marked : CellEvent
    + unMarked : CellEvent
    + IsSelected : bool <<get>>
    + IsResponsive : bool <<get>>
    + WasSelectedThisFrame : bool <<get>>
    # <<Unity>> Awake() : void
    # <<Unity>> OnDestroy() : void
    + <<Unity>> Select() : void
    + <<Unity>> Deselect() : void
    + <<Unity>> OnSelect(eventData:BaseEventData) : void
    + <<Unity>> OnDeselect(eventData:BaseEventData) : void
    + <<Unity>> OnPointerEnter(eventData:PointerEventData) : void
    + {static} MarkedCells : List<CellSelectHandler>
    + MarkExclusive() : void
    + UnMark() : void
    + Mark() : void
    + {static} ClearAndSetMarked(cell:CellSelectHandler) : void
    + {static} AddMarked(cell:CellSelectHandler) : void
    + {static} RemoveMarked(cell:CellSelectHandler, notify:bool) : void
    + {static} ToggleMarked(cell:CellSelectHandler) : void
    + {static} ClearMarked(notify:bool) : void
}
Selectable <|-- CellSelectHandler
CellSelectHandler --> Cell
CellSelectHandler *-- CellEvent

class CollapseGroup {
    - _isExpanded : bool = true
    + targetGraphic : Image
    + targetGroup : CanvasGroup
    + collapsed : Sprite
    + expanded : Sprite
    + transitionDuration : float = 0.1f
    Toggle() : void
    - Update() : void
    + OnPointerClick(eventData:PointerEventData) : void
}

IPointerClickHandler <|-- CollapseGroup

enum ContainerId {
    Canvas1,
    Canvas2,
    Canvas3,
    Canvas4,
    Canvas5,
    Canvas6,
    Stack1,
    Stack2,
    Stack3,
    Stack4,
    Stack5,
    Trash,
    Invalid,
}

class ContextMenu {
    - targetGroup : CanvasGroup = null
    - referenceCamera : Camera = null
    Awake() : void
    Update() : void
    - Toggle() : void
}


class ContrastWithBackground {
    - background : Image
    - target : Graphic
    - colorSampleCount : byte
    - cell : Cell
    - Start() : void
    - UpdateContrast() : void
    + GetAvgBgColor() : Color
}


class CreateCellHandler {
    - referenceCamera : Camera = null
    - maxSize : float = 2048f
    - minSize : float = 2f
    + id : ContainerId
    - _tree : QuadTreeLayout
    + OnPointerClick(eventData:PointerEventData) : void
}

IPointerClickHandler <|-- CreateCellHandler

class DragGizmo {
    + graphicTarget : Image
    + valid : Sprite
    + invalid : Sprite
    + SetValid(value:bool) : void
    + SetPosition(pos:Vector2) : void
}


class DrawingCanvas {
    - _isDrawing : bool = false
    - _isOnCanvas : bool = false
    - _rectTransform : RectTransform = null
    - _penBlock : Color[]
    - _eraserBlock : Color[]
    - <<const>> EraserScale : byte = 5
    - <<const>> BlockSize : byte = 4
    - <<const>> Resolution : int = 512
    - target : RawImage
    + texture : Texture2D
    - _prevPos : Vector2Int
    Start() : void
    + Line(start:Vector2Int, end:Vector2Int, blockSize:Vector2Int, block:Color[], mode:Func<Color, Color, Color>) : void
    + Line(startX:int, startY:int, endX:int, endY:int, blockWidth:int, blockHeight:int, block:Color[], mode:Func<Color, Color, Color>) : void
    Update() : void
    - MousePxPos() : Vector2Int
    - FixedUpdate() : void
    + OnPointerEnter(eventData:PointerEventData) : void
    + OnPointerExit(eventData:PointerEventData) : void
}

IPointerEnterHandler <|-- DrawingCanvas
IPointerExitHandler <|-- DrawingCanvas

class FlowLayoutGroup {
    # _cellSize : Vector2
    + CellSize : Vector2 <<get>> <<set>>
    # _spacing : Vector2
    + Spacing : Vector2 <<get>> <<set>>
    # FlowLayoutGroup()
    + <<override>> CalculateLayoutInputHorizontal() : void
    + <<override>> CalculateLayoutInputVertical() : void
    + <<override>> SetLayoutHorizontal() : void
    + <<override>> SetLayoutVertical() : void
    _cellsPerMainAxis : int
    _actualCellCountX : int
    _actualCellCountY : int
    _positionX : int
    _positionY : int
    _totalWidth : float = 0
    _totalHeight : float = 0
    _lastMaxHeight : float = 0
    - SetCellsAlongAxis(axis:int) : void
}
enum Corner {
    UpperLeft= 0,
    UpperRight= 1,
    LowerLeft= 2,
    LowerRight= 3,
}
enum Constraint {
    Flexible= 0,
    FixedColumnCount= 1,
    FixedRowCount= 2,
}
LayoutGroup <|-- FlowLayoutGroup
FlowLayoutGroup +-- Corner
FlowLayoutGroup +-- Constraint

class GlobalInput {
    Start() : void
    Update() : void
}


interface ICellDrop {
    Drop(cell:Cell, targetPos:Vector2) : void
}

class InputRouter {
    + {static} Mode : InputMode
    + {static} MomentaryPanning : bool <<get>>
    + {static} CmdFrameAll : bool <<get>>
    + {static} CmdFrameSelected : bool <<get>>
    + {static} MomentaryPanTool : bool <<get>>
    + {static} MomentaryCtrl : bool <<get>>
    + {static} CmdRandomise : bool <<get>>
    + {static} MomentaryShift : bool <<get>>
    + {static} MomentarySpace : bool <<get>>
    + {static} MomentaryAlt : bool <<get>>
    + {static} CmdCopy : bool <<get>>
    + {static} CmdPaste : bool <<get>>
    + {static} CmdShowContextMenu : bool <<get>>
    + {static} CmdSelectStackOne : bool <<get>>
    + {static} CmdSelectStackTwo : bool <<get>>
    + {static} CmdSelectStackThree : bool <<get>>
    + {static} CmdSelectStackFour : bool <<get>>
    + {static} CmdSelectStackFive : bool <<get>>
    + {static} CmdSelectStackSix : bool <<get>>
    + {static} CmdSendToStack : bool <<get>>
    + {static} CmdPullFromStack : bool <<get>>
    + {static} AnyKey : bool <<get>>
    + {static} CmdEditCell : bool <<get>>
    + {static} CmdCancel : bool <<get>>
    + {static} CmdDivideCell : bool <<get>>
    + {static} CmdDuplicateCell : bool <<get>>
    + {static} CmdMarkCell : bool <<get>>
    + {static} CmdPlacePicture : bool <<get>>
    + {static} CmdDeleteCell : bool <<get>>
    + {static} CmdSave : bool <<get>>
    + {static} CmdSaveAs : bool <<get>>
    + {static} CmdOpen : bool <<get>>
    + {static} CmdNew : bool <<get>>
    + {static} CmdImport : bool <<get>>
    + {static} CmdRight : bool <<get>>
    + {static} CmdLeft : bool <<get>>
    + {static} CmdUp : bool <<get>>
    + {static} CmdDown : bool <<get>>
    + {static} CmdVertical : bool <<get>>
    + {static} CmdHorizontal : bool <<get>>
    + {static} CmdTogglePanels : bool <<get>>
    + DefaultSelect : GameObject
    - Update() : void
}
enum InputMode {
    TextEdit,
    Drawing,
    Default,
}


class InteractableBasedOnRelativeSize {
    - _ratio : float = 1.0f
    + selectableTarget : Selectable = null
    + minRelativeSize : float = 0.125f
    + maxRelativeSize : float = 1.1f
    + referenceCamera : Camera = null
    + referenceRect : RectTransform = null
    - Awake() : void
    - Start() : void
    Update() : void
    - UpdateInteractable() : void
}


class RendererExtensions <<static>> {
    - {static} CountCornersVisibleFrom(rectTransform:RectTransform, camera:Camera) : int
    + {static} IsFullyVisibleFrom(rectTransform:RectTransform, camera:Camera) : bool
    + {static} IsVisibleFrom(rectTransform:RectTransform, camera:Camera) : bool
}
class LevelOfDetail {
    - _isOn : bool = true
    - _group : CanvasGroup = null
    - _rect : RectTransform = null
    - min : float = 0.25f
    - max : float = 1.0f
    - hiddenAlpha : float = 0.1f
    - Awake() : void
    - Update() : void
}


class MarkAllCellsUnderTarget {
    - target : GameObject = null
    + OnPointerClick(eventData:PointerEventData) : void
}

IPointerClickHandler <|-- MarkAllCellsUnderTarget

class MarkdownParserBridge {
    - inputField : TMP_InputField
    + InputField : TMP_InputField <<get>>
    + MarkDown() : void
}


class MessagePresenter {
    messagePrefab : GameObject
    progressBar : RectTransform
    progressBarGroup : CanvasGroup
    messageLifetime : float
    fadeInDuration : float
    fadeOutDuration : float
    defaultTextColor : Color
    defaultBackgroundColor : Color
    warningTextColor : Color
    warningBackgroundColor : Color
    errorTextColor : Color
    errorBackgroundColor : Color
    _baseProgressBarSize : Vector2
    TimePadding : float = 0.25f
    << Unity >>  Awake() : void
    << Unity >>  Start() : void
    Log(message:string, type:MessageType) : void
    Progress(progress:float) : void
}
enum MessageType {
    Normal,
    Warning,
    Error,
}

MessagePresenter +-- MessageType

class ModalCanvas {
    - gameObjectsToDisable : GameObject[] = null
    - dialogCanvas : GameObject = null
    - buttonPrefab : Button = null
    - buttonContainer : RectTransform = null
    - note : TextMeshProUGUI = null
    - progressBar : RectTransform = null
    - _savedComponentState : (GameObject targetObject, bool isActive)[] = null
    - _baseProgressBarSize : Vector2
    {static} Singleton : ModalCanvas
    << Unity >>  Awake() : void
    << Unity >> Update() : void
    PushChoice(text:string, options:(string label, Action action)[]) : void
    PushProgress(text:string, progress:float, options:(string label, Action action)[]) : void
    CancelDialog() : void
    Activate() : void
    Deactivate() : void
}
Periscope ..> ModalCanvas
ModalCanvas ..> Periscope


class ModalTrigger {
    << Unity >> OnBeginDrag(data:PointerEventData) : void
    << Unity >> OnCancel(data:BaseEventData) : void
    << Unity >> OnDeselect(data:BaseEventData) : void
    << Unity >> OnDrag(data:PointerEventData) : void
    << Unity >> OnDrop(data:PointerEventData) : void
    << Unity >> OnEndDrag(data:PointerEventData) : void
    << Unity >> OnInitializePotentialDrag(data:PointerEventData) : void
    << Unity >> OnMove(data:AxisEventData) : void
    << Unity >> OnPointerClick(data:PointerEventData) : void
    << Unity >> OnPointerDown(data:PointerEventData) : void
    << Unity >> OnPointerEnter(data:PointerEventData) : void
    << Unity >> OnPointerExit(data:PointerEventData) : void
    << Unity >> OnPointerUp(data:PointerEventData) : void
    << Unity >> OnScroll(data:PointerEventData) : void
    << Unity >> OnSelect(data:BaseEventData) : void
    << Unity >> OnSubmit(data:BaseEventData) : void
    << Unity >> OnUpdateSelected(data:BaseEventData) : void
}
EventTrigger <|-- ModalTrigger

class MouseGizmo {
    FixedUpdate() : void
}


class OutOfBoundsHandler {
    + OnDrop(eventData:PointerEventData) : void
    + OnPointerClick(eventData:PointerEventData) : void
}

IDropHandler <|-- OutOfBoundsHandler
IPointerClickHandler <|-- OutOfBoundsHandler

class PanAndZoom {
    - targetCamera : Camera = null
    - cameraPosBoundary : BoxCollider = null
    - speed : Vector3
    - minZoom : float = .0675f
    - maxZoom : float = 2f
    - safeArea : float = 0.65f
    - _posTarget : Vector3
    - _orthoSizeTarget : float = 100f
    - blockingOverlayCanvas : Canvas
    - _blockingOverlayRaycasters : GraphicRaycaster[]
    - _isPointerOnOverlay : bool
    - _oldMousePos : Vector3
    - _currentMousePos : Vector3
    - _worldMouseDelta : Vector3
    - WorldMouseDelta : Vector3 <<get>>
    + HoveredCell : Cell <<get>>
    Awake() : void
    Update() : void
    - UpdateBlockingState() : void
    - UpdateMouseDelta() : void
    + FrameSelected() : void
    + ResetView() : void
    + CenterViewOn(target:RectTransform) : void
    - HotkeyHandler() : void
    - AnimateMovement() : void
    - KeepLastMarkedCellInView() : void
    - {static} FindFrameAround(rects:IEnumerable<RectTransform>) : Rect
    - SetViewTargetsFromMouseInput() : void
    - PanTo(pos:Vector2) : void
    - ZoomTo(target:float) : void
    - SetZoomTarget(aggregateDelta:Vector3) : void
    - SetPanTarget(delta:Vector3) : void
    - CalculateZoomPanDelta(z:float) : Vector3
    - IsCameraDistinctlyInsideMinMaxZoom() : bool
    - IsMouseInViewport() : bool
    - SetPanViewTarget(pos:Vector2) : void
    - SetResetViewTarget() : void
    - SetFocusViewTarget(pos:Vector2) : void
    - SetFrameViewTarget(position:Vector3, size:float) : void
}


class Parallax {
    + parallaxCamera : Camera = null
    + parallaxTarget : RectTransform = null
    + parallaxDistance : float = 512f
    Update() : void
}


class Periscope {
    + panAndZoom : PanAndZoom = null
    + sidebarController : SidebarController = null
    + lastHoveredCell : Cell
    + stackToggleGroup : ToggleGroup
    + cellPrefab : GameObject
    + cells : List<Cell>
    + canvas1Target : RectTransform
    + canvas2Target : RectTransform
    + canvas3Target : RectTransform
    + canvas4Target : RectTransform
    + stack1Target : RectTransform
    + stack2Target : RectTransform
    + stack3Target : RectTransform
    + stack4Target : RectTransform
    + stack5Target : RectTransform
    + stack6Target : RectTransform
    + cellDetailPanel : CellDetail
    + dragGizmo : DragGizmo = null
    + message : MessagePresenter
    + {static} Singleton : Periscope <<get>>
    - {static} _singleton : Periscope
    - Awake() : void
    + Start() : void
    - Update() : void
    - _timeOfLastActivity : float
    - _prevMousePos : Vector3
    - _smoothFps : float
    - <<const>> TargetFpsActive : int = 60
    - <<const>> TargetFpsIdle : int = 30
    - <<const>> TargetFpsSleep : int = 5
    - <<const>> IdleTimeout : float = .5f
    - <<const>> SleepTimeout : float = 10f
    - ThrottleFps() : void
    - KeyShortcutsHandler() : void
    - WelcomeMessage() : void
    + GetActiveStack() : StackCellDropHandler
    + GetContainerDropTarget(target:ContainerId) : RectTransform
    + IsInWorldSpace(target:ContainerId) : bool
    + GetContainerDropHandler(target:ContainerId) : StackCellDropHandler
    + GetActiveStackDropTarget() : Transform
    - _peristentCursor : (Texture2D texture, Vector2 focus)
    - _momentaryCursor : (bool active, Texture2D texture, Vector2 focus)
    - defaultCursor : Texture2D = null
    - panCursor : Texture2D = null
    - textCursor : Texture2D = null
    - drawCursor : Texture2D = null
    + InjectCursor(tex:Texture2D, focus:Vector2) : void
    + EndCursorInjection() : void
    - UpdateCursor() : void
    + SetModeDefault() : void
    + SetModeDrawing() : void
    + SetModeTextInput() : void
    - quickstartSession : TextAsset = null
    - _sessionSavePath : string = ""
    - _isSaved : bool = false
    - _guiBox : GUIStyle = null
    - <<const>> ImportBatchSize : int = 5
    - recoverySaveInterval : float = 15f
    - _saveForRecoveryQueued : bool = true
    - _recoverySaveTimeout : float = 0
    - _injectCursor : bool = false
    - _injectedCursor : Texture2D = null
    - _injectedCursorFocus : Vector2
    - _lastImportDir : string = null
    + {static} <<readonly>> ValidImageExtensions : string[]
    + {static} <<readonly>> ValidTextExtensions : string[]
    + {static} <<readonly>> ValidAudioExtensions : string[]
    + {static} <<readonly>> ValidVideoExtensions : string[]
    + SessionSavePath : string <<get>>
    + IsSaved : bool <<set>> <<get>>
    + NewSession() : void
    + Open() : void
    + Import() : void
    + Save() : void
    + SaveAs() : void
    + {static} LoadImageFromDisk(filePath:string, targetSize:int) : Texture2D
    + {static} ImportCellGraphic(cellData:Cell, searchPaths:string[]) : bool
    - CreateCellFromSession(i:int, session:Session) : void
    + SelectSingleImage() : string
    - ImportTextRt(paths:string[]) : IEnumerator
    - ImportImagesRt(paths:string[]) : IEnumerator
    - LoadSessionFromFile(path:string) : IEnumerator
    - CheckIntegrity(session:Session) : bool
    - BuildSessionFromJson(json:string) : IEnumerator
    + Clear() : void
    + SaveRecoveryFile() : void
    - SaveRecoveryFileHandler() : void
    - ClearRecovery() : void
    - SaveToFile(info:FileInfo, silent:bool) : void
    - CollectSessionAssets(saveFile:FileInfo, session:Session) : void
    + CreateCopyOfCell(original:Cell, container:ContainerId, spawnPos:Vector2) : Cell
    + CreateEmptyCell(container:ContainerId, spawnPos:Vector2) : Cell
    + About() : void
    + Quit() : void
    - OnGUI() : void
}


class CameraRig {
    + cameraConstraints : BoxCollider = null
    + targetCamera : Camera = null
}


class CellAttachmentTrigger {
    - targetButton : Button = null
    - cell : Cell = null
    - cellSelectHandler : CellSelectHandler = null
    - targetGraphic : Image = null
    - addPicture : Sprite = null
    - removePicture : Sprite = null
    - Awake() : void
    - Start() : void
    - TogglePicture() : void
    - Update() : void
}


class QTreeCellDropHandler {
    + id : ContainerId
    - layout : QuadTreeLayout = null
    + <<const>> MinSquareToRecvDrop : int
    + CanReceiveDrop(pos:Vector2) : bool
    + Drop(cell:Cell, targetPos:Vector2) : void
    + OnPointerEnter(eventData:PointerEventData) : void
}

IPointerEnterHandler <|-- QTreeCellDropHandler
ICellDrop <|-- QTreeCellDropHandler

class ScaleToMatchSize {
    - sizeTarget : RectTransform = null
    - _rect : RectTransform = null
    - _baseSize : Vector3
    padding : float = 0
    - Awake() : void
    + SetLayoutHorizontal() : void
    + SetLayoutVertical() : void
    - Update() : void
    - AdjustScale() : void
}

ILayoutController <|-- ScaleToMatchSize

class Session {
    + Product : string
    + Version : string
    + Build : string
    + Company : string
    + Identifier : string
    + DataPath : string
    + PersistentDataPath : string
    + Timestamp : string
    + CollectionPath : string
    + Checksum : string
    + Container : List<int>
    + Path : List<string>
    + Text : List<string>
    + Reverse : List<string>
    + X : List<float>
    + Y : List<float>
    + Tags : List<string>
    + Rating : List<int>
    + Favorite : List<bool>
    + Flag : List<bool>
    + Checked : List<bool>
    + Reversed : List<bool>
    - Session()
    + {static} CreateEmpty() : Session
}
Periscope o-- Session

class SessionFilePresenter {
    + textTarget : TextMeshProUGUI = null
    Update() : void
}
SessionFilePresenter ..> Periscope 

class SidebarController {
}

class StackCellDropHandler {
    + id : ContainerId
    + dropTarget : Transform = null
    - _rect : RectTransform = null
    + OnDrop(eventData:PointerEventData) : void
    - Start() : void
    + Drop(cell:Cell, targetPos:Vector2) : void
    + OnPointerEnter(eventData:PointerEventData) : void
}

IDropHandler <|-- StackCellDropHandler
IPointerEnterHandler <|-- StackCellDropHandler
ICellDrop <|-- StackCellDropHandler

class StackFlow {
    - container : Transform = null
    - _rect : RectTransform = null
    - _previous : Transform = null
    - _slidingItemsCount : int
    Rect : RectTransform <<get>>
    + OnScroll(eventData:PointerEventData) : void
}

IScrollHandler <|-- StackFlow

class StackHotkeys {
    - toggleGroup : ToggleGroup = null
    - togglesParent : Transform = null
    - _toggles : List<Toggle>
    - Start() : void
    Update() : void
}


class StackPresenter {
    - counter : TextMeshProUGUI = null
    - itemContainer : Transform = null
    - toggle : Toggle = null
    << Unity >> Start() : void
    << Unity >> Update() : void
    - Scalorama(isOn:bool) : void
    + ScaleUp() : void
    + ScaleDown() : void
}


class StackShuffle {
    + target : Transform = null
    + toggle : Toggle = null
    - Update() : void
    + Shuffle(parent:Transform) : void
}


class SystemInfoPresenter {
    - textTarget : TextMeshProUGUI
    Update() : void
}


class TagButton {
    + highlight : Button = null
    + delete : Button = null
    + label : TextMeshProUGUI = null
}


class TagManager {
    - tagWidgetPrefab : TagButton = null
    - _dependents : Queue<GameObject>
    + RebuildTags(tags:IEnumerable<string>) : void
    - HighlightTagHandler(tag:string) : void
    - DeleteTagHandler(tag:string) : void
}


class TextureScale {
    - {static} _texColors : Color[]
    - {static} _newColors : Color[]
    - {static} _w : int
    - {static} _ratioX : float
    - {static} _ratioY : float
    - {static} _w2 : int
    + {static} Point(tex:Texture2D, newWidth:int, newHeight:int) : void
    + {static} Bilinear(tex:Texture2D, newWidth:int, newHeight:int) : void
    + {static} PointAsync(tex:Texture2D, newWidth:int, newHeight:int) : Task
    + {static} BilinearAsync(tex:Texture2D, newWidth:int, newHeight:int) : Task
    - {static} ScaleAsync(tex:Texture2D, newWidth:int, newHeight:int, useBilinear:bool) : Task
    + {static} BilinearScaleAsync(slice:(int start, int end)) : Task
    + {static} PointScale(slice:(int start, int end)) : Task
    - {static} ColorLerpUnclamped(c1:Color, c2:Color, value:float) : Color
}

class Tools {
    + edit : Toggle = null
    + draw : Toggle = null
    + Default : Toggle = null
    - Update() : void
}


class TreeNodeController {
    + GridLayoutComponent : GridLayoutGroup = null
    + Bucket : List<TreeNodeController> = null
    + Root : int = 2
    + BucketSize : int <<get>>
    + SizeDelta : Vector2
    - _rect : RectTransform = null
    + IsFull() : bool
    Start() : void
    Update() : void
}

class BringToFront 
{
    - OnEnable()
}

class CameraRig 
{
    BoxCollider cameraConstraints
    Camera targetCamera
}

CellAttachmentTrigger --> Cell
CellAttachmentTrigger --> CellSelectHandler
class CellAttachmentTrigger 
{
    targetButton : Button
    targetGraphic : Image
    addPicture : Sprite
    removePicture : Sprite
    << Unity >> Awake()
    << Unity >> Start()
    << Unity >> Update()
    TogglePicture()
}

class CellEditHandler 
{
    inputField : TMP_InputField
    << Unity >> Awake() : void
    << Unity >> Update() : void
    CopyToClipboard() : void
    PasteIntoCell() : void
    OnPointerClick(e:EventData) : void
    ActivateInputFiled() : void
    DeactivateInputField(t:string) : void
    UpdateDataSource(t:string) : void
}
CellEditHandler --> Cell
CellEditHandler --> CellSelectHandler
interface IPointerClickHandler << Unity >> 
IPointerClickHandler <|-- CellEditHandler

class CellHotkeyHandler 
{
        << Unity >> Awake() : void
        << Unity >> Update() : void
        ObserveNavigation() : void
        ObserveCancel() : void
        ObserveMoveToTrash() : void
        ObserveDeleteCell() : void
        ObserveSendToStack() : void
}
CellHotkeyHandler --> Cell
CellHotkeyHandler --> CellSelectHandler

class CellPresenter 
{
    cellText : TextMeshProUGUI
    cellGraphic : Image
    cellTextBg : Image
    shadeDisabledColor : Color
    rejectedAlpha : float
    colorSampleCount : int
    Group : CanvasGroup
    << Unity >> Awake() : void
    Reverse() : void
    GetAvgBgColor() : Color
    Refresh(c:Cell) : void
}
CellPresenter --> Cell

class CellSelectHandler 
{
        markedTargetGraphic : Image
        << Event >> selected;
        << Event >> deselected;
        << Event >> marked;
        << Event >> unMarked;
        << Unity >> Awake() : void
        << Unity >> OnDeselect(e:EventData) : void
        IsSelected() : bool
        IsResponsive() : bool
        WasSelectedThisFrame() : bool
        OnDestroy() : void
        Select() : void
        Deselect() : void
        OnSelect(e:EventData) : void
        OnPointerEnter(e:EventData) : void
        {static} MarkedCells : CellSelectHandler[]
        MarkExclusive() : void
        UnMark() : void
        Mark() : void
        {static} ClearAndSetMarked(c:Cell) : void
        {static} AddMarked(c:Cell) : void
        {static} RemoveMarked(c:Cell) : void
        {static} ToggleMarked(c:Cell) : void
        {static} ClearMarked() : void
}
class Selectable << Unity >>  
Selectable <|-- CellSelectHandler
CellSelectHandler --> CellDetail
CellSelectHandler --> Cell
CellSelectHandler --> CellSelectHandler

class LevelOfDetail 
{
        group : CanvasGroup 
        rect : RectTransform 
        min = 0.25f
        max = 1.0f
        hiddenAlpha = 0.1f
        << Unity >> Awake() : void
        << Unity >> Update() : void
}

class StackFlow 
{
    + container : Transform
    + OnScroll(PointerEventData eventData) : void
}


class LAPJV <<static>> {
    - <<const>> Big : int = 100000
    + {static} Solve(dim:int, costMatrix:double[][], rowSolution:int[], colSolution:int[], u:double[], v:double[]) : double
}
@enduml
