mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 10:13:19 +02:00
Map a full hierarchy during PDF plotting
Re-create the schematic hierarchy in PDF plots to ease navigation relative to the on screen schematic Fixes https://gitlab.com/kicad/code/kicad/-/issues/12154 (cherry picked from commit 4a3b33df4e8a95ce3cafe8dc810642501f929d72)
This commit is contained in:
parent
27b55eb32f
commit
49d8fc900f
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio> // snprintf
|
#include <cstdio> // snprintf
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
@ -658,13 +659,19 @@ void PDF_PLOTTER::closePdfStream()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PDF_PLOTTER::StartPage( const wxString& aPageNumber, const wxString& aPageName )
|
void PDF_PLOTTER::StartPage( const wxString& aPageNumber, const wxString& aPageName,
|
||||||
|
const wxString& aParentPageNumber, const wxString& aParentPageName )
|
||||||
{
|
{
|
||||||
wxASSERT( m_outputFile );
|
wxASSERT( m_outputFile );
|
||||||
wxASSERT( !m_workFile );
|
wxASSERT( !m_workFile );
|
||||||
|
|
||||||
m_pageNumbers.push_back( aPageNumber );
|
m_pageNumbers.push_back( aPageNumber );
|
||||||
m_pageName = aPageName;
|
m_pageName = aPageName.IsEmpty()
|
||||||
|
? wxString::Format( _( "Page %s" ), aPageNumber )
|
||||||
|
: wxString::Format( _( "%s (Page %s)" ), aPageName, aPageNumber );
|
||||||
|
m_parentPageName = aParentPageName.IsEmpty()
|
||||||
|
? wxString::Format( _( "Page %s" ), aParentPageNumber )
|
||||||
|
: wxString::Format( _( "%s (Page %s)" ), aParentPageName, aParentPageNumber );
|
||||||
|
|
||||||
// Compute the paper size in IUs
|
// Compute the paper size in IUs
|
||||||
m_paperSize = m_pageInfo.GetSizeMils();
|
m_paperSize = m_pageInfo.GetSizeMils();
|
||||||
@ -889,20 +896,34 @@ void PDF_PLOTTER::ClosePage()
|
|||||||
// Mark the page stream as idle
|
// Mark the page stream as idle
|
||||||
m_pageStreamHandle = 0;
|
m_pageStreamHandle = 0;
|
||||||
|
|
||||||
wxString pageOutlineName = wxEmptyString;
|
int actionHandle = emitGoToAction( pageHandle );
|
||||||
|
PDF_PLOTTER::OUTLINE_NODE* parent_node = m_outlineRoot.get();
|
||||||
|
|
||||||
if( m_pageName.IsEmpty() )
|
if( !m_parentPageName.IsEmpty() )
|
||||||
{
|
{
|
||||||
pageOutlineName = wxString::Format( _( "Page %s" ), m_pageNumbers.back() );
|
// Search for the parent node iteratively through the entire tree
|
||||||
}
|
std::stack<OUTLINE_NODE*> nodes;
|
||||||
else
|
nodes.push( m_outlineRoot.get() );
|
||||||
{
|
|
||||||
pageOutlineName = wxString::Format( _( "%s (Page %s)" ), m_pageName, m_pageNumbers.back() );
|
while( !nodes.empty() )
|
||||||
|
{
|
||||||
|
OUTLINE_NODE* node = nodes.top();
|
||||||
|
nodes.pop();
|
||||||
|
|
||||||
|
// Check if this node matches
|
||||||
|
if( node->title == m_parentPageName )
|
||||||
|
{
|
||||||
|
parent_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all children to the stack
|
||||||
|
for( OUTLINE_NODE* child : node->children )
|
||||||
|
nodes.push( child );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int actionHandle = emitGoToAction( pageHandle );
|
OUTLINE_NODE* pageOutlineNode = addOutlineNode( parent_node, actionHandle, m_pageName );
|
||||||
OUTLINE_NODE* pageOutlineNode =
|
|
||||||
addOutlineNode( m_outlineRoot.get(), actionHandle, pageOutlineName );
|
|
||||||
|
|
||||||
// let's reorg the symbol bookmarks under a page handle
|
// let's reorg the symbol bookmarks under a page handle
|
||||||
// let's reorg the symbol bookmarks under a page handle
|
// let's reorg the symbol bookmarks under a page handle
|
||||||
|
@ -122,7 +122,7 @@ void SCH_PLOTTER::createPDFFile( const SCH_PLOT_OPTS& aPlotOpts,
|
|||||||
if( aPlotOpts.m_plotAll || aPlotOpts.m_plotPages.size() > 0 )
|
if( aPlotOpts.m_plotAll || aPlotOpts.m_plotPages.size() > 0 )
|
||||||
{
|
{
|
||||||
sheetList.BuildSheetList( &m_schematic->Root(), true );
|
sheetList.BuildSheetList( &m_schematic->Root(), true );
|
||||||
sheetList.SortByPageNumbers();
|
sheetList.SortByHierarchicalPageNumbers();
|
||||||
|
|
||||||
// remove the non-selected pages if we are in plot pages mode
|
// remove the non-selected pages if we are in plot pages mode
|
||||||
if( aPlotOpts.m_plotPages.size() > 0 )
|
if( aPlotOpts.m_plotPages.size() > 0 )
|
||||||
@ -226,7 +226,20 @@ void SCH_PLOTTER::createPDFFile( const SCH_PLOT_OPTS& aPlotOpts,
|
|||||||
* reconfigure, and then start a new one */
|
* reconfigure, and then start a new one */
|
||||||
plotter->ClosePage();
|
plotter->ClosePage();
|
||||||
setupPlotPagePDF( plotter, screen, aPlotOpts );
|
setupPlotPagePDF( plotter, screen, aPlotOpts );
|
||||||
plotter->StartPage( sheetList[i].GetPageNumber(), sheetName );
|
SCH_SHEET_PATH parentSheet = sheetList[i];
|
||||||
|
|
||||||
|
if( parentSheet.size() > 1 )
|
||||||
|
{
|
||||||
|
// The sheet path is the full path to the sheet, so we need to remove the last
|
||||||
|
// sheet name to get the parent sheet path
|
||||||
|
parentSheet.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString parentSheetName =
|
||||||
|
parentSheet.Last()->GetName();
|
||||||
|
|
||||||
|
plotter->StartPage( sheetList[i].GetPageNumber(), sheetName,
|
||||||
|
parentSheet.GetPageNumber(), parentSheetName );
|
||||||
}
|
}
|
||||||
|
|
||||||
plotOneSheetPDF( plotter, screen, aPlotOpts );
|
plotOneSheetPDF( plotter, screen, aPlotOpts );
|
||||||
|
@ -816,6 +816,44 @@ void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums )
|
||||||
|
{
|
||||||
|
for( const SCH_SHEET_PATH& path : *this )
|
||||||
|
path.CachePageNumber();
|
||||||
|
|
||||||
|
std::sort( begin(), end(),
|
||||||
|
[]( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool
|
||||||
|
{
|
||||||
|
if( a.size() != b.size() )
|
||||||
|
return a.size() < b.size();
|
||||||
|
|
||||||
|
int retval = SCH_SHEET::ComparePageNum( a.GetCachedPageNumber(),
|
||||||
|
b.GetCachedPageNumber() );
|
||||||
|
|
||||||
|
if( retval < 0 )
|
||||||
|
return true;
|
||||||
|
else if( retval > 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( a.GetVirtualPageNumber() < b.GetVirtualPageNumber() )
|
||||||
|
return true;
|
||||||
|
else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Enforce strict ordering. If the page numbers are the same, use UUIDs
|
||||||
|
return a.GetCurrentHash() < b.GetCurrentHash();
|
||||||
|
} );
|
||||||
|
|
||||||
|
if( aUpdateVirtualPageNums )
|
||||||
|
{
|
||||||
|
int virtualPageNum = 1;
|
||||||
|
|
||||||
|
for( SCH_SHEET_PATH& sheet : *this )
|
||||||
|
sheet.SetVirtualPageNumber( virtualPageNum++ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
|
void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums )
|
||||||
{
|
{
|
||||||
for( const SCH_SHEET_PATH& path : *this )
|
for( const SCH_SHEET_PATH& path : *this )
|
||||||
|
@ -617,6 +617,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SortByPageNumbers( bool aUpdateVirtualPageNums = true );
|
void SortByPageNumbers( bool aUpdateVirtualPageNums = true );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This works like #SortByPageNumbers, but it sorts the sheets first by their hierarchical
|
||||||
|
* depth and then by their page numbers. This ensures that printouts follow the
|
||||||
|
* hierarchical structure of the schematic.
|
||||||
|
*/
|
||||||
|
void SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums = true );
|
||||||
|
|
||||||
bool NameExists( const wxString& aSheetName ) const;
|
bool NameExists( const wxString& aSheetName ) const;
|
||||||
|
|
||||||
bool PageNumberExists( const wxString& aPageNumber ) const;
|
bool PageNumberExists( const wxString& aPageNumber ) const;
|
||||||
|
@ -289,7 +289,9 @@ public:
|
|||||||
* Start a new page in the PDF document.
|
* Start a new page in the PDF document.
|
||||||
*/
|
*/
|
||||||
virtual void StartPage( const wxString& aPageNumber,
|
virtual void StartPage( const wxString& aPageNumber,
|
||||||
const wxString& aPageName = wxEmptyString );
|
const wxString& aPageName = wxEmptyString,
|
||||||
|
const wxString& aParentPageNumber = wxEmptyString,
|
||||||
|
const wxString& aParentPageName = wxEmptyString );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the current page in the PDF document (and emit its compressed stream).
|
* Close the current page in the PDF document (and emit its compressed stream).
|
||||||
@ -498,8 +500,11 @@ protected:
|
|||||||
std::vector<int> m_pageHandles; ///< Handles to the page objects.
|
std::vector<int> m_pageHandles; ///< Handles to the page objects.
|
||||||
int m_pageStreamHandle; ///< Handle of the page content object.
|
int m_pageStreamHandle; ///< Handle of the page content object.
|
||||||
int m_streamLengthHandle; ///< Handle to the deferred stream length.
|
int m_streamLengthHandle; ///< Handle to the deferred stream length.
|
||||||
|
|
||||||
wxString m_workFilename;
|
wxString m_workFilename;
|
||||||
wxString m_pageName;
|
wxString m_pageName;
|
||||||
|
wxString m_parentPageName;
|
||||||
|
|
||||||
FILE* m_workFile; ///< Temporary file to construct the stream before zipping.
|
FILE* m_workFile; ///< Temporary file to construct the stream before zipping.
|
||||||
std::vector<long> m_xrefTable; ///< The PDF xref offset table.
|
std::vector<long> m_xrefTable; ///< The PDF xref offset table.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user