dialog_edit_libentry_fields_in_lib.cpp 24.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2011-2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
 * Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

26 27 28

#include <algorithm>

29
#include <fctsys.h>
30
#include <pgm_base.h>
31
#include <kiway.h>
32 33 34 35
#include <confirm.h>
#include <class_drawpanel.h>
#include <wxEeschemaStruct.h>
#include <id.h>
36
#include <base_units.h>
37

38 39 40 41 42 43 44
#include <general.h>
#include <libeditframe.h>
#include <class_library.h>
#include <sch_component.h>
#include <sch_field.h>
#include <template_fieldnames.h>
#include <dialog_helpers.h>
45

46
#include <dialog_edit_libentry_fields_in_lib_base.h>
47 48 49 50

// Local variables:
static int s_SelectedRow;

51 52
#define COLUMN_FIELD_NAME   0
#define COLUMN_TEXT         1
53 54 55 56

class DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB : public DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE
{
public:
57
    DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB( LIB_EDIT_FRAME* aParent, LIB_COMPONENT* aLibEntry );
58
    //~DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB() {}
59 60 61 62 63 64 65 66

private:
    // Events handlers:
    void OnInitDialog( wxInitDialogEvent& event );

    void OnListItemDeselected( wxListEvent& event );
    void OnListItemSelected( wxListEvent& event );
    void addFieldButtonHandler( wxCommandEvent& event );
67 68 69 70 71 72 73 74

    /**
     * Function deleteFieldButtonHandler
     * deletes a field.
     * MANDATORY_FIELDS cannot be deleted.
     * If a field is empty, it is removed.
     * if not empty, the text is removed.
     */
75
    void deleteFieldButtonHandler( wxCommandEvent& event );
76

77 78 79
    void moveUpButtonHandler( wxCommandEvent& event );
    void OnCancelButtonClick( wxCommandEvent& event );
    void OnOKButtonClick( wxCommandEvent& event );
80
    void showButtonHandler( wxCommandEvent& event );
81 82 83 84 85 86 87

    // internal functions:
    void setSelectedFieldNdx( int aFieldNdx );

    int  getSelectedFieldNdx();

    /**
88
     * Function initBuffers
89 90
     * sets up to edit the given component.
     */
91
    void initBuffers();
92 93 94 95 96 97 98

    /**
     * Function findField
     * searches m_FieldsBuf and returns a LIB_FIELD with \a aFieldName or NULL if
     * not found.
     */
    LIB_FIELD* findField( const wxString& aFieldName );
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

    /**
     * Function copySelectedFieldToPanel
     * sets the values displayed on the panel according to
     * the currently selected field row
     */
    void copySelectedFieldToPanel();

    /**
     * Function copyPanelToSelectedField
     * copies the values displayed on the panel fields to the currently selected field
     * @return bool - true if all fields are OK, else false if the user has put
     *   bad data into a field, and this value can be used to deny a row change.
     */
    bool copyPanelToSelectedField();
114
    void setRowItem( int aFieldNdx, const LIB_FIELD& aField );
115

116 117
    /**
     * Function updateDisplay
118 119 120 121 122
     * update the listbox showing fields, according to the fields texts
     * must be called after a text change in fields, if this change is not an edition
     */
    void updateDisplay( )
    {
123
        for( unsigned ii = MANDATORY_FIELDS;  ii<m_FieldsBuf.size(); ii++ )
124 125
            setRowItem( ii, m_FieldsBuf[ii] );
    }
126 127 128 129 130 131 132

    LIB_EDIT_FRAME*    m_parent;
    LIB_COMPONENT*     m_libEntry;
    bool               m_skipCopyFromPanel;

    /// a copy of the edited component's LIB_FIELDs
    std::vector <LIB_FIELD> m_FieldsBuf;
133 134
};

135

136
void LIB_EDIT_FRAME::InstallFieldsEditorDialog( wxCommandEvent& event )
137
{
138
    if( m_component == NULL )
139 140
        return;

141
    m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
142

143
    DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB dlg( this, m_component );
144

145
    int abort = dlg.ShowQuasiModal();
146 147 148

    if( abort )
        return;
149

150 151
    UpdateAliasSelectList();
    UpdatePartSelectList();
152
    DisplayLibInfos();
153
    Refresh();
154 155 156 157
}


DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB(
158 159
    LIB_EDIT_FRAME* aParent,
    LIB_COMPONENT*  aLibEntry ) :
160 161
    DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE( aParent )
{
162 163
    m_parent   = aParent;
    m_libEntry = aLibEntry;
jean-pierre charras's avatar
jean-pierre charras committed
164 165 166

    GetSizer()->SetSizeHints( this );
    Centre();
167 168 169 170 171 172 173 174 175 176 177
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnInitDialog( wxInitDialogEvent& event )
{
    m_skipCopyFromPanel = false;
    wxListItem columnLabel;

    columnLabel.SetImage( -1 );

    columnLabel.SetText( _( "Name" ) );
charras's avatar
charras committed
178
    fieldListCtrl->InsertColumn( COLUMN_FIELD_NAME, columnLabel );
179 180

    columnLabel.SetText( _( "Value" ) );
charras's avatar
charras committed
181
    fieldListCtrl->InsertColumn( COLUMN_TEXT, columnLabel );
182

183 184 185
    m_staticTextUnitSize->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
    m_staticTextUnitPosX->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
    m_staticTextUnitPosY->SetLabel( GetAbbreviatedUnitsLabel( g_UserUnit ) );
186

187
    initBuffers();
188 189
    copySelectedFieldToPanel();

190
    stdDialogButtonSizerOK->SetDefault();
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnListItemDeselected( wxListEvent& event )
{
    if( !m_skipCopyFromPanel )
    {
        if( !copyPanelToSelectedField() )
            event.Skip();   // do not go to the next row
    }
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnListItemSelected( wxListEvent& event )
{
    // remember the selected row, statically
    s_SelectedRow = event.GetIndex();

    copySelectedFieldToPanel();
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnCancelButtonClick( wxCommandEvent& event )
{
215
    EndQuasiModal( 1 );
216 217 218 219 220 221 222 223
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnOKButtonClick( wxCommandEvent& event )
{
    if( !copyPanelToSelectedField() )
        return;

224
    // test if reference prefix is acceptable
225
    if( !SCH_COMPONENT::IsReferenceStringValid( m_FieldsBuf[REFERENCE].GetText() ) )
226 227 228 229 230
    {
        DisplayError( NULL, _( "Illegal reference prefix. A reference must start by a letter" ) );
        return;
    }

231 232 233 234 235
    /* Note: this code is now (2010-dec-04) not used, because the value field is no more editable
     * because changing the value is equivalent to create a new component or alias.
     * This is now handled in libedit main frame, and no more in this dialog
     * but this code is not removed, just in case
     */
236 237
    /* If a new name entered in the VALUE field, that it not an existing alias name
     * or root alias of the component */
238
    wxString newvalue = m_FieldsBuf[VALUE].GetText();
239

240
    if( m_libEntry->HasAlias( newvalue ) && !m_libEntry->GetAlias( newvalue )->IsRoot() )
241
    {
242 243 244 245 246 247
        wxString msg = wxString::Format(
            _( "A new name is entered for this component\n"
               "An alias %s already exists!\n"
               "Cannot update this component" ),
            GetChars( newvalue )
            );
248 249
        DisplayError( this, msg );
        return;
250
    }
251
    /* End unused code */
252

253
    // save old cmp in undo list
254
    m_parent->SaveCopyInUndoList( m_libEntry, IS_CHANGED );
255

256 257 258
    // delete any fields with no name or no value before we copy all of m_FieldsBuf
    // back into the component
    for( unsigned i = MANDATORY_FIELDS; i < m_FieldsBuf.size(); )
259
    {
260
        if( m_FieldsBuf[i].GetName().IsEmpty() || m_FieldsBuf[i].GetText().IsEmpty() )
261 262 263 264 265 266 267 268
        {
            m_FieldsBuf.erase( m_FieldsBuf.begin() + i );
            continue;
        }

        ++i;
    }

269
#if defined(DEBUG)
270
    for( unsigned i=0;  i<m_FieldsBuf.size();  ++i )
271 272
    {
        printf( "save[%d].name:'%s' value:'%s'\n", i,
273
                TO_UTF8( m_FieldsBuf[i].GetName() ),
274
                TO_UTF8( m_FieldsBuf[i].GetText() ) );
275 276 277 278
    }
#endif

    // copy all the fields back, fully replacing any previous fields
279
    m_libEntry->SetFields( m_FieldsBuf );
280

281
    // We need to keep the name and the value the same at the moment!
282
    SetName( m_libEntry->GetValueField().GetText() );
283

284
    m_parent->OnModify();
285

286
    EndQuasiModal( 0 );
287 288 289 290 291 292 293 294 295 296
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::addFieldButtonHandler( wxCommandEvent& event )
{
    // in case m_FieldsBuf[REFERENCE].m_Orient has changed on screen only, grab
    // screen contents.
    if( !copyPanelToSelectedField() )
        return;

297
    unsigned fieldNdx = m_FieldsBuf.size();
298

299
    LIB_FIELD blank( fieldNdx );
300 301

    m_FieldsBuf.push_back( blank );
302
    m_FieldsBuf[fieldNdx].SetName( TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldNdx ) );
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

    setRowItem( fieldNdx, m_FieldsBuf[fieldNdx] );

    m_skipCopyFromPanel = true;
    setSelectedFieldNdx( fieldNdx );
    m_skipCopyFromPanel = false;
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::deleteFieldButtonHandler( wxCommandEvent& event )
{
    unsigned fieldNdx = getSelectedFieldNdx();

    if( fieldNdx >= m_FieldsBuf.size() )    // traps the -1 case too
        return;

319
    if( fieldNdx < MANDATORY_FIELDS )
320 321 322 323 324
    {
        wxBell();
        return;
    }

325
    m_skipCopyFromPanel = true;
326

327
    if( m_FieldsBuf[fieldNdx].GetText().IsEmpty() )
charras's avatar
charras committed
328 329 330
    {
        m_FieldsBuf.erase( m_FieldsBuf.begin() + fieldNdx );
        fieldListCtrl->DeleteItem( fieldNdx );
331

charras's avatar
charras committed
332 333 334 335 336
        if( fieldNdx >= m_FieldsBuf.size() )
            --fieldNdx;
    }
    else
    {
337
        m_FieldsBuf[fieldNdx].Empty();
charras's avatar
charras committed
338 339
        copySelectedFieldToPanel();
    }
340

341 342 343
    updateDisplay( );

    setRowItem( fieldNdx, m_FieldsBuf[fieldNdx] );
344 345 346 347 348 349 350 351 352 353 354 355
    setSelectedFieldNdx( fieldNdx );
    m_skipCopyFromPanel = false;
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB:: moveUpButtonHandler( wxCommandEvent& event )
{
    unsigned fieldNdx = getSelectedFieldNdx();

    if( fieldNdx >= m_FieldsBuf.size() )    // traps the -1 case too
        return;

356
    if( fieldNdx < MANDATORY_FIELDS )
357 358 359 360 361 362 363 364 365 366
    {
        wxBell();
        return;
    }

    if( !copyPanelToSelectedField() )
        return;

    // swap the fieldNdx field with the one before it, in both the vector
    // and in the fieldListCtrl
367
    LIB_FIELD tmp = m_FieldsBuf[fieldNdx - 1];
368 369 370 371 372 373 374

    m_FieldsBuf[fieldNdx - 1] = m_FieldsBuf[fieldNdx];
    setRowItem( fieldNdx - 1, m_FieldsBuf[fieldNdx] );

    m_FieldsBuf[fieldNdx] = tmp;
    setRowItem( fieldNdx, tmp );

375 376
    updateDisplay( );

377 378 379 380 381 382
    m_skipCopyFromPanel = true;
    setSelectedFieldNdx( fieldNdx - 1 );
    m_skipCopyFromPanel = false;
}


383 384
void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::showButtonHandler( wxCommandEvent& event )
{
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    unsigned fieldNdx = getSelectedFieldNdx();

    if( fieldNdx == DATASHEET )
    {
        wxString datasheet_uri = fieldValueTextCtrl->GetValue();
        ::wxLaunchDefaultBrowser( datasheet_uri );
    }
    else if( fieldNdx == FOOTPRINT )
    {
        // pick a footprint using the footprint picker.
        wxString fpid;

        KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );

        if( frame->ShowModal( &fpid, this ) )
        {
            // DBG( printf( "%s: %s\n", __func__, TO_UTF8( fpid ) ); )
            fieldValueTextCtrl->SetValue( fpid );
        }

        frame->Destroy();
    }
407 408 409
}


410 411
void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::setSelectedFieldNdx( int aFieldNdx )
{
412 413 414
    // deselect old selection, but I think this is done by single selection
    // flag within fieldListCtrl
    // fieldListCtrl->SetItemState( s_SelectedRow, 0, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434

    if( aFieldNdx >= (int) m_FieldsBuf.size() )
        aFieldNdx = m_FieldsBuf.size() - 1;

    if( aFieldNdx < 0 )
        aFieldNdx = 0;

    fieldListCtrl->SetItemState( aFieldNdx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
    fieldListCtrl->EnsureVisible( aFieldNdx );

    s_SelectedRow = aFieldNdx;
}


int DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::getSelectedFieldNdx()
{
    return s_SelectedRow;
}


435 436 437 438
/**
 * Function findfield
 * searches a LIB_FIELD_LIST for aFieldName.
 */
439
static LIB_FIELD* findfield( const LIB_FIELDS& aList, const wxString& aFieldName )
440
{
441 442 443 444
    const LIB_FIELD*  field = NULL;

    for( unsigned i=0;  i<aList.size();  ++i )
    {
445
        if( aFieldName == aList[i].GetName() )
446 447 448 449 450 451
        {
            field = &aList[i];  // best to avoid casting here.
            break;
        }
    }
    return (LIB_FIELD*) field;  // remove const-ness last
452 453
}

454 455 456 457 458

LIB_FIELD* DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::findField( const wxString& aFieldName )
{
    for( unsigned i=0;  i<m_FieldsBuf.size();  ++i )
    {
459
        if( aFieldName == m_FieldsBuf[i].GetName() )
460 461 462 463 464 465
            return &m_FieldsBuf[i];
    }
    return NULL;
}


466
void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::initBuffers()
467
{
468
    LIB_FIELDS cmpFields;
469

470
    m_libEntry->GetFields( cmpFields );
471

472 473 474
#if defined(DEBUG)
    for( unsigned i=0; i<cmpFields.size();  ++i )
    {
475
        printf( "cmpFields[%d].name:%s\n", i, TO_UTF8( cmpFields[i].GetName() ) );
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    }
#endif

    /*  We have 3 component related field lists to be aware of: 1) UI
        presentation (m_FieldsBuf), 2) fields in component ram copy, and 3)
        fields recorded with component on disk. m_FieldsBuf is the list of UI
        fields, and this list is not the same as the list which is in the
        component, which is also not the same as the list on disk. All 3 lists
        are potentially different. In the UI we choose to preserve the order of
        the first MANDATORY_FIELDS which are sometimes called fixed fields. Then
        we append the template fieldnames in the exact same order as the
        template fieldname editor shows them. Then we append any user defined
        fieldnames which came from the component, and user can modify it during
        editing, but cannot delete or move a fixed field.
    */
491

492
    m_FieldsBuf.clear();
493

494 495 496 497 498
    /*  When this code was written, all field constructors ensured that the
        MANDATORY_FIELDS are all present within a component (in ram only). So we can
        knowingly copy them over in the normal order. Copy only the fixed fields
        at first. Please do not break the field constructors.
    */
499

500 501
    // fixed fields:
    for( int i=0; i<MANDATORY_FIELDS; ++i )
502
    {
503
        DBG( printf( "add fixed:%s\n", TO_UTF8( cmpFields[i].GetName() ) ); )
504
        m_FieldsBuf.push_back( cmpFields[i] );
505 506
    }

507 508 509
    // Add template fieldnames:
    // Now copy in the template fields, in the order that they are present in the
    // template field editor UI.
510 511 512
    SCH_EDIT_FRAME* editor = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, true );

    const TEMPLATE_FIELDNAMES& tfnames = editor->GetTemplateFieldNames();
513 514 515 516 517 518

    for( TEMPLATE_FIELDNAMES::const_iterator it = tfnames.begin();  it!=tfnames.end();  ++it )
    {
        // add a new field unconditionally to the UI only for this template fieldname

        // field id must not be in range 0 - MANDATORY_FIELDS, set before saving to disk
519
        LIB_FIELD fld( m_libEntry, -1 );
520 521 522

        // See if field by same name already exists in component.
        LIB_FIELD* libField = findfield( cmpFields, it->m_Name );
523

524 525 526 527 528
        // If the field does not already exist in the component, then we
        // use defaults from the template fieldname, otherwise the original
        // values from the component will be set.
        if( !libField )
        {
529
            DBG( printf( "add template:%s\n", TO_UTF8( it->m_Name ) ); )
530

Dick Hollenbeck's avatar
Dick Hollenbeck committed
531
            fld.SetName( it->m_Name );
532
            fld.SetText( it->m_Value );   // empty? ok too.
533 534

            if( !it->m_Visible )
535
                fld.SetVisible( false );
536
            else
537
                fld.SetVisible( true );;
538 539 540
        }
        else
        {
541
            DBG( printf( "match template:%s\n", TO_UTF8( libField->GetName() ) ); )
542 543 544 545 546
            fld = *libField;    // copy values from component, m_Name too
        }

        m_FieldsBuf.push_back( fld );
    }
547

548 549 550
    // Lastly, append any original fields from the component which were not added
    // from the set of fixed fields nor from the set of template fields.
    for( unsigned i=MANDATORY_FIELDS;  i<cmpFields.size();  ++i )
551
    {
552
        LIB_FIELD*  cmp = &cmpFields[i];
553
        LIB_FIELD*  buf = findField( cmp->GetName() );
554 555 556

        if( !buf )
        {
557
            DBG( printf( "add cmp:%s\n", TO_UTF8( cmp->GetName() ) ); )
558 559
            m_FieldsBuf.push_back( *cmp );
        }
560 561
    }

562 563 564 565 566
    /*  field names have become more important than field ids, so we cannot
        mangle the names in the buffer, but can do so in the panel, see elsewhere.
    m_FieldsBuf[VALUE].m_Name << wxT( "/" ) << _( "Chip Name" );
    */

567 568 569 570 571 572 573 574 575
    for( unsigned ii = 0; ii < m_FieldsBuf.size();  ++ii )
    {
        setRowItem( ii, m_FieldsBuf[ii] );
    }

    // put focus on the list ctrl
    fieldListCtrl->SetFocus();

    // resume editing at the last row edited, last time dialog was up.
576 577
    if ( s_SelectedRow < (int) m_FieldsBuf.size() )
        s_SelectedRow = 0;
578

579 580 581 582
    setSelectedFieldNdx( s_SelectedRow );
}


583
void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::setRowItem( int aFieldNdx, const LIB_FIELD& aField )
584 585 586 587 588 589 590 591 592 593
{
    wxASSERT( aFieldNdx >= 0 );

    // insert blanks if aFieldNdx is referencing a "yet to be defined" row
    while( aFieldNdx >= fieldListCtrl->GetItemCount() )
    {
        long ndx = fieldListCtrl->InsertItem( fieldListCtrl->GetItemCount(), wxEmptyString );

        wxASSERT( ndx >= 0 );

charras's avatar
charras committed
594
        fieldListCtrl->SetItem( ndx, COLUMN_TEXT, wxEmptyString );
595 596
    }

597
    fieldListCtrl->SetItem( aFieldNdx, COLUMN_FIELD_NAME, aField.GetName() );
598
    fieldListCtrl->SetItem( aFieldNdx, COLUMN_TEXT, aField.GetText() );
599 600

    // recompute the column widths here, after setting texts
charras's avatar
charras committed
601 602
    fieldListCtrl->SetColumnWidth( COLUMN_FIELD_NAME, wxLIST_AUTOSIZE );
    fieldListCtrl->SetColumnWidth( COLUMN_TEXT, wxLIST_AUTOSIZE );
603 604 605 606 607 608 609 610 611 612
}


void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copySelectedFieldToPanel()
{
    unsigned fieldNdx = getSelectedFieldNdx();

    if( fieldNdx >= m_FieldsBuf.size() )    // traps the -1 case too
        return;

613
    LIB_FIELD& field = m_FieldsBuf[fieldNdx];
614

615
    showCheckBox->SetValue( field.IsVisible() );
616

617
    rotateCheckBox->SetValue( field.GetOrientation() == TEXT_ORIENT_VERT );
618 619

    int style = 0;
620 621

    if( field.IsItalic() )
622
        style = 1;
623

624
    if( field.IsBold() )
625
        style |= 2;
626

627 628
    m_StyleRadioBox->SetSelection( style );

629
    // Select the right text justification
630
    if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
631
        m_FieldHJustifyCtrl->SetSelection(0);
632
    else if( field.GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
633 634 635 636
        m_FieldHJustifyCtrl->SetSelection(2);
    else
        m_FieldHJustifyCtrl->SetSelection(1);

637
    if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
638
        m_FieldVJustifyCtrl->SetSelection(0);
639
    else if( field.GetVertJustify() == GR_TEXT_VJUSTIFY_TOP )
640 641 642 643
        m_FieldVJustifyCtrl->SetSelection(2);
    else
        m_FieldVJustifyCtrl->SetSelection(1);

644 645 646

    // Field names have become more important than field ids, so we cannot
    // mangle the names in the buffer but we can do so in the panel.
647 648 649 650 651 652 653
    if( field.GetId() == VALUE )
    {
        // This field is the lib name and the default value when loading this component in
        // schematic.  The value is now not editable here (in this dialog) because changing
        // it is equivalent to create a new component or alias. This is handles in libedir,
        // not in this dialog.
        fieldNameTextCtrl->SetValue( field.GetName() + wxT( " / " ) + _( "Chip Name" ) );
654 655
        fieldValueTextCtrl->Enable( false );
    }
656
    else
657 658
    {
        fieldValueTextCtrl->Enable( true );
659
        fieldNameTextCtrl->SetValue( field.GetName() );
660
    }
661

662
    // if fieldNdx == REFERENCE, VALUE, FOOTPRINT, or DATASHEET, then disable field name editing
663 664 665 666 667
    fieldNameTextCtrl->Enable(  fieldNdx >= MANDATORY_FIELDS );
    fieldNameTextCtrl->SetEditable( fieldNdx >= MANDATORY_FIELDS );

    // only user defined fields may be moved, and not the top most user defined
    // field since it would be moving up into the fixed fields, > not >=
668
    moveUpButton->Enable( fieldNdx >= MANDATORY_FIELDS );
669

charras's avatar
charras committed
670
    // if fieldNdx == REFERENCE, VALUE, then disable delete button
671
    deleteFieldButton->Enable( fieldNdx >= MANDATORY_FIELDS );
672

673
    fieldValueTextCtrl->SetValue( field.GetText() );
674

675
    textSizeTextCtrl->SetValue( EDA_GRAPHIC_TEXT_CTRL::FormatSize( g_UserUnit, field.GetSize().x ) );
676

677 678 679 680 681 682 683 684
    m_show_datasheet_button->Enable( fieldNdx == DATASHEET || fieldNdx == FOOTPRINT );

    if( fieldNdx == DATASHEET )
        m_show_datasheet_button->SetLabel( _( "Show in Browser" ) );
    else if( fieldNdx == FOOTPRINT )
        m_show_datasheet_button->SetLabel( _( "Assign Footprint" ) );
    else
        m_show_datasheet_button->SetLabel( wxEmptyString );
685

686
    wxPoint coord = field.GetTextPosition();
687 688 689 690 691 692
    wxPoint zero;

    // If the field value is empty and the position is at relative zero, we set the
    // initial position as a small offset from the ref field, and orient
    // it the same as the ref field.  That is likely to put it at least
    // close to the desired position.
693
    if( coord == zero && field.GetText().IsEmpty() )
694
    {
695
        rotateCheckBox->SetValue( m_FieldsBuf[REFERENCE].GetOrientation() == TEXT_ORIENT_VERT );
696

697 698 699 700
        coord.x = m_FieldsBuf[REFERENCE].GetTextPosition().x +
                  (fieldNdx - MANDATORY_FIELDS + 1) * 100;
        coord.y = m_FieldsBuf[REFERENCE].GetTextPosition().y +
                  (fieldNdx - MANDATORY_FIELDS + 1) * 100;
701

702
        // coord can compute negative if field is < MANDATORY_FIELDS, e.g. FOOTPRINT.
703 704 705 706
        // That is ok, we basically don't want all the new empty fields on
        // top of each other.
    }

707
    wxString coordText = StringFromValue( g_UserUnit, coord.x );
708 709 710 711 712
    posXTextCtrl->SetValue( coordText );

    // Note: the Y axis for components in lib is from bottom to top
    // and the screen axis is top to bottom: we must change the y coord sign for editing
    NEGATE( coord.y );
713
    coordText = StringFromValue( g_UserUnit, coord.y );
714 715 716 717 718 719 720 721 722 723 724
    posYTextCtrl->SetValue( coordText );
}


bool DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copyPanelToSelectedField()
{
    unsigned fieldNdx = getSelectedFieldNdx();

    if( fieldNdx >= m_FieldsBuf.size() )        // traps the -1 case too
        return true;

725
    LIB_FIELD& field = m_FieldsBuf[fieldNdx];
726 727

    if( showCheckBox->GetValue() )
728
        field.SetVisible( true );
729
    else
730
        field.SetVisible( false );
731 732

    if( rotateCheckBox->GetValue() )
733
        field.SetOrientation( TEXT_ORIENT_VERT );
734
    else
735
        field.SetOrientation( TEXT_ORIENT_HORIZ );
736

737
    // Copy the text justification
738
    static const EDA_TEXT_HJUSTIFY_T hjustify[3] = {
739 740 741
        GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_HJUSTIFY_CENTER,
        GR_TEXT_HJUSTIFY_RIGHT
    };
742

743
    static const EDA_TEXT_VJUSTIFY_T vjustify[3] = {
744 745 746
        GR_TEXT_VJUSTIFY_BOTTOM, GR_TEXT_VJUSTIFY_CENTER,
        GR_TEXT_VJUSTIFY_TOP
    };
747

748 749
    field.SetHorizJustify( hjustify[m_FieldHJustifyCtrl->GetSelection()] );
    field.SetVertJustify( vjustify[m_FieldVJustifyCtrl->GetSelection()] );
750

751 752 753
    // Blank/empty field texts for REFERENCE and VALUE are not allowed.
    // (Value is the name of the component in lib!)
    // Change them only if user provided a non blank value
754
    if( !fieldValueTextCtrl->GetValue().IsEmpty() || fieldNdx > VALUE )
755
        field.SetText( fieldValueTextCtrl->GetValue() );
756

757 758
    // FieldNameTextCtrl has a tricked value in it for VALUE index, do not copy it back.
    // It has the "Chip Name" appended.
759
    if( field.GetId() >= MANDATORY_FIELDS )
760 761
    {
        wxString name = fieldNameTextCtrl->GetValue();
762
        DBG( printf("name:%s\n", TO_UTF8( name ) ); )
763 764 765
        field.SetName( name );
    }

766
    DBG( printf("setname:%s\n", TO_UTF8( field.GetName() ) ); )
767 768 769

    setRowItem( fieldNdx, field );  // update fieldListCtrl

770
    int tmp = EDA_GRAPHIC_TEXT_CTRL::ParseSize( textSizeTextCtrl->GetValue(), g_UserUnit );
771

772
    field.SetSize( wxSize( tmp, tmp ) );
773 774 775

    int style = m_StyleRadioBox->GetSelection();

776 777
    field.SetItalic( (style & 1 ) != 0 );
    field.SetBold( (style & 2 ) != 0 );
778

779 780
    wxPoint pos( ValueFromString( g_UserUnit, posXTextCtrl->GetValue() ),
                 ValueFromString( g_UserUnit, posYTextCtrl->GetValue() ) );
781

782 783
    // Note: the Y axis for components in lib is from bottom to top
    // and the screen axis is top to bottom: we must change the y coord sign for editing
784 785
    NEGATE( pos.y );

786
    field.SetTextPosition( pos );
787 788 789

    return true;
}