import * as constants from "asciiflow/client/constants" ; import { store , IModifierKeys , ToolMode } from "asciiflow/client/store" ; import { Vector } from "asciiflow/client/vector" ; import { screenToCell } from "asciiflow/client/view" ; import { HTMLAttributes } from "react" ; import React = require ( "react" ) ; /**
 * Different modes of control.
 */ const Mode = { NONE : 0 , DRAG : 1 , DRAW : 2 , } ; type EventWithModifierKeys = KeyboardEvent | React . MouseEvent | React . TouchEvent ; /**
 * Handles user input events and modifies state.
 */ export class Controller { private mode = Mode . NONE ; private dragOrigin : Vector ; private dragOriginCell : Vector ; private lastMoveCell : Vector ; startDraw ( position , e ) { this . mode = Mode . DRAW ; store . currentTool . start ( screenToCell ( position ) , getModifierKeys ( e ) ) ; } startDrag ( position ) { this . mode = Mode . DRAG ; this . dragOrigin = position ; this . dragOriginCell = store . currentCanvas . offset ; } endAll ( ) { if ( this . mode === Mode . DRAW ) { store . currentTool . end ( ) ; } this . mode = Mode . NONE ; this . dragOrigin = null ; this . dragOriginCell = null ; this . lastMoveCell = null ; } handleKeyPress ( event ) { if ( ! event . ctrlKey && ! event . metaKey && event . keyCode !== 13 ) { store . currentTool . handleKey ( String . fromCharCode ( event . keyCode ) , getModifierKeys ( event ) ) ; } } handleKeyDown ( event ) { let specialKeyCode = null ; if ( event . altKey ) { store . altPressed = true ; if ( event . keyCode === "1" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . BOX ) ; event . preventDefault ( ) ; } else if ( event . keyCode === "2" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . SELECT ) ; event . preventDefault ( ) ; } else if ( event . keyCode === "3" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . FREEFORM ) ; event . preventDefault ( ) ; } else if ( event . keyCode === "4" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . ARROWS ) ; event . preventDefault ( ) ; } else if ( event . keyCode === "5" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . LINES ) ; event . preventDefault ( ) ; } else if ( event . keyCode === "6" . charCodeAt ( 0 ) ) { store . setToolMode ( ToolMode . TEXT ) ; event . preventDefault ( ) ; } } if ( event . ctrlKey || event . metaKey ) { if ( event . keyCode === 67 ) { specialKeyCode = constants . KEY_COPY ; } if ( event . keyCode === 86 ) { specialKeyCode = constants . KEY_PASTE ; } if ( event . keyCode === 90 ) { if ( event . shiftKey ) { store . currentCanvas . redo ( ) ; } else { store . currentCanvas . undo ( ) ; } } if ( event . keyCode === 89 ) { store . currentCanvas . redo ( ) ; } if ( event . keyCode === 88 ) { specialKeyCode = constants . KEY_CUT ; } } if ( event . keyCode === 8 ) { specialKeyCode = constants . KEY_BACKSPACE ; } if ( event . keyCode === 46 ) { specialKeyCode = constants . KEY_DELETE ; } if ( event . keyCode === 13 ) { specialKeyCode = constants . KEY_RETURN ; } if ( event . keyCode === 38 ) { specialKeyCode = constants . KEY_UP ; } if ( event . keyCode === 40 ) { specialKeyCode = constants . KEY_DOWN ; } if ( event . keyCode === 37 ) { specialKeyCode = constants . KEY_LEFT ; } if ( event . keyCode === 39 ) { specialKeyCode = constants . KEY_RIGHT ; } if ( event . keyCode === 32 ) { store . panning = true ; } store . currentTool . handleKey ( specialKeyCode , getModifierKeys ( event ) ) ; } handleKeyUp ( event ) { if ( event . keyCode === 32 ) { store . panning = false ; } if ( ! event . altKey ) { store . altPressed = false ; } } public handleMove ( position , e ) { const moveCell = screenToCell ( position ) ; if ( this . lastMoveCell == null ) { this . lastMoveCell = moveCell ; } if ( ! moveCell . equals ( this . lastMoveCell ) ) { store . currentCursor = store . currentTool . getCursor ( moveCell , getModifierKeys ( e ) ) ; } if ( this . mode === Mode . DRAW && ! moveCell . equals ( this . lastMoveCell ) ) { store . currentTool . move ( moveCell , getModifierKeys ( e ) ) ; } if ( this . mode === Mode . DRAG && ! moveCell . equals ( this . lastMoveCell ) ) { store . currentCanvas . setOffset ( this . dragOriginCell . add ( this . dragOrigin . subtract ( position ) . scale ( 1 / store . currentCanvas . zoom ) ) ) ; } this . lastMoveCell = moveCell ; } } function getModifierKeys ( event ) { return { ctrl : event . ctrlKey , shift : event . shiftKey , meta : event . metaKey , } ; } /**
 * Handles desktop inputs, and passes them onto the main controller.
 */ export class DesktopController { constructor ( private controller ) { } public getHandlerProps ( ) { return { onMouseDown : this . handleMouseDown , onMouseUp : this . handleMouseUp , onWheel : this . handleWheel , onMouseMove : this . handleMouseMove , } ; } handleMouseDown = ( e ) => { if ( store . panning ) { this . controller . startDrag ( Vector . fromMouseEvent ( e ) ) ; } else { this . controller . startDraw ( Vector . fromMouseEvent ( e ) , e ) ; } } ; handleMouseUp = ( e ) => { this . controller . endAll ( ) ; } ; handleMouseLeave = ( e ) => { this . controller . endAll ( ) ; } ; handleWheel = ( e ) => { const delta = - e . deltaY ; const newZoom = store . currentCanvas . zoom * ( delta > 0 ? 1.1 : 0.9 ) ; store . currentCanvas . setZoom ( Math . max ( Math . min ( newZoom , 5 ) , 0.2 ) ) ; } ; handleMouseMove = ( e ) => { this . controller . handleMove ( Vector . fromMouseEvent ( e ) , e ) ; } ; } /**
 * Handles touch inputs, and passes them onto the main controller.
 */ export class TouchController { private pressVector : Vector ; private originalZoom : number ; private zoomLength : number ; private pressTimestamp : number ; private dragStarted = false ; private zoomStarted = false ; constructor ( private controller ) { } public getHandlerProps ( ) { return { onTouchStart : this . handleTouchStart , onTouchMove : this . handleTouchMove , onTouchEnd : this . handleTouchEnd , } ; } private handlePress ( position , e ) { this . pressVector = position ; this . pressTimestamp = Date . now ( ) ; this . dragStarted = false ; window . setTimeout ( ( ) => { if ( ! this . dragStarted && ! this . zoomStarted && this . pressVector != null ) { this . controller . startDraw ( position , e ) ; } } , constants . DRAG_LATENCY ) ; } private handlePressMulti ( positionOne , positionTwo ) { this . controller . endAll ( ) ; this . zoomStarted = true ; this . dragStarted = false ; this . zoomLength = positionOne . subtract ( positionTwo ) . length ( ) ; this . originalZoom = store . currentCanvas . zoom ; } private handleMove ( position , e ) { if ( ! this . dragStarted && Date . now ( ) - this . pressTimestamp < constants . DRAG_LATENCY && position . subtract ( this . pressVector ) . length ( ) > constants . DRAG_ACCURACY ) { this . dragStarted = true ; this . controller . startDrag ( position ) ; } this . controller . handleMove ( position , e ) ; } private handleMoveMulti ( positionOne , positionTwo ) { if ( this . zoomStarted ) { let newZoom = ( this . originalZoom * positionOne . subtract ( positionTwo ) . length ( ) ) / this . zoomLength ; newZoom = Math . max ( Math . min ( newZoom , 5 ) , 0.5 ) ; store . currentCanvas . setZoom ( newZoom ) ; } } /**
     * Ends all current actions, cleans up any state.
     */ reset ( ) { this . dragStarted = false ; this . zoomStarted = false ; this . pressVector = null ; } public handleTouchStart = ( e ) => { e . preventDefault ( ) ; if ( e . touches . length === 1 ) { this . handlePress ( Vector . fromTouchEvent ( e ) , e ) ; } else if ( e . touches . length > 1 ) { this . handlePressMulti ( Vector . fromTouchEvent ( e , 0 ) , Vector . fromTouchEvent ( e , 1 ) ) ; } } ; public handleTouchMove = ( e ) => { e . preventDefault ( ) ; if ( e . touches . length === 1 ) { this . handleMove ( Vector . fromTouchEvent ( e ) , e ) ; } else if ( e . touches . length > 1 ) { this . handleMoveMulti ( Vector . fromTouchEvent ( e , 0 ) , Vector . fromTouchEvent ( e , 1 ) ) ; } } ; public handleTouchEnd = ( e ) => { e . preventDefault ( ) ; this . reset ( ) ; this . controller . endAll ( ) ; } ; }