int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList, bool aFullConnection ) { SCH_ITEM* item; EDA_ITEM* tmp; EDA_ITEMS list; // Clear flags member for all items. ClearDrawingState(); BreakSegmentsOnJunctions(); if( GetNode( aPosition, list ) == 0 ) return 0; for( size_t i = 0; i < list.size(); i++ ) { item = (SCH_ITEM*) list[ i ]; item->SetFlags( SELECTEDNODE | STRUCT_DELETED ); /* Put this structure in the picked list: */ ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } // Mark all wires, junctions, .. connected to the item(s) found. if( aFullConnection ) { SCH_LINE* segment; for( item = m_drawList.begin(); item; item = item->Next() ) { if( !(item->GetFlags() & SELECTEDNODE) ) continue; if( item->Type() != SCH_LINE_T ) continue; MarkConnections( (SCH_LINE*) item ); } // Search all attached wires (i.e wire with one new dangling end ) for( item = m_drawList.begin(); item; item = item->Next() ) { bool noconnect = false; if( item->GetFlags() & STRUCT_DELETED ) continue; // Already seen if( !(item->GetFlags() & CANDIDATE) ) continue; // not a candidate if( item->Type() != SCH_LINE_T ) continue; item->SetFlags( SKIP_STRUCT ); segment = (SCH_LINE*) item; /* If the wire start point is connected to a wire that was already found * and now is not connected, add the wire to the list. */ for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) { // Ensure tmp is a previously deleted segment: if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) continue; if( tmp->Type() != SCH_LINE_T ) continue; SCH_LINE* testSegment = (SCH_LINE*) tmp; // Test for segment connected to the previously deleted segment: if( testSegment->IsEndPoint( segment->GetStartPoint() ) ) break; } // when tmp != NULL, segment is a new candidate: // put it in deleted list if // the start point is not connected to an other item (like pin) if( tmp && !CountConnectedItems( segment->GetStartPoint(), true ) ) noconnect = true; /* If the wire end point is connected to a wire that has already been found * and now is not connected, add the wire to the list. */ for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() ) { // Ensure tmp is a previously deleted segment: if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 ) continue; if( tmp->Type() != SCH_LINE_T ) continue; SCH_LINE* testSegment = (SCH_LINE*) tmp; // Test for segment connected to the previously deleted segment: if( testSegment->IsEndPoint( segment->GetEndPoint() ) ) break; } // when tmp != NULL, segment is a new candidate: // put it in deleted list if // the end point is not connected to an other item (like pin) if( tmp && !CountConnectedItems( segment->GetEndPoint(), true ) ) noconnect = true; item->ClearFlags( SKIP_STRUCT ); if( noconnect ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); item = m_drawList.begin(); } } // Get redundant junctions (junctions which connect < 3 end wires // and no pin) for( item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & STRUCT_DELETED ) continue; if( !(item->GetFlags() & CANDIDATE) ) continue; if( item->Type() != SCH_JUNCTION_T ) continue; SCH_JUNCTION* junction = (SCH_JUNCTION*) item; if( CountConnectedItems( junction->GetPosition(), false ) <= 2 ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } } for( item = m_drawList.begin(); item; item = item->Next() ) { if( item->GetFlags() & STRUCT_DELETED ) continue; if( item->Type() != SCH_LABEL_T ) continue; tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() ); if( tmp && tmp->GetFlags() & STRUCT_DELETED ) { item->SetFlags( STRUCT_DELETED ); ITEM_PICKER picker( item, UR_DELETED ); aList.PushItem( picker ); } } } ClearDrawingState(); return aList.GetCount(); }
/** * Function OnLeftDClick * called on a double click event from the drawpanel mouse handler * if an editable item is found (text, component) * Call the suitable dialog editor. * Id a create command is in progress: * validate and finish the command */ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) { EDA_ITEM* item = GetScreen()->GetCurItem(); switch( GetToolId() ) { case ID_NO_TOOL_SELECTED: if( ( item == NULL ) || ( item->GetFlags() == 0 ) ) { item = LocateAndShowItem( aPosition ); } if( ( item == NULL ) || ( item->GetFlags() != 0 ) ) break; switch( item->Type() ) { case SCH_SHEET_T: m_CurrentSheet->push_back( (SCH_SHEET*) item ); DisplayCurrentSheet(); break; case SCH_COMPONENT_T: EditComponent( (SCH_COMPONENT*) item ); GetCanvas()->MoveCursorToCrossHair(); if( item->GetFlags() == 0 ) GetScreen()->SetCurItem( NULL ); GetCanvas()->Refresh(); break; case SCH_TEXT_T: case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: case SCH_HIERARCHICAL_LABEL_T: EditSchematicText( (SCH_TEXT*) item ); break; case SCH_BITMAP_T: EditImage( (SCH_BITMAP*) item ); break; case SCH_FIELD_T: EditComponentFieldText( (SCH_FIELD*) item ); GetCanvas()->MoveCursorToCrossHair(); break; case SCH_MARKER_T: ( (SCH_MARKER*) item )->DisplayMarkerInfo( this ); break; default: break; } break; case ID_BUS_BUTT: case ID_WIRE_BUTT: case ID_LINE_COMMENT_BUTT: if( item && item->IsNew() ) EndSegment( aDC ); break; } }
void EDA_DRAW_PANEL::OnMouseEvent( wxMouseEvent& event ) { int localbutt = 0; BASE_SCREEN* screen = GetScreen(); if( !screen ) return; /* Adjust value to filter mouse displacement before consider the drag * mouse is really a drag command, not just a movement while click */ #define MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND 5 if( event.Leaving() ) m_canStartBlock = -1; if( !IsMouseCaptured() ) // No mouse capture in progress. SetAutoPanRequest( false ); if( GetParent()->IsActive() ) SetFocus(); else return; if( !event.IsButton() && !event.Moving() && !event.Dragging() ) return; if( event.RightDown() ) { OnRightClick( event ); return; } if( m_ignoreMouseEvents ) return; if( event.LeftDown() ) localbutt = GR_M_LEFT_DOWN; if( event.ButtonDClick( 1 ) ) localbutt = GR_M_LEFT_DOWN | GR_M_DCLICK; if( event.MiddleDown() ) localbutt = GR_M_MIDDLE_DOWN; INSTALL_UNBUFFERED_DC( DC, this ); DC.SetBackground( *wxBLACK_BRUSH ); // Compute the cursor position in drawing (logical) units. GetParent()->SetMousePosition( event.GetLogicalPosition( DC ) ); int kbstat = 0; if( event.ShiftDown() ) kbstat |= GR_KB_SHIFT; if( event.ControlDown() ) kbstat |= GR_KB_CTRL; if( event.AltDown() ) kbstat |= GR_KB_ALT; // Calling Double Click and Click functions : if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) ) { if( m_ClickTimer ) { m_ClickTimer->Stop(); wxDELETE( m_ClickTimer ); } GetParent()->OnLeftDClick( &DC, GetParent()->RefPos( true ) ); // inhibit a response to the mouse left button release, // because we have a double click, and we do not want a new // OnLeftClick command at end of this Double Click m_ignoreNextLeftButtonRelease = true; } else if( event.LeftUp() ) { // A block command is in progress: a left up is the end of block // or this is the end of a double click, already seen // Note also m_ignoreNextLeftButtonRelease can be set by // the call to OnLeftClick(), so do not change it after calling OnLeftClick bool ignoreEvt = m_ignoreNextLeftButtonRelease; m_ignoreNextLeftButtonRelease = false; if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK && !ignoreEvt ) { EDA_ITEM* item = screen->GetCurItem(); m_CursorClickPos = GetParent()->RefPos( true ); // If we have an item already selected, or we are using a tool, // we won't use the disambiguation menu so process the click immediately if( ( item && item->GetFlags() ) || GetParent()->GetToolId() != ID_NO_TOOL_SELECTED ) GetParent()->OnLeftClick( &DC, m_CursorClickPos ); else { wxDELETE( m_ClickTimer ); m_ClickTimer = new wxTimer(this, ID_MOUSE_DOUBLECLICK); m_ClickTimer->StartOnce( m_doubleClickInterval ); } } } else if( !event.LeftIsDown() ) { /* be sure there is a response to a left button release command * even when a LeftUp event is not seen. This happens when a * double click opens a dialog box, and the release mouse button * is made when the dialog box is opened. */ m_ignoreNextLeftButtonRelease = false; } if( event.ButtonDown( wxMOUSE_BTN_MIDDLE ) ) { m_PanStartCenter = GetParent()->GetScrollCenterPosition(); m_PanStartEventPosition = event.GetPosition(); INSTALL_UNBUFFERED_DC( dc, this ); CrossHairOff( &dc ); SetCursor( wxCURSOR_SIZING ); } if( event.ButtonUp( wxMOUSE_BTN_MIDDLE ) ) { INSTALL_UNBUFFERED_DC( dc, this ); CrossHairOn( &dc ); SetCursor( (wxStockCursor) m_currentCursor ); } if( event.MiddleIsDown() ) { wxPoint currentPosition = event.GetPosition(); double scale = GetParent()->GetScreen()->GetScalingFactor(); int x = m_PanStartCenter.x + KiROUND( (double) ( m_PanStartEventPosition.x - currentPosition.x ) / scale ); int y = m_PanStartCenter.y + KiROUND( (double) ( m_PanStartEventPosition.y - currentPosition.y ) / scale ); GetParent()->RedrawScreen( wxPoint( x, y ), false ); } // Calling the general function on mouse changes (and pseudo key commands) GetParent()->GeneralControl( &DC, event.GetLogicalPosition( DC ), 0 ); /*******************************/ /* Control of block commands : */ /*******************************/ // Command block can't start if mouse is dragging a new panel static EDA_DRAW_PANEL* lastPanel; if( lastPanel != this ) { m_minDragEventCount = 0; m_canStartBlock = -1; } /* A new command block can start after a release buttons * and if the drag is enough * This is to avoid a false start block when a dialog box is dismissed, * or when changing panels in hierarchy navigation * or when clicking while and moving mouse */ if( !event.LeftIsDown() && !event.MiddleIsDown() ) { m_minDragEventCount = 0; m_canStartBlock = 0; /* Remember the last cursor position when a drag mouse starts * this is the last position ** before ** clicking a button * this is useful to start a block command from the point where the * mouse was clicked first * (a filter creates a delay for the real block command start, and * we must remember this point) */ m_CursorStartPos = GetParent()->GetCrossHairPosition(); } if( m_enableBlockCommands && !(localbutt & GR_M_DCLICK) ) { if( !screen->IsBlockActive() ) { screen->m_BlockLocate.SetOrigin( m_CursorStartPos ); } if( event.LeftDown() ) { if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE ) { SetAutoPanRequest( false ); GetParent()->HandleBlockPlace( &DC ); m_ignoreNextLeftButtonRelease = true; } } else if( ( m_canStartBlock >= 0 ) && event.LeftIsDown() && !IsMouseCaptured() ) { // Mouse is dragging: if no block in progress, start a block command. if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK ) { // Start a block command int cmd_type = kbstat; // A block command is started if the drag is enough. A small // drag is ignored (it is certainly a little mouse move when // clicking) not really a drag mouse if( m_minDragEventCount < MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND ) m_minDragEventCount++; else { auto cmd = (GetParent()->GetToolId() == ID_ZOOM_SELECTION) ? BLOCK_ZOOM : 0; if( !GetParent()->HandleBlockBegin( &DC, cmd_type, m_CursorStartPos, cmd ) ) { // should not occur: error GetParent()->DisplayToolMsg( wxT( "EDA_DRAW_PANEL::OnMouseEvent() Block Error" ) ); } else { SetAutoPanRequest( true ); SetCursor( wxCURSOR_SIZING ); } } } } if( event.ButtonUp( wxMOUSE_BTN_LEFT ) ) { /* Release the mouse button: end of block. * The command can finish (DELETE) or have a next command (MOVE, * COPY). However the block command is canceled if the block * size is small because a block command filtering is already * made, this case happens, but only when the on grid cursor has * not moved. */ #define BLOCK_MINSIZE_LIMIT 1 bool BlockIsSmall = ( std::abs( screen->m_BlockLocate.GetWidth() ) < BLOCK_MINSIZE_LIMIT ) && ( std::abs( screen->m_BlockLocate.GetHeight() ) < BLOCK_MINSIZE_LIMIT ); if( (screen->m_BlockLocate.GetState() != STATE_NO_BLOCK) && BlockIsSmall ) { if( m_endMouseCaptureCallback ) { m_endMouseCaptureCallback( this, &DC ); SetAutoPanRequest( false ); } SetCursor( (wxStockCursor) m_currentCursor ); } else if( screen->m_BlockLocate.GetState() == STATE_BLOCK_END ) { SetAutoPanRequest( false ); GetParent()->HandleBlockEnd( &DC ); SetCursor( (wxStockCursor) m_currentCursor ); if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE ) { SetAutoPanRequest( true ); SetCursor( wxCURSOR_HAND ); } } } } // End of block command on a double click // To avoid an unwanted block move command if the mouse is moved while double clicking if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) ) { if( !screen->IsBlockActive() && IsMouseCaptured() ) { m_endMouseCaptureCallback( this, &DC ); } } lastPanel = this; #ifdef __WXGTK3__ // Screen has to be updated on every operation, otherwise the cursor leaves a trail (when xor // operation is changed to copy) or is not updated at all. Refresh(); #endif }
void PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey ) { wxRealPoint gridSize; wxPoint oldpos; wxPoint pos = GetScreen()->GetNearestGridPosition( aPosition ); oldpos = GetScreen()->GetCrossHairPosition(); gridSize = GetScreen()->GetGridSize(); switch( aHotKey ) { case WXK_NUMPAD8: case WXK_UP: pos.y -= wxRound( gridSize.y ); m_canvas->MoveCursor( pos ); break; case WXK_NUMPAD2: case WXK_DOWN: pos.y += wxRound( gridSize.y ); m_canvas->MoveCursor( pos ); break; case WXK_NUMPAD4: case WXK_LEFT: pos.x -= wxRound( gridSize.x ); m_canvas->MoveCursor( pos ); break; case WXK_NUMPAD6: case WXK_RIGHT: pos.x += wxRound( gridSize.x ); m_canvas->MoveCursor( pos ); break; default: break; } // Put cursor in new position, according to the zoom keys (if any). GetScreen()->SetCrossHairPosition( pos ); /* Put cursor on grid or a pad centre if requested. If the tool DELETE is active the * cursor is left off grid this is better to reach items to delete off grid, */ bool keep_on_grid = true; if( GetToolId() == ID_PCB_DELETE_ITEM_BUTT ) keep_on_grid = false; /* Cursor is left off grid if no block in progress and no moving object */ if( GetScreen()->m_BlockLocate.m_State != STATE_NO_BLOCK ) keep_on_grid = true; EDA_ITEM* DrawStruct = GetScreen()->GetCurItem(); if( DrawStruct && DrawStruct->GetFlags() ) keep_on_grid = true; if( keep_on_grid ) { wxPoint on_grid = GetScreen()->GetNearestGridPosition( pos ); wxSize grid; grid.x = (int) GetScreen()->GetGridSize().x; grid.y = (int) GetScreen()->GetGridSize().y; if( Magnetize( m_Pcb, this, GetToolId(), grid, on_grid, &pos ) ) { GetScreen()->SetCrossHairPosition( pos, false ); } else { // If there's no intrusion and DRC is active, we pass the cursor // "as is", and let ShowNewTrackWhenMovingCursor figure out what to do. if( !Drc_On || !g_CurrentTrackSegment || (BOARD_ITEM*)g_CurrentTrackSegment != this->GetCurItem() || !LocateIntrusion( m_Pcb->m_Track, g_CurrentTrackSegment, GetScreen()->m_Active_Layer, GetScreen()->RefPos( true ) ) ) { GetScreen()->SetCrossHairPosition( on_grid ); } } } if( oldpos != GetScreen()->GetCrossHairPosition() ) { pos = GetScreen()->GetCrossHairPosition(); GetScreen()->SetCrossHairPosition( oldpos, false ); m_canvas->CrossHairOff( aDC ); GetScreen()->SetCrossHairPosition( pos, false ); m_canvas->CrossHairOn( aDC ); if( m_canvas->IsMouseCaptured() ) { #ifdef USE_WX_OVERLAY wxDCOverlay oDC( m_overlay, (wxWindowDC*)aDC ); oDC.Clear(); m_canvas->CallMouseCapture( aDC, aPosition, false ); #else m_canvas->CallMouseCapture( aDC, aPosition, true ); #endif } #ifdef USE_WX_OVERLAY else { m_overlay.Reset(); } #endif } if( aHotKey ) { OnHotKey( aDC, aHotKey, aPosition ); } UpdateStatusBar(); /* Display new cursor coordinates */ }