void PCB_DRAW_PANEL_GAL::SetTopLayer( LAYER_ID aLayer )
{
    m_view->ClearTopLayers();
    m_view->SetTopLayer( aLayer );

    if( IsCopperLayer( aLayer ) )
    {
        // Bring some other layers to the front in case of copper layers and make them colored
        // fixme do not like the idea of storing the list of layers here,
        // should be done in some other way I guess..
        LAYER_NUM layers[] = {
                GetNetnameLayer( aLayer ), ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ),
                ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ),
                ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ),
                ITEM_GAL_LAYER( GP_OVERLAY ), ITEM_GAL_LAYER( RATSNEST_VISIBLE ), Dwgs_User,
                ITEM_GAL_LAYER( DRC_VISIBLE )
        };

        for( unsigned int i = 0; i < sizeof( layers ) / sizeof( LAYER_NUM ); ++i )
        {
            m_view->SetTopLayer( layers[i] );
        }

        // Pads should be shown too
        if( aLayer == B_Cu )
        {
            m_view->SetTopLayer( ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
            m_view->SetTopLayer( NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE ) );
        }
        else if( aLayer == F_Cu )
        {
            m_view->SetTopLayer( ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
            m_view->SetTopLayer( NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE ) );
        }
    }

    m_view->UpdateAllLayersOrder();
}
Beispiel #2
0
const wxString GetGerberExtension( LAYER_NUM aLayer )
{
    if( IsCopperLayer( aLayer ) )
    {
        if( aLayer == F_Cu )
            return wxT( "gtl" );
        else if( aLayer == B_Cu )
            return wxT( "gbl" );
        else
        {
            return wxT( "gbr" );
        }
    }
    else
    {
        switch( aLayer )
        {
        case B_Adhes:       return wxT( "gba" );
        case F_Adhes:       return wxT( "gta" );

        case B_Paste:       return wxT( "gbp" );
        case F_Paste:       return wxT( "gtp" );

        case B_SilkS:       return wxT( "gbo" );
        case F_SilkS:       return wxT( "gto" );

        case B_Mask:        return wxT( "gbs" );
        case F_Mask:        return wxT( "gts" );

        case Dwgs_User:
        case Cmts_User:
        case Eco1_User:
        case Eco2_User:
        case Edge_Cuts:
        default:            return wxT( "gbr" );
        }
    }
}
void PCB_DRAW_PANEL_GAL::SyncLayersVisibility( const BOARD* aBoard )
{
    // Load layer & elements visibility settings
    for( LAYER_NUM i = 0; i < LAYER_ID_COUNT; ++i )
    {
        m_view->SetLayerVisible( i, aBoard->IsLayerVisible( LAYER_ID( i ) ) );

        // Synchronize netname layers as well
        if( IsCopperLayer( i ) )
            m_view->SetLayerVisible( GetNetnameLayer( i ), aBoard->IsLayerVisible( LAYER_ID( i ) ) );
    }

    for( LAYER_NUM i = 0; i < END_PCB_VISIBLE_LIST; ++i )
    {
        m_view->SetLayerVisible( ITEM_GAL_LAYER( i ), aBoard->IsElementVisible( i ) );
    }

    // Enable some layers that are GAL specific
    m_view->SetLayerVisible( ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), true );
    m_view->SetLayerVisible( ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), true );
    m_view->SetLayerVisible( ITEM_GAL_LAYER( WORKSHEET ), true );
    m_view->SetLayerVisible( ITEM_GAL_LAYER( GP_OVERLAY ), true );
}
bool BOARD::OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList,
                                   ZONE_CONTAINER* modified_area )
{
    // clip polygon against itself
    bool modified = NormalizeAreaPolygon( aModifiedZonesList, modified_area );

    // now see if we need to clip against other areas
    LAYER_NUM layer = modified_area->GetLayer();
    bool bCheckAllAreas = TestAreaIntersections( modified_area );

    if( bCheckAllAreas )
    {
        modified = true;
        CombineAllAreasInNet( aModifiedZonesList, modified_area->GetNetCode(), true );
    }

    if( !IsCopperLayer( layer ) )       // Refill non copper zones on this layer
    {
        for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ )
            if( m_ZoneDescriptorList[ia]->GetLayer() == layer )
                m_ZoneDescriptorList[ia]->BuildFilledSolidAreasPolygons( this );
    }

    // Test for bad areas: all zones must have more than 2 corners:
    // Note: should not happen, but just in case.
    for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); )
    {
        ZONE_CONTAINER* zone = m_ZoneDescriptorList[ii];

        if( zone->GetNumCorners() >= 3 )
            ii++;
        else               // Remove zone because it is incorrect:
            RemoveArea( aModifiedZonesList, zone );
    }

    return modified;
}
bool PCB_EDIT_FRAME::OnHotkeyDeleteItem( wxDC* aDC )
{
    BOARD_ITEM* item = GetCurItem();
    bool ItemFree = (item == NULL) || (item->GetFlags() == 0);

    switch( GetToolId() )
    {
    case ID_TRACK_BUTT:
        if( !IsCopperLayer ( GetActiveLayer() ) )
            return false;

        if( ItemFree )
        {
            item = PcbGeneralLocateAndDisplay();

            if( item && !item->IsTrack() )
                return false;

            Delete_Track( aDC, (TRACK*) item );
        }
        else if( item->IsTrack( ) )
        {
            // simple lines for debugger:
            TRACK* track = (TRACK*) item;
            track = Delete_Segment( aDC, track );
            SetCurItem( track );
            OnModify();
            return true;
        }
        break;

    case ID_PCB_MODULE_BUTT:
        if( ItemFree )
        {
            wxPoint pos    = RefPos( false );
            MODULE* module = GetBoard()->GetFootprint( pos, UNDEFINED_LAYER, false );

            if( module == NULL || module->IsLocked() )
                return false;

            RemoveStruct( module, aDC );
        }
        else
            return false;
        break;

    default:
        if( ItemFree )
        {
            item = PcbGeneralLocateAndDisplay();

            // Shouldn't there be a check for locked tracks and vias here?
            if( item == NULL || (item->Type() == PCB_MODULE_T && (MODULE*)item->IsLocked()) )
                return false;

            RemoveStruct( item, aDC );
        }
        else
            return false;
    }

    OnModify();
    SetCurItem( NULL );
    return true;
}
const wxString GetGerberFileFunctionAttribute( const BOARD *aBoard, LAYER_NUM aLayer )
{
    wxString attrib;

    switch( aLayer )
    {
    case F_Adhes:
        attrib = "Glue,Top";
        break;

    case B_Adhes:
        attrib = "Glue,Bot";
        break;

    case F_SilkS:
        attrib = "Legend,Top";
        break;

    case B_SilkS:
        attrib = "Legend,Bot";
        break;

    case F_Mask:
        attrib = "Soldermask,Top";
        break;

    case B_Mask:
        attrib = "Soldermask,Bot";
        break;

    case F_Paste:
        attrib = "Paste,Top";
        break;

    case B_Paste:
        attrib = "Paste,Bot";
        break;

    case Edge_Cuts:
        // Board outline.
        // Can be "Profile,NP" (Not Plated: usual) or "Profile,P"
        // This last is the exception (Plated)
        attrib = "Profile,NP";
        break;

    case Dwgs_User:
        attrib = "Drawing";
        break;

    case Cmts_User:
        attrib = "Other,Comment";
        break;

    case Eco1_User:
        attrib = "Other,ECO1";
        break;

    case Eco2_User:
        attrib = "Other,ECO2";
        break;

    case B_Fab:
        attrib = "Other,Fab,Bot";
        break;

    case F_Fab:
        attrib = "Other,Fab,Top";
        break;

    case B_Cu:
        attrib.Printf( wxT( "Copper,L%d,Bot" ), aBoard->GetCopperLayerCount() );
        break;

    case F_Cu:
        attrib = "Copper,L1,Top";
        break;

    default:
        if( IsCopperLayer( aLayer ) )
            attrib.Printf( wxT( "Copper,L%d,Inr" ), aLayer+1 );
        else
            attrib.Printf( wxT( "Other,User" ), aLayer+1 );
        break;
    }

    // Add the signal type of the layer, if relevant
    if( IsCopperLayer( aLayer ) )
    {
        LAYER_T type = aBoard->GetLayerType( ToLAYER_ID( aLayer ) );

        switch( type )
        {
        case LT_SIGNAL:
            attrib += ",Signal";
            break;
        case LT_POWER:
            attrib += ",Plane";
            break;
        case LT_MIXED:
            attrib += ",Mixed";
            break;
        default:
            break;   // do nothing (but avoid a warning for unhandled LAYER_T values from GCC)
        }
    }

    wxString fileFct;
    fileFct.Printf( "%%TF.FileFunction,%s*%%", GetChars( attrib ) );

    return fileFct;
}
void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
                        const wxPoint& offset )
{
    int         ux0, uy0, dx, dy, radius, StAngle, EndAngle;
    int         typeaff;
    LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;

    MODULE* module = (MODULE*) m_Parent;

    if( !module )
        return;

    BOARD* brd = GetBoard( );

    if( brd->IsLayerVisible( m_Layer ) == false )
        return;

    EDA_COLOR_T color = brd->GetLayerColor( m_Layer );

    if(( draw_mode & GR_ALLOW_HIGHCONTRAST ) && DisplayOpt.ContrastModeDisplay )
    {
        if( !IsOnLayer( curr_layer ) )
            ColorTurnToDarkDarkGray( &color );
    }

    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) panel->GetParent();

    ux0 = m_Start.x - offset.x;
    uy0 = m_Start.y - offset.y;

    dx = m_End.x - offset.x;
    dy = m_End.y - offset.y;

    GRSetDrawMode( DC, draw_mode );
    typeaff = frame->m_DisplayModEdge;

    if( IsCopperLayer( m_Layer ) )
    {
        typeaff = frame->m_DisplayPcbTrackFill;

        if( !typeaff )
            typeaff = SKETCH;
    }

    if( DC->LogicalToDeviceXRel( m_Width ) <= MIN_DRAW_WIDTH )
        typeaff = LINE;

    switch( m_Shape )
    {
    case S_SEGMENT:
        if( typeaff == LINE )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, 0, color );
        else if( typeaff == FILLED )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        else
            // SKETCH Mode
            GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );

        break;

    case S_CIRCLE:
        radius = KiROUND( Distance( ux0, uy0, dx, dy ) );

        if( typeaff == LINE )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, color );
        }
        else
        {
            if( typeaff == FILLED )
            {
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
            }
            else        // SKETCH Mode
            {
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + (m_Width / 2), color );
                GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - (m_Width / 2), color );
            }
        }

        break;

    case S_ARC:
        radius   = KiROUND( Distance( ux0, uy0, dx, dy ) );
        StAngle  = ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;

        if( !panel->GetPrintMirrored() )
        {
            if( StAngle > EndAngle )
                EXCHG( StAngle, EndAngle );
        }
        else    // Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                EXCHG( StAngle, EndAngle );
        }

        if( typeaff == LINE )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, color );
        }
        else if( typeaff == FILLED )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius + (m_Width / 2), color );
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius - (m_Width / 2), color );
        }
        break;

    case S_POLYGON:
        {
        // We must compute true coordinates from m_PolyPoints
        // which are relative to module position, orientation 0
        std::vector<wxPoint> points = m_PolyPoints;

        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];

            RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
            pt += module->GetPosition() - offset;
        }

        GRPoly( panel->GetClipBox(), DC, points.size(), &points[0], true, m_Width, color, color );
        }
        break;

    default:
        break;
    }
}
Beispiel #8
0
void PCB_PAD::AddToBoard()
{
    PCB_PAD_SHAPE*  padShape;
    int             i;
    int             width = 0;
    int             height = 0;

    if( m_objType == wxT( 'V' ) ) // via
    {
        // choose one of the shapes
        for( i = 0; i < (int) m_shapes.GetCount(); i++ )
        {
            padShape = m_shapes[i];

            if( padShape->m_width > 0 && padShape->m_height > 0 )
            {
                if( padShape->m_KiCadLayer == F_Cu
                    || padShape->m_KiCadLayer == B_Cu )
                {
                    width = padShape->m_width;
                    height = padShape->m_height;

                    break;
                }
            }
        }

        if( width == 0 || height == 0 )
            THROW_IO_ERROR( wxT( "pad or via with zero size" ) );

        if( IsCopperLayer( m_KiCadLayer ) )
        {
            VIA* via = new VIA( m_board );
            m_board->m_Track.Append( via );

            via->SetTimeStamp( 0 );

            via->SetPosition( wxPoint( m_positionX, m_positionY ) );
            via->SetEnd( wxPoint( m_positionX, m_positionY ) );

            via->SetWidth( height );
            via->SetViaType( VIA_THROUGH );
            via->SetLayerPair( F_Cu, B_Cu );
            via->SetDrill( m_hole );

            via->SetLayer( m_KiCadLayer );
            via->SetNetCode( m_netCode );
        }
    }
    else // pad
    {
        MODULE* module = new MODULE( m_board );
        m_board->Add( module, ADD_APPEND );

        m_name.text = m_defaultPinDes;

        module->SetPosition( wxPoint( m_positionX, m_positionY ) );
        AddToModule( module, 0, true );

    }
}
bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT*& aGraphic,
                                boost::optional<VECTOR2D> aStartingPoint )
{
    // Only two shapes are currently supported
    assert( aShape == S_SEGMENT || aShape == S_CIRCLE );

    DRAWSEGMENT line45;

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();

    bool direction45 = false;       // 45 degrees only mode
    bool started = false;
    VECTOR2I cursorPos = m_controls->GetCursorPosition();

    if( aStartingPoint )
    {
        LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

        // Init the new item attributes
        aGraphic->SetShape( (STROKE_T) aShape );
        aGraphic->SetWidth( m_lineWidth );
        aGraphic->SetStart( wxPoint( aStartingPoint->x, aStartingPoint->y ) );
        aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
        aGraphic->SetLayer( layer );

        if( aShape == S_SEGMENT )
            line45 = *aGraphic; // used only for direction 45 mode with lines

        preview.Add( aGraphic );
        m_controls->SetAutoPan( true );
        m_controls->CaptureCursor( true );

        started = true;
    }

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        bool updatePreview = false;            // should preview be updated
        cursorPos = m_controls->GetCursorPosition();

        // Enable 45 degrees lines only mode by holding control
        if( direction45 != evt->Modifier( MD_CTRL ) && started && aShape == S_SEGMENT )
        {
            direction45 = evt->Modifier( MD_CTRL );

            if( direction45 )
            {
                preview.Add( &line45 );
                make45DegLine( aGraphic, &line45 );
            }
            else
            {
                preview.Remove( &line45 );
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
            }

            updatePreview = true;
        }

        if( evt->IsCancel() || evt->IsActivate() || evt->IsAction( &COMMON_ACTIONS::layerChanged ) )
        {
            preview.Clear();
            updatePreview = true;
            delete aGraphic;
            aGraphic = NULL;
            break;
        }

        else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
        {
            if( !started )
            {
                LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

                if( IsCopperLayer( layer ) )
                {
                    DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
                }
                else
                {
                    // Init the new item attributes
                    aGraphic->SetShape( (STROKE_T) aShape );
                    m_lineWidth = getSegmentWidth( layer );
                    aGraphic->SetWidth( m_lineWidth );
                    aGraphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetLayer( layer );

                    if( aShape == S_SEGMENT )
                        line45 = *aGraphic; // used only for direction 45 mode with lines

                    preview.Add( aGraphic );
                    m_controls->SetAutoPan( true );
                    m_controls->CaptureCursor( true );

                    started = true;
                }
            }
            else
            {
                if( aGraphic->GetEnd() == aGraphic->GetStart() ||
                        ( evt->IsDblClick( BUT_LEFT ) && aShape == S_SEGMENT ) )
                                                // User has clicked twice in the same spot
                {                               // a clear sign that the current drawing is finished
                    if( direction45 )
                    {
                        // Now we have to add the helper line as well
                        if( m_editModules )
                        {
                            EDGE_MODULE* l = new EDGE_MODULE( m_board->m_Modules );

                            // Copy coordinates, layer, etc.
                            *static_cast<DRAWSEGMENT*>( l ) = line45;
                            l->SetEnd( aGraphic->GetStart() );
                            l->SetLocalCoord();

                            m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT );
                            m_board->m_Modules->SetLastEditTime();
                            m_board->m_Modules->GraphicalItems().PushFront( l );

                            m_view->Add( l );
                            l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                        }
                        else
                        {
                            DRAWSEGMENT* l = static_cast<DRAWSEGMENT*>( line45.Clone() );
                            l->SetEnd( aGraphic->GetStart() );

                            m_frame->SaveCopyInUndoList( l, UR_NEW );
                            m_board->Add( l );

                            m_view->Add( l );
                            l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                        }

                        m_frame->OnModify();
                    }

                    delete aGraphic;
                    aGraphic = NULL;
                }
                else
                {
                    assert( aGraphic->GetLength() > 0 );
                    assert( aGraphic->GetWidth() > 0 );

                    m_view->Add( aGraphic );
                    aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                }

                preview.Clear();
                break;
            }
        }

        else if( evt->IsMotion() )
        {
            // 45 degree lines
            if( direction45 && aShape == S_SEGMENT )
                make45DegLine( aGraphic, &line45 );
            else
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );

            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) )
        {
            m_lineWidth += WIDTH_STEP;
            aGraphic->SetWidth( m_lineWidth );
            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) )
        {
            if( m_lineWidth > (unsigned) WIDTH_STEP )
            {
                m_lineWidth -= WIDTH_STEP;
                aGraphic->SetWidth( m_lineWidth );
                updatePreview = true;
            }
        }

        if( updatePreview )
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    return started;
}
int DRAWING_TOOL::drawZone( bool aKeepout )
{
    ZONE_CONTAINER* zone = NULL;
    DRAWSEGMENT line45;
    DRAWSEGMENT* helperLine = NULL;  // we will need more than one helper line

    // if one day it is possible to draw zones in the footprint editor,
    // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet
    assert( !m_editModules );

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();

    VECTOR2I origin;
    int numPoints = 0;
    bool direction45 = false;       // 45 degrees only mode

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        bool updatePreview = false;            // should preview be updated
        VECTOR2I cursorPos = m_controls->GetCursorPosition();

        // Enable 45 degrees lines only mode by holding control
        if( direction45 != ( evt->Modifier( MD_CTRL ) && numPoints > 0 ) )
        {
            direction45 = evt->Modifier( MD_CTRL );

            if( direction45 )
            {
                preview.Add( &line45 );
                make45DegLine( helperLine, &line45 );
            }
            else
            {
                preview.Remove( &line45 );
                helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
            }

            updatePreview = true;
        }

        if( evt->IsCancel() || evt->IsActivate() )
        {
            if( numPoints > 0 )         // cancel the current zone
            {
                delete zone;
                zone = NULL;
                m_controls->SetAutoPan( false );
                m_controls->CaptureCursor( false );

                if( direction45 )
                {
                    preview.Remove( &line45 );
                    direction45 = false;
                }

                preview.FreeItems();
                updatePreview = true;

                numPoints = 0;
            }
            else                        // there is no zone currently drawn - just stop the tool
                break;

            if( evt->IsActivate() )  // now finish unconditionally
                break;
        }

        else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
        {
            // Check if it is double click / closing line (so we have to finish the zone)
            if( evt->IsDblClick( BUT_LEFT ) || ( numPoints > 0 && cursorPos == origin ) )
            {
                if( numPoints > 2 )     // valid zone consists of more than 2 points
                {
                    assert( zone->GetNumCorners() > 2 );

                    // Finish the zone
                    if( direction45 )
                        zone->AppendCorner( cursorPos == origin ? line45.GetStart() : line45.GetEnd() );

                    zone->Outline()->CloseLastContour();
                    zone->Outline()->RemoveNullSegments();

                    m_board->Add( zone );
                    m_view->Add( zone );

                    if( !aKeepout )
                        static_cast<PCB_EDIT_FRAME*>( m_frame )->Fill_Zone( zone );

                    zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                    m_board->GetRatsnest()->Update( zone );

                    m_frame->OnModify();
                    m_frame->SaveCopyInUndoList( zone, UR_NEW );

                    zone = NULL;
                }
                else
                {
                    delete zone;
                    zone = NULL;
                }

                numPoints = 0;
                m_controls->SetAutoPan( false );
                m_controls->CaptureCursor( false );

                if( direction45 )
                {
                    preview.Remove( &line45 );
                    direction45 = false;
                }

                preview.FreeItems();
                updatePreview = true;
            }
            else
            {
                if( numPoints == 0 )        // it's the first click
                {
                    // Get the current default settings for zones
                    ZONE_SETTINGS zoneInfo = m_frame->GetZoneSettings();
                    zoneInfo.m_CurrentZone_Layer = m_frame->GetScreen()->m_Active_Layer;

                    m_controls->SetAutoPan( true );
                    m_controls->CaptureCursor( true );

                    // Show options dialog
                    ZONE_EDIT_T dialogResult;

                    if( aKeepout )
                        dialogResult = InvokeKeepoutAreaEditor( m_frame, &zoneInfo );
                    else
                    {
                        if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) )
                            dialogResult = InvokeCopperZonesEditor( m_frame, &zoneInfo );
                        else
                            dialogResult = InvokeNonCopperZonesEditor( m_frame, NULL, &zoneInfo );
                    }

                    if( dialogResult == ZONE_ABORT )
                    {
                        m_controls->SetAutoPan( false );
                        m_controls->CaptureCursor( false );
                        continue;
                    }

                    // Apply the selected settings
                    zone = new ZONE_CONTAINER( m_board );
                    zoneInfo.ExportSetting( *zone );
                    m_frame->GetGalCanvas()->SetTopLayer( zoneInfo.m_CurrentZone_Layer );

                    // Add the first point
                    zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer,
                                            cursorPos.x, cursorPos.y,
                                            zone->GetHatchStyle() );
                    origin = cursorPos;

                    // Helper line represents the currently drawn line of the zone polygon
                    helperLine = new DRAWSEGMENT;
                    helperLine->SetShape( S_SEGMENT );
                    helperLine->SetWidth( 1 );
                    helperLine->SetLayer( zoneInfo.m_CurrentZone_Layer );
                    helperLine->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
                    helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                    line45 = *helperLine;

                    preview.Add( helperLine );
                }
                else
                {
                    zone->AppendCorner( helperLine->GetEnd() );
                    helperLine = new DRAWSEGMENT( *helperLine );
                    helperLine->SetStart( helperLine->GetEnd() );
                    preview.Add( helperLine );
                }

                ++numPoints;
                updatePreview = true;
            }
        }

        else if( evt->IsMotion() && numPoints > 0 )
        {
            // 45 degree lines
            if( direction45 )
                make45DegLine( helperLine, &line45 );
            else
                helperLine->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );

            // Show a preview of the item
            updatePreview = true;
        }

        if( updatePreview )
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );

    return 0;
}
Beispiel #11
0
void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
                        const wxPoint& offset )
{
    int         ux0, uy0, dx, dy, radius, StAngle, EndAngle;
    PCB_LAYER_ID    curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;

    MODULE* module = (MODULE*) m_Parent;

    if( !module )
        return;

    BOARD* brd = GetBoard( );

    if( brd->IsLayerVisible( m_Layer ) == false )
        return;


    auto frame = static_cast<PCB_BASE_FRAME*> ( panel->GetParent() );
    auto color = frame->Settings().Colors().GetLayerColor( m_Layer );

    auto displ_opts = (PCB_DISPLAY_OPTIONS*)( panel->GetDisplayOptions() );

    if(( draw_mode & GR_ALLOW_HIGHCONTRAST ) && displ_opts && displ_opts->m_ContrastModeDisplay )
    {
        if( !IsOnLayer( curr_layer ) )
            color = COLOR4D( DARKDARKGRAY );
    }

    ux0 = m_Start.x - offset.x;
    uy0 = m_Start.y - offset.y;

    dx = m_End.x - offset.x;
    dy = m_End.y - offset.y;

    GRSetDrawMode( DC, draw_mode );
    bool filled = displ_opts ? displ_opts->m_DisplayModEdgeFill : FILLED;

    if( IsCopperLayer( m_Layer ) )
        filled = displ_opts ? displ_opts->m_DisplayPcbTrackFill : FILLED;

    switch( m_Shape )
    {
    case S_SEGMENT:
        if( filled )
            GRLine( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );
        else
            // SKETCH Mode
            GRCSegm( panel->GetClipBox(), DC, ux0, uy0, dx, dy, m_Width, color );

        break;

    case S_CIRCLE:
        radius = KiROUND( Distance( ux0, uy0, dx, dy ) );

        if( filled )
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius + (m_Width / 2), color );
            GRCircle( panel->GetClipBox(), DC, ux0, uy0, radius - (m_Width / 2), color );
        }

        break;

    case S_ARC:
        radius   = KiROUND( Distance( ux0, uy0, dx, dy ) );
        StAngle  = ArcTangente( dy - uy0, dx - ux0 );
        EndAngle = StAngle + m_Angle;

        if( !panel->GetPrintMirrored() )
        {
            if( StAngle > EndAngle )
                std::swap( StAngle, EndAngle );
        }
        else    // Mirrored mode: arc orientation is reversed
        {
            if( StAngle < EndAngle )
                std::swap( StAngle, EndAngle );
        }

        if( filled )
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle, radius, m_Width, color );
        }
        else        // SKETCH Mode
        {
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius + (m_Width / 2), color );
            GRArc( panel->GetClipBox(), DC, ux0, uy0, StAngle, EndAngle,
                   radius - (m_Width / 2), color );
        }
        break;

    case S_POLYGON:
        if( m_Poly.IsEmpty() )
            break;

        {
        // We must compute absolute coordinates from m_PolyPoints
        // which are relative to module position, orientation 0
        std::vector<wxPoint> points;

        for( auto iter = m_Poly.CIterate(); iter; iter++ )
        {
            points.push_back( wxPoint( iter->x,iter->y ) );
        }

        for( unsigned ii = 0; ii < points.size(); ii++ )
        {
            wxPoint& pt = points[ii];

            RotatePoint( &pt.x, &pt.y, module->GetOrientation() );
            pt += module->GetPosition() - offset;
        }

        GRPoly( panel->GetClipBox(), DC, points.size(), &points[0], true, m_Width, color, color );
        }
        break;

    default:
        break;
    }
}
void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone )
{
    ZONE_EDIT_T     edited;
    ZONE_SETTINGS   zoneInfo = GetZoneSettings();

    BOARD_COMMIT commit( this );
    m_canvas->SetIgnoreMouseEvents( true );

    // Save initial zones configuration, for undo/redo, before adding new zone
    // note the net name and the layer can be changed, so we must save all zones
    s_AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList.ClearListAndDeleteItems();
    SaveCopyOfZones( s_PickedList, GetBoard(), -1, UNDEFINED_LAYER );

    if( aZone->GetIsKeepout() )
    {
        // edit a keepout area on a copper layer
        zoneInfo << *aZone;
        edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
    }
    else if( IsCopperLayer( aZone->GetLayer() ) )
    {
        // edit a zone on a copper layer

        zoneInfo << *aZone;

        edited = InvokeCopperZonesEditor( this, &zoneInfo );
    }
    else
    {
        edited = InvokeNonCopperZonesEditor( this, aZone, &zoneInfo );
    }

    m_canvas->MoveCursorToCrossHair();
    m_canvas->SetIgnoreMouseEvents( false );

    if( edited == ZONE_ABORT )
    {
        s_AuxiliaryList.ClearListAndDeleteItems();
        s_PickedList.ClearListAndDeleteItems();
        return;
    }

    SetZoneSettings( zoneInfo );

    if( edited == ZONE_EXPORT_VALUES )
    {
        UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
        commit.Stage( s_PickedList );
        commit.Push( _( "Modify zone properties" ) );
        s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
        return;
    }

    // Undraw old zone outlines
    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii );
        edge_zone->Draw( m_canvas, DC, GR_XOR );

        if( IsGalCanvasActive() )
        {
            GetGalCanvas()->GetView()->Update( edge_zone );
        }
    }

    zoneInfo.ExportSetting( *aZone );

    NETINFO_ITEM* net = GetBoard()->FindNet( zoneInfo.m_NetcodeSelection );

    if( net )   // net == NULL should not occur
        aZone->SetNetCode( net->GetNet() );

    // Combine zones if possible
    GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone );

    // Redraw the real new zone outlines
    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, UNDEFINED_LAYER );


    UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() );
    commit.Stage( s_PickedList );
    commit.Push( _( "Modify zone properties" ) );

    s_PickedList.ClearItemsList();  // s_ItemsListPicker is no longer owner of picked items
}
int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC )
{
    ZONE_SETTINGS zoneInfo = GetZoneSettings();

    // verify if s_CurrentZone exists (could be deleted since last selection) :
    int ii;
    for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        if( s_CurrentZone == GetBoard()->GetArea( ii ) )
            break;
    }

    if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection
    {
        s_AddCutoutToCurrentZone = false;
        s_CurrentZone = NULL;
    }

    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;

    // Verify if a new zone is allowed on this layer:
    if( zone == NULL  )
    {
        if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && !IsCopperLayer( GetActiveLayer() ) )
        {
            DisplayError( this,
                          _( "Error: a keepout area is allowed only on copper layers" ) );
            return 0;
        }
    }

    // If no zone contour in progress, a new zone is being created,
    if( zone == NULL )
    {
        zone = GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() );
        zone->SetFlags( IS_NEW );
        zone->SetTimeStamp( GetNewTimeStamp() );
    }

    if( zone->GetNumCorners() == 0 )    // Start a new contour: init zone params (net, layer ...)
    {
        if( !s_CurrentZone )            // A new outline is created, from scratch
        {
            ZONE_EDIT_T edited;

            // Init zone params to reasonable values
            zone->SetLayer( GetActiveLayer() );

            // Prompt user for parameters:
            m_canvas->SetIgnoreMouseEvents( true );

            if( zone->IsOnCopperLayer() )
            {
                // Put a zone on a copper layer
                if( GetBoard()->GetHighLightNetCode() > 0 )
                {
                    zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode();
                    zone->SetNetCode( zoneInfo.m_NetcodeSelection );
                }

                double tmp = ZONE_THERMAL_RELIEF_GAP_MIL;

                wxConfigBase* cfg = Kiface().KifaceSettings();
                cfg->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp );
                zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS);

                tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL;
                cfg->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp );
                zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS );

                tmp = ZONE_CLEARANCE_MIL;
                cfg->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp );
                zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS );

                tmp = ZONE_THICKNESS_MIL;
                cfg->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp );
                zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS );

                zoneInfo.m_CurrentZone_Layer = zone->GetLayer();

                if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT )
                {
                    zoneInfo.SetIsKeepout( true );
                    // Netcode, netname and some other settings are irrelevant,
                    // so ensure they are cleared
                    zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
                    zoneInfo.SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
                    zoneInfo.SetCornerRadius( 0 );

                    edited = InvokeKeepoutAreaEditor( this, &zoneInfo );
                }
                else
                {
                    zoneInfo.SetIsKeepout( false );
                    edited = InvokeCopperZonesEditor( this, &zoneInfo );
                }
            }
            else   // Put a zone on a non copper layer (technical layer)
            {
                zoneInfo.SetIsKeepout( false );
                zoneInfo.m_NetcodeSelection = 0;     // No net for non copper zones
                edited = InvokeNonCopperZonesEditor( this, zone, &zoneInfo );
            }

            m_canvas->MoveCursorToCrossHair();
            m_canvas->SetIgnoreMouseEvents( false );

            if( edited == ZONE_ABORT )
            {
                GetBoard()->m_CurrentZoneContour = NULL;
                delete zone;
                return 0;
            }

            // Switch active layer to the selected zone layer
            SetActiveLayer( zoneInfo.m_CurrentZone_Layer );
            SetZoneSettings( zoneInfo );
        }
        else
        {
            // Start a new contour: init zone params (net and layer) from an existing
            // zone (add cutout or similar zone)

            zoneInfo.m_CurrentZone_Layer = s_CurrentZone->GetLayer();
            SetActiveLayer( s_CurrentZone->GetLayer() );

            zoneInfo << *s_CurrentZone;

            SetZoneSettings( zoneInfo );
        }

        // Show the Net for zones on copper layers
        if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) &&
            !zoneInfo.GetIsKeepout() )
        {
            if( s_CurrentZone )
            {
                zoneInfo.m_NetcodeSelection = s_CurrentZone->GetNetCode();
                GetBoard()->SetZoneSettings( zoneInfo );
            }

            if( GetBoard()->IsHighLightNetON() )
            {
                HighLight( DC );    // Remove old highlight selection
            }

            GetBoard()->SetHighLightNet( zoneInfo.m_NetcodeSelection );
            HighLight( DC );
        }

        if( !s_AddCutoutToCurrentZone )
            s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command)
    }

    // if first segment
    if( zone->GetNumCorners() == 0 )
    {
        zoneInfo.ExportSetting( *zone );

        zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer,
                                GetCrossHairPosition().x,
                                GetCrossHairPosition().y,
                                zone->GetHatchStyle() );

        zone->AppendCorner( GetCrossHairPosition() );

        if( g_Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() )
        {
            zone->ClearFlags();
            zone->RemoveAllContours();

            // use the form of SetCurItem() which does not write to the msg panel,
            // SCREEN::SetCurItem(), so the DRC error remains on screen.
            // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo().
            GetScreen()->SetCurItem( NULL );
            DisplayError( this,
                          _( "DRC error: this start point is inside or too close an other area" ) );
            return 0;
        }

        SetCurItem( zone );
        m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline );
    }
    else    // edge in progress:
    {
        ii = zone->GetNumCorners() - 1;

        // edge in progress : the current corner coordinate was set
        // by Show_New_Edge_While_Move_Mouse
        if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) )
        {
            if( !g_Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) )
            {
                // Ok, we can add a new corner
                if( m_canvas->IsMouseCaptured() )
                    m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
                zone->AppendCorner( GetCrossHairPosition() );
                SetCurItem( zone );     // calls DisplayInfo().
                if( m_canvas->IsMouseCaptured() )
                    m_canvas->CallMouseCapture( DC, wxPoint(0,0), false );
            }
        }
    }

    return zone->GetNumCorners();
}
Beispiel #14
0
void PCB_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
{
    int     rowCount;
    int     menuId = event.GetId();
    bool    visible;
    bool    force_active_layer_visible;

    m_alwaysShowActiveCopperLayer = ( menuId == ID_ALWAYS_SHOW_NO_COPPER_LAYERS_BUT_ACTIVE );
    force_active_layer_visible = ( menuId == ID_SHOW_NO_COPPER_LAYERS_BUT_ACTIVE ||
            menuId == ID_ALWAYS_SHOW_NO_COPPER_LAYERS_BUT_ACTIVE );

    switch( menuId )
    {
        case ID_SHOW_NO_LAYERS:
        case ID_SHOW_ALL_LAYERS:
            {
                visible = ( menuId == ID_SHOW_ALL_LAYERS );
                rowCount = GetLayerRowCount();

                for( int row=0;  row<rowCount;  ++row )
                {
                    bool isLast;
                    wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
                    PCB_LAYER_ID    layer = ToLAYER_ID( getDecodedId( cb->GetId() ) );
                    cb->SetValue( visible );

                    isLast = row == rowCount-1;

                    OnLayerVisible( layer, visible, isLast );

                    if( isLast )
                        break;
                }
                break;
            }

        case ID_SHOW_ALL_COPPER_LAYERS:
        case ID_ALWAYS_SHOW_NO_COPPER_LAYERS_BUT_ACTIVE:
        case ID_SHOW_NO_COPPER_LAYERS_BUT_ACTIVE:
        case ID_SHOW_NO_COPPER_LAYERS:
        case ID_HIDE_ALL_NON_COPPER:
        case ID_SHOW_ALL_NON_COPPER:
            {

                // Search the last copper layer row index:
                int lastCu = -1;
                rowCount = GetLayerRowCount();
                for( int row = rowCount-1; row>=0; --row )
                {
                    wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
                    PCB_LAYER_ID    layer = ToLAYER_ID( getDecodedId( cb->GetId() ) );

                    if( IsCopperLayer( layer ) )
                    {
                        lastCu = row;
                        break;
                    }
                }

                // Enable/disable the copper layers visibility:
                int startrow = 0;

                if(     ( menuId == ID_SHOW_ALL_NON_COPPER ) ||
                        ( menuId == ID_HIDE_ALL_NON_COPPER ) )
                {
                    startrow = lastCu + 1;
                }

                for( int row = startrow;  row<rowCount;  ++row )
                {
                    wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
                    PCB_LAYER_ID    layer = ToLAYER_ID( getDecodedId( cb->GetId() ) );

                    visible = ( ( menuId == ID_SHOW_ALL_COPPER_LAYERS ) || ( menuId == ID_SHOW_ALL_NON_COPPER ) );

                    if( force_active_layer_visible && (layer == myframe->GetActiveLayer() ) )
                        visible = true;

                    cb->SetValue( visible );

                    bool isLastLayer = (row == lastCu);

                    if(     ( menuId == ID_SHOW_ALL_NON_COPPER ) ||
                            ( menuId == ID_HIDE_ALL_NON_COPPER ) )
                    {
                        isLastLayer = false;
                    }
                    OnLayerVisible( layer, visible, isLastLayer );

                    if( isLastLayer )
                        break;
                }
                break;
            }

        case ID_SHOW_ALL_FRONT:
            {
                visible = false;
                rowCount = GetLayerRowCount();

                for( int row=0;  row<rowCount;  ++row )
                {
                    bool isLast;
                    wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
                    PCB_LAYER_ID    layer = ToLAYER_ID( getDecodedId( cb->GetId() ) );
                    isLast = ( row == rowCount-1 );

                    if(  layer == F_Paste || layer == F_SilkS ||
                         layer == F_Mask  || layer == F_Cu ||
                         layer == F_Fab || layer == F_CrtYd  || layer == Edge_Cuts )
                    {
                        visible = true;
                    }
                    else
                    {
                        visible = false;
                    }

                    cb->SetValue( visible );
                    OnLayerVisible( layer, visible, isLast );

                    if( isLast )
                        break;
                }
                break;
            }
        case ID_SHOW_ALL_BACK:
            {
                visible = false;
                rowCount = GetLayerRowCount();

                for( int row=0;  row<rowCount;  ++row )
                {
                    bool isLast;
                    wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
                    PCB_LAYER_ID    layer = ToLAYER_ID( getDecodedId( cb->GetId() ) );
                    isLast = ( row == rowCount-1 );

                    if( layer == B_Paste || layer == B_SilkS ||
                        layer == B_Mask  || layer == B_Cu ||
                        layer == B_Fab || layer == B_CrtYd || layer == Edge_Cuts )
                    {
                        visible = true;
                    }
                    else
                    {
                        visible = false;
                    }

                    cb->SetValue( visible );
                    OnLayerVisible( layer, visible, isLast );

                    if( isLast )
                        break;
                }
                break;
            }
    }
}
Beispiel #15
0
void PCB_EDIT_FRAME::SwitchLayer( wxDC* DC, LAYER_NUM layer )
{
    LAYER_NUM curLayer = getActiveLayer();

    // Check if the specified layer matches the present layer
    if( layer == curLayer )
        return;

    // Copper layers cannot be selected unconditionally; how many
    // of those layers are currently enabled needs to be checked.
    if( IsCopperLayer( layer ) )
    {
        // If only one copper layer is enabled, the only such layer
        // that can be selected to is the "Back" layer (so the
        // selection of any other copper layer is disregarded).
        if( GetBoard()->GetCopperLayerCount() < 2 )
        {
            if( layer != LAYER_N_BACK )
                return;
        }
        // If more than one copper layer is enabled, the "Copper"
        // and "Component" layers can be selected, but the total
        // number of copper layers determines which internal
        // layers are also capable of being selected.
        else
        {
            if( ( layer != LAYER_N_BACK ) && ( layer != LAYER_N_FRONT )
               && ( layer >= GetBoard()->GetCopperLayerCount() - 1 ) )
                return;
        }

        EDA_ITEM* current = GetScreen()->GetCurItem();

        // See if we are drawing a segment; if so, add a via?
        if( GetToolId() == ID_TRACK_BUTT && current != NULL )
        {
            if( current->Type() == PCB_TRACE_T && ( current->IsNew() ) )
            {
                // Want to set the routing layers so that it switches properly -
                // see the implementation of Other_Layer_Route - the working
                // layer is used to 'start' the via and set the layer masks appropriately.
                GetScreen()->m_Route_Layer_TOP    = curLayer;
                GetScreen()->m_Route_Layer_BOTTOM = layer;

                setActiveLayer( curLayer );

                if( Other_Layer_Route( (TRACK*) GetScreen()->GetCurItem(), DC ) )
                {
                    if( DisplayOpt.ContrastModeDisplay )
                        m_canvas->Refresh();
                }

                // if the via was allowed by DRC, then the layer swap has already
                // been done by Other_Layer_Route(). if via not allowed, then
                // return now so assignment to setActiveLayer() below doesn't happen.
                return;
            }
        }
    }

    // Is yet more checking required? E.g. when the layer to be selected
    // is a non-copper layer, or when switching between a copper layer
    // and a non-copper layer, or vice-versa?
    // ...

    setActiveLayer( layer );

    if( DisplayOpt.ContrastModeDisplay )
        m_canvas->Refresh();
}
bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT*& aGraphic,
                                boost::optional<VECTOR2D> aStartingPoint )
{
    // Only two shapes are currently supported
    assert( aShape == S_SEGMENT || aShape == S_CIRCLE );

    DRAWSEGMENT line45;

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();

    bool direction45 = false;       // 45 degrees only mode
    bool started = false;
    VECTOR2I cursorPos = m_controls->GetCursorPosition();

    if( aStartingPoint )
    {
        LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

        // Init the new item attributes
        aGraphic->SetShape( (STROKE_T) aShape );
        aGraphic->SetWidth( m_lineWidth );
        aGraphic->SetStart( wxPoint( aStartingPoint->x, aStartingPoint->y ) );
        aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
        aGraphic->SetLayer( layer );

        if( aShape == S_SEGMENT )
            line45 = *aGraphic; // used only for direction 45 mode with lines

        preview.Add( aGraphic );
        m_controls->SetAutoPan( true );
        m_controls->CaptureCursor( true );

        started = true;
    }

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        bool updatePreview = false;            // should preview be updated
        cursorPos = m_controls->GetCursorPosition();

        // Enable 45 degrees lines only mode by holding control
        if( direction45 != evt->Modifier( MD_CTRL ) && started && aShape == S_SEGMENT )
        {
            direction45 = evt->Modifier( MD_CTRL );

            if( direction45 )
            {
                preview.Add( &line45 );
                make45DegLine( aGraphic, &line45 );
            }
            else
            {
                preview.Remove( &line45 );
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
            }

            updatePreview = true;
        }

        if( evt->IsCancel() || evt->IsActivate() || evt->IsAction( &COMMON_ACTIONS::layerChanged ) )
        {
            preview.Clear();
            updatePreview = true;
            delete aGraphic;
            aGraphic = NULL;
            break;
        }

        else if( evt->IsClick( BUT_LEFT ) )
        {
            if( !started )
            {
                LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

                if( IsCopperLayer( layer ) )
                {
                    DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
                }
                else
                {
                    // Init the new item attributes
                    aGraphic->SetShape( (STROKE_T) aShape );
                    m_lineWidth = getSegmentWidth( layer );
                    aGraphic->SetWidth( m_lineWidth );
                    aGraphic->SetStart( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetLayer( layer );

                    if( aShape == S_SEGMENT )
                        line45 = *aGraphic; // used only for direction 45 mode with lines

                    preview.Add( aGraphic );
                    m_controls->SetAutoPan( true );
                    m_controls->CaptureCursor( true );

                    started = true;
                }
            }
            else
            {
                if( aGraphic->GetEnd() != aGraphic->GetStart() )
                {
                    assert( aGraphic->GetLength() > 0 );
                    assert( aGraphic->GetWidth() > 0 );

                    m_view->Add( aGraphic );
                    aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
                }
                else                            // User has clicked twice in the same spot
                {                               // a clear sign that the current drawing is finished
                    delete aGraphic;            // but only if at least one graphic was created
                    aGraphic = NULL;            // otherwise - force user to draw more or cancel
                }

                preview.Clear();
                break;
            }
        }

        else if( evt->IsMotion() )
        {
            // 45 degree lines
            if( direction45 && aShape == S_SEGMENT )
                make45DegLine( aGraphic, &line45 );
            else
                aGraphic->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );

            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) )
        {
            m_lineWidth += WIDTH_STEP;
            aGraphic->SetWidth( m_lineWidth );
            updatePreview = true;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) )
        {
            if( m_lineWidth > (unsigned) WIDTH_STEP )
            {
                m_lineWidth -= WIDTH_STEP;
                aGraphic->SetWidth( m_lineWidth );
                updatePreview = true;
            }
        }

        if( updatePreview )
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    }

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    return started;
}
void D_PAD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDraw_mode,
                  const wxPoint& aOffset )
{
    wxSize mask_margin;   // margin (clearance) used for some non copper layers

#ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
    int    showActualMaskSize = 0;  /* Layer number if the actual pad size on mask layer can
                                     * be displayed i.e. if only one layer is shown for this pad
                                     * and this layer is a mask (solder mask or solder paste
                                     */
#endif

    if( m_Flags & DO_NOT_DRAW )
        return;

    PAD_DRAWINFO drawInfo;

    drawInfo.m_Offset = aOffset;

    /* We can show/hide pads from the layer manager.
     * options are show/hide pads on front and/or back side of the board
     * For through pads, we hide them only if both sides are hidden.
     * smd pads on back are hidden for all layers (copper and technical layers)
     * on back side of the board
     * smd pads on front are hidden for all layers (copper and technical layers)
     * on front side of the board
     * ECO, edge and Draw layers and not considered
     */

    BOARD* brd = GetBoard();
    bool   frontVisible = brd->IsElementVisible( PCB_VISIBLE( PAD_FR_VISIBLE ) );
    bool   backVisible  = brd->IsElementVisible( PCB_VISIBLE( PAD_BK_VISIBLE ) );

    if( !frontVisible && !backVisible )
        return;

    // If pad is only on front side (no layer on back side)
    // and if hide front side pads is enabled, do not draw
    if( !frontVisible && !( m_layerMask & LSET::BackMask() ).any() )
        return;

    // If pad is only on back side (no layer on front side)
    // and if hide back side pads is enabled, do not draw
    if( !backVisible && !( m_layerMask & LSET::FrontMask() ).any() )
        return;

    PCB_BASE_FRAME* frame  = (PCB_BASE_FRAME*) aPanel->GetParent();

    wxCHECK_RET( frame != NULL, wxT( "Panel has no parent frame window." ) );

    DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions();
    PCB_SCREEN*     screen = frame->GetScreen();

    if( displ_opts && displ_opts->m_DisplayPadFill == SKETCH )
        drawInfo.m_ShowPadFilled = false;
    else
        drawInfo.m_ShowPadFilled = true;

    EDA_COLOR_T color = BLACK;

    if( m_layerMask[F_Cu] )
    {
        color = brd->GetVisibleElementColor( PAD_FR_VISIBLE );
    }

    if( m_layerMask[B_Cu] )
    {
        color = ColorMix( color, brd->GetVisibleElementColor( PAD_BK_VISIBLE ) );
    }

    if( color == BLACK ) // Not on a visible copper layer (i.e. still nothing to show)
    {
        // If the pad is on only one tech layer, use the layer color else use DARKGRAY
        LSET mask_non_copper_layers = m_layerMask & ~LSET::AllCuMask();

#ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
        mask_non_copper_layers &= brd->GetVisibleLayers();
#endif
        LAYER_ID pad_layer = mask_non_copper_layers.ExtractLayer();

        switch( (int) pad_layer )
        {
        case UNDEFINED_LAYER:   // More than one layer
            color = DARKGRAY;
            break;

        case UNSELECTED_LAYER:  // Shouldn't really happen...
            break;

        default:
            color = brd->GetLayerColor( pad_layer );
#ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
            showActualMaskSize = pad_layer;
#endif
        }
    }

    // if SMD or connector pad and high contrast mode
    if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
        ( GetAttribute() == PAD_SMD || GetAttribute() == PAD_CONN ) &&
        displ_opts && displ_opts->m_ContrastModeDisplay )
    {
        // when routing tracks
        if( frame->GetToolId() == ID_TRACK_BUTT )
        {
            LAYER_ID routeTop = screen->m_Route_Layer_TOP;
            LAYER_ID routeBot = screen->m_Route_Layer_BOTTOM;

            // if routing between copper and component layers,
            // or the current layer is one of said 2 external copper layers,
            // then highlight only the current layer.
            if( ( screen->m_Active_Layer == F_Cu || screen->m_Active_Layer == B_Cu ) ||
                ( routeTop==F_Cu && routeBot==B_Cu ) ||
                ( routeTop==B_Cu && routeBot==F_Cu )
                )
            {
                if( !IsOnLayer( screen->m_Active_Layer ) )
                    ColorTurnToDarkDarkGray( &color );
            }
            // else routing between an internal signal layer and some other
            // layer.  Grey out all PAD_SMD pads not on current or the single
            // selected external layer.
            else if( !IsOnLayer( screen->m_Active_Layer )
                    && !IsOnLayer( routeTop )
                    && !IsOnLayer( routeBot ) )
            {
                ColorTurnToDarkDarkGray( &color );
            }
        }
        // when not edting tracks, show PAD_SMD components not on active layer
        // as greyed out
        else
        {
            if( !IsOnLayer( screen->m_Active_Layer ) )
                ColorTurnToDarkDarkGray( &color );
        }
    }

#ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
    if( showActualMaskSize )
    {
        switch( showActualMaskSize )
        {
        case B_Mask:
        case F_Mask:
            mask_margin.x = mask_margin.y = GetSolderMaskMargin();
            break;

        case B_Paste:
        case F_Paste:
            mask_margin = GetSolderPasteMargin();
            break;

        default:
            // Another layer which has no margin to handle
            break;
        }
    }
#endif

    // if Contrast mode is ON and a technical layer active, show pads on this
    // layer so we can see pads on paste or solder layer and the size of the
    // mask
    if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
        displ_opts && displ_opts->m_ContrastModeDisplay && !IsCopperLayer( screen->m_Active_Layer ) )
    {
        if( IsOnLayer( screen->m_Active_Layer ) )
        {
            color = brd->GetLayerColor( screen->m_Active_Layer );

            // In high contrast mode, and if the active layer is the mask
            // layer shows the pad size with the mask clearance
            switch( screen->m_Active_Layer )
            {
            case B_Mask:
            case F_Mask:
                mask_margin.x = mask_margin.y = GetSolderMaskMargin();
                break;

            case B_Paste:
            case F_Paste:
                mask_margin = GetSolderPasteMargin();
                break;

            default:
                break;
            }
        }
        else
            color = DARKDARKGRAY;
    }


    if( aDraw_mode & GR_HIGHLIGHT )
        ColorChangeHighlightFlag( &color, !(aDraw_mode & GR_AND) );

    ColorApplyHighlightFlag( &color );

    bool DisplayIsol = displ_opts && displ_opts->m_DisplayPadIsol;

    if( !( m_layerMask & LSET::AllCuMask() ).any() )
        DisplayIsol = false;

    if( ( GetAttribute() == PAD_HOLE_NOT_PLATED ) &&
        brd->IsElementVisible( NON_PLATED_VISIBLE ) )
    {
        drawInfo.m_ShowNotPlatedHole = true;
        drawInfo.m_NPHoleColor = brd->GetVisibleElementColor( NON_PLATED_VISIBLE );
    }

    drawInfo.m_DrawMode    = aDraw_mode;
    drawInfo.m_Color       = color;
    drawInfo.m_DrawPanel   = aPanel;
    drawInfo.m_Mask_margin = mask_margin;
    drawInfo.m_ShowNCMark  = brd->IsElementVisible( PCB_VISIBLE( NO_CONNECTS_VISIBLE ) );
    drawInfo.m_IsPrinting  = screen->m_IsPrinting;
    SetAlpha( &color, 170 );

    /* Get the pad clearance. This has a meaning only for Pcbnew.
     *  for CvPcb GetClearance() creates debug errors because
     *  there is no net classes so a call to GetClearance() is made only when
     *   needed (never needed in CvPcb)
     */
    drawInfo.m_PadClearance = DisplayIsol ? GetClearance() : 0;

    // Draw the pad number
    if( displ_opts && !displ_opts->m_DisplayPadNum )
        drawInfo.m_Display_padnum = false;

    if( displ_opts &&
        (( displ_opts ->m_DisplayNetNamesMode == 0 ) || ( displ_opts->m_DisplayNetNamesMode == 2 )) )
        drawInfo.m_Display_netname = false;

    // Display net names is restricted to pads that are on the active layer
    // in high contrast mode display
    if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
        !IsOnLayer( screen->m_Active_Layer ) && displ_opts && displ_opts->m_ContrastModeDisplay )
        drawInfo.m_Display_netname = false;

    DrawShape( aPanel->GetClipBox(), aDC, drawInfo );
}
/* tests to see if this object is on the given layer.
 * DRC markers are not really on a copper layer, but
 * MARKER_PCB::IsOnCopperLayer return true if aLayer is a cooper layer,
 * because this test is often used to locad a marker
 * param aLayer The layer to test for.
 * return bool - true if on given layer, else false.
 */
bool MARKER_PCB::IsOnLayer( LAYER_ID aLayer ) const
{
    return IsCopperLayer( aLayer );
}
int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent )
{
    DIMENSION* dimension = NULL;
    int width, maxThickness;

    // if one day it is possible to draw dimensions in the footprint editor,
    // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet
    assert( !m_editModules );

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();
    m_frame->SetToolID( ID_PCB_DIMENSION_BUTT, wxCURSOR_PENCIL, _( "Add dimension" ) );

    enum DIMENSION_STEPS
    {
        SET_ORIGIN = 0,
        SET_END,
        SET_HEIGHT,
        FINISHED
    };
    int step = SET_ORIGIN;

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        VECTOR2I cursorPos = m_controls->GetCursorPosition();

        if( evt->IsCancel() || evt->IsActivate() )
        {
            if( step != SET_ORIGIN )    // start from the beginning
            {
                preview.Clear();
                preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );

                delete dimension;
                step = SET_ORIGIN;
            }
            else
                break;

            if( evt->IsActivate() )  // now finish unconditionally
                break;
        }

        else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) && step != SET_ORIGIN )
        {
            dimension->SetWidth( dimension->GetWidth() + WIDTH_STEP );
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) && step != SET_ORIGIN )
        {
            int width = dimension->GetWidth();

            if( width > WIDTH_STEP )
            {
                dimension->SetWidth( width - WIDTH_STEP );
                preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            }
        }

        else if( evt->IsClick( BUT_LEFT ) )
        {
            switch( step )
            {
            case SET_ORIGIN:
                {
                    LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

                    if( IsCopperLayer( layer ) || layer == Edge_Cuts )
                    {
                        DisplayInfoMessage( NULL, _( "Dimension not allowed on Copper or Edge Cut layers" ) );
                        --step;
                    }
                    else
                    {
                        // Init the new item attributes
                        dimension = new DIMENSION( m_board );
                        dimension->SetLayer( layer );
                        dimension->SetOrigin( wxPoint( cursorPos.x, cursorPos.y ) );
                        dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                        dimension->Text().SetSize( m_board->GetDesignSettings().m_PcbTextSize );

                        width = m_board->GetDesignSettings().m_PcbTextWidth;
                        maxThickness = Clamp_Text_PenSize( width, dimension->Text().GetSize() );

                        if( width > maxThickness )
                            width = maxThickness;

                        dimension->Text().SetThickness( width );
                        dimension->SetWidth( width );
                        dimension->AdjustDimensionDetails();

                        preview.Add( dimension );

                        m_controls->SetAutoPan( true );
                        m_controls->CaptureCursor( true );
                    }
                }
                break;

            case SET_END:
                dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );

                // Dimensions that have origin and end in the same spot are not valid
                if( dimension->GetOrigin() == dimension->GetEnd() )
                    --step;
                break;

            case SET_HEIGHT:
                {
                    if( wxPoint( cursorPos.x, cursorPos.y ) != dimension->GetPosition() )
                    {
                        assert( dimension->GetOrigin() != dimension->GetEnd() );
                        assert( dimension->GetWidth() > 0 );

                        m_view->Add( dimension );
                        m_board->Add( dimension );
                        dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );

                        m_frame->OnModify();
                        m_frame->SaveCopyInUndoList( dimension, UR_NEW );

                        preview.Remove( dimension );
                    }
                }
                break;
            }

            if( ++step == FINISHED )
            {
                step = SET_ORIGIN;
                m_controls->SetAutoPan( false );
                m_controls->CaptureCursor( false );
            }
        }

        else if( evt->IsMotion() )
        {
            switch( step )
            {
            case SET_END:
                dimension->SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                break;

            case SET_HEIGHT:
            {
                // Calculating the direction of travel perpendicular to the selected axis
                double angle = dimension->GetAngle() + ( M_PI / 2 );

                wxPoint pos( cursorPos.x, cursorPos.y );
                wxPoint delta( pos - dimension->m_featureLineDO );
                double height  = ( delta.x * cos( angle ) ) + ( delta.y * sin( angle ) );
                dimension->SetHeight( height );
            }
            break;
            }

            // Show a preview of the item
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }
    }

    if( step != SET_ORIGIN )
        delete dimension;

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );

    return 0;
}
PCB_DRAW_PANEL_GAL::PCB_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId,
                                        const wxPoint& aPosition, const wxSize& aSize,
                                        GalType aGalType ) :
EDA_DRAW_PANEL_GAL( aParentWindow, aWindowId, aPosition, aSize, aGalType )
{
    m_worksheet = NULL;
    m_ratsnest = NULL;

    // Set rendering order and properties of layers
    for( LAYER_NUM i = 0; (unsigned) i < sizeof(GAL_LAYER_ORDER) / sizeof(LAYER_NUM); ++i )
    {
        LAYER_NUM layer = GAL_LAYER_ORDER[i];
        wxASSERT( layer < KIGFX::VIEW::VIEW_MAX_LAYERS );

        m_view->SetLayerOrder( layer, i );

        if( IsCopperLayer( layer ) )
        {
            // Copper layers are required for netname layers
            m_view->SetRequired( GetNetnameLayer( layer ), layer );
            m_view->SetLayerTarget( layer, KIGFX::TARGET_CACHED );
        }
        else if( IsNetnameLayer( layer ) )
        {
            // Netnames are drawn only when scale is sufficient (level of details)
            // so there is no point in caching them
            m_view->SetLayerTarget( layer, KIGFX::TARGET_NONCACHED );
            m_view->SetLayerDisplayOnly( layer );
        }
    }

    m_view->SetLayerTarget( ITEM_GAL_LAYER( ANCHOR_VISIBLE ), KIGFX::TARGET_NONCACHED );
    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( ANCHOR_VISIBLE ) );

    // Some more required layers settings
    m_view->SetRequired( ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( VIA_THROUGH_VISIBLE ) );
    m_view->SetRequired( ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) );
    m_view->SetRequired( NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) );

    // Front modules
    m_view->SetRequired( ITEM_GAL_LAYER( PAD_FR_VISIBLE ), ITEM_GAL_LAYER( MOD_FR_VISIBLE ) );
    m_view->SetRequired( ITEM_GAL_LAYER( MOD_TEXT_FR_VISIBLE ), ITEM_GAL_LAYER( MOD_FR_VISIBLE ) );
    m_view->SetRequired( NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    m_view->SetRequired( F_Adhes, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    m_view->SetRequired( F_Paste, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    m_view->SetRequired( F_Mask, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    m_view->SetRequired( F_CrtYd, ITEM_GAL_LAYER( MOD_FR_VISIBLE ) );
    m_view->SetRequired( F_Fab, ITEM_GAL_LAYER( MOD_FR_VISIBLE ) );

    // Back modules
    m_view->SetRequired( ITEM_GAL_LAYER( PAD_BK_VISIBLE ), ITEM_GAL_LAYER( MOD_BK_VISIBLE ) );
    m_view->SetRequired( ITEM_GAL_LAYER( MOD_TEXT_BK_VISIBLE ), ITEM_GAL_LAYER( MOD_BK_VISIBLE ) );
    m_view->SetRequired( NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    m_view->SetRequired( B_Adhes, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    m_view->SetRequired( B_Paste, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    m_view->SetRequired( B_Mask, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    m_view->SetRequired( B_CrtYd, ITEM_GAL_LAYER( MOD_BK_VISIBLE ) );
    m_view->SetRequired( B_Fab, ITEM_GAL_LAYER( MOD_BK_VISIBLE ) );

    m_view->SetLayerTarget( ITEM_GAL_LAYER( GP_OVERLAY ), KIGFX::TARGET_OVERLAY );
    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( GP_OVERLAY ) );
    m_view->SetLayerTarget( ITEM_GAL_LAYER( RATSNEST_VISIBLE ), KIGFX::TARGET_OVERLAY );
    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( RATSNEST_VISIBLE ) );

    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( WORKSHEET ) );
    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( GRID_VISIBLE ) );
    m_view->SetLayerDisplayOnly( ITEM_GAL_LAYER( DRC_VISIBLE ) );

    // Load display options (such as filled/outline display of items).
    // Can be made only if the parent windos is a EDA_DRAW_FRAME (or a derived class)
    // which is not always the case (namely when it is used from a wxDialog like the pad editor)
    EDA_DRAW_FRAME* frame = dynamic_cast<EDA_DRAW_FRAME*>( aParentWindow );

    if( frame )
    {
        DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*) frame->GetDisplayOptions();
        static_cast<KIGFX::PCB_RENDER_SETTINGS*>( m_view->GetPainter()->GetSettings() )->LoadDisplayOptions( displ_opts );
    }
}
bool DRAWING_TOOL::drawArc( DRAWSEGMENT*& aGraphic )
{
    bool clockwise = true;      // drawing direction of the arc
    double startAngle = 0.0f;   // angle of the first arc line
    VECTOR2I cursorPos = m_controls->GetCursorPosition();

    DRAWSEGMENT helperLine;
    helperLine.SetShape( S_SEGMENT );
    helperLine.SetLayer( Dwgs_User );
    helperLine.SetWidth( 1 );

    // Add a VIEW_GROUP that serves as a preview for the new item
    KIGFX::VIEW_GROUP preview( m_view );
    m_view->Add( &preview );

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_controls->ShowCursor( true );
    m_controls->SetSnapping( true );

    Activate();

    enum ARC_STEPS
    {
        SET_ORIGIN = 0,
        SET_END,
        SET_ANGLE,
        FINISHED
    };
    int step = SET_ORIGIN;

    // Main loop: keep receiving events
    while( OPT_TOOL_EVENT evt = Wait() )
    {
        cursorPos = m_controls->GetCursorPosition();

        if( evt->IsCancel() || evt->IsActivate() )
        {
            preview.Clear();
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            delete aGraphic;
            aGraphic = NULL;
            break;
        }

        else if( evt->IsClick( BUT_LEFT ) )
        {
            switch( step )
            {
            case SET_ORIGIN:
            {
                LAYER_ID layer = m_frame->GetScreen()->m_Active_Layer;

                if( IsCopperLayer( layer ) )
                {
                    DisplayInfoMessage( NULL, _( "Graphic not allowed on Copper layers" ) );
                    --step;
                }
                else
                {
                    // Init the new item attributes
                    aGraphic->SetShape( S_ARC );
                    aGraphic->SetAngle( 0.0 );
                    aGraphic->SetWidth( getSegmentWidth( layer ) );
                    aGraphic->SetCenter( wxPoint( cursorPos.x, cursorPos.y ) );
                    aGraphic->SetLayer( layer );

                    helperLine.SetStart( aGraphic->GetCenter() );
                    helperLine.SetEnd( aGraphic->GetCenter() );

                    preview.Add( aGraphic );
                    preview.Add( &helperLine );

                    m_controls->SetAutoPan( true );
                    m_controls->CaptureCursor( true );
                }
            }
            break;

            case SET_END:
            {
                if( wxPoint( cursorPos.x, cursorPos.y ) != aGraphic->GetCenter() )
                {
                    VECTOR2D startLine( aGraphic->GetArcStart() - aGraphic->GetCenter() );
                    startAngle = startLine.Angle();
                    aGraphic->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
                }
                else
                    --step;     // one another chance to draw a proper arc
            }
            break;

            case SET_ANGLE:
            {
                if( wxPoint( cursorPos.x, cursorPos.y ) != aGraphic->GetArcStart() && aGraphic->GetAngle() != 0 )
                {
                    assert( aGraphic->GetArcStart() != aGraphic->GetArcEnd() );
                    assert( aGraphic->GetWidth() > 0 );

                    m_view->Add( aGraphic );
                    aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );

                    preview.Remove( aGraphic );
                    preview.Remove( &helperLine );
                }
                else
                    --step;     // one another chance to draw a proper arc
            }
            break;
            }

            if( ++step == FINISHED )
                break;
        }

        else if( evt->IsMotion() )
        {
            switch( step )
            {
            case SET_END:
                helperLine.SetEnd( wxPoint( cursorPos.x, cursorPos.y ) );
                aGraphic->SetArcStart( wxPoint( cursorPos.x, cursorPos.y ) );
                break;

            case SET_ANGLE:
            {
                VECTOR2D endLine( wxPoint( cursorPos.x, cursorPos.y ) - aGraphic->GetCenter() );
                double newAngle = RAD2DECIDEG( endLine.Angle() - startAngle );

                // Adjust the new angle to (counter)clockwise setting
                if( clockwise && newAngle < 0.0 )
                    newAngle += 3600.0;
                else if( !clockwise && newAngle > 0.0 )
                    newAngle -= 3600.0;

                aGraphic->SetAngle( newAngle );
            }
            break;
            }

            // Show a preview of the item
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) )
        {
            aGraphic->SetWidth( aGraphic->GetWidth() + WIDTH_STEP );
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) )
        {
            int width = aGraphic->GetWidth();

            if( width > WIDTH_STEP )
            {
                aGraphic->SetWidth( width - WIDTH_STEP );
                preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            }
        }

        else if( evt->IsAction( &COMMON_ACTIONS::arcPosture ) )
        {
            if( clockwise )
                aGraphic->SetAngle( aGraphic->GetAngle() - 3600.0 );
            else
                aGraphic->SetAngle( aGraphic->GetAngle() + 3600.0 );

            clockwise = !clockwise;
            preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }
    }

    m_controls->ShowCursor( false );
    m_controls->SetSnapping( false );
    m_controls->SetAutoPan( false );
    m_controls->CaptureCursor( false );
    m_view->Remove( &preview );

    return ( step > SET_ORIGIN );
}
bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem )
{
    if( !IsCopperLayer( aItem->GetLayer() ) )
        return false;

    markItemNetAsDirty ( aItem );

    switch( aItem->Type() )
    {
    case PCB_NETINFO_T:
        {
            MarkNetAsDirty( static_cast<NETINFO_ITEM*>( aItem )->GetNet() );
            break;
        }
    case PCB_MODULE_T:
        for( auto pad : static_cast<MODULE*>( aItem ) -> Pads() )
        {
            if( m_itemMap.find( pad ) != m_itemMap.end() )
                return false;

            add( m_itemList, pad );
        }

        break;

    case PCB_PAD_T:
        if( m_itemMap.find ( static_cast<D_PAD*>( aItem ) ) != m_itemMap.end() )
            return false;

        add( m_itemList, static_cast<D_PAD*>( aItem ) );

        break;

    case PCB_TRACE_T:
    {
        if( m_itemMap.find( static_cast<TRACK*>( aItem ) ) != m_itemMap.end() )
            return false;

        add( m_itemList, static_cast<TRACK*>( aItem ) );

        break;
    }

    case PCB_VIA_T:
        if( m_itemMap.find( static_cast<VIA*>( aItem ) ) != m_itemMap.end() )
            return false;

        add( m_itemList, static_cast<VIA*>( aItem ) );

        break;

    case PCB_ZONE_AREA_T:
    {
        auto zone = static_cast<ZONE_CONTAINER*>( aItem );

        if( m_itemMap.find( static_cast<ZONE_CONTAINER*>( aItem ) ) != m_itemMap.end() )
            return false;

        m_itemMap[zone] = ITEM_MAP_ENTRY();

        for( auto zitem : m_itemList.Add( zone ) )
            m_itemMap[zone].Link(zitem);

        break;
    }

    default:
        return false;
    }

    return true;
}
ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, bool aIgnorePads,
								 const std::vector<ITEM*> aAvoidItems)
{
    int tl = getView()->GetTopLayer();

    if( aLayer > 0 )
        tl = aLayer;

    static const int candidateCount = 5;
    ITEM* prioritized[candidateCount];
    int dist[candidateCount];

    for( int i = 0; i < candidateCount; i++ )
    {
        prioritized[i] = 0;
        dist[i] = std::numeric_limits<int>::max();
    }

    ITEM_SET candidates = m_router->QueryHoverItems( aWhere );

    for( ITEM* item : candidates.Items() )
    {
        if( !item->IsRoutable() )
            continue;

        if( !IsCopperLayer( item->Layers().Start() ) )
            continue;

        if( std::find( aAvoidItems.begin(), aAvoidItems.end(), item ) != aAvoidItems.end() )
            continue;

        // fixme: this causes flicker with live loop removal...
        //if( item->Parent() && !item->Parent()->ViewIsVisible() )
        //    continue;

        if( aNet <= 0 || item->Net() == aNet )
        {
            if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
            {
                if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
                    continue;

                int itemDist = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();

                if( !prioritized[2] || itemDist < dist[2] )
                {
                    prioritized[2] = item;
                    dist[2] = itemDist;
                }
                if( item->Layers().Overlaps( tl ) &&  itemDist < dist[0] )
                {
                    prioritized[0] = item;
                    dist[0] = itemDist;
                }
            }
            else
            {
                if( !prioritized[3] )
                    prioritized[3] = item;
                if( item->Layers().Overlaps( tl ) )
                    prioritized[1] = item;
            }
        }
        // Allow unconnected items as last resort in RM_MarkObstacles mode
        else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
        {
            if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
                continue;

            if( item->Layers().Overlaps( tl ) )
                prioritized[4] = item;
        }
    }

    ITEM* rv = NULL;

    for( int i = 0; i < candidateCount; i++ )
    {
        ITEM* item = prioritized[i];

        if( displayOptions()->m_ContrastModeDisplay )
            if( item && !item->Layers().Overlaps( tl ) )
                item = NULL;

        if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
        {
            rv = item;
            break;
        }
    }

    if( rv )
    {
        wxLogTrace( "PNS", "%s, layer : %d, tl: %d", rv->KindStr().c_str(), rv->Layers().Start(), tl );
    }

    return rv;
}
Beispiel #24
0
const wxString GetGerberFileFunctionAttribute( const BOARD *aBoard, LAYER_NUM aLayer )
{
    wxString attrib;

    switch( aLayer )
    {
    case F_Adhes:
        attrib = "Glue,Top";
        break;

    case B_Adhes:
        attrib = "Glue,Bot";
        break;

    case F_SilkS:
        attrib = "Legend,Top";
        break;

    case B_SilkS:
        attrib = "Legend,Bot";
        break;

    case F_Mask:
        attrib = "Soldermask,Top";
        break;

    case B_Mask:
        attrib = "Soldermask,Bot";
        break;

    case F_Paste:
        attrib = "Paste,Top";
        break;

    case B_Paste:
        attrib = "Paste,Bot";
        break;

    case Edge_Cuts:
        // Board outline.
        // Can be "Profile,NP" (Not Plated: usual) or "Profile,P"
        // This last is the exception (Plated)
        attrib = "Profile,NP";
        break;

    case Dwgs_User:
        attrib = "Drawing";
        break;

    case Cmts_User:
        attrib = "Other,Comment";
        break;

    case Eco1_User:
        attrib = "Other,ECO1";
        break;

    case Eco2_User:
        attrib = "Other,ECO2";
        break;

    case B_Fab:
        attrib = "Other,Fab,Bot";
        break;

    case F_Fab:
        attrib = "Other,Fab,Top";
        break;

    case B_Cu:
        attrib.Printf( wxT( "Copper,L%d,Bot" ), aBoard->GetCopperLayerCount() );
        break;

    case F_Cu:
        attrib = "Copper,L1,Top";
        break;

    default:
        if( IsCopperLayer( aLayer ) )
            attrib.Printf( wxT( "Copper,L%d,Inr" ), aLayer+1 );
        else
            attrib.Printf( wxT( "Other,User" ), aLayer+1 );
        break;
    }

    // This code adds a optional parameter: the type of copper layers.
    // Because it is not used by Pcbnew (it can be used only by external autorouters)
    // user do not really set this parameter.
    // Therefore do not add it.
    // However, this code is left here, for perhaps a future usage.
#if 0
    // Add the signal type of the layer, if relevant
    if( IsCopperLayer( aLayer ) )
    {
        LAYER_T type = aBoard->GetLayerType( ToLAYER_ID( aLayer ) );

        switch( type )
        {
        case LT_SIGNAL:
            attrib += ",Signal";
            break;
        case LT_POWER:
            attrib += ",Plane";
            break;
        case LT_MIXED:
            attrib += ",Mixed";
            break;
        default:
            break;   // do nothing (but avoid a warning for unhandled LAYER_T values from GCC)
        }
    }
#endif

    wxString fileFct;
    fileFct.Printf( "%%TF.FileFunction,%s*%%", GetChars( attrib ) );

    return fileFct;
}
Beispiel #25
0
void PCB_BASE_FRAME::LoadSettings()
{
    wxASSERT( wxGetApp().GetSettings() != NULL );

    wxConfig* cfg = wxGetApp().GetSettings();

    EDA_DRAW_FRAME::LoadSettings();

    // Ensure grid id is an existent grid id:
    if( (m_LastGridSizeId <= 0) ||
        (m_LastGridSizeId > (ID_POPUP_GRID_USER - ID_POPUP_GRID_LEVEL_1000)) )
        m_LastGridSizeId = ID_POPUP_GRID_LEVEL_500 - ID_POPUP_GRID_LEVEL_1000;

    cfg->Read( m_FrameName + UserGridSizeXEntry, &m_UserGridSize.x, 0.01 );
    cfg->Read( m_FrameName + UserGridSizeYEntry, &m_UserGridSize.y, 0.01 );

    long itmp;
    cfg->Read( m_FrameName + UserGridUnitsEntry, &itmp, ( long )INCHES );
    m_UserGridUnit = (EDA_UNITS_T) itmp;
    cfg->Read( m_FrameName + DisplayPadFillEntry, &m_DisplayPadFill, true );
    cfg->Read( m_FrameName + DisplayViaFillEntry, &m_DisplayViaFill, true );
    cfg->Read( m_FrameName + DisplayPadNumberEntry, &m_DisplayPadNum, true );
    cfg->Read( m_FrameName + DisplayModuleEdgeEntry, &m_DisplayModEdge, ( long )FILLED );

    cfg->Read( m_FrameName + FastGrid1Entry, &itmp, ( long )0);
    m_FastGrid1 = itmp;
    cfg->Read( m_FrameName + FastGrid2Entry, &itmp, ( long )0);
    m_FastGrid2 = itmp;

    if( m_DisplayModEdge < LINE || m_DisplayModEdge > SKETCH )
        m_DisplayModEdge = FILLED;

    cfg->Read( m_FrameName + DisplayModuleTextEntry, &m_DisplayModText, ( long )FILLED );

    if( m_DisplayModText < LINE || m_DisplayModText > SKETCH )
        m_DisplayModText = FILLED;

    // Apply display settings for GAL
    KIGFX::VIEW* view = GetGalCanvas()->GetView();

    // Set rendering order and properties of layers
    for( LAYER_NUM i = 0; (unsigned) i < sizeof(GAL_LAYER_ORDER) / sizeof(LAYER_NUM); ++i )
    {
        LAYER_NUM layer = GAL_LAYER_ORDER[i];
        wxASSERT( layer < KIGFX::VIEW::VIEW_MAX_LAYERS );

        view->SetLayerOrder( layer, i );

        if( IsCopperLayer( layer ) )
        {
            // Copper layers are required for netname layers
            view->SetRequired( GetNetnameLayer( layer ), layer );
            view->SetLayerTarget( layer, KIGFX::TARGET_CACHED );
        }
        else if( IsNetnameLayer( layer ) )
        {
            // Netnames are drawn only when scale is sufficient (level of details)
            // so there is no point in caching them
            view->SetLayerTarget( layer, KIGFX::TARGET_NONCACHED );
        }
    }

    // Some more required layers settings
    view->SetRequired( ITEM_GAL_LAYER( VIAS_HOLES_VISIBLE ), ITEM_GAL_LAYER( VIAS_VISIBLE ) );
    view->SetRequired( ITEM_GAL_LAYER( PADS_HOLES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) );
    view->SetRequired( NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PADS_VISIBLE ) );

    view->SetRequired( NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    view->SetRequired( ADHESIVE_N_FRONT, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    view->SetRequired( SOLDERPASTE_N_FRONT, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );
    view->SetRequired( SOLDERMASK_N_FRONT, ITEM_GAL_LAYER( PAD_FR_VISIBLE ) );

    view->SetRequired( NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE ), ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    view->SetRequired( ADHESIVE_N_BACK, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    view->SetRequired( SOLDERPASTE_N_BACK, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );
    view->SetRequired( SOLDERMASK_N_BACK, ITEM_GAL_LAYER( PAD_BK_VISIBLE ) );

    view->SetLayerTarget( ITEM_GAL_LAYER( GP_OVERLAY ), KIGFX::TARGET_OVERLAY );
    view->SetLayerTarget( ITEM_GAL_LAYER( RATSNEST_VISIBLE ), KIGFX::TARGET_OVERLAY );

    // Apply layer coloring scheme & display options
    if( view->GetPainter() )
    {
        KIGFX::PCB_RENDER_SETTINGS* settings = new KIGFX::PCB_RENDER_SETTINGS();

        // Load layers' colors from PCB data
        settings->ImportLegacyColors( m_Pcb->GetColorsSettings() );
        view->GetPainter()->ApplySettings( settings );

        // Load display options (such as filled/outline display of items)
        settings->LoadDisplayOptions( DisplayOpt );
    }

    // WxWidgets 2.9.1 seems call setlocale( LC_NUMERIC, "" )
    // when reading doubles in config,
    // but forget to back to current locale. So we call SetLocaleTo_Default
    SetLocaleTo_Default( );
}
wxString GetGerberFileFunction( const BOARD *aBoard, LAYER_NUM aLayer )
{
    wxString attrib = wxEmptyString;

    switch( aLayer )
    {
    case F_Adhes:
        attrib = wxString( wxT( "Glue,Top" ) );
        break;

    case B_Adhes:
        attrib = wxString( wxT( "Glue,Bot" ) );
        break;

    case F_SilkS:
        attrib = wxString( wxT( "Legend,Top" ) );
        break;

    case B_SilkS:
        attrib = wxString( wxT( "Legend,Bot" ) );
        break;

    case F_Mask:
        attrib = wxString( wxT( "Soldermask,Top" ) );
        break;

    case B_Mask:
        attrib = wxString( wxT( "Soldermask,Bot" ) );
        break;

    case F_Paste:
        attrib = wxString( wxT( "Paste,Top" ) );
        break;

    case B_Paste:
        attrib = wxString( wxT( "Paste,Bot" ) );
        break;

    case Edge_Cuts:
        // Board outline.
        // Can be "Profile,NP" (Not Plated: usual) or "Profile,P"
        // This last is the exception (Plated)
        attrib = wxString( wxT( "Profile,NP" ) );
        break;

    case Dwgs_User:
        attrib = wxString( wxT( "Drawing" ) );
        break;

    case Cmts_User:
        attrib = wxString( wxT( "Other,Comment" ) );
        break;

    case Eco1_User:
        attrib = wxString( wxT( "Other,ECO1" ) );
        break;

    case Eco2_User:
        attrib = wxString( wxT( "Other,ECO2" ) );
        break;

    case B_Cu:
        attrib = wxString::Format( wxT( "Copper,L%d,Bot" ), aBoard->GetCopperLayerCount() );
        break;

    case F_Cu:
        attrib = wxString::Format( wxT( "Copper,L1,Top" ) );
        break;

    default:
        if( IsCopperLayer( aLayer ) )
        {
            attrib = wxString::Format( wxT( "Copper,L%d,Inr" ), aLayer+1 );
        }
        break;
    }

    // Add the signal type of the layer, if relevant
    if( IsCopperLayer( aLayer ) )
    {
        LAYER_T type = aBoard->GetLayerType( ToLAYER_ID( aLayer ) );

        switch( type )
        {
        case LT_SIGNAL:
            attrib += wxString( wxT( ",Signal" ) );
            break;
        case LT_POWER:
            attrib += wxString( wxT( ",Plane" ) );
            break;
        case LT_MIXED:
            attrib += wxString( wxT( ",Mixed" ) );
            break;
        default:
            ;   // do nothing (but avoid a warning for unhandled LAYER_T values from GCC)
        }
    }

    return attrib;
}
void DRC::testTexts()
{
    std::vector<wxPoint> textShape;      // a buffer to store the text shape (set of segments)
    std::vector<D_PAD*> padList = m_pcb->GetPads();

    // Test text areas for vias, tracks and pads inside text areas
    for( BOARD_ITEM* item = m_pcb->m_Drawings; item; item = item->Next() )
    {
        // Drc test only items on copper layers
        if( ! IsCopperLayer( item->GetLayer() ) )
            continue;

        // only texts on copper layers are tested
        if( item->Type() !=  PCB_TEXT_T )
            continue;

        textShape.clear();

        // So far the bounding box makes up the text-area
        TEXTE_PCB* text = (TEXTE_PCB*) item;
        text->TransformTextShapeToSegmentList( textShape );

        if( textShape.size() == 0 )     // Should not happen (empty text?)
            continue;

        for( TRACK* track = m_pcb->m_Track; track != NULL; track = track->Next() )
        {
            if( ! track->IsOnLayer( item->GetLayer() ) )
                    continue;

            // Test the distance between each segment and the current track/via
            int min_dist = ( track->GetWidth() + text->GetThickness() ) /2 +
                           track->GetClearance(NULL);

            if( track->Type() == PCB_TRACE_T )
            {
                SEG segref( track->GetStart(), track->GetEnd() );

                // Error condition: Distance between text segment and track segment is
                // smaller than the clearance of the segment
                for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
                {
                    SEG segtest( textShape[jj], textShape[jj+1] );
                    int dist = segref.Distance( segtest );

                    if( dist < min_dist )
                    {
                        addMarkerToPcb( fillMarker( track, text,
                                                    DRCE_TRACK_INSIDE_TEXT,
                                                    m_currentMarker ) );
                        m_currentMarker = nullptr;
                        break;
                    }
                }
            }
            else if( track->Type() == PCB_VIA_T )
            {
                // Error condition: Distance between text segment and via is
                // smaller than the clearance of the via
                for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
                {
                    SEG segtest( textShape[jj], textShape[jj+1] );

                    if( segtest.PointCloserThan( track->GetPosition(), min_dist ) )
                    {
                        addMarkerToPcb( fillMarker( track, text,
                                                    DRCE_VIA_INSIDE_TEXT, m_currentMarker ) );
                        m_currentMarker = nullptr;
                        break;
                    }
                }
            }
        }

        // Test pads
        for( unsigned ii = 0; ii < padList.size(); ii++ )
        {
            D_PAD* pad = padList[ii];

            if( ! pad->IsOnLayer( item->GetLayer() ) )
                    continue;

            wxPoint shape_pos = pad->ShapePos();

            for( unsigned jj = 0; jj < textShape.size(); jj += 2 )
            {
                /* In order to make some calculations more easier or faster,
                 * pads and tracks coordinates will be made relative
                 * to the segment origin
                 */
                wxPoint origin = textShape[jj];  // origin will be the origin of other coordinates
                m_segmEnd = textShape[jj+1] - origin;
                wxPoint delta = m_segmEnd;
                m_segmAngle = 0;

                // for a non horizontal or vertical segment Compute the segment angle
                // in tenths of degrees and its length
                if( delta.x || delta.y )    // delta.x == delta.y == 0 for vias
                {
                    // Compute the segment angle in 0,1 degrees
                    m_segmAngle = ArcTangente( delta.y, delta.x );

                    // Compute the segment length: we build an equivalent rotated segment,
                    // this segment is horizontal, therefore dx = length
                    RotatePoint( &delta, m_segmAngle );    // delta.x = length, delta.y = 0
                }

                m_segmLength = delta.x;
                m_padToTestPos = shape_pos - origin;

                if( !checkClearanceSegmToPad( pad, text->GetThickness(),
                                              pad->GetClearance(NULL) ) )
                {
                    addMarkerToPcb( fillMarker( pad, text,
                                                DRCE_PAD_INSIDE_TEXT, m_currentMarker ) );
                    m_currentMarker = nullptr;
                    break;
                }
            }
        }
    }
}
/* Handle the left button mouse click, when a tool is active
 */
void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
{
    BOARD_ITEM* DrawStruct = GetCurItem();
    bool        exit = false;
    bool no_tool = GetToolId() == ID_NO_TOOL_SELECTED;

    if( no_tool || ( DrawStruct && DrawStruct->GetFlags() ) )
    {
        m_canvas->SetAutoPanRequest( false );

        if( DrawStruct && DrawStruct->GetFlags() ) // Command in progress
        {
            m_canvas->SetIgnoreMouseEvents( true );
            m_canvas->CrossHairOff( aDC );

            switch( DrawStruct->Type() )
            {
            case PCB_ZONE_AREA_T:
                if( DrawStruct->IsNew() )
                {
                    m_canvas->SetAutoPanRequest( true );
                    Begin_Zone( aDC );
                }
                else
                {
                    End_Move_Zone_Corner_Or_Outlines( aDC, (ZONE_CONTAINER*) DrawStruct );
                }

                exit = true;
                break;

            case PCB_TRACE_T:
            case PCB_VIA_T:
                if( DrawStruct->IsDragging() )
                {
                    PlaceDraggedOrMovedTrackSegment( (TRACK*) DrawStruct, aDC );
                    exit = true;
                }

                break;

            case PCB_TEXT_T:
                Place_Texte_Pcb( (TEXTE_PCB*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_MODULE_TEXT_T:
                PlaceTexteModule( (TEXTE_MODULE*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_PAD_T:
                PlacePad( (D_PAD*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_MODULE_T:
                PlaceModule( (MODULE*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_TARGET_T:
                PlaceTarget( (PCB_TARGET*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_LINE_T:
                if( no_tool )   // when no tools: existing item moving.
                {
                    Place_DrawItem( (DRAWSEGMENT*) DrawStruct, aDC );
                    exit = true;
                }

                break;

            case PCB_DIMENSION_T:
                if( ! DrawStruct->IsNew() )
                {   // We are moving the text of an existing dimension. Place it
                    PlaceDimensionText( (DIMENSION*) DrawStruct, aDC );
                    exit = true;
                }
                break;

            default:
                DisplayError( this,
                              wxT( "PCB_EDIT_FRAME::OnLeftClick() err: DrawType %d m_Flags != 0" ),
                              DrawStruct->Type() );
                exit = true;
                break;
            }

            m_canvas->SetIgnoreMouseEvents( false );
            m_canvas->CrossHairOn( aDC );

            if( exit )
                return;
        }
        else if( !wxGetKeyState( WXK_SHIFT ) && !wxGetKeyState( WXK_ALT )
                && !wxGetKeyState( WXK_CONTROL ) )
        {
            DrawStruct = PcbGeneralLocateAndDisplay();

            if( DrawStruct )
                SendMessageToEESCHEMA( DrawStruct );
        }
    }

    if( DrawStruct ) // display netclass info for zones, tracks and pads
    {
        switch( DrawStruct->Type() )
        {
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
        case PCB_PAD_T:
            GetDesignSettings().SetCurrentNetClass(
                ((BOARD_CONNECTED_ITEM*)DrawStruct)->GetNetClassName() );
            updateTraceWidthSelectBox();
            updateViaSizeSelectBox();
            break;

        default:
           break;
        }
    }

    switch( GetToolId() )
    {
    case ID_MAIN_MENUBAR:
    case ID_NO_TOOL_SELECTED:
        break;

    case ID_PCB_MUWAVE_TOOL_SELF_CMD:
    case ID_PCB_MUWAVE_TOOL_GAP_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD:
    case ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD:
        MuWaveCommand( aDC, aPosition );
        break;

    case ID_PCB_HIGHLIGHT_BUTT:
    {
        int netcode = SelectHighLight( aDC );

        if( netcode < 0 )
            SetMsgPanel( GetBoard() );
        else
        {
            NETINFO_ITEM* net = GetBoard()->FindNet( netcode );

            if( net )
            {
                MSG_PANEL_ITEMS items;
                net->GetMsgPanelInfo( items );
                SetMsgPanel( items );
            }
        }
    }
    break;

    case ID_PCB_SHOW_1_RATSNEST_BUTT:
        DrawStruct = PcbGeneralLocateAndDisplay();
        Show_1_Ratsnest( DrawStruct, aDC );

        if( DrawStruct )
            SendMessageToEESCHEMA( DrawStruct );

        break;

    case ID_PCB_MIRE_BUTT:
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            SetCurItem( (BOARD_ITEM*) CreateTarget( aDC ) );
            m_canvas->MoveCursorToCrossHair();
        }
        else if( DrawStruct->Type() == PCB_TARGET_T )
        {
            PlaceTarget( (PCB_TARGET*) DrawStruct, aDC );
        }
        else
        {
            DisplayError( this, wxT( "OnLeftClick err: not a PCB_TARGET_T" ) );
        }

        break;

    case ID_PCB_CIRCLE_BUTT:
    case ID_PCB_ARC_BUTT:
    case ID_PCB_ADD_LINE_BUTT:
        {
            STROKE_T shape = S_SEGMENT;

            if( GetToolId() == ID_PCB_CIRCLE_BUTT )
                shape = S_CIRCLE;

            if( GetToolId() == ID_PCB_ARC_BUTT )
                shape = S_ARC;

            if( IsCopperLayer( GetActiveLayer() ) )
            {
                DisplayError( this, _( "Graphic not allowed on Copper layers" ) );
                break;
            }

            if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
            {
                DrawStruct = (BOARD_ITEM*) Begin_DrawSegment( NULL, shape, aDC );
                SetCurItem( DrawStruct );
                m_canvas->SetAutoPanRequest( true );
            }
            else if( DrawStruct
                   && (DrawStruct->Type() == PCB_LINE_T)
                   && DrawStruct->IsNew() )
            {
                DrawStruct = (BOARD_ITEM*) Begin_DrawSegment( (DRAWSEGMENT*) DrawStruct, shape, aDC );
                SetCurItem( DrawStruct );
                m_canvas->SetAutoPanRequest( true );
            }
        }
        break;

    case ID_TRACK_BUTT:
        if( !IsCopperLayer( GetActiveLayer() ) )
        {
            DisplayError( this, _( "Tracks on Copper layers only " ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            DrawStruct = (BOARD_ITEM*) Begin_Route( NULL, aDC );
            SetCurItem( DrawStruct );

            if( DrawStruct )
                m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct && DrawStruct->IsNew() )
        {
            TRACK* track = Begin_Route( (TRACK*) DrawStruct, aDC );

            // SetCurItem() must not write to the msg panel
            // because a track info is displayed while moving the mouse cursor
            if( track )  // A new segment was created
                SetCurItem( DrawStruct = (BOARD_ITEM*) track, false );

            m_canvas->SetAutoPanRequest( true );
        }

        break;

    case ID_PCB_ZONES_BUTT:
    case ID_PCB_KEEPOUT_AREA_BUTT:
        /* ZONE or KEEPOUT Tool is selected. Determine action for a left click:
         *  this can be start a new zone or select and move an existing zone outline corner
         *  if found near the mouse cursor
         */
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            if( Begin_Zone( aDC ) )
            {
                m_canvas->SetAutoPanRequest( true );
                DrawStruct = GetBoard()->m_CurrentZoneContour;
                GetScreen()->SetCurItem( DrawStruct );
            }
        }
        else if( DrawStruct && (DrawStruct->Type() == PCB_ZONE_AREA_T) && DrawStruct->IsNew() )
        {   // Add a new corner to the current outline being created:
            m_canvas->SetAutoPanRequest( true );
            Begin_Zone( aDC );
            DrawStruct = GetBoard()->m_CurrentZoneContour;
            GetScreen()->SetCurItem( DrawStruct );
        }
        else
        {
            DisplayError( this, wxT( "PCB_EDIT_FRAME::OnLeftClick() zone internal error" ) );
        }

        break;

    case ID_PCB_ADD_TEXT_BUTT:
        if( IsLayerInList( EDGE_LAYER, GetActiveLayer() ) )
        {
            DisplayError( this,
                          _( "Texts not allowed on Edge Cut layer" ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            SetCurItem( CreateTextePcb( aDC ) );
            m_canvas->MoveCursorToCrossHair();
            m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct->Type() == PCB_TEXT_T )
        {
            Place_Texte_Pcb( (TEXTE_PCB*) DrawStruct, aDC );
            m_canvas->SetAutoPanRequest( false );
        }
        else
        {
            DisplayError( this, wxT( "OnLeftClick err: not a PCB_TEXT_T" ) );
        }

        break;

    case ID_PCB_MODULE_BUTT:
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            m_canvas->MoveCursorToCrossHair();
            DrawStruct = (BOARD_ITEM*) LoadModuleFromLibrary(
                    wxEmptyString, Prj().PcbFootprintLibs(), true, aDC );

            SetCurItem( DrawStruct );

            if( DrawStruct )
                StartMoveModule( (MODULE*) DrawStruct, aDC, false );
        }
        else if( DrawStruct->Type() == PCB_MODULE_T )
        {
            PlaceModule( (MODULE*) DrawStruct, aDC );
            m_canvas->SetAutoPanRequest( false );
        }
        else
        {
            DisplayError( this, wxT( "Internal err: Struct not PCB_MODULE_T" ) );
        }

        break;

    case ID_PCB_DIMENSION_BUTT:
        if( IsLayerInList( EDGE_LAYER|ALL_CU_LAYERS, GetActiveLayer() ) )
        {
            DisplayError( this,
                          _( "Dimension not allowed on Copper or Edge Cut layers" ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            DrawStruct = (BOARD_ITEM*) EditDimension( NULL, aDC );
            SetCurItem( DrawStruct );
            m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct && (DrawStruct->Type() == PCB_DIMENSION_T) && DrawStruct->IsNew() )
        {
            DrawStruct = (BOARD_ITEM*) EditDimension( (DIMENSION*) DrawStruct, aDC );
            SetCurItem( DrawStruct );
            m_canvas->SetAutoPanRequest( true );
        }
        else
        {
            DisplayError( this,
                          wxT( "PCB_EDIT_FRAME::OnLeftClick() error item is not a DIMENSION" ) );
        }

        break;

    case ID_PCB_DELETE_ITEM_BUTT:
        if( !DrawStruct || !DrawStruct->GetFlags() )
        {
            DrawStruct = PcbGeneralLocateAndDisplay();

            if( DrawStruct && (DrawStruct->GetFlags() == 0) )
            {
                RemoveStruct( DrawStruct, aDC );
                SetCurItem( DrawStruct = NULL );
            }
        }

        break;

    case ID_PCB_PLACE_OFFSET_COORD_BUTT:
        m_canvas->DrawAuxiliaryAxis( aDC, GR_XOR );
        SetAuxOrigin( GetCrossHairPosition() );
        m_canvas->DrawAuxiliaryAxis( aDC, GR_COPY );
        OnModify();
        break;

    case ID_PCB_PLACE_GRID_COORD_BUTT:
        m_canvas->DrawGridAxis( aDC, GR_XOR, GetBoard()->GetGridOrigin() );
        SetGridOrigin( GetCrossHairPosition() );
        m_canvas->DrawGridAxis( aDC, GR_COPY, GetBoard()->GetGridOrigin() );
        break;

    default:
        DisplayError( this, wxT( "PCB_EDIT_FRAME::OnLeftClick() id error" ) );
        SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        break;
    }
}
bool PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosition,
                               EDA_ITEM* aItem )
{
    if( aHotkeyCode == 0 )
        return false;

    bool itemCurrentlyEdited = GetCurItem() && GetCurItem()->GetFlags();
    MODULE* module = NULL;
    int evt_type = 0;       //Used to post a wxCommandEvent on demand
    PCB_SCREEN* screen = GetScreen();
    auto displ_opts = (PCB_DISPLAY_OPTIONS*)GetDisplayOptions();

    /* Convert lower to upper case
     * (the usual toupper function has problem with non ascii codes like function keys
     */
    if( (aHotkeyCode >= 'a') && (aHotkeyCode <= 'z') )
        aHotkeyCode += 'A' - 'a';

    EDA_HOTKEY* HK_Descr = GetDescriptorFromHotkey( aHotkeyCode, common_Hotkey_List );

    if( HK_Descr == NULL )
        HK_Descr = GetDescriptorFromHotkey( aHotkeyCode, board_edit_Hotkey_List );

    if( HK_Descr == NULL )
        return false;

    int hk_id = HK_Descr->m_Idcommand;

    // Create a wxCommandEvent that will be posted in some hot keys functions
    wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
    cmd.SetEventObject( this );

    LAYER_NUM  ll;

    switch( hk_id )
    {
    default:
    case HK_NOT_FOUND:
        return false;

    case HK_LEFT_CLICK:
        OnLeftClick( aDC, aPosition );
        break;

    case HK_LEFT_DCLICK:    // Simulate a double left click: generate 2 events
        OnLeftClick( aDC, aPosition );
        OnLeftDClick( aDC, aPosition );
        break;

    case HK_SWITCH_TRACK_WIDTH_TO_NEXT:
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );

        if( GetDesignSettings().GetTrackWidthIndex() < GetDesignSettings().m_TrackWidthList.size() - 1 )
            GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().GetTrackWidthIndex() + 1 );
        else
            GetDesignSettings().SetTrackWidthIndex( 0 );

        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );

        break;

    case HK_SWITCH_TRACK_WIDTH_TO_PREVIOUS:
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );

        if( GetDesignSettings().GetTrackWidthIndex() <= 0 )
            GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().m_TrackWidthList.size() -1 );
        else
            GetDesignSettings().SetTrackWidthIndex( GetDesignSettings().GetTrackWidthIndex() - 1 );

        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );

        break;

    case HK_SWITCH_GRID_TO_FASTGRID1:
        SetFastGrid1();
        break;

    case HK_SWITCH_GRID_TO_FASTGRID2:
        SetFastGrid2();
        break;

    case HK_SWITCH_GRID_TO_NEXT:
        evt_type = ID_POPUP_GRID_NEXT;
        break;

    case HK_SWITCH_GRID_TO_PREVIOUS:
        evt_type = ID_POPUP_GRID_PREV;
        break;

    case HK_SWITCH_LAYER_TO_PREVIOUS:
        ll = GetActiveLayer();

        if( !IsCopperLayer( ll ) )
            break;

        if( ll == F_Cu )
            ll = B_Cu;
        else if( ll == B_Cu )
            ll = ToLAYER_ID( GetBoard()->GetCopperLayerCount() - 2 );
        else
            ll = ll - 1;

        SwitchLayer( aDC, ToLAYER_ID( ll ) );
        break;

    case HK_SWITCH_LAYER_TO_NEXT:
        ll = GetActiveLayer();

        if( !IsCopperLayer( ll ) )
            break;

        if( ll == B_Cu )
            ll = F_Cu;
        else if( ++ll >= GetBoard()->GetCopperLayerCount() - 1 )
            ll = B_Cu;

        SwitchLayer( aDC, ToLAYER_ID( ll ) );
        break;

    case HK_SWITCH_LAYER_TO_COMPONENT:
        SwitchLayer( aDC, F_Cu );
        break;

    case HK_SWITCH_LAYER_TO_COPPER:
        SwitchLayer( aDC, B_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER1:
        SwitchLayer( aDC, In1_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER2:
        SwitchLayer( aDC, In2_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER3:
        SwitchLayer( aDC, In3_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER4:
        SwitchLayer( aDC, In4_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER5:
        SwitchLayer( aDC, In5_Cu );
        break;

    case HK_SWITCH_LAYER_TO_INNER6:
        SwitchLayer( aDC, In6_Cu );
        break;

    case HK_HELP: // Display Current hotkey list
        DisplayHotkeyList( this, g_Board_Editor_Hotkeys_Descr );
        break;

    case HK_PREFERENCES:
        evt_type = wxID_PREFERENCES;
        break;

    case HK_ZOOM_IN:
        evt_type = ID_KEY_ZOOM_IN;
        break;

    case HK_ZOOM_OUT:
        evt_type = ID_KEY_ZOOM_OUT;
        break;

    case HK_ZOOM_REDRAW:
        evt_type = ID_ZOOM_REDRAW;
        break;

    case HK_ZOOM_AUTO:
        evt_type = ID_ZOOM_PAGE;
        break;

    case HK_ZOOM_CENTER:
        evt_type = ID_POPUP_ZOOM_CENTER;
        break;

    case HK_ZOOM_SELECTION:
        evt_type = ID_ZOOM_SELECTION;
        break;

    case HK_ADD_MODULE:
        evt_type = ID_PCB_MODULE_BUTT;
        break;

    case HK_UNDO:
    case HK_REDO:
        if( !itemCurrentlyEdited )
        {
            wxCommandEvent event( wxEVT_COMMAND_TOOL_CLICKED, HK_Descr->m_IdMenuEvent );
            wxPostEvent( this, event );
        }

        break;

    case HK_RESET_LOCAL_COORD:  // Set the relative coord
        GetScreen()->m_O_Curseur = GetCrossHairPosition();
        break;

    case HK_SET_GRID_ORIGIN:
        PCBNEW_CONTROL::SetGridOrigin( GetGalCanvas()->GetView(), this,
                                       new KIGFX::ORIGIN_VIEWITEM( GetGridOrigin(), UR_TRANSIENT ),
                                       GetCrossHairPosition() );
        m_canvas->Refresh();
        break;

    case HK_RESET_GRID_ORIGIN:
        PCBNEW_CONTROL::SetGridOrigin( GetGalCanvas()->GetView(), this,
                                       new KIGFX::ORIGIN_VIEWITEM( GetGridOrigin(), UR_TRANSIENT ),
                                       wxPoint( 0, 0 ) );
        m_canvas->Refresh();
        break;

    case HK_SWITCH_UNITS:
        evt_type = (GetUserUnits() == INCHES) ?
                    ID_TB_OPTIONS_SELECT_UNIT_MM : ID_TB_OPTIONS_SELECT_UNIT_INCH;
        break;

    case HK_SWITCH_TRACK_DISPLAY_MODE:
        displ_opts->m_DisplayPcbTrackFill = !displ_opts->m_DisplayPcbTrackFill;
        m_canvas->Refresh();
        break;

    case HK_DELETE:
        OnHotkeyDeleteItem( aDC );
        break;

    case HK_BACK_SPACE:
        if( IsCopperLayer( GetActiveLayer() ) )
        {
            if( !itemCurrentlyEdited )
            {
                // no track is currently being edited - select a segment and remove it.
                // @todo: possibly? pass the HK command code to PcbGeneralLocateAndDisplay()
                // so it can restrict its search to specific item types.
                BOARD_ITEM * item = PcbGeneralLocateAndDisplay();

                // don't let backspace delete modules!!
                if( item && item->IsTrack() )
                {
                    Delete_Segment( aDC, (TRACK*) item );
                    SetCurItem( NULL );
                }

                OnModify();
            }
            else if( GetCurItem()->IsTrack() )
            {
                // then an element is being edited - remove the last segment.
                // simple lines for debugger:
                TRACK* track = (TRACK*) GetCurItem();
                track = Delete_Segment( aDC, track );
                SetCurItem( track );
                OnModify();
            }
        }

        break;

    case HK_GET_AND_MOVE_FOOTPRINT:
        if( !itemCurrentlyEdited )
            evt_type = ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST;

        break;

    case HK_FIND_ITEM:
        if( !itemCurrentlyEdited )
            evt_type = ID_FIND_ITEMS;

        break;

    case HK_OPEN:
        if( !itemCurrentlyEdited )
            evt_type = ID_LOAD_FILE ;

        break;

    case HK_SAVE:
        if( !itemCurrentlyEdited )
            evt_type = ID_SAVE_BOARD;

        break;

    case HK_ADD_MICROVIA: // Place a micro via if a track is in progress
        if( GetToolId() != ID_TRACK_BUTT )
            return true;

        if( !itemCurrentlyEdited )                         // no track in progress: nothing to do
            break;

        if( GetCurItem()->Type() != PCB_TRACE_T )           // Should not occur
            return true;

        if( !GetCurItem()->IsNew() )
            return true;

        // place micro via and switch layer
        if( IsMicroViaAcceptable() )
            evt_type = ID_POPUP_PCB_PLACE_MICROVIA;

        break;

    case HK_ADD_BLIND_BURIED_VIA:
    case HK_ADD_THROUGH_VIA: // Switch to alternate layer and Place a via if a track is in progress
        if( GetBoard()->GetDesignSettings().m_BlindBuriedViaAllowed &&
            hk_id == HK_ADD_BLIND_BURIED_VIA  )
            GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_BLIND_BURIED;
        else
            GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_THROUGH;

        if( !itemCurrentlyEdited ) // no track in progress: switch layer only
        {
            Other_Layer_Route( NULL, aDC );
            if( displ_opts->m_ContrastModeDisplay )
                m_canvas->Refresh();
            break;
        }

        if( GetToolId() != ID_TRACK_BUTT )
            return true;

        if( GetCurItem()->Type() != PCB_TRACE_T )
            return true;

        if( !GetCurItem()->IsNew() )
            return true;

        evt_type = hk_id == HK_ADD_BLIND_BURIED_VIA ?
            ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA : ID_POPUP_PCB_PLACE_THROUGH_VIA;
        break;

    case HK_SEL_LAYER_AND_ADD_THROUGH_VIA:
    case HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA:
        if( GetCurItem() == NULL || !GetCurItem()->IsNew() ||
            GetCurItem()->Type() != PCB_TRACE_T )
            break;

        evt_type = hk_id == HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA ?
            ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA :
            ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA;
        break;

    case HK_SWITCH_TRACK_POSTURE:
        /* change the position of initial segment when creating new tracks
         * switch from _/  to -\ .
         */
        evt_type = ID_POPUP_PCB_SWITCH_TRACK_POSTURE ;
        break;

    case HK_DRAG_TRACK_KEEP_SLOPE:
        OnHotkeyMoveItem( HK_DRAG_TRACK_KEEP_SLOPE );
        break;

    case HK_PLACE_ITEM:
        OnHotkeyPlaceItem( aDC );
        break;

    case HK_ADD_NEW_TRACK: // Start new track, if possible
        OnHotkeyBeginRoute( aDC );
        break;

    case HK_EDIT_ITEM:      // Edit board item
        OnHotkeyEditItem( HK_EDIT_ITEM );
        break;

    case HK_EDIT_MODULE_WITH_MODEDIT:      // Edit module with module editor
        OnHotkeyEditItem( HK_EDIT_MODULE_WITH_MODEDIT );
        break;

    case HK_LOCK_UNLOCK_FOOTPRINT: // toggle module "MODULE_is_LOCKED" status:
        // get any module, locked or not locked and toggle its locked status
        if( !itemCurrentlyEdited )
        {
            wxPoint pos = RefPos( true );
            module = GetBoard()->GetFootprint( pos, screen->m_Active_Layer, true );
        }
        else if( GetCurItem()->Type() == PCB_MODULE_T )
        {
            module = (MODULE*) GetCurItem();
        }

        if( module )
        {
            SetCurItem( module );
            module->SetLocked( !module->IsLocked() );
            OnModify();
            SetMsgPanel( module );
        }
        break;

    case HK_DRAG_ITEM:    // Start drag module or track segment
        OnHotkeyMoveItem( HK_DRAG_ITEM );
        break;

    case HK_MOVE_ITEM:                  // Start move item
        OnHotkeyMoveItem( HK_MOVE_ITEM );
        break;

    case HK_COPY_ITEM:
        evt_type = OnHotkeyCopyItem();
        break;

    case HK_ROTATE_ITEM:        // Rotation
        OnHotkeyRotateItem( HK_ROTATE_ITEM );
        break;

    case HK_FLIP_ITEM:
        OnHotkeyFlipItem( HK_FLIP_ITEM );
        break;

    case HK_MOVE_ITEM_EXACT:
    case HK_DUPLICATE_ITEM:
    case HK_DUPLICATE_ITEM_AND_INCREMENT:
    case HK_CREATE_ARRAY:
        OnHotkeyDuplicateOrArrayItem( HK_Descr->m_Idcommand );
        break;

    case HK_SWITCH_HIGHCONTRAST_MODE: // switch to high contrast mode and refresh the canvas
        displ_opts->m_ContrastModeDisplay = !displ_opts->m_ContrastModeDisplay;
        m_canvas->Refresh();
        break;

    case HK_CANVAS_CAIRO:
        evt_type = ID_MENU_CANVAS_CAIRO;
        break;

    case HK_CANVAS_OPENGL:
        evt_type = ID_MENU_CANVAS_OPENGL;
        break;

    case HK_CANVAS_LEGACY:
        evt_type = ID_MENU_CANVAS_LEGACY;
        break;

    case HK_ZONE_FILL_OR_REFILL:
        evt_type = ID_POPUP_PCB_FILL_ALL_ZONES;
        break;

    case HK_ZONE_REMOVE_FILLED:
        evt_type = ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES;
        break;
    }

    if( evt_type != 0 )
    {
        wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
        evt.SetEventObject( this );
        evt.SetId( evt_type );
        GetEventHandler()->ProcessEvent( evt );
    }

    return true;
}
Beispiel #30
0
bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
{
    wxString    msg;
    STATUS_FLAGS flags = 0;
    bool        trackFound = false; // Flag set to true,
                                    // if a track is being the cursor, to avoid
                                    // to display menus relative to tracks twice
    bool        blockActive  = !GetScreen()->m_BlockLocate.IsIdle();

    BOARD_ITEM* item = GetCurItem();

    m_canvas->SetCanStartBlock( -1 );    // Avoid to start a block command when clicking on menu

    // If a command or a block is in progress:
    // Put the Cancel command (if needed) and the End command

    if( blockActive )
    {
        createPopUpBlockMenu( aPopMenu );
        aPopMenu->AppendSeparator();
        return true;
    }

    if( GetToolId() != ID_NO_TOOL_SELECTED )
    {
        if( item && item->GetFlags() )
        {
            AddMenuItem( aPopMenu, ID_POPUP_CANCEL_CURRENT_COMMAND, _( "Cancel" ),
                         KiBitmap( cancel_xpm ) );
        }
        else
        {
            AddMenuItem( aPopMenu, ID_POPUP_CLOSE_CURRENT_TOOL,
                         _( "End Tool" ), KiBitmap( cursor_xpm ) );
        }

        aPopMenu->AppendSeparator();
    }
    else
    {
        if( item && item->GetFlags() )
        {
            AddMenuItem( aPopMenu, ID_POPUP_CANCEL_CURRENT_COMMAND,
                         _( "Cancel" ), KiBitmap( cancel_xpm ) );
            aPopMenu->AppendSeparator();
        }
    }

    // Select a proper item

    wxPoint cursorPos = GetCrossHairPosition();
    wxPoint selectPos = m_Collector->GetRefPos();

    selectPos = GetNearestGridPosition( selectPos );

    /*  We can reselect another item only if there are no item being edited
     * because ALL moving functions use GetCurItem(), therefore GetCurItem()
     * must return the same item during moving. We know an item is moving
     * if( item && (item->m_Flags != 0)) is true and after calling
     * PcbGeneralLocateAndDisplay(), GetCurItem() is any arbitrary BOARD_ITEM,
     * not the current item being edited. In such case we cannot call
     * PcbGeneralLocateAndDisplay().
     */
    if( !item || (item->GetFlags() == 0) )
    {
        // show the "item selector" menu if no item selected or
        // if there is a selected item but the mouse has moved
        // (therefore a new item is perhaps under the cursor)
        if( !item || cursorPos != selectPos )
        {
            m_canvas->SetAbortRequest( false );
            PcbGeneralLocateAndDisplay();

            if( m_canvas->GetAbortRequest() )
            {
                return false;
            }
        }
    }

    item = GetCurItem();
    flags = item ? item->GetFlags() : 0;

    // Add the context menu, which depends on the picked item:
    if( item )
    {
        switch( item->Type() )
        {
        case PCB_MODULE_T:
            createPopUpMenuForFootprints( (MODULE*) item, aPopMenu );

            if( m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_MODULE ) )
            {
                aPopMenu->AppendSeparator();

                if( !( (MODULE*) item )->IsLocked() )
                {
                    msg = AddHotkeyName( _("Lock Footprint" ), g_Board_Editor_Hokeys_Descr,
                                         HK_LOCK_UNLOCK_FOOTPRINT );
                    AddMenuItem( aPopMenu, ID_POPUP_PCB_AUTOPLACE_FIXE_MODULE, msg,
                                 KiBitmap( locked_xpm ) );
                }
                else
                {
                    msg = AddHotkeyName( _( "Unlock Footprint" ), g_Board_Editor_Hokeys_Descr,
                                         HK_LOCK_UNLOCK_FOOTPRINT );
                    AddMenuItem( aPopMenu, ID_POPUP_PCB_AUTOPLACE_FREE_MODULE, msg,
                                 KiBitmap( unlocked_xpm ) );
                }

                if( !flags )
                    aPopMenu->Append( ID_POPUP_PCB_AUTOPLACE_CURRENT_MODULE,
                                      _( "Automatically Place Footprint" ) );
            }

            if( m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_TRACKS ) )
            {
                if( !flags )
                    aPopMenu->Append( ID_POPUP_PCB_AUTOROUTE_MODULE,
                                      _( "Automatically Route Footprint" ) );
            }
            break;

        case PCB_PAD_T:
            createPopUpMenuForFpPads( static_cast<D_PAD*>( item ), aPopMenu );
            break;

        case PCB_MODULE_TEXT_T:
            createPopUpMenuForFpTexts( static_cast<TEXTE_MODULE*>( item ), aPopMenu );
            break;

        case PCB_LINE_T:  // Some graphic items on technical layers
            if( (flags & IS_NEW) )
            {
                AddMenuItem( aPopMenu, ID_POPUP_PCB_STOP_CURRENT_DRAWING,
                             _( "End Drawing" ), KiBitmap( checked_ok_xpm ) );
            }

            if( !flags )
            {
                msg = AddHotkeyName( _( "Move Drawing" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_DRAWING_REQUEST,
                             msg, KiBitmap( move_xpm ) );

                msg = AddHotkeyName( _( "Duplicate Drawing" ), g_Board_Editor_Hokeys_Descr,
                                     HK_DUPLICATE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_DUPLICATE_ITEM,
                             msg, KiBitmap( duplicate_line_xpm ) );

                msg = AddHotkeyName( _("Move Drawing Exactly" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM_EXACT );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_EXACT,
                             msg, KiBitmap( move_line_xpm ) );

                msg = AddHotkeyName( _("Create Drawing Array" ), g_Board_Editor_Hokeys_Descr,
                                     HK_CREATE_ARRAY );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_CREATE_ARRAY,
                             msg, KiBitmap( array_line_xpm ) );

                msg = AddHotkeyName( _( "Edit Drawing" ), g_Board_Editor_Hokeys_Descr,
                                     HK_EDIT_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_EDIT_DRAWING,
                             msg, KiBitmap( edit_xpm ) );

                AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_DRAWING,
                             _( "Delete Drawing" ), KiBitmap( delete_xpm ) );

                if( !IsCopperLayer( item->GetLayer() ) )
                    AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_DRAWING_LAYER,
                                 _( "Delete All Drawings on Layer" ), KiBitmap( delete_xpm ) );
            }

            break;

        case PCB_ZONE_T:      // Item used to fill a zone
            AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_ZONE,
                         _( "Delete Zone Filling" ), KiBitmap( delete_xpm ) );
            break;

        case PCB_ZONE_AREA_T:    // Item used to handle a zone area (outlines, holes ...)
            if( flags & IS_NEW )
            {
                AddMenuItem( aPopMenu, ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE,
                             _( "Close Zone Outline" ), KiBitmap( checked_ok_xpm ) );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_ZONE_LAST_CREATED_CORNER,
                             _( "Delete Last Corner" ), KiBitmap( delete_xpm ) );
            }
            else
            {
                createPopUpMenuForZones( (ZONE_CONTAINER*) item, aPopMenu );
            }

            break;

        case PCB_TEXT_T:
            createPopUpMenuForTexts( (TEXTE_PCB*) item, aPopMenu );
            break;

        case PCB_TRACE_T:
        case PCB_VIA_T:
            trackFound = true;
            createPopupMenuForTracks( (TRACK*) item, aPopMenu );
            break;

        case PCB_MARKER_T:
            createPopUpMenuForMarkers( (MARKER_PCB*) item, aPopMenu );
            break;

        case PCB_DIMENSION_T:
            if( !flags )
            {
                msg = AddHotkeyName( _( "Edit Dimension" ), g_Board_Editor_Hokeys_Descr,
                                     HK_EDIT_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_EDIT_DIMENSION, msg, KiBitmap( edit_xpm ) );

                msg = AddHotkeyName( _( "Move Dimension Text" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST,
                             msg, KiBitmap( move_text_xpm ) );

                msg = AddHotkeyName( _( "Duplicate Dimension" ), g_Board_Editor_Hokeys_Descr,
                                     HK_DUPLICATE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_DUPLICATE_ITEM,
                             msg, KiBitmap( duplicate_text_xpm ) );

                msg = AddHotkeyName( _("Move Dimension Exactly" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM_EXACT );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_EXACT,
                             msg, KiBitmap( move_text_xpm ) );

                msg = AddHotkeyName( _( "Delete Dimension" ), g_Board_Editor_Hokeys_Descr,
                                     HK_DELETE );

                AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_DIMENSION,
                             msg, KiBitmap( delete_xpm ) );
            }
            break;

        case PCB_TARGET_T:
            if( !flags )
            {
                msg = AddHotkeyName( _( "Move Target" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_MIRE_REQUEST,
                             msg, KiBitmap( move_target_xpm ) );

                msg = AddHotkeyName( _("Move Target Exactly" ), g_Board_Editor_Hokeys_Descr,
                                     HK_MOVE_ITEM_EXACT );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_MOVE_EXACT,
                             msg, KiBitmap( move_target_xpm ) );

                msg = AddHotkeyName( _( "Duplicate Target" ), g_Board_Editor_Hokeys_Descr,
                                     HK_DUPLICATE_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_DUPLICATE_ITEM,
                             msg, KiBitmap( duplicate_target_xpm ) );

                msg = AddHotkeyName( _("Create Target Array" ), g_Board_Editor_Hokeys_Descr,
                                     HK_CREATE_ARRAY );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_CREATE_ARRAY,
                             msg, KiBitmap( array_target_xpm ) );

                msg = AddHotkeyName( _( "Edit Target" ), g_Board_Editor_Hokeys_Descr,
                                     HK_EDIT_ITEM );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_EDIT_MIRE, msg, KiBitmap( edit_xpm ) );

                msg = AddHotkeyName( _( "Delete Target" ), g_Board_Editor_Hokeys_Descr, HK_DELETE );
                AddMenuItem( aPopMenu, ID_POPUP_PCB_DELETE_MIRE,
                             msg, KiBitmap( delete_xpm ) );
            }

            break;

        case PCB_MODULE_EDGE_T:
        case SCREEN_T:
        case TYPE_NOT_INIT:
        case PCB_T:
            msg.Printf( wxT( "PCB_EDIT_FRAME::OnRightClick() Error: unexpected DrawType %d" ),
                        item->Type() );
            wxMessageBox( msg );
            SetCurItem( NULL );
            break;

        default:
            msg.Printf( wxT( "PCB_EDIT_FRAME::OnRightClick() Error: unknown DrawType %d" ),
                        item->Type() );
            wxMessageBox( msg );

            // Attempt to clear error (but should no occurs )
            if( item->Type() >= MAX_STRUCT_TYPE_ID )
                SetCurItem( NULL );

            break;
        }

       aPopMenu->AppendSeparator();
    }

    if( !flags )
    {
        msg = AddHotkeyName( _( "Get and Move Footprint" ),
                             g_Board_Editor_Hokeys_Descr, HK_GET_AND_MOVE_FOOTPRINT );
        AddMenuItem( aPopMenu, ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST,
                     msg, KiBitmap( move_module_xpm ) );
    }

    // Display context sensitive commands:
    switch(  GetToolId() )
    {
    case ID_PCB_ZONES_BUTT:
        if(  GetBoard()->m_ZoneDescriptorList.size() > 0 )
        {
            aPopMenu->AppendSeparator();
            msg = AddHotkeyName( _( "Fill or Refill All Zones" ),
                                 g_Board_Editor_Hokeys_Descr, HK_ZONE_FILL_OR_REFILL );
            AddMenuItem( aPopMenu, ID_POPUP_PCB_FILL_ALL_ZONES,
                         msg, KiBitmap( fill_zone_xpm ) );
            msg = AddHotkeyName( _( "Remove Filled Areas in All Zones" ),
                                 g_Board_Editor_Hokeys_Descr, HK_ZONE_REMOVE_FILLED );
            AddMenuItem( aPopMenu, ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_ALL_ZONES,
                         msg, KiBitmap( zone_unfill_xpm ) );
            aPopMenu->AppendSeparator();
        }

        AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER,
                     _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) );
        aPopMenu->AppendSeparator();
        break;

    case ID_PCB_KEEPOUT_AREA_BUTT:
        AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER,
                     _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) );
        aPopMenu->AppendSeparator();
        break;

    case ID_TRACK_BUTT:
        if ( ! trackFound )   // This menu is already added when a track is located
        {
            aPopMenu->AppendSeparator();
            msg = AddHotkeyName( _( "Begin Track" ),
                                 g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK );
            AddMenuItem( aPopMenu, ID_POPUP_PCB_BEGIN_TRACK,
                         msg, KiBitmap( add_tracks_xpm ) );

            AddMenuItem( aPopMenu, Append_Track_Width_List( GetBoard() ),
                         ID_POPUP_PCB_SELECT_WIDTH, _( "Select Track Width" ),
                         KiBitmap( width_track_xpm ) );

            AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_CU_LAYER,
                         _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) );
            AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER_PAIR,
                         _( "Select Layer Pair for Vias" ), KiBitmap( select_layer_pair_xpm ) );
            aPopMenu->AppendSeparator();
        }
        break;

    case ID_PCB_CIRCLE_BUTT:
    case ID_PCB_ARC_BUTT:
    case ID_PCB_ADD_TEXT_BUTT:
    case ID_PCB_ADD_LINE_BUTT:
    case ID_PCB_DIMENSION_BUTT:
        AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_NO_CU_LAYER,
                      _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) );
        aPopMenu->AppendSeparator();
        break;

    case ID_PCB_MODULE_BUTT:
        if( !flags )
        {
            AddMenuItem( aPopMenu, ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC,
                         _( "Footprint Documentation" ), KiBitmap( book_xpm ) );
            aPopMenu->AppendSeparator();
        }
        break;

    case ID_NO_TOOL_SELECTED:
        if( m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_MODULE ) )
        {
            wxMenu* commands = new wxMenu;
            AddMenuItem( aPopMenu, commands, ID_POPUP_PCB_AUTOPLACE_COMMANDS,
                         _( "Global Spread and Place" ), KiBitmap( move_xpm ) );
            AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FREE_ALL_MODULES,
                         _( "Unlock All Footprints" ), KiBitmap( unlocked_xpm ) );
            AddMenuItem( commands, ID_POPUP_PCB_AUTOPLACE_FIXE_ALL_MODULES,
                         _( "Lock All Footprints" ), KiBitmap( locked_xpm ) );
            commands->AppendSeparator();
            AddMenuItem( commands, ID_POPUP_PCB_SPREAD_ALL_MODULES,
                         _( "Spread out All Footprints" ), KiBitmap( move_xpm ) );
            commands->Append( ID_POPUP_PCB_SPREAD_NEW_MODULES,
                              _( "Spread out Footprints not Already on Board" ) );
            commands->AppendSeparator();
            commands->Append( ID_POPUP_PCB_AUTOPLACE_ALL_MODULES,
                              _( "Automatically Place All Footprints" ) );
            commands->Append( ID_POPUP_PCB_AUTOPLACE_NEW_MODULES,
                              _( "Automatically Place New Footprints" ) );
            commands->Append( ID_POPUP_PCB_AUTOPLACE_NEXT_MODULE,
                              _( "Automatically Place Next Footprints" ) );
            commands->AppendSeparator();
            AddMenuItem( commands, ID_POPUP_PCB_REORIENT_ALL_MODULES,
                         _( "Orient All Footprints" ), KiBitmap( rotate_module_cw_xpm ) );
            aPopMenu->AppendSeparator();
        }

        if( m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_TRACKS ) )
        {
            wxMenu* commands = new wxMenu;
            aPopMenu->Append( ID_POPUP_PCB_AUTOROUTE_COMMANDS, _( "Autoroute" ), commands );
            AddMenuItem( commands, ID_POPUP_PCB_SELECT_LAYER_PAIR,
                         _( "Select Layer Pair" ), KiBitmap( select_layer_pair_xpm ) );
            commands->AppendSeparator();
            commands->Append( ID_POPUP_PCB_AUTOROUTE_ALL_MODULES,
                              _( "Automatically Route All Footprints" ) );
            commands->AppendSeparator();
            commands->Append( ID_POPUP_PCB_AUTOROUTE_RESET_UNROUTED, _( "Reset Unrouted" ) );
            aPopMenu->AppendSeparator();
        }

        if( !trackFound )
        {
            msg = AddHotkeyName( _( "Begin Track" ), g_Board_Editor_Hokeys_Descr, HK_ADD_NEW_TRACK );
            AddMenuItem( aPopMenu, ID_POPUP_PCB_BEGIN_TRACK, msg, KiBitmap( add_tracks_xpm ) );

            AddMenuItem( aPopMenu, Append_Track_Width_List( GetBoard() ),
                         ID_POPUP_PCB_SELECT_WIDTH, _( "Select Track Width" ),
                         KiBitmap( width_track_xpm ) );

            AddMenuItem( aPopMenu, ID_POPUP_PCB_SELECT_LAYER,
                         _( "Select Working Layer" ), KiBitmap( select_w_layer_xpm ) );
            aPopMenu->AppendSeparator();
        }
        break;
    }

    return true;
}