mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 18:23:15 +02:00
Replace all instances of wxLogDebug with wxLogTrace in the common and kicad folders to prevent unwanted debugging output. Add new trace flags for locale and screen object tracing. The usual smattering of code policy fixes.
484 lines
12 KiB
C++
484 lines
12 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
|
|
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
/**
|
|
* @file base_screen.cpp
|
|
* @brief BASE_SCREEN object implementation.
|
|
*/
|
|
|
|
#include <fctsys.h>
|
|
#include <macros.h>
|
|
#include <common.h>
|
|
#include <base_struct.h>
|
|
#include <base_screen.h>
|
|
#include <id.h>
|
|
#include <base_units.h>
|
|
#include <trace_helpers.h>
|
|
|
|
|
|
wxString BASE_SCREEN::m_PageLayoutDescrFileName; // the name of the page layout descr file.
|
|
|
|
|
|
BASE_SCREEN::BASE_SCREEN( KICAD_T aType ) :
|
|
EDA_ITEM( aType )
|
|
{
|
|
m_UndoRedoCountMax = DEFAULT_MAX_UNDO_ITEMS;
|
|
m_Initialized = false;
|
|
m_ScreenNumber = 1;
|
|
m_NumberOfScreens = 1; // Hierarchy: Root: ScreenNumber = 1
|
|
m_Zoom = 32.0;
|
|
m_Grid.m_Size = wxRealPoint( 50, 50 ); // Default grid size
|
|
m_Grid.m_CmdId = ID_POPUP_GRID_LEVEL_50;
|
|
m_Center = true;
|
|
m_IsPrinting = false;
|
|
m_ScrollPixelsPerUnitX = 1;
|
|
m_ScrollPixelsPerUnitY = 1;
|
|
|
|
m_FlagModified = false; // Set when any change is made on board.
|
|
m_FlagSave = false; // Used in auto save set when an auto save is required.
|
|
|
|
SetCurItem( NULL );
|
|
}
|
|
|
|
|
|
BASE_SCREEN::~BASE_SCREEN()
|
|
{
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::InitDataPoints( const wxSize& aPageSizeIU )
|
|
{
|
|
if( m_Center )
|
|
{
|
|
m_crossHairPosition.x = 0;
|
|
m_crossHairPosition.y = 0;
|
|
|
|
m_DrawOrg.x = -aPageSizeIU.x / 2;
|
|
m_DrawOrg.y = -aPageSizeIU.y / 2;
|
|
}
|
|
else
|
|
{
|
|
m_crossHairPosition.x = aPageSizeIU.x / 2;
|
|
m_crossHairPosition.y = aPageSizeIU.y / 2;
|
|
|
|
m_DrawOrg.x = 0;
|
|
m_DrawOrg.y = 0;
|
|
}
|
|
|
|
m_O_Curseur.x = m_O_Curseur.y = 0;
|
|
}
|
|
|
|
|
|
double BASE_SCREEN::GetScalingFactor() const
|
|
{
|
|
double scale = 1.0 / GetZoom();
|
|
return scale;
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::SetScalingFactor( double aScale )
|
|
{
|
|
// Limit zoom to max and min allowed values:
|
|
double zoom = Clamp( GetMinAllowedZoom(), aScale, GetMaxAllowedZoom() );
|
|
|
|
SetZoom( zoom );
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::SetFirstZoom()
|
|
{
|
|
return SetZoom( GetMinAllowedZoom() );
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::SetLastZoom()
|
|
{
|
|
return SetZoom( GetMaxAllowedZoom() );
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::SetZoom( double iu_per_du )
|
|
{
|
|
if( iu_per_du == m_Zoom )
|
|
return false;
|
|
|
|
wxLogTrace( traceScreen, "Zoom:%.16g 1/Zoom:%.16g", iu_per_du, 1/iu_per_du );
|
|
|
|
if( iu_per_du < GetMinAllowedZoom() )
|
|
return false;
|
|
|
|
if( iu_per_du > GetMaxAllowedZoom() )
|
|
return false;
|
|
|
|
m_Zoom = iu_per_du;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::SetNextZoom()
|
|
{
|
|
// Step must be AT LEAST 1.2
|
|
double target = m_Zoom * 1.2;
|
|
|
|
for( unsigned i=0; i < m_ZoomList.size(); ++i )
|
|
{
|
|
if( target < m_ZoomList[i] )
|
|
{
|
|
SetZoom( m_ZoomList[i] );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::SetPreviousZoom()
|
|
{
|
|
// Step must be AT LEAST 1.2
|
|
double target = m_Zoom / 1.2;
|
|
|
|
for( unsigned i = m_ZoomList.size(); i != 0; --i )
|
|
{
|
|
if( target > m_ZoomList[i - 1] )
|
|
{
|
|
SetZoom( m_ZoomList[i - 1] );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Build the list of human readable grid list.
|
|
* The list shows the grid size both in mils or mm.
|
|
* aMmFirst = true to have mm first and mils after
|
|
* false to have mils first and mm after
|
|
*/
|
|
int BASE_SCREEN::BuildGridsChoiceList( wxArrayString& aGridsList, bool aMmFirst) const
|
|
{
|
|
wxString msg;
|
|
wxRealPoint curr_grid_size = GetGridSize();
|
|
int idx = -1;
|
|
int idx_usergrid = -1;
|
|
|
|
for( size_t i = 0; i < GetGridCount(); i++ )
|
|
{
|
|
const GRID_TYPE& grid = m_grids[i];
|
|
double gridValueMils = To_User_Unit( INCHES, grid.m_Size.x ) * 1000;
|
|
double gridValue_mm = To_User_Unit( MILLIMETRES, grid.m_Size.x );
|
|
|
|
if( grid.m_CmdId == ID_POPUP_GRID_USER )
|
|
{
|
|
msg = _( "Custom User Grid" );
|
|
idx_usergrid = i;
|
|
}
|
|
else
|
|
{
|
|
if( aMmFirst )
|
|
msg.Printf( _( "Grid: %.4f mm (%.2f mils)" ),
|
|
gridValue_mm, gridValueMils );
|
|
else
|
|
msg.Printf( _( "Grid: %.2f mils (%.4f mm)" ),
|
|
gridValueMils, gridValue_mm );
|
|
}
|
|
|
|
aGridsList.Add( msg );
|
|
|
|
if( curr_grid_size == grid.m_Size )
|
|
idx = i;
|
|
}
|
|
|
|
if( idx < 0 )
|
|
idx = idx_usergrid;
|
|
|
|
return idx;
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::SetGridList( GRIDS& gridlist )
|
|
{
|
|
if( !m_grids.empty() )
|
|
m_grids.clear();
|
|
|
|
m_grids = gridlist;
|
|
}
|
|
|
|
|
|
int BASE_SCREEN::SetGrid( const wxRealPoint& size )
|
|
{
|
|
wxASSERT( !m_grids.empty() );
|
|
|
|
GRID_TYPE nearest_grid = m_grids[0];
|
|
int gridIdx = 0;
|
|
|
|
for( unsigned i = 0; i < m_grids.size(); i++ )
|
|
{
|
|
if( m_grids[i].m_Size == size )
|
|
{
|
|
m_Grid = m_grids[i];
|
|
return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
|
|
}
|
|
|
|
// keep track of the nearest larger grid size, if the exact size is not found
|
|
if ( size.x < m_grids[i].m_Size.x )
|
|
{
|
|
gridIdx = m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
|
|
nearest_grid = m_grids[i];
|
|
}
|
|
}
|
|
|
|
m_Grid = nearest_grid;
|
|
|
|
wxLogWarning( _( "Grid size( %f, %f ) not in grid list, falling back "
|
|
"to grid size( %f, %f )." ),
|
|
size.x, size.y, m_Grid.m_Size.x, m_Grid.m_Size.y );
|
|
|
|
return gridIdx;
|
|
}
|
|
|
|
|
|
int BASE_SCREEN::SetGrid( int aCommandId )
|
|
{
|
|
wxASSERT( !m_grids.empty() );
|
|
|
|
for( unsigned i = 0; i < m_grids.size(); i++ )
|
|
{
|
|
if( m_grids[i].m_CmdId == aCommandId )
|
|
{
|
|
m_Grid = m_grids[i];
|
|
return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
|
|
}
|
|
}
|
|
|
|
m_Grid = m_grids[0];
|
|
|
|
wxLogWarning( _( "Grid ID %d not in grid list, falling back to "
|
|
"grid size( %g, %g )." ), aCommandId,
|
|
m_Grid.m_Size.x, m_Grid.m_Size.y );
|
|
|
|
return m_grids[0].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::AddGrid( const GRID_TYPE& grid )
|
|
{
|
|
for( unsigned i = 0; i < m_grids.size(); i++ )
|
|
{
|
|
if( m_grids[i].m_Size == grid.m_Size && grid.m_CmdId != ID_POPUP_GRID_USER )
|
|
{
|
|
wxLogTrace( traceScreen, "Discarding duplicate grid size( %g, %g ).",
|
|
grid.m_Size.x, grid.m_Size.y );
|
|
return;
|
|
}
|
|
|
|
if( m_grids[i].m_CmdId == grid.m_CmdId )
|
|
{
|
|
wxLogTrace( traceScreen, wxT( "Changing grid ID %d from size( %g, %g ) to " ) \
|
|
wxT( "size( %g, %g )." ),
|
|
grid.m_CmdId, m_grids[i].m_Size.x,
|
|
m_grids[i].m_Size.y, grid.m_Size.x, grid.m_Size.y );
|
|
m_grids[i].m_Size = grid.m_Size;
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_grids.push_back( grid );
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::AddGrid( const wxRealPoint& size, int id )
|
|
{
|
|
GRID_TYPE grid;
|
|
|
|
grid.m_Size = size;
|
|
grid.m_CmdId = id;
|
|
AddGrid( grid );
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::AddGrid( const wxRealPoint& size, EDA_UNITS_T aUnit, int id )
|
|
{
|
|
wxRealPoint new_size;
|
|
GRID_TYPE new_grid;
|
|
|
|
new_size.x = From_User_Unit( aUnit, size.x );
|
|
new_size.y = From_User_Unit( aUnit, size.y );
|
|
new_grid.m_CmdId = id;
|
|
new_grid.m_Size = new_size;
|
|
|
|
AddGrid( new_grid );
|
|
}
|
|
|
|
|
|
GRID_TYPE& BASE_SCREEN::GetGrid( size_t aIndex )
|
|
{
|
|
wxCHECK_MSG( !m_grids.empty() && aIndex < m_grids.size(), m_Grid,
|
|
wxT( "Cannot get grid object outside the bounds of the grid list." ) );
|
|
|
|
return m_grids[ aIndex ];
|
|
}
|
|
|
|
|
|
bool BASE_SCREEN::GridExists( int aCommandId )
|
|
{
|
|
// tests for grid command ID (not an index in grid list, but a wxID) exists in grid list.
|
|
for( unsigned i = 0; i < m_grids.size(); i++ )
|
|
{
|
|
if( m_grids[i].m_CmdId == aCommandId )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
wxPoint BASE_SCREEN::getNearestGridPosition( const wxPoint& aPosition,
|
|
const wxPoint& aGridOrigin, wxRealPoint* aGridSize ) const
|
|
{
|
|
wxPoint pt;
|
|
wxRealPoint gridSize;
|
|
|
|
if( aGridSize )
|
|
gridSize = *aGridSize;
|
|
else
|
|
gridSize = GetGridSize();
|
|
|
|
double offset = fmod( aGridOrigin.x, gridSize.x );
|
|
int x = KiROUND( (aPosition.x - offset) / gridSize.x );
|
|
|
|
pt.x = KiROUND( x * gridSize.x + offset );
|
|
|
|
offset = fmod( aGridOrigin.y, gridSize.y );
|
|
|
|
int y = KiROUND( (aPosition.y - offset) / gridSize.y );
|
|
pt.y = KiROUND ( y * gridSize.y + offset );
|
|
|
|
return pt;
|
|
}
|
|
|
|
|
|
wxPoint BASE_SCREEN::getCursorPosition( bool aOnGrid, const wxPoint& aGridOrigin,
|
|
wxRealPoint* aGridSize ) const
|
|
{
|
|
if( aOnGrid )
|
|
return getNearestGridPosition( m_crossHairPosition, aGridOrigin, aGridSize );
|
|
|
|
return m_crossHairPosition;
|
|
}
|
|
|
|
|
|
wxPoint BASE_SCREEN::getCrossHairScreenPosition() const
|
|
{
|
|
wxPoint pos = m_crossHairPosition - m_DrawOrg;
|
|
double scalar = GetScalingFactor();
|
|
|
|
pos.x = KiROUND( (double) pos.x * scalar );
|
|
pos.y = KiROUND( (double) pos.y * scalar );
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::setCrossHairPosition( const wxPoint& aPosition, const wxPoint& aGridOrigin,
|
|
bool aSnapToGrid )
|
|
{
|
|
if( aSnapToGrid )
|
|
m_crossHairPosition = getNearestGridPosition( aPosition, aGridOrigin, NULL );
|
|
else
|
|
m_crossHairPosition = aPosition;
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::ClearUndoRedoList()
|
|
{
|
|
ClearUndoORRedoList( m_UndoList );
|
|
ClearUndoORRedoList( m_RedoList );
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::PushCommandToUndoList( PICKED_ITEMS_LIST* aNewitem )
|
|
{
|
|
m_UndoList.PushCommand( aNewitem );
|
|
|
|
// Delete the extra items, if count max reached
|
|
if( m_UndoRedoCountMax > 0 )
|
|
{
|
|
int extraitems = GetUndoCommandCount() - m_UndoRedoCountMax;
|
|
|
|
if( extraitems > 0 )
|
|
ClearUndoORRedoList( m_UndoList, extraitems );
|
|
}
|
|
}
|
|
|
|
|
|
void BASE_SCREEN::PushCommandToRedoList( PICKED_ITEMS_LIST* aNewitem )
|
|
{
|
|
m_RedoList.PushCommand( aNewitem );
|
|
|
|
// Delete the extra items, if count max reached
|
|
if( m_UndoRedoCountMax > 0 )
|
|
{
|
|
int extraitems = GetRedoCommandCount() - m_UndoRedoCountMax;
|
|
|
|
if( extraitems > 0 )
|
|
ClearUndoORRedoList( m_RedoList, extraitems );
|
|
}
|
|
}
|
|
|
|
|
|
PICKED_ITEMS_LIST* BASE_SCREEN::PopCommandFromUndoList( )
|
|
{
|
|
return m_UndoList.PopCommand();
|
|
}
|
|
|
|
|
|
PICKED_ITEMS_LIST* BASE_SCREEN::PopCommandFromRedoList( )
|
|
{
|
|
return m_RedoList.PopCommand();
|
|
}
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
void BASE_SCREEN::Show( int nestLevel, std::ostream& os ) const
|
|
{
|
|
// for now, make it look like XML, expand on this later.
|
|
NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
|
|
|
|
/* this class will eventually go away, but here's a place holder until then.
|
|
for( EDA_ITEM* item = m_drawList; item; item = item->Next() )
|
|
{
|
|
item->Show( nestLevel+1, os );
|
|
}
|
|
*/
|
|
|
|
NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
|
|
}
|
|
|
|
#endif
|