コード例 #1
0
/*
 * Function GlobalChange_PadSettings
 * Function to change pad caracteristics for the given footprint
 * or alls footprints which look like the given footprint
 * aPad is the pattern. The given footprint is the parent of this pad
 * aSameFootprints: if true, make changes on all identical footprints
 * aPadShapeFilter: if true, make changes only on pads having the same shape as aPad
 * aPadOrientFilter: if true, make changes only on pads having the same orientation as aPad
 * aPadLayerFilter: if true, make changes only on pads having the same layers as aPad
 * aRedraw: if true: redraws the footprint
 * aSaveForUndo: if true: create an entry in the Undo/Redo list
 *        (usually: true in Schematic editor, false in Module editor)
 */
void PCB_BASE_FRAME::GlobalChange_PadSettings( D_PAD* aPad,
                                               bool aSameFootprints,
                                               bool aPadShapeFilter,
                                               bool aPadOrientFilter,
                                               bool aPadLayerFilter,
                                               bool aRedraw, bool aSaveForUndo )
{
    if( aPad == NULL )
        aPad = &GetDesignSettings().m_Pad_Master;

    MODULE* module = aPad->GetParent();

    if( module == NULL )
    {
        DisplayError( this, wxT( "Global_Import_Pad_Settings() Error: NULL module" ) );
        return;
    }

    // Search and copy the name of library reference.
    MODULE* Module_Ref = module;
    double pad_orient = aPad->GetOrientation() - Module_Ref->GetOrientation();

    // Prepare an undo list:
    if( aSaveForUndo )
    {
        PICKED_ITEMS_LIST itemsList;

        for( module = m_Pcb->m_Modules;  module;  module = module->Next() )
        {
            if( !aSameFootprints && (module != Module_Ref) )
                continue;

            if( module->GetFPID() != Module_Ref->GetFPID() )
                continue;

            bool   saveMe = false;

            for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
            {
                // Filters changes prohibited.
                if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
                    continue;

                double currpad_orient = pad->GetOrientation() - module->GetOrientation();

                if( aPadOrientFilter && ( currpad_orient != pad_orient ) )
                    continue;

                if( aPadLayerFilter  &&  pad->GetLayerSet() != aPad->GetLayerSet() )
                    continue;

                saveMe = true;
            }

            if( saveMe )
            {
                ITEM_PICKER itemWrapper( module, UR_CHANGED );

                itemsList.PushItem( itemWrapper );
            }
        }

        SaveCopyInUndoList( itemsList, UR_CHANGED );
    }

    // Update the current module and same others modules if requested.
    for( module = m_Pcb->m_Modules;  module;  module = module->Next() )
    {
        if( !aSameFootprints && (module != Module_Ref) )
            continue;

        if( module->GetFPID() != Module_Ref->GetFPID() )
            continue;

        // Erase module on screen
        if( aRedraw )
        {
            module->SetFlags( DO_NOT_DRAW );
            m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
            module->ClearFlags( DO_NOT_DRAW );
        }

        for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
        {
            // Filters changes prohibited.
            if( aPadShapeFilter && ( pad->GetShape() != aPad->GetShape() ) )
                continue;

            if( aPadOrientFilter &&  (pad->GetOrientation() - module->GetOrientation()) != pad_orient )
                continue;

            if( aPadLayerFilter )
            {
                if( pad->GetLayerSet() != aPad->GetLayerSet() )
                    continue;
                else
                    m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK);
            }

            // Change characteristics:
            pad->SetAttribute( aPad->GetAttribute() );
            pad->SetShape( aPad->GetShape() );

            pad->SetLayerSet( aPad->GetLayerSet() );

            pad->SetSize( aPad->GetSize() );
            pad->SetDelta( aPad->GetDelta() );
            pad->SetOffset( aPad->GetOffset() );

            pad->SetDrillSize( aPad->GetDrillSize() );
            pad->SetDrillShape( aPad->GetDrillShape() );

            pad->SetOrientation( pad_orient + module->GetOrientation() );

            // copy also local mask margins, because these parameters usually depend on
            // pad sizes and layers
            pad->SetLocalSolderMaskMargin( aPad->GetLocalSolderMaskMargin() );
            pad->SetLocalSolderPasteMargin( aPad->GetLocalSolderPasteMargin() );
            pad->SetLocalSolderPasteMarginRatio( aPad->GetLocalSolderPasteMarginRatio() );

            if( pad->GetShape() != PAD_SHAPE_TRAPEZOID )
            {
                pad->SetDelta( wxSize( 0, 0 ) );
            }

            if( pad->GetShape() == PAD_SHAPE_CIRCLE )
            {
                // Ensure pad size.y = pad size.x
                int size = pad->GetSize().x;
                pad->SetSize( wxSize( size, size ) );
            }

            switch( pad->GetAttribute() )
            {
            case PAD_ATTRIB_SMD:
            case PAD_ATTRIB_CONN:
                pad->SetDrillSize( wxSize( 0, 0 ) );
                break;

            default:
                break;
            }
        }

        module->CalculateBoundingBox();

        if( aRedraw )
            m_canvas->RefreshDrawingRect( module->GetBoundingBox() );
    }

    OnModify();
}
コード例 #2
0
int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent )
{
    // first, check if we have a selection, or try to get one
    SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
    const SELECTION& selection = selTool->GetSelection();

    // Be sure that there is at least one item that we can modify
    if( !hoverSelection( selection ) )
        return 0;

    bool originalItemsModified = false;

    // we have a selection to work on now, so start the tool process

    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
    editFrame->OnModify();

    if( m_editModules )
    {
        // Module editors do their undo point upfront for the whole module
        editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT );
    }
    else
    {
        // We may also change the original item
        editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
    }

    DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* array_opts = NULL;

    VECTOR2I rp = selection.GetCenter();
    const wxPoint rotPoint( rp.x, rp.y );

    DIALOG_CREATE_ARRAY dialog( editFrame, rotPoint, &array_opts );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK && array_opts != NULL )
    {
        PICKED_ITEMS_LIST newItemList;

        for( int i = 0; i < selection.Size(); ++i )
        {
            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

            if( !item )
                continue;

            wxString cachedString;

            if( item->Type() == PCB_MODULE_T )
            {
                cachedString = static_cast<MODULE*>( item )->GetReferencePrefix();
            }
            else if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item ) )
            {
                // Copy the text (not just take a reference
                cachedString = text->GetText();
            }

            // iterate across the array, laying out the item at the
            // correct position
            const unsigned nPoints = array_opts->GetArraySize();

            for( unsigned ptN = 0; ptN < nPoints; ++ptN )
            {
                BOARD_ITEM* newItem = NULL;

                if( ptN == 0 )
                    newItem = item;
                else
                {
                    // if renumbering, no need to increment
                    const bool increment = !array_opts->ShouldRenumberItems();

                    // Some items cannot be duplicated
                    // i.e. the ref and value fields of a footprint or zones
                    // therefore newItem can be null

                    if( m_editModules )
                        newItem = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem( item, increment );
                    else
                    {
#if 0
                        // @TODO: see if we allow zone duplication here
                        // Duplicate zones is especially tricky (overlaping zones must be merged)
                        // so zones are not duplicated
                        if( item->Type() == PCB_ZONE_AREA_T )
                            newItem = NULL;
                        else
#endif
                            newItem = editFrame->GetBoard()->DuplicateAndAddItem( item, increment );
                    }

                    if( newItem )
                    {
                        array_opts->TransformItem( ptN, newItem, rotPoint );

                        m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, newItem );

                        newItemList.PushItem( newItem );

                        if( newItem->Type() == PCB_MODULE_T)
                        {
                            static_cast<MODULE*>( newItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add,
                                    getView(), _1 ) );
                        }

                        editFrame->GetGalCanvas()->GetView()->Add( newItem );
                        getModel<BOARD>()->GetRatsnest()->Update( newItem );
                    }
                }

                // set the number if needed:
                if( newItem && array_opts->ShouldRenumberItems() )
                {
                    switch( newItem->Type() )
                    {
                    case PCB_PAD_T:
                    {
                        const wxString padName = array_opts->GetItemNumber( ptN );
                        static_cast<D_PAD*>( newItem )->SetPadName( padName );

                        originalItemsModified = true;
                        break;
                    }
                    case PCB_MODULE_T:
                    {
                        const wxString moduleName = array_opts->GetItemNumber( ptN );
                        MODULE* module = static_cast<MODULE*>( newItem );
                        module->SetReference( cachedString + moduleName );

                        originalItemsModified = true;
                        break;
                    }
                    case PCB_MODULE_TEXT_T:
                    case PCB_TEXT_T:
                    {
                        EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( newItem );
                        if( text )
                            text->SetText( array_opts->InterpolateNumberIntoString( ptN, cachedString ) );

                        originalItemsModified = true;
                        break;
                    }
                    default:
                        // no renumbering of other items
                        break;
                    }
                }
            }
        }

        if( !m_editModules )
        {
            if( originalItemsModified )
            {
                // Update the appearance of the original items
                selection.group->ItemsViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            }

            // Add all items as a single undo point for PCB editors
            // TODO: Can this be merged into the previous undo point (where
            //       we saved the original items)
            editFrame->SaveCopyInUndoList( newItemList, UR_NEW );
        }
    }

    getModel<BOARD>()->GetRatsnest()->Recalculate();

    return 0;
}
コード例 #3
0
ファイル: sch_screen.cpp プロジェクト: natsfr/kicad
int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList,
                               bool aFullConnection )
{
    SCH_ITEM* item;
    EDA_ITEM* tmp;
    EDA_ITEMS list;

    // Clear flags member for all items.
    ClearDrawingState();
    BreakSegmentsOnJunctions();

    if( GetNode( aPosition, list ) == 0 )
        return 0;

    for( size_t i = 0;  i < list.size();  i++ )
    {
        item = (SCH_ITEM*) list[ i ];
        item->SetFlags( SELECTEDNODE | STRUCT_DELETED );

        /* Put this structure in the picked list: */
        ITEM_PICKER picker( item, UR_DELETED );
        aList.PushItem( picker );
    }

    // Mark all wires, junctions, .. connected to the item(s) found.
    if( aFullConnection )
    {
        SCH_LINE* segment;

        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            if( !(item->GetFlags() & SELECTEDNODE) )
                continue;

            if( item->Type() != SCH_LINE_T )
                continue;

            MarkConnections( (SCH_LINE*) item );
        }

        // Search all attached wires (i.e wire with one new dangling end )
        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            bool noconnect = false;

            if( item->GetFlags() & STRUCT_DELETED )
                continue;                                   // Already seen

            if( !(item->GetFlags() & CANDIDATE) )
                continue;                                   // not a candidate

            if( item->Type() != SCH_LINE_T )
                continue;

            item->SetFlags( SKIP_STRUCT );

            segment = (SCH_LINE*) item;

            /* If the wire start point is connected to a wire that was already found
             * and now is not connected, add the wire to the list. */
            for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() )
            {
                // Ensure tmp is a previously deleted segment:
                if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 )
                    continue;

                if( tmp->Type() != SCH_LINE_T )
                    continue;

                SCH_LINE* testSegment = (SCH_LINE*) tmp;

               // Test for segment connected to the previously deleted segment:
                if( testSegment->IsEndPoint( segment->GetStartPoint() ) )
                    break;
            }

            // when tmp != NULL, segment is a new candidate:
            // put it in deleted list if
            // the start point is not connected to an other item (like pin)
            if( tmp && !CountConnectedItems( segment->GetStartPoint(), true ) )
                noconnect = true;

            /* If the wire end point is connected to a wire that has already been found
             * and now is not connected, add the wire to the list. */
            for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() )
            {
                // Ensure tmp is a previously deleted segment:
                if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 )
                    continue;

                if( tmp->Type() != SCH_LINE_T )
                    continue;

                SCH_LINE* testSegment = (SCH_LINE*) tmp;

                // Test for segment connected to the previously deleted segment:
                if( testSegment->IsEndPoint( segment->GetEndPoint() ) )
                    break;
            }

            // when tmp != NULL, segment is a new candidate:
            // put it in deleted list if
            // the end point is not connected to an other item (like pin)
            if( tmp && !CountConnectedItems( segment->GetEndPoint(), true ) )
                noconnect = true;

            item->ClearFlags( SKIP_STRUCT );

            if( noconnect )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );

                item = m_drawList.begin();
            }
        }

        // Get redundant junctions (junctions which connect < 3 end wires
        // and no pin)
        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            if( item->GetFlags() & STRUCT_DELETED )
                continue;

            if( !(item->GetFlags() & CANDIDATE) )
                continue;

            if( item->Type() != SCH_JUNCTION_T )
                continue;

            SCH_JUNCTION* junction = (SCH_JUNCTION*) item;

            if( CountConnectedItems( junction->GetPosition(), false ) <= 2 )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );
            }
        }

        for( item = m_drawList.begin(); item;  item = item->Next() )
        {
            if( item->GetFlags() & STRUCT_DELETED )
                continue;

            if( item->Type() != SCH_LABEL_T )
                continue;

            tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() );

            if( tmp && tmp->GetFlags() & STRUCT_DELETED )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );
            }
        }
    }

    ClearDrawingState();

    return aList.GetCount();
}
コード例 #4
0
void PCB_EDIT_FRAME::Block_SelectItems()
{
    LSET layerMask;
    bool selectOnlyComplete = GetScreen()->m_BlockLocate.GetWidth() > 0 ;

    GetScreen()->m_BlockLocate.Normalize();

    PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems();
    ITEM_PICKER        picker( NULL, UR_UNSPECIFIED );

    // Add modules
    if( blockIncludeModules )
    {
        for( MODULE* module = m_Pcb->m_Modules;  module;  module = module->Next() )
        {
            LAYER_ID layer = module->GetLayer();

            if( module->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete )
                && ( !module->IsLocked() || blockIncludeLockedModules ) )
            {
                if( blockIncludeItemsOnInvisibleLayers || m_Pcb->IsModuleLayerVisible( layer ) )
                {
                    picker.SetItem ( module );
                    itemsList->PushItem( picker );
                }
            }
        }
    }

    // Add tracks and vias
    if( blockIncludeTracks )
    {
        for( TRACK* track = m_Pcb->m_Track; track != NULL; track = track->Next() )
        {
            if( track->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
            {
                if( blockIncludeItemsOnInvisibleLayers
                  || m_Pcb->IsLayerVisible( track->GetLayer() ) )
                {
                    picker.SetItem( track );
                    itemsList->PushItem( picker );
                }
            }
        }
    }

    // Add graphic items
    layerMask = LSET( Edge_Cuts );

    if( blockIncludeItemsOnTechLayers )
        layerMask.set();

    if( !blockIncludeBoardOutlineLayer )
        layerMask.set( Edge_Cuts, false );

    for( BOARD_ITEM* PtStruct = m_Pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
    {
        if( !m_Pcb->IsLayerVisible( PtStruct->GetLayer() ) && ! blockIncludeItemsOnInvisibleLayers)
            continue;

        bool select_me = false;

        switch( PtStruct->Type() )
        {
        case PCB_LINE_T:
            if( !layerMask[PtStruct->GetLayer()] )
                break;

            if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
                break;

            select_me = true; // This item is in bloc: select it
            break;

        case PCB_TEXT_T:
            if( !blockIncludePcbTexts )
                break;

            if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
                break;

            select_me = true; // This item is in bloc: select it
            break;

        case PCB_TARGET_T:
            if( !layerMask[PtStruct->GetLayer()] )
                break;

            if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
                break;

            select_me = true; // This item is in bloc: select it
            break;

        case PCB_DIMENSION_T:
            if( !layerMask[PtStruct->GetLayer()] )
                break;

            if( !PtStruct->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
                break;

            select_me = true; // This item is in bloc: select it
            break;

        default:
            break;
        }

        if( select_me )
        {
            picker.SetItem ( PtStruct );
            itemsList->PushItem( picker );
        }
    }

    // Add zones
    if( blockIncludeZones )
    {
        for( int ii = 0; ii < m_Pcb->GetAreaCount(); ii++ )
        {
            ZONE_CONTAINER* area = m_Pcb->GetArea( ii );

            if( area->HitTest( GetScreen()->m_BlockLocate, selectOnlyComplete ) )
            {
                if( blockIncludeItemsOnInvisibleLayers
                  || m_Pcb->IsLayerVisible( area->GetLayer() ) )
                {
                    BOARD_ITEM* zone_c = (BOARD_ITEM*) area;
                    picker.SetItem ( zone_c );
                    itemsList->PushItem( picker );
                }
            }
        }
    }
}
コード例 #5
0
void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM*    aItem,
                                         UNDO_REDO_T    aCommandType,
                                         const wxPoint& aTransformPoint )
{
    if( aItem == NULL )     // Nothing to save
        return;

    // For texts belonging to modules, we need to save state of the parent module
    if( aItem->Type() == PCB_MODULE_TEXT_T )
    {
        aItem = aItem->GetParent();
        wxASSERT( aItem->Type() == PCB_MODULE_T );
        aCommandType = UR_CHANGED;

        if( aItem == NULL )
            return;
    }

    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

    ITEM_PICKER itemWrapper( aItem, aCommandType );

    switch( aCommandType )
    {
    case UR_CHANGED:                        // Create a copy of item
        if( itemWrapper.GetLink() == NULL ) // When not null, the copy is already done
            itemWrapper.SetLink( aItem->Clone() );
        commandToUndo->PushItem( itemWrapper );
        break;

    case UR_NEW:
    case UR_DELETED:
#ifdef USE_WX_OVERLAY
    // Avoid to redraw when autoplacing
    if( aItem->Type() == PCB_MODULE_T )
        if( ((MODULE*)aItem)->GetFlags() & MODULE_to_PLACE )
            break;
        m_canvas->Refresh();
#endif
    case UR_MOVED:
    case UR_FLIPPED:
    case UR_ROTATED:
    case UR_ROTATED_CLOCKWISE:
        commandToUndo->PushItem( itemWrapper );
        break;

    default:
    {
        wxString msg;
        msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), aCommandType );
        wxMessageBox( msg );
    }
    break;
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after new save there is no redo to do */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else
    {
        delete commandToUndo;
    }
}
コード例 #6
0
void PCB_BASE_FRAME::ResetModuleTextSizes( const wxString & aFilter, bool aRef,
                                           bool aValue, bool aOthers )
{
    MODULE* module;
    BOARD_ITEM* boardItem;
    TEXTE_MODULE* item;
    ITEM_PICKER itemWrapper( NULL, UR_CHANGED );
    PICKED_ITEMS_LIST undoItemList;
    unsigned int ii;

    // Prepare undo list
    for( module = GetBoard()->m_Modules; module; module = module->Next() )
    {
        itemWrapper.SetItem( module );

        if( ! aFilter.IsEmpty() )
        {
            if( ! WildCompareString( aFilter, FROM_UTF8( module->GetFPID().Format().c_str() ),
                                     false ) )
                continue;
        }


        if( aRef )
        {
            item = &module->Reference();

            if( item->GetSize() != GetDesignSettings().m_ModuleTextSize ||
                item->GetThickness() != GetDesignSettings().m_ModuleTextWidth )
            {
                undoItemList.PushItem( itemWrapper );
            }
        }

        if( aValue )
        {
            item = &module->Value();

            if( item->GetSize() != GetDesignSettings().m_ModuleTextSize ||
                item->GetThickness() != GetDesignSettings().m_ModuleTextWidth )
            {
                undoItemList.PushItem( itemWrapper );
            }
        }

        if( aOthers )
        {
            // Go through all other module text fields
            for( boardItem = module->GraphicalItems(); boardItem; boardItem = boardItem->Next() )
            {
                if( boardItem->Type() == PCB_MODULE_TEXT_T )
                {
                    item = (TEXTE_MODULE*) boardItem;

                    if( item->GetSize() != GetDesignSettings().m_ModuleTextSize
                        || item->GetThickness() != GetDesignSettings().m_ModuleTextWidth )
                    {
                        undoItemList.PushItem( itemWrapper );
                    }
                }
            }
        }
    }

    // Exit if there's nothing to do
    if( !undoItemList.GetCount() )
        return;

    SaveCopyInUndoList( undoItemList, UR_CHANGED );

    // Apply changes to modules in the undo list
    for( ii = 0; ii < undoItemList.GetCount(); ii++ )
    {
        module = (MODULE*) undoItemList.GetPickedItem( ii );

        if( aRef )
        {
            module->Reference().SetThickness( GetDesignSettings().m_ModuleTextWidth );
            module->Reference().SetSize( GetDesignSettings().m_ModuleTextSize );
        }

        if( aValue )
        {
            module->Value().SetThickness( GetDesignSettings().m_ModuleTextWidth );
            module->Value().SetSize( GetDesignSettings().m_ModuleTextSize );
        }

        if( aOthers )
        {
            for( boardItem = module->GraphicalItems(); boardItem; boardItem = boardItem->Next() )
            {
                if( boardItem->Type() == PCB_MODULE_TEXT_T )
                {
                    item = (TEXTE_MODULE*) boardItem;
                    item->SetThickness( GetDesignSettings().m_ModuleTextWidth );
                    item->SetSize( GetDesignSettings().m_ModuleTextSize );
                }
            }
        }
    }

    OnModify();
}