PROPERTIES* LIB_TABLE::ParseOptions( const std::string& aOptionsList )
{
    if( aOptionsList.size() )
    {
        const char* cp  = &aOptionsList[0];
        const char* end = cp + aOptionsList.size();

        PROPERTIES  props;
        std::string pair;

        // Parse all name=value pairs
        while( cp < end )
        {
            pair.clear();

            // Skip leading white space.
            while( cp < end && isspace( *cp )  )
                ++cp;

            // Find the end of pair/field
            while( cp < end )
            {
                if( *cp == '\\'  &&  cp + 1 < end  &&  cp[1] == OPT_SEP  )
                {
                    ++cp;           // skip the escape
                    pair += *cp++;  // add the separator
                }
                else if( *cp == OPT_SEP )
                {
                    ++cp;           // skip the separator
                    break;          // process the pair
                }
                else
                    pair += *cp++;
            }

            // stash the pair
            if( pair.size() )
            {
                // first equals sign separates 'name' and 'value'.
                size_t  eqNdx = pair.find( '=' );

                if( eqNdx != pair.npos )
                {
                    std::string name  = pair.substr( 0, eqNdx );
                    std::string value = pair.substr( eqNdx + 1 );
                    props[name] = value;
                }
                else
                    props[pair] = "";       // property is present, but with no value.
            }
        }

        if( props.size() )
            return new PROPERTIES( props );
    }

    return NULL;
}
    void onListBoxItemSelected( wxCommandEvent& event ) override
    {
        // change the help text based on the m_listbox selection:
        if( event.IsSelection() )
        {
            string  option = TO_UTF8( event.GetString() );
            UTF8    help_text;

            if( m_choices.Value( option.c_str(), &help_text ) )
            {
                wxString page = help_text;

                m_html->SetPage( page );
            }
            else
            {
                m_html->SetPage( m_initial_help );
            }
        }
    }
    DIALOG_FP_PLUGIN_OPTIONS( wxTopLevelWindow* aParent,
            const wxString& aNickname, const wxString& aPluginType,
            const wxString& aOptions, wxString* aResult ) :
        DIALOG_FP_PLUGIN_OPTIONS_BASE( aParent ),
        m_callers_options( aOptions ),
        m_result( aResult ),
        m_initial_help( INITIAL_HELP )
    {
        wxString title = wxString::Format(
                _( "Options for Library '%s'" ), GetChars( aNickname ) );

        SetTitle( title );

        // add Cut, Copy, and Paste to wxGrid
        m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );

        m_grid->SetColMinimalWidth( 1, 250 );

        // Fill the grid with existing aOptions
        string options = TO_UTF8( aOptions );

        PROPERTIES* props = FP_LIB_TABLE::ParseOptions( options );

        if( props )
        {
            if( (int) props->size() > m_grid->GetNumberRows() )
                m_grid->AppendRows( props->size() - m_grid->GetNumberRows() );

            int row = 0;
            for( PROPERTIES::const_iterator it = props->begin();  it != props->end();  ++it, ++row )
            {
                m_grid->SetCellValue( row, 0, FROM_UTF8( it->first.c_str() ) );
                m_grid->SetCellValue( row, 1, it->second );
            }

            delete props;
        }

        // Option Choices Panel:

        IO_MGR::PCB_FILE_T  pi_type = IO_MGR::EnumFromStr( aPluginType );
        PLUGIN::RELEASER    pi( IO_MGR::PluginFind( pi_type ) );

        pi->FootprintLibOptions( &m_choices );

        if( m_choices.size() )
        {
            int row = 0;
            for( PROPERTIES::const_iterator it = m_choices.begin();  it != m_choices.end();  ++it, ++row )
            {
                wxString item = FROM_UTF8( it->first.c_str() );

                m_listbox->InsertItems( 1, &item, row );
            }
        }

        m_html->SetPage( m_initial_help );

        if( !col_width_option )
        {
            m_grid->AutoSizeColumns( false );
        }
        else
        {
            m_grid->SetColSize( 0, col_width_option );
            m_grid->SetColSize( 1, col_width_value );
        }

        Fit();

        // initial focus on the grid please.
        m_grid->SetFocus();
    }