← Back to team overview

kicad-developers team mailing list archive

Bug #1773638: The origins of 6.0 (pun intended)

 

Rene pointed out that my work on display origin transforms is really a fix for Bug #1773638, thus the retitling.

I'm making good progress, but I need a bit of guidance before proceeding further.

The code I've developed allows the user to select the origin for the display of X and Y coordinates, rather than the origin always being the upper left corner of the surrounding "page" frame. There is no change to the underlying board file or internal coordinate representation. This is purely a change the way coordinates are displayed to the user and entered by the user in dialog boxes.

The user gets three configuration options:

 * The absolute display origin: Page (default), Aux, or Grid.
 * The direction of the positive Y-axis: Down (default) or Up.
 * The direction of the positive X-axis: Right (default) or Left.

I've attached patch diffs for review and experimentation. The patches will apply cleanly to the current "eemodern" branch (commit 6137921), the 5.1.2 tag with one trivial merge error, and probably the "master" branch. It's not ready for merging, though. It lacks a UI for configuration, and configuration isn't saved or loaded from the user preferences file. For testing the config defaults to Aux origin and Y-axis Up. Obviously these deficiencies will have to be addressed before a merge.

Now for my request for guidance:

1. The user configuration options are currently in the PCB_DISPLAY_OPTIONS class. I'd like some confirmation that this is the correct place before I code the preferences file save and restore.
2. Where should the config UI go? I expect this will be a set-and-forget thing for most users. I'm thinking on the Pcbnew Preferences -> Preferences -> Pcbnew -> Display Options dialog, if there's room. But this panel seems to be half-shared with other apps and is getting kind of full. Perhaps another panel instead of Display Options?
3. The last time I did UI work was when the TRS-80 was hot stuff (I'm a Linux kernel guy). Can someone recommend an approach for developing the UI changes, and perhaps a pointer to a relevant how-to?
4. The dx/dy (relative coordinate) part of the status line isn't being transformed yet because of commit e6a200b. I posted a question regarding that earlier today but haven't received any replies yet.
5. Have I missed any dialog boxes that present absolute coordinates to the user? There's a list in the commit log.
6. Should this be extended to the footprint editor? Eeschema? Anywhere else?

Thanks for the help, folks!

-Reece


>From 4c9c94a1364397809741590eb952a1f79aac944b Mon Sep 17 00:00:00 2001
From: "Reece R. Pollack" <reece@xxxxxxx>
Date: Fri, 3 May 2019 09:43:11 -0400
Subject: [PATCH 1/2] RRP: Common changes to support Display Origin Transforms

This commit contains the changes to common files to support Display
Origin Transforms. This will allow the user to change the origin
of the displayed coordinates in status lines and dialog boxes to be
relative to a user-selected origin.

The origin may be selected as one of the following:
  * The upper left corner of the surrounding page frame
  * The Auxilliary origin (aka Drill or Manufacturing origin)
  * The Grid origin

The defined transforms are:
  * A null (or identity) transform
  * X-axis origin and sign transform for absolute coordinates
  * Y-axis origin and sign transform for absolute coordinates
  * X-axis sign transform for relative coordinates
  * Y-axis sign transform for relative coordinates

The default transform is the null transform, and is supplied by
the EDA_DRAW_FRAME class. These transforms may be overridden by
derived classes, such as the PCB_BASE_FRAME class.
---
 common/widgets/unit_binder.cpp | 29 ++++++++++++++++++++++++-----
 include/common.h               | 15 +++++++++++++++
 include/draw_frame.h           | 10 ++++++++++
 include/widgets/unit_binder.h  | 15 ++++++++++++++-
 4 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/common/widgets/unit_binder.cpp b/common/widgets/unit_binder.cpp
index 4e7b7ab..e5c7c1f 100644
--- a/common/widgets/unit_binder.cpp
+++ b/common/widgets/unit_binder.cpp
@@ -35,11 +35,14 @@ wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
 
 UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent,
                           wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel,
-                          bool aUseMils, bool allowEval ) :
+                          bool aUseMils, bool allowEval, ORIGIN_XFORMS aOriginXform ) :
+    m_parent( aParent ),
     m_label( aLabel ),
     m_value( aValue ),
     m_unitLabel( aUnitLabel ),
-    m_eval( aParent->GetUserUnits(), aUseMils )
+    m_eval( aParent->GetUserUnits(), aUseMils ),
+    m_originXform( aOriginXform ),
+    m_allowOriginXform( aOriginXform != ORIGIN_XFORM_NONE )
 {
     // Fix the units (to the current units) for the life of the binder
     m_units = aParent->GetUserUnits();
@@ -168,7 +171,11 @@ bool UNIT_BINDER::Validate( int aMin, int aMax, bool setFocusOnError )
 
 void UNIT_BINDER::SetValue( int aValue )
 {
-    SetValue( StringFromValue( m_units, aValue, false, m_useMils ) );
+    int displayValue = m_allowOriginXform ?
+                               m_parent->OriginXformToDisplay( m_originXform, aValue ) :
+                               aValue;
+
+    SetValue( StringFromValue( m_units, displayValue, false, m_useMils ) );
 }
 
 
@@ -191,7 +198,11 @@ void UNIT_BINDER::SetValue( wxString aValue )
 
 void UNIT_BINDER::ChangeValue( int aValue )
 {
-    ChangeValue( StringFromValue( m_units, aValue, false, m_useMils ) );
+    int displayValue = m_allowOriginXform ?
+                               m_parent->OriginXformToDisplay( m_originXform, aValue ) :
+                               aValue;
+
+    ChangeValue( StringFromValue( m_units, displayValue, false, m_useMils ) );
 }
 
 
@@ -230,7 +241,11 @@ int UNIT_BINDER::GetValue()
     else
         return 0;
 
-    return ValueFromString( m_units, value, m_useMils );
+    int intValue = ValueFromString( m_units, value, m_useMils );
+    if( m_allowOriginXform )
+        intValue = m_parent->OriginXformFromDisplay( m_originXform, intValue );
+
+    return intValue;
 }
 
 
@@ -266,3 +281,7 @@ void UNIT_BINDER::Show( bool aShow )
     m_unitLabel->Show( aShow );
 }
 
+void UNIT_BINDER::AllowOriginXform( bool aEnable )
+{
+    m_allowOriginXform = aEnable;
+}
diff --git a/include/common.h b/include/common.h
index 4ec7b3e..3fe4dde 100644
--- a/include/common.h
+++ b/include/common.h
@@ -422,6 +422,21 @@ private:
 long long TimestampDir( const wxString& aDirPath, const wxString& aFilespec );
 
 
+enum ORIGIN_REFERENCES
+{
+    ORIGIN_REFERENCE_PAGE = 0,
+    ORIGIN_REFERENCE_AUX,
+    ORIGIN_REFERENCE_GRID,
+};
+
+enum ORIGIN_XFORMS
+{
+    ORIGIN_XFORM_NONE = 0,
+    ORIGIN_XFORM_X_ABS,
+    ORIGIN_XFORM_Y_ABS,
+    ORIGIN_XFORM_X_REL,
+    ORIGIN_XFORM_Y_REL,
+};
 
 
 #endif  // INCLUDE__COMMON_H_
diff --git a/include/draw_frame.h b/include/draw_frame.h
index e1a659d..1d750e4 100644
--- a/include/draw_frame.h
+++ b/include/draw_frame.h
@@ -303,6 +303,16 @@ public:
     int GetLastGridSizeId() const { return m_LastGridSizeId; }
     void SetLastGridSizeId( int aId ) { m_LastGridSizeId = aId; }
 
+    virtual int OriginXformToDisplay( ORIGIN_XFORMS aOriginXform, int aValue ) const
+    {
+        return aValue;
+    }
+
+    virtual int OriginXformFromDisplay( ORIGIN_XFORMS aOriginXform, int aValue ) const
+    {
+        return aValue;
+    }
+
     //-----<BASE_SCREEN API moved here>------------------------------------------
     /**
      * Return the current cross hair position in logical (drawing) coordinates.
diff --git a/include/widgets/unit_binder.h b/include/widgets/unit_binder.h
index 4cf935b..6d463ae 100644
--- a/include/widgets/unit_binder.h
+++ b/include/widgets/unit_binder.h
@@ -53,7 +53,8 @@ public:
      */
     UNIT_BINDER( EDA_DRAW_FRAME* aParent,
                  wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel,
-                 bool aUseMils = false, bool aAllowEval = true );
+                 bool aUseMils = false, bool aAllowEval = true,
+                 ORIGIN_XFORMS aOriginXform = ORIGIN_XFORM_NONE );
 
     /**
      * Function SetUnits
@@ -118,12 +119,20 @@ public:
      */
     void Show( bool aShow );
 
+    /**
+     * Allow or disallow display origin transformations.
+     */
+    void AllowOriginXform( bool aEnable );
+
 protected:
 
     void onSetFocus( wxFocusEvent& aEvent );
     void onKillFocus( wxFocusEvent& aEvent );
     void delayedFocusHandler( wxCommandEvent& aEvent );
 
+    ///> The parent window
+    EDA_DRAW_FRAME*   m_parent;
+
     ///> The bound widgets
     wxStaticText*     m_label;
     wxWindow*         m_value;
@@ -140,6 +149,10 @@ protected:
     NUMERIC_EVALUATOR m_eval;
     bool              m_allowEval;
     bool              m_needsEval;
+
+    ///> Origin transforms
+    ORIGIN_XFORMS     m_originXform;
+    bool              m_allowOriginXform;
 };
 
 #endif /* __UNIT_BINDER_H_ */
-- 
2.7.4

>From 03247d385aa7898dd88b18f90ad7e44922d5f359 Mon Sep 17 00:00:00 2001
From: "Reece R. Pollack" <reece@xxxxxxx>
Date: Fri, 3 May 2019 09:49:00 -0400
Subject: [PATCH 2/2] RRP: Pcbnew support for Display Origin Transforms

This commit contains the changes to pcbnew Display Origin Transforms.
This includes X and Y axis transforms in the PCB_BASE_FRAME class that
override the default null transforms in the EDA_BASE_FRAME class.

Dialog box support is provided in the following pcbnew classes:
  * DIALOG_FOOTPRINT_BOARD_EDITOR
  * DIALOG_GRAPHIC_ITEM_PROPERTIES
  * DIALOG_PAD_PROPERTIES
  * DIALOG_TEXT_PROPERTIES

Configuration parameters are located in the PCB_DISPLAY_OPTIONS. This
may not be the appropriate place. Also note that the default values
set in the constructor are NOT appropriate for production builds
and must be changed before merging into the source tree.

What is left to be done:
  * Any dialog not mentioned above is unsupported.
  * Polar coordinate support is completely untested.
  * There is no user interface support for config parameters.
  * Config parameters are not saved or restored.
---
 include/pcb_base_frame.h                           |  20 +++
 include/pcb_display_options.h                      |   6 +
 .../dialog_edit_footprint_for_BoardEditor.cpp      |   6 +-
 pcbnew/dialogs/dialog_graphic_item_properties.cpp  |   9 +-
 pcbnew/dialogs/dialog_pad_properties.cpp           |   4 +-
 pcbnew/dialogs/dialog_text_properties.cpp          |   4 +-
 pcbnew/pcb_base_frame.cpp                          | 140 ++++++++++++++++++++-
 pcbnew/pcb_display_options.cpp                     |   4 +
 8 files changed, 179 insertions(+), 14 deletions(-)

diff --git a/include/pcb_base_frame.h b/include/pcb_base_frame.h
index fec63ee..bd1c054 100644
--- a/include/pcb_base_frame.h
+++ b/include/pcb_base_frame.h
@@ -148,6 +148,26 @@ public:
     const wxPoint& GetGridOrigin() const override;
     void SetGridOrigin( const wxPoint& aPoint ) override;
 
+    /**
+     * Transform an internal coordinate value for display
+     * relative to the user-selected origin.
+     *
+     * @param aXform specifies the transform to be applied
+     * @param aValue specifies the value to be transformed
+     * @returns the transformed value
+     */
+    int OriginXformToDisplay( ORIGIN_XFORMS aXform, int aValue ) const override;
+
+    /**
+     * Transform a display coordinate value relative to the
+     * user-selected origin back to the internal origin.
+     *
+     * @param aXform specifies the transform to be applied
+     * @param aValue specifies the value to be transformed
+     * @returns the transformed value
+     */
+    int OriginXformFromDisplay( ORIGIN_XFORMS aXform, int aValue ) const override;
+
     const TITLE_BLOCK& GetTitleBlock() const override;
     void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) override;
 
diff --git a/include/pcb_display_options.h b/include/pcb_display_options.h
index 01dd6ad..282eb49 100644
--- a/include/pcb_display_options.h
+++ b/include/pcb_display_options.h
@@ -30,6 +30,8 @@
 #ifndef PCB_DISPLAY_OPTIONS_H_
 #define PCB_DISPLAY_OPTIONS_H_
 
+#include <common.h>
+
 /**
  * Class PCB_DISPLAY_OPTIONS
  * handles display options like enable/disable some optional drawings.
@@ -87,6 +89,10 @@ public:
     bool m_DisplayRatsnestLinesCurved;  // Airwires can be drawn as straight lines (false)
                                         // or curved lines (true)
 
+    ORIGIN_REFERENCES m_displayOrigin; //< Which origin is used for display transforms
+    bool              m_invertXAxis;   //< true: Invert the X axis for display
+    bool              m_invertYAxis;   //< true: Invert the Y axis for display
+
 public:
 
     PCB_DISPLAY_OPTIONS();
diff --git a/pcbnew/dialogs/dialog_edit_footprint_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_footprint_for_BoardEditor.cpp
index 233734d..872cfba 100644
--- a/pcbnew/dialogs/dialog_edit_footprint_for_BoardEditor.cpp
+++ b/pcbnew/dialogs/dialog_edit_footprint_for_BoardEditor.cpp
@@ -58,8 +58,8 @@ int DIALOG_FOOTPRINT_BOARD_EDITOR::m_page = 0;     // remember the last open pag
 DIALOG_FOOTPRINT_BOARD_EDITOR::DIALOG_FOOTPRINT_BOARD_EDITOR( PCB_EDIT_FRAME* aParent,
                                                               MODULE* aModule, wxDC* aDC ) :
     DIALOG_FOOTPRINT_BOARD_EDITOR_BASE( aParent ),
-    m_posX( aParent, m_XPosLabel, m_ModPositionX, m_XPosUnit ),
-    m_posY( aParent, m_YPosLabel, m_ModPositionY, m_YPosUnit ),
+    m_posX( aParent, m_XPosLabel, m_ModPositionX, m_XPosUnit, false, true, ORIGIN_XFORM_X_ABS ),
+    m_posY( aParent, m_YPosLabel, m_ModPositionY, m_YPosUnit, false, true, ORIGIN_XFORM_Y_ABS ),
     m_OrientValidator( 1, &m_OrientValue ),
     m_netClearance( aParent, m_NetClearanceLabel, m_NetClearanceCtrl, m_NetClearanceUnits, false, 0 ),
     m_solderMask( aParent, m_SolderMaskMarginLabel, m_SolderMaskMarginCtrl, m_SolderMaskMarginUnits ),
@@ -903,4 +903,4 @@ void DIALOG_FOOTPRINT_BOARD_EDITOR::OnGridSize( wxSizeEvent& aEvent )
 void DIALOG_FOOTPRINT_BOARD_EDITOR::updateOrientationControl()
 {
     KIUI::ValidatorTransferToWindowWithoutEvents( m_OrientValidator );
-}
\ No newline at end of file
+}
diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp
index 73d667f..d8402fa 100644
--- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp
+++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp
@@ -82,10 +82,10 @@ private:
 DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent,
                                                                 BOARD_ITEM* aItem ):
     DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE( aParent ),
-    m_startX( aParent, m_startXLabel, m_startXCtrl, m_startXUnits ),
-    m_startY( aParent, m_startYLabel, m_startYCtrl, m_startYUnits ),
-    m_endX( aParent, m_endXLabel, m_endXCtrl, m_endXUnits ),
-    m_endY( aParent, m_endYLabel, m_endYCtrl, m_endYUnits ),
+    m_startX( aParent, m_startXLabel, m_startXCtrl, m_startXUnits, false, true, ORIGIN_XFORM_X_ABS ),
+    m_startY( aParent, m_startYLabel, m_startYCtrl, m_startYUnits, false, true, ORIGIN_XFORM_Y_ABS ),
+    m_endX( aParent, m_endXLabel, m_endXCtrl, m_endXUnits, false, true, ORIGIN_XFORM_X_ABS ),
+    m_endY( aParent, m_endYLabel, m_endYCtrl, m_endYUnits, false, true, ORIGIN_XFORM_Y_ABS ),
     m_angle( aParent, m_angleLabel, m_angleCtrl, m_angleUnits ),
     m_thickness( aParent, m_thicknessLabel, m_thicknessCtrl, m_thicknessUnits, true ),
     m_bezierCtrl1X( aParent, m_BezierPointC1XLabel, m_BezierC1X_Ctrl, m_BezierPointC1XUnit ),
@@ -165,6 +165,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
         m_startXLabel->SetLabel( _( "Center X:" ) );
         m_startYLabel->SetLabel( _( "Center Y:" ) );
         m_endXLabel->SetLabel( _( "Radius:" ) );
+        m_endX.AllowOriginXform( false );
         m_endY.Show( false );
         break;
 
diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp
index b8c0798..25fe43c 100644
--- a/pcbnew/dialogs/dialog_pad_properties.cpp
+++ b/pcbnew/dialogs/dialog_pad_properties.cpp
@@ -109,8 +109,8 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP
     DIALOG_PAD_PROPERTIES_BASE( aParent ),
     m_parent( aParent ),
     m_canUpdate( false ),
-    m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits ),
-    m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits ),
+    m_posX( aParent, m_posXLabel, m_posXCtrl, m_posXUnits, false, true, ORIGIN_XFORM_X_ABS ),
+    m_posY( aParent, m_posYLabel, m_posYCtrl, m_posYUnits, false, true, ORIGIN_XFORM_Y_ABS ),
     m_sizeX( aParent, m_sizeXLabel, m_sizeXCtrl, m_sizeXUnits, true ),
     m_sizeY( aParent, m_sizeYLabel, m_sizeYCtrl, m_sizeYUnits, true ),
     m_offsetX( aParent, m_offsetXLabel, m_offsetXCtrl, m_offsetXUnits, true ),
diff --git a/pcbnew/dialogs/dialog_text_properties.cpp b/pcbnew/dialogs/dialog_text_properties.cpp
index d70d755..799ba63 100644
--- a/pcbnew/dialogs/dialog_text_properties.cpp
+++ b/pcbnew/dialogs/dialog_text_properties.cpp
@@ -61,8 +61,8 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, BO
     m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits, true ),
     m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits, true ),
     m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits, true ),
-    m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits ),
-    m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits ),
+    m_posX( aParent, m_PositionXLabel, m_PositionXCtrl, m_PositionXUnits, false, true, ORIGIN_XFORM_X_ABS ),
+    m_posY( aParent, m_PositionYLabel, m_PositionYCtrl, m_PositionYUnits, false, true, ORIGIN_XFORM_Y_ABS ),
     m_OrientValidator( 1, &m_OrientValue )
 {
     wxString title;
diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp
index 8e9447c..ba335d0 100644
--- a/pcbnew/pcb_base_frame.cpp
+++ b/pcbnew/pcb_base_frame.cpp
@@ -308,6 +308,136 @@ void PCB_BASE_FRAME::SetGridOrigin( const wxPoint& aPoint )
 }
 
 
+int PCB_BASE_FRAME::OriginXformToDisplay( ORIGIN_XFORMS aXform, int aValue ) const
+{
+    int     displayValue = aValue;
+    wxPoint origin( 0, 0 );
+
+    // Find the display origin
+    switch( m_DisplayOptions.m_displayOrigin )
+    {
+    case ORIGIN_REFERENCE_PAGE:
+        break;      // no-op
+    case ORIGIN_REFERENCE_AUX:
+        origin = GetAuxOrigin();
+        break;
+    case ORIGIN_REFERENCE_GRID:
+        origin = GetGridOrigin();
+        break;
+    default:
+        wxASSERT( false );
+        break;
+    }
+
+    // Make the value relative to the selected origin
+    switch( aXform )
+    {
+    case ORIGIN_XFORM_NONE:
+    case ORIGIN_XFORM_X_REL:
+    case ORIGIN_XFORM_Y_REL:
+        break;      // No-op
+    case ORIGIN_XFORM_X_ABS:
+        displayValue -= origin.x;
+        break;
+    case ORIGIN_XFORM_Y_ABS:
+        displayValue -= origin.y;
+        break;
+    default:
+        wxASSERT( false );
+        break;
+    }
+
+    // Invert the direction if needed
+    switch( aXform )
+    {
+    case ORIGIN_XFORM_NONE:
+        // No-op
+        break;
+    case ORIGIN_XFORM_X_ABS:
+    case ORIGIN_XFORM_X_REL:
+        if( m_DisplayOptions.m_invertXAxis )
+            displayValue = -displayValue;
+        break;
+    case ORIGIN_XFORM_Y_ABS:
+    case ORIGIN_XFORM_Y_REL:
+        if( m_DisplayOptions.m_invertYAxis )
+            displayValue = -displayValue;
+        break;
+    default:
+        wxASSERT( false );
+        break;
+    }
+
+    return displayValue;
+}
+
+
+int PCB_BASE_FRAME::OriginXformFromDisplay( ORIGIN_XFORMS aXform, int aValue ) const
+{
+    wxPoint origin( 0, 0 );
+    int     internalValue = aValue;
+
+    // Find the display origin
+    switch( m_DisplayOptions.m_displayOrigin )
+    {
+    case ORIGIN_REFERENCE_PAGE:
+        // no-op
+        break;
+    case ORIGIN_REFERENCE_AUX:
+        origin = GetAuxOrigin();
+        break;
+    case ORIGIN_REFERENCE_GRID:
+        origin = GetGridOrigin();
+        break;
+    default:
+        wxASSERT(false);
+        break;
+    }
+
+    // Invert the direction if needed
+    switch( aXform )
+    {
+    case ORIGIN_XFORM_NONE:
+        // No-op
+        break;
+    case ORIGIN_XFORM_X_ABS:
+    case ORIGIN_XFORM_X_REL:
+        if( m_DisplayOptions.m_invertXAxis )
+            internalValue = -internalValue;
+        break;
+    case ORIGIN_XFORM_Y_ABS:
+    case ORIGIN_XFORM_Y_REL:
+        if( m_DisplayOptions.m_invertYAxis )
+            internalValue = -internalValue;
+        break;
+    default:
+        wxASSERT(false);
+        break;
+    }
+
+    // Make the value relative to the internal origin
+    switch( aXform )
+    {
+    case ORIGIN_XFORM_NONE:
+    case ORIGIN_XFORM_X_REL:
+    case ORIGIN_XFORM_Y_REL:
+        // No-op
+        break;
+    case ORIGIN_XFORM_X_ABS:
+        internalValue += origin.x;
+        break;
+    case ORIGIN_XFORM_Y_ABS:
+        internalValue += origin.y;
+        break;
+    default:
+        wxASSERT(false);
+        break;
+    }
+
+    return internalValue;
+}
+
+
 const TITLE_BLOCK& PCB_BASE_FRAME::GetTitleBlock() const
 {
     wxASSERT( m_Pcb );
@@ -869,9 +999,13 @@ void PCB_BASE_FRAME::UpdateStatusBar()
         SetStatusText( line, 3 );
     }
 
-    // Display absolute coordinates:
-    double dXpos = To_User_Unit( GetUserUnits(), GetCrossHairPosition().x );
-    double dYpos = To_User_Unit( GetUserUnits(), GetCrossHairPosition().y );
+    // Display coordinates relative to user origin
+    int iXpos = OriginXformToDisplay( ORIGIN_XFORM_X_ABS, GetCrossHairPosition().x );
+    int iYpos = OriginXformToDisplay( ORIGIN_XFORM_Y_ABS, GetCrossHairPosition().y );
+
+    double dXpos = To_User_Unit( GetUserUnits(), iXpos );
+    double dYpos = To_User_Unit( GetUserUnits(), iYpos );
+
 
     // The following sadly is an if Eeschema/if Pcbnew
     wxString absformatter;
diff --git a/pcbnew/pcb_display_options.cpp b/pcbnew/pcb_display_options.cpp
index f5f15c9..5491eac 100644
--- a/pcbnew/pcb_display_options.cpp
+++ b/pcbnew/pcb_display_options.cpp
@@ -57,4 +57,8 @@ PCB_DISPLAY_OPTIONS::PCB_DISPLAY_OPTIONS()
     m_MaxLinksShowed   = 3;             // in track creation: number of hairwires shown
     m_Show_Module_Ratsnest  = true;     // When moving a footprint: allows displaying a ratsnest
     m_DisplayRatsnestLinesCurved = false;
+
+    m_displayOrigin = ORIGIN_REFERENCE_AUX;     // :FIXME: should default to PAGE
+    m_invertXAxis   = false;
+    m_invertYAxis   = true;                     // :FIXME: Should default to false
 }
-- 
2.7.4


Follow ups