import { SocketGraphicsItem } from "./socketgraphicsitem" ; import { GraphicsItem , MouseDownEvent , MouseMoveEvent , MouseUpEvent } from "./graphicsitem" ; import { SceneView , Vector2 , Rect } from "./view" ; import { Color } from "../designer/color" ; import { IPropertyHolder , Property , StringProperty } from "../designer/properties" ; import { NodeScene } from "../scene" ; import { MoveItemsAction } from "../actions/moveItemsaction" ; import { UndoStack } from "../undostack" ; import { FrameGraphicsItem } from "./framegraphicsitem" ; export class SelectionGraphicsItem extends GraphicsItem { view : SceneView ; color : Color ; padding : number ; fontHeight : number ; tooSmallSize : number ; hit : boolean ; dragged : boolean ; items : GraphicsItem [ ] ; draggableItems : GraphicsItem [ ] ; itemsDragStartPos : Vector2 [ ] ; constructor ( scene , view ) { super ( ) ; this . scene = scene ; this . view = view ; this . color = new Color ( 0.9 , 0.9 , 0.9 ) ; this . items = [ ] ; this . itemsDragStartPos = [ ] ; this . hit = false ; this . dragged = false ; this . padding = 5 ; this . fontHeight = 20 ; this . tooSmallSize = 5 ; } public isPointInside ( px , py ) { for ( const item of this . items ) { if ( px >= item . left && px <= item . left + item . getWidth ( ) && py >= item . top && py <= item . top + item . getHeight ( ) ) return true ; } return false ; } draw ( ctx , renderData = null ) { if ( this . hit == false && this . items . length == 0 ) return ; const width = this . width ; const height = this . height ; if ( this . items . length == 0 ) { if ( ! this . isTooSmall ( ) ) { ctx . beginPath ( ) ; ctx . lineWidth = 3 ; ctx . strokeStyle = "rgb(250, 250, 250)" ; ctx . rect ( this . x , this . y , width , height ) ; ctx . setLineDash ( [ 5 , 3 ] ) ; ctx . stroke ( ) ; ctx . setLineDash ( [ ] ) ; const items = this . getHitItems ( ) ; this . drawSelectedItems ( items , ctx ) ; } } else { } } drawSelectedItems ( items , ctx ) { for ( const item of items ) { ctx . beginPath ( ) ; ctx . lineWidth = 2 ; ctx . strokeStyle = "rgba(250, 250, 250)" ; const rect = item . getRect ( ) ; rect . expand ( 15 ) ; ctx . rect ( rect . left , rect . top , rect . width , rect . height ) ; ctx . stroke ( ) ; ctx . fillStyle = "rgba(255, 255, 255, 0.1)" ; ctx . rect ( rect . left , rect . top , rect . width , rect . height ) ; ctx . fill ( ) ; } ctx . setLineDash ( [ ] ) ; } /**
     * If user drags left of up, the width or height becomes negative
     * This returns a rect with positive dimensions
     */ getPositiveRect ( ) { const rect = new Rect ( ) ; rect . x = this . x ; rect . y = this . y ; rect . width = Math . abs ( this . width ) ; rect . height = Math . abs ( this . height ) ; if ( this . width < 0 ) rect . x += this . width ; if ( this . height < 0 ) rect . y += this . height ; return rect ; } setHitItems ( items ) { this . items = items ; this . draggableItems = this . getDraggableHitItems ( this . items ) ; } getHitItems ( ) { const items = [ ] ; const rect = this . getPositiveRect ( ) ; for ( const node of this . scene . nodes ) { if ( node . intersectsRect ( rect ) ) { items . push ( node ) ; } } for ( const item of this . scene . comments ) { if ( item . intersectsRect ( rect ) ) { items . push ( item ) ; } } for ( const item of this . scene . frames ) { const frame = < FrameGraphicsItem > item ; const regions = frame . getFrameRegions ( ) ; for ( const region of regions ) { if ( region . rect . intersects ( rect ) ) { items . push ( item ) ; break ; } } } for ( const item of this . scene . navigations ) { if ( item . intersectsRect ( rect ) ) { items . push ( item ) ; } } return items ; } getDraggableHitItems ( hitItems ) { const items = new Set < GraphicsItem > ( ) ; hitItems . forEach ( ( i ) => { items . add ( i ) ; if ( i instanceof FrameGraphicsItem ) { const captured = ( < FrameGraphicsItem > i ) . getHoveredNodes ( ) ; captured . forEach ( c => items . add ( c ) ) ; } } ) ; const results = [ ] ; items . forEach ( ( i ) => results . push ( i ) ) ; return results ; } public mouseDown ( evt ) { this . hit = true ; this . dragged = false ; if ( this . items . length > 0 ) { this . captureDragStarts ( ) ; } else { this . x = evt . globalX ; this . y = evt . globalY ; this . scene . setSelectedItems ( [ ] ) ; } } public mouseMove ( evt ) { if ( this . items . length > 0 ) { for ( const item of this . draggableItems ) { item . move ( evt . deltaX , evt . deltaY ) ; } this . dragged = true ; } else if ( this . hit ) { this . width += evt . deltaX ; this . height += evt . deltaY ; } } public mouseUp ( evt ) { this . hit = false ; if ( this . items . length == 0 && ! this . isTooSmall ( ) ) { this . items = this . getHitItems ( ) ; this . scene . setSelectedItems ( this . items ) ; this . draggableItems = this . getDraggableHitItems ( this . items ) ; } else { if ( this . dragged ) this . createUndoAction ( ) ; } this . dragged = false ; } captureDragStarts ( ) { this . itemsDragStartPos = [ ] ; for ( const item of this . draggableItems ) { const pos = new Vector2 ( item . left , item . top ) ; this . itemsDragStartPos . push ( pos ) ; } } isTooSmall ( ) { return ( Math . abs ( this . width ) < this . tooSmallSize || Math . abs ( this . height ) < this . tooSmallSize ) ; } createUndoAction ( ) { const newPosList = [ ] ; for ( const item of this . draggableItems ) { const pos = new Vector2 ( item . left , item . top ) ; newPosList . push ( pos ) ; } const action = new MoveItemsAction ( this . draggableItems , this . itemsDragStartPos , newPosList ) ; UndoStack . current . push ( action ) ; } }