Files
kicad-source-mirror/common/widgets/zoom_correction_ctrl.cpp
T

258 lines
7.8 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 3
* 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.
*
* Inspired by the Inkscape preferences widget, which is
* Authors:
* Marco Scholten
* Bruno Dilly <bruno.dilly@gmail.com>
*
* Copyright (C) 2004, 2006, 2007 Authors
*
* Released under GNU GPL v2+
*/
#include <advanced_config.h>
#include <widgets/zoom_correction_ctrl.h>
#include <widgets/ui_common.h>
#include <wx/dcclient.h>
#include <wx/display.h>
#include <wx/math.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/settings.h>
class ZOOM_CORRECTION_RULER : public wxPanel
{
public:
ZOOM_CORRECTION_RULER( wxWindow* aParent ) :
wxPanel( aParent, wxID_ANY, wxDefaultPosition, aParent->FromDIP( wxSize( 200, 30 ) ),
wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE )
{
Bind( wxEVT_PAINT, &ZOOM_CORRECTION_RULER::OnPaint, this );
}
private:
void OnPaint( wxPaintEvent& )
{
wxPaintDC dc( this );
wxSize size = GetClientSize();
dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) ) );
// Draw baseline
dc.DrawLine( 0, size.y - 1, size.x, size.y - 1 );
ZOOM_CORRECTION_CTRL* parent = static_cast<ZOOM_CORRECTION_CTRL*>( GetParent() );
if( !parent )
return;
double value = parent->GetValue();
ZOOM_CORRECTION_UNITS units = static_cast<ZOOM_CORRECTION_UNITS>( parent->GetUnitsSelection() );
double dpi = ADVANCED_CFG::GetCfg().m_ScreenDPI;
double unitsPerInch = 25.4;
if( units == ZOOM_CORRECTION_UNITS::CM )
unitsPerInch = 2.54;
else if( units == ZOOM_CORRECTION_UNITS::INCH )
unitsPerInch = 1.0;
double pxPerUnit = dpi / unitsPerInch * value;
// Minimum spacing between number labels to prevent overlap (in pixels)
int minLabelSpacing = GetTextExtent( wxT( "000_" ) ).x;
double lastLabelX = -minLabelSpacing;
int majorTickEvery = 10;
double tickLabelDiv = 1;
double pxPerMinorTick;
// Draw major and minor tick marks with numbering
if( units == ZOOM_CORRECTION_UNITS::INCH )
{
majorTickEvery = 4;
tickLabelDiv = 4;
pxPerMinorTick = pxPerUnit / 4.0; // 1/4 inch intervals
}
else if( units == ZOOM_CORRECTION_UNITS::CM )
{
majorTickEvery = 10;
tickLabelDiv = 10;
pxPerMinorTick = pxPerUnit / 10.0; // 1mm intervals
}
else // MM
{
// For mm: Same as cm ruler but numbers count by 10 (so 10mm, 20mm, etc.)
majorTickEvery = 10;
tickLabelDiv = 1;
pxPerMinorTick = pxPerUnit;
}
if( pxPerMinorTick < 3 )
{
pxPerMinorTick *= 2;
majorTickEvery /= 2;
tickLabelDiv /= 2;
}
for( double x = 0; x <= size.x; x += pxPerMinorTick )
{
int tickCount = (int) round( x / pxPerMinorTick );
if( tickCount % majorTickEvery == 0 )
{
// Major tick
dc.DrawLine( x, size.y - 1, x, size.y - 16 );
int labelNum = wxRound(tickCount / tickLabelDiv);
if( labelNum > 0 && x < size.x - 10 && ( x - lastLabelX ) >= minLabelSpacing )
{
wxString label = wxString::Format( wxT( "%d" ), labelNum );
wxSize textSize = dc.GetTextExtent( label );
dc.DrawText( label, x - textSize.x / 2, 0 );
lastLabelX = x;
}
}
else
{
// Minor tick
dc.DrawLine( x, size.y - 1, x, size.y - 8 );
}
}
}
};
ZOOM_CORRECTION_CTRL::ZOOM_CORRECTION_CTRL( wxWindow* aParent, double& aValue, double aBaseValue ) :
wxPanel( aParent, wxID_ANY ),
m_baseValue( aBaseValue ),
m_value( &aValue )
{
wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
// Top section: Label, spinner, auto button
wxBoxSizer* controlsSizer = new wxBoxSizer( wxHORIZONTAL );
m_label = new wxStaticText( this, wxID_ANY, _( "Display PPI: " ) );
controlsSizer->Add( m_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, KIUI::GetStdMargin() );
m_spinner = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, 10, 1000, (int)( aValue * m_baseValue ) );
controlsSizer->Add( m_spinner, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, KIUI::GetStdMargin() );
m_autoButton = new wxButton( this, wxID_ANY, _( "Detect" ) );
controlsSizer->Add( m_autoButton, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, KIUI::GetStdMargin() );
topSizer->Add( controlsSizer, 0, wxEXPAND, KIUI::GetStdMargin() );
// Middle section: Ruler and units choice
wxBoxSizer* rulerSizer = new wxBoxSizer( wxHORIZONTAL );
m_ruler = new ZOOM_CORRECTION_RULER( this );
rulerSizer->Add( m_ruler, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, KIUI::GetStdMargin() );
wxArrayString choices;
choices.Add( wxT( "mm" ) );
choices.Add( wxT( "cm" ) );
choices.Add( wxT( "in" ) );
m_unitsChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices );
m_unitsChoice->SetSelection( 0 ); // Default to MM
rulerSizer->Add( m_unitsChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxTOP, KIUI::GetStdMargin() );
topSizer->Add( rulerSizer, 0, wxEXPAND | wxTOP, KIUI::GetStdMargin() );
SetSizer( topSizer );
m_autoButton->Bind( wxEVT_BUTTON, &ZOOM_CORRECTION_CTRL::autoPressed, this );
m_spinner->Bind( wxEVT_SPINCTRL, &ZOOM_CORRECTION_CTRL::spinnerChanged, this );
m_unitsChoice->Bind( wxEVT_CHOICE, &ZOOM_CORRECTION_CTRL::unitsChanged, this );
// Ensure initial synchronization of all controls
m_ruler->Refresh();
}
void ZOOM_CORRECTION_CTRL::SetDisplayedValue( double aValue )
{
m_spinner->SetValue( (int)( aValue * m_baseValue ) );
m_ruler->Refresh();
}
double ZOOM_CORRECTION_CTRL::GetValue() const
{
return (double) m_spinner->GetValue() / m_baseValue;
}
int ZOOM_CORRECTION_CTRL::GetUnitsSelection() const
{
return m_unitsChoice->GetSelection();
}
bool ZOOM_CORRECTION_CTRL::TransferDataToWindow()
{
m_spinner->SetValue( (int)( *m_value * m_baseValue ) );
m_ruler->Refresh();
return true;
}
bool ZOOM_CORRECTION_CTRL::TransferDataFromWindow()
{
*m_value = GetValue();
return true;
}
void ZOOM_CORRECTION_CTRL::spinnerChanged( wxSpinEvent& )
{
*m_value = m_spinner->GetValue() / m_baseValue;
m_ruler->Refresh();
}
void ZOOM_CORRECTION_CTRL::unitsChanged( wxCommandEvent& )
{
m_ruler->Refresh();
}
void ZOOM_CORRECTION_CTRL::autoPressed( wxCommandEvent& aEvent )
{
wxDisplay dpy( this );
double val = 0.0;
#if wxCHECK_VERSION( 3, 3, 2 )
wxSize rawPPI = dpy.GetRawPPI();
val = wxRound( ( rawPPI.x + rawPPI.y ) / 2.0 );
#endif
if( val < 10 )
{
#ifdef wxHAS_DPI_INDEPENDENT_PIXELS
val = dpy.GetStdPPIValue() / dpy.GetScaleFactor();
#else
wxSize ppi = dpy.GetPPI();
val = wxRound( ( ppi.x + ppi.y ) / 2.0 );
#endif
}
m_spinner->SetValue( val );
m_ruler->Refresh();
}