void PropertiesManager::GenerateProperties( PropertiesThreadArgs& args ) { M_ElementByType currentElements; M_ElementsByType commonElements; M_InterpretersByType commonElementInterpreters; EnumerateElementArgs enumerateElementArgs( currentElements, commonElements, commonElementInterpreters ); OS_SceneNodeDumbPtr selection; for ( OrderedSet<SceneNodePtr>::Iterator itr = args.m_Selection.Begin(), end = args.m_Selection.End(); itr != end; ++itr ) { selection.Append( *itr ); } // // First Pass: // Iterates over selection, asking each to enumerate their attributes into temp members (current) // Then coallate those results into an intersection member (common) // HELIUM_ASSERT( !selection.Empty() ); // intersection support M_PanelCreators intersectingPanels = s_PanelCreators; // union support typedef std::map< tstring, OS_SceneNodeDumbPtr > M_UnionedSelections; M_UnionedSelections unionedSelections; M_PanelCreators unionedPanels; { SCENE_GRAPH_SCOPE_TIMER( ("Selection Processing") ); OS_SceneNodeDumbPtr::Iterator itr = selection.Begin(); OS_SceneNodeDumbPtr::Iterator end = selection.End(); for ( size_t index = 0; itr != end; ++itr, ++index ) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } currentElements.clear(); { SCENE_GRAPH_SCOPE_TIMER( ("Object Property Enumeration") ); (*itr)->ConnectProperties(enumerateElementArgs); } M_PanelCreators currentPanels; #ifdef SCENE_DEBUG_PROPERTIES_GENERATOR Log::Print("Object type %s:\n", (*itr)->GetClass()->m_Name.c_str() ); #endif { SCENE_GRAPH_SCOPE_TIMER( ("Object Panel Validation") ); M_PanelCreators::const_iterator itrPanel = args.m_Style == PropertiesStyles::Intersection ? intersectingPanels.begin() : s_PanelCreators.begin(); M_PanelCreators::const_iterator endPanel = args.m_Style == PropertiesStyles::Intersection ? intersectingPanels.end() : s_PanelCreators.end(); for ( ; itrPanel != endPanel; ++itrPanel) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } if ((*itr)->ValidatePanel(itrPanel->first)) { #ifdef SCENE_DEBUG_PROPERTIES_GENERATOR Log::Print(" accepts %s\n", itrPanel->first.c_str()); #endif switch (m_Style) { case PropertiesStyles::Intersection: { currentPanels.insert( *itrPanel ); break; } case PropertiesStyles::Union: { unionedPanels.insert( *itrPanel ); Helium::StdInsert<M_UnionedSelections>::Result inserted = unionedSelections.insert( M_UnionedSelections::value_type ( itrPanel->first, OS_SceneNodeDumbPtr () ) ); inserted.first->second.Append( *itr ); } } } else { #ifdef SCENE_DEBUG_PROPERTIES_GENERATOR Log::Print(" rejects %s\n", itrPanel->first.c_str()); #endif } } } #ifdef SCENE_DEBUG_PROPERTIES_GENERATOR Log::Print("\n"); #endif if ( m_Style == PropertiesStyles::Intersection ) { intersectingPanels = currentPanels; } if (currentElements.empty()) { commonElements.clear(); } else { SCENE_GRAPH_SCOPE_TIMER( ("Object Unique Reflect Property Culling") ); M_ElementsByType newCommonElements; if (index == 0) { M_ElementByType::const_iterator currentItr = currentElements.begin(); M_ElementByType::const_iterator currentEnd = currentElements.end(); for ( ; currentItr != currentEnd; ++currentItr ) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } // copy the shared list into the new shared map Helium::StdInsert<M_ElementsByType>::Result inserted = newCommonElements.insert(M_ElementsByType::value_type( currentItr->first, std::vector<Reflect::Object*> () )); // add this current element's instance to the new shared list inserted.first->second.push_back(currentItr->second); } } else { M_ElementsByType::const_iterator sharedItr = commonElements.begin(); M_ElementsByType::const_iterator sharedEnd = commonElements.end(); for ( ; sharedItr != sharedEnd; ++sharedItr ) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } M_ElementByType::const_iterator found = currentElements.find(sharedItr->first); // if we found a current element entry for this shared element if (found != currentElements.end()) { // copy the shared list into the new shared map Helium::StdInsert<M_ElementsByType>::Result inserted = newCommonElements.insert(M_ElementsByType::value_type( sharedItr->first, sharedItr->second )); // add this current element's instance to the new shared list inserted.first->second.push_back(found->second); } else { // there is NO instance of this element in the current instance, let it be culled from the shared list } } } commonElements = newCommonElements; } // we have eliminated all the shared types, abort if (intersectingPanels.empty() && commonElements.empty() ) { break; } } } // // Second Pass: // Create client-constructed attribute panels // Inspect::ContainerPtr container = new Inspect::Container (); { SCENE_GRAPH_SCOPE_TIMER( ("Static Panel Creation") ); M_PanelCreators::const_iterator itr = args.m_Style == PropertiesStyles::Intersection ? intersectingPanels.begin() : unionedPanels.begin(); M_PanelCreators::const_iterator end = args.m_Style == PropertiesStyles::Intersection ? intersectingPanels.end() : unionedPanels.end(); for ( ; itr != end; ++itr ) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } switch ( args.m_Style ) { case PropertiesStyles::Intersection: { m_Generator->Push( container ); itr->second.Invoke( CreatePanelArgs (m_Generator, selection) ); m_Generator->Pop( false ); break; } case PropertiesStyles::Union: { M_UnionedSelections::const_iterator found = unionedSelections.find( itr->first ); if (found != unionedSelections.end()) { // this connects the invocation with the validated selection m_Generator->Push( container ); itr->second.Invoke( CreatePanelArgs (m_Generator, found->second) ); m_Generator->Pop( false ); } else { // something is horribly horribly wrong HELIUM_BREAK(); } break; } } // if you hit then, then your custom panel creator needs work HELIUM_ASSERT(m_Generator->GetContainerStack().empty()); } } // // Third Pass: // Iterates over resultant map and causes interpretation to occur for each object in the list // { SCENE_GRAPH_SCOPE_TIMER( ("Reflect Interpret") ); M_ElementsByType::const_iterator itr = commonElements.begin(); M_ElementsByType::const_iterator end = commonElements.end(); for ( ; itr != end; ++itr ) { if ( *args.m_CurrentSelectionId != args.m_SelectionId ) { return; } Inspect::ReflectInterpreterPtr interpreter = m_Generator->CreateInterpreter<Inspect::ReflectInterpreter>( container ); interpreter->Interpret(itr->second, itr->first.m_IncludeFlags, itr->first.m_ExcludeFlags); Helium::StdInsert<M_InterpretersByType>::Result inserted = commonElementInterpreters.insert( M_InterpretersByType::value_type(itr->first, interpreter) ); } } class Presenter { public: Presenter( PropertiesManager* propertiesManager, uint32_t selectionId, const Inspect::V_Control& controls ) : m_PropertiesManager( propertiesManager ) , m_SelectionId( selectionId ) , m_Controls( controls ) { } void Finalize( Helium::Void ) { m_PropertiesManager->Present( m_SelectionId, m_Controls ); delete this; } private: PropertiesManager* m_PropertiesManager; uint32_t m_SelectionId; Inspect::V_Control m_Controls; }; // release ownership of the controls now we have passed them onto the main thread for // realization and presentation to the user, this will try and unrealize the controls // from a background thread, but that is okay since they haven't been realized yet :) Presenter* presenter = new Presenter ( this, args.m_SelectionId, container->ReleaseChildren() ); // will cause the main thread to realize and present the controls m_CommandQueue->Post( VoidSignature::Delegate( presenter, &Presenter::Finalize ) ); }
int SettingsDialog::ShowModal( SettingsManager* settingsManager ) { m_SettingSizer = new wxBoxSizer( wxVERTICAL ); m_CurrentSetting = NULL; m_SettingInfo.clear(); M_Settings settings = settingsManager->GetSettingsMap(); wxListBox* propertiesListBox = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxSize( 130 /* 207 */, -1 ) ); propertiesListBox->Connect( propertiesListBox->GetId(), wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( SettingsDialog::OnSettingsChanged ), NULL, this ); wxSizer* propertiesSizer = new wxBoxSizer( wxHORIZONTAL ); propertiesSizer->Add( propertiesListBox, 0, wxEXPAND | wxALL, 6 ); propertiesSizer->Add( 6, 0, 0 ); propertiesSizer->Add( m_SettingSizer, 1, wxEXPAND | wxALL, 6 ); propertiesSizer->Add( 6, 0, 0 ); Inspect::V_Control canvasControls; for ( M_Settings::iterator itr = settings.begin(), end = settings.end(); itr != end; ++itr ) { Settings* settings = Reflect::SafeCast< Settings >( (*itr).second ); // skip settings that we don't want the user to see if ( settings && !settings->UserVisible() ) { continue; } Reflect::ObjectPtr clone = (*itr).second->Clone(); clone->e_Changed.Add( Reflect::ObjectChangeSignature::Delegate( this, &SettingsDialog::OnRefreshElements ) ); Helium::TreeWndCtrl* treeWndCtrl = new Helium::TreeWndCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle | wxALWAYS_SHOW_SB | wxCLIP_CHILDREN | wxNO_BORDER, wxPanelNameStr, wxTR_HIDE_ROOT ); Editor::TreeCanvasPtr canvas = new Editor::TreeCanvas(); canvas->SetTreeWndCtrl( treeWndCtrl ); canvasControls.push_back( canvas ); m_SettingSizer->Add( treeWndCtrl, 1, wxEXPAND, 0 ); m_SettingSizer->Show( treeWndCtrl, false ); Inspect::ReflectInterpreterPtr interpreter = new Inspect::ReflectInterpreter( canvas ); std::vector< Reflect::Object* > elems; elems.push_back( clone ); interpreter->Interpret( elems ); m_Interpreters.push_back( interpreter ); tstring uiName; (*itr).second->GetClass()->GetProperty( TXT( "UIName" ), uiName ); if ( uiName.empty() ) { uiName = *(*itr).second->GetClass()->m_Name; } int index = propertiesListBox->Append( uiName.c_str() ); Reflect::ObjectPtr source = Reflect::AssertCast< Reflect::Object >( (*itr).second ); m_SettingInfo.insert( std::make_pair( index, new SettingInfo( source, clone, canvas ) ) ); } wxButton* restoreDefaults = new wxButton( this, wxID_ANY, wxT( "Restore Defaults" ), wxDefaultPosition, wxDefaultSize, 0 ); restoreDefaults->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SettingsDialog::OnRestoreDefaults ), NULL, this ); wxBoxSizer* propertiesButtonSizer = new wxBoxSizer( wxHORIZONTAL ); propertiesButtonSizer->Add( restoreDefaults, 0, 0, 0 ); m_SettingSizer->Add( 0, 6, 0 ); m_SettingSizer->Add( propertiesButtonSizer, 0, wxALIGN_RIGHT, 0 ); m_SettingSizer->Add( new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ), 0, wxEXPAND | wxTOP, 5 ); wxButton* okButton = new wxButton( this, wxID_ANY, wxT( "OK" ), wxDefaultPosition, wxDefaultSize, 0 ); okButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SettingsDialog::OnOk ), NULL, this ); wxButton* cancelButton = new wxButton( this, wxID_ANY, wxT( "Cancel" ), wxDefaultPosition, wxDefaultSize, 0 ); cancelButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SettingsDialog::OnCancel ), NULL, this ); wxBoxSizer* buttonSizer = new wxBoxSizer( wxHORIZONTAL ); buttonSizer->Add( okButton, 0, wxALL, 5 ); buttonSizer->Add( cancelButton, 0, wxUP | wxDOWN | wxRIGHT, 5 ); buttonSizer->Add( 7, 0, 0 ); wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL ); mainSizer->Add( 0, 1, 0 ); mainSizer->Add( propertiesSizer, 1, wxEXPAND, 0 ); mainSizer->Add( buttonSizer, 0, wxALIGN_RIGHT, 0 ); mainSizer->Add( 0, 8, 0 ); if ( propertiesListBox->GetCount() && ( m_SettingInfo.find( 0 ) != m_SettingInfo.end() ) ) { propertiesListBox->SetSelection( 0 ); SelectCanvas( m_SettingInfo[ 0 ] ); } SetSizer( mainSizer ); Layout(); Centre(); int result = wxDialog::ShowModal(); if ( result == wxID_OK ) { for ( M_SettingInfo::iterator itr = m_SettingInfo.begin(), end = m_SettingInfo.end(); itr != end; ++itr ) { SettingInfo* info = itr->second; if ( !info->m_Clone->Equals( info->m_Source ) ) { info->m_Clone->CopyTo( info->m_Source ); info->m_Source->RaiseChanged(); } } } for ( M_SettingInfo::iterator itr = m_SettingInfo.begin(), end = m_SettingInfo.end(); itr != end; ++itr ) { itr->second->m_Clone->e_Changed.Remove( Reflect::ObjectChangeSignature::Delegate( this, &SettingsDialog::OnRefreshElements ) ); } return result; }