258 lines
7.8 KiB
C++
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();
|
|
}
|