void Panel::_onMaskPatches( Patches& patches, const Rect& geo, const Rect& clip, WgBlendMode blendMode ) { //TODO: Don't just check isOpaque() globally, check rect by rect. if( (m_bOpaque && blendMode == WG_BLENDMODE_BLEND) || blendMode == WG_BLENDMODE_OPAQUE ) { patches.sub( Rect(geo,clip) ); return; } switch( m_maskOp ) { case WG_MASKOP_RECURSE: { Rect childGeo; PanelHook * p = static_cast<PanelHook*>(_firstHookWithGeo( childGeo )); while(p) { if( p->isVisible() ) p->_widget()->_onMaskPatches( patches, childGeo + geo.pos(), clip, blendMode ); p = static_cast<PanelHook*>(_nextHookWithGeo( childGeo, p )); } break; } case WG_MASKOP_SKIP: break; case WG_MASKOP_MASK: patches.sub( Rect(geo,clip) ); break; } }
void WgPackList::_onMaskPatches( WgPatches& patches, const WgRect& geo, const WgRect& clip, WgBlendMode blendMode ) { if( (m_bOpaque && blendMode == WG_BLENDMODE_BLEND) || blendMode == WG_BLENDMODE_OPAQUE) patches.Sub( WgRect(geo,clip) ); else if( m_bOpaqueEntries && blendMode == WG_BLENDMODE_BLEND ) { if( m_bHorizontal ) patches.Sub( WgRect( WgRect( geo.x, geo.y, WgMin(geo.w,m_contentLength), geo.h ), clip ) ); else patches.Sub( WgRect( WgRect( geo.x, geo.y, geo.w, WgMin(geo.h,m_contentLength) ), clip ) ); } else { WgRect childGeo; WgPackListHook * p = static_cast<WgPackListHook*>(_firstHookWithGeo( childGeo )); while(p) { if( p->_isVisible() ) p->_widget()->_onMaskPatches( patches, childGeo + geo.Pos(), clip, blendMode ); p = static_cast<WgPackListHook*>(_nextHookWithGeo( childGeo, p )); } } }
void WgPackList::_renderPatches( WgGfxDevice * pDevice, const WgRect& _canvas, const WgRect& _window, WgPatches * _pPatches ) { // We start by eliminating dirt outside our geometry WgPatches patches( _pPatches->Size() ); // TODO: Optimize by pre-allocating? for( const WgRect * pRect = _pPatches->Begin() ; pRect != _pPatches->End() ; pRect++ ) { if( _canvas.IntersectsWith( *pRect ) ) patches.Push( WgRect(*pRect,_canvas) ); } // Render container itself for( const WgRect * pRect = patches.Begin() ; pRect != patches.End() ; pRect++ ) _onRender(pDevice, _canvas, _window, *pRect ); // Render children WgRect dirtBounds = patches.Union(); { WgRect childGeo; WgPackListHook * p = (WgPackListHook*)_firstHookWithGeo( childGeo ); while(p) { WgRect canvas = childGeo + _canvas.Pos(); if( p->_isVisible() && canvas.IntersectsWith( dirtBounds ) ) p->_widget()->_renderPatches( pDevice, canvas, canvas, &patches ); p = (WgPackListHook*) _nextHookWithGeo( childGeo, p ); } } // Render header if( m_header.m_height != 0 ) { bool bInvertedSort = (m_sortOrder == WG_SORT_DESCENDING); WgRect canvas = _headerGeo() + _canvas.Pos(); for( const WgRect * pRect = patches.Begin() ; pRect != patches.End() ; pRect++ ) _renderHeader( pDevice, canvas, *pRect, m_header.m_pSkin, &m_header.label, &m_header.icon, &m_header.arrow, m_header.m_state, true, bInvertedSort ); } // Render Lasso if( m_pLassoSkin && m_lassoBegin != m_lassoEnd ) { WgRect lasso( m_lassoBegin, m_lassoEnd ); lasso += _canvas.Pos(); for( const WgRect * pRect = patches.Begin() ; pRect != patches.End() ; pRect++ ) m_pLassoSkin->Render( pDevice, lasso, m_state, WgRect( lasso, *pRect ) ); } }
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 ); } } }