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 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 WgPanel::_onMaskPatches( WgPatches& patches, const WgRect& geo, const WgRect& 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( WgRect(geo,clip) ); return; } switch( m_maskOp ) { case WG_MASKOP_RECURSE: { WgRect childGeo; WgPanelHook * p = static_cast<WgPanelHook*>(_firstHookWithGeo( childGeo )); while(p) { if( p->IsVisible() ) p->_widget()->_onMaskPatches( patches, childGeo + geo.Pos(), clip, blendMode ); p = static_cast<WgPanelHook*>(_nextHookWithGeo( childGeo, p )); } break; } case WG_MASKOP_SKIP: break; case WG_MASKOP_MASK: patches.Sub( WgRect(geo,clip) ); break; } }
void WgPackList::_onRender( WgGfxDevice * pDevice, const WgRect& _canvas, const WgRect& _window, const WgRect& _clip ) { WgRect contentRect = _listCanvas() + _canvas.Pos(); if( m_pSkin ) { m_pSkin->Render( pDevice, contentRect, m_state, _clip ); contentRect = m_pSkin->ContentRect( contentRect, m_state ); } int startOfs = m_bHorizontal ? _clip.x-contentRect.x : _clip.y-contentRect.y; if( startOfs < 0 ) startOfs = 0; for( int i = _getEntryAt( startOfs ) ; i < m_hooks.Size() ; i++ ) { WgPackListHook * pHook = m_hooks.Hook(i); WgWidget * pChild = pHook->_widget(); // Get entry geometry, skin and state WgRect entryGeo( contentRect ); if( m_bHorizontal ) { if( pHook->m_ofs >= contentRect.w ) break; entryGeo.x += pHook->m_ofs; entryGeo.w = pHook->m_length; } else { if( pHook->m_ofs >= contentRect.h ) break; entryGeo.y += pHook->m_ofs; entryGeo.h = pHook->m_length; } WgSkin * pEntrySkin = m_pEntrySkin[i&0x1].RawPtr(); WgState state = pChild->State(); // WgRect childGeo( entryGeo ); // Render entry skin, shrink child geo if( pEntrySkin ) { pEntrySkin->Render( pDevice, entryGeo, state, _clip ); // childGeo = pEntrySkin->ContentRect( entryGeo, state ); } // Render child // pChild->_onRender( pDevice, childGeo, childGeo, _clip ); } }
WgWidget * WgPackList::_findWidget( const WgCoord& ofs, WgSearchMode mode ) { WgWidget * pResult = 0; WgRect list = _listArea(); if( list.Contains(ofs) && _listWindow().Contains(ofs) ) { int entry; if( m_bHorizontal ) entry = _getEntryAt(ofs.x-list.x); else entry = _getEntryAt(ofs.y-list.y); if( entry != m_hooks.Size() ) { WgPackListHook * pHook = m_hooks.Hook(entry); WgRect childGeo; _getChildGeo( childGeo, pHook ); if( childGeo.Contains(ofs) ) { if( pHook->_widget()->IsContainer() ) { pResult = static_cast<WgContainer*>(pHook->_widget())->_findWidget( ofs - childGeo.Pos(), mode ); } else if( mode == WG_SEARCH_GEOMETRY || pHook->_widget()->MarkTest( ofs - childGeo.Pos() ) ) { pResult = pHook->_widget(); } } if( !pResult && mode == WG_SEARCH_ACTION_TARGET ) pResult = pHook->_widget(); // Entries are opaque as action targets. } } // Check against ourselves if( !pResult && ( mode == WG_SEARCH_GEOMETRY || MarkTest(ofs)) ) pResult = this; return pResult; }
WgWidget * WgPopupLayer::_findWidget( const WgCoord& ofs, WgSearchMode mode ) { // MenuPanel has its own _findWidget() method since we need special treatment of // searchmode ACTION_TARGET when a menu is open. if( mode == WG_SEARCH_ACTION_TARGET && !m_popupHooks.IsEmpty() ) { // In search mode ACTION_TARGET we limit our target to us, our menu-branches and the menu-opener if a menu is open. WgPopupHook * pHook = m_popupHooks.Last(); WgWidget * pResult = 0; while( pHook && !pResult ) { if( pHook->m_geo.Contains( ofs ) ) { if( pHook->_widget()->IsContainer() ) pResult = static_cast<WgContainer*>(pHook->_widget())->_findWidget( ofs - pHook->m_geo.Pos(), mode ); else if( pHook->_widget()->MarkTest( ofs - pHook->m_geo.Pos() ) ) pResult = pHook->_widget(); } pHook = pHook->_prev(); } if( pResult == 0 ) { // Check the first opener WgPopupHook * pHook = m_popupHooks.First(); if( pHook && pHook->m_pOpener ) { WgWidget * pOpener = pHook->m_pOpener.RawPtr(); WgCoord absPos = ofs + GlobalPos(); WgRect openerGeo = pOpener->GlobalGeo(); if( openerGeo.Contains(absPos) && pOpener->MarkTest( absPos - openerGeo.Pos() ) ) pResult = pOpener; } // Fall back to us. if( pResult == 0 ) pResult = this; } return pResult; } else { // For the rest of the modes we can rely on the default method. return WgContainer::_findWidget( ofs, mode ); } }
WgCoord WgPackListHook::GlobalPos() const { WgRect geo; m_pParent->_getChildGeo(geo,this); return m_pParent->GlobalPos() + geo.Pos(); }