void ReflectInterpreter::InterpretType(const std::vector<Reflect::Element*>& instances, Container* parent, i32 includeFlags, i32 excludeFlags, bool expandPanel)
{
  const Class* typeInfo = instances[0]->GetClass();
  
  // create a panel
  PanelPtr panel = m_Container->GetCanvas()->Create<Panel>(this);

  // parse
  ContainerPtr scriptOutput = m_Container->GetCanvas()->Create<Container>(this);

  tstring typeInfoUI;
  typeInfo->GetProperty( TXT( "UIScript" ), typeInfoUI );
  bool result = Script::Parse(typeInfoUI, this, parent->GetCanvas(), scriptOutput);

  // compute panel label
  tstring labelText;
  if (result)
  {
    V_Control::const_iterator itr = scriptOutput->GetControls().begin();
    V_Control::const_iterator end = scriptOutput->GetControls().end();
    for( ; itr != end; ++itr )
    {
      Label* label = Reflect::ObjectCast<Label>( *itr );
      if (label)
      {
          bool converted = Helium::ConvertString( label->GetText(), labelText );
          HELIUM_ASSERT( converted );
            
        if ( !labelText.empty() )
        {
          break;
        }
      }
    }
  }

  if (labelText.empty())
  {
    std::vector<Reflect::Element*>::const_iterator itr = instances.begin();
    std::vector<Reflect::Element*>::const_iterator end = instances.end();
    for ( ; itr != end; ++itr )
    {
      Reflect::Element* instance = *itr;

      if ( labelText.empty() )
      {
        labelText = instance->GetTitle();
      }
      else
      {
        if ( labelText != instance->GetTitle() )
        {
          labelText.clear();
          break;
        }
      }
    }

    if ( labelText.empty() )
    {
      labelText = typeInfo->m_UIName;
    }
  }

  tstring temp;
  bool converted = Helium::ConvertString( labelText, temp );
  HELIUM_ASSERT( converted );

  panel->SetText( temp );

  M_Panel panelsMap;
  panelsMap.insert( std::make_pair( TXT( "" ), panel) );

  // don't bother including Element's fields
  int offset = Reflect::GetClass<Element>()->m_LastFieldID;

  // for each field in the type
  M_FieldIDToInfo::const_iterator itr = typeInfo->m_FieldIDToInfo.find(offset + 1);
  M_FieldIDToInfo::const_iterator end = typeInfo->m_FieldIDToInfo.end();
  for ( ; itr != end; ++itr )
  {
    const Field* field = itr->second;

    bool noFlags = ( field->m_Flags == 0 && includeFlags == 0xFFFFFFFF );
    bool doInclude = ( field->m_Flags & includeFlags ) != 0;
    bool dontExclude = ( excludeFlags == 0 ) || !(field->m_Flags & excludeFlags );
    bool hidden = (field->m_Flags & Reflect::FieldFlags::Hide) != 0; 

    // if we don't have flags (or we are included, and we aren't excluded) then make UI
    if ( ( noFlags || doInclude ) && ( dontExclude ) )
    {
      //
      // Handle sub panels for grouping content
      // 

      bool groupExpanded = false;
      field->GetProperty( TXT( "UIGroupExpanded" ), groupExpanded );

      tstring fieldUIGroup;
      field->GetProperty( TXT( "UIGroup" ), fieldUIGroup );
      if ( !fieldUIGroup.empty() )
      {
        M_Panel::iterator itr = panelsMap.find( fieldUIGroup );
        if ( itr == panelsMap.end() )
        {
          // This panel isn't in our list so make a new one
          PanelPtr newPanel = m_Container->GetCanvas()->Create<Panel>(this);
          panelsMap.insert( std::make_pair(fieldUIGroup, newPanel) );

          PanelPtr parent;
          tstring groupName;
          size_t idx = fieldUIGroup.find_last_of( TXT( "/" ) );
          if ( idx != tstring::npos )
          {
            tstring parentName = fieldUIGroup.substr( 0, idx );
            groupName = fieldUIGroup.substr( idx+1 );
            if ( panelsMap.find( parentName ) == panelsMap.end() )
            {          
              parent = m_Container->GetCanvas()->Create<Panel>(this);

              // create the parent hierarchy since it hasn't already been made
              tstring currentParent = parentName;
              for (;;)
              {
                idx = currentParent.find_last_of( TXT( "/" ) );
                if ( idx == tstring::npos )
                {
                  // no more parents so we add it to the root
                  panelsMap.insert( std::make_pair(currentParent, parent) );
                  parent->SetText( currentParent );
                  panelsMap[ TXT( "" ) ]->AddControl( parent );
                  break;
                }
                else
                {
                  parent->SetText( currentParent.substr( idx+1 ) );
                  
                  if ( panelsMap.find( currentParent ) != panelsMap.end() )
                  {
                    break;
                  }
                  else
                  {
                    PanelPtr grandParent = m_Container->GetCanvas()->Create<Panel>(this);
                    grandParent->AddControl( parent );
                    panelsMap.insert( std::make_pair(currentParent, parent) );
                    
                    parent = grandParent;
                  }
                  currentParent = currentParent.substr( 0, idx );
                }
              }
              panelsMap.insert( std::make_pair(parentName, parent) );
            }
            parent = panelsMap[parentName];
          }
          else
          {
            parent = panelsMap[ TXT( "" )];
            groupName = fieldUIGroup;
          }
          newPanel->SetText( groupName );
          if( groupExpanded )
          {
            newPanel->SetExpanded( true );
          }
          parent->AddControl( newPanel );
        }
        
        panel = panelsMap[fieldUIGroup];
      }
      else
      {
        panel = panelsMap[ TXT( "" )];
      }


      //
      // Pointer support
      //

      if (field->m_SerializerID == Reflect::GetType<Reflect::PointerSerializer>())
      {
        if (hidden)
        {
          continue; 
        }        

        std::vector<Reflect::Element*> fieldInstances;

        std::vector<Reflect::Element*>::const_iterator elementItr = instances.begin();
        std::vector<Reflect::Element*>::const_iterator elementEnd = instances.end();
        for ( ; elementItr != elementEnd; ++elementItr )
        {
          uintptr fieldAddress = (uintptr)(*elementItr) + itr->second->m_Offset;

          Element* element = *((ElementPtr*)(fieldAddress));

          if ( element )
          {
            fieldInstances.push_back( element );
          }
        }

        if ( !fieldInstances.empty() && fieldInstances.size() == instances.size() )
        {
          InterpretType(fieldInstances, panel);
        }

        continue;
      }


      //
      // Attempt to find a handler via the factory
      //

      ReflectFieldInterpreterPtr fieldInterpreter;

      for ( const Reflect::Class* type = Registry::GetInstance()->GetClass( field->m_SerializerID );
            type != Reflect::GetClass<Reflect::Element>() && !fieldInterpreter;
            type = Reflect::Registry::GetInstance()->GetClass( type->m_Base ) )
      {
        fieldInterpreter = ReflectFieldInterpreterFactory::Create( type->m_TypeID, field->m_Flags, m_Container );
      }

      if ( fieldInterpreter.ReferencesObject() )
      {
        Interpreter::ConnectInterpreterEvents( this, fieldInterpreter );
        fieldInterpreter->InterpretField( field, instances, panel );
        m_Interpreters.push_back( fieldInterpreter );
        continue;
      }


      //
      // ElementArray support
      //

#pragma TODO("Move this out to an interpreter")
      if (field->m_SerializerID == Reflect::GetType<ElementArraySerializer>())
      {
        if (hidden)
        {
          continue;
        }

        if ( instances.size() == 1 )
        {
          uintptr fieldAddress = (uintptr)(instances.front()) + itr->second->m_Offset;

          V_Element* elements = (V_Element*)fieldAddress;

          if ( elements->size() > 0 )
          {
            PanelPtr childPanel = panel->GetCanvas()->Create<Panel>( this );

               tstring temp;
              bool converted = Helium::ConvertString( field->m_UIName, temp );
              HELIUM_ASSERT( converted );

              childPanel->SetText( temp );

            V_Element::const_iterator elementItr = elements->begin();
            V_Element::const_iterator elementEnd = elements->end();
            for ( ; elementItr != elementEnd; ++elementItr )
            {
              std::vector<Reflect::Element*> childInstances;
              childInstances.push_back(*elementItr);
              InterpretType(childInstances, childPanel);
            }

            panel->AddControl( childPanel );
          }
        }

        continue;
      }


      //
      // Lastly fall back to the value interpreter
      //

      const Reflect::Class* type = Registry::GetInstance()->GetClass( field->m_SerializerID );
      if ( !type->HasType( Reflect::GetType<Reflect::ContainerSerializer>() ) )
      {
        fieldInterpreter = CreateInterpreter< ReflectValueInterpreter >( m_Container );
        fieldInterpreter->InterpretField( field, instances, panel );
        m_Interpreters.push_back( fieldInterpreter );
        continue;
      }
    }
  }

  // Make sure we have the base panel
  panel = panelsMap[TXT( "" )];

  if (parent == m_Container)
  {
    panel->SetExpanded(expandPanel);
  }

  if ( !panel->GetControls().empty() )
  {
    parent->AddControl(panel);
  }
}
Exemple #2
0
void ReflectInterpreter::InterpretType(const std::vector<Reflect::Object*>& instances, Container* parent, int32_t includeFlags, int32_t excludeFlags, bool expandPanel)
{
    const Composite* composite = instances[0]->GetClass();

    // create a container
    ContainerPtr container = CreateControl<Container>();

    // parse
    ContainerPtr scriptOutput = CreateControl<Container>();

    tstring typeInfoUI;
    composite->GetProperty( TXT( "UIScript" ), typeInfoUI );
    bool result = Script::Parse(typeInfoUI, this, parent->GetCanvas(), scriptOutput);

    // compute container label
    tstring labelText;
    if (result)
    {
        V_Control::const_iterator itr = scriptOutput->GetChildren().begin();
        V_Control::const_iterator end = scriptOutput->GetChildren().end();
        for( ; itr != end; ++itr )
        {
            Label* label = Reflect::SafeCast<Label>( *itr );
            if (label)
            {
                label->ReadStringData( labelText );

                if ( !labelText.empty() )
                {
                    break;
                }
            }
        }
    }

    if (labelText.empty())
    {
        composite->GetProperty( TXT( "UIName" ), labelText );
    }

    if ( labelText.empty() )
    {
        labelText = *composite->m_Name;
    }

    container->a_Name.Set( labelText );

    std::map< tstring, ContainerPtr > containersMap;
    containersMap.insert( std::make_pair( TXT( "" ), container) );

    std::stack< const Composite* > bases;
    for ( const Composite* current = composite; current != NULL; current = current->m_Base )
    {
        bases.push( current );
    }

    while ( !bases.empty() )
    {
        const Composite* current = bases.top();
        bases.pop();

        // for each field in the type
        DynArray< Field >::ConstIterator itr = current->m_Fields.Begin();
        DynArray< Field >::ConstIterator end = current->m_Fields.End();
        for ( ; itr != end; ++itr )
        {
            const Field* field = &*itr;

            bool noFlags = ( field->m_Flags == 0 && includeFlags == 0xFFFFFFFF );
            bool doInclude = ( field->m_Flags & includeFlags ) != 0;
            bool dontExclude = ( excludeFlags == 0 ) || !(field->m_Flags & excludeFlags );
            bool hidden = (field->m_Flags & Reflect::FieldFlags::Hide) != 0; 

            // if we don't have flags (or we are included, and we aren't excluded) then make UI
            if ( ( noFlags || doInclude ) && ( dontExclude ) )
            {
                tstring fieldUIGroup;
                field->GetProperty( TXT( "UIGroup" ), fieldUIGroup );
                if ( !fieldUIGroup.empty() )
                {
                    std::map< tstring, ContainerPtr >::iterator itr = containersMap.find( fieldUIGroup );
                    if ( itr == containersMap.end() )
                    {
                        // This container isn't in our list so make a new one
                        ContainerPtr newContainer = CreateControl<Container>();
                        containersMap.insert( std::make_pair(fieldUIGroup, newContainer) );

                        ContainerPtr parent;
                        tstring groupName;
                        size_t idx = fieldUIGroup.find_last_of( TXT( "/" ) );
                        if ( idx != tstring::npos )
                        {
                            tstring parentName = fieldUIGroup.substr( 0, idx );
                            groupName = fieldUIGroup.substr( idx+1 );
                            if ( containersMap.find( parentName ) == containersMap.end() )
                            {          
                                parent = CreateControl<Container>();

                                // create the parent hierarchy since it hasn't already been made
                                tstring currentParent = parentName;
                                for (;;)
                                {
                                    idx = currentParent.find_last_of( TXT( "/" ) );
                                    if ( idx == tstring::npos )
                                    {
                                        // no more parents so we add it to the root
                                        containersMap.insert( std::make_pair(currentParent, parent) );
                                        parent->a_Name.Set( currentParent );
                                        containersMap[ TXT( "" ) ]->AddChild( parent );
                                        break;
                                    }
                                    else
                                    {
                                        parent->a_Name.Set( currentParent.substr( idx+1 ) );

                                        if ( containersMap.find( currentParent ) != containersMap.end() )
                                        {
                                            break;
                                        }
                                        else
                                        {
                                            ContainerPtr grandParent = CreateControl<Container>();
                                            grandParent->AddChild( parent );
                                            containersMap.insert( std::make_pair(currentParent, parent) );

                                            parent = grandParent;
                                        }
                                        currentParent = currentParent.substr( 0, idx );
                                    }
                                }
                                containersMap.insert( std::make_pair(parentName, parent) );
                            }
                            parent = containersMap[parentName];
                        }
                        else
                        {
                            parent = containersMap[ TXT( "" )];
                            groupName = fieldUIGroup;
                        }
                        newContainer->a_Name.Set( groupName );
                        parent->AddChild( newContainer );
                    }

                    container = containersMap[fieldUIGroup];
                }
                else
                {
                    container = containersMap[ TXT( "" )];
                }


                //
                // Pointer support
                //

                if (field->m_DataClass == Reflect::GetClass<Reflect::PointerData>())
                {
                    if (hidden)
                    {
                        continue; 
                    }        

                    std::vector<Reflect::Object*> fieldInstances;

                    std::vector<Reflect::Object*>::const_iterator elementItr = instances.begin();
                    std::vector<Reflect::Object*>::const_iterator elementEnd = instances.end();
                    for ( ; elementItr != elementEnd; ++elementItr )
                    {
                        uintptr_t fieldAddress = (uintptr_t)(*elementItr) + itr->m_Offset;

                        Object* element = *((ObjectPtr*)(fieldAddress));

                        if ( element )
                        {
                            fieldInstances.push_back( element );
                        }
                    }

                    if ( !fieldInstances.empty() && fieldInstances.size() == instances.size() )
                    {
                        InterpretType(fieldInstances, container);
                    }

                    continue;
                }


                //
                // Attempt to find a handler via the factory
                //

                ReflectFieldInterpreterPtr fieldInterpreter;

                for ( const Reflect::Class* type = field->m_DataClass;
                    type != Reflect::GetClass<Reflect::Object>() && !fieldInterpreter;
                    type = Reflect::ReflectionCast< const Class >( type->m_Base ) )
                {
                    fieldInterpreter = ReflectFieldInterpreterFactory::Create( type, field->m_Flags, m_Container );
                }

                if ( fieldInterpreter.ReferencesObject() )
                {
                    Interpreter::ConnectInterpreterEvents( this, fieldInterpreter );
                    fieldInterpreter->InterpretField( field, instances, container );
                    m_Interpreters.push_back( fieldInterpreter );
                    continue;
                }


                //
                // ElementArray support
                //

#pragma TODO("Move this out to an interpreter")
                if (field->m_DataClass == Reflect::GetClass<ObjectStlVectorData>())
                {
                    if (hidden)
                    {
                        continue;
                    }

                    if ( instances.size() == 1 )
                    {
                        uintptr_t fieldAddress = (uintptr_t)(instances.front()) + itr->m_Offset;

                        std::vector< ObjectPtr >* elements = (std::vector< ObjectPtr >*)fieldAddress;

                        if ( elements->size() > 0 )
                        {
                            ContainerPtr childContainer = CreateControl<Container>();

                            tstring temp;
                            field->GetProperty( TXT( "UIName" ), temp );
                            if ( temp.empty() )
                            {
                                bool converted = Helium::ConvertString( field->m_Name, temp );
                                HELIUM_ASSERT( converted );
                            }

                            childContainer->a_Name.Set( temp );

                            std::vector< ObjectPtr >::const_iterator elementItr = elements->begin();
                            std::vector< ObjectPtr >::const_iterator elementEnd = elements->end();
                            for ( ; elementItr != elementEnd; ++elementItr )
                            {
                                std::vector<Reflect::Object*> childInstances;
                                childInstances.push_back(*elementItr);
                                InterpretType(childInstances, childContainer);
                            }

                            container->AddChild( childContainer );
                        }
                    }

                    continue;
                }


                //
                // Lastly fall back to the value interpreter
                //

                const Reflect::Class* type = field->m_DataClass;
                if ( !type->IsType( Reflect::GetClass<Reflect::ContainerData>() ) )
                {
                    fieldInterpreter = CreateInterpreter< ReflectValueInterpreter >( m_Container );
                    fieldInterpreter->InterpretField( field, instances, container );
                    m_Interpreters.push_back( fieldInterpreter );
                    continue;
                }
            }
        }
    }

    // Make sure we have the base container
    container = containersMap[TXT( "" )];

    if ( !container->GetChildren().empty() )
    {
        parent->AddChild(container);
    }
}