From c48f4272f3f305ff9ad0727f0fbd25cc11698a52 Mon Sep 17 00:00:00 2001
From: Jeff Young <jeff@rokeby.ie>
Date: Sat, 13 Jun 2020 22:09:02 +0100
Subject: [PATCH] Collapse a level out of the zoom settings.

The APP_SETTINGS_BASE now holds the list of zoom factors, and
the old legacy (screen-based) code has been removed.
---
 common/base_screen.cpp                        |  21 ---
 common/draw_panel_gal.cpp                     |  11 +-
 common/eda_draw_frame.cpp                     |  10 +-
 common/settings/app_settings.cpp              |   3 +
 common/tool/common_tools.cpp                  |  45 +++---
 common/tool/grid_menu.cpp                     |   3 +-
 common/tool/zoom_menu.cpp                     |  41 ++---
 cvpcb/display_footprints_frame.cpp            |   2 -
 eeschema/cross-probing.cpp                    |   1 -
 eeschema/dialogs/dialog_erc.cpp               |   1 -
 eeschema/dialogs/dialog_migrate_buses.cpp     |   1 -
 .../dialogs/dialog_print_using_printer.cpp    |   5 +-
 eeschema/eeschema_config.cpp                  |  23 +++
 eeschema/sch_base_frame.cpp                   |  19 ---
 eeschema/sch_base_frame.h                     |   8 -
 eeschema/sch_edit_frame.cpp                   |   2 -
 eeschema/sch_screen.cpp                       |  34 -----
 eeschema/sheet.cpp                            |   6 +-
 eeschema/tools/sch_editor_control.cpp         |   1 -
 gerbview/CMakeLists.txt                       |   1 -
 gerbview/clear_gbr_drawlayers.cpp             |   2 +
 gerbview/gbr_screen.cpp                       |  71 ---------
 gerbview/gbr_screen.h                         |  53 -------
 gerbview/gerbview_frame.cpp                   | 143 +++++++++---------
 gerbview/gerbview_frame.h                     |  13 +-
 include/base_screen.h                         |  47 +-----
 include/class_draw_panel_gal.h                |   6 -
 include/convert_to_biu.h                      |  51 +++++++
 include/eda_draw_frame.h                      |  16 +-
 include/id.h                                  |  28 ----
 include/pcb_base_frame.h                      |   6 -
 include/settings/app_settings.h               |   2 +
 .../dialogs/dialogs_for_printing.cpp          |   5 +-
 pagelayout_editor/pl_editor_frame.cpp         |  55 ++++---
 pagelayout_editor/pl_editor_frame.h           |   6 -
 pagelayout_editor/pl_editor_screen.cpp        |  37 +----
 pcbnew/footprint_edit_frame.cpp               |   1 -
 pcbnew/footprint_viewer_frame.cpp             |   1 -
 pcbnew/footprint_wizard_frame.cpp             |   1 -
 pcbnew/pcb_base_frame.cpp                     |  64 ++++----
 pcbnew/pcb_edit_frame.cpp                     |   1 -
 pcbnew/pcb_screen.cpp                         |  90 +----------
 42 files changed, 286 insertions(+), 651 deletions(-)
 delete mode 100644 gerbview/gbr_screen.cpp
 delete mode 100644 gerbview/gbr_screen.h

diff --git a/common/base_screen.cpp b/common/base_screen.cpp
index 4e90f3bbd6..de71a49be1 100644
--- a/common/base_screen.cpp
+++ b/common/base_screen.cpp
@@ -27,7 +27,6 @@
 #include <base_screen.h>
 #include <base_struct.h>
 #include <fctsys.h>
-#include <id.h>
 #include <trace_helpers.h>
 
 
@@ -41,7 +40,6 @@ BASE_SCREEN::BASE_SCREEN( EDA_ITEM* aParent, KICAD_T aType ) :
     m_Initialized      = false;
     m_ScreenNumber     = 1;
     m_NumberOfScreens  = 1;      // Hierarchy: Root: ScreenNumber = 1
-    m_Zoom             = 32.0;
     m_Center           = true;
 
     m_FlagModified     = false;     // Set when any change is made on board.
@@ -72,25 +70,6 @@ void BASE_SCREEN::InitDataPoints( const wxSize& aPageSizeIU )
 }
 
 
-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;
-}
-
-
 void BASE_SCREEN::ClearUndoRedoList()
 {
     ClearUndoORRedoList( m_UndoList );
diff --git a/common/draw_panel_gal.cpp b/common/draw_panel_gal.cpp
index 6236e7b6ac..b2533266be 100644
--- a/common/draw_panel_gal.cpp
+++ b/common/draw_panel_gal.cpp
@@ -158,13 +158,10 @@ void EDA_DRAW_PANEL_GAL::SetFocus()
 
 void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
 {
-    // Update current zoom settings if the canvas is managed by a EDA frame
+    // Update scroll position if the canvas is managed by a EDA frame
     // (i.e. not by a preview panel in a dialog)
     if( GetParentEDAFrame() && GetParentEDAFrame()->GetScreen() )
-    {
-        GetParentEDAFrame()->GetScreen()->SetZoom( GetLegacyZoom() );
         GetParentEDAFrame()->GetScreen()->m_ScrollCenter = GetView()->GetCenter();
-    }
 
     m_viewControls->UpdateScrollbars();
 
@@ -355,12 +352,6 @@ void EDA_DRAW_PANEL_GAL::SetTopLayer( int aLayer )
 }
 
 
-double EDA_DRAW_PANEL_GAL::GetLegacyZoom() const
-{
-    return m_edaFrame->GetZoomLevelCoeff() / m_gal->GetZoomFactor();
-}
-
-
 bool EDA_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType )
 {
     // Do not do anything if the currently used GAL is correct
diff --git a/common/eda_draw_frame.cpp b/common/eda_draw_frame.cpp
index 30fa8d4535..e9f4f0c921 100644
--- a/common/eda_draw_frame.cpp
+++ b/common/eda_draw_frame.cpp
@@ -87,7 +87,6 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame
                                                 // BLACK for Pcbnew, BLACK or WHITE for eeschema
     m_colorSettings       = nullptr;
     m_MsgFrameHeight      = EDA_MSG_PANEL::GetRequiredHeight();
-    m_zoomLevelCoeff      = 1.0;
     m_userUnits           = EDA_UNITS::MILLIMETRES;
     m_PolarCoords         = false;
     m_findReplaceData     = new wxFindReplaceData( wxFR_DOWN );
@@ -342,12 +341,6 @@ void EDA_DRAW_FRAME::OnSelectZoom( wxCommandEvent& event )
 }
 
 
-double EDA_DRAW_FRAME::GetZoom()
-{
-    return GetScreen()->GetZoom();
-}
-
-
 void EDA_DRAW_FRAME::OnMove( wxMoveEvent& aEvent )
 {
     // If the window is moved to a different display, the scaling factor may change
@@ -458,7 +451,8 @@ const wxString EDA_DRAW_FRAME::GetZoomLevelIndicator() const
 {
     // returns a human readable value which can be displayed as zoom
     // level indicator in dialogs.
-    return wxString::Format( wxT( "Z %.2f" ), m_canvas->GetGAL()->GetZoomFactor() );
+    double zoom = m_canvas->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
+    return wxString::Format( wxT( "Z %.2f" ), zoom );
 }
 
 
diff --git a/common/settings/app_settings.cpp b/common/settings/app_settings.cpp
index 5194c2277b..59ba41e67c 100644
--- a/common/settings/app_settings.cpp
+++ b/common/settings/app_settings.cpp
@@ -255,6 +255,9 @@ void APP_SETTINGS_BASE::addParamsForWindow( WINDOW_SETTINGS* aWindow, const std:
 
     m_params.emplace_back( new PARAM<int>( aJsonPath + ".pos_y", &aWindow->pos_y, 0 ) );
 
+    m_params.emplace_back( new PARAM_LIST<double>( aJsonPath + ".zoom_factors",
+            &aWindow->zoom_factors, {} ) );
+
     m_params.emplace_back( new PARAM<bool>( aJsonPath + ".grid.axes_enabled",
             &aWindow->grid.axes_enabled, false ) );
 
diff --git a/common/tool/common_tools.cpp b/common/tool/common_tools.cpp
index dabf9be4f0..40ff9d81a0 100644
--- a/common/tool/common_tools.cpp
+++ b/common/tool/common_tools.cpp
@@ -195,30 +195,19 @@ int COMMON_TOOLS::ZoomInOutCenter( const TOOL_EVENT& aEvent )
 
 int COMMON_TOOLS::doZoomInOut( bool aDirection, bool aCenterOnCursor )
 {
-    double zoom = m_frame->GetCanvas()->GetLegacyZoom();
+    double zoom = getView()->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
 
     // Step must be AT LEAST 1.3
     if( aDirection )
-        zoom /= 1.3;
-    else
         zoom *= 1.3;
+    else
+        zoom /= 1.3;
 
     // Now look for the next closest menu step
-    std::vector<double>& zoomList = m_frame->GetScreen()->m_ZoomList;
+    std::vector<double>& zoomList = m_toolMgr->GetSettings()->m_Window.zoom_factors;
     int idx;
 
     if( aDirection )
-    {
-        for( idx = zoomList.size() - 1; idx >= 0; --idx )
-        {
-            if( zoomList[idx] <= zoom )
-                break;
-        }
-
-        if( idx < 0 )
-            idx = 0;        // if we ran off the end then peg to the end
-    }
-    else
     {
         for( idx = 0; idx < (int)zoomList.size(); ++idx )
         {
@@ -226,8 +215,19 @@ int COMMON_TOOLS::doZoomInOut( bool aDirection, bool aCenterOnCursor )
                 break;
         }
 
-        if( idx >= (int)zoomList.size() )
-            idx = zoomList.size() - 1;        // if we ran off the end then peg to the end
+        if( idx >= zoomList.size() )
+            idx = (int) zoomList.size() - 1;        // if we ran off the end then peg to the end
+    }
+    else
+    {
+        for( idx = (int) zoomList.size() - 1; idx >= 0; --idx )
+        {
+            if( zoomList[idx] <= zoom )
+                break;
+        }
+
+        if( idx < 0 )
+            idx = 0;        // if we ran off the end then peg to the end
     }
 
     return doZoomToPreset( idx + 1, aCenterOnCursor );
@@ -313,15 +313,14 @@ int COMMON_TOOLS::CenterContents( const TOOL_EVENT& aEvent )
 int COMMON_TOOLS::ZoomPreset( const TOOL_EVENT& aEvent )
 {
     unsigned int idx = aEvent.Parameter<intptr_t>();
-    return doZoomToPreset( idx, false );
+    return doZoomToPreset( (int) idx, false );
 }
 
 
 // Note: idx == 0 is Auto; idx == 1 is first entry in zoomList
 int COMMON_TOOLS::doZoomToPreset( int idx, bool aCenterOnCursor )
 {
-    std::vector<double>& zoomList = m_frame->GetScreen()->m_ZoomList;
-    KIGFX::VIEW* view = m_frame->GetCanvas()->GetView();
+    std::vector<double>& zoomList = m_toolMgr->GetSettings()->m_Window.zoom_factors;
 
     if( idx == 0 )      // Zoom Auto
     {
@@ -333,18 +332,18 @@ int COMMON_TOOLS::doZoomToPreset( int idx, bool aCenterOnCursor )
         idx--;
     }
 
-    double scale = m_frame->GetZoomLevelCoeff() / zoomList[idx];
+    double scale = zoomList[idx] * ZOOM_COEFF;
 
     if( aCenterOnCursor )
     {
-        view->SetScale( scale, getViewControls()->GetCursorPosition() );
+        getView()->SetScale( scale, getViewControls()->GetCursorPosition() );
 
         if( getViewControls()->IsCursorWarpingEnabled() )
             getViewControls()->CenterOnCursor();
     }
     else
     {
-        view->SetScale( scale );
+        getView()->SetScale( scale );
     }
 
     return 0;
diff --git a/common/tool/grid_menu.cpp b/common/tool/grid_menu.cpp
index 79d2917f43..728c1edb3b 100644
--- a/common/tool/grid_menu.cpp
+++ b/common/tool/grid_menu.cpp
@@ -2,8 +2,8 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2015 CERN
- * @author Maciej Suminski <maciej.suminski@cern.ch>
  * Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
+ * @author Maciej Suminski <maciej.suminski@cern.ch>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,7 +26,6 @@
 #include <tool/grid_menu.h>
 #include <id.h>
 #include <eda_draw_frame.h>
-#include <base_screen.h>
 #include <settings/app_settings.h>
 #include <tool/actions.h>
 #include <bitmaps.h>
diff --git a/common/tool/zoom_menu.cpp b/common/tool/zoom_menu.cpp
index 0b043991bd..345e1feccc 100644
--- a/common/tool/zoom_menu.cpp
+++ b/common/tool/zoom_menu.cpp
@@ -2,6 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2015 CERN
+ * Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
  * @author Maciej Suminski <maciej.suminski@cern.ch>
  *
  * This program is free software; you can redistribute it and/or
@@ -23,61 +24,49 @@
  */
 
 #include <tool/zoom_menu.h>
-#include <id.h>
 #include <eda_draw_frame.h>
-#include <base_screen.h>
+#include <settings/app_settings.h>
 #include <tool/actions.h>
+#include <gal/graphics_abstraction_layer.h>
 #include <bitmaps.h>
-
+#include <convert_to_biu.h>
 #include <functional>
+
 using namespace std::placeholders;
 
 ZOOM_MENU::ZOOM_MENU( EDA_DRAW_FRAME* aParent ) :
         ACTION_MENU( true ),
         m_parent( aParent )
 {
-    BASE_SCREEN* screen = aParent->GetScreen();
-
     SetTitle( _( "Zoom" ) );
     SetIcon( zoom_selection_xpm );
 
-    //int zoom = screen->GetZoom();
-    int maxZoomIds = std::min( ID_POPUP_ZOOM_LEVEL_END - ID_POPUP_ZOOM_LEVEL_START,
-                               (int) screen->m_ZoomList.size() );
+    int i = 1;  // 0 reserved for menus which support auto-zoom
 
-    for( int i = 0; i < maxZoomIds; ++i )
-    {
-        Append( ID_POPUP_ZOOM_LEVEL_START+1 + i,   // ID_POPUP_ZOOM_LEVEL_START == Auto
-            wxString::Format( _( "Zoom: %.2f" ), aParent->GetZoomLevelCoeff() / screen->m_ZoomList[i] ),
-            wxEmptyString, wxITEM_CHECK );
-    }
+    for( double factor : m_parent->config()->m_Window.zoom_factors )
+        Append( i++, wxString::Format( _( "Zoom: %.2f" ), factor ), wxEmptyString, wxITEM_CHECK );
 }
 
 
 OPT_TOOL_EVENT ZOOM_MENU::eventHandler( const wxMenuEvent& aEvent )
 {
     OPT_TOOL_EVENT event( ACTIONS::zoomPreset.MakeEvent() );
-    intptr_t idx = aEvent.GetId() - ID_POPUP_ZOOM_LEVEL_START;
-    event->SetParameter( idx );
-
+    event->SetParameter( (intptr_t) aEvent.GetId() );
     return event;
 }
 
 
 void ZOOM_MENU::update()
 {
-    BASE_SCREEN* screen = m_parent->GetScreen();
-    double zoom = screen->GetZoom();
-    const std::vector<double>& zoomList = m_parent->GetScreen()->m_ZoomList;
+    double zoom = m_parent->GetCanvas()->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
 
-    // Check the current zoom
-    int maxZoomIds = std::min( ID_POPUP_ZOOM_LEVEL_END - ID_POPUP_ZOOM_LEVEL_START,
-                               (int) screen->m_ZoomList.size() );
+    const std::vector<double>& zoomList = m_parent->config()->m_Window.zoom_factors;
 
-    for( int i = 0; i < maxZoomIds; ++i )
+    for( int i = 0; i < zoomList.size(); ++i )
     {
         // Search for a value near the current zoom setting:
-        double rel_error = std::fabs( zoomList[i] - zoom )/zoom;
-        Check( ID_POPUP_ZOOM_LEVEL_START+1 + i, rel_error < 0.1 );
+        double rel_error = std::fabs( zoomList[i] - zoom ) / zoom;
+        // IDs start with 1 (leaving 0 for auto-zoom)
+        Check( i+1, rel_error < 0.1 );
     }
 }
diff --git a/cvpcb/display_footprints_frame.cpp b/cvpcb/display_footprints_frame.cpp
index 34e5f61c43..e2e8168a8a 100644
--- a/cvpcb/display_footprints_frame.cpp
+++ b/cvpcb/display_footprints_frame.cpp
@@ -146,8 +146,6 @@ DISPLAY_FOOTPRINTS_FRAME::DISPLAY_FOOTPRINTS_FRAME( KIWAY* aKiway, wxWindow* aPa
     auto& galOpts = GetGalDisplayOptions();
     galOpts.m_axesEnabled = true;
 
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
-
     ActivateGalCanvas();
 
     // Restore last zoom.  (If auto-zooming we'll adjust when we load the footprint.)
diff --git a/eeschema/cross-probing.cpp b/eeschema/cross-probing.cpp
index 7efffa76e3..12fa89f3db 100644
--- a/eeschema/cross-probing.cpp
+++ b/eeschema/cross-probing.cpp
@@ -103,7 +103,6 @@ SCH_ITEM* SCH_EDITOR_CONTROL::FindComponentAndItem( const wxString& aReference,
     {
         if( *sheetWithComponentFound != m_frame->GetCurrentSheet() )
         {
-            sheetWithComponentFound->LastScreen()->SetZoom( m_frame->GetScreen()->GetZoom() );
             m_frame->Schematic().SetCurrentSheet( *sheetWithComponentFound );
             m_frame->DisplayCurrentSheet();
         }
diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp
index f1b991c19a..11221d77f0 100644
--- a/eeschema/dialogs/dialog_erc.cpp
+++ b/eeschema/dialogs/dialog_erc.cpp
@@ -361,7 +361,6 @@ void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
 
             m_parent->SetCurrentSheet( sheet );
             m_parent->DisplayCurrentSheet();
-            sheet.LastScreen()->SetZoom( m_parent->GetScreen()->GetZoom() );
             m_parent->RedrawScreen( (wxPoint) m_parent->GetScreen()->m_ScrollCenter, false );
         }
 
diff --git a/eeschema/dialogs/dialog_migrate_buses.cpp b/eeschema/dialogs/dialog_migrate_buses.cpp
index 1339dcf872..3559019840 100644
--- a/eeschema/dialogs/dialog_migrate_buses.cpp
+++ b/eeschema/dialogs/dialog_migrate_buses.cpp
@@ -178,7 +178,6 @@ void DIALOG_MIGRATE_BUSES::onItemSelected( wxListEvent& aEvent )
 
     if( sheet != current )
     {
-        sheet.LastScreen()->SetZoom( m_frame->GetScreen()->GetZoom() );
         sheet.UpdateAllScreenReferences();
         m_frame->Schematic().SetCurrentSheet( sheet );
         sheet.LastScreen()->TestDanglingEnds();
diff --git a/eeschema/dialogs/dialog_print_using_printer.cpp b/eeschema/dialogs/dialog_print_using_printer.cpp
index e83129f99f..779569bca6 100644
--- a/eeschema/dialogs/dialog_print_using_printer.cpp
+++ b/eeschema/dialogs/dialog_print_using_printer.cpp
@@ -422,7 +422,6 @@ bool SCH_PRINTOUT::OnBeginDocument( int startPage, int endPage )
  */
 void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
 {
-    int      oldZoom;
     wxPoint  tmp_startvisu;
     wxSize   pageSizeIU;             // Page size in internal units
     wxPoint  old_org;
@@ -431,9 +430,8 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
 
     wxBusyCursor dummy;
 
-    // Save current scale factor, offsets, and clip box.
+    // Save current offsets and clip box.
     tmp_startvisu = aScreen->m_StartVisu;
-    oldZoom = aScreen->GetZoom();
     old_org = aScreen->m_DrawOrg;
 
     SETTINGS_MANAGER&  mgr   = Pgm().GetSettingsManager();
@@ -532,7 +530,6 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
 
     aScreen->m_StartVisu = tmp_startvisu;
     aScreen->m_DrawOrg   = old_org;
-    aScreen->SetZoom( oldZoom );
 }
 
 
diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp
index fff04f88da..e062d729f9 100644
--- a/eeschema/eeschema_config.cpp
+++ b/eeschema/eeschema_config.cpp
@@ -440,6 +440,29 @@ void SCH_BASE_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
                                      "1 mil" };
     }
 
+    if( aCfg->m_Window.zoom_factors.empty() )
+    {
+        aCfg->m_Window.zoom_factors = { 0.5,
+                                        0.7,
+                                        1.0,
+                                        1.5,
+                                        2.0,
+                                        3.0,
+                                        4.5,
+                                        6.5,
+                                        10.0,
+                                        15.0,
+                                        20.0,
+                                        30.0,
+                                        45.0,
+                                        65.0,
+                                        100.0,
+                                        150.0 };
+    }
+
+    for( double& factor : aCfg->m_Window.zoom_factors )
+        factor = std::min( factor, MAX_ZOOM_FACTOR );
+
     wxString templateFieldNames = cfg->m_Drawing.field_names;
 
     if( !templateFieldNames.IsEmpty() )
diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp
index 8a2dc0831e..46ed45fde7 100644
--- a/eeschema/sch_base_frame.cpp
+++ b/eeschema/sch_base_frame.cpp
@@ -87,10 +87,6 @@ SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindo
     m_defaults( &m_base_frame_defaults )
 {
     createCanvas();
-
-    // Adjusted to display zoom level ~ 1 when the screen shows a 1:1 image
-    // Obviously depends on the monitor, but this is an acceptable value
-    m_zoomLevelCoeff = 11.0 * IU_PER_MILS;
 }
 
 
@@ -117,12 +113,6 @@ LIBEDIT_SETTINGS* SCH_BASE_FRAME::libeditconfig() const
 }
 
 
-const wxString SCH_BASE_FRAME::GetZoomLevelIndicator() const
-{
-    return EDA_DRAW_FRAME::GetZoomLevelIndicator();
-}
-
-
 void SCH_BASE_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
 {
     GetScreen()->SetPageSettings( aPageSettings );
@@ -283,15 +273,6 @@ void SCH_BASE_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointe
 {
     KIGFX::GAL* gal = GetCanvas()->GetGAL();
 
-    double selectedZoom = GetScreen()->GetZoom();
-    double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
-    double scale = 1.0 / ( zoomFactor * selectedZoom );
-
-    if( aCenterPoint != wxPoint( 0, 0 ) )
-        GetCanvas()->GetView()->SetScale( scale, aCenterPoint );
-    else
-        GetCanvas()->GetView()->SetScale( scale );
-
     GetCanvas()->GetView()->SetCenter( aCenterPoint );
 
     if( aWarpPointer )
diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h
index b6ffaf930b..bb246a69c4 100644
--- a/eeschema/sch_base_frame.h
+++ b/eeschema/sch_base_frame.h
@@ -130,14 +130,6 @@ public:
      */
     virtual bool GetShowAllPins() const { return true; }
 
-    /**
-     * Function GetZoomLevelIndicator
-     * returns a human readable value which can be displayed as zoom
-     * level indicator in dialogs.
-     * Virtual from the base class
-     */
-    const wxString GetZoomLevelIndicator() const override;
-
     void SetPageSettings( const PAGE_INFO& aPageSettings ) override;
     const PAGE_INFO& GetPageSettings () const override;
     const wxSize GetPageSizeIU() const override;
diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp
index f14a0130ee..5abf009a01 100644
--- a/eeschema/sch_edit_frame.cpp
+++ b/eeschema/sch_edit_frame.cpp
@@ -430,8 +430,6 @@ void SCH_EDIT_FRAME::CreateScreens()
         screen->SetMaxUndoItems( m_UndoRedoCountMax );
         SetScreen( screen );
     }
-
-    GetScreen()->SetZoom( 32.0 );
 }
 
 
diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp
index 1890524b50..cfb65eb98e 100644
--- a/eeschema/sch_screen.cpp
+++ b/eeschema/sch_screen.cpp
@@ -66,35 +66,6 @@
 // TODO(JE) Debugging only
 #include <profile.h>
 
-#define ZOOM_FACTOR( x )       ( x * IU_PER_MILS )
-
-
-/* Default zoom values. Limited to these values to keep a decent size
- * to menus
- */
-static double SchematicZoomList[] =
-{
-    ZOOM_FACTOR( 0.5 ),
-    ZOOM_FACTOR( 0.7 ),
-    ZOOM_FACTOR( 1.0 ),
-    ZOOM_FACTOR( 1.5 ),
-    ZOOM_FACTOR( 2.0 ),
-    ZOOM_FACTOR( 3.0 ),
-    ZOOM_FACTOR( 4.0 ),
-    ZOOM_FACTOR( 6.0 ),
-    ZOOM_FACTOR( 8.0 ),
-    ZOOM_FACTOR( 11.0 ),
-    ZOOM_FACTOR( 13.0 ),
-    ZOOM_FACTOR( 16.0 ),
-    ZOOM_FACTOR( 20.0 ),
-    ZOOM_FACTOR( 26.0 ),
-    ZOOM_FACTOR( 32.0 ),
-    ZOOM_FACTOR( 48.0 ),
-    ZOOM_FACTOR( 64.0 ),
-    ZOOM_FACTOR( 80.0 ),
-    ZOOM_FACTOR( 128.0 )
-};
-
 
 SCH_SCREEN::SCH_SCREEN( EDA_ITEM* aParent ) :
     BASE_SCREEN( aParent, SCH_SCREEN_T ),
@@ -102,11 +73,6 @@ SCH_SCREEN::SCH_SCREEN( EDA_ITEM* aParent ) :
 {
     m_modification_sync = 0;
 
-    SetZoom( 32 );
-
-    for( unsigned zoom : SchematicZoomList )
-        m_ZoomList.push_back( zoom );
-
     m_refCount = 0;
 
     // Suitable for schematic only. For libedit and viewlib, must be set to true
diff --git a/eeschema/sheet.cpp b/eeschema/sheet.cpp
index 6247bb533c..d05bd3c1b9 100644
--- a/eeschema/sheet.cpp
+++ b/eeschema/sheet.cpp
@@ -585,13 +585,10 @@ void SCH_EDIT_FRAME::DrawCurrentSheetToClipboard()
     // Set draw offset, zoom... to values needed to draw in the memory DC
     // after saving initial values:
     wxPoint tmp_startvisu = screen->m_StartVisu;
-    double tmpzoom = screen->GetZoom();
-    wxPoint old_org = screen->m_DrawOrg;
+    wxPoint old_org       = screen->m_DrawOrg;
     screen->m_DrawOrg.x   = screen->m_DrawOrg.y = 0;
     screen->m_StartVisu.x = screen->m_StartVisu.y = 0;
 
-    screen->SetZoom( 1 );   // we use zoom = 1 in draw functions.
-
     wxMemoryDC dc;
     wxBitmap image( dcsize );
     dc.SelectObject( image );
@@ -620,7 +617,6 @@ void SCH_EDIT_FRAME::DrawCurrentSheetToClipboard()
 
     screen->m_StartVisu = tmp_startvisu;
     screen->m_DrawOrg   = old_org;
-    screen->SetZoom( tmpzoom );
 }
 
 
diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp
index 26d0e8107c..72b9296ec5 100644
--- a/eeschema/tools/sch_editor_control.cpp
+++ b/eeschema/tools/sch_editor_control.cpp
@@ -433,7 +433,6 @@ int SCH_EDITOR_CONTROL::FindNext( const TOOL_EVENT& aEvent )
                 m_frame->Schematic().SetCurrentSheet( *sheet );
                 m_frame->GetCurrentSheet().UpdateAllScreenReferences();
 
-                screen->SetZoom( m_frame->GetScreen()->GetZoom() );
                 screen->TestDanglingEnds();
 
                 m_frame->SetScreen( screen );
diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt
index 24fd6d110d..87527ef3e2 100644
--- a/gerbview/CMakeLists.txt
+++ b/gerbview/CMakeLists.txt
@@ -30,7 +30,6 @@ set( GERBVIEW_SRCS
     am_param.cpp
     am_primitive.cpp
     DCodeSelectionbox.cpp
-    gbr_screen.cpp
     gbr_layout.cpp
     gerber_file_image.cpp
     gerber_file_image_list.cpp
diff --git a/gerbview/clear_gbr_drawlayers.cpp b/gerbview/clear_gbr_drawlayers.cpp
index 22840aa26e..614a7b8cb0 100644
--- a/gerbview/clear_gbr_drawlayers.cpp
+++ b/gerbview/clear_gbr_drawlayers.cpp
@@ -34,6 +34,8 @@
 #include <gerber_file_image_list.h>
 #include <gerbview_layer_widget.h>
 #include <view/view.h>
+#include <base_screen.h>
+
 #include <tool/tool_manager.h>
 
 bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
diff --git a/gerbview/gbr_screen.cpp b/gerbview/gbr_screen.cpp
deleted file mode 100644
index a657a02dd0..0000000000
--- a/gerbview/gbr_screen.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2012-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
- * Copyright (C) 1992-2020 KiCad Developers, see change_log.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
- */
-
-#include <fctsys.h>
-#include <macros.h>
-#include <gbr_screen.h>
-
-
-/**
-    Default GerbView zoom values.
-    Roughly a 1.5 progression.
-*/
-static const double gbrZoomList[] =
-{
-    ZOOM_FACTOR( 0.022 ),
-    ZOOM_FACTOR( 0.035 ),
-    ZOOM_FACTOR( 0.05 ),
-    ZOOM_FACTOR( 0.08 ),
-    ZOOM_FACTOR( 0.13 ),
-    ZOOM_FACTOR( 0.22 ),
-    ZOOM_FACTOR( 0.35 ),
-    ZOOM_FACTOR( 0.6 ),
-    ZOOM_FACTOR( 1.0 ),
-    ZOOM_FACTOR( 1.5 ),
-    ZOOM_FACTOR( 2.2 ),
-    ZOOM_FACTOR( 3.5 ),
-    ZOOM_FACTOR( 5.0 ),
-    ZOOM_FACTOR( 8.0 ),
-    ZOOM_FACTOR( 13.0 ),
-    ZOOM_FACTOR( 20.0 ),
-    ZOOM_FACTOR( 35.0 ),
-    ZOOM_FACTOR( 50.0 ),
-    ZOOM_FACTOR( 80.0 ),
-    ZOOM_FACTOR( 130.0 ),
-    ZOOM_FACTOR( 220.0 )
-};
-
-
-GBR_SCREEN::GBR_SCREEN( const wxSize& aPageSizeIU ) :
-    BASE_SCREEN( SCREEN_T )
-{
-    for( unsigned i = 0; i < arrayDim( gbrZoomList );  ++i )
-        m_ZoomList.push_back( gbrZoomList[i] );
-
-    SetZoom( ZOOM_FACTOR( 350 ) );  // a default value for zoom
-
-    m_Active_Layer       = 0;       // default active layer = first graphic layer
-
-    InitDataPoints( aPageSizeIU );
-}
diff --git a/gerbview/gbr_screen.h b/gerbview/gbr_screen.h
deleted file mode 100644
index 186b0df891..0000000000
--- a/gerbview/gbr_screen.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2012-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
- * Copyright (C) 1992-2014 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
- */
-
-#ifndef GBR_SCREEN_H
-#define GBR_SCREEN_H
-
-#include <base_units.h>
-#include <base_screen.h>
-
-#define ZOOM_FACTOR( x )       ( x * IU_PER_MILS )
-
-/* Handle info to display a board */
-class GBR_SCREEN : public BASE_SCREEN
-{
-public:
-    int m_Active_Layer;
-    /**
-     * Constructor
-     * @param aPageSizeIU is the size of the initial paper page in internal units.
-     */
-    GBR_SCREEN( const wxSize& aPageSizeIU );
-
-    /**
-     * Function ClearUndoORRedoList
-     * virtual pure in BASE_SCREEN, so it must be defined here
-     */
-    void ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount = -1 ) override
-    { }
-};
-
-
-#endif  // GBR_SCREEN_H
diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp
index 3fc280329e..a144e19303 100644
--- a/gerbview/gerbview_frame.cpp
+++ b/gerbview/gerbview_frame.cpp
@@ -50,6 +50,7 @@
 #include <tools/gerbview_selection_tool.h>
 #include <tools/gerbview_control.h>
 #include <view/view.h>
+#include <base_screen.h>
 #include <gerbview_painter.h>
 #include <geometry/shape_poly_set.h>
 #include <widgets/paged_dialog.h>
@@ -62,28 +63,24 @@
 GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent )
         : EDA_DRAW_FRAME( aKiway, aParent, FRAME_GERBER, wxT( "GerbView" ), wxDefaultPosition,
                 wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, GERBVIEW_FRAME_NAME ),
+          m_activeLayer( 0 ),
           m_zipFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_ZIP_FILE1,
                   ID_GERBVIEW_ZIP_FILE_LIST_CLEAR, _( "Clear Recent Zip Files" ) ),
           m_drillFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_DRILL_FILE1,
                   ID_GERBVIEW_DRILL_FILE_LIST_CLEAR, _( "Clear Recent Drill Files" ) ),
           m_jobFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_JOB_FILE1,
-                  ID_GERBVIEW_JOB_FILE_LIST_CLEAR, _( "Clear Recent Job Files" ) )
+                  ID_GERBVIEW_JOB_FILE_LIST_CLEAR, _( "Clear Recent Job Files" ) ),
+          m_TextInfo( nullptr )
 {
     m_gerberLayout = NULL;
-    m_zoomLevelCoeff = ZOOM_FACTOR( 110 );   // Adjusted to roughly displays zoom level = 1
-                                             // when the screen shows a 1:1 image
-                                             // obviously depends on the monitor,
-                                             // but this is an acceptable value
-
     m_show_layer_manager_tools = true;
-
     m_showBorderAndTitleBlock = false;      // true for reference drawings.
-    m_SelLayerBox   = NULL;
+    m_SelLayerBox = NULL;
     m_DCodeSelector = NULL;
     m_SelComponentBox = nullptr;
     m_SelNetnameBox = nullptr;
     m_SelAperAttributesBox = nullptr;
-    m_displayMode   = 0;
+    m_displayMode = 0;
     m_AboutTitle = "GerbView";
 
     SHAPE_POLY_SET dummy;   // A ugly trick to force the linker to include
@@ -115,7 +112,7 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent )
 
     SetVisibleLayers( LSET::AllLayersMask() );         // All draw layers visible.
 
-    SetScreen( new GBR_SCREEN( GetPageSettings().GetSizeIU() ) );
+    SetScreen( new BASE_SCREEN( GetPageSettings().GetSizeIU() ) );
 
     // Create the PCB_LAYER_WIDGET *after* SetLayout():
     m_LayersManager = new GERBER_LAYER_WIDGET( this, GetCanvas() );
@@ -300,35 +297,62 @@ void GERBVIEW_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
 {
     EDA_DRAW_FRAME::LoadSettings( aCfg );
 
+    if( aCfg->m_Window.grid.sizes.empty() )
+    {
+        aCfg->m_Window.grid.sizes = { "100 mil",
+                                      "50 mil",
+                                      "25 mil",
+                                      "20 mil",
+                                      "10 mil",
+                                      "5 mil",
+                                      "2.5 mil",
+                                      "2 mil",
+                                      "1 mil",
+                                      "0.5 mil",
+                                      "0.2 mil",
+                                      "0.1 mil",
+                                      "5.0 mm",
+                                      "2.5 mm",
+                                      "1.0 mm",
+                                      "0.5 mm",
+                                      "0.25 mm",
+                                      "0.2 mm",
+                                      "0.1 mm",
+                                      "0.05 mm",
+                                      "0.025 mm",
+                                      "0.01 mm" };
+    }
+
+    if( aCfg->m_Window.zoom_factors.empty() )
+    {
+        aCfg->m_Window.zoom_factors = { 0.022,
+                                        0.035,
+                                        0.05,
+                                        0.08,
+                                        0.13,
+                                        0.22,
+                                        0.35,
+                                        0.6,
+                                        1.0,
+                                        2.2,
+                                        3.5,
+                                        5.0,
+                                        8.0,
+                                        13.0,
+                                        22.0,
+                                        35.0,
+                                        50.0,
+                                        80.0,
+                                        130.0,
+                                        220.0 };
+    }
+
+    for( double& factor : aCfg->m_Window.zoom_factors )
+        factor = std::min( factor, MAX_ZOOM_FACTOR );
+
     GERBVIEW_SETTINGS* cfg = dynamic_cast<GERBVIEW_SETTINGS*>( aCfg );
     wxCHECK( cfg, /*void*/ );
 
-    if( cfg->m_Window.grid.sizes.empty() )
-    {
-        cfg->m_Window.grid.sizes = { "100 mil",
-                                     "50 mil",
-                                     "25 mil",
-                                     "20 mil",
-                                     "10 mil",
-                                     "5 mil",
-                                     "2.5 mil",
-                                     "2 mil",
-                                     "1 mil",
-                                     "0.5 mil",
-                                     "0.2 mil",
-                                     "0.1 mil",
-                                     "5.0 mm",
-                                     "2.5 mm",
-                                     "1.0 mm",
-                                     "0.5 mm",
-                                     "0.25 mm",
-                                     "0.2 mm",
-                                     "0.1 mm",
-                                     "0.05 mm",
-                                     "0.025 mm",
-                                     "0.01 mm" };
-    }
-
     SetElementVisibility( LAYER_WORKSHEET, cfg->m_Appearance.show_border_and_titleblock );
 
     PAGE_INFO pageInfo( wxT( "GERBER" ) );
@@ -860,15 +884,9 @@ void GERBVIEW_FRAME::SetLayerColor( int aLayer, COLOR4D aColor )
 }
 
 
-int GERBVIEW_FRAME::GetActiveLayer()
-{
-    return ( (GBR_SCREEN*) GetScreen() )->m_Active_Layer;
-}
-
-
 void GERBVIEW_FRAME::SetActiveLayer( int aLayer, bool doLayerWidgetUpdate )
 {
-    ( (GBR_SCREEN*) GetScreen() )->m_Active_Layer = aLayer;
+    m_activeLayer = aLayer;
 
     if( doLayerWidgetUpdate )
         m_LayersManager->SelectLayer( aLayer );
@@ -886,10 +904,9 @@ void GERBVIEW_FRAME::SetActiveLayer( int aLayer, bool doLayerWidgetUpdate )
 void GERBVIEW_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
 {
     m_paper = aPageSettings;
-    GBR_SCREEN* screen = static_cast<GBR_SCREEN*>( GetScreen() );
 
-    if( screen )
-        screen->InitDataPoints( aPageSettings.GetSizeIU() );
+    if( GetScreen() )
+        GetScreen()->InitDataPoints( aPageSettings.GetSizeIU() );
 
     auto drawPanel = static_cast<GERBVIEW_DRAW_PANEL_GAL*>( GetCanvas() );
 
@@ -897,7 +914,7 @@ void GERBVIEW_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings )
     auto worksheet = new KIGFX::WS_PROXY_VIEW_ITEM( IU_PER_MILS, &GetPageSettings(),
                                                     &Prj(), &GetTitleBlock() );
 
-    if( screen != NULL )
+    if( GetScreen() )
     {
         worksheet->SetSheetNumber( 1 );
         worksheet->SetSheetCount( 1 );
@@ -987,9 +1004,7 @@ void GERBVIEW_FRAME::UpdateStatusBar()
 {
     EDA_DRAW_FRAME::UpdateStatusBar();
 
-    GBR_SCREEN* screen = (GBR_SCREEN*) GetScreen();
-
-    if( !screen )
+    if( !GetScreen() )
         return;
 
     wxString line;
@@ -997,8 +1012,8 @@ void GERBVIEW_FRAME::UpdateStatusBar()
 
     if( GetShowPolarCoords() )  // display relative polar coordinates
     {
-        double   dx = cursorPos.x - screen->m_LocalOrigin.x;
-        double   dy = cursorPos.y - screen->m_LocalOrigin.y;
+        double   dx = cursorPos.x - GetScreen()->m_LocalOrigin.x;
+        double   dy = cursorPos.y - GetScreen()->m_LocalOrigin.y;
         double   theta = RAD2DEG( atan2( -dy, dx ) );
         double   ro = hypot( dx, dy );
         wxString formatter;
@@ -1051,8 +1066,8 @@ void GERBVIEW_FRAME::UpdateStatusBar()
     if( !GetShowPolarCoords() )  // display relative cartesian coordinates
     {
         // Display relative coordinates:
-        dXpos = To_User_Unit( GetUserUnits(), cursorPos.x - screen->m_LocalOrigin.x );
-        dYpos = To_User_Unit( GetUserUnits(), cursorPos.y - screen->m_LocalOrigin.y );
+        dXpos = To_User_Unit( GetUserUnits(), cursorPos.x - GetScreen()->m_LocalOrigin.x );
+        dYpos = To_User_Unit( GetUserUnits(), cursorPos.y - GetScreen()->m_LocalOrigin.y );
 
         // We already decided the formatter above
         line.Printf( relformatter, dXpos, dYpos, hypot( dXpos, dYpos ) );
@@ -1063,12 +1078,6 @@ void GERBVIEW_FRAME::UpdateStatusBar()
 }
 
 
-const wxString GERBVIEW_FRAME::GetZoomLevelIndicator() const
-{
-    return EDA_DRAW_FRAME::GetZoomLevelIndicator();
-}
-
-
 GERBER_FILE_IMAGE* GERBVIEW_FRAME::GetGbrImage( int aIdx ) const
 {
     return m_gerberLayout->GetImagesList()->GetGbrImage( aIdx );
@@ -1184,23 +1193,19 @@ void GERBVIEW_FRAME::updateZoomSelectBox()
     if( m_zoomSelectBox == NULL )
         return;
 
-    wxString msg;
+    double zoom = GetCanvas()->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
 
     m_zoomSelectBox->Clear();
     m_zoomSelectBox->Append( _( "Zoom Auto" ) );
     m_zoomSelectBox->SetSelection( 0 );
 
-    for( unsigned i = 0;  i < GetScreen()->m_ZoomList.size();  ++i )
+    for( unsigned i = 0;  i < config()->m_Window.zoom_factors.size();  ++i )
     {
-        msg = _( "Zoom " );
+        double current = config()->m_Window.zoom_factors[i];
 
-        double level =  m_zoomLevelCoeff / (double)GetScreen()->m_ZoomList[i];
-        wxString value = wxString::Format( wxT( "%.2f" ), level );
-        msg += value;
+        m_zoomSelectBox->Append( wxString::Format( _( "Zoom %.2f" ), current ) );
 
-        m_zoomSelectBox->Append( msg );
-
-        if( GetScreen()->GetZoom() == GetScreen()->m_ZoomList[i] )
+        if( zoom == current )
             m_zoomSelectBox->SetSelection( i + 1 );
     }
 }
diff --git a/gerbview/gerbview_frame.h b/gerbview/gerbview_frame.h
index 1ace732882..93f7371cf7 100644
--- a/gerbview/gerbview_frame.h
+++ b/gerbview/gerbview_frame.h
@@ -30,9 +30,9 @@
 #include <gerbview.h>
 #include <convert_to_biu.h>
 #include <gbr_layout.h>
-#include <gbr_screen.h>
 #include <page_info.h>
 #include <gbr_display_options.h>
+#include <undo_redo_container.h>
 
 #define NO_AVAILABLE_LAYERS UNDEFINED_LAYER
 
@@ -55,6 +55,7 @@ class REPORTER;
 class GERBVIEW_FRAME : public EDA_DRAW_FRAME    // PCB_BASE_FRAME
 {
     GBR_LAYOUT*         m_gerberLayout;
+    int                 m_activeLayer;
     wxPoint             m_grid_origin;
     PAGE_INFO           m_paper;            // used only to show paper limits to screen
     GBR_DISPLAY_OPTIONS m_DisplayOptions;
@@ -221,14 +222,6 @@ public:
     void ReCreateMenuBar() override;
     void UpdateStatusBar() override;
 
-    /**
-     * Function GetZoomLevelIndicator
-     * returns a human readable value which can be displayed as zoom
-     * level indicator in dialogs.
-     * Virtual from the base class
-     */
-    const wxString GetZoomLevelIndicator() const override;
-
     /**
      * Function GetDisplayMode
      *  @return 0 for fast mode (not fully compatible with negative objects)
@@ -327,7 +320,7 @@ public:
      * Function SetActiveLayer
      * returns the active layer
      */
-    int GetActiveLayer();
+    int GetActiveLayer() const { return m_activeLayer; }
 
     /**
      * Function getNextAvailableLayer
diff --git a/include/base_screen.h b/include/base_screen.h
index eb4d0bc5ed..c9c7e11a74 100644
--- a/include/base_screen.h
+++ b/include/base_screen.h
@@ -55,8 +55,6 @@ private:
      */
     wxPoint     m_crossHairPosition;
 
-    double      m_Zoom;             ///< Current zoom coefficient.
-
 public:
     static  wxString m_PageLayoutDescrFileName; ///< the name of the page layout descr file,
                                                 ///< or emty to used the default pagelayout
@@ -87,11 +85,15 @@ public:
     int                 m_ScreenNumber;
     int                 m_NumberOfScreens;
 
-    std::vector<double> m_ZoomList;         ///< standard zoom (i.e. scale) coefficients.
-
 public:
     BASE_SCREEN( EDA_ITEM* aParent, KICAD_T aType = SCREEN_T );
 
+    BASE_SCREEN( const wxSize& aPageSizeIU, KICAD_T aType = SCREEN_T ) :
+            BASE_SCREEN( nullptr, aType )
+    {
+        InitDataPoints( aPageSizeIU );
+    }
+
     BASE_SCREEN( KICAD_T aType = SCREEN_T ) :
             BASE_SCREEN( nullptr, aType )
     {}
@@ -114,7 +116,8 @@ public:
      *                     old commands this will empty the list of commands.
      *  Commands are deleted from the older to the last.
      */
-    virtual void ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount = -1 ) = 0;
+    virtual void ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount = -1 )
+    { }
 
     /**
      * Function ClearUndoRedoList
@@ -184,40 +187,6 @@ public:
     bool IsModify() const   { return m_FlagModified; }
     bool IsSave() const     { return m_FlagSave; }
 
-
-    //----<zoom stuff>---------------------------------------------------------
-
-    /**
-     * Function GetZoom
-     * returns the current "zoom factor", which is a measure of
-     * "internal units per device unit", or "world units per device unit".
-     * A device unit is typically a pixel.
-     */
-    double GetZoom() const      { return m_Zoom; }
-
-    /**
-     * Function SetZoom
-     * adjusts the current zoom factor.
-     *
-     * @param iu_per_du is the number of internal units (world units) per
-     *   device units (pixels typically).
-     */
-    virtual bool SetZoom( double iu_per_du );
-
-    /**
-     * Function GetMaxAllowedZoom
-     * returns the maximum allowed zoom factor, which was established as the last entry
-     * in m_ZoomList.
-     */
-    double GetMaxAllowedZoom() const    { return m_ZoomList.size() ? *m_ZoomList.rbegin() : 1.0; }
-
-    /**
-     * Function GetMinAllowedZoom
-     * returns the minimum allowed zoom factor, which was established as the first entry
-     * in m_ZoomList.
-     */
-    double GetMinAllowedZoom() const    { return m_ZoomList.size() ? *m_ZoomList.begin() : 1.0; }
-
     /**
      * Function GetClass
      * returns the class name.
diff --git a/include/class_draw_panel_gal.h b/include/class_draw_panel_gal.h
index ad8ef0c383..7d6e3e7010 100644
--- a/include/class_draw_panel_gal.h
+++ b/include/class_draw_panel_gal.h
@@ -161,12 +161,6 @@ public:
         wxASSERT( false );
     }
 
-    /**
-     * Function GetLegacyZoom()
-     * Returns current view scale converted to zoom value used by the legacy canvas.
-     */
-    double GetLegacyZoom() const;
-
     /**
      * Function GetParentEDAFrame()
      * Returns parent EDA_DRAW_FRAME, if available or NULL otherwise.
diff --git a/include/convert_to_biu.h b/include/convert_to_biu.h
index 882a5a157d..1bd919e678 100644
--- a/include/convert_to_biu.h
+++ b/include/convert_to_biu.h
@@ -122,4 +122,55 @@ constexpr inline double Iu2Millimeter( int iu )
 constexpr int ARC_LOW_DEF  = Millimeter2iu( 0.02 );
 constexpr int ARC_HIGH_DEF = Millimeter2iu( 0.005 );
 
+/*  ZOOM LIMITS
+
+    The largest distance that wx can support is INT_MAX, since it represents
+    distance often in a wxCoord or wxSize. As a scalar, a distance is always
+    positive. On most machines which run KiCad, int is 32 bits and INT_MAX is
+    2147483647. The most difficult distance for a virtual (world) cartesian
+    space is the hypotenuse, or diagonal measurement at a 45 degree angle. This
+    puts the most stress on the distance magnitude within the bounded virtual
+    space. So if we allow this distance to be our constraint of <= INT_MAX, this
+    constraint then propagates to the maximum distance in X and in Y that can be
+    supported on each axis. Remember that the hypotenuse of a 1x1 square is
+    sqrt( 1x1 + 1x1 ) = sqrt(2) = 1.41421356.
+
+    hypotenuse of any square = sqrt(2) * deltaX;
+
+    Let maximum supported hypotenuse be INT_MAX, then:
+
+    MAX_AXIS = INT_MAX / sqrt(2) = 2147483647 / 1.41421356 = 1518500251
+
+    This maximum distance is imposed by wxWidgets, not by KiCad. The imposition
+    comes in the form of the data structures used in the graphics API at the
+    wxDC level. Obviously when we are not interacting with wx we can use double
+    to compute distances larger than this. For example the computation of the
+    total length of a net, can and should be done in double, since it might
+    actually be longer than a single diagonal line.
+
+    The next choice is what to use for internal units (IU), sometimes called
+    world units.  If nanometers, then the virtual space must be limited to
+    about 1.5 x 1.5 meters square.  This is 1518500251 divided by 1e9 nm/meter.
+
+    The maximum zoom factor then depends on the client window size.  If we ask
+    wx to handle something outside INT_MIN to INT_MAX, there are unreported
+    problems in the non-Debug build because wxRound() goes silent.
+
+    Let:
+        const double MAX_AXIS = 1518500251;
+
+    Then a maximum zoom factor for a screen of 1920 pixels wide is
+        1518500251 / 1920 = 790885.
+
+    The largest zoom factor allowed is therefore ~ 300 (which computes to 762000).
+*/
+
+#define MAX_ZOOM_FACTOR 300.0
+
+// Adjusted to display zoom level ~ 1 when the screen shows a 1:1 image.
+// Obviously depends on the monitor, but this is an acceptable value.
+#define ZOOM_COEFF 1.1
+
+
+
 #endif  // CONVERT_TO_BIU_H_
diff --git a/include/eda_draw_frame.h b/include/eda_draw_frame.h
index 90706624f3..747a989f3c 100644
--- a/include/eda_draw_frame.h
+++ b/include/eda_draw_frame.h
@@ -84,9 +84,6 @@ protected:
     COLOR4D            m_gridColor;         // Grid color
     COLOR4D            m_drawBgColor;       // The background color of the draw canvas; BLACK for
                                             // Pcbnew, BLACK or WHITE for eeschema
-    double             m_zoomLevelCoeff;    // A suitable value to convert the internal zoom
-                                            // scaling factor to a zoom level value which rougly
-                                            // gives 1.0 when the board/schematic is at scale = 1
     int                m_UndoRedoCountMax;  // Default Undo/Redo command Max depth, to be handed
                                             // to screens
     bool               m_PolarCoords;       // For those frames that support polar coordinates
@@ -245,17 +242,8 @@ public:
 
     /**
      * Return a human readable value for display in dialogs.
-     * this can be a percentage or other indicator.
-     * it is virtual because it could be different for pcbnew, gerbview or eeschema
-     * (different internal units and different purposes)
-     * note also adjust m_zoomLevelCoeff is the way to adjust the displayed value
      */
-    virtual const wxString GetZoomLevelIndicator() const;
-
-    /**
-     * Return the coefficient to convert internal display scale factor to zoom level.
-     */
-    inline double GetZoomLevelCoeff() const { return m_zoomLevelCoeff; }
+    const wxString GetZoomLevelIndicator() const;
 
     void EraseMsgBox();
 
@@ -328,8 +316,6 @@ public:
      */
     void FocusOnLocation( const wxPoint& aPos );
 
-    double GetZoom();
-
     /**
      * Function CreateBasicMenu
      *
diff --git a/include/id.h b/include/id.h
index 350eb3b51d..246b2a0342 100644
--- a/include/id.h
+++ b/include/id.h
@@ -165,34 +165,6 @@ enum main_id
     ID_POPUP_ZOOM_END_RANGE,         // last zoom id
 
     ID_ON_GRID_SELECT,
-    ID_POPUP_GRID_SELECT,
-    ID_POPUP_GRID_FIRST,
-    ID_POPUP_GRID_LEVEL_1000 = ID_POPUP_GRID_FIRST, // These must be in same order as menu
-    ID_POPUP_GRID_LEVEL_500,
-    ID_POPUP_GRID_LEVEL_250,
-    ID_POPUP_GRID_LEVEL_200,
-    ID_POPUP_GRID_LEVEL_100,
-    ID_POPUP_GRID_LEVEL_50,
-    ID_POPUP_GRID_LEVEL_25,
-    ID_POPUP_GRID_LEVEL_20,
-    ID_POPUP_GRID_LEVEL_10,
-    ID_POPUP_GRID_LEVEL_5,
-    ID_POPUP_GRID_LEVEL_2,
-    ID_POPUP_GRID_LEVEL_1,
-    ID_POPUP_GRID_LEVEL_5MM,
-    ID_POPUP_GRID_LEVEL_2_5MM,
-    ID_POPUP_GRID_LEVEL_1MM,
-    ID_POPUP_GRID_LEVEL_0_5MM,
-    ID_POPUP_GRID_LEVEL_0_25MM,
-    ID_POPUP_GRID_LEVEL_0_2MM,
-    ID_POPUP_GRID_LEVEL_0_1MM,
-    ID_POPUP_GRID_LEVEL_0_0_5MM,
-    ID_POPUP_GRID_LEVEL_0_0_25MM,
-    ID_POPUP_GRID_LEVEL_0_0_1MM,
-    ID_POPUP_GRID_USER,
-    ID_POPUP_GRID_SEPARATOR,
-    ID_POPUP_GRID_SETTINGS,
-
     ID_GRID_SETTINGS,
 
     ID_ZOOM_BEGIN,
diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h
index dae6f62dbb..687b899346 100644
--- a/include/pcb_base_frame.h
+++ b/include/pcb_base_frame.h
@@ -227,12 +227,6 @@ public:
 
     void UpdateGridSelectBox();
 
-    /**
-     * Function GetZoomLevelIndicator
-     * returns a human readable value for display in dialogs.
-     */
-    const wxString GetZoomLevelIndicator() const override;
-
     /**
      * Shows the 3D view frame.
      * If it does not exist, it is created.
diff --git a/include/settings/app_settings.h b/include/settings/app_settings.h
index 9144896245..4f596a8131 100644
--- a/include/settings/app_settings.h
+++ b/include/settings/app_settings.h
@@ -63,6 +63,8 @@ struct WINDOW_SETTINGS
     int pos_x;
     int pos_y;
 
+    std::vector<double> zoom_factors;
+
     CURSOR_SETTINGS cursor;
     GRID_SETTINGS grid;
 };
diff --git a/pagelayout_editor/dialogs/dialogs_for_printing.cpp b/pagelayout_editor/dialogs/dialogs_for_printing.cpp
index 8b62da7d47..967ebfddd4 100644
--- a/pagelayout_editor/dialogs/dialogs_for_printing.cpp
+++ b/pagelayout_editor/dialogs/dialogs_for_printing.cpp
@@ -147,7 +147,6 @@ void PLEDITOR_PRINTOUT::GetPageInfo( int* minPage, int* maxPage,
  */
 void PLEDITOR_PRINTOUT::PrintPage( int aPageNum )
 {
-    int      oldZoom;
     wxPoint  tmp_startvisu;
     wxSize   pageSizeIU;             // Page size in internal units
     wxPoint  old_org;
@@ -155,9 +154,8 @@ void PLEDITOR_PRINTOUT::PrintPage( int aPageNum )
     wxDC*    dc = GetDC();
     PL_EDITOR_SCREEN* screen = m_parent->GetScreen();
 
-    // Save current scale factor, offsets, and clip box.
+    // Save current offsets and clip box.
     tmp_startvisu = screen->m_StartVisu;
-    oldZoom = screen->GetZoom();
     old_org = screen->m_DrawOrg;
 
     // Change scale factor and offset to print the whole page.
@@ -205,7 +203,6 @@ void PLEDITOR_PRINTOUT::PrintPage( int aPageNum )
 
     screen->m_StartVisu = tmp_startvisu;
     screen->m_DrawOrg   = old_org;
-    screen->SetZoom( oldZoom );
 
     // PrintWorkSheet clears the current display list when calling BuildWorkSheetGraphicList()
     // So rebuild and redraw it.
diff --git a/pagelayout_editor/pl_editor_frame.cpp b/pagelayout_editor/pl_editor_frame.cpp
index 1bbe94e48b..877f7cb4ea 100644
--- a/pagelayout_editor/pl_editor_frame.cpp
+++ b/pagelayout_editor/pl_editor_frame.cpp
@@ -85,10 +85,6 @@ PL_EDITOR_FRAME::PL_EDITOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
                         KICAD_DEFAULT_DRAWFRAME_STYLE, PL_EDITOR_FRAME_NAME )
 {
     m_userUnits = EDA_UNITS::MILLIMETRES;
-    m_zoomLevelCoeff = 290.0;   // Adjusted to roughly displays zoom level = 1
-                                // when the screen shows a 1:1 image
-                                // obviously depends on the monitor,
-                                // but this is an acceptable value
 
     m_showBorderAndTitleBlock   = true; // true for reference drawings.
     m_originSelectChoice = 0;
@@ -180,7 +176,6 @@ PL_EDITOR_FRAME::PL_EDITOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
 
     m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() );
 
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
     ActivateGalCanvas();
 
     // Call Update() to fix all pane default sizes, especially the "InfoBar" pane before
@@ -423,18 +418,45 @@ void PL_EDITOR_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
 {
     EDA_DRAW_FRAME::LoadSettings( aCfg );
 
+    if( aCfg->m_Window.grid.sizes.empty() )
+    {
+        aCfg->m_Window.grid.sizes = { "1.0 mm",
+                                      "0.50 mm",
+                                      "0.25 mm",
+                                      "0.20 mm",
+                                      "0.10 mm" };
+    }
+
+    if( aCfg->m_Window.zoom_factors.empty() )
+    {
+        aCfg->m_Window.zoom_factors = { 0.022,
+                                        0.035,
+                                        0.05,
+                                        0.08,
+                                        0.13,
+                                        0.22,
+                                        0.35,
+                                        0.6,
+                                        1.0,
+                                        2.2,
+                                        3.5,
+                                        5.0,
+                                        8.0,
+                                        13.0,
+                                        22.0,
+                                        35.0,
+                                        50.0,
+                                        80.0,
+                                        130.0,
+                                        220.0 };
+    }
+
+    for( double& factor : aCfg->m_Window.zoom_factors )
+        factor = std::min( factor, MAX_ZOOM_FACTOR );
+
     PL_EDITOR_SETTINGS* cfg = dynamic_cast<PL_EDITOR_SETTINGS*>( aCfg );
     wxCHECK( cfg, /*void*/ );
 
-    if( cfg->m_Window.grid.sizes.empty() )
-    {
-        cfg->m_Window.grid.sizes = { "1.0 mm",
-                                     "0.50 mm",
-                                     "0.25 mm",
-                                     "0.20 mm",
-                                     "0.10 mm" };
-    }
-
     m_propertiesFrameWidth = cfg->m_PropertiesFrameWidth;
     m_originSelectChoice = cfg->m_CornerOrigin;
 
@@ -820,8 +842,3 @@ void PL_EDITOR_FRAME::OnNewPageLayout()
 }
 
 
-const wxString PL_EDITOR_FRAME::GetZoomLevelIndicator() const
-{
-    return EDA_DRAW_FRAME::GetZoomLevelIndicator();
-}
-
diff --git a/pagelayout_editor/pl_editor_frame.h b/pagelayout_editor/pl_editor_frame.h
index 839c10b045..137d1c188b 100644
--- a/pagelayout_editor/pl_editor_frame.h
+++ b/pagelayout_editor/pl_editor_frame.h
@@ -122,12 +122,6 @@ public:
     const PAGE_INFO& GetPageSettings () const override;
     const wxSize GetPageSizeIU() const override;
 
-    /**
-     * Function GetZoomLevelIndicator
-     * returns a human readable value which can be displayed in dialogs.
-     */
-    const wxString GetZoomLevelIndicator() const override;
-
     PL_DRAW_PANEL_GAL* GetCanvas() const override;
 
     PL_EDITOR_SCREEN* GetScreen() const override
diff --git a/pagelayout_editor/pl_editor_screen.cpp b/pagelayout_editor/pl_editor_screen.cpp
index 95dd52c9b3..1076e1b45f 100644
--- a/pagelayout_editor/pl_editor_screen.cpp
+++ b/pagelayout_editor/pl_editor_screen.cpp
@@ -25,49 +25,14 @@
 
 #include <fctsys.h>
 #include <pl_editor_screen.h>
-#include <base_units.h>
-
-
-#define ZOOM_FACTOR( x )  ( x * IU_PER_MM / 1000 )
-
-
-/**
-    Default zoom values.
-    Roughly a 1.5 progression.
-*/
-static const double pl_editorZoomList[] =
-{
-    ZOOM_FACTOR( 10.0 ),        // Zoom in
-    ZOOM_FACTOR( 15.0 ),
-    ZOOM_FACTOR( 22.0 ),
-    ZOOM_FACTOR( 35.0 ),
-    ZOOM_FACTOR( 50.0 ),
-    ZOOM_FACTOR( 80.0 ),
-    ZOOM_FACTOR( 120.0 ),
-    ZOOM_FACTOR( 160.0 ),
-    ZOOM_FACTOR( 230.0 ),
-    ZOOM_FACTOR( 290.0 ),
-    ZOOM_FACTOR( 380.0 ),
-    ZOOM_FACTOR( 500.0 ),
-    ZOOM_FACTOR( 750.0 ),
-    ZOOM_FACTOR( 1000.0 ),
-    ZOOM_FACTOR( 1500.0 ),
-    ZOOM_FACTOR( 2000.0 ),
-    ZOOM_FACTOR( 3000.0 ),
-    ZOOM_FACTOR( 4500.0 ),      // Zoom out
-};
 
 
 PL_EDITOR_SCREEN::PL_EDITOR_SCREEN( const wxSize& aPageSizeIU ) :
-    BASE_SCREEN( SCREEN_T )
+    BASE_SCREEN( aPageSizeIU )
 {
-    for( double zoom : pl_editorZoomList )
-        m_ZoomList.push_back( zoom );
-
     // pl_editor uses the same frame position as schematic and board editors
     m_Center = false;
 
-    InitDataPoints( aPageSizeIU );
     m_NumberOfScreens = 2;
 }
 
diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp
index 032aa38ca1..f3137061df 100644
--- a/pcbnew/footprint_edit_frame.cpp
+++ b/pcbnew/footprint_edit_frame.cpp
@@ -219,7 +219,6 @@ FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent,
 
     m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" ).Center() );
 
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
     ActivateGalCanvas();
 
     // Call Update() to fix all pane default sizes, especially the "InfoBar" pane before
diff --git a/pcbnew/footprint_viewer_frame.cpp b/pcbnew/footprint_viewer_frame.cpp
index 98c0361e29..172e8f3328 100644
--- a/pcbnew/footprint_viewer_frame.cpp
+++ b/pcbnew/footprint_viewer_frame.cpp
@@ -263,7 +263,6 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
     // The canvas should not steal the focus from the list boxes
     GetCanvas()->SetCanFocus( false );
     GetCanvas()->GetGAL()->SetAxesEnabled( true );
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
     ActivateGalCanvas();
 
     // Restore last zoom.  (If auto-zooming we'll adjust when we load the footprint.)
diff --git a/pcbnew/footprint_wizard_frame.cpp b/pcbnew/footprint_wizard_frame.cpp
index f2961fe8c5..5b196933da 100644
--- a/pcbnew/footprint_wizard_frame.cpp
+++ b/pcbnew/footprint_wizard_frame.cpp
@@ -211,7 +211,6 @@ FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway, wxWindow* aParent
     galOpts.m_forceDisplayCursor = true;
     galOpts.m_axesEnabled = true;
 
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
     ActivateGalCanvas();
     updateView();
 
diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp
index e147b31129..0c83e4003a 100644
--- a/pcbnew/pcb_base_frame.cpp
+++ b/pcbnew/pcb_base_frame.cpp
@@ -26,9 +26,7 @@
 
 #include <fctsys.h>
 #include <kiface_i.h>
-#include <eda_base_frame.h>
 #include <confirm.h>
-#include <kiface_i.h>
 #include <dialog_helpers.h>
 #include <pcb_base_frame.h>
 #include <base_units.h>
@@ -40,12 +38,10 @@
 #include <fp_lib_table.h>
 #include <pcbnew_id.h>
 #include <class_board.h>
-#include <class_track.h>
 #include <class_module.h>
 #include <class_drawsegment.h>
 #include <collectors.h>
 #include <pcb_draw_panel_gal.h>
-#include <pcb_view.h>
 #include <math/vector2d.h>
 #include <trigo.h>
 #include <pcb_painter.h>
@@ -54,7 +50,6 @@
 #include <tool/tool_manager.h>
 #include <tool/tool_dispatcher.h>
 #include <tools/pcb_actions.h>
-#include <pcbnew_settings.h>
 #include <tool/grid_menu.h>
 
 wxDEFINE_EVENT( BOARD_CHANGED, wxCommandEvent );
@@ -71,11 +66,6 @@ PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame
     EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ),
     m_Pcb( nullptr )
 {
-    m_zoomLevelCoeff      = 11.0 * IU_PER_MILS;  // Adjusted to roughly displays zoom level = 1
-                                        // when the screen shows a 1:1 image
-                                        // obviously depends on the monitor,
-                                        // but this is an acceptable value
-
     m_Settings = static_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
 }
 
@@ -467,11 +457,11 @@ void PCB_BASE_FRAME::OnUpdateSelectZoom( wxUpdateUIEvent& aEvent )
     int current = 0;    // display Auto if no match found
 
     // check for a match within 1%
-    double zoom = GetCanvas()->GetLegacyZoom();
+    double zoom = GetCanvas()->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
 
-    for( unsigned i = 0; i < GetScreen()->m_ZoomList.size(); i++ )
+    for( unsigned i = 0; i < config()->m_Window.zoom_factors.size(); i++ )
     {
-        if( std::fabs( zoom - GetScreen()->m_ZoomList[i] ) < ( zoom / 100.0 ) )
+        if( std::fabs( zoom - config()->m_Window.zoom_factors[i] ) < ( zoom / 100.0 ) )
         {
             current = i + 1;
             break;
@@ -663,6 +653,34 @@ void PCB_BASE_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
                                       "0.01 mm" };
     }
 
+    if( aCfg->m_Window.zoom_factors.empty() )
+    {
+        aCfg->m_Window.zoom_factors = { 0.035,
+                                        0.05,
+                                        0.08,
+                                        0.13,
+                                        0.22,
+                                        0.35,
+                                        0.6,
+                                        1.0,
+                                        1.5,
+                                        2.2,
+                                        3.5,
+                                        5.0,
+                                        8.0,
+                                        13.0,
+                                        20.0,
+                                        35.0,
+                                        50.0,
+                                        80.0,
+                                        130.0,
+                                        220.0,
+                                        300.0 };
+    }
+
+    for( double& factor : aCfg->m_Window.zoom_factors )
+        factor = std::min( factor, MAX_ZOOM_FACTOR );
+
     // Some, but not all derived classes have a PCBNEW_SETTINGS.
     PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( aCfg );
 
@@ -731,12 +749,6 @@ void PCB_BASE_FRAME::OnModify()
 }
 
 
-const wxString PCB_BASE_FRAME::GetZoomLevelIndicator() const
-{
-    return EDA_DRAW_FRAME::GetZoomLevelIndicator();
-}
-
-
 void PCB_BASE_FRAME::UpdateGridSelectBox()
 {
     UpdateStatusBar();
@@ -766,23 +778,19 @@ void PCB_BASE_FRAME::updateZoomSelectBox()
     if( m_zoomSelectBox == NULL )
         return;
 
-    wxString msg;
+    double zoom = GetCanvas()->GetGAL()->GetZoomFactor() / ZOOM_COEFF;
 
     m_zoomSelectBox->Clear();
     m_zoomSelectBox->Append( _( "Zoom Auto" ) );
     m_zoomSelectBox->SetSelection( 0 );
 
-    for( unsigned i = 0;  i < GetScreen()->m_ZoomList.size();  ++i )
+    for( unsigned i = 0;  i < config()->m_Window.zoom_factors.size();  ++i )
     {
-        msg = _( "Zoom " );
+        double current = config()->m_Window.zoom_factors[i];
 
-        double level =  m_zoomLevelCoeff / (double)GetScreen()->m_ZoomList[i];
-        wxString value = wxString::Format( wxT( "%.2f" ), level );
-        msg += value;
+        m_zoomSelectBox->Append( wxString::Format( _( "Zoom %.2f" ), current ) );
 
-        m_zoomSelectBox->Append( msg );
-
-        if( GetScreen()->GetZoom() == GetScreen()->m_ZoomList[i] )
+        if( zoom == current )
             m_zoomSelectBox->SetSelection( i + 1 );
     }
 }
diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp
index 15d071b9bf..453162f97b 100644
--- a/pcbnew/pcb_edit_frame.cpp
+++ b/pcbnew/pcb_edit_frame.cpp
@@ -311,7 +311,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
     InitExitKey();
 
     GetCanvas()->SwitchBackend( m_canvasType );
-    GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
     ActivateGalCanvas();
 
     // Default shutdown reason until a file is loaded
diff --git a/pcbnew/pcb_screen.cpp b/pcbnew/pcb_screen.cpp
index 31a5481d28..71000cfd84 100644
--- a/pcbnew/pcb_screen.cpp
+++ b/pcbnew/pcb_screen.cpp
@@ -4,7 +4,7 @@
  * 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@verizon.net>
- * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2020 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
@@ -26,101 +26,15 @@
 
 #include <fctsys.h>
 #include <pcb_screen.h>
-#include <base_units.h>
 #include <layers_id_colors_and_visibility.h>
 
 
-#define ZOOM_FACTOR( x )       ( x * IU_PER_MILS / 10 )
-
-/**
-    Default Pcbnew zoom values.
-    Limited to 19 values to keep a decent size to menus.
-    Roughly a 1.5 progression.
-    The last 2 values are handy when somebody uses a library import of a module
-    (or foreign data) which has a bad coordinate.
-    Also useful in GerbView for this reason.
-    Zoom 5 and 10 can create artefacts when drawing (integer overflow in low level graphic
-    functions )
-*/
-static const double pcbZoomList[] =
-{
-    ZOOM_FACTOR( 0.035 ),
-    ZOOM_FACTOR( 0.05 ),
-    ZOOM_FACTOR( 0.08 ),
-    ZOOM_FACTOR( 0.13 ),
-    ZOOM_FACTOR( 0.22 ),
-    ZOOM_FACTOR( 0.35 ),
-    ZOOM_FACTOR( 0.6 ),
-    ZOOM_FACTOR( 1.0 ),
-    ZOOM_FACTOR( 1.5 ),
-    ZOOM_FACTOR( 2.2 ),
-    ZOOM_FACTOR( 3.5 ),
-    ZOOM_FACTOR( 5.0 ),
-    ZOOM_FACTOR( 8.0 ),
-    ZOOM_FACTOR( 13.0 ),
-    ZOOM_FACTOR( 20.0 ),
-    ZOOM_FACTOR( 35.0 ),
-    ZOOM_FACTOR( 50.0 ),
-    ZOOM_FACTOR( 80.0 ),
-    ZOOM_FACTOR( 130.0 ),
-    ZOOM_FACTOR( 220.0 ),
-    ZOOM_FACTOR( 350.0 )
-/*
-    The largest distance that wx can support is INT_MAX, since it represents
-    distance often in a wxCoord or wxSize. As a scalar, a distance is always
-    positive. On most machines which run KiCad, int is 32 bits and INT_MAX is
-    2147483647. The most difficult distance for a virtual (world) cartesian
-    space is the hypotenuse, or diagonal measurement at a 45 degree angle. This
-    puts the most stress on the distance magnitude within the bounded virtual
-    space. So if we allow this distance to be our constraint of <= INT_MAX, this
-    constraint then propagates to the maximum distance in X and in Y that can be
-    supported on each axis. Remember that the hypotenuse of a 1x1 square is
-    sqrt( 1x1 + 1x1 ) = sqrt(2) = 1.41421356.
-
-    hypotenuse of any square = sqrt(2) * deltaX;
-
-    Let maximum supported hypotenuse be INT_MAX, then:
-
-    MAX_AXIS = INT_MAX / sqrt(2) = 2147483647 / 1.41421356 = 1518500251
-
-    This maximum distance is imposed by wxWidgets, not by KiCad. The imposition
-    comes in the form of the data structures used in the graphics API at the
-    wxDC level. Obviously when we are not interacting with wx we can use double
-    to compute distances larger than this. For example the computation of the
-    total length of a net, can and should be done in double, since it might
-    actually be longer than a single diagonal line.
-
-    The next choice is what to use for internal units (IU), sometimes called
-    world units.  If nanometers, then the virtual space must be limited to
-    about 1.5 x 1.5 meters square.  This is 1518500251 divided by 1e9 nm/meter.
-
-    The maximum zoom factor then depends on the client window size.  If we ask
-    wx to handle something outside INT_MIN to INT_MAX, there are unreported
-    problems in the non-Debug build because wxRound() goes silent.
-
-    Let:
-    const double MAX_AXIS = 1518500251;
-
-    Then a maximum zoom factor for a screen of 1920 pixels wide is
-        1518500251 / 1920 = 790885.
-
-    The largest ZOOM_FACTOR in above table is ZOOM_FACTOR( 300 ), which computes
-    out to 762000 just below 790885.
-*/
-};
-
-
 PCB_SCREEN::PCB_SCREEN( const wxSize& aPageSizeIU ) :
-    BASE_SCREEN( SCREEN_T )
+    BASE_SCREEN( aPageSizeIU )
 {
-    for( double zoom : pcbZoomList )
-        m_ZoomList.push_back( zoom );
-
     m_Active_Layer       = F_Cu;     // default active layer = front layer
     m_Route_Layer_TOP    = F_Cu;     // default layers pair for vias (bottom to top)
     m_Route_Layer_BOTTOM = B_Cu;
-
-    InitDataPoints( aPageSizeIU );
 }