Widget * Container::_findWidget( const Coord& ofs, SearchMode mode ) { Rect childGeo; Hook * pHook = _lastHookWithGeo( childGeo ); Widget * pResult = 0; while( pHook && !pResult ) { if( pHook->_isVisible() && childGeo.contains( ofs ) ) { if( pHook->_widget()->isContainer() ) { pResult = static_cast<Container*>(pHook->_widget())->_findWidget( ofs - childGeo.pos(), mode ); } else if( mode == SearchMode::Geometry || pHook->_widget()->markTest( ofs - childGeo.pos() ) ) { pResult = pHook->_widget(); } } pHook = _prevHookWithGeo( childGeo, pHook ); } // Check against ourselves if( !pResult && ( mode == SearchMode::Geometry || markTest(ofs)) ) pResult = this; return pResult; }
void Container::_collectPatches( Patches& container, const Rect& geo, const Rect& clip ) { if( m_pSkin ) container.add( Rect( geo, clip ) ); else { Rect childGeo; Hook * p = _firstHookWithGeo( childGeo ); while(p) { if( p->_isVisible() ) p->_widget()->_collectPatches( container, childGeo + geo.pos(), clip ); p = _nextHookWithGeo( childGeo, p ); } } }
void Container::_maskPatches( Patches& patches, const Rect& geo, const Rect& clip, BlendMode blendMode ) { //TODO: Don't just check isOpaque() globally, check rect by rect. if( (m_bOpaque && blendMode == BlendMode::Blend) || blendMode == BlendMode::Replace) patches.sub( Rect(geo,clip) ); else { Rect childGeo; Hook * p = _firstHookWithGeo( childGeo ); while(p) { if( p->_isVisible() ) p->_widget()->_maskPatches( patches, childGeo + geo.pos(), clip, blendMode ); p = _nextHookWithGeo( childGeo, p ); } } }
void Container::_renderPatches( GfxDevice * pDevice, const Rect& _canvas, const Rect& _window, Patches * _pPatches ) { // We start by eliminating dirt outside our geometry Patches patches( _pPatches->size() ); // TODO: Optimize by pre-allocating? for( const Rect * pRect = _pPatches->begin() ; pRect != _pPatches->end() ; pRect++ ) { if( _canvas.intersectsWith( *pRect ) ) patches.push( Rect(*pRect,_canvas) ); } // Render container itself for( const Rect * pRect = patches.begin() ; pRect != patches.end() ; pRect++ ) _render(pDevice, _canvas, _window, *pRect ); // Render children Rect dirtBounds = patches.getUnion(); if( m_bSiblingsOverlap ) { // Create WidgetRenderContext's for siblings that might get dirty patches std::vector<WidgetRenderContext> renderList; Rect childGeo; Hook * p = _firstHookWithGeo( childGeo ); while(p) { Rect geo = childGeo + _canvas.pos(); if( p->_isVisible() && geo.intersectsWith( dirtBounds ) ) renderList.push_back( WidgetRenderContext(p->_widget(), geo ) ); p = _nextHookWithGeo( childGeo, p ); } // Go through WidgetRenderContexts in reverse order (topmost first), push and mask dirt for( int i = renderList.size()-1 ; i >= 0 ; i-- ) { WidgetRenderContext * p = &renderList[i]; p->patches.push( &patches ); p->pWidget->_maskPatches( patches, p->geo, p->geo, pDevice->blendMode() ); //TODO: Need some optimizations here, grandchildren can be called repeatedly! Expensive! if( patches.isEmpty() ) break; } // Go through WidgetRenderContexts and render the patches for( int i = 0 ; i < (int) renderList.size() ; i++ ) { WidgetRenderContext * p = &renderList[i]; p->pWidget->_renderPatches( pDevice, p->geo, p->geo, &p->patches ); } } else { Rect childGeo; Hook * p = _firstHookWithGeo( childGeo ); while(p) { Rect canvas = childGeo + _canvas.pos(); if( p->_isVisible() && canvas.intersectsWith( dirtBounds ) ) p->_widget()->_renderPatches( pDevice, canvas, canvas, &patches ); p = _nextHookWithGeo( childGeo, p ); } } }