<s> from __future__ import division <EOL> import weakref <EOL> import numpy as np <EOL> from . . import gloo <EOL> from . . import app <EOL> from . visuals import VisualNode <EOL> from . . visuals . transforms import TransformSystem <EOL> from . . color import Color <EOL> from . . util import logger , Frozen <EOL> from . . util . profiler import Profiler <EOL> from . subscene import SubScene <EOL> from . events import SceneMouseEvent <EOL> from . widgets import Widget <EOL> class SceneCanvas ( app . Canvas , Frozen ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , title = '<STR_LIT>' , size = ( <NUM_LIT> , <NUM_LIT> ) , position = None , <EOL> show = False , autoswap = True , app = None , create_native = True , <EOL> vsync = False , resizable = True , decorate = True , fullscreen = False , <EOL> config = None , shared = None , keys = None , parent = None , dpi = None , <EOL> always_on_top = False , px_scale = <NUM_LIT:1> , bgcolor = '<STR_LIT>' ) : <EOL> self . _scene = None <EOL> self . _central_widget = None <EOL> self . _draw_order = weakref . WeakKeyDictionary ( ) <EOL> self . _drawing = False <EOL> self . _fb_stack = [ ] <EOL> self . _vp_stack = [ ] <EOL> self . _mouse_handler = None <EOL> self . transforms = TransformSystem ( canvas = self ) <EOL> self . _bgcolor = Color ( bgcolor ) . rgba <EOL> self . _send_hover_events = False <EOL> super ( SceneCanvas , self ) . __init__ ( <EOL> title , size , position , show , autoswap , app , create_native , vsync , <EOL> resizable , decorate , fullscreen , config , shared , keys , parent , dpi , <EOL> always_on_top , px_scale ) <EOL> self . events . mouse_press . connect ( self . _process_mouse_event ) <EOL> self . events . mouse_move . connect ( self . _process_mouse_event ) <EOL> self . events . mouse_release . connect ( self . _process_mouse_event ) <EOL> self . events . mouse_wheel . connect ( self . _process_mouse_event ) <EOL> self . scene = SubScene ( ) <EOL> self . freeze ( ) <EOL> @ property <EOL> def scene ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _scene <EOL> @ scene . setter <EOL> def scene ( self , node ) : <EOL> oldscene = self . _scene <EOL> self . _scene = node <EOL> if oldscene is not None : <EOL> oldscene . _set_canvas ( None ) <EOL> oldscene . events . children_change . disconnect ( self . _update_scenegraph ) <EOL> if node is not None : <EOL> node . _set_canvas ( self ) <EOL> node . events . children_change . connect ( self . _update_scenegraph ) <EOL> @ property <EOL> def central_widget ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . _central_widget is None : <EOL> self . _central_widget = Widget ( size = self . size , parent = self . scene ) <EOL> return self . _central_widget <EOL> @ property <EOL> def bgcolor ( self ) : <EOL> return Color ( self . _bgcolor ) <EOL> @ bgcolor . setter <EOL> def bgcolor ( self , color ) : <EOL> self . _bgcolor = Color ( color ) . rgba <EOL> if hasattr ( self , '<STR_LIT>' ) : <EOL> self . update ( ) <EOL> def update ( self , node = None ) : <EOL> """<STR_LIT>""" <EOL> if self . _drawing : <EOL> return <EOL> app . Canvas . update ( self ) <EOL> def on_draw ( self , event ) : <EOL> """<STR_LIT>""" <EOL> if self . _scene is None : <EOL> return <EOL> logger . debug ( '<STR_LIT>' ) <EOL> self . _draw_scene ( ) <EOL> def render ( self , region = None , size = None , bgcolor = None ) : <EOL> """<STR_LIT>""" <EOL> self . set_current ( ) <EOL> offset = ( <NUM_LIT:0> , <NUM_LIT:0> ) if region is None else region [ : <NUM_LIT:2> ] <EOL> csize = self . size if region is None else region [ <NUM_LIT:2> : ] <EOL> s = self . pixel_scale <EOL> size = tuple ( [ x * s for x in csize ] ) if size is None else size <EOL> fbo = gloo . FrameBuffer ( color = gloo . RenderBuffer ( size [ : : - <NUM_LIT:1> ] ) , <EOL> depth = gloo . RenderBuffer ( size [ : : - <NUM_LIT:1> ] ) ) <EOL> self . push_fbo ( fbo , offset , csize ) <EOL> try : <EOL> self . _draw_scene ( bgcolor = bgcolor ) <EOL> return fbo . read ( ) <EOL> finally : <EOL> self . pop_fbo ( ) <EOL> def _draw_scene ( self , bgcolor = None ) : <EOL> if bgcolor is None : <EOL> bgcolor = self . _bgcolor <EOL> self . context . clear ( color = bgcolor , depth = True ) <EOL> self . draw_visual ( self . scene ) <EOL> def draw_visual ( self , visual , event = None ) : <EOL> """<STR_LIT>""" <EOL> prof = Profiler ( ) <EOL> self . set_current ( ) <EOL> try : <EOL> self . _drawing = True <EOL> if visual not in self . _draw_order : <EOL> self . _draw_order [ visual ] = self . _generate_draw_order ( ) <EOL> order = self . _draw_order [ visual ] <EOL> stack = [ ] <EOL> invisible_node = None <EOL> for node , start in order : <EOL> if start : <EOL> stack . append ( node ) <EOL> if invisible_node is None : <EOL> if not node . visible : <EOL> invisible_node = node <EOL> else : <EOL> if hasattr ( node , '<STR_LIT>' ) : <EOL> node . draw ( ) <EOL> prof . mark ( str ( node ) ) <EOL> else : <EOL> if node is invisible_node : <EOL> invisible_node = None <EOL> stack . pop ( ) <EOL> finally : <EOL> self . _drawing = False <EOL> def _generate_draw_order ( self , node = None ) : <EOL> """<STR_LIT>""" <EOL> if node is None : <EOL> node = self . _scene <EOL> order = [ ( node , True ) ] <EOL> children = node . children <EOL> children . sort ( key = lambda ch : ch . order ) <EOL> for ch in children : <EOL> order . extend ( self . _generate_draw_order ( ch ) ) <EOL> order . append ( ( node , False ) ) <EOL> return order <EOL> def _update_scenegraph ( self , event ) : <EOL> """<STR_LIT>""" <EOL> self . _draw_order . clear ( ) <EOL> self . update ( ) <EOL> def _process_mouse_event ( self , event ) : <EOL> prof = Profiler ( ) <EOL> deliver_types = [ '<STR_LIT>' , '<STR_LIT>' ] <EOL> if self . _send_hover_events : <EOL> deliver_types += [ '<STR_LIT>' ] <EOL> picked = self . _mouse_handler <EOL> if picked is None : <EOL> if event . type in deliver_types : <EOL> picked = self . visual_at ( event . pos ) <EOL> if picked is None : <EOL> return <EOL> scene_event = SceneMouseEvent ( event = event , visual = picked ) <EOL> if picked == self . _mouse_handler : <EOL> if event . type == '<STR_LIT>' : <EOL> self . _mouse_handler = None <EOL> getattr ( picked . events , event . type ) ( scene_event ) <EOL> else : <EOL> while picked is not None : <EOL> getattr ( picked . events , event . type ) ( scene_event ) <EOL> if scene_event . handled : <EOL> if event . type == '<STR_LIT>' : <EOL> self . _mouse_handler = picked <EOL> break <EOL> if event . type in deliver_types : <EOL> picked = picked . parent <EOL> scene_event . visual = picked <EOL> else : <EOL> picked = None <EOL> event . handled = scene_event . handled <EOL> def visual_at ( self , pos ) : <EOL> """<STR_LIT>""" <EOL> tr = self . transforms . get_transform ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> fbpos = tr . map ( pos ) [ : <NUM_LIT:2> ] <EOL> try : <EOL> id_ = self . _render_picking ( region = ( fbpos [ <NUM_LIT:0> ] , fbpos [ <NUM_LIT:1> ] , <EOL> <NUM_LIT:1> , <NUM_LIT:1> ) ) <EOL> vis = VisualNode . _visual_ids . get ( id_ [ <NUM_LIT:0> , <NUM_LIT:0> ] , None ) <EOL> except RuntimeError : <EOL> return self . _visual_bounds_at ( pos ) <EOL> return vis <EOL> def _visual_bounds_at ( self , pos , node = None ) : <EOL> """<STR_LIT>""" <EOL> if node is None : <EOL> node = self . scene <EOL> for ch in node . children : <EOL> hit = self . _visual_bounds_at ( pos , ch ) <EOL> if hit is not None : <EOL> return hit <EOL> if ( not isinstance ( node , VisualNode ) or not node . visible or <EOL> not node . interactive ) : <EOL> return None <EOL> bounds = [ node . bounds ( axis = i ) for i in range ( <NUM_LIT:2> ) ] <EOL> if None in bounds : <EOL> return None <EOL> tr = self . scene . node_transform ( node ) . inverse <EOL> corners = np . array ( [ <EOL> [ bounds [ <NUM_LIT:0> ] [ <NUM_LIT:0> ] , bounds [ <NUM_LIT:1> ] [ <NUM_LIT:0> ] ] , <EOL> [ bounds [ <NUM_LIT:0> ] [ <NUM_LIT:0> ] , bounds [ <NUM_LIT:1> ] [ <NUM_LIT:1> ] ] , <EOL> [ bounds [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] , bounds [ <NUM_LIT:1> ] [ <NUM_LIT:0> ] ] , <EOL> [ bounds [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] , bounds [ <NUM_LIT:1> ] [ <NUM_LIT:1> ] ] ] ) <EOL> bounds = tr . map ( corners ) <EOL> xhit = bounds [ : , <NUM_LIT:0> ] . min ( ) < pos [ <NUM_LIT:0> ] < bounds [ : , <NUM_LIT:0> ] . max ( ) <EOL> yhit = bounds [ : , <NUM_LIT:1> ] . min ( ) < pos [ <NUM_LIT:1> ] < bounds [ : , <NUM_LIT:1> ] . max ( ) <EOL> if xhit and yhit : <EOL> return node <EOL> def visuals_at ( self , pos , radius = <NUM_LIT:10> ) : <EOL> """<STR_LIT>""" <EOL> tr = self . transforms . get_transform ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> pos = tr . map ( pos ) [ : <NUM_LIT:2> ] <EOL> id = self . _render_picking ( region = ( pos [ <NUM_LIT:0> ] - radius , pos [ <NUM_LIT:1> ] - radius , <EOL> radius * <NUM_LIT:2> + <NUM_LIT:1> , radius * <NUM_LIT:2> + <NUM_LIT:1> ) ) <EOL> ids = [ ] <EOL> seen = set ( ) <EOL> for i in range ( radius ) : <EOL> subr = id [ radius - i : radius + i + <NUM_LIT:1> , radius - i : radius + i + <NUM_LIT:1> ] <EOL> subr_ids = set ( list ( np . unique ( subr ) ) ) <EOL> ids . extend ( list ( subr_ids - seen ) ) <EOL> seen |= subr_ids <EOL> visuals = [ VisualNode . _visual_ids . get ( x , None ) for x in ids ] <EOL> return [ v for v in visuals if v is not None ] <EOL> def _render_picking ( self , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> self . _scene . picking = True <EOL> img = self . render ( bgcolor = ( <NUM_LIT:0> , <NUM_LIT:0> , <NUM_LIT:0> , <NUM_LIT:0> ) , ** kwargs ) <EOL> finally : <EOL> self . _scene . picking = False <EOL> img = img . astype ( '<STR_LIT>' ) * [ <NUM_LIT:2> ** <NUM_LIT:0> , <NUM_LIT:2> ** <NUM_LIT:8> , <NUM_LIT:2> ** <NUM_LIT:16> , <NUM_LIT:2> ** <NUM_LIT> ] <EOL> id_ = img . sum ( axis = <NUM_LIT:2> ) . astype ( '<STR_LIT>' ) <EOL> return id_ <EOL> def on_resize ( self , event ) : <EOL> """<STR_LIT>""" <EOL> self . _update_transforms ( ) <EOL> if self . _central_widget is not None : <EOL> self . _central_widget . size = self . size <EOL> if len ( self . _vp_stack ) == <NUM_LIT:0> : <EOL> self . context . set_viewport ( <NUM_LIT:0> , <NUM_LIT:0> , * self . physical_size ) <EOL> def on_close ( self , event ) : <EOL> """<STR_LIT>""" <EOL> self . events . mouse_press . disconnect ( self . _process_mouse_event ) <EOL> self . events . mouse_move . disconnect ( self . _process_mouse_event ) <EOL> self . events . mouse_release . disconnect ( self . _process_mouse_event ) <EOL> self . events . mouse_wheel . disconnect ( self . _process_mouse_event ) <EOL> def push_viewport ( self , viewport ) : <EOL> """<STR_LIT>""" <EOL> vp = list ( viewport ) <EOL> if vp [ <NUM_LIT:2> ] < <NUM_LIT:0> : <EOL> vp [ <NUM_LIT:0> ] += vp [ <NUM_LIT:2> ] <EOL> vp [ <NUM_LIT:2> ] *= - <NUM_LIT:1> <EOL> if vp [ <NUM_LIT:3> ] < <NUM_LIT:0> : <EOL> vp [ <NUM_LIT:1> ] += vp [ <NUM_LIT:3> ] <EOL> vp [ <NUM_LIT:3> ] *= - <NUM_LIT:1> <EOL> self . _vp_stack . append ( vp ) <EOL> try : <EOL> self . context . set_viewport ( * vp ) <EOL> except : <EOL> self . _vp_stack . pop ( ) <EOL> raise <EOL> self . _update_transforms ( ) <EOL> def pop_viewport ( self ) : <EOL> """<STR_LIT>""" <EOL> vp = self . _vp_stack . pop ( ) <EOL> if len ( self . _vp_stack ) > <NUM_LIT:0> : <EOL> self . context . set_viewport ( * self . _vp_stack [ - <NUM_LIT:1> ] ) <EOL> else : <EOL> self . context . set_viewport ( <NUM_LIT:0> , <NUM_LIT:0> , * self . physical_size ) <EOL> self . _update_transforms ( ) <EOL> return vp <EOL> def push_fbo ( self , fbo , offset , csize ) : <EOL> """<STR_LIT>""" <EOL> self . _fb_stack . append ( ( fbo , offset , csize ) ) <EOL> try : <EOL> fbo . activate ( ) <EOL> h , w = fbo . color_buffer . shape [ : <NUM_LIT:2> ] <EOL> self . push_viewport ( ( <NUM_LIT:0> , <NUM_LIT:0> , w , h ) ) <EOL> except Exception : <EOL> self . _fb_stack . pop ( ) <EOL> raise <EOL> self . _update_transforms ( ) <EOL> def pop_fbo ( self ) : <EOL> """<STR_LIT>""" <EOL> fbo = self . _fb_stack . pop ( ) <EOL> fbo [ <NUM_LIT:0> ] . deactivate ( ) <EOL> self . pop_viewport ( ) <EOL> if len ( self . _fb_stack ) > <NUM_LIT:0> : <EOL> old_fbo = self . _fb_stack [ - <NUM_LIT:1> ] <EOL> old_fbo [ <NUM_LIT:0> ] . activate ( ) <EOL> self . _update_transforms ( ) <EOL> return fbo <EOL> def _current_framebuffer ( self ) : <EOL> """<STR_LIT>""" <EOL> if len ( self . _fb_stack ) == <NUM_LIT:0> : <EOL> return None , ( <NUM_LIT:0> , <NUM_LIT:0> ) , self . size <EOL> else : <EOL> return self . _fb_stack [ - <NUM_LIT:1> ] <EOL> def _update_transforms ( self ) : <EOL> """<STR_LIT>""" <EOL> if len ( self . _fb_stack ) == <NUM_LIT:0> : <EOL> fb_size = fb_rect = None <EOL> else : <EOL> fb , origin , fb_size = self . _fb_stack [ - <NUM_LIT:1> ] <EOL> fb_rect = origin + fb_size <EOL> if len ( self . _vp_stack ) == <NUM_LIT:0> : <EOL> viewport = None <EOL> else : <EOL> viewport = self . _vp_stack [ - <NUM_LIT:1> ] <EOL> self . transforms . configure ( viewport = viewport , fbo_size = fb_size , <EOL> fbo_rect = fb_rect ) </s>
