50    wxBoxSizer* mainSizer = 
new wxBoxSizer( wxVERTICAL );
 
   55        wxPGInitResourceModule();
 
   61        wxPGEditor_TextCtrl = 
nullptr;
 
   62        wxPGEditor_Choice = 
nullptr;
 
   63        wxPGEditor_ComboBox = 
nullptr;
 
   64        wxPGEditor_TextCtrlAndButton = 
nullptr;
 
   65        wxPGEditor_CheckBox = 
nullptr;
 
   66        wxPGEditor_ChoiceAndButton = 
nullptr;
 
   67        wxPGEditor_SpinCtrl = 
nullptr;
 
   68        wxPGEditor_DatePickerCtrl = 
nullptr;
 
   71    if( !
Pgm().m_PropertyGridInitialized )
 
   78    m_caption = 
new wxStaticText( 
this, wxID_ANY, 
_( 
"No objects selected" ) );
 
   79    mainSizer->Add( 
m_caption, 0, wxALL | wxEXPAND, 5 );
 
   81    m_grid = 
new wxPropertyGrid( 
this );
 
   82    m_grid->SetUnspecifiedValueAppearance( wxPGCell( wxT( 
"<...>" ) ) );
 
   83    m_grid->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
 
   85#if wxCHECK_VERSION( 3, 3, 0 ) 
   86    m_grid->SetValidationFailureBehavior( wxPGVFBFlags::MarkCell );
 
   88    m_grid->SetValidationFailureBehavior( wxPG_VFB_MARK_CELL );
 
   91#if wxCHECK_VERSION( 3, 3, 0 ) 
   92    m_grid->AddActionTrigger( wxPGKeyboardAction::NextProperty, WXK_RETURN );
 
   93    m_grid->AddActionTrigger( wxPGKeyboardAction::NextProperty, WXK_NUMPAD_ENTER );
 
   94    m_grid->AddActionTrigger( wxPGKeyboardAction::NextProperty, WXK_DOWN );
 
   95    m_grid->AddActionTrigger( wxPGKeyboardAction::PrevProperty, WXK_UP );
 
   96    m_grid->AddActionTrigger( wxPGKeyboardAction::Edit, WXK_SPACE );
 
   98    m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_RETURN );
 
   99    m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_NUMPAD_ENTER );
 
  100    m_grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_DOWN );
 
  101    m_grid->AddActionTrigger( wxPG_ACTION_PREV_PROPERTY, WXK_UP );
 
  102    m_grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_SPACE );
 
  105    m_grid->DedicateKey( WXK_RETURN );
 
  106    m_grid->DedicateKey( WXK_NUMPAD_ENTER );
 
  107    m_grid->DedicateKey( WXK_DOWN );
 
  108    m_grid->DedicateKey( WXK_UP );
 
  109    mainSizer->Add( 
m_grid, 1, wxEXPAND, 5 );
 
  111    m_grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
 
  115    m_grid->SetCaptionTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_CAPTIONTEXT ) );
 
  120    SetSizer( mainSizer );
 
  130    Bind( wxEVT_PG_COL_END_DRAG,
 
  131          [&]( wxPropertyGridEvent& )
 
  137          [&]( wxSizeEvent& aEvent )
 
 
  196                if( 
m_grid->IsEditorFocused() )
 
  197                    m_grid->CommitChangesFromEditor();
 
  203    if( aSelection.
Empty() )
 
  205        m_caption->SetLabel( 
_( 
"No objects selected" ) );
 
  209    else if( aSelection.
Size() == 1 )
 
  215        m_caption->SetLabel( wxString::Format( 
_( 
"%d objects selected" ), aSelection.
Size() ) );
 
  219    std::set<TYPE_ID> types;
 
  224    wxCHECK( !types.empty(),  );  
 
  227    std::map<wxString, PROPERTY_BASE*> commonProps;
 
  228    const std::vector<PROPERTY_BASE*>& allProperties = propMgr.
GetProperties( *types.begin() );
 
  231        commonProps.emplace( property->Name(), property );
 
  233    std::map<wxString, int> displayOrder;
 
  235        displayOrder.emplace( entry.first->Name(), entry.second );
 
  238    std::set<wxString>    groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
 
  241    for( 
auto itType = std::next( types.begin() ); itType != types.end(); ++itType )
 
  247            if( !groups.count( 
group ) )
 
  249                groupDisplayOrder.emplace_back( 
group );
 
  250                groups.insert( 
group );
 
  254        for( 
auto it = commonProps.begin(); it != commonProps.end(); )
 
  257                it = commonProps.erase( it );
 
  269    std::set<wxString> availableProps;
 
  272    for( 
auto& [
name, property] : commonProps )
 
  274        if( property->IsHiddenFromPropertiesManager() )
 
  277        if( isLibraryEditor && property->IsHiddenFromLibraryEditors() )
 
  280        if( isDesignEditor && property->IsHiddenFromDesignEditors() )
 
  288            availableProps.insert( 
name );
 
  291    bool               writeable = 
true;
 
  292    std::set<wxString> existingProps;
 
  294    for( wxPropertyGridIterator it = 
m_grid->GetIterator(); !it.AtEnd(); it.Next() )
 
  296        wxPGProperty* pgProp = it.GetProperty();
 
  297        wxString      
name   = pgProp->GetName();
 
  301        existingProps.insert( 
name );
 
  303        if( !availableProps.count( 
name ) )
 
  311        if( choices.GetCount() > 0 )
 
  312            pgProp->SetChoices( choices );
 
  314        pgProp->SetValue( commonVal );
 
  315        pgProp->Enable( writeable );
 
  318    if( !existingProps.empty() && existingProps == availableProps )
 
  324    std::map<wxPGProperty*, int>                   pgPropOrders;
 
  325    std::map<wxString, std::vector<wxPGProperty*>> pgPropGroups;
 
  327    for( 
const wxString& 
name : availableProps )
 
  339            if( choices.GetCount() )
 
  340                pgProp->SetChoices( choices );
 
  342            pgProp->SetValue( commonVal );
 
  343            pgProp->Enable( writeable );
 
  346            wxASSERT( displayOrder.count( 
name ) );
 
  347            pgPropOrders[pgProp] = displayOrder[
name];
 
  348            pgPropGroups[
property->Group()].emplace_back( pgProp );
 
  352    const wxString unspecifiedGroupCaption = 
_( 
"Basic Properties" );
 
  354    for( 
const wxString& groupName : groupDisplayOrder )
 
  356        if( !pgPropGroups.count( groupName ) )
 
  359        std::vector<wxPGProperty*>& properties = pgPropGroups[groupName];
 
  360        wxString                    groupCaption = wxGetTranslation( groupName );
 
  362        auto groupItem = 
new wxPropertyCategory( groupName.IsEmpty() ? unspecifiedGroupCaption
 
  365        m_grid->Append( groupItem );
 
  367        std::sort( properties.begin(), properties.end(),
 
  368                   [&]( wxPGProperty*& aFirst, wxPGProperty*& aSecond )
 
  370                       return pgPropOrders[aFirst] < pgPropOrders[aSecond];
 
  373        for( wxPGProperty* property : properties )
 
  374            m_grid->Append( property );
 
 
  413                                                   wxVariant& aValue, 
bool& aWritable, wxPGChoices& aChoices )
 
  416    bool              different = 
false;
 
  431        if( property->IsHiddenFromPropertiesManager() )
 
  434        wxPGChoices choices = 
property->
GetChoices( item );
 
  443            wxArrayString labels = choices.GetLabels();
 
  444            wxArrayInt    values = choices.GetValuesForStrings( labels );
 
  446            if( labels != aChoices.GetLabels() || values != aChoices.GetValuesForStrings( labels ) )
 
  459            if( !different && !aValue.IsNull() && value != aValue )
 
  464            else if( !different )
 
 
  492    if( aEvent.GetKeyCode() == WXK_TAB && !aEvent.ShiftDown() )
 
  496        if( wxPGProperty* prop = 
m_grid->GetSelectedProperty() )
 
  497            oldValue = prop->GetValue();
 
  499        m_grid->CommitChangesFromEditor();
 
  502        if( wxPGProperty* prop = 
m_grid->GetSelectedProperty() )
 
  504            if( prop->GetValue() == oldValue )
 
  511    if( aEvent.GetKeyCode() == WXK_SPACE )
 
  513        if( wxPGProperty* prop = 
m_grid->GetSelectedProperty() )
 
  515            if( prop->GetValueType() == wxT( 
"bool" ) )
 
  517                m_grid->SetPropertyValue( prop, !prop->GetValue().GetBool() );
 
  523    if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER
 
  524        || aEvent.GetKeyCode() == WXK_DOWN || aEvent.GetKeyCode() == WXK_UP )
 
  526        m_grid->CommitChangesFromEditor();
 
  530                       m_grid->SelectProperty( 
m_grid->GetSelectedProperty(), 
true );