From f341ab9b000369797940358109150978bd403893 Mon Sep 17 00:00:00 2001
From: Jeff Young <jeff@rokeby.ie>
Date: Sat, 9 Mar 2024 22:16:53 +0000
Subject: [PATCH] Bug fixes for flipping tables.

Also adds support for tabbing between table cells in the
table editor dialog.

Also adds support for calling the table editor dialog from
edit properties on a table selection.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17337
---
 common/scintilla_tricks.cpp                | 47 ++++++++++++++++++
 pcbnew/dialogs/dialog_table_properties.cpp | 17 +++++--
 pcbnew/edit.cpp                            |  8 +++
 pcbnew/pcb_table.cpp                       | 14 ++++++
 pcbnew/pcb_tablecell.cpp                   |  2 +
 pcbnew/tools/drawing_tool.cpp              | 57 +++++++++++++---------
 6 files changed, 119 insertions(+), 26 deletions(-)

diff --git a/common/scintilla_tricks.cpp b/common/scintilla_tricks.cpp
index fdeab3fbe0..c3bf8798fd 100644
--- a/common/scintilla_tricks.cpp
+++ b/common/scintilla_tricks.cpp
@@ -24,6 +24,7 @@
 
 #include <string_utils.h>
 #include <scintilla_tricks.h>
+#include <widgets/wx_grid.h>
 #include <wx/stc/stc.h>
 #include <gal/color4d.h>
 #include <dialog_shim.h>
@@ -255,6 +256,11 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
     }
     else if( aEvent.GetKeyCode() == WXK_TAB )
     {
+        wxWindow* ancestor = m_te->GetParent();
+
+        while( ancestor && !dynamic_cast<WX_GRID*>( ancestor ) )
+            ancestor = ancestor->GetParent();
+
         if( aEvent.ControlDown() )
         {
             int flags = 0;
@@ -270,6 +276,47 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
             if( parent )
                 parent->NavigateIn( flags );
         }
+        else if( dynamic_cast<WX_GRID*>( ancestor ) )
+        {
+            WX_GRID* grid = static_cast<WX_GRID*>( ancestor );
+            int      row = grid->GetGridCursorRow();
+            int      col = grid->GetGridCursorCol();
+
+            if( aEvent.ShiftDown() )
+            {
+                if( col > 0 )
+                {
+                    col--;
+                }
+                else if( row > 0 )
+                {
+                    col = (int) grid->GetNumberCols() - 1;
+
+                    if( row > 0 )
+                        row--;
+                    else
+                        row = (int) grid->GetNumberRows() - 1;
+                }
+            }
+            else
+            {
+                if( col < (int) grid->GetNumberCols() - 1 )
+                {
+                    col++;
+                }
+                else if( row < grid->GetNumberRows() - 1 )
+                {
+                    col = 0;
+
+                    if( row < grid->GetNumberRows() - 1 )
+                        row++;
+                    else
+                        row = 0;
+                }
+            }
+
+            grid->SetGridCursor( row, col );
+        }
         else
         {
             m_te->Tab();
diff --git a/pcbnew/dialogs/dialog_table_properties.cpp b/pcbnew/dialogs/dialog_table_properties.cpp
index 2302ae6f05..fab94425d4 100644
--- a/pcbnew/dialogs/dialog_table_properties.cpp
+++ b/pcbnew/dialogs/dialog_table_properties.cpp
@@ -159,7 +159,12 @@ bool DIALOG_TABLE_PROPERTIES::TransferDataToWindow()
     {
         for( int col = 0; col < m_table->GetColCount(); ++col )
         {
-            PCB_TABLECELL* tableCell = m_table->GetCell( row, col );
+            PCB_TABLECELL* tableCell;
+
+            if( IsBackLayer( m_table->GetLayer() ) )
+                tableCell = m_table->GetCell( row, m_table->GetColCount() - 1 - col );
+            else
+                tableCell = m_table->GetCell( row, col );
 
             if( tableCell->GetColSpan() == 0 || tableCell->GetRowSpan() == 0 )
                 m_grid->SetCellValue( row, col, coveredColor.GetAsString() );
@@ -292,8 +297,14 @@ bool DIALOG_TABLE_PROPERTIES::TransferDataFromWindow()
     {
         for( int col = 0; col < m_table->GetColCount(); ++col )
         {
-            PCB_TABLECELL* tableCell = m_table->GetCell( row, col );
-            wxString       txt = m_grid->GetCellValue( row, col );
+            PCB_TABLECELL* tableCell;
+
+            if( IsBackLayer( m_table->GetLayer() ) )
+                tableCell = m_table->GetCell( row, m_table->GetColCount() - 1 - col );
+            else
+                tableCell = m_table->GetCell( row, col );
+
+            wxString txt = m_grid->GetCellValue( row, col );
 
 #ifdef __WXMAC__
             // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp
index 570f956ef3..6dcab5b2e2 100644
--- a/pcbnew/edit.cpp
+++ b/pcbnew/edit.cpp
@@ -46,6 +46,7 @@
 #include <tools/pcb_actions.h>
 #include <tools/drc_tool.h>
 #include <dialogs/dialog_dimension_properties.h>
+#include <dialogs/dialog_table_properties.h>
 #include <pcb_layer_box_selector.h>
 
 // Handles the selection of command events.
@@ -137,6 +138,13 @@ void PCB_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem )
         ShowTextBoxPropertiesDialog( static_cast<PCB_TEXTBOX*>( aItem ) );
         break;
 
+    case PCB_TABLE_T:
+    {
+        DIALOG_TABLE_PROPERTIES dlg( this, static_cast<PCB_TABLE*>( aItem ) );
+        dlg.ShowQuasiModal();   // Scintilla's auto-complete requires quasiModal
+        break;
+    }
+
     case PCB_PAD_T:
         ShowPadPropertiesDialog( static_cast<PAD*>( aItem ) );
         break;
diff --git a/pcbnew/pcb_table.cpp b/pcbnew/pcb_table.cpp
index 42e42836ac..5177c1e871 100644
--- a/pcbnew/pcb_table.cpp
+++ b/pcbnew/pcb_table.cpp
@@ -189,6 +189,20 @@ void PCB_TABLE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
 {
     for( PCB_TABLECELL* cell : m_cells )
         cell->Flip( aCentre, aFlipLeftRight );
+
+    std::vector<PCB_TABLECELL*> oldCells = m_cells;
+    int                         rowOffset = 0;
+
+    for( int row = 0; row < GetRowCount(); ++row )
+    {
+        for( int col = 0; col < GetColCount(); ++col )
+            m_cells[ rowOffset + col ] = oldCells[ rowOffset + GetColCount() - 1 - col ];
+
+        rowOffset += GetColCount();
+    }
+
+    SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
+    Normalize();
 }
 
 
diff --git a/pcbnew/pcb_tablecell.cpp b/pcbnew/pcb_tablecell.cpp
index 0754b3429b..5a134e2a3f 100644
--- a/pcbnew/pcb_tablecell.cpp
+++ b/pcbnew/pcb_tablecell.cpp
@@ -34,6 +34,8 @@ PCB_TABLECELL::PCB_TABLECELL( BOARD_ITEM* aParent ) :
         m_colSpan( 1 ),
         m_rowSpan( 1 )
 {
+    if( IsBackLayer( aParent->GetLayer() ) )
+        SetMirrored( true );
 }
 
 
diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp
index c3717a5269..99dab48f1b 100644
--- a/pcbnew/tools/drawing_tool.cpp
+++ b/pcbnew/tools/drawing_tool.cpp
@@ -25,6 +25,7 @@
 
 #include "drawing_tool.h"
 #include "geometry/shape_rect.h"
+#include "dialog_table_properties.h"
 
 #include <pgm_base.h>
 #include <settings/settings_manager.h>
@@ -1135,43 +1136,53 @@ int DRAWING_TOOL::DrawTable( const TOOL_EVENT& aEvent )
         {
             if( !table )
             {
-            m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
+                m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
 
-            PCB_LAYER_ID layer = m_frame->GetActiveLayer();
+                PCB_LAYER_ID layer = m_frame->GetActiveLayer();
 
-            table = new PCB_TABLE( m_frame->GetModel(), bds.GetLineThickness( layer ) );
-            table->SetColCount( 1 );
-            table->AddCell( new PCB_TABLECELL( table ) );
+                table = new PCB_TABLE( m_frame->GetModel(), bds.GetLineThickness( layer ) );
+                table->SetLayer( layer );
+                table->SetColCount( 1 );
+                table->AddCell( new PCB_TABLECELL( table ) );
 
-            table->SetLayer( layer );
-            table->SetPosition( cursorPos );
+                table->SetLayer( layer );
+                table->SetPosition( cursorPos );
 
-            if( !m_view->IsLayerVisible( layer ) )
-            {
-                m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
-                m_frame->GetCanvas()->Refresh();
-            }
+                if( !m_view->IsLayerVisible( layer ) )
+                {
+                    m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
+                    m_frame->GetCanvas()->Refresh();
+                }
 
-            m_toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, table );
-            m_view->Update( &selection() );
+                m_toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, table );
+                m_view->Update( &selection() );
 
-            // update the cursor so it looks correct before another event
-            setCursor();
+                // update the cursor so it looks correct before another event
+                setCursor();
             }
             else
             {
                 table->ClearFlags();
-                m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
-
                 table->Normalize();
 
-                commit.Add( table, m_frame->GetScreen() );
-                commit.Push( _( "Draw Table" ) );
+                DIALOG_TABLE_PROPERTIES dlg( m_frame, table );
+
+                if( dlg.ShowQuasiModal() == wxID_OK )
+                {
+                    m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
+
+                    commit.Add( table, m_frame->GetScreen() );
+                    commit.Push( _( "Draw Table" ) );
+
+                    m_toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, table );
+                    m_toolMgr->PostAction( ACTIONS::activatePointEditor );
+                }
+                else
+                {
+                    delete table;
+                }
 
-                m_toolMgr->RunAction<EDA_ITEM*>( PCB_ACTIONS::selectItem, table );
                 table = nullptr;
-
-                m_toolMgr->PostAction( ACTIONS::activatePointEditor );
             }
         }
         else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )