/* Redraw the current graphic item during its creation * Use this function to show a new outline, in begin command */ static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem(); if( edge == NULL ) return; MODULE* module = (MODULE*) edge->GetParent(); // if( erase ) { edge->Draw( aPanel, aDC, GR_XOR ); } edge->SetEnd( aPanel->GetParent()->GetCrossHairPosition() ); // Update relative coordinate. edge->SetEnd0( edge->GetEnd() - module->GetPosition() ); wxPoint pt( edge->GetEnd0() ); RotatePoint( &pt, -module->GetOrientation() ); edge->SetEnd0( pt ); edge->Draw( aPanel, aDC, GR_XOR ); module->CalculateBoundingBox(); }
static void AbortMoveAndEditTarget( EDA_DRAW_PANEL* Panel, wxDC* DC ) { BASE_SCREEN* screen = Panel->GetScreen(); PCB_TARGET* target = (PCB_TARGET*) screen->GetCurItem(); ( (PCB_EDIT_FRAME*) Panel->GetParent() )->SetCurItem( NULL ); Panel->SetMouseCapture( NULL, NULL ); if( target == NULL ) return; target->Draw( Panel, DC, GR_XOR ); if( target->IsNew() ) // If it is new, delete it { target->Draw( Panel, DC, GR_XOR ); target->DeleteStructure(); target = NULL; } else // it is an existing item: retrieve initial values of parameters { if( ( target->GetFlags() & (IN_EDIT | IS_MOVED) ) ) { target->SetPosition( s_TargetCopy.GetPosition() ); target->SetWidth( s_TargetCopy.GetWidth() ); target->SetSize( s_TargetCopy.GetSize() ); target->SetShape( s_TargetCopy.GetShape() ); } target->ClearFlags(); target->Draw( Panel, DC, GR_OR ); } }
static void Show_MoveTexte_Module( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); TEXTE_MODULE* Text = static_cast<TEXTE_MODULE*>( screen->GetCurItem() ); if( Text == NULL ) return; // Erase umbilical and text if necessary if( aErase ) { Text->DrawUmbilical( aPanel, aDC, GR_XOR, -MoveVector ); Text->Draw( aPanel, aDC, GR_XOR, MoveVector ); } MoveVector = TextInitialPosition - aPanel->GetParent()->GetCrossHairPosition(); // Draw umbilical if text moved if( MoveVector.x || MoveVector.y ) Text->DrawUmbilical( aPanel, aDC, GR_XOR, -MoveVector ); // Redraw text Text->Draw( aPanel, aDC, GR_XOR, MoveVector ); }
/** * Abort text move in progress. * * If a text is selected, its initial coordinates are regenerated. */ static void AbortMoveTextModule( EDA_DRAW_PANEL* Panel, wxDC* DC ) { BASE_SCREEN* screen = Panel->GetScreen(); TEXTE_MODULE* Text = static_cast<TEXTE_MODULE*>( screen->GetCurItem() ); MODULE* Module; Panel->SetMouseCapture( NULL, NULL ); if( Text == NULL ) return; Module = static_cast<MODULE*>( Text->GetParent() ); Text->DrawUmbilical( Panel, DC, GR_XOR, -MoveVector ); Text->Draw( Panel, DC, GR_XOR, MoveVector ); // If the text was moved (the move does not change internal data) // it could be rotated while moving. So set old value for orientation if( Text->IsMoving() ) Text->SetTextAngle( TextInitialOrientation ); // Redraw the text Panel->RefreshDrawingRect( Text->GetBoundingBox() ); // leave it at (0,0) so we can use it Rotate when not moving. MoveVector.x = MoveVector.y = 0; Text->ClearFlags(); Module->ClearFlags(); screen->SetCurItem( NULL ); }
// Redraw the contour of the track while moving the mouse static void ShowTargetShapeWhileMovingMouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); PCB_TARGET* target = (PCB_TARGET*) screen->GetCurItem(); if( target == NULL ) return; if( aErase ) target->Draw( aPanel, aDC, GR_XOR ); target->SetPosition( aPanel->GetParent()->GetCrossHairPosition() ); target->Draw( aPanel, aDC, GR_XOR ); }
/* Move selected sheet with the cursor. * Callback function use by m_mouseCaptureCallback. */ static void MoveOrResizeSheet( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { wxPoint moveVector; BASE_SCREEN* screen = aPanel->GetScreen(); SCH_SHEET* sheet = (SCH_SHEET*) screen->GetCurItem(); if( aErase ) sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); wxPoint pos = sheet->GetPosition(); if( sheet->IsResized() ) { int width = aPanel->GetParent()->GetCrossHairPosition().x - sheet->GetPosition().x; int height = aPanel->GetParent()->GetCrossHairPosition().y - sheet->GetPosition().y; // If the sheet doesn't have any pins, clamp the minimum size to the default values. width = ( width < MIN_SHEET_WIDTH ) ? MIN_SHEET_WIDTH : width; height = ( height < MIN_SHEET_HEIGHT ) ? MIN_SHEET_HEIGHT : height; if( sheet->HasPins() ) { int gridSizeX = KiROUND( screen->GetGridSize().x ); int gridSizeY = KiROUND( screen->GetGridSize().y ); // If the sheet has pins, use the pin positions to clamp the minimum height. height = ( height < sheet->GetMinHeight() + gridSizeY ) ? sheet->GetMinHeight() + gridSizeY : height; width = ( width < sheet->GetMinWidth() + gridSizeX ) ? sheet->GetMinWidth() + gridSizeX : width; } wxPoint grid = aPanel->GetParent()->GetNearestGridPosition( wxPoint( pos.x + width, pos.y + height ) ); sheet->Resize( wxSize( grid.x - pos.x, grid.y - pos.y ) ); } else if( sheet->IsMoving() ) { moveVector = aPanel->GetParent()->GetCrossHairPosition() - pos; sheet->Move( moveVector ); } sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode ); }
/* Redraw the current moved graphic item when mouse is moving * Use this function to show an existing outline, in move command */ static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem(); if( edge == NULL ) return; MODULE* module = (MODULE*) edge->GetParent(); if( aErase ) { edge->Draw( aPanel, aDC, GR_XOR, MoveVector ); } MoveVector = -(aPanel->GetParent()->GetCrossHairPosition() - CursorInitialPosition); edge->Draw( aPanel, aDC, GR_XOR, MoveVector ); module->CalculateBoundingBox(); }
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 }